diff --git a/.fern/metadata.json b/.fern/metadata.json new file mode 100644 index 00000000..3f8cac7f --- /dev/null +++ b/.fern/metadata.json @@ -0,0 +1,16 @@ +{ + "cliVersion": "5.50.1", + "generatorName": "fernapi/fern-python-sdk", + "generatorVersion": "4.64.1", + "generatorConfig": { + "package_name": "zep_cloud", + "client": { + "filename": "base_client.py", + "class_name": "BaseClient", + "exported_filename": "client.py", + "exported_class_name": "Zep" + } + }, + "originGitCommit": "06c25fceee846a69ed557aa11262309bbf9f64c1", + "sdkVersion": "4.0.0a1" +} \ No newline at end of file diff --git a/.fern/replay.lock b/.fern/replay.lock index afed4a45..7523e374 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: 1cc511d088dc998df04846bee0d23f0df1adf89a + tree_hash: 76a8a1d2ad837bbac56bbd4710c52efbd796e8ac + timestamp: 2026-08-24T20:10:22.592Z + cli_version: unknown + generator_versions: + fernapi/fern-python-sdk: 4.64.1 +current_generation: 1cc511d088dc998df04846bee0d23f0df1adf89a patches: [] diff --git a/pyproject.toml b/pyproject.toml index 6eba05c7..dbfb3f62 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,10 +1,10 @@ [project] name = "zep-cloud" -version = "3.28.0" +version = "4.0.0a1" [tool.poetry] name = "zep-cloud" -version = "3.28.0" +version = "4.0.0a1" description = "" readme = "README.md" authors = [] diff --git a/reference.md b/reference.md index d9dba041..1643d1ab 100644 --- a/reference.md +++ b/reference.md @@ -1,6 +1,6 @@ # Reference -## UserGroup -
client.user_group.list_policy_sets(...) +## Batch +
client.batch.list(...) -> BatchPage
@@ -14,13 +14,17 @@ ```python from zep_cloud import Zep +from zep_cloud.environment import ZepEnvironment client = Zep( - api_key="YOUR_API_KEY", + api_key="", + environment=ZepEnvironment.DEFAULT, ) -client.user_group.list_policy_sets( - group_uuid="groupUUID", - project_id="projectId", + +client.batch.list( + limit=1, + cursor="cursor", + status="status", ) ``` @@ -37,7 +41,15 @@ client.user_group.list_policy_sets(
-**group_uuid:** `str` — UserGroup UUID +**limit:** `typing.Optional[int]` — Page size + +
+
+ +
+
+ +**cursor:** `typing.Optional[str]` — Opaque page cursor
@@ -45,7 +57,7 @@ client.user_group.list_policy_sets(
-**project_id:** `str` — Project UUID +**status:** `typing.Optional[str]` — Batch status filter
@@ -65,7 +77,7 @@ client.user_group.list_policy_sets(
-
client.user_group.attach_policy_set(...) +
client.batch.create(...) -> Batch
@@ -79,16 +91,15 @@ client.user_group.list_policy_sets( ```python from zep_cloud import Zep +from zep_cloud.environment import ZepEnvironment client = Zep( - api_key="YOUR_API_KEY", -) -client.user_group.attach_policy_set( - group_uuid="groupUUID", - project_id="projectId", - policy_set_uuid="policy_set_uuid", + api_key="", + environment=ZepEnvironment.DEFAULT, ) +client.batch.create() + ```
@@ -103,7 +114,7 @@ client.user_group.attach_policy_set(
-**group_uuid:** `str` — UserGroup UUID +**ignore_roles:** `typing.Optional[typing.List[str]]`
@@ -111,7 +122,7 @@ client.user_group.attach_policy_set(
-**project_id:** `str` — Project UUID +**metadata:** `typing.Optional[typing.Dict[str, typing.Any]]`
@@ -119,7 +130,7 @@ client.user_group.attach_policy_set(
-**policy_set_uuid:** `str` +**strict_ontology:** `typing.Optional[bool]`
@@ -139,7 +150,7 @@ client.user_group.attach_policy_set(
-
client.user_group.detach_policy_set(...) +
client.batch.get(...) -> Batch
@@ -153,14 +164,15 @@ client.user_group.attach_policy_set( ```python from zep_cloud import Zep +from zep_cloud.environment import ZepEnvironment client = Zep( - api_key="YOUR_API_KEY", + api_key="", + environment=ZepEnvironment.DEFAULT, ) -client.user_group.detach_policy_set( - group_uuid="groupUUID", - policy_set_uuid="policySetUUID", - project_id="projectId", + +client.batch.get( + batch_uuid="batch_uuid", ) ``` @@ -177,23 +189,7 @@ client.user_group.detach_policy_set(
-**group_uuid:** `str` — UserGroup UUID - -
-
- -
-
- -**policy_set_uuid:** `str` — Policy set UUID - -
-
- -
-
- -**project_id:** `str` — Project UUID +**batch_uuid:** `str` — Batch UUID
@@ -213,7 +209,7 @@ client.user_group.detach_policy_set(
-
client.user_group.list(...) +
client.batch.delete(...)
@@ -227,15 +223,15 @@ client.user_group.detach_policy_set( ```python from zep_cloud import Zep +from zep_cloud.environment import ZepEnvironment client = Zep( - api_key="YOUR_API_KEY", + api_key="", + environment=ZepEnvironment.DEFAULT, ) -client.user_group.list( - project_id="projectId", - page_number=1, - page_size=1, - search="search", + +client.batch.delete( + batch_uuid="batch_uuid", ) ``` @@ -252,31 +248,7 @@ client.user_group.list(
-**project_id:** `str` — Project UUID - -
-
- -
-
- -**page_number:** `int` — Page number - -
-
- -
-
- -**page_size:** `int` — Page size - -
-
- -
-
- -**search:** `typing.Optional[str]` — Name search +**batch_uuid:** `str` — Batch UUID
@@ -296,7 +268,7 @@ client.user_group.list(
-
client.user_group.create(...) +
client.batch.list_items(...) -> JsonObjectPage
@@ -310,13 +282,17 @@ client.user_group.list( ```python from zep_cloud import Zep +from zep_cloud.environment import ZepEnvironment client = Zep( - api_key="YOUR_API_KEY", + api_key="", + environment=ZepEnvironment.DEFAULT, ) -client.user_group.create( - project_id="projectId", - name="name", + +client.batch.list_items( + batch_uuid="batch_uuid", + limit=1, + cursor="cursor", ) ``` @@ -333,7 +309,7 @@ client.user_group.create(
-**project_id:** `str` — Project UUID +**batch_uuid:** `str` — Batch UUID
@@ -341,7 +317,7 @@ client.user_group.create(
-**name:** `str` +**limit:** `typing.Optional[int]` — Page size
@@ -349,7 +325,7 @@ client.user_group.create(
-**description:** `typing.Optional[str]` +**cursor:** `typing.Optional[str]` — Opaque page cursor
@@ -369,7 +345,7 @@ client.user_group.create(
-
client.user_group.list_for_user(...) +
client.batch.add_items(...) -> BatchItemsResponse
@@ -383,13 +359,15 @@ client.user_group.create( ```python from zep_cloud import Zep +from zep_cloud.environment import ZepEnvironment client = Zep( - api_key="YOUR_API_KEY", + api_key="", + environment=ZepEnvironment.DEFAULT, ) -client.user_group.list_for_user( - user_uuid="userUUID", - project_id="projectId", + +client.batch.add_items( + batch_uuid="batch_uuid", ) ``` @@ -406,7 +384,7 @@ client.user_group.list_for_user(
-**user_uuid:** `str` — User UUID +**batch_uuid:** `str` — Batch UUID
@@ -414,7 +392,7 @@ client.user_group.list_for_user(
-**project_id:** `str` — Project UUID +**items:** `typing.Optional[typing.List[typing.Dict[str, typing.Any]]]`
@@ -434,7 +412,7 @@ client.user_group.list_for_user(
-
client.user_group.get(...) +
client.batch.process(...) -> ProcessBatchResult
@@ -448,13 +426,15 @@ client.user_group.list_for_user( ```python from zep_cloud import Zep +from zep_cloud.environment import ZepEnvironment client = Zep( - api_key="YOUR_API_KEY", + api_key="", + environment=ZepEnvironment.DEFAULT, ) -client.user_group.get( - group_uuid="groupUUID", - project_id="projectId", + +client.batch.process( + batch_uuid="batch_uuid", ) ``` @@ -471,15 +451,7 @@ client.user_group.get(
-**group_uuid:** `str` — UserGroup UUID - -
-
- -
-
- -**project_id:** `str` — Project UUID +**batch_uuid:** `str` — Batch UUID
@@ -499,7 +471,8 @@ client.user_group.get(
-
client.user_group.delete(...) +## Context +
client.context.create_template(...) -> ContextTemplate
@@ -513,15 +486,15 @@ client.user_group.get( ```python from zep_cloud import Zep +from zep_cloud.environment import ZepEnvironment client = Zep( - api_key="YOUR_API_KEY", -) -client.user_group.delete( - group_uuid="groupUUID", - project_id="projectId", + api_key="", + environment=ZepEnvironment.DEFAULT, ) +client.context.create_template() + ```
@@ -536,15 +509,7 @@ client.user_group.delete(
-**group_uuid:** `str` — UserGroup UUID - -
-
- -
-
- -**project_id:** `str` — Project UUID +**request:** `CreateContextTemplateRequest`
@@ -564,7 +529,7 @@ client.user_group.delete(
-
client.user_group.update(...) +
client.context.list_templates(...) -> ContextTemplatePage
@@ -578,14 +543,16 @@ client.user_group.delete( ```python from zep_cloud import Zep +from zep_cloud.environment import ZepEnvironment client = Zep( - api_key="YOUR_API_KEY", + api_key="", + environment=ZepEnvironment.DEFAULT, ) -client.user_group.update( - group_uuid="groupUUID", - project_id="projectId", - expected_version=1, + +client.context.list_templates( + limit=1, + cursor="cursor", ) ``` @@ -602,23 +569,7 @@ client.user_group.update(
-**group_uuid:** `str` — UserGroup UUID - -
-
- -
-
- -**project_id:** `str` — Project UUID - -
-
- -
-
- -**expected_version:** `int` +**limit:** `typing.Optional[int]` — Page size
@@ -626,7 +577,7 @@ client.user_group.update(
-**description:** `typing.Optional[str]` +**cursor:** `typing.Optional[str]` — Opaque page cursor
@@ -654,7 +605,7 @@ client.user_group.update(
-
client.user_group.list_members(...) +
client.context.get_template(...) -> ContextTemplate
@@ -668,16 +619,15 @@ client.user_group.update( ```python from zep_cloud import Zep +from zep_cloud.environment import ZepEnvironment client = Zep( - api_key="YOUR_API_KEY", + api_key="", + environment=ZepEnvironment.DEFAULT, ) -client.user_group.list_members( - group_uuid="groupUUID", - project_id="projectId", - page_number=1, - page_size=1, - search="search", + +client.context.get_template( + template_uuid="template_uuid", ) ``` @@ -694,7 +644,7 @@ client.user_group.list_members(
-**group_uuid:** `str` — UserGroup UUID +**template_uuid:** `str` — Template UUID
@@ -702,23 +652,58 @@ client.user_group.list_members(
-**project_id:** `str` — Project UUID +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+ + + + +
+
client.context.update_template(...) -> ContextTemplate
-**page_number:** `int` — Page number - +#### 🔌 Usage + +
+
+ +
+
+ +```python +from zep_cloud import Zep +from zep_cloud.environment import ZepEnvironment + +client = Zep( + api_key="", + environment=ZepEnvironment.DEFAULT, +) + +client.context.update_template( + template_uuid="template_uuid", +) + +```
+
+
+ +#### ⚙️ Parameters
-**page_size:** `int` — Page size +
+
+ +**template_uuid:** `str` — Template UUID
@@ -726,7 +711,7 @@ client.user_group.list_members(
-**search:** `typing.Optional[str]` — User search +**request:** `CreateContextTemplateRequest`
@@ -746,7 +731,7 @@ client.user_group.list_members(
-
client.user_group.add_members(...) +
client.context.delete_template(...)
@@ -760,14 +745,15 @@ client.user_group.list_members( ```python from zep_cloud import Zep +from zep_cloud.environment import ZepEnvironment client = Zep( - api_key="YOUR_API_KEY", + api_key="", + environment=ZepEnvironment.DEFAULT, ) -client.user_group.add_members( - group_uuid="groupUUID", - project_id="projectId", - user_uuids=["user_uuids"], + +client.context.delete_template( + template_uuid="template_uuid", ) ``` @@ -784,23 +770,7 @@ client.user_group.add_members(
-**group_uuid:** `str` — UserGroup UUID - -
-
- -
-
- -**project_id:** `str` — Project UUID - -
-
- -
-
- -**user_uuids:** `typing.Sequence[str]` +**template_uuid:** `str` — Template UUID
@@ -820,7 +790,8 @@ client.user_group.add_members(
-
client.user_group.remove_members(...) +## Graph +
client.graph.create(...) -> Graph
@@ -834,16 +805,15 @@ client.user_group.add_members( ```python from zep_cloud import Zep +from zep_cloud.environment import ZepEnvironment client = Zep( - api_key="YOUR_API_KEY", -) -client.user_group.remove_members( - group_uuid="groupUUID", - project_id="projectId", - user_uuids=["user_uuids"], + api_key="", + environment=ZepEnvironment.DEFAULT, ) +client.graph.create() + ```
@@ -858,7 +828,15 @@ client.user_group.remove_members(
-**group_uuid:** `str` — UserGroup UUID +**description:** `typing.Optional[str]` + +
+
+ +
+
+ +**graph_id:** `typing.Optional[str]`
@@ -866,7 +844,7 @@ client.user_group.remove_members(
-**project_id:** `str` — Project UUID +**name:** `typing.Optional[str]`
@@ -874,7 +852,7 @@ client.user_group.remove_members(
-**user_uuids:** `typing.Sequence[str]` +**time_zone:** `typing.Optional[str]`
@@ -894,7 +872,7 @@ client.user_group.remove_members(
-
client.user_group.list_member_candidates(...) +
client.graph.list(...) -> GraphPage
@@ -908,16 +886,18 @@ client.user_group.remove_members( ```python from zep_cloud import Zep +from zep_cloud.environment import ZepEnvironment client = Zep( - api_key="YOUR_API_KEY", + api_key="", + environment=ZepEnvironment.DEFAULT, ) -client.user_group.list_member_candidates( - group_uuid="groupUUID", - project_id="projectId", - page_number=1, - page_size=1, - search="search", + +client.graph.list( + limit=1, + cursor="cursor", + order_by="order_by", + order="order", ) ``` @@ -934,7 +914,7 @@ client.user_group.list_member_candidates(
-**group_uuid:** `str` — UserGroup UUID +**limit:** `typing.Optional[int]` — Page size
@@ -942,7 +922,7 @@ client.user_group.list_member_candidates(
-**project_id:** `str` — Project UUID +**cursor:** `typing.Optional[str]` — Opaque page cursor
@@ -950,7 +930,7 @@ client.user_group.list_member_candidates(
-**page_number:** `int` — Page number +**order_by:** `typing.Optional[str]` — Sort field
@@ -958,7 +938,7 @@ client.user_group.list_member_candidates(
-**page_size:** `int` — Page size +**order:** `typing.Optional[str]` — asc or desc
@@ -966,7 +946,7 @@ client.user_group.list_member_candidates(
-**search:** `typing.Optional[str]` — User search +**search:** `typing.Optional[str]`
@@ -986,7 +966,7 @@ client.user_group.list_member_candidates(
-
client.user_group.remove_member(...) +
client.graph.lookup(...) -> Graph
@@ -1000,16 +980,15 @@ client.user_group.list_member_candidates( ```python from zep_cloud import Zep +from zep_cloud.environment import ZepEnvironment client = Zep( - api_key="YOUR_API_KEY", -) -client.user_group.remove_member( - group_uuid="groupUUID", - user_uuid="userUUID", - project_id="projectId", + api_key="", + environment=ZepEnvironment.DEFAULT, ) +client.graph.lookup() + ```
@@ -1024,23 +1003,7 @@ client.user_group.remove_member(
-**group_uuid:** `str` — UserGroup UUID - -
-
- -
-
- -**user_uuid:** `str` — User UUID - -
-
- -
-
- -**project_id:** `str` — Project UUID +**request:** `LookupRequest`
@@ -1060,25 +1023,10 @@ client.user_group.remove_member(
-## Batch -
client.batch.list(...) -
-
- -#### 📝 Description - +
client.graph.get(...) -> Graph
-
-
- -List batches for the current project, optionally filtered by batch status. -
-
-
-
- #### 🔌 Usage
@@ -1089,14 +1037,15 @@ List batches for the current project, optionally filtered by batch status. ```python from zep_cloud import Zep +from zep_cloud.environment import ZepEnvironment client = Zep( - api_key="YOUR_API_KEY", + api_key="", + environment=ZepEnvironment.DEFAULT, ) -client.batch.list( - limit=1, - cursor=1, - status="status", + +client.graph.get( + graph_uuid="graph_uuid", ) ``` @@ -1113,23 +1062,7 @@ client.batch.list(
-**limit:** `typing.Optional[int]` — Maximum number of batches to return. - -
-
- -
-
- -**cursor:** `typing.Optional[int]` — Pagination cursor from a previous response. - -
-
- -
-
- -**status:** `typing.Optional[str]` — Batch status filter. +**graph_uuid:** `str` — Graph UUID
@@ -1149,24 +1082,10 @@ client.batch.list(
-
client.batch.create(...) -
-
- -#### 📝 Description - -
-
- +
client.graph.delete(...) -> GraphDeleteResult
-Create a draft batch that can be filled with graph episodes and thread messages. -
-
-
-
- #### 🔌 Usage
@@ -1177,11 +1096,16 @@ Create a draft batch that can be filled with graph episodes and thread messages. ```python from zep_cloud import Zep +from zep_cloud.environment import ZepEnvironment client = Zep( - api_key="YOUR_API_KEY", + api_key="", + environment=ZepEnvironment.DEFAULT, +) + +client.graph.delete( + graph_uuid="graph_uuid", ) -client.batch.create() ```
@@ -1197,20 +1121,7 @@ client.batch.create()
-**ignore_roles:** `typing.Optional[typing.Sequence[RoleType]]` - -Optional list of message role types to skip during graph ingestion for -thread_message items in this batch. The messages are still stored and -retained as context, but no graph extraction is performed for them. -Has no effect on graph_episode items. - -
-
- -
-
- -**metadata:** `typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]]` +**graph_uuid:** `str` — Graph UUID
@@ -1230,24 +1141,10 @@ Has no effect on graph_episode items.
-
client.batch.get(...) -
-
- -#### 📝 Description - -
-
- +
client.graph.update(...) -> Graph
-Get a batch summary, including runtime progress when the batch has been processed. -
-
-
-
- #### 🔌 Usage
@@ -1258,12 +1155,15 @@ Get a batch summary, including runtime progress when the batch has been processe ```python from zep_cloud import Zep +from zep_cloud.environment import ZepEnvironment client = Zep( - api_key="YOUR_API_KEY", + api_key="", + environment=ZepEnvironment.DEFAULT, ) -client.batch.get( - batch_id="batchId", + +client.graph.update( + graph_uuid="graph_uuid", ) ``` @@ -1280,7 +1180,7 @@ client.batch.get(
-**batch_id:** `str` — The batch ID. +**graph_uuid:** `str` — Graph UUID
@@ -1288,35 +1188,45 @@ client.batch.get(
-**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. +**description:** `typing.Optional[str]` — Omit to leave unchanged, send JSON null to clear, or send a value to set.
-
-
+
+
+**name:** `typing.Optional[str]` — Omit to leave unchanged, send JSON null to clear, or send a value to set. +
-
-
client.batch.delete(...)
-#### 📝 Description - -
-
+**time_zone:** `typing.Optional[str]` — Omit to leave unchanged, send JSON null to clear, or send a value to set. + +
+
-Delete a draft or invalid unprocessed batch. Processed batches cannot be deleted. +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. + +
+
+ +
+
+ +
client.graph.clone(...) -> CloneGraphResult +
+
#### 🔌 Usage @@ -1328,12 +1238,15 @@ Delete a draft or invalid unprocessed batch. Processed batches cannot be deleted ```python from zep_cloud import Zep +from zep_cloud.environment import ZepEnvironment client = Zep( - api_key="YOUR_API_KEY", + api_key="", + environment=ZepEnvironment.DEFAULT, ) -client.batch.delete( - batch_id="batchId", + +client.graph.clone( + graph_uuid="graph_uuid", ) ``` @@ -1350,7 +1263,15 @@ client.batch.delete(
-**batch_id:** `str` — The batch ID. +**graph_uuid:** `str` — Graph UUID + +
+
+ +
+
+ +**target_graph_id:** `typing.Optional[str]`
@@ -1370,24 +1291,10 @@ client.batch.delete(
-
client.batch.list_items(...) -
-
- -#### 📝 Description - -
-
- +
client.graph.get_context(...) -> GraphContextResponse
-List items in a batch, including derived runtime status when the batch has been processed. -
-
-
-
- #### 🔌 Usage
@@ -1398,15 +1305,15 @@ List items in a batch, including derived runtime status when the batch has been ```python from zep_cloud import Zep +from zep_cloud.environment import ZepEnvironment client = Zep( - api_key="YOUR_API_KEY", + api_key="", + environment=ZepEnvironment.DEFAULT, ) -client.batch.list_items( - batch_id="batchId", - limit=1, - cursor=1, - status="status", + +client.graph.get_context( + graph_uuid="graph_uuid", ) ``` @@ -1423,7 +1330,7 @@ client.batch.list_items(
-**batch_id:** `str` — The batch ID. +**graph_uuid:** `str` — Graph UUID
@@ -1431,7 +1338,7 @@ client.batch.list_items(
-**limit:** `typing.Optional[int]` — Maximum number of batch items to return. +**filters:** `typing.Optional[typing.Dict[str, typing.Any]]`
@@ -1439,7 +1346,7 @@ client.batch.list_items(
-**cursor:** `typing.Optional[int]` — Pagination cursor from a previous response. +**include_results:** `typing.Optional[bool]`
@@ -1447,7 +1354,7 @@ client.batch.list_items(
-**status:** `typing.Optional[str]` — Batch item status filter. +**max_characters:** `typing.Optional[int]`
@@ -1455,35 +1362,45 @@ client.batch.list_items(
-**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. +**query:** `typing.Optional[str]`
-
-
+
+
+**recency_bias:** `typing.Optional[str]` +
-
-
client.batch.add(...)
-#### 📝 Description - -
-
+**template_uuid:** `typing.Optional[str]` + +
+
-Add graph episodes and thread messages to a draft batch. Items are appended in request order. +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. + +
+
+ + +
+ +
client.graph.get_instructions(...) -> Instructions +
+
#### 🔌 Usage @@ -1494,18 +1411,16 @@ Add graph episodes and thread messages to a draft batch. Items are appended in r
```python -from zep_cloud import BatchAddItem, Zep +from zep_cloud import Zep +from zep_cloud.environment import ZepEnvironment client = Zep( - api_key="YOUR_API_KEY", + api_key="", + environment=ZepEnvironment.DEFAULT, ) -client.batch.add( - batch_id="batchId", - items=[ - BatchAddItem( - type="graph_episode", - ) - ], + +client.graph.get_instructions( + graph_uuid="graph_uuid", ) ``` @@ -1522,15 +1437,7 @@ client.batch.add(
-**batch_id:** `str` — The batch ID. - -
-
- -
-
- -**items:** `typing.Sequence[BatchAddItem]` +**graph_uuid:** `str` — Graph UUID
@@ -1550,24 +1457,10 @@ client.batch.add(
-
client.batch.process(...) -
-
- -#### 📝 Description - +
client.graph.set_instructions(...) -> Instructions
-
-
- -Start processing a filled batch. Repeated calls return a conflict. -
-
-
-
- #### 🔌 Usage
@@ -1578,12 +1471,15 @@ Start processing a filled batch. Repeated calls return a conflict. ```python from zep_cloud import Zep +from zep_cloud.environment import ZepEnvironment client = Zep( - api_key="YOUR_API_KEY", + api_key="", + environment=ZepEnvironment.DEFAULT, ) -client.batch.process( - batch_id="batchId", + +client.graph.set_instructions( + graph_uuid="graph_uuid", ) ``` @@ -1600,7 +1496,15 @@ client.batch.process(
-**batch_id:** `str` — The batch ID. +**graph_uuid:** `str` — Graph UUID + +
+
+ +
+
+ +**request:** `Instructions`
@@ -1620,25 +1524,10 @@ client.batch.process(
-## Context -
client.context.list_context_templates() -
-
- -#### 📝 Description - -
-
- +
client.graph.get_observation_steering(...) -> ObservationSteering
-Lists all context templates. -
-
-
-
- #### 🔌 Usage
@@ -1649,11 +1538,16 @@ Lists all context templates. ```python from zep_cloud import Zep +from zep_cloud.environment import ZepEnvironment client = Zep( - api_key="YOUR_API_KEY", + api_key="", + environment=ZepEnvironment.DEFAULT, +) + +client.graph.get_observation_steering( + graph_uuid="graph_uuid", ) -client.context.list_context_templates() ```
@@ -1669,6 +1563,14 @@ client.context.list_context_templates()
+**graph_uuid:** `str` — Graph UUID + +
+
+ +
+
+ **request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
@@ -1681,24 +1583,10 @@ client.context.list_context_templates()
-
client.context.create_context_template(...) -
-
- -#### 📝 Description - -
-
- +
client.graph.set_observation_steering(...) -> ObservationSteering
-Creates a new context template. -
-
-
-
- #### 🔌 Usage
@@ -1709,13 +1597,15 @@ Creates a new context template. ```python from zep_cloud import Zep +from zep_cloud.environment import ZepEnvironment client = Zep( - api_key="YOUR_API_KEY", + api_key="", + environment=ZepEnvironment.DEFAULT, ) -client.context.create_context_template( - template="template", - template_id="template_id", + +client.graph.set_observation_steering( + graph_uuid="graph_uuid", ) ``` @@ -1732,7 +1622,7 @@ client.context.create_context_template(
-**template:** `str` — The template content (max 1200 characters). +**graph_uuid:** `str` — Graph UUID
@@ -1740,7 +1630,7 @@ client.context.create_context_template(
-**template_id:** `str` — Unique identifier for the template (max 100 characters). +**request:** `ObservationSteering`
@@ -1760,24 +1650,10 @@ client.context.create_context_template(
-
client.context.get_context_template(...) -
-
- -#### 📝 Description - +
client.graph.get_ontology(...) -> Ontology
-
-
- -Retrieves a context template by template_id. -
-
-
-
- #### 🔌 Usage
@@ -1788,12 +1664,15 @@ Retrieves a context template by template_id. ```python from zep_cloud import Zep +from zep_cloud.environment import ZepEnvironment client = Zep( - api_key="YOUR_API_KEY", + api_key="", + environment=ZepEnvironment.DEFAULT, ) -client.context.get_context_template( - template_id="template_id", + +client.graph.get_ontology( + graph_uuid="graph_uuid", ) ``` @@ -1810,7 +1689,7 @@ client.context.get_context_template(
-**template_id:** `str` — Template ID +**graph_uuid:** `str` — Graph UUID
@@ -1830,24 +1709,10 @@ client.context.get_context_template(
-
client.context.update_context_template(...) -
-
- -#### 📝 Description - -
-
- +
client.graph.set_ontology(...) -> Ontology
-Updates an existing context template by template_id. -
-
-
-
- #### 🔌 Usage
@@ -1858,13 +1723,15 @@ Updates an existing context template by template_id. ```python from zep_cloud import Zep +from zep_cloud.environment import ZepEnvironment client = Zep( - api_key="YOUR_API_KEY", + api_key="", + environment=ZepEnvironment.DEFAULT, ) -client.context.update_context_template( - template_id="template_id", - template="template", + +client.graph.set_ontology( + graph_uuid="graph_uuid", ) ``` @@ -1881,7 +1748,7 @@ client.context.update_context_template(
-**template_id:** `str` — Template ID +**graph_uuid:** `str` — Graph UUID
@@ -1889,7 +1756,7 @@ client.context.update_context_template(
-**template:** `str` — The template content (max 1200 characters). +**request:** `Ontology`
@@ -1909,24 +1776,10 @@ client.context.update_context_template(
-
client.context.delete_context_template(...) -
-
- -#### 📝 Description - -
-
- +
client.graph.search_edges(...) -> JsonObjectPage
-Deletes a context template by template_id. -
-
-
-
- #### 🔌 Usage
@@ -1937,12 +1790,17 @@ Deletes a context template by template_id. ```python from zep_cloud import Zep +from zep_cloud.environment import ZepEnvironment client = Zep( - api_key="YOUR_API_KEY", + api_key="", + environment=ZepEnvironment.DEFAULT, ) -client.context.delete_context_template( - template_id="template_id", + +client.graph.search_edges( + graph_uuid="graph_uuid", + limit=1, + cursor="cursor", ) ``` @@ -1959,7 +1817,7 @@ client.context.delete_context_template(
-**template_id:** `str` — Template ID +**graph_uuid:** `str` — Graph UUID
@@ -1967,37 +1825,46 @@ client.context.delete_context_template(
-**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. +**request:** `SearchRequest`
-
-
+
+
+**limit:** `typing.Optional[int]` — Page size +
-
-## Graph -
client.graph.list_custom_instructions(...)
-#### 📝 Description - -
-
+**cursor:** `typing.Optional[str]` — Opaque page cursor + +
+
-Lists all custom instructions for a project, user, or graph. +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. +
+ +
+
+
+ +
client.graph.search_episodes(...) -> JsonObjectPage +
+
+ #### 🔌 Usage
@@ -2008,13 +1875,17 @@ Lists all custom instructions for a project, user, or graph. ```python from zep_cloud import Zep +from zep_cloud.environment import ZepEnvironment client = Zep( - api_key="YOUR_API_KEY", + api_key="", + environment=ZepEnvironment.DEFAULT, ) -client.graph.list_custom_instructions( - user_id="user_id", - graph_id="graph_id", + +client.graph.search_episodes( + graph_uuid="graph_uuid", + limit=1, + cursor="cursor", ) ``` @@ -2031,7 +1902,7 @@ client.graph.list_custom_instructions(
-**user_id:** `typing.Optional[str]` — User ID to get user-specific instructions +**graph_uuid:** `str` — Graph UUID
@@ -2039,7 +1910,7 @@ client.graph.list_custom_instructions(
-**graph_id:** `typing.Optional[str]` — Graph ID to get graph-specific instructions +**request:** `SearchRequest`
@@ -2047,35 +1918,37 @@ client.graph.list_custom_instructions(
-**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. +**limit:** `typing.Optional[int]` — Page size
-
-
- - -
-
-
-
client.graph.add_custom_instructions(...)
-#### 📝 Description - -
-
+**cursor:** `typing.Optional[str]` — Opaque page cursor + +
+
-Adds new custom instructions for graphs without removing existing ones. If user_ids or graph_ids is empty, adds to project-wide default instructions. +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. + +
+
+ + +
+ +
client.graph.search_nodes(...) -> JsonObjectPage +
+
#### 🔌 Usage @@ -2086,18 +1959,18 @@ Adds new custom instructions for graphs without removing existing ones. If user_
```python -from zep_cloud import CustomInstruction, Zep +from zep_cloud import Zep +from zep_cloud.environment import ZepEnvironment client = Zep( - api_key="YOUR_API_KEY", + api_key="", + environment=ZepEnvironment.DEFAULT, ) -client.graph.add_custom_instructions( - instructions=[ - CustomInstruction( - name="name", - text="text", - ) - ], + +client.graph.search_nodes( + graph_uuid="graph_uuid", + limit=1, + cursor="cursor", ) ``` @@ -2114,7 +1987,15 @@ client.graph.add_custom_instructions(
-**instructions:** `typing.Sequence[CustomInstruction]` — Instructions to add to the graph. +**graph_uuid:** `str` — Graph UUID + +
+
+ +
+
+ +**request:** `SearchRequest`
@@ -2122,7 +2003,7 @@ client.graph.add_custom_instructions(
-**graph_ids:** `typing.Optional[typing.Sequence[str]]` — Graph IDs to add the instructions to. If empty, the instructions are added to the project-wide default. +**limit:** `typing.Optional[int]` — Page size
@@ -2130,7 +2011,7 @@ client.graph.add_custom_instructions(
-**user_ids:** `typing.Optional[typing.Sequence[str]]` — User IDs to add the instructions to. If empty, the instructions are added to the project-wide default. +**cursor:** `typing.Optional[str]` — Opaque page cursor
@@ -2150,24 +2031,10 @@ client.graph.add_custom_instructions(
-
client.graph.delete_custom_instructions(...) +
client.graph.search_observations(...) -> JsonObjectPage
-#### 📝 Description - -
-
- -
-
- -Deletes custom instructions for graphs or project wide defaults. -
-
-
-
- #### 🔌 Usage
@@ -2178,11 +2045,18 @@ Deletes custom instructions for graphs or project wide defaults. ```python from zep_cloud import Zep +from zep_cloud.environment import ZepEnvironment client = Zep( - api_key="YOUR_API_KEY", + api_key="", + environment=ZepEnvironment.DEFAULT, +) + +client.graph.search_observations( + graph_uuid="graph_uuid", + limit=1, + cursor="cursor", ) -client.graph.delete_custom_instructions() ```
@@ -2198,7 +2072,15 @@ client.graph.delete_custom_instructions()
-**graph_ids:** `typing.Optional[typing.Sequence[str]]` — Determines which group graphs will have their custom instructions deleted. If no graphs are provided, the project-wide custom instructions will be affected. +**graph_uuid:** `str` — Graph UUID + +
+
+ +
+
+ +**request:** `SearchRequest`
@@ -2206,7 +2088,7 @@ client.graph.delete_custom_instructions()
-**instruction_names:** `typing.Optional[typing.Sequence[str]]` — Unique identifier for the instructions to be deleted. If empty deletes all instructions. +**limit:** `typing.Optional[int]` — Page size
@@ -2214,7 +2096,7 @@ client.graph.delete_custom_instructions()
-**user_ids:** `typing.Optional[typing.Sequence[str]]` — Determines which user graphs will have their custom instructions deleted. If no users are provided, the project-wide custom instructions will be affected. +**cursor:** `typing.Optional[str]` — Opaque page cursor
@@ -2234,1897 +2116,11 @@ client.graph.delete_custom_instructions()
-
client.graph.list_entity_types(...) +
client.graph.search_thread_summaries(...) -> JsonObjectPage
-#### 📝 Description - -
-
- -
-
- -Returns all entity types for a project, user, or graph. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from zep_cloud import Zep - -client = Zep( - api_key="YOUR_API_KEY", -) -client.graph.list_entity_types( - user_id="user_id", - graph_id="graph_id", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**user_id:** `typing.Optional[str]` — User ID to get user-specific entity types - -
-
- -
-
- -**graph_id:** `typing.Optional[str]` — Graph ID to get graph-specific entity types - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.graph.set_entity_types_internal(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Sets the entity types for multiple users and graphs, replacing any existing ones. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from zep_cloud import Zep - -client = Zep( - api_key="YOUR_API_KEY", -) -client.graph.set_entity_types_internal() - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**edge_types:** `typing.Optional[typing.Sequence[EdgeType]]` - -
-
- -
-
- -**entity_types:** `typing.Optional[typing.Sequence[EntityType]]` - -
-
- -
-
- -**graph_ids:** `typing.Optional[typing.Sequence[str]]` - -
-
- -
-
- -**user_ids:** `typing.Optional[typing.Sequence[str]]` - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.graph.add(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Add data to the graph. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from zep_cloud import Zep - -client = Zep( - api_key="YOUR_API_KEY", -) -client.graph.add( - data="data", - type="text", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**data:** `str` - -
-
- -
-
- -**type:** `GraphDataType` - -
-
- -
-
- -**created_at:** `typing.Optional[str]` - -
-
- -
-
- -**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. - -
-
- -
-
- -**metadata:** `typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]]` — Optional metadata key-value pairs. Max 10 keys. Values must be strings, numbers, booleans, or arrays of scalars. - -
-
- -
-
- -**source_description:** `typing.Optional[str]` - -
-
- -
-
- -**strict_ontology:** `typing.Optional[bool]` — When true, prevents extraction of generic Entity nodes that do not match the configured ontology. - -
-
- -
-
- -**user_id:** `typing.Optional[str]` — User ID is the ID of the user to which the data will be added. If not adding to a user graph, please use graph_id field instead. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.graph.add_batch(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Deprecated. Use the [Batch API](/adding-batch-data) (`client.batch.*`) instead. - -Adds data to the graph in batch mode, processing episodes concurrently. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from zep_cloud import EpisodeData, Zep - -client = Zep( - api_key="YOUR_API_KEY", -) -client.graph.add_batch( - episodes=[ - EpisodeData( - data="data", - type="text", - ) - ], -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**episodes:** `typing.Sequence[EpisodeData]` - -
-
- -
-
- -**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. - -
-
- -
-
- -**strict_ontology:** `typing.Optional[bool]` — When true, prevents extraction of generic Entity nodes that do not match the configured ontology. - -
-
- -
-
- -**user_id:** `typing.Optional[str]` — User ID is the ID of the user to which the data will be added. If not adding to a user graph, please use graph_id field instead. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.graph.add_fact_triple(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Add a fact triple for a user or group -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from zep_cloud import Zep - -client = Zep( - api_key="YOUR_API_KEY", -) -client.graph.add_fact_triple( - fact="fact", - fact_name="fact_name", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**fact:** `str` — The fact relating the two nodes that this edge represents - -
-
- -
-
- -**fact_name:** `str` — The name of the edge to add. Should be all caps using snake case (eg RELATES_TO) - -
-
- -
-
- -**created_at:** `typing.Optional[str]` — The timestamp of the message - -
-
- -
-
- -**edge_attributes:** `typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]]` - -Additional attributes of the edge. Values must be scalar types (string, number, boolean, or null). -Nested objects and arrays are not allowed. - -
-
- -
-
- -**expired_at:** `typing.Optional[str]` — The time (if any) at which the edge expires - -
-
- -
-
- -**graph_id:** `typing.Optional[str]` - -
-
- -
-
- -**invalid_at:** `typing.Optional[str]` — The time (if any) at which the fact stops being true - -
-
- -
-
- -**metadata:** `typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]]` - -Optional metadata key-value pairs for the shadow episode created for this fact triple. -Max 10 keys. Values must be strings, numbers, or booleans. - -
-
- -
-
- -**source_node_attributes:** `typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]]` - -Additional attributes of the source node. Values must be scalar types (string, number, boolean, or null). -Nested objects and arrays are not allowed. - -
-
- -
-
- -**source_node_labels:** `typing.Optional[typing.Sequence[str]]` - -The labels for the source node. At most one entity-type label may be -provided so that manually-added triples remain consistent with automatic -episode extraction, which assigns one best-match entity type per node. -The base "Entity" label is added implicitly by the graph layer on save -and does not need to be supplied here. - -
-
- -
-
- -**source_node_name:** `typing.Optional[str]` — The name of the source node to add - -
-
- -
-
- -**source_node_summary:** `typing.Optional[str]` — The summary of the source node to add - -
-
- -
-
- -**source_node_uuid:** `typing.Optional[str]` — The source node uuid - -
-
- -
-
- -**target_node_attributes:** `typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]]` - -Additional attributes of the target node. Values must be scalar types (string, number, boolean, or null). -Nested objects and arrays are not allowed. - -
-
- -
-
- -**target_node_labels:** `typing.Optional[typing.Sequence[str]]` - -The labels for the target node. At most one entity-type label may be -provided so that manually-added triples remain consistent with automatic -episode extraction, which assigns one best-match entity type per node. -The base "Entity" label is added implicitly by the graph layer on save -and does not need to be supplied here. - -
-
- -
-
- -**target_node_name:** `typing.Optional[str]` — The name of the target node to add - -
-
- -
-
- -**target_node_summary:** `typing.Optional[str]` — The summary of the target node to add - -
-
- -
-
- -**target_node_uuid:** `typing.Optional[str]` — The target node uuid - -
-
- -
-
- -**user_id:** `typing.Optional[str]` - -
-
- -
-
- -**valid_at:** `typing.Optional[str]` — The time at which the fact becomes true - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.graph.clone(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Clone a user or group graph. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from zep_cloud import Zep - -client = Zep( - api_key="YOUR_API_KEY", -) -client.graph.clone() - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**source_graph_id:** `typing.Optional[str]` — source_graph_id is the ID of the graph to be cloned. Required if source_user_id is not provided - -
-
- -
-
- -**source_user_id:** `typing.Optional[str]` — user_id of the user whose graph is being cloned. Required if source_graph_id is not provided - -
-
- -
-
- -**target_graph_id:** `typing.Optional[str]` — target_graph_id is the ID to be set on the cloned graph. Must not point to an existing graph. Required if target_user_id is not provided. - -
-
- -
-
- -**target_user_id:** `typing.Optional[str]` — user_id to be set on the cloned user. Must not point to an existing user. Required if target_graph_id is not provided. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.graph.create(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Creates a new graph. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from zep_cloud import Zep - -client = Zep( - api_key="YOUR_API_KEY", -) -client.graph.create( - graph_id="graph_id", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**graph_id:** `str` - -
-
- -
-
- -**description:** `typing.Optional[str]` - -
-
- -
-
- -**name:** `typing.Optional[str]` - -
-
- -
-
- -**time_zone:** `typing.Optional[str]` — The graph's IANA time zone. Stored on its group-backed subject. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.graph.list_all(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Returns all graphs. In order to list users, use user.list_ordered instead -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from zep_cloud import Zep - -client = Zep( - api_key="YOUR_API_KEY", -) -client.graph.list_all( - page_number=1, - page_size=1, - search="search", - order_by="order_by", - asc=True, -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**page_number:** `typing.Optional[int]` — Page number for pagination, starting from 1. - -
-
- -
-
- -**page_size:** `typing.Optional[int]` — Number of graphs to retrieve per page (default 50, range 1-100; explicit 0 is invalid). - -
-
- -
-
- -**search:** `typing.Optional[str]` — Search term for filtering graphs by graph_id, name, or description. Queries longer than 200 Unicode code points after whitespace normalization are invalid. - -
-
- -
-
- -**order_by:** `typing.Optional[str]` — Column to sort by (created_at, graph_id, name). - -
-
- -
-
- -**asc:** `typing.Optional[bool]` — Sort in ascending order. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.graph.add_nodes(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Add entity nodes to a user or graph directly, without episode ingestion. Up to 100 nodes per request. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from zep_cloud import AddNodeItem, Zep - -client = Zep( - api_key="YOUR_API_KEY", -) -client.graph.add_nodes( - nodes=[ - AddNodeItem( - name="name", - ) - ], -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**nodes:** `typing.Sequence[AddNodeItem]` — The nodes to add. 1 to 100 items. - -
-
- -
-
- -**graph_id:** `typing.Optional[str]` - -
-
- -
-
- -**user_id:** `typing.Optional[str]` - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.graph.detect_patterns(...) -
-
- -#### 📝 Description - -
-
- -
-
- -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, -detects triple-frequency patterns, and returns resolved edges ranked by relevance. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from zep_cloud import Zep - -client = Zep( - api_key="YOUR_API_KEY", -) -client.graph.detect_patterns() - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**detect:** `typing.Optional[DetectConfig]` - -Which pattern types to detect with type-specific configuration. -Omit to detect all types with defaults. Ignored when query is set. - -
-
- -
-
- -**edge_limit:** `typing.Optional[int]` — Max resolved edges per pattern. Default: 10, Max: 100. Only used with query. - -
-
- -
-
- -**graph_id:** `typing.Optional[str]` — Graph ID when detecting patterns on a named graph - -
-
- -
-
- -**limit:** `typing.Optional[int]` — Max patterns to return. Default: 50, Max: 200 - -
-
- -
-
- -**min_occurrences:** `typing.Optional[int]` — Minimum occurrence count to report a pattern. Default: 2 - -
-
- -
-
- -**query:** `typing.Optional[str]` - -Search query for discovering seed nodes via hybrid search. -When set, forces triple-frequency detection only and enables edge resolution -with cross-encoder reranking. Mutually exclusive with seeds. - -
-
- -
-
- -**query_limit:** `typing.Optional[int]` — Max seed nodes from search. Default: 10, Max: 50. Only used with query. - -
-
- -
-
- -**recency_weight:** `typing.Optional[RecencyWeight]` - -Exponential half-life decay applied to edge created_at timestamps. -Valid values: none, 7_days, 30_days, 90_days. Default: none - -
-
- -
-
- -**search_filters:** `typing.Optional[SearchFilters]` - -Filters which edges/nodes participate in pattern detection. -Reuses the same filter format as /graph/search. - -
-
- -
-
- -**seeds:** `typing.Optional[PatternSeeds]` — Seed selection. If omitted, analyzes the entire graph. Mutually exclusive with query. - -
-
- -
-
- -**user_id:** `typing.Optional[str]` — User ID when detecting patterns on a user graph - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.graph.search(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Perform a graph search query. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from zep_cloud import Zep - -client = Zep( - api_key="YOUR_API_KEY", -) -client.graph.search( - query="query", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**query:** `str` — The string to search for (required) - -
-
- -
-
- -**bfs_origin_node_uuids:** `typing.Optional[typing.Sequence[str]]` — Nodes that are the origins of the BFS searches - -
-
- -
-
- -**center_node_uuid:** `typing.Optional[str]` — Node to rerank around for node distance reranking - -
-
- -
-
- -**graph_id:** `typing.Optional[str]` — The graph_id to search in. When searching user graph, please use user_id instead. - -
-
- -
-
- -**limit:** `typing.Optional[int]` — The maximum number of facts to retrieve for non-auto scopes. Defaults to 10. Limited to 50. Ignored when scope=auto. - -
-
- -
-
- -**max_characters:** `typing.Optional[int]` — Maximum total characters across all selected results when scope=auto. Defaults to 2500. Limited to 50000. - -
-
- -
-
- -**mmr_lambda:** `typing.Optional[float]` — weighting for maximal marginal relevance - -
-
- -
-
- -**reranker:** `typing.Optional[Reranker]` - -Defaults to RRF. Ignored when scope=auto except node_distance and episode_mentions are rejected; -auto search always uses RRF retrieval and applies its own internal rerank after retrieval. -episode_mentions ranks edge candidates by how many of the episodes listed -in search_filters.episode_uuids mention them; without episode_uuids it has -no effect and results are ranked as if no reranker were specified. - -
-
- -
-
- -**return_raw_results:** `typing.Optional[bool]` - -When scope=auto, include the selected raw graph results alongside the materialized context block. -For graph-service-backed auto mode, selected raw results may include episodes, -edges, nodes, observations, and thread_summaries. - -
-
- -
-
- -**scope:** `typing.Optional[GraphSearchScope]` — Defaults to Edges. - -
-
- -
-
- -**search_filters:** `typing.Optional[SearchFilters]` — Search filters to apply to the search - -
-
- -
-
- -**user_id:** `typing.Optional[str]` — The user_id when searching user graph. If not searching user graph, please use graph_id instead. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.graph.get_subgraph(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Returns the bounded neighborhood of a set of seed nodes as a single {nodes, edges} payload: breadth-first expansion up to a caller-specified depth, subject to explicit budgets, with explicit truncation reporting. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from zep_cloud import Zep - -client = Zep( - api_key="YOUR_API_KEY", -) -client.graph.get_subgraph( - seed_node_uuids=["seed_node_uuids"], -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**seed_node_uuids:** `typing.Sequence[str]` - -Seed node UUIDs to expand from, in traversal-priority order: seeds are -admitted before any expansion, in this order, and count toward -max_nodes first. 1-20 entries, required. Seeds that do not exist in -the target graph are ignored, not an error. - -
-
- -
-
- -**depth:** `typing.Optional[int]` — Maximum traversal depth from the seeds. 1-3. Defaults to 1. - -
-
- -
-
- -**direction:** `typing.Optional[str]` - -Edge orientation followed during expansion, relative to each frontier -node: "in" | "out" | "both". Defaults to "both". - -
-
- -
-
- -**graph_id:** `typing.Optional[str]` - -graph_id identifies the target named graph. Exactly one of user_id or -graph_id is required. - -
-
- -
-
- -**max_edges:** `typing.Optional[int]` — Maximum number of edges in the response. 1-1000. Defaults to 200. - -
-
- -
-
- -**max_nodes:** `typing.Optional[int]` - -Maximum number of nodes in the response, including admitted seeds. -1-500. Defaults to 100. - -
-
- -
-
- -**search_filters:** `typing.Optional[SearchFilters]` - -Filters constraining traversed edges and included nodes. Reuses the -graph.search filter type. search_filters.episode_metadata_filters is -rejected: it cannot be enforced during graph traversal (spec-2 §9.4). - -
-
- -
-
- -**user_id:** `typing.Optional[str]` - -user_id identifies the target user graph. Exactly one of user_id or -graph_id is required. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.graph.get(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Returns a graph. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from zep_cloud import Zep - -client = Zep( - api_key="YOUR_API_KEY", -) -client.graph.get( - graph_id="graphId", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**graph_id:** `str` — The graph_id of the graph to get. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.graph.delete(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Deletes a graph. If you would like to delete a user graph, make sure to use user.delete instead. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from zep_cloud import Zep - -client = Zep( - api_key="YOUR_API_KEY", -) -client.graph.delete( - graph_id="graphId", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**graph_id:** `str` — Graph ID - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.graph.update(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Updates information about a graph. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from zep_cloud import Zep - -client = Zep( - api_key="YOUR_API_KEY", -) -client.graph.update( - graph_id="graphId", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**graph_id:** `str` — Graph ID - -
-
- -
-
- -**description:** `typing.Optional[str]` - -
-
- -
-
- -**name:** `typing.Optional[str]` - -
-
- -
-
- -**time_zone:** `typing.Optional[str]` — The graph's IANA time zone. Stored on its group-backed subject. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.graph.warm(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Hints Zep to warm a graph for low-latency search -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from zep_cloud import Zep - -client = Zep( - api_key="YOUR_API_KEY", -) -client.graph.warm( - graph_id="graphId", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**graph_id:** `str` — The graph_id of the graph to warm. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -## Project -
client.project.get() -
-
- -#### 📝 Description - -
-
- -
-
- -Retrieve project info based on the provided api key. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from zep_cloud import Zep - -client = Zep( - api_key="YOUR_API_KEY", -) -client.project.get() - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.project.update(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Sets or clears the project-level fallback time zone for the API key's project. -
-
-
-
- -#### 🔌 Usage +#### 🔌 Usage
@@ -4134,11 +2130,18 @@ Sets or clears the project-level fallback time zone for the API key's project. ```python from zep_cloud import Zep +from zep_cloud.environment import ZepEnvironment client = Zep( - api_key="YOUR_API_KEY", + api_key="", + environment=ZepEnvironment.DEFAULT, +) + +client.graph.search_thread_summaries( + graph_uuid="graph_uuid", + limit=1, + cursor="cursor", ) -client.project.update() ```
@@ -4154,7 +2157,7 @@ client.project.update()
-**default_time_zone:** `typing.Optional[str]` — The project's IANA fallback time zone. Null clears the existing value. +**graph_uuid:** `str` — Graph UUID
@@ -4162,70 +2165,15 @@ client.project.update()
-**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. +**request:** `SearchRequest`
-
-
- - - - -
- -
client.project.get_observation_steering(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Returns project steering or the effective user/graph steering with project fallback. This API is experimental and may change in future releases. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from zep_cloud import Zep - -client = Zep( - api_key="YOUR_API_KEY", -) -client.project.get_observation_steering( - user_id="user_id", - graph_id="graph_id", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
-**user_id:** `typing.Optional[str]` — User ID for user-specific steering +**limit:** `typing.Optional[int]` — Page size
@@ -4233,7 +2181,7 @@ client.project.get_observation_steering(
-**graph_id:** `typing.Optional[str]` — Graph ID for graph-specific steering +**cursor:** `typing.Optional[str]` — Opaque page cursor
@@ -4253,24 +2201,10 @@ client.project.get_observation_steering(
-
client.project.set_observation_steering(...) -
-
- -#### 📝 Description - -
-
- +
client.graph.get_subgraph(...) -> JsonObject
-Replaces project, user, or graph steering. An empty configuration clears the project default or removes the user/graph override. Changes affect later materializer runs only. This API is experimental and may change in future releases. -
-
-
-
- #### 🔌 Usage
@@ -4281,13 +2215,15 @@ Replaces project, user, or graph steering. An empty configuration clears the pro ```python from zep_cloud import Zep +from zep_cloud.environment import ZepEnvironment client = Zep( - api_key="YOUR_API_KEY", + api_key="", + environment=ZepEnvironment.DEFAULT, ) -client.project.set_observation_steering( - user_id="user_id", - graph_id="graph_id", + +client.graph.get_subgraph( + graph_uuid="graph_uuid", ) ``` @@ -4304,7 +2240,7 @@ client.project.set_observation_steering(
-**user_id:** `typing.Optional[str]` — User ID for user-specific steering +**graph_uuid:** `str` — Graph UUID
@@ -4312,7 +2248,7 @@ client.project.set_observation_steering(
-**graph_id:** `typing.Optional[str]` — Graph ID for graph-specific steering +**depth:** `typing.Optional[int]`
@@ -4320,7 +2256,7 @@ client.project.set_observation_steering(
-**instruction:** `typing.Optional[str]` +**direction:** `typing.Optional[str]`
@@ -4328,7 +2264,7 @@ client.project.set_observation_steering(
-**types:** `typing.Optional[typing.Sequence[ObservationType]]` +**filters:** `typing.Optional[typing.Dict[str, typing.Any]]`
@@ -4336,70 +2272,23 @@ client.project.set_observation_steering(
-**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. +**max_edges:** `typing.Optional[int]`
-
-
- - - - -
- -## Task -
client.task.get(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Gets a task by its ID -
-
-
-
- -#### 🔌 Usage - -
-
-```python -from zep_cloud import Zep - -client = Zep( - api_key="YOUR_API_KEY", -) -client.task.get( - task_id="task_id", -) - -``` -
-
+**max_nodes:** `typing.Optional[int]` +
-#### ⚙️ Parameters - -
-
-
-**task_id:** `str` — Task ID +**seed_node_uuids:** `typing.Optional[typing.List[str]]`
@@ -4419,25 +2308,10 @@ client.task.get(
-## Thread -
client.thread.list_all(...) -
-
- -#### 📝 Description - -
-
- +
client.graph.warm(...) -> AsyncResult
-Returns all threads. -
-
-
-
- #### 🔌 Usage
@@ -4448,15 +2322,15 @@ Returns all threads. ```python from zep_cloud import Zep +from zep_cloud.environment import ZepEnvironment client = Zep( - api_key="YOUR_API_KEY", + api_key="", + environment=ZepEnvironment.DEFAULT, ) -client.thread.list_all( - page_number=1, - page_size=1, - order_by="order_by", - asc=True, + +client.graph.warm( + graph_uuid="graph_uuid", ) ``` @@ -4473,31 +2347,7 @@ client.thread.list_all(
-**page_number:** `typing.Optional[int]` — Page number for pagination, starting from 1 - -
-
- -
-
- -**page_size:** `typing.Optional[int]` — Number of threads to retrieve per page. - -
-
- -
-
- -**order_by:** `typing.Optional[str]` — Field to order the results by: created_at, updated_at, user_id, thread_id. - -
-
- -
-
- -**asc:** `typing.Optional[bool]` — Order direction: true for ascending, false for descending. +**graph_uuid:** `str` — Graph UUID
@@ -4517,24 +2367,11 @@ client.thread.list_all(
-
client.thread.create(...) -
-
- -#### 📝 Description - -
-
- +## Lookup +
client.lookup.batch(...) -> LookupBatchResponse
-Start a new thread. -
-
-
-
- #### 🔌 Usage
@@ -4545,15 +2382,15 @@ Start a new thread. ```python from zep_cloud import Zep +from zep_cloud.environment import ZepEnvironment client = Zep( - api_key="YOUR_API_KEY", -) -client.thread.create( - thread_id="thread_id", - user_id="user_id", + api_key="", + environment=ZepEnvironment.DEFAULT, ) +client.lookup.batch() + ```
@@ -4568,7 +2405,15 @@ client.thread.create(
-**thread_id:** `str` — The unique identifier of the thread. +**graphs:** `typing.Optional[typing.List[str]]` + +
+
+ +
+
+ +**threads:** `typing.Optional[typing.List[str]]`
@@ -4576,7 +2421,7 @@ client.thread.create(
-**user_id:** `str` — The unique identifier of the user associated with the thread +**users:** `typing.Optional[typing.List[str]]`
@@ -4596,24 +2441,11 @@ client.thread.create(
-
client.thread.delete(...) -
-
- -#### 📝 Description - -
-
- +## Project +
client.project.get() -> Project
-Deletes a thread. -
-
-
-
- #### 🔌 Usage
@@ -4624,14 +2456,15 @@ Deletes a thread. ```python from zep_cloud import Zep +from zep_cloud.environment import ZepEnvironment client = Zep( - api_key="YOUR_API_KEY", -) -client.thread.delete( - thread_id="threadId", + api_key="", + environment=ZepEnvironment.DEFAULT, ) +client.project.get() + ```
@@ -4646,14 +2479,6 @@ client.thread.delete(
-**thread_id:** `str` — The ID of the thread for which memory should be deleted. - -
-
- -
-
- **request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
@@ -4666,24 +2491,10 @@ client.thread.delete(
-
client.thread.get_user_context(...) -
-
- -#### 📝 Description - -
-
- +
client.project.update(...) -> Project
-Returns most relevant context from the user graph (including memory from any/all past threads) based on the content of the past few messages of the given thread. -
-
-
-
- #### 🔌 Usage
@@ -4694,15 +2505,15 @@ Returns most relevant context from the user graph (including memory from any/all ```python from zep_cloud import Zep +from zep_cloud.environment import ZepEnvironment client = Zep( - api_key="YOUR_API_KEY", -) -client.thread.get_user_context( - thread_id="threadId", - template_id="template_id", + api_key="", + environment=ZepEnvironment.DEFAULT, ) +client.project.update() + ```
@@ -4717,15 +2528,7 @@ client.thread.get_user_context(
-**thread_id:** `str` — The ID of the current thread (for which context is being retrieved). - -
-
- -
-
- -**template_id:** `typing.Optional[str]` — Optional template ID to use for custom context rendering. +**default_time_zone:** `typing.Optional[str]` — Omit to leave unchanged, send JSON null to clear, or send a value to set.
@@ -4743,25 +2546,11 @@ client.thread.get_user_context( -
- -
client.thread.get(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Returns messages for a thread. -
-
-
-
+
+ +
client.project.get_instructions() -> Instructions +
+
#### 🔌 Usage @@ -4773,17 +2562,15 @@ Returns messages for a thread. ```python from zep_cloud import Zep +from zep_cloud.environment import ZepEnvironment client = Zep( - api_key="YOUR_API_KEY", -) -client.thread.get( - thread_id="threadId", - limit=1, - cursor=1, - lastn=1, + api_key="", + environment=ZepEnvironment.DEFAULT, ) +client.project.get_instructions() + ```
@@ -4798,31 +2585,56 @@ client.thread.get(
-**thread_id:** `str` — Thread ID +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+ + -
-
-**limit:** `typing.Optional[int]` — Limit the number of results returned -
+
+
client.project.set_instructions(...) -> Instructions
-**cursor:** `typing.Optional[int]` — Cursor for pagination - +#### 🔌 Usage + +
+
+ +
+
+ +```python +from zep_cloud import Zep +from zep_cloud.environment import ZepEnvironment + +client = Zep( + api_key="", + environment=ZepEnvironment.DEFAULT, +) + +client.project.set_instructions() + +```
+
+
+ +#### ⚙️ Parameters
-**lastn:** `typing.Optional[int]` — Number of most recent messages to return (overrides limit and cursor) +
+
+ +**request:** `Instructions`
@@ -4842,24 +2654,10 @@ client.thread.get(
-
client.thread.add_messages(...) -
-
- -#### 📝 Description - -
-
- +
client.project.get_observation_steering() -> ObservationSteering
-Add messages to a thread. -
-
-
-
- #### 🔌 Usage
@@ -4869,21 +2667,16 @@ Add messages to a thread.
```python -from zep_cloud import Message, Zep +from zep_cloud import Zep +from zep_cloud.environment import ZepEnvironment client = Zep( - api_key="YOUR_API_KEY", -) -client.thread.add_messages( - thread_id="threadId", - messages=[ - Message( - content="content", - role="norole", - ) - ], + api_key="", + environment=ZepEnvironment.DEFAULT, ) +client.project.get_observation_steering() + ```
@@ -4898,43 +2691,56 @@ client.thread.add_messages(
-**thread_id:** `str` — The ID of the thread to which messages should be added. +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
-
-
-**messages:** `typing.Sequence[Message]` — A list of message objects, where each message contains a role and content. -
+
+
client.project.set_observation_steering(...) -> ObservationSteering
-**ignore_roles:** `typing.Optional[typing.Sequence[RoleType]]` +#### 🔌 Usage -Optional list of role types to ignore when adding messages to graph memory. -The message itself will still be added, retained and used as context for messages -that are added to a user's graph. - -
-
+
+
-**return_context:** `typing.Optional[bool]` — Optionally return context block relevant to the most recent messages. - +```python +from zep_cloud import Zep +from zep_cloud.environment import ZepEnvironment + +client = Zep( + api_key="", + environment=ZepEnvironment.DEFAULT, +) + +client.project.set_observation_steering() + +``` +
+
+#### ⚙️ Parameters + +
+
+
-**strict_ontology:** `typing.Optional[bool]` — When true, prevents extraction of generic Entity nodes that do not match the configured ontology. +**request:** `ObservationSteering`
@@ -4954,26 +2760,10 @@ that are added to a user's graph.
-
client.thread.add_messages_batch(...) -
-
- -#### 📝 Description - +
client.project.get_ontology() -> Ontology
-
-
- -Deprecated. Use the [Batch API](/adding-batch-data) (`client.batch.*` with `type: "thread_message"`) instead. - -Adds messages to a thread in batch mode, processing messages concurrently. -
-
-
-
- #### 🔌 Usage
@@ -4983,21 +2773,16 @@ Adds messages to a thread in batch mode, processing messages concurrently.
```python -from zep_cloud import Message, Zep +from zep_cloud import Zep +from zep_cloud.environment import ZepEnvironment client = Zep( - api_key="YOUR_API_KEY", -) -client.thread.add_messages_batch( - thread_id="threadId", - messages=[ - Message( - content="content", - role="norole", - ) - ], + api_key="", + environment=ZepEnvironment.DEFAULT, ) +client.project.get_ontology() + ```
@@ -5012,43 +2797,56 @@ client.thread.add_messages_batch(
-**thread_id:** `str` — The ID of the thread to which messages should be added. +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
-
-
-**messages:** `typing.Sequence[Message]` — A list of message objects, where each message contains a role and content. -
+
+
client.project.set_ontology(...) -> Ontology
-**ignore_roles:** `typing.Optional[typing.Sequence[RoleType]]` +#### 🔌 Usage -Optional list of role types to ignore when adding messages to graph memory. -The message itself will still be added, retained and used as context for messages -that are added to a user's graph. - -
-
+
+
-**return_context:** `typing.Optional[bool]` — Optionally return context block relevant to the most recent messages. - +```python +from zep_cloud import Zep +from zep_cloud.environment import ZepEnvironment + +client = Zep( + api_key="", + environment=ZepEnvironment.DEFAULT, +) + +client.project.set_ontology() + +``` +
+
+#### ⚙️ Parameters + +
+
+
-**strict_ontology:** `typing.Optional[bool]` — When true, prevents extraction of generic Entity nodes that do not match the configured ontology. +**request:** `Ontology`
@@ -5068,24 +2866,10 @@ that are added to a user's graph.
-
client.thread.get_summary(...) -
-
- -#### 📝 Description - -
-
- +
client.project.get_user_summary_instructions() -> UserSummaryInstructions
-Returns the incremental summary generated from messages in the thread. Returns 404 if no summary exists for the thread. -
-
-
-
- #### 🔌 Usage
@@ -5096,14 +2880,15 @@ Returns the incremental summary generated from messages in the thread. Returns 4 ```python from zep_cloud import Zep +from zep_cloud.environment import ZepEnvironment client = Zep( - api_key="YOUR_API_KEY", -) -client.thread.get_summary( - thread_id="threadId", + api_key="", + environment=ZepEnvironment.DEFAULT, ) +client.project.get_user_summary_instructions() + ```
@@ -5118,14 +2903,6 @@ client.thread.get_summary(
-**thread_id:** `str` — The thread ID. - -
-
- -
-
- **request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
@@ -5138,25 +2915,10 @@ client.thread.get_summary(
-## User -
client.user.list_user_summary_instructions(...) -
-
- -#### 📝 Description - +
client.project.set_user_summary_instructions(...) -> UserSummaryInstructions
-
-
- -Lists all user summary instructions for a project, user. -
-
-
-
- #### 🔌 Usage
@@ -5167,14 +2929,15 @@ Lists all user summary instructions for a project, user. ```python from zep_cloud import Zep +from zep_cloud.environment import ZepEnvironment client = Zep( - api_key="YOUR_API_KEY", -) -client.user.list_user_summary_instructions( - user_id="user_id", + api_key="", + environment=ZepEnvironment.DEFAULT, ) +client.project.set_user_summary_instructions() + ```
@@ -5189,7 +2952,7 @@ client.user.list_user_summary_instructions(
-**user_id:** `typing.Optional[str]` — User ID to get user-specific instructions +**request:** `UserSummaryInstructions`
@@ -5209,24 +2972,11 @@ client.user.list_user_summary_instructions(
-
client.user.add_user_summary_instructions(...) -
-
- -#### 📝 Description - -
-
- +## Task +
client.task.list(...) -> TaskPage
-Adds new summary instructions for users graphs without removing existing ones. If user_ids is empty, adds to project-wide default instructions. -
-
-
-
- #### 🔌 Usage
@@ -5236,18 +2986,17 @@ Adds new summary instructions for users graphs without removing existing ones. I
```python -from zep_cloud import UserInstruction, Zep +from zep_cloud import Zep +from zep_cloud.environment import ZepEnvironment client = Zep( - api_key="YOUR_API_KEY", + api_key="", + environment=ZepEnvironment.DEFAULT, ) -client.user.add_user_summary_instructions( - instructions=[ - UserInstruction( - name="name", - text="text", - ) - ], + +client.task.list( + limit=1, + cursor="cursor", ) ``` @@ -5264,7 +3013,7 @@ client.user.add_user_summary_instructions(
-**instructions:** `typing.Sequence[UserInstruction]` — Instructions to add to the user summary generation. +**limit:** `typing.Optional[int]` — Page size
@@ -5272,7 +3021,7 @@ client.user.add_user_summary_instructions(
-**user_ids:** `typing.Optional[typing.Sequence[str]]` — User IDs to add the instructions to. If empty, the instructions are added to the project-wide default. +**cursor:** `typing.Optional[str]` — Opaque page cursor
@@ -5292,24 +3041,10 @@ client.user.add_user_summary_instructions(
-
client.user.delete_user_summary_instructions(...) -
-
- -#### 📝 Description - -
-
- +
client.task.get(...) -> Task
-Deletes user summary/instructions for users or project wide defaults. -
-
-
-
- #### 🔌 Usage
@@ -5320,11 +3055,16 @@ Deletes user summary/instructions for users or project wide defaults. ```python from zep_cloud import Zep +from zep_cloud.environment import ZepEnvironment client = Zep( - api_key="YOUR_API_KEY", + api_key="", + environment=ZepEnvironment.DEFAULT, +) + +client.task.get( + task_uuid="task_uuid", ) -client.user.delete_user_summary_instructions() ```
@@ -5340,15 +3080,7 @@ client.user.delete_user_summary_instructions()
-**instruction_names:** `typing.Optional[typing.Sequence[str]]` — Unique identifier for the instructions to be deleted. If empty deletes all instructions. - -
-
- -
-
- -**user_ids:** `typing.Optional[typing.Sequence[str]]` — Determines which users will have their custom instructions deleted. If no users are provided, the project-wide custom instructions will be effected. +**task_uuid:** `str` — Task UUID
@@ -5368,24 +3100,11 @@ client.user.delete_user_summary_instructions()
-
client.user.add(...) -
-
- -#### 📝 Description - -
-
- +## Thread +
client.thread.list(...) -> ThreadPage
-Adds a user. -
-
-
-
- #### 🔌 Usage
@@ -5396,12 +3115,19 @@ Adds a user. ```python from zep_cloud import Zep +from zep_cloud.environment import ZepEnvironment client = Zep( - api_key="YOUR_API_KEY", + api_key="", + environment=ZepEnvironment.DEFAULT, ) -client.user.add( - user_id="user_id", + +client.thread.list( + limit=1, + cursor="cursor", + order_by="order_by", + order="order", + user_uuid="user_uuid", ) ``` @@ -5418,31 +3144,7 @@ client.user.add(
-**user_id:** `str` — The unique identifier of the user. - -
-
- -
-
- -**disable_default_ontology:** `typing.Optional[bool]` — When true, disables the use of default/fallback ontology for the user's graph. - -
-
- -
-
- -**email:** `typing.Optional[str]` — The email address of the user. - -
-
- -
-
- -**first_name:** `typing.Optional[str]` — The first name of the user. +**limit:** `typing.Optional[int]` — Page size
@@ -5450,7 +3152,7 @@ client.user.add(
-**last_name:** `typing.Optional[str]` — The last name of the user. +**cursor:** `typing.Optional[str]` — Opaque page cursor
@@ -5458,7 +3160,7 @@ client.user.add(
-**metadata:** `typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]]` — The metadata associated with the user. +**order_by:** `typing.Optional[str]` — Sort field
@@ -5466,7 +3168,7 @@ client.user.add(
-**time_zone:** `typing.Optional[str]` — The user's IANA time zone. Null or omission leaves it unset at creation. +**order:** `typing.Optional[str]` — asc or desc
@@ -5474,35 +3176,29 @@ client.user.add(
-**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. +**user_uuid:** `typing.Optional[str]` — Filter by user UUID
-
-
- - - - -
- -
client.user.list_ordered(...) -
-
- -#### 📝 Description - -
-
-Returns all users. +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. + +
+
+ +
+
+ +
client.thread.create(...) -> Thread +
+
#### 🔌 Usage @@ -5514,18 +3210,15 @@ Returns all users. ```python from zep_cloud import Zep +from zep_cloud.environment import ZepEnvironment client = Zep( - api_key="YOUR_API_KEY", -) -client.user.list_ordered( - page_number=1, - page_size=1, - search="search", - order_by="order_by", - asc=True, + api_key="", + environment=ZepEnvironment.DEFAULT, ) +client.thread.create() + ```
@@ -5540,7 +3233,7 @@ client.user.list_ordered(
-**page_number:** `typing.Optional[int]` — Page number for pagination, starting from 1 +**thread_id:** `typing.Optional[str]`
@@ -5548,7 +3241,7 @@ client.user.list_ordered(
-**page_size:** `typing.Optional[int]` — Number of users to retrieve per page +**user_uuid:** `typing.Optional[str]`
@@ -5556,59 +3249,78 @@ client.user.list_ordered(
-**search:** `typing.Optional[str]` — Search term for filtering users by user_id, name, or email +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+ + -
-
-**order_by:** `typing.Optional[str]` — Column to sort by (created_at, user_id, email) -
+
+
client.thread.lookup(...) -> Thread
-**asc:** `typing.Optional[bool]` — Sort in ascending order - -
-
+#### 🔌 Usage
-**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - +
+
+ +```python +from zep_cloud import Zep +from zep_cloud.environment import ZepEnvironment + +client = Zep( + api_key="", + environment=ZepEnvironment.DEFAULT, +) + +client.thread.lookup() + +```
+#### ⚙️ Parameters - - -
- -
client.user.get(...)
-#### 📝 Description -
+**request:** `LookupRequest` + +
+
+
-Returns a user. +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. + +
+
+ + +
+ +
client.thread.get(...) -> Thread +
+
#### 🔌 Usage @@ -5620,12 +3332,15 @@ Returns a user. ```python from zep_cloud import Zep +from zep_cloud.environment import ZepEnvironment client = Zep( - api_key="YOUR_API_KEY", + api_key="", + environment=ZepEnvironment.DEFAULT, ) -client.user.get( - user_id="userId", + +client.thread.get( + thread_uuid="thread_uuid", ) ``` @@ -5642,7 +3357,7 @@ client.user.get(
-**user_id:** `str` — The user_id of the user to get. +**thread_uuid:** `str` — Thread UUID
@@ -5662,24 +3377,10 @@ client.user.get(
-
client.user.delete(...) -
-
- -#### 📝 Description - +
client.thread.delete(...) -> ThreadDeleteResult
-
-
- -Deletes a user. -
-
-
-
- #### 🔌 Usage
@@ -5690,12 +3391,15 @@ Deletes a user. ```python from zep_cloud import Zep +from zep_cloud.environment import ZepEnvironment client = Zep( - api_key="YOUR_API_KEY", + api_key="", + environment=ZepEnvironment.DEFAULT, ) -client.user.delete( - user_id="userId", + +client.thread.delete( + thread_uuid="thread_uuid", ) ``` @@ -5712,7 +3416,7 @@ client.user.delete(
-**user_id:** `str` — User ID +**thread_uuid:** `str` — Thread UUID
@@ -5732,24 +3436,10 @@ client.user.delete(
-
client.user.update(...) -
-
- -#### 📝 Description - -
-
- +
client.thread.get_context(...) -> ThreadContextResponse
-Updates a user. -
-
-
-
- #### 🔌 Usage
@@ -5760,12 +3450,16 @@ Updates a user. ```python from zep_cloud import Zep +from zep_cloud.environment import ZepEnvironment client = Zep( - api_key="YOUR_API_KEY", + api_key="", + environment=ZepEnvironment.DEFAULT, ) -client.user.update( - user_id="userId", + +client.thread.get_context( + thread_uuid="thread_uuid", + template_uuid="template_uuid", ) ``` @@ -5782,7 +3476,7 @@ client.user.update(
-**user_id:** `str` — User ID +**thread_uuid:** `str` — Thread UUID
@@ -5790,7 +3484,7 @@ client.user.update(
-**disable_default_ontology:** `typing.Optional[bool]` — When true, disables the use of default/fallback ontology for the user's graph. +**template_uuid:** `typing.Optional[str]` — Context template UUID
@@ -5798,23 +3492,60 @@ client.user.update(
-**email:** `typing.Optional[str]` — The email address of the user. +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+ + +
+
+
+
client.thread.list_episodes(...) -> JsonObjectPage
-**first_name:** `typing.Optional[str]` — The first name of the user. - +#### 🔌 Usage + +
+
+ +
+
+ +```python +from zep_cloud import Zep +from zep_cloud.environment import ZepEnvironment + +client = Zep( + api_key="", + environment=ZepEnvironment.DEFAULT, +) + +client.thread.list_episodes( + thread_uuid="thread_uuid", + limit=1, + cursor="cursor", +) + +```
+
+
+ +#### ⚙️ Parameters
-**last_name:** `typing.Optional[str]` — The last name of the user. +
+
+ +**thread_uuid:** `str` — Thread UUID
@@ -5822,7 +3553,7 @@ client.user.update(
-**metadata:** `typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]]` — The metadata to update +**limit:** `typing.Optional[int]` — Page size
@@ -5830,7 +3561,7 @@ client.user.update(
-**time_zone:** `typing.Optional[str]` — The user's IANA time zone. Null clears the existing value. +**cursor:** `typing.Optional[str]` — Opaque page cursor
@@ -5850,24 +3581,10 @@ client.user.update(
-
client.user.get_node(...) -
-
- -#### 📝 Description - -
-
- +
client.thread.list_messages(...) -> MessagePage
-Returns a user's node. -
-
-
-
- #### 🔌 Usage
@@ -5878,12 +3595,17 @@ Returns a user's node. ```python from zep_cloud import Zep +from zep_cloud.environment import ZepEnvironment client = Zep( - api_key="YOUR_API_KEY", + api_key="", + environment=ZepEnvironment.DEFAULT, ) -client.user.get_node( - user_id="userId", + +client.thread.list_messages( + thread_uuid="thread_uuid", + limit=1, + cursor="cursor", ) ``` @@ -5900,7 +3622,7 @@ client.user.get_node(
-**user_id:** `str` — The user_id of the user to get the node for. +**thread_uuid:** `str` — Thread UUID
@@ -5908,35 +3630,37 @@ client.user.get_node(
-**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. +**limit:** `typing.Optional[int]` — Page size
-
-
- - - - -
-
client.user.get_threads(...)
-#### 📝 Description - -
-
+**cursor:** `typing.Optional[str]` — Opaque page cursor + +
+
-Returns all threads for a user. +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. + +
+
+ + +
+ +
client.thread.add_messages(...) -> AddMessagesResult +
+
#### 🔌 Usage @@ -5948,12 +3672,15 @@ Returns all threads for a user. ```python from zep_cloud import Zep +from zep_cloud.environment import ZepEnvironment client = Zep( - api_key="YOUR_API_KEY", + api_key="", + environment=ZepEnvironment.DEFAULT, ) -client.user.get_threads( - user_id="userId", + +client.thread.add_messages( + thread_uuid="thread_uuid", ) ``` @@ -5970,7 +3697,7 @@ client.user.get_threads(
-**user_id:** `str` — User ID +**thread_uuid:** `str` — Thread UUID
@@ -5978,36 +3705,54 @@ client.user.get_threads(
-**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. +**ignore_roles:** `typing.Optional[typing.List[str]]`
-
-
+
+
+**messages:** `typing.Optional[typing.List[AddMessage]]` +
-
-
client.user.warm(...)
-#### 📝 Description +**return_context:** `typing.Optional[bool]` + +
+
+**strict_ontology:** `typing.Optional[bool]` + +
+
+
-Hints Zep to warm a user's graph for low-latency search +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. +
+ + + +
+ +
client.thread.get_summary(...) -> ThreadSummary +
+
+ #### 🔌 Usage
@@ -6018,12 +3763,15 @@ Hints Zep to warm a user's graph for low-latency search ```python from zep_cloud import Zep +from zep_cloud.environment import ZepEnvironment client = Zep( - api_key="YOUR_API_KEY", + api_key="", + environment=ZepEnvironment.DEFAULT, ) -client.user.warm( - user_id="userId", + +client.thread.get_summary( + thread_uuid="thread_uuid", ) ``` @@ -6040,7 +3788,7 @@ client.user.warm(
-**user_id:** `str` — User ID +**thread_uuid:** `str` — Thread UUID
@@ -6060,25 +3808,11 @@ client.user.warm(
-## Graph Edge -
client.graph.edge.get_by_graph_id(...) -
-
- -#### 📝 Description - -
-
- +## User +
client.user.create(...) -> User
-Returns all edges for a graph. -
-
-
-
- #### 🔌 Usage
@@ -6089,14 +3823,15 @@ Returns all edges for a graph. ```python from zep_cloud import Zep +from zep_cloud.environment import ZepEnvironment client = Zep( - api_key="YOUR_API_KEY", -) -client.graph.edge.get_by_graph_id( - graph_id="graph_id", + api_key="", + environment=ZepEnvironment.DEFAULT, ) +client.user.create() + ```
@@ -6111,7 +3846,7 @@ client.graph.edge.get_by_graph_id(
-**graph_id:** `str` — Graph ID +**disable_default_ontology:** `typing.Optional[bool]`
@@ -6119,10 +3854,7 @@ client.graph.edge.get_by_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. +**email:** `typing.Optional[str]`
@@ -6130,7 +3862,7 @@ of the previous page. Encodes the sort field, direction, and continuation positi
-**direction:** `typing.Optional[str]` — Sort direction. One of "asc" or "desc" (default "desc"). +**first_name:** `typing.Optional[str]`
@@ -6138,7 +3870,7 @@ of the previous page. Encodes the sort field, direction, and continuation positi
-**filters:** `typing.Optional[SearchFilters]` — Optional filters applied to the listed artifacts. Reuses the graph.search filter type. +**last_name:** `typing.Optional[str]`
@@ -6146,7 +3878,7 @@ of the previous page. Encodes the sort field, direction, and continuation positi
-**limit:** `typing.Optional[int]` — Maximum number of items to return +**metadata:** `typing.Optional[typing.Dict[str, typing.Any]]`
@@ -6154,7 +3886,7 @@ of the previous page. Encodes the sort field, direction, and continuation positi
-**order_by:** `typing.Optional[str]` — Field to sort by. One of "created_at", "valid_at", or "uuid" (default "uuid"). +**time_zone:** `typing.Optional[str]`
@@ -6162,11 +3894,7 @@ of the previous page. Encodes the sort field, direction, and continuation positi
-**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. +**user_id:** `typing.Optional[str]`
@@ -6186,24 +3914,10 @@ Deprecated: prefer Cursor, the opaque cursor returned via the Zep-Next-Cursor re
-
client.graph.edge.get_by_user_id(...) -
-
- -#### 📝 Description - -
-
- +
client.user.list(...) -> UserPage
-Returns all edges for a user. -
-
-
-
- #### 🔌 Usage
@@ -6214,12 +3928,18 @@ Returns all edges for a user. ```python from zep_cloud import Zep +from zep_cloud.environment import ZepEnvironment client = Zep( - api_key="YOUR_API_KEY", + api_key="", + environment=ZepEnvironment.DEFAULT, ) -client.graph.edge.get_by_user_id( - user_id="user_id", + +client.user.list( + limit=1, + cursor="cursor", + order_by="order_by", + order="order", ) ``` @@ -6236,7 +3956,7 @@ client.graph.edge.get_by_user_id(
-**user_id:** `str` — User ID +**limit:** `typing.Optional[int]` — Page size
@@ -6244,10 +3964,15 @@ client.graph.edge.get_by_user_id(
-**cursor:** `typing.Optional[str]` +**cursor:** `typing.Optional[str]` — Opaque page cursor + +
+
+ +
+
-Opaque cursor for pagination, obtained from the Zep-Next-Cursor response header -of the previous page. Encodes the sort field, direction, and continuation position. +**order_by:** `typing.Optional[str]` — Sort field
@@ -6255,7 +3980,7 @@ of the previous page. Encodes the sort field, direction, and continuation positi
-**direction:** `typing.Optional[str]` — Sort direction. One of "asc" or "desc" (default "desc"). +**order:** `typing.Optional[str]` — asc or desc
@@ -6263,7 +3988,7 @@ of the previous page. Encodes the sort field, direction, and continuation positi
-**filters:** `typing.Optional[SearchFilters]` — Optional filters applied to the listed artifacts. Reuses the graph.search filter type. +**search:** `typing.Optional[str]`
@@ -6271,27 +3996,56 @@ of the previous page. Encodes the sort field, direction, and continuation positi
-**limit:** `typing.Optional[int]` — Maximum number of items to return +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+ + + + +
+ +
client.user.lookup(...) -> User +
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```python +from zep_cloud import Zep +from zep_cloud.environment import ZepEnvironment + +client = Zep( + api_key="", + environment=ZepEnvironment.DEFAULT, +) -
-
+client.user.lookup() -**order_by:** `typing.Optional[str]` — Field to sort by. One of "created_at", "valid_at", or "uuid" (default "uuid"). - +```
+
+
+ +#### ⚙️ Parameters
-**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:** `LookupRequest`
@@ -6311,24 +4065,10 @@ Deprecated: prefer Cursor, the opaque cursor returned via the Zep-Next-Cursor re
-
client.graph.edge.get(...) -
-
- -#### 📝 Description - -
-
- +
client.user.get(...) -> User
-Returns a specific edge by its UUID. -
-
-
-
- #### 🔌 Usage
@@ -6339,12 +4079,15 @@ Returns a specific edge by its UUID. ```python from zep_cloud import Zep +from zep_cloud.environment import ZepEnvironment client = Zep( - api_key="YOUR_API_KEY", + api_key="", + environment=ZepEnvironment.DEFAULT, ) -client.graph.edge.get( - uuid_="uuid", + +client.user.get( + user_uuid="user_uuid", ) ``` @@ -6361,7 +4104,7 @@ client.graph.edge.get(
-**uuid_:** `str` — Edge UUID +**user_uuid:** `str` — User UUID
@@ -6381,24 +4124,10 @@ client.graph.edge.get(
-
client.graph.edge.delete(...) -
-
- -#### 📝 Description - -
-
- +
client.user.delete(...) -> UserDeleteResult
-Deletes an edge by UUID. -
-
-
-
- #### 🔌 Usage
@@ -6409,12 +4138,15 @@ Deletes an edge by UUID. ```python from zep_cloud import Zep +from zep_cloud.environment import ZepEnvironment client = Zep( - api_key="YOUR_API_KEY", + api_key="", + environment=ZepEnvironment.DEFAULT, ) -client.graph.edge.delete( - uuid_="uuid", + +client.user.delete( + user_uuid="user_uuid", ) ``` @@ -6431,7 +4163,7 @@ client.graph.edge.delete(
-**uuid_:** `str` — Edge UUID +**user_uuid:** `str` — User UUID
@@ -6451,24 +4183,10 @@ client.graph.edge.delete(
-
client.graph.edge.update(...) -
-
- -#### 📝 Description - -
-
- +
client.user.update(...) -> User
-Updates an entity edge by UUID. -
-
-
-
- #### 🔌 Usage
@@ -6479,12 +4197,15 @@ Updates an entity edge by UUID. ```python from zep_cloud import Zep +from zep_cloud.environment import ZepEnvironment client = Zep( - api_key="YOUR_API_KEY", + api_key="", + environment=ZepEnvironment.DEFAULT, ) -client.graph.edge.update( - uuid_="uuid", + +client.user.update( + user_uuid="user_uuid", ) ``` @@ -6501,7 +4222,7 @@ client.graph.edge.update(
-**uuid_:** `str` — Edge UUID +**user_uuid:** `str` — User UUID
@@ -6509,7 +4230,7 @@ client.graph.edge.update(
-**attributes:** `typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]]` — Updated attributes. Merged with existing attributes. Set a key to null to delete it. +**disable_default_ontology:** `typing.Optional[bool]` — Omit to leave unchanged, send JSON null to clear, or send a value to set.
@@ -6517,7 +4238,7 @@ client.graph.edge.update(
-**expired_at:** `typing.Optional[str]` — Updated time at which the edge expires +**email:** `typing.Optional[str]` — Omit to leave unchanged, send JSON null to clear, or send a value to set.
@@ -6525,7 +4246,7 @@ client.graph.edge.update(
-**fact:** `typing.Optional[str]` — Updated fact for the edge +**first_name:** `typing.Optional[str]` — Omit to leave unchanged, send JSON null to clear, or send a value to set.
@@ -6533,7 +4254,7 @@ client.graph.edge.update(
-**invalid_at:** `typing.Optional[str]` — Updated time at which the fact stopped being true +**last_name:** `typing.Optional[str]` — Omit to leave unchanged, send JSON null to clear, or send a value to set.
@@ -6541,7 +4262,7 @@ client.graph.edge.update(
-**name:** `typing.Optional[str]` — Updated name (relationship type) for the edge +**metadata:** `typing.Optional[typing.Dict[str, typing.Any]]`
@@ -6549,7 +4270,7 @@ client.graph.edge.update(
-**valid_at:** `typing.Optional[str]` — Updated time at which the fact becomes true +**time_zone:** `typing.Optional[str]` — Omit to leave unchanged, send JSON null to clear, or send a value to set.
@@ -6569,25 +4290,10 @@ client.graph.edge.update(
-## Graph Episode -
client.graph.episode.get_by_graph_id(...) -
-
- -#### 📝 Description - +
client.user.get_node(...) -> JsonObject
-
-
- -Returns episodes by graph id. -
-
-
-
- #### 🔌 Usage
@@ -6598,13 +4304,15 @@ Returns episodes by graph id. ```python from zep_cloud import Zep +from zep_cloud.environment import ZepEnvironment client = Zep( - api_key="YOUR_API_KEY", + api_key="", + environment=ZepEnvironment.DEFAULT, ) -client.graph.episode.get_by_graph_id( - graph_id="graph_id", - lastn=1, + +client.user.get_node( + user_uuid="user_uuid", ) ``` @@ -6621,15 +4329,7 @@ client.graph.episode.get_by_graph_id(
-**graph_id:** `str` — Graph ID - -
-
- -
-
- -**lastn:** `typing.Optional[int]` — The number of most recent episodes to retrieve. +**user_uuid:** `str` — User UUID
@@ -6649,23 +4349,68 @@ client.graph.episode.get_by_graph_id(
-
client.graph.episode.list_by_graph_id(...) +
client.user.get_summary_instructions(...) -> UserSummaryInstructions +
+
+ +#### 🔌 Usage + +
+
+
-#### 📝 Description +```python +from zep_cloud import Zep +from zep_cloud.environment import ZepEnvironment + +client = Zep( + api_key="", + environment=ZepEnvironment.DEFAULT, +) + +client.user.get_summary_instructions( + user_uuid="user_uuid", +) + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+**user_uuid:** `str` — User UUID + +
+
+
-Returns a paginated, filterable list of episodes for a graph. +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. + +
+
+ +
+
+ +
client.user.set_summary_instructions(...) -> UserSummaryInstructions +
+
#### 🔌 Usage @@ -6677,12 +4422,15 @@ Returns a paginated, filterable list of episodes for a graph. ```python from zep_cloud import Zep +from zep_cloud.environment import ZepEnvironment client = Zep( - api_key="YOUR_API_KEY", + api_key="", + environment=ZepEnvironment.DEFAULT, ) -client.graph.episode.list_by_graph_id( - graph_id="graph_id", + +client.user.set_summary_instructions( + user_uuid="user_uuid", ) ``` @@ -6699,7 +4447,7 @@ client.graph.episode.list_by_graph_id(
-**graph_id:** `str` — Graph ID +**user_uuid:** `str` — User UUID
@@ -6707,10 +4455,7 @@ client.graph.episode.list_by_graph_id(
-**cursor:** `typing.Optional[str]` - -Opaque cursor for pagination, obtained from the Zep-Next-Cursor -response header of the previous page. +**request:** `UserSummaryInstructions`
@@ -6718,37 +4463,61 @@ response header of the previous page.
-**direction:** `typing.Optional[str]` — Sort direction. One of "asc" or "desc". Defaults to "desc". +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+ + +
+
+
+## Graph DocumentSummary +
client.graph.document_summary.list(...) -> JsonObjectPage
-**limit:** `typing.Optional[int]` +#### 🔌 Usage -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]]` +```python +from zep_cloud import Zep +from zep_cloud.environment import ZepEnvironment -Restricts results to episodes that mention any of the listed node -UUIDs. At most 256 entries; each must be a syntactically valid UUID. - +client = Zep( + api_key="", + environment=ZepEnvironment.DEFAULT, +) + +client.graph.document_summary.list( + graph_uuid="graph_uuid", + limit=1, + cursor="cursor", +) + +``` +
+
+#### ⚙️ Parameters + +
+
+
-**order_by:** `typing.Optional[str]` — Field to sort by. One of "uuid" or "created_at". Defaults to "uuid". +**graph_uuid:** `str` — Graph UUID
@@ -6756,36 +4525,47 @@ UUIDs. At most 256 entries; each must be a syntactically valid UUID.
-**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. +**request:** `ArtifactListRequest`
-
-
+
+
+**limit:** `typing.Optional[int]` — Page size +
-
-
client.graph.episode.get_by_user_id(...)
-#### 📝 Description - -
-
+**cursor:** `typing.Optional[str]` — Opaque page cursor + +
+
-Returns episodes by user id. +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. +
+ + + +
+ +## Graph Episode +
client.graph.episode.list_for_document(...) -> JsonObjectPage +
+
+ #### 🔌 Usage
@@ -6796,13 +4576,18 @@ Returns episodes by user id. ```python from zep_cloud import Zep +from zep_cloud.environment import ZepEnvironment client = Zep( - api_key="YOUR_API_KEY", + api_key="", + environment=ZepEnvironment.DEFAULT, ) -client.graph.episode.get_by_user_id( - user_id="user_id", - lastn=1, + +client.graph.episode.list_for_document( + graph_uuid="graph_uuid", + document_id="document_id", + limit=1, + cursor="cursor", ) ``` @@ -6819,7 +4604,7 @@ client.graph.episode.get_by_user_id(
-**user_id:** `str` — User ID +**graph_uuid:** `str` — Graph UUID
@@ -6827,7 +4612,7 @@ client.graph.episode.get_by_user_id(
-**lastn:** `typing.Optional[int]` — The number of most recent episodes entries to retrieve. +**document_id:** `str` — Document ID
@@ -6835,35 +4620,37 @@ client.graph.episode.get_by_user_id(
-**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. +**limit:** `typing.Optional[int]` — Page size
-
-
- - - - -
-
client.graph.episode.list_by_user_id(...)
-#### 📝 Description - -
-
+**cursor:** `typing.Optional[str]` — Opaque page cursor + +
+
-Returns a paginated, filterable list of episodes for a user's graph. +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. + +
+
+ + +
+ +
client.graph.episode.add(...) -> AddEpisodeResult +
+
#### 🔌 Usage @@ -6875,12 +4662,15 @@ Returns a paginated, filterable list of episodes for a user's graph. ```python from zep_cloud import Zep +from zep_cloud.environment import ZepEnvironment client = Zep( - api_key="YOUR_API_KEY", + api_key="", + environment=ZepEnvironment.DEFAULT, ) -client.graph.episode.list_by_user_id( - user_id="user_id", + +client.graph.episode.add( + graph_uuid="graph_uuid", ) ``` @@ -6897,7 +4687,7 @@ client.graph.episode.list_by_user_id(
-**user_id:** `str` — User ID +**graph_uuid:** `str` — Graph UUID
@@ -6905,10 +4695,7 @@ client.graph.episode.list_by_user_id(
-**cursor:** `typing.Optional[str]` - -Opaque cursor for pagination, obtained from the Zep-Next-Cursor -response header of the previous page. +**created_at:** `typing.Optional[str]`
@@ -6916,7 +4703,7 @@ response header of the previous page.
-**direction:** `typing.Optional[str]` — Sort direction. One of "asc" or "desc". Defaults to "desc". +**data:** `typing.Optional[str]`
@@ -6924,10 +4711,15 @@ response header of the previous page.
-**limit:** `typing.Optional[int]` +**document_id:** `typing.Optional[str]` + +
+
+ +
+
-Maximum number of episodes to return. An explicit value is clamped to -50; when omitted, the default page size (100) applies. +**metadata:** `typing.Optional[typing.Dict[str, typing.Any]]`
@@ -6935,10 +4727,15 @@ Maximum number of episodes to return. An explicit value is clamped to
-**mentioned_node_uuids:** `typing.Optional[typing.Sequence[str]]` +**source_description:** `typing.Optional[str]` + +
+
-Restricts results to episodes that mention any of the listed node -UUIDs. At most 256 entries; each must be a syntactically valid UUID. +
+
+ +**strict_ontology:** `typing.Optional[bool]`
@@ -6946,7 +4743,7 @@ UUIDs. At most 256 entries; each must be a syntactically valid UUID.
-**order_by:** `typing.Optional[str]` — Field to sort by. One of "uuid" or "created_at". Defaults to "uuid". +**type:** `typing.Optional[str]`
@@ -6966,11 +4763,11 @@ UUIDs. At most 256 entries; each must be a syntactically valid UUID.
-
client.graph.episode.get(...) +
client.graph.episode.list(...) -> JsonObjectPage
-#### 📝 Description +#### 🔌 Usage
@@ -6978,13 +4775,28 @@ UUIDs. At most 256 entries; each must be a syntactically valid UUID.
-Returns episodes by UUID +```python +from zep_cloud import Zep +from zep_cloud.environment import ZepEnvironment + +client = Zep( + api_key="", + environment=ZepEnvironment.DEFAULT, +) + +client.graph.episode.list( + graph_uuid="graph_uuid", + limit=1, + cursor="cursor", +) + +```
-#### 🔌 Usage +#### ⚙️ Parameters
@@ -6992,31 +4804,31 @@ Returns episodes by UUID
-```python -from zep_cloud import Zep - -client = Zep( - api_key="YOUR_API_KEY", -) -client.graph.episode.get( - uuid_="uuid", -) - -``` +**graph_uuid:** `str` — Graph UUID +
+ +
+
+ +**request:** `ArtifactListRequest` +
-#### ⚙️ Parameters -
+**limit:** `typing.Optional[int]` — Page size + +
+
+
-**uuid_:** `str` — Episode UUID +**cursor:** `typing.Optional[str]` — Opaque page cursor
@@ -7036,24 +4848,10 @@ client.graph.episode.get(
-
client.graph.episode.delete(...) -
-
- -#### 📝 Description - -
-
- +
client.graph.episode.get(...) -> JsonObject
-Deletes an episode by its UUID. -
-
-
-
- #### 🔌 Usage
@@ -7064,12 +4862,16 @@ Deletes an episode by its UUID. ```python from zep_cloud import Zep +from zep_cloud.environment import ZepEnvironment client = Zep( - api_key="YOUR_API_KEY", + api_key="", + environment=ZepEnvironment.DEFAULT, ) -client.graph.episode.delete( - uuid_="uuid", + +client.graph.episode.get( + graph_uuid="graph_uuid", + episode_uuid="episode_uuid", ) ``` @@ -7086,7 +4888,15 @@ client.graph.episode.delete(
-**uuid_:** `str` — Episode UUID +**graph_uuid:** `str` — Graph UUID + +
+
+ +
+
+ +**episode_uuid:** `str` — Episode UUID
@@ -7106,24 +4916,10 @@ client.graph.episode.delete(
-
client.graph.episode.update(...) -
-
- -#### 📝 Description - -
-
- +
client.graph.episode.delete(...) -> AsyncResult
-Update episode metadata with merge semantics. Supplied keys overwrite or add to existing metadata; keys set to null are removed. -
-
-
-
- #### 🔌 Usage
@@ -7134,13 +4930,16 @@ Update episode metadata with merge semantics. Supplied keys overwrite or add to ```python from zep_cloud import Zep +from zep_cloud.environment import ZepEnvironment client = Zep( - api_key="YOUR_API_KEY", + api_key="", + environment=ZepEnvironment.DEFAULT, ) -client.graph.episode.update( - uuid_="uuid", - metadata={"key": "value"}, + +client.graph.episode.delete( + graph_uuid="graph_uuid", + episode_uuid="episode_uuid", ) ``` @@ -7157,7 +4956,7 @@ client.graph.episode.update(
-**uuid_:** `str` — Episode UUID +**graph_uuid:** `str` — Graph UUID
@@ -7165,7 +4964,7 @@ client.graph.episode.update(
-**metadata:** `typing.Dict[str, typing.Optional[typing.Any]]` — Updated metadata. Merged with existing metadata: supplied keys overwrite/add, keys set to null are removed. Maximum 10 keys. Values must be scalars (string, number, boolean, null) or arrays of scalars. +**episode_uuid:** `str` — Episode UUID
@@ -7185,24 +4984,10 @@ client.graph.episode.update(
-
client.graph.episode.get_nodes_and_edges(...) -
-
- -#### 📝 Description - -
-
- +
client.graph.episode.update(...) -> JsonObject
-Deprecated. Use edge and node listing with `filters.episode_uuids` instead. Returns nodes and edges mentioned in an episode, subject to an internal cap; responses reduced by that cap set the Zep-Truncated header. -
-
-
-
- #### 🔌 Usage
@@ -7213,12 +4998,16 @@ Deprecated. Use edge and node listing with `filters.episode_uuids` instead. Retu ```python from zep_cloud import Zep +from zep_cloud.environment import ZepEnvironment client = Zep( - api_key="YOUR_API_KEY", + api_key="", + environment=ZepEnvironment.DEFAULT, ) -client.graph.episode.get_nodes_and_edges( - uuid_="uuid", + +client.graph.episode.update( + graph_uuid="graph_uuid", + episode_uuid="episode_uuid", ) ``` @@ -7235,7 +5024,7 @@ client.graph.episode.get_nodes_and_edges(
-**uuid_:** `str` — Episode uuid +**graph_uuid:** `str` — Graph UUID
@@ -7243,36 +5032,38 @@ client.graph.episode.get_nodes_and_edges(
-**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. +**episode_uuid:** `str` — Episode UUID
-
-
- - - - -
-## Graph Node -
client.graph.node.get_by_graph_id(...)
-#### 📝 Description - -
-
+**metadata:** `typing.Optional[typing.Dict[str, typing.Any]]` + +
+
-Returns all nodes for a graph. +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. + +
+
+ + +
+ +## Graph Edge +
client.graph.edge.add(...) -> AddEdgeResult +
+
#### 🔌 Usage @@ -7284,12 +5075,15 @@ Returns all nodes for a graph. ```python from zep_cloud import Zep +from zep_cloud.environment import ZepEnvironment client = Zep( - api_key="YOUR_API_KEY", + api_key="", + environment=ZepEnvironment.DEFAULT, ) -client.graph.node.get_by_graph_id( - graph_id="graph_id", + +client.graph.edge.add( + graph_uuid="graph_uuid", ) ``` @@ -7306,7 +5100,7 @@ client.graph.node.get_by_graph_id(
-**graph_id:** `str` — Graph ID +**graph_uuid:** `str` — Graph UUID
@@ -7314,10 +5108,7 @@ client.graph.node.get_by_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. +**attributes:** `typing.Optional[typing.Dict[str, typing.Any]]`
@@ -7325,7 +5116,7 @@ of the previous page. Encodes the sort field, direction, and continuation positi
-**direction:** `typing.Optional[str]` — Sort direction. One of "asc" or "desc" (default "desc"). +**expired_at:** `typing.Optional[str]`
@@ -7333,7 +5124,7 @@ of the previous page. Encodes the sort field, direction, and continuation positi
-**filters:** `typing.Optional[SearchFilters]` — Optional filters applied to the listed artifacts. Reuses the graph.search filter type. +**fact:** `typing.Optional[str]`
@@ -7341,7 +5132,7 @@ of the previous page. Encodes the sort field, direction, and continuation positi
-**limit:** `typing.Optional[int]` — Maximum number of items to return +**fact_name:** `typing.Optional[str]`
@@ -7349,7 +5140,7 @@ of the previous page. Encodes the sort field, direction, and continuation positi
-**order_by:** `typing.Optional[str]` — Field to sort by. One of "created_at", "valid_at", or "uuid" (default "uuid"). +**invalid_at:** `typing.Optional[str]`
@@ -7357,11 +5148,7 @@ of the previous page. Encodes the sort field, direction, and continuation positi
-**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. +**metadata:** `typing.Optional[typing.Dict[str, typing.Any]]`
@@ -7369,35 +5156,45 @@ Deprecated: prefer Cursor, the opaque cursor returned via the Zep-Next-Cursor re
-**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. +**source_node:** `typing.Optional[typing.Dict[str, typing.Any]]`
-
-
+
+
+**target_node:** `typing.Optional[typing.Dict[str, typing.Any]]` +
-
-
client.graph.node.get_by_user_id(...)
-#### 📝 Description - -
-
+**valid_at:** `typing.Optional[str]` + +
+
-Returns all nodes for a user +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. + +
+
+ + +
+ +
client.graph.edge.list(...) -> JsonObjectPage +
+
#### 🔌 Usage @@ -7409,12 +5206,17 @@ Returns all nodes for a user ```python from zep_cloud import Zep +from zep_cloud.environment import ZepEnvironment client = Zep( - api_key="YOUR_API_KEY", + api_key="", + environment=ZepEnvironment.DEFAULT, ) -client.graph.node.get_by_user_id( - user_id="user_id", + +client.graph.edge.list( + graph_uuid="graph_uuid", + limit=1, + cursor="cursor", ) ``` @@ -7431,7 +5233,7 @@ client.graph.node.get_by_user_id(
-**user_id:** `str` — User ID +**graph_uuid:** `str` — Graph UUID
@@ -7439,10 +5241,7 @@ client.graph.node.get_by_user_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. +**request:** `ArtifactListRequest`
@@ -7450,7 +5249,7 @@ of the previous page. Encodes the sort field, direction, and continuation positi
-**direction:** `typing.Optional[str]` — Sort direction. One of "asc" or "desc" (default "desc"). +**limit:** `typing.Optional[int]` — Page size
@@ -7458,7 +5257,7 @@ of the previous page. Encodes the sort field, direction, and continuation positi
-**filters:** `typing.Optional[SearchFilters]` — Optional filters applied to the listed artifacts. Reuses the graph.search filter type. +**cursor:** `typing.Optional[str]` — Opaque page cursor
@@ -7466,63 +5265,89 @@ of the previous page. Encodes the sort field, direction, and continuation positi
-**limit:** `typing.Optional[int]` — Maximum number of items to return +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
-
-
-**order_by:** `typing.Optional[str]` — Field to sort by. One of "created_at", "valid_at", or "uuid" (default "uuid"). -
+
+
client.graph.edge.get(...) -> JsonObject
-**uuid_cursor:** `typing.Optional[str]` - -UUID based cursor, used for pagination. Should be the UUID of the last item in the previous page. +#### 🔌 Usage -Deprecated: prefer Cursor, the opaque cursor returned via the Zep-Next-Cursor response header. - -
-
+
+
-**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - +```python +from zep_cloud import Zep +from zep_cloud.environment import ZepEnvironment + +client = Zep( + api_key="", + environment=ZepEnvironment.DEFAULT, +) + +client.graph.edge.get( + graph_uuid="graph_uuid", + edge_uuid="edge_uuid", +) + +```
+#### ⚙️ Parameters - - -
+
+
-
client.graph.node.get_edges(...)
-#### 📝 Description +**graph_uuid:** `str` — Graph UUID + +
+
+**edge_uuid:** `str` — Edge UUID + +
+
+
-Deprecated. Use edge listing with `filters.connected_node_uuids`, or the neighbors endpoint (`POST /graph/node/{node_uuid}/neighbors`), instead. Returns all edges for a node, subject to an internal cap; responses reduced by that cap set the Zep-Truncated header. +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. + +
+
+ + +
+ +
client.graph.edge.delete(...) -> AsyncResult +
+
#### 🔌 Usage @@ -7534,12 +5359,16 @@ Deprecated. Use edge listing with `filters.connected_node_uuids`, or the neighbo ```python from zep_cloud import Zep +from zep_cloud.environment import ZepEnvironment client = Zep( - api_key="YOUR_API_KEY", + api_key="", + environment=ZepEnvironment.DEFAULT, ) -client.graph.node.get_edges( - node_uuid="node_uuid", + +client.graph.edge.delete( + graph_uuid="graph_uuid", + edge_uuid="edge_uuid", ) ``` @@ -7556,7 +5385,15 @@ client.graph.node.get_edges(
-**node_uuid:** `str` — Node UUID +**graph_uuid:** `str` — Graph UUID + +
+
+ +
+
+ +**edge_uuid:** `str` — Edge UUID
@@ -7576,24 +5413,10 @@ client.graph.node.get_edges(
-
client.graph.node.get_episodes(...) +
client.graph.edge.update(...) -> JsonObject
-#### 📝 Description - -
-
- -
-
- -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. -
-
-
-
- #### 🔌 Usage
@@ -7604,12 +5427,16 @@ Deprecated. Use episode listing with `mentioned_node_uuids` (`POST /graph/episod ```python from zep_cloud import Zep +from zep_cloud.environment import ZepEnvironment client = Zep( - api_key="YOUR_API_KEY", + api_key="", + environment=ZepEnvironment.DEFAULT, ) -client.graph.node.get_episodes( - node_uuid="node_uuid", + +client.graph.edge.update( + graph_uuid="graph_uuid", + edge_uuid="edge_uuid", ) ``` @@ -7626,7 +5453,7 @@ client.graph.node.get_episodes(
-**node_uuid:** `str` — Node UUID +**graph_uuid:** `str` — Graph UUID
@@ -7634,35 +5461,46 @@ client.graph.node.get_episodes(
-**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. +**edge_uuid:** `str` — Edge UUID
-
-
+
+
+**attributes:** `typing.Optional[typing.Dict[str, typing.Any]]` +
-
-
client.graph.node.get_neighbors(...)
-#### 📝 Description - -
-
+**fact:** `typing.Optional[str]` — Omit to leave unchanged, send JSON null to clear, or send a value to set. + +
+
-Enumerates the distinct entity nodes directly connected to a node, together with the edges connecting each to it. +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. + +
+
+ + +
+ +## Graph Node +
client.graph.node.add(...) -> AddNodesResult +
+
#### 🔌 Usage @@ -7674,12 +5512,15 @@ Enumerates the distinct entity nodes directly connected to a node, together with ```python from zep_cloud import Zep +from zep_cloud.environment import ZepEnvironment client = Zep( - api_key="YOUR_API_KEY", + api_key="", + environment=ZepEnvironment.DEFAULT, ) -client.graph.node.get_neighbors( - node_uuid="node_uuid", + +client.graph.node.add( + graph_uuid="graph_uuid", ) ``` @@ -7696,7 +5537,7 @@ client.graph.node.get_neighbors(
-**node_uuid:** `str` — Node UUID +**graph_uuid:** `str` — Graph UUID
@@ -7704,10 +5545,7 @@ client.graph.node.get_neighbors(
-**cursor:** `typing.Optional[str]` - -Opaque cursor for pagination, obtained from the Zep-Next-Cursor -response header of the previous page. +**nodes:** `typing.Optional[typing.List[typing.Dict[str, typing.Any]]]`
@@ -7715,58 +5553,60 @@ response header of the previous page.
-**direction:** `typing.Optional[str]` - -Orientation of the connecting edge relative to the anchor node: "out" -(anchor is the edge's source), "in" (anchor is the edge's target), or -"both" (either). Defaults to "both". +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
-
-
- -**direction_sort:** `typing.Optional[str]` -Sort direction for order_by. One of "asc" or "desc". Defaults to -"desc". Named direction_sort to avoid clashing with the traversal -Direction field above. -
+
+
client.graph.node.list(...) -> JsonObjectPage
-**filters:** `typing.Optional[SearchFilters]` +#### 🔌 Usage -Filters constraining the connecting edges (edge types, dates, and the -section-3 node-/episode-anchored fields) and the neighbor nodes -(node_labels/exclude_node_labels). Reuses the graph.search filter -type. - -
-
+
+
-**limit:** `typing.Optional[int]` +```python +from zep_cloud import Zep +from zep_cloud.environment import ZepEnvironment -Maximum number of neighbor nodes to return. An explicit value is -clamped to 50; when omitted, the default page size (100) applies. - +client = Zep( + api_key="", + environment=ZepEnvironment.DEFAULT, +) + +client.graph.node.list( + graph_uuid="graph_uuid", + limit=1, + cursor="cursor", +) + +``` +
+
+#### ⚙️ Parameters +
-**order_by:** `typing.Optional[str]` +
+
-Field to sort neighbor nodes by. One of "uuid" or "created_at". -Defaults to "uuid". +**graph_uuid:** `str` — Graph UUID
@@ -7774,35 +5614,45 @@ Defaults to "uuid".
-**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. +**request:** `ArtifactListRequest`
-
-
+
+
+**limit:** `typing.Optional[int]` — Page size +
-
-
client.graph.node.get(...)
-#### 📝 Description - -
-
+**cursor:** `typing.Optional[str]` — Opaque page cursor + +
+
-Returns a specific node by its UUID. +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. + +
+
+ + +
+ +
client.graph.node.get(...) -> JsonObject +
+
#### 🔌 Usage @@ -7814,12 +5664,16 @@ Returns a specific node by its UUID. ```python from zep_cloud import Zep +from zep_cloud.environment import ZepEnvironment client = Zep( - api_key="YOUR_API_KEY", + api_key="", + environment=ZepEnvironment.DEFAULT, ) + client.graph.node.get( - uuid_="uuid", + graph_uuid="graph_uuid", + node_uuid="node_uuid", ) ``` @@ -7836,7 +5690,15 @@ client.graph.node.get(
-**uuid_:** `str` — Node UUID +**graph_uuid:** `str` — Graph UUID + +
+
+ +
+
+ +**node_uuid:** `str` — Node UUID
@@ -7856,24 +5718,10 @@ client.graph.node.get(
-
client.graph.node.delete(...) -
-
- -#### 📝 Description - -
-
- +
client.graph.node.delete(...) -> AsyncResult
-Deletes a node by UUID. -
-
-
-
- #### 🔌 Usage
@@ -7884,12 +5732,16 @@ Deletes a node by UUID. ```python from zep_cloud import Zep +from zep_cloud.environment import ZepEnvironment client = Zep( - api_key="YOUR_API_KEY", + api_key="", + environment=ZepEnvironment.DEFAULT, ) + client.graph.node.delete( - uuid_="uuid", + graph_uuid="graph_uuid", + node_uuid="node_uuid", ) ``` @@ -7906,7 +5758,15 @@ client.graph.node.delete(
-**uuid_:** `str` — Node UUID +**graph_uuid:** `str` — Graph UUID + +
+
+ +
+
+ +**node_uuid:** `str` — Node UUID
@@ -7926,24 +5786,10 @@ client.graph.node.delete(
-
client.graph.node.update(...) -
-
- -#### 📝 Description - -
-
- +
client.graph.node.update(...) -> JsonObject
-Updates an entity node by UUID. -
-
-
-
- #### 🔌 Usage
@@ -7954,12 +5800,16 @@ Updates an entity node by UUID. ```python from zep_cloud import Zep +from zep_cloud.environment import ZepEnvironment client = Zep( - api_key="YOUR_API_KEY", + api_key="", + environment=ZepEnvironment.DEFAULT, ) + client.graph.node.update( - uuid_="uuid", + graph_uuid="graph_uuid", + node_uuid="node_uuid", ) ``` @@ -7976,7 +5826,7 @@ client.graph.node.update(
-**uuid_:** `str` — Node UUID +**graph_uuid:** `str` — Graph UUID
@@ -7984,7 +5834,7 @@ client.graph.node.update(
-**attributes:** `typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]]` — Updated attributes. Merged with existing attributes. Set a key to null to delete it. +**node_uuid:** `str` — Node UUID
@@ -7992,7 +5842,7 @@ client.graph.node.update(
-**labels:** `typing.Optional[typing.Sequence[str]]` — Updated labels for the node +**attributes:** `typing.Optional[typing.Dict[str, typing.Any]]`
@@ -8000,7 +5850,7 @@ client.graph.node.update(
-**name:** `typing.Optional[str]` — Updated name for the node +**name:** `typing.Optional[str]` — Omit to leave unchanged, send JSON null to clear, or send a value to set.
@@ -8008,7 +5858,7 @@ client.graph.node.update(
-**summary:** `typing.Optional[str]` — Updated summary for the node +**summary:** `typing.Optional[str]` — Omit to leave unchanged, send JSON null to clear, or send a value to set.
@@ -8028,25 +5878,10 @@ client.graph.node.update(
-## Graph Observation -
client.graph.observation.get_by_graph_id(...) -
-
- -#### 📝 Description - -
-
- +
client.graph.node.list_neighbors(...) -> NeighborPage
-Returns read-only observation nodes for a graph. -
-
-
-
- #### 🔌 Usage
@@ -8057,12 +5892,18 @@ Returns read-only observation nodes for a graph. ```python from zep_cloud import Zep +from zep_cloud.environment import ZepEnvironment client = Zep( - api_key="YOUR_API_KEY", + api_key="", + environment=ZepEnvironment.DEFAULT, ) -client.graph.observation.get_by_graph_id( - graph_id="graph_id", + +client.graph.node.list_neighbors( + graph_uuid="graph_uuid", + node_uuid="node_uuid", + limit=1, + cursor="cursor", ) ``` @@ -8079,18 +5920,7 @@ client.graph.observation.get_by_graph_id(
-**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. +**graph_uuid:** `str` — Graph UUID
@@ -8098,7 +5928,7 @@ of the previous page. Encodes the sort field, direction, and continuation positi
-**direction:** `typing.Optional[str]` — Sort direction. One of "asc" or "desc" (default "desc"). +**node_uuid:** `str` — Node UUID
@@ -8106,7 +5936,7 @@ of the previous page. Encodes the sort field, direction, and continuation positi
-**filters:** `typing.Optional[SearchFilters]` — Optional filters applied to the listed artifacts. Reuses the graph.search filter type. +**limit:** `typing.Optional[int]` — Page size
@@ -8114,7 +5944,7 @@ of the previous page. Encodes the sort field, direction, and continuation positi
-**limit:** `typing.Optional[int]` — Maximum number of items to return +**cursor:** `typing.Optional[str]` — Opaque page cursor
@@ -8122,7 +5952,7 @@ of the previous page. Encodes the sort field, direction, and continuation positi
-**order_by:** `typing.Optional[str]` — Field to sort by. One of "created_at", "valid_at", or "uuid" (default "uuid"). +**direction:** `typing.Optional[str]`
@@ -8130,11 +5960,7 @@ of the previous page. Encodes the sort field, direction, and continuation positi
-**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. +**filters:** `typing.Optional[typing.Dict[str, typing.Any]]`
@@ -8154,24 +5980,11 @@ Deprecated: prefer Cursor, the opaque cursor returned via the Zep-Next-Cursor re
-
client.graph.observation.get_by_user_id(...) -
-
- -#### 📝 Description - -
-
- +## Graph Observation +
client.graph.observation.list(...) -> JsonObjectPage
-Returns read-only observation nodes for a user's graph. -
-
-
-
- #### 🔌 Usage
@@ -8182,12 +5995,17 @@ Returns read-only observation nodes for a user's graph. ```python from zep_cloud import Zep +from zep_cloud.environment import ZepEnvironment client = Zep( - api_key="YOUR_API_KEY", + api_key="", + environment=ZepEnvironment.DEFAULT, ) -client.graph.observation.get_by_user_id( - user_id="user_id", + +client.graph.observation.list( + graph_uuid="graph_uuid", + limit=1, + cursor="cursor", ) ``` @@ -8204,34 +6022,7 @@ client.graph.observation.get_by_user_id(
-**user_id:** `str` — User ID - -
-
- -
-
- -**cursor:** `typing.Optional[str]` - -Opaque cursor for pagination, obtained from the Zep-Next-Cursor response header -of the previous page. 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. +**graph_uuid:** `str` — Graph UUID
@@ -8239,7 +6030,7 @@ of the previous page. Encodes the sort field, direction, and continuation positi
-**limit:** `typing.Optional[int]` — Maximum number of items to return +**request:** `ArtifactListRequest`
@@ -8247,7 +6038,7 @@ of the previous page. Encodes the sort field, direction, and continuation positi
-**order_by:** `typing.Optional[str]` — Field to sort by. One of "created_at", "valid_at", or "uuid" (default "uuid"). +**limit:** `typing.Optional[int]` — Page size
@@ -8255,11 +6046,7 @@ of the previous page. Encodes the sort field, direction, and continuation positi
-**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. +**cursor:** `typing.Optional[str]` — Opaque page cursor
@@ -8279,24 +6066,10 @@ Deprecated: prefer Cursor, the opaque cursor returned via the Zep-Next-Cursor re
-
client.graph.observation.get(...) -
-
- -#### 📝 Description - -
-
- +
client.graph.observation.get(...) -> JsonObject
-Returns a specific observation node by UUID. Observation nodes are read-only. -
-
-
-
- #### 🔌 Usage
@@ -8307,12 +6080,16 @@ Returns a specific observation node by UUID. Observation nodes are read-only. ```python from zep_cloud import Zep +from zep_cloud.environment import ZepEnvironment client = Zep( - api_key="YOUR_API_KEY", + api_key="", + environment=ZepEnvironment.DEFAULT, ) + client.graph.observation.get( - uuid_="uuid", + graph_uuid="graph_uuid", + observation_uuid="observation_uuid", ) ``` @@ -8329,7 +6106,15 @@ client.graph.observation.get(
-**uuid_:** `str` — Observation UUID +**graph_uuid:** `str` — Graph UUID + +
+
+ +
+
+ +**observation_uuid:** `str` — Observation UUID
@@ -8350,24 +6135,10 @@ client.graph.observation.get(
## Graph ThreadSummary -
client.graph.thread_summary.get_by_graph_id(...) -
-
- -#### 📝 Description - -
-
- +
client.graph.thread_summary.list(...) -> JsonObjectPage
-Returns incremental thread summaries associated with the graph. -
-
-
-
- #### 🔌 Usage
@@ -8378,12 +6149,17 @@ Returns incremental thread summaries associated with the graph. ```python from zep_cloud import Zep +from zep_cloud.environment import ZepEnvironment client = Zep( - api_key="YOUR_API_KEY", + api_key="", + environment=ZepEnvironment.DEFAULT, ) -client.graph.thread_summary.get_by_graph_id( - graph_id="graph_id", + +client.graph.thread_summary.list( + graph_uuid="graph_uuid", + limit=1, + cursor="cursor", ) ``` @@ -8400,34 +6176,7 @@ client.graph.thread_summary.get_by_graph_id(
-**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. +**graph_uuid:** `str` — Graph UUID
@@ -8435,7 +6184,7 @@ of the previous page. Encodes the sort field, direction, and continuation positi
-**limit:** `typing.Optional[int]` — Maximum number of items to return +**request:** `ArtifactListRequest`
@@ -8443,7 +6192,7 @@ of the previous page. Encodes the sort field, direction, and continuation positi
-**order_by:** `typing.Optional[str]` — Field to sort by. One of "created_at", "valid_at", or "uuid" (default "uuid"). +**limit:** `typing.Optional[int]` — Page size
@@ -8451,11 +6200,7 @@ of the previous page. Encodes the sort field, direction, and continuation positi
-**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. +**cursor:** `typing.Optional[str]` — Opaque page cursor
@@ -8475,24 +6220,11 @@ Deprecated: prefer Cursor, the opaque cursor returned via the Zep-Next-Cursor re
-
client.graph.thread_summary.get_by_user_id(...) -
-
- -#### 📝 Description - -
-
- +## Thread Message +
client.thread.message.get(...) -> Message
-Returns incremental thread summaries generated from messages in each thread associated with the user's graph. -
-
-
-
- #### 🔌 Usage
@@ -8503,12 +6235,16 @@ Returns incremental thread summaries generated from messages in each thread asso ```python from zep_cloud import Zep +from zep_cloud.environment import ZepEnvironment client = Zep( - api_key="YOUR_API_KEY", + api_key="", + environment=ZepEnvironment.DEFAULT, ) -client.graph.thread_summary.get_by_user_id( - user_id="user_id", + +client.thread.message.get( + thread_uuid="thread_uuid", + message_uuid="message_uuid", ) ``` @@ -8525,50 +6261,7 @@ client.graph.thread_summary.get_by_user_id(
-**user_id:** `str` — User ID - -
-
- -
-
- -**cursor:** `typing.Optional[str]` - -Opaque cursor for pagination, obtained from the Zep-Next-Cursor response header -of the previous page. 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"). +**thread_uuid:** `str` — Thread UUID
@@ -8576,11 +6269,7 @@ of the previous page. Encodes the sort field, direction, and continuation positi
-**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. +**message_uuid:** `str` — Message UUID
@@ -8600,25 +6289,10 @@ Deprecated: prefer Cursor, the opaque cursor returned via the Zep-Next-Cursor re
-## Thread Message -
client.thread.message.update(...) -
-
- -#### 📝 Description - +
client.thread.message.update(...) -> Message
-
-
- -Updates a message. -
-
-
-
- #### 🔌 Usage
@@ -8629,13 +6303,16 @@ Updates a message. ```python from zep_cloud import Zep +from zep_cloud.environment import ZepEnvironment client = Zep( - api_key="YOUR_API_KEY", + api_key="", + environment=ZepEnvironment.DEFAULT, ) + client.thread.message.update( - message_uuid="messageUUID", - metadata={"key": "value"}, + thread_uuid="thread_uuid", + message_uuid="message_uuid", ) ``` @@ -8652,7 +6329,15 @@ client.thread.message.update(
-**message_uuid:** `str` — The UUID of the message. +**thread_uuid:** `str` — Thread UUID + +
+
+ +
+
+ +**message_uuid:** `str` — Message UUID
@@ -8660,7 +6345,7 @@ client.thread.message.update(
-**metadata:** `typing.Dict[str, typing.Optional[typing.Any]]` +**metadata:** `typing.Optional[typing.Dict[str, typing.Any]]`
diff --git a/src/zep_cloud/__init__.py b/src/zep_cloud/__init__.py index 9b7b03c9..7100fb41 100644 --- a/src/zep_cloud/__init__.py +++ b/src/zep_cloud/__init__.py @@ -2,230 +2,212 @@ # isort: skip_file -from .types import ( - AddNodeItem, - AddNodesResponse, - AddThreadMessagesRequest, - AddThreadMessagesResponse, - AddTripleResponse, - AddedNode, - ApiError, - ApidataBatchAddItemRole, - ApidataBatchAddItemType, - AttachedPolicySetsResponse, - BatchAddItem, - BatchItemDetail, - BatchItemKind, - BatchItemListResponse, - BatchItemStatus, - BatchListResponse, - BatchProgress, - BatchStatus, - BatchSummary, - CloneGraphResponse, - ClusterDetectConfig, - CoOccurrenceDetectConfig, - ComparisonOperator, - ContextTemplateResponse, - CustomInstruction, - DateFilter, - DerivedNode, - DetectConfig, - DetectPatternsResponse, - EdgeType, - EntityEdge, - EntityEdgeSourceTarget, - EntityNode, - EntityProperty, - EntityPropertyType, - EntityType, - EntityTypeResponse, - Episode, - EpisodeData, - EpisodeMentions, - EpisodeMetadataFilter, - EpisodeResponse, - GetTaskResponse, - Graph, - GraphDataType, - GraphEdgesRequest, - GraphEpisodeListRequest, - GraphListResponse, - GraphNodeNeighbor, - GraphNodesRequest, - GraphObservationsRequest, - GraphSearchResponseMetadata, - GraphSearchResults, - GraphSearchScope, - GraphSubgraphResponse, - GraphThreadSummariesRequest, - GraphitiMetadataFilterGroupType, - GraphitiSagaNode, - HubDetectConfig, - ListContextTemplatesResponse, - ListCustomInstructionsResponse, - ListUserInstructionsResponse, - Message, - MessageListResponse, - MetadataFilterGroup, - MutateUserGroupMembersRequest, - ObservationSteeringConfig, - ObservationType, - PathDetectConfig, - PatternMetadata, - PatternResult, - PatternSeeds, - PolicySetSummaryResponse, - ProjectInfo, - ProjectInfoResponse, - PropertyFilter, - RecencyWeight, - RelationshipDetectConfig, - Reranker, - RoleType, - SearchFilters, - SuccessResponse, - TaskErrorResponse, - TaskProgress, - Thread, - ThreadContextResponse, - ThreadListResponse, - ThreadSummary, - User, - UserGroup, - UserGroupKind, - UserGroupListResponse, - UserGroupMembersResponse, - UserGroupMembershipResponse, - UserGroupQuota, - UserGroupResponse, - UserInstruction, - UserListResponse, - UserMembershipGroupsResponse, - UserNodeResponse, -) -from .errors import BadRequestError, ConflictError, ForbiddenError, InternalServerError, NotFoundError -from . import batch, context, graph, project, task, thread, user, user_group -from .client import AsyncZep, Zep -from .environment import ZepEnvironment -from .version import __version__ +import typing +from importlib import import_module + +if typing.TYPE_CHECKING: + from .types import ( + AddEdgeResult, + AddEpisodeResult, + AddMessage, + AddMessagesResult, + AddNodesResult, + ApiError, + ArtifactListRequest, + AsyncResult, + Batch, + BatchItemsResponse, + BatchPage, + CloneGraphResult, + ContextTemplate, + ContextTemplatePage, + CreateContextTemplateRequest, + ErrorBody, + Graph, + GraphContextResponse, + GraphDeleteResult, + GraphPage, + Instructions, + JsonObject, + JsonObjectPage, + LookupBatchResponse, + LookupItem, + LookupRequest, + Message, + MessagePage, + NeighborEntry, + NeighborPage, + ObservationSteering, + Ontology, + ProcessBatchResult, + Project, + SearchRequest, + Task, + TaskPage, + TaskProgress, + Thread, + ThreadContextResponse, + ThreadDeleteResult, + ThreadPage, + ThreadSummary, + User, + UserDeleteResult, + UserPage, + UserSummaryInstructions, + ) + from .errors import BadRequestError, NotFoundError, UnauthorizedError + from . import batch, context, graph, lookup, project, task, thread, user + from .client import AsyncZep, Zep + from .environment import ZepEnvironment + from .version import __version__ +_dynamic_imports: typing.Dict[str, str] = { + "AddEdgeResult": ".types", + "AddEpisodeResult": ".types", + "AddMessage": ".types", + "AddMessagesResult": ".types", + "AddNodesResult": ".types", + "ApiError": ".types", + "ArtifactListRequest": ".types", + "AsyncResult": ".types", + "AsyncZep": ".client", + "BadRequestError": ".errors", + "Batch": ".types", + "BatchItemsResponse": ".types", + "BatchPage": ".types", + "CloneGraphResult": ".types", + "ContextTemplate": ".types", + "ContextTemplatePage": ".types", + "CreateContextTemplateRequest": ".types", + "ErrorBody": ".types", + "Graph": ".types", + "GraphContextResponse": ".types", + "GraphDeleteResult": ".types", + "GraphPage": ".types", + "Instructions": ".types", + "JsonObject": ".types", + "JsonObjectPage": ".types", + "LookupBatchResponse": ".types", + "LookupItem": ".types", + "LookupRequest": ".types", + "Message": ".types", + "MessagePage": ".types", + "NeighborEntry": ".types", + "NeighborPage": ".types", + "NotFoundError": ".errors", + "ObservationSteering": ".types", + "Ontology": ".types", + "ProcessBatchResult": ".types", + "Project": ".types", + "SearchRequest": ".types", + "Task": ".types", + "TaskPage": ".types", + "TaskProgress": ".types", + "Thread": ".types", + "ThreadContextResponse": ".types", + "ThreadDeleteResult": ".types", + "ThreadPage": ".types", + "ThreadSummary": ".types", + "UnauthorizedError": ".errors", + "User": ".types", + "UserDeleteResult": ".types", + "UserPage": ".types", + "UserSummaryInstructions": ".types", + "Zep": ".client", + "ZepEnvironment": ".environment", + "__version__": ".version", + "batch": ".batch", + "context": ".context", + "graph": ".graph", + "lookup": ".lookup", + "project": ".project", + "task": ".task", + "thread": ".thread", + "user": ".user", +} + + +def __getattr__(attr_name: str) -> typing.Any: + module_name = _dynamic_imports.get(attr_name) + if module_name is None: + raise AttributeError(f"No {attr_name} found in _dynamic_imports for module name -> {__name__}") + try: + module = import_module(module_name, __package__) + if module_name == f".{attr_name}": + return module + else: + return getattr(module, attr_name) + except ImportError as e: + raise ImportError(f"Failed to import {attr_name} from {module_name}: {e}") from e + except AttributeError as e: + raise AttributeError(f"Failed to get {attr_name} from {module_name}: {e}") from e + + +def __dir__(): + lazy_attrs = list(_dynamic_imports.keys()) + return sorted(lazy_attrs) + __all__ = [ - "AddNodeItem", - "AddNodesResponse", - "AddThreadMessagesRequest", - "AddThreadMessagesResponse", - "AddTripleResponse", - "AddedNode", + "AddEdgeResult", + "AddEpisodeResult", + "AddMessage", + "AddMessagesResult", + "AddNodesResult", "ApiError", - "ApidataBatchAddItemRole", - "ApidataBatchAddItemType", + "ArtifactListRequest", + "AsyncResult", "AsyncZep", - "AttachedPolicySetsResponse", "BadRequestError", - "BatchAddItem", - "BatchItemDetail", - "BatchItemKind", - "BatchItemListResponse", - "BatchItemStatus", - "BatchListResponse", - "BatchProgress", - "BatchStatus", - "BatchSummary", - "CloneGraphResponse", - "ClusterDetectConfig", - "CoOccurrenceDetectConfig", - "ComparisonOperator", - "ConflictError", - "ContextTemplateResponse", - "CustomInstruction", - "DateFilter", - "DerivedNode", - "DetectConfig", - "DetectPatternsResponse", - "EdgeType", - "EntityEdge", - "EntityEdgeSourceTarget", - "EntityNode", - "EntityProperty", - "EntityPropertyType", - "EntityType", - "EntityTypeResponse", - "Episode", - "EpisodeData", - "EpisodeMentions", - "EpisodeMetadataFilter", - "EpisodeResponse", - "ForbiddenError", - "GetTaskResponse", + "Batch", + "BatchItemsResponse", + "BatchPage", + "CloneGraphResult", + "ContextTemplate", + "ContextTemplatePage", + "CreateContextTemplateRequest", + "ErrorBody", "Graph", - "GraphDataType", - "GraphEdgesRequest", - "GraphEpisodeListRequest", - "GraphListResponse", - "GraphNodeNeighbor", - "GraphNodesRequest", - "GraphObservationsRequest", - "GraphSearchResponseMetadata", - "GraphSearchResults", - "GraphSearchScope", - "GraphSubgraphResponse", - "GraphThreadSummariesRequest", - "GraphitiMetadataFilterGroupType", - "GraphitiSagaNode", - "HubDetectConfig", - "InternalServerError", - "ListContextTemplatesResponse", - "ListCustomInstructionsResponse", - "ListUserInstructionsResponse", + "GraphContextResponse", + "GraphDeleteResult", + "GraphPage", + "Instructions", + "JsonObject", + "JsonObjectPage", + "LookupBatchResponse", + "LookupItem", + "LookupRequest", "Message", - "MessageListResponse", - "MetadataFilterGroup", - "MutateUserGroupMembersRequest", + "MessagePage", + "NeighborEntry", + "NeighborPage", "NotFoundError", - "ObservationSteeringConfig", - "ObservationType", - "PathDetectConfig", - "PatternMetadata", - "PatternResult", - "PatternSeeds", - "PolicySetSummaryResponse", - "ProjectInfo", - "ProjectInfoResponse", - "PropertyFilter", - "RecencyWeight", - "RelationshipDetectConfig", - "Reranker", - "RoleType", - "SearchFilters", - "SuccessResponse", - "TaskErrorResponse", + "ObservationSteering", + "Ontology", + "ProcessBatchResult", + "Project", + "SearchRequest", + "Task", + "TaskPage", "TaskProgress", "Thread", "ThreadContextResponse", - "ThreadListResponse", + "ThreadDeleteResult", + "ThreadPage", "ThreadSummary", + "UnauthorizedError", "User", - "UserGroup", - "UserGroupKind", - "UserGroupListResponse", - "UserGroupMembersResponse", - "UserGroupMembershipResponse", - "UserGroupQuota", - "UserGroupResponse", - "UserInstruction", - "UserListResponse", - "UserMembershipGroupsResponse", - "UserNodeResponse", + "UserDeleteResult", + "UserPage", + "UserSummaryInstructions", "Zep", "ZepEnvironment", "__version__", "batch", "context", "graph", + "lookup", "project", "task", "thread", "user", - "user_group", ] diff --git a/src/zep_cloud/base_client.py b/src/zep_cloud/base_client.py index e95c27b5..998188e7 100644 --- a/src/zep_cloud/base_client.py +++ b/src/zep_cloud/base_client.py @@ -1,20 +1,25 @@ # This file was auto-generated by Fern from our API Definition. +from __future__ import annotations + import os import typing import httpx -from .batch.client import AsyncBatchClient, BatchClient -from .context.client import AsyncContextClient, ContextClient from .core.api_error import ApiError from .core.client_wrapper import AsyncClientWrapper, SyncClientWrapper +from .core.logging import LogConfig, Logger from .environment import ZepEnvironment -from .graph.client import AsyncGraphClient, GraphClient -from .project.client import AsyncProjectClient, ProjectClient -from .task.client import AsyncTaskClient, TaskClient -from .thread.client import AsyncThreadClient, ThreadClient -from .user.client import AsyncUserClient, UserClient -from .user_group.client import AsyncUserGroupClient, UserGroupClient + +if typing.TYPE_CHECKING: + from .batch.client import AsyncBatchClient, BatchClient + from .context.client import AsyncContextClient, ContextClient + from .graph.client import AsyncGraphClient, GraphClient + from .lookup.client import AsyncLookupClient, LookupClient + from .project.client import AsyncProjectClient, ProjectClient + from .task.client import AsyncTaskClient, TaskClient + from .thread.client import AsyncThreadClient, ThreadClient + from .user.client import AsyncUserClient, UserClient class BaseClient: @@ -48,6 +53,9 @@ class BaseClient: httpx_client : typing.Optional[httpx.Client] The httpx client to use for making requests, a preconfigured client is used by default, however this is useful should you want to pass in any custom httpx configuration. + logging : typing.Optional[typing.Union[LogConfig, Logger]] + Configure logging for the SDK. Accepts a LogConfig dict with 'level' (debug/info/warn/error), 'logger' (custom logger implementation), and 'silent' (boolean, defaults to True) fields. You can also pass a pre-configured Logger instance. + Examples -------- from zep_cloud import Zep @@ -67,6 +75,7 @@ def __init__( timeout: typing.Optional[float] = None, follow_redirects: typing.Optional[bool] = True, httpx_client: typing.Optional[httpx.Client] = None, + logging: typing.Optional[typing.Union[LogConfig, Logger]] = None, ): _defaulted_timeout = ( timeout if timeout is not None else 60 if httpx_client is None else httpx_client.timeout.read @@ -83,15 +92,80 @@ def __init__( if follow_redirects is not None else httpx.Client(timeout=_defaulted_timeout), timeout=_defaulted_timeout, + logging=logging, ) - self.user_group = UserGroupClient(client_wrapper=self._client_wrapper) - self.batch = BatchClient(client_wrapper=self._client_wrapper) - self.context = ContextClient(client_wrapper=self._client_wrapper) - self.graph = GraphClient(client_wrapper=self._client_wrapper) - self.project = ProjectClient(client_wrapper=self._client_wrapper) - self.task = TaskClient(client_wrapper=self._client_wrapper) - self.thread = ThreadClient(client_wrapper=self._client_wrapper) - self.user = UserClient(client_wrapper=self._client_wrapper) + self._batch: typing.Optional[BatchClient] = None + self._context: typing.Optional[ContextClient] = None + self._graph: typing.Optional[GraphClient] = None + self._lookup: typing.Optional[LookupClient] = None + self._project: typing.Optional[ProjectClient] = None + self._task: typing.Optional[TaskClient] = None + self._thread: typing.Optional[ThreadClient] = None + self._user: typing.Optional[UserClient] = None + + @property + def batch(self): + if self._batch is None: + from .batch.client import BatchClient # noqa: E402 + + self._batch = BatchClient(client_wrapper=self._client_wrapper) + return self._batch + + @property + def context(self): + if self._context is None: + from .context.client import ContextClient # noqa: E402 + + self._context = ContextClient(client_wrapper=self._client_wrapper) + return self._context + + @property + def graph(self): + if self._graph is None: + from .graph.client import GraphClient # noqa: E402 + + self._graph = GraphClient(client_wrapper=self._client_wrapper) + return self._graph + + @property + def lookup(self): + if self._lookup is None: + from .lookup.client import LookupClient # noqa: E402 + + self._lookup = LookupClient(client_wrapper=self._client_wrapper) + return self._lookup + + @property + def project(self): + if self._project is None: + from .project.client import ProjectClient # noqa: E402 + + self._project = ProjectClient(client_wrapper=self._client_wrapper) + return self._project + + @property + def task(self): + if self._task is None: + from .task.client import TaskClient # noqa: E402 + + self._task = TaskClient(client_wrapper=self._client_wrapper) + return self._task + + @property + def thread(self): + if self._thread is None: + from .thread.client import ThreadClient # noqa: E402 + + self._thread = ThreadClient(client_wrapper=self._client_wrapper) + return self._thread + + @property + def user(self): + if self._user is None: + from .user.client import UserClient # noqa: E402 + + self._user = UserClient(client_wrapper=self._client_wrapper) + return self._user class AsyncBaseClient: @@ -125,6 +199,9 @@ class AsyncBaseClient: httpx_client : typing.Optional[httpx.AsyncClient] The httpx client to use for making requests, a preconfigured client is used by default, however this is useful should you want to pass in any custom httpx configuration. + logging : typing.Optional[typing.Union[LogConfig, Logger]] + Configure logging for the SDK. Accepts a LogConfig dict with 'level' (debug/info/warn/error), 'logger' (custom logger implementation), and 'silent' (boolean, defaults to True) fields. You can also pass a pre-configured Logger instance. + Examples -------- from zep_cloud import AsyncZep @@ -144,6 +221,7 @@ def __init__( timeout: typing.Optional[float] = None, follow_redirects: typing.Optional[bool] = True, httpx_client: typing.Optional[httpx.AsyncClient] = None, + logging: typing.Optional[typing.Union[LogConfig, Logger]] = None, ): _defaulted_timeout = ( timeout if timeout is not None else 60 if httpx_client is None else httpx_client.timeout.read @@ -160,15 +238,80 @@ def __init__( if follow_redirects is not None else httpx.AsyncClient(timeout=_defaulted_timeout), timeout=_defaulted_timeout, + logging=logging, ) - self.user_group = AsyncUserGroupClient(client_wrapper=self._client_wrapper) - self.batch = AsyncBatchClient(client_wrapper=self._client_wrapper) - self.context = AsyncContextClient(client_wrapper=self._client_wrapper) - self.graph = AsyncGraphClient(client_wrapper=self._client_wrapper) - self.project = AsyncProjectClient(client_wrapper=self._client_wrapper) - self.task = AsyncTaskClient(client_wrapper=self._client_wrapper) - self.thread = AsyncThreadClient(client_wrapper=self._client_wrapper) - self.user = AsyncUserClient(client_wrapper=self._client_wrapper) + self._batch: typing.Optional[AsyncBatchClient] = None + self._context: typing.Optional[AsyncContextClient] = None + self._graph: typing.Optional[AsyncGraphClient] = None + self._lookup: typing.Optional[AsyncLookupClient] = None + self._project: typing.Optional[AsyncProjectClient] = None + self._task: typing.Optional[AsyncTaskClient] = None + self._thread: typing.Optional[AsyncThreadClient] = None + self._user: typing.Optional[AsyncUserClient] = None + + @property + def batch(self): + if self._batch is None: + from .batch.client import AsyncBatchClient # noqa: E402 + + self._batch = AsyncBatchClient(client_wrapper=self._client_wrapper) + return self._batch + + @property + def context(self): + if self._context is None: + from .context.client import AsyncContextClient # noqa: E402 + + self._context = AsyncContextClient(client_wrapper=self._client_wrapper) + return self._context + + @property + def graph(self): + if self._graph is None: + from .graph.client import AsyncGraphClient # noqa: E402 + + self._graph = AsyncGraphClient(client_wrapper=self._client_wrapper) + return self._graph + + @property + def lookup(self): + if self._lookup is None: + from .lookup.client import AsyncLookupClient # noqa: E402 + + self._lookup = AsyncLookupClient(client_wrapper=self._client_wrapper) + return self._lookup + + @property + def project(self): + if self._project is None: + from .project.client import AsyncProjectClient # noqa: E402 + + self._project = AsyncProjectClient(client_wrapper=self._client_wrapper) + return self._project + + @property + def task(self): + if self._task is None: + from .task.client import AsyncTaskClient # noqa: E402 + + self._task = AsyncTaskClient(client_wrapper=self._client_wrapper) + return self._task + + @property + def thread(self): + if self._thread is None: + from .thread.client import AsyncThreadClient # noqa: E402 + + self._thread = AsyncThreadClient(client_wrapper=self._client_wrapper) + return self._thread + + @property + def user(self): + if self._user is None: + from .user.client import AsyncUserClient # noqa: E402 + + self._user = AsyncUserClient(client_wrapper=self._client_wrapper) + return self._user def _get_base_url(*, base_url: typing.Optional[str] = None, environment: ZepEnvironment) -> str: diff --git a/src/zep_cloud/batch/client.py b/src/zep_cloud/batch/client.py index 4b56e20a..53f73d86 100644 --- a/src/zep_cloud/batch/client.py +++ b/src/zep_cloud/batch/client.py @@ -3,14 +3,14 @@ import typing from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper +from ..core.pagination import AsyncPager, SyncPager from ..core.request_options import RequestOptions -from ..types.batch_add_item import BatchAddItem -from ..types.batch_item_detail import BatchItemDetail -from ..types.batch_item_list_response import BatchItemListResponse -from ..types.batch_list_response import BatchListResponse -from ..types.batch_summary import BatchSummary -from ..types.role_type import RoleType -from ..types.success_response import SuccessResponse +from ..types.batch import Batch +from ..types.batch_items_response import BatchItemsResponse +from ..types.batch_page import BatchPage +from ..types.json_object import JsonObject +from ..types.json_object_page import JsonObjectPage +from ..types.process_batch_result import ProcessBatchResult from .raw_client import AsyncRawBatchClient, RawBatchClient # this is used as the default value for optional parameters @@ -36,31 +36,29 @@ def list( self, *, limit: typing.Optional[int] = None, - cursor: typing.Optional[int] = None, + cursor: typing.Optional[str] = None, status: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> BatchListResponse: + ) -> SyncPager[Batch, BatchPage]: """ - List batches for the current project, optionally filtered by batch status. - Parameters ---------- limit : typing.Optional[int] - Maximum number of batches to return. + Page size - cursor : typing.Optional[int] - Pagination cursor from a previous response. + cursor : typing.Optional[str] + Opaque page cursor status : typing.Optional[str] - Batch status filter. + Batch status filter request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - BatchListResponse - Batch list + SyncPager[Batch, BatchPage] + OK Examples -------- @@ -69,42 +67,46 @@ def list( client = Zep( api_key="YOUR_API_KEY", ) - client.batch.list( + response = client.batch.list( limit=1, - cursor=1, + cursor="cursor", status="status", ) + for item in response: + yield item + # alternatively, you can paginate page-by-page + for page in response.iter_pages(): + yield page """ - _response = self._raw_client.list(limit=limit, cursor=cursor, status=status, request_options=request_options) - return _response.data + return self._raw_client.list(limit=limit, cursor=cursor, status=status, request_options=request_options) def create( self, *, - ignore_roles: typing.Optional[typing.Sequence[RoleType]] = OMIT, - metadata: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = OMIT, + ignore_roles: typing.Optional[typing.Sequence[str]] = OMIT, + metadata: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + strict_ontology: typing.Optional[bool] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> BatchSummary: + ) -> Batch: """ - Create a draft batch that can be filled with graph episodes and thread messages. - Parameters ---------- - ignore_roles : typing.Optional[typing.Sequence[RoleType]] - Optional list of message role types to skip during graph ingestion for - thread_message items in this batch. The messages are still stored and - retained as context, but no graph extraction is performed for them. - Has no effect on graph_episode items. + ignore_roles : typing.Optional[typing.Sequence[str]] + + metadata : typing.Optional[typing.Dict[str, typing.Any]] - metadata : typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] + strict_ontology : typing.Optional[bool] + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - BatchSummary - Created batch + Batch + Created Examples -------- @@ -116,26 +118,28 @@ 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, + idempotency_key=idempotency_key, + request_options=request_options, ) return _response.data - def get(self, batch_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> BatchSummary: + def get(self, batch_uuid: str, *, request_options: typing.Optional[RequestOptions] = None) -> Batch: """ - Get a batch summary, including runtime progress when the batch has been processed. - Parameters ---------- - batch_id : str - The batch ID. + batch_uuid : str + Batch UUID request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - BatchSummary - Batch summary + Batch + OK Examples -------- @@ -145,28 +149,33 @@ def get(self, batch_id: str, *, request_options: typing.Optional[RequestOptions] api_key="YOUR_API_KEY", ) client.batch.get( - batch_id="batchId", + batch_uuid="batch_uuid", ) """ - _response = self._raw_client.get(batch_id, request_options=request_options) + _response = self._raw_client.get(batch_uuid, request_options=request_options) return _response.data - def delete(self, batch_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> SuccessResponse: + def delete( + self, + batch_uuid: str, + *, + idempotency_key: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> None: """ - Delete a draft or invalid unprocessed batch. Processed batches cannot be deleted. - Parameters ---------- - batch_id : str - The batch ID. + batch_uuid : str + Batch UUID + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - SuccessResponse - Deleted batch + None Examples -------- @@ -176,45 +185,41 @@ def delete(self, batch_id: str, *, request_options: typing.Optional[RequestOptio api_key="YOUR_API_KEY", ) client.batch.delete( - batch_id="batchId", + batch_uuid="batch_uuid", ) """ - _response = self._raw_client.delete(batch_id, request_options=request_options) + _response = self._raw_client.delete( + batch_uuid, idempotency_key=idempotency_key, request_options=request_options + ) return _response.data def list_items( self, - batch_id: str, + batch_uuid: str, *, limit: typing.Optional[int] = None, - cursor: typing.Optional[int] = None, - status: typing.Optional[str] = None, + cursor: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> BatchItemListResponse: + ) -> SyncPager[JsonObject, JsonObjectPage]: """ - List items in a batch, including derived runtime status when the batch has been processed. - Parameters ---------- - batch_id : str - The batch ID. + batch_uuid : str + Batch UUID limit : typing.Optional[int] - Maximum number of batch items to return. - - cursor : typing.Optional[int] - Pagination cursor from a previous response. + Page size - status : typing.Optional[str] - Batch item status filter. + cursor : typing.Optional[str] + Opaque page cursor request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - BatchItemListResponse - Batch item list + SyncPager[JsonObject, JsonObjectPage] + OK Examples -------- @@ -223,78 +228,83 @@ def list_items( client = Zep( api_key="YOUR_API_KEY", ) - client.batch.list_items( - batch_id="batchId", + response = client.batch.list_items( + batch_uuid="batch_uuid", limit=1, - cursor=1, - status="status", + cursor="cursor", ) + for item in response: + yield item + # alternatively, you can paginate page-by-page + for page in response.iter_pages(): + yield page """ - _response = self._raw_client.list_items( - batch_id, limit=limit, cursor=cursor, status=status, request_options=request_options - ) - return _response.data + return self._raw_client.list_items(batch_uuid, limit=limit, cursor=cursor, request_options=request_options) - def add( + def add_items( self, - batch_id: str, + batch_uuid: str, *, - items: typing.Sequence[BatchAddItem], + items: typing.Optional[typing.Sequence[typing.Dict[str, typing.Any]]] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> typing.List[BatchItemDetail]: + ) -> BatchItemsResponse: """ - Add graph episodes and thread messages to a draft batch. Items are appended in request order. - Parameters ---------- - batch_id : str - The batch ID. + batch_uuid : str + Batch UUID + + items : typing.Optional[typing.Sequence[typing.Dict[str, typing.Any]]] - items : typing.Sequence[BatchAddItem] + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - typing.List[BatchItemDetail] - Added batch items + BatchItemsResponse + OK Examples -------- - from zep_cloud import BatchAddItem, Zep + from zep_cloud import Zep client = Zep( api_key="YOUR_API_KEY", ) - client.batch.add( - batch_id="batchId", - items=[ - BatchAddItem( - type="graph_episode", - ) - ], + client.batch.add_items( + batch_uuid="batch_uuid", ) """ - _response = self._raw_client.add(batch_id, items=items, request_options=request_options) + _response = self._raw_client.add_items( + batch_uuid, items=items, idempotency_key=idempotency_key, request_options=request_options + ) return _response.data - def process(self, batch_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> BatchSummary: + def process( + self, + batch_uuid: str, + *, + idempotency_key: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> ProcessBatchResult: """ - Start processing a filled batch. Repeated calls return a conflict. - Parameters ---------- - batch_id : str - The batch ID. + batch_uuid : str + Batch UUID + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - BatchSummary - Batch processing state + ProcessBatchResult + Accepted Examples -------- @@ -304,10 +314,12 @@ def process(self, batch_id: str, *, request_options: typing.Optional[RequestOpti api_key="YOUR_API_KEY", ) client.batch.process( - batch_id="batchId", + batch_uuid="batch_uuid", ) """ - _response = self._raw_client.process(batch_id, request_options=request_options) + _response = self._raw_client.process( + batch_uuid, idempotency_key=idempotency_key, request_options=request_options + ) return _response.data @@ -330,31 +342,29 @@ async def list( self, *, limit: typing.Optional[int] = None, - cursor: typing.Optional[int] = None, + cursor: typing.Optional[str] = None, status: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> BatchListResponse: + ) -> AsyncPager[Batch, BatchPage]: """ - List batches for the current project, optionally filtered by batch status. - Parameters ---------- limit : typing.Optional[int] - Maximum number of batches to return. + Page size - cursor : typing.Optional[int] - Pagination cursor from a previous response. + cursor : typing.Optional[str] + Opaque page cursor status : typing.Optional[str] - Batch status filter. + Batch status filter request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - BatchListResponse - Batch list + AsyncPager[Batch, BatchPage] + OK Examples -------- @@ -368,47 +378,50 @@ async def list( async def main() -> None: - await client.batch.list( + response = await client.batch.list( limit=1, - cursor=1, + cursor="cursor", status="status", ) + async for item in response: + yield item + + # alternatively, you can paginate page-by-page + async for page in response.iter_pages(): + yield page asyncio.run(main()) """ - _response = await self._raw_client.list( - limit=limit, cursor=cursor, status=status, request_options=request_options - ) - return _response.data + return await self._raw_client.list(limit=limit, cursor=cursor, status=status, request_options=request_options) async def create( self, *, - ignore_roles: typing.Optional[typing.Sequence[RoleType]] = OMIT, - metadata: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = OMIT, + ignore_roles: typing.Optional[typing.Sequence[str]] = OMIT, + metadata: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + strict_ontology: typing.Optional[bool] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> BatchSummary: + ) -> Batch: """ - Create a draft batch that can be filled with graph episodes and thread messages. - Parameters ---------- - ignore_roles : typing.Optional[typing.Sequence[RoleType]] - Optional list of message role types to skip during graph ingestion for - thread_message items in this batch. The messages are still stored and - retained as context, but no graph extraction is performed for them. - Has no effect on graph_episode items. + ignore_roles : typing.Optional[typing.Sequence[str]] - metadata : typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] + metadata : typing.Optional[typing.Dict[str, typing.Any]] + + strict_ontology : typing.Optional[bool] + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - BatchSummary - Created batch + Batch + Created Examples -------- @@ -428,26 +441,28 @@ 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, + idempotency_key=idempotency_key, + request_options=request_options, ) return _response.data - async def get(self, batch_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> BatchSummary: + async def get(self, batch_uuid: str, *, request_options: typing.Optional[RequestOptions] = None) -> Batch: """ - Get a batch summary, including runtime progress when the batch has been processed. - Parameters ---------- - batch_id : str - The batch ID. + batch_uuid : str + Batch UUID request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - BatchSummary - Batch summary + Batch + OK Examples -------- @@ -462,33 +477,36 @@ async def get(self, batch_id: str, *, request_options: typing.Optional[RequestOp async def main() -> None: await client.batch.get( - batch_id="batchId", + batch_uuid="batch_uuid", ) asyncio.run(main()) """ - _response = await self._raw_client.get(batch_id, request_options=request_options) + _response = await self._raw_client.get(batch_uuid, request_options=request_options) return _response.data async def delete( - self, batch_id: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> SuccessResponse: + self, + batch_uuid: str, + *, + idempotency_key: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> None: """ - Delete a draft or invalid unprocessed batch. Processed batches cannot be deleted. - Parameters ---------- - batch_id : str - The batch ID. + batch_uuid : str + Batch UUID + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - SuccessResponse - Deleted batch + None Examples -------- @@ -503,48 +521,44 @@ async def delete( async def main() -> None: await client.batch.delete( - batch_id="batchId", + batch_uuid="batch_uuid", ) asyncio.run(main()) """ - _response = await self._raw_client.delete(batch_id, request_options=request_options) + _response = await self._raw_client.delete( + batch_uuid, idempotency_key=idempotency_key, request_options=request_options + ) return _response.data async def list_items( self, - batch_id: str, + batch_uuid: str, *, limit: typing.Optional[int] = None, - cursor: typing.Optional[int] = None, - status: typing.Optional[str] = None, + cursor: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> BatchItemListResponse: + ) -> AsyncPager[JsonObject, JsonObjectPage]: """ - List items in a batch, including derived runtime status when the batch has been processed. - Parameters ---------- - batch_id : str - The batch ID. + batch_uuid : str + Batch UUID limit : typing.Optional[int] - Maximum number of batch items to return. + Page size - cursor : typing.Optional[int] - Pagination cursor from a previous response. - - status : typing.Optional[str] - Batch item status filter. + cursor : typing.Optional[str] + Opaque page cursor request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - BatchItemListResponse - Batch item list + AsyncPager[JsonObject, JsonObjectPage] + OK Examples -------- @@ -558,51 +572,56 @@ async def list_items( async def main() -> None: - await client.batch.list_items( - batch_id="batchId", + response = await client.batch.list_items( + batch_uuid="batch_uuid", limit=1, - cursor=1, - status="status", + cursor="cursor", ) + async for item in response: + yield item + + # alternatively, you can paginate page-by-page + async for page in response.iter_pages(): + yield page asyncio.run(main()) """ - _response = await self._raw_client.list_items( - batch_id, limit=limit, cursor=cursor, status=status, request_options=request_options + return await self._raw_client.list_items( + batch_uuid, limit=limit, cursor=cursor, request_options=request_options ) - return _response.data - async def add( + async def add_items( self, - batch_id: str, + batch_uuid: str, *, - items: typing.Sequence[BatchAddItem], + items: typing.Optional[typing.Sequence[typing.Dict[str, typing.Any]]] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> typing.List[BatchItemDetail]: + ) -> BatchItemsResponse: """ - Add graph episodes and thread messages to a draft batch. Items are appended in request order. - Parameters ---------- - batch_id : str - The batch ID. + batch_uuid : str + Batch UUID - items : typing.Sequence[BatchAddItem] + items : typing.Optional[typing.Sequence[typing.Dict[str, typing.Any]]] + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - typing.List[BatchItemDetail] - Added batch items + BatchItemsResponse + OK Examples -------- import asyncio - from zep_cloud import AsyncZep, BatchAddItem + from zep_cloud import AsyncZep client = AsyncZep( api_key="YOUR_API_KEY", @@ -610,37 +629,40 @@ async def add( async def main() -> None: - await client.batch.add( - batch_id="batchId", - items=[ - BatchAddItem( - type="graph_episode", - ) - ], + await client.batch.add_items( + batch_uuid="batch_uuid", ) asyncio.run(main()) """ - _response = await self._raw_client.add(batch_id, items=items, request_options=request_options) + _response = await self._raw_client.add_items( + batch_uuid, items=items, idempotency_key=idempotency_key, request_options=request_options + ) return _response.data - async def process(self, batch_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> BatchSummary: + async def process( + self, + batch_uuid: str, + *, + idempotency_key: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> ProcessBatchResult: """ - Start processing a filled batch. Repeated calls return a conflict. - Parameters ---------- - batch_id : str - The batch ID. + batch_uuid : str + Batch UUID + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - BatchSummary - Batch processing state + ProcessBatchResult + Accepted Examples -------- @@ -655,11 +677,13 @@ async def process(self, batch_id: str, *, request_options: typing.Optional[Reque async def main() -> None: await client.batch.process( - batch_id="batchId", + batch_uuid="batch_uuid", ) asyncio.run(main()) """ - _response = await self._raw_client.process(batch_id, request_options=request_options) + _response = await self._raw_client.process( + batch_uuid, idempotency_key=idempotency_key, 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..d7a9bbf1 100644 --- a/src/zep_cloud/batch/raw_client.py +++ b/src/zep_cloud/batch/raw_client.py @@ -7,22 +7,21 @@ from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper from ..core.http_response import AsyncHttpResponse, HttpResponse from ..core.jsonable_encoder import jsonable_encoder +from ..core.pagination import AsyncPager, SyncPager +from ..core.parse_error import ParsingError 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.conflict_error import ConflictError -from ..errors.forbidden_error import ForbiddenError -from ..errors.internal_server_error import InternalServerError from ..errors.not_found_error import NotFoundError +from ..errors.unauthorized_error import UnauthorizedError from ..types.api_error import ApiError as types_api_error_ApiError -from ..types.batch_add_item import BatchAddItem -from ..types.batch_item_detail import BatchItemDetail -from ..types.batch_item_list_response import BatchItemListResponse -from ..types.batch_list_response import BatchListResponse -from ..types.batch_summary import BatchSummary -from ..types.role_type import RoleType -from ..types.success_response import SuccessResponse +from ..types.batch import Batch +from ..types.batch_items_response import BatchItemsResponse +from ..types.batch_page import BatchPage +from ..types.json_object import JsonObject +from ..types.json_object_page import JsonObjectPage +from ..types.process_batch_result import ProcessBatchResult +from pydantic import ValidationError # this is used as the default value for optional parameters OMIT = typing.cast(typing.Any, ...) @@ -36,31 +35,29 @@ def list( self, *, limit: typing.Optional[int] = None, - cursor: typing.Optional[int] = None, + cursor: typing.Optional[str] = None, status: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> HttpResponse[BatchListResponse]: + ) -> SyncPager[Batch, BatchPage]: """ - List batches for the current project, optionally filtered by batch status. - Parameters ---------- limit : typing.Optional[int] - Maximum number of batches to return. + Page size - cursor : typing.Optional[int] - Pagination cursor from a previous response. + cursor : typing.Optional[str] + Opaque page cursor status : typing.Optional[str] - Batch status filter. + Batch status filter request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - HttpResponse[BatchListResponse] - Batch list + SyncPager[Batch, BatchPage] + OK """ _response = self._client_wrapper.httpx_client.request( "batches", @@ -74,27 +71,36 @@ def list( ) try: if 200 <= _response.status_code < 300: - _data = typing.cast( - BatchListResponse, + _parsed_response = typing.cast( + BatchPage, parse_obj_as( - type_=BatchListResponse, # type: ignore + type_=BatchPage, # type: ignore object_=_response.json(), ), ) - return HttpResponse(response=_response, data=_data) + _items = _parsed_response.items + _parsed_next = _parsed_response.next_cursor + _has_next = _parsed_next is not None and _parsed_next != "" + _get_next = lambda: self.list( + limit=limit, + cursor=_parsed_next, + status=status, + request_options=request_options, + ) + return SyncPager(has_next=_has_next, items=_items, get_next=_get_next, response=_parsed_response) if _response.status_code == 400: raise BadRequestError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore object_=_response.json(), ), ), ) - if _response.status_code == 403: - raise ForbiddenError( + if _response.status_code == 401: + raise UnauthorizedError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -104,8 +110,8 @@ def list( ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -120,6 +126,10 @@ def list( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) @@ -127,30 +137,30 @@ def list( def create( self, *, - ignore_roles: typing.Optional[typing.Sequence[RoleType]] = OMIT, - metadata: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = OMIT, + ignore_roles: typing.Optional[typing.Sequence[str]] = OMIT, + metadata: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + strict_ontology: typing.Optional[bool] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> HttpResponse[BatchSummary]: + ) -> HttpResponse[Batch]: """ - Create a draft batch that can be filled with graph episodes and thread messages. - Parameters ---------- - ignore_roles : typing.Optional[typing.Sequence[RoleType]] - Optional list of message role types to skip during graph ingestion for - thread_message items in this batch. The messages are still stored and - retained as context, but no graph extraction is performed for them. - Has no effect on graph_episode items. + ignore_roles : typing.Optional[typing.Sequence[str]] + + metadata : typing.Optional[typing.Dict[str, typing.Any]] - metadata : typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] + strict_ontology : typing.Optional[bool] + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - HttpResponse[BatchSummary] - Created batch + HttpResponse[Batch] + Created """ _response = self._client_wrapper.httpx_client.request( "batches", @@ -158,9 +168,11 @@ def create( json={ "ignore_roles": ignore_roles, "metadata": metadata, + "strict_ontology": strict_ontology, }, headers={ "content-type": "application/json", + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, }, request_options=request_options, omit=OMIT, @@ -168,9 +180,9 @@ def create( try: if 200 <= _response.status_code < 300: _data = typing.cast( - BatchSummary, + Batch, parse_obj_as( - type_=BatchSummary, # type: ignore + type_=Batch, # type: ignore object_=_response.json(), ), ) @@ -179,15 +191,15 @@ def create( raise BadRequestError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore object_=_response.json(), ), ), ) - if _response.status_code == 403: - raise ForbiddenError( + if _response.status_code == 401: + raise UnauthorizedError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -197,8 +209,8 @@ def create( ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -213,57 +225,46 @@ def create( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - def get( - self, batch_id: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> HttpResponse[BatchSummary]: + def get(self, batch_uuid: str, *, request_options: typing.Optional[RequestOptions] = None) -> HttpResponse[Batch]: """ - Get a batch summary, including runtime progress when the batch has been processed. - Parameters ---------- - batch_id : str - The batch ID. + batch_uuid : str + Batch UUID request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - HttpResponse[BatchSummary] - Batch summary + HttpResponse[Batch] + OK """ _response = self._client_wrapper.httpx_client.request( - f"batches/{jsonable_encoder(batch_id)}", + f"batches/{jsonable_encoder(batch_uuid)}", method="GET", request_options=request_options, ) try: if 200 <= _response.status_code < 300: _data = typing.cast( - BatchSummary, + Batch, parse_obj_as( - type_=BatchSummary, # type: ignore + type_=Batch, # type: ignore object_=_response.json(), ), ) return HttpResponse(response=_response, data=_data) if _response.status_code == 400: raise BadRequestError( - headers=dict(_response.headers), - body=typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ), - ) - if _response.status_code == 403: - raise ForbiddenError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -273,8 +274,8 @@ def get( ), ), ) - if _response.status_code == 404: - raise NotFoundError( + if _response.status_code == 401: + raise UnauthorizedError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -284,8 +285,8 @@ def get( ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -300,68 +301,49 @@ def get( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) def delete( - self, batch_id: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> HttpResponse[SuccessResponse]: + self, + batch_uuid: str, + *, + idempotency_key: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[None]: """ - Delete a draft or invalid unprocessed batch. Processed batches cannot be deleted. - Parameters ---------- - batch_id : str - The batch ID. + batch_uuid : str + Batch UUID + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - HttpResponse[SuccessResponse] - Deleted batch + HttpResponse[None] """ _response = self._client_wrapper.httpx_client.request( - f"batches/{jsonable_encoder(batch_id)}", + f"batches/{jsonable_encoder(batch_uuid)}", method="DELETE", + headers={ + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, + }, request_options=request_options, ) try: if 200 <= _response.status_code < 300: - _data = typing.cast( - SuccessResponse, - parse_obj_as( - type_=SuccessResponse, # type: ignore - object_=_response.json(), - ), - ) - return HttpResponse(response=_response, data=_data) + return HttpResponse(response=_response, data=None) if _response.status_code == 400: raise BadRequestError( - headers=dict(_response.headers), - body=typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ), - ) - if _response.status_code == 403: - raise ForbiddenError( - headers=dict(_response.headers), - body=typing.cast( - types_api_error_ApiError, - parse_obj_as( - type_=types_api_error_ApiError, # type: ignore - object_=_response.json(), - ), - ), - ) - if _response.status_code == 404: - raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -371,8 +353,8 @@ def delete( ), ), ) - if _response.status_code == 409: - raise ConflictError( + if _response.status_code == 401: + raise UnauthorizedError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -382,8 +364,8 @@ def delete( ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -398,77 +380,72 @@ def delete( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) def list_items( self, - batch_id: str, + batch_uuid: str, *, limit: typing.Optional[int] = None, - cursor: typing.Optional[int] = None, - status: typing.Optional[str] = None, + cursor: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> HttpResponse[BatchItemListResponse]: + ) -> SyncPager[JsonObject, JsonObjectPage]: """ - List items in a batch, including derived runtime status when the batch has been processed. - Parameters ---------- - batch_id : str - The batch ID. + batch_uuid : str + Batch UUID limit : typing.Optional[int] - Maximum number of batch items to return. + Page size - cursor : typing.Optional[int] - Pagination cursor from a previous response. - - status : typing.Optional[str] - Batch item status filter. + cursor : typing.Optional[str] + Opaque page cursor request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - HttpResponse[BatchItemListResponse] - Batch item list + SyncPager[JsonObject, JsonObjectPage] + OK """ _response = self._client_wrapper.httpx_client.request( - f"batches/{jsonable_encoder(batch_id)}/items", + f"batches/{jsonable_encoder(batch_uuid)}/items", method="GET", params={ "limit": limit, "cursor": cursor, - "status": status, }, request_options=request_options, ) try: if 200 <= _response.status_code < 300: - _data = typing.cast( - BatchItemListResponse, + _parsed_response = typing.cast( + JsonObjectPage, parse_obj_as( - type_=BatchItemListResponse, # type: ignore + type_=JsonObjectPage, # type: ignore object_=_response.json(), ), ) - return HttpResponse(response=_response, data=_data) + _items = _parsed_response.items + _parsed_next = _parsed_response.next_cursor + _has_next = _parsed_next is not None and _parsed_next != "" + _get_next = lambda: self.list_items( + batch_uuid, + limit=limit, + cursor=_parsed_next, + request_options=request_options, + ) + return SyncPager(has_next=_has_next, items=_items, get_next=_get_next, response=_parsed_response) if _response.status_code == 400: raise BadRequestError( - headers=dict(_response.headers), - body=typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ), - ) - if _response.status_code == 403: - raise ForbiddenError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -478,8 +455,8 @@ def list_items( ), ), ) - if _response.status_code == 404: - raise NotFoundError( + if _response.status_code == 401: + raise UnauthorizedError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -489,8 +466,8 @@ def list_items( ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -505,45 +482,49 @@ def list_items( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - def add( + def add_items( self, - batch_id: str, + batch_uuid: str, *, - items: typing.Sequence[BatchAddItem], + items: typing.Optional[typing.Sequence[typing.Dict[str, typing.Any]]] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> HttpResponse[typing.List[BatchItemDetail]]: + ) -> HttpResponse[BatchItemsResponse]: """ - Add graph episodes and thread messages to a draft batch. Items are appended in request order. - Parameters ---------- - batch_id : str - The batch ID. + batch_uuid : str + Batch UUID - items : typing.Sequence[BatchAddItem] + items : typing.Optional[typing.Sequence[typing.Dict[str, typing.Any]]] + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - HttpResponse[typing.List[BatchItemDetail]] - Added batch items + HttpResponse[BatchItemsResponse] + OK """ _response = self._client_wrapper.httpx_client.request( - f"batches/{jsonable_encoder(batch_id)}/items", + f"batches/{jsonable_encoder(batch_uuid)}/items", method="POST", json={ - "items": convert_and_respect_annotation_metadata( - object_=items, annotation=typing.Sequence[BatchAddItem], direction="write" - ), + "items": items, }, headers={ "content-type": "application/json", + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, }, request_options=request_options, omit=OMIT, @@ -551,37 +532,15 @@ def add( try: if 200 <= _response.status_code < 300: _data = typing.cast( - typing.List[BatchItemDetail], + BatchItemsResponse, parse_obj_as( - type_=typing.List[BatchItemDetail], # type: ignore + type_=BatchItemsResponse, # type: ignore object_=_response.json(), ), ) return HttpResponse(response=_response, data=_data) if _response.status_code == 400: raise BadRequestError( - headers=dict(_response.headers), - body=typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ), - ) - if _response.status_code == 403: - raise ForbiddenError( - headers=dict(_response.headers), - body=typing.cast( - types_api_error_ApiError, - parse_obj_as( - type_=types_api_error_ApiError, # type: ignore - object_=_response.json(), - ), - ), - ) - if _response.status_code == 404: - raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -591,8 +550,8 @@ def add( ), ), ) - if _response.status_code == 409: - raise ConflictError( + if _response.status_code == 401: + raise UnauthorizedError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -602,8 +561,8 @@ def add( ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -618,57 +577,57 @@ def add( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) def process( - self, batch_id: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> HttpResponse[BatchSummary]: + self, + batch_uuid: str, + *, + idempotency_key: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[ProcessBatchResult]: """ - Start processing a filled batch. Repeated calls return a conflict. - Parameters ---------- - batch_id : str - The batch ID. + batch_uuid : str + Batch UUID + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - HttpResponse[BatchSummary] - Batch processing state + HttpResponse[ProcessBatchResult] + Accepted """ _response = self._client_wrapper.httpx_client.request( - f"batches/{jsonable_encoder(batch_id)}/process", + f"batches/{jsonable_encoder(batch_uuid)}/process", method="POST", + headers={ + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, + }, request_options=request_options, ) try: if 200 <= _response.status_code < 300: _data = typing.cast( - BatchSummary, + ProcessBatchResult, parse_obj_as( - type_=BatchSummary, # type: ignore + type_=ProcessBatchResult, # type: ignore object_=_response.json(), ), ) return HttpResponse(response=_response, data=_data) if _response.status_code == 400: raise BadRequestError( - headers=dict(_response.headers), - body=typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ), - ) - if _response.status_code == 403: - raise ForbiddenError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -678,8 +637,8 @@ def process( ), ), ) - if _response.status_code == 404: - raise NotFoundError( + if _response.status_code == 401: + raise UnauthorizedError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -689,19 +648,8 @@ def process( ), ), ) - if _response.status_code == 409: - raise ConflictError( - 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( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -716,6 +664,10 @@ def process( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) @@ -729,31 +681,29 @@ async def list( self, *, limit: typing.Optional[int] = None, - cursor: typing.Optional[int] = None, + cursor: typing.Optional[str] = None, status: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> AsyncHttpResponse[BatchListResponse]: + ) -> AsyncPager[Batch, BatchPage]: """ - List batches for the current project, optionally filtered by batch status. - Parameters ---------- limit : typing.Optional[int] - Maximum number of batches to return. + Page size - cursor : typing.Optional[int] - Pagination cursor from a previous response. + cursor : typing.Optional[str] + Opaque page cursor status : typing.Optional[str] - Batch status filter. + Batch status filter request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - AsyncHttpResponse[BatchListResponse] - Batch list + AsyncPager[Batch, BatchPage] + OK """ _response = await self._client_wrapper.httpx_client.request( "batches", @@ -767,27 +717,39 @@ async def list( ) try: if 200 <= _response.status_code < 300: - _data = typing.cast( - BatchListResponse, + _parsed_response = typing.cast( + BatchPage, parse_obj_as( - type_=BatchListResponse, # type: ignore + type_=BatchPage, # type: ignore object_=_response.json(), ), ) - return AsyncHttpResponse(response=_response, data=_data) + _items = _parsed_response.items + _parsed_next = _parsed_response.next_cursor + _has_next = _parsed_next is not None and _parsed_next != "" + + async def _get_next(): + return await self.list( + limit=limit, + cursor=_parsed_next, + status=status, + request_options=request_options, + ) + + return AsyncPager(has_next=_has_next, items=_items, get_next=_get_next, response=_parsed_response) if _response.status_code == 400: raise BadRequestError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore object_=_response.json(), ), ), ) - if _response.status_code == 403: - raise ForbiddenError( + if _response.status_code == 401: + raise UnauthorizedError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -797,8 +759,8 @@ async def list( ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -813,6 +775,10 @@ async def list( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) @@ -820,30 +786,30 @@ async def list( async def create( self, *, - ignore_roles: typing.Optional[typing.Sequence[RoleType]] = OMIT, - metadata: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = OMIT, + ignore_roles: typing.Optional[typing.Sequence[str]] = OMIT, + metadata: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + strict_ontology: typing.Optional[bool] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> AsyncHttpResponse[BatchSummary]: + ) -> AsyncHttpResponse[Batch]: """ - Create a draft batch that can be filled with graph episodes and thread messages. - Parameters ---------- - ignore_roles : typing.Optional[typing.Sequence[RoleType]] - Optional list of message role types to skip during graph ingestion for - thread_message items in this batch. The messages are still stored and - retained as context, but no graph extraction is performed for them. - Has no effect on graph_episode items. + ignore_roles : typing.Optional[typing.Sequence[str]] + + metadata : typing.Optional[typing.Dict[str, typing.Any]] - metadata : typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] + strict_ontology : typing.Optional[bool] + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - AsyncHttpResponse[BatchSummary] - Created batch + AsyncHttpResponse[Batch] + Created """ _response = await self._client_wrapper.httpx_client.request( "batches", @@ -851,9 +817,11 @@ async def create( json={ "ignore_roles": ignore_roles, "metadata": metadata, + "strict_ontology": strict_ontology, }, headers={ "content-type": "application/json", + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, }, request_options=request_options, omit=OMIT, @@ -861,9 +829,9 @@ async def create( try: if 200 <= _response.status_code < 300: _data = typing.cast( - BatchSummary, + Batch, parse_obj_as( - type_=BatchSummary, # type: ignore + type_=Batch, # type: ignore object_=_response.json(), ), ) @@ -872,15 +840,15 @@ async def create( raise BadRequestError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore object_=_response.json(), ), ), ) - if _response.status_code == 403: - raise ForbiddenError( + if _response.status_code == 401: + raise UnauthorizedError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -890,8 +858,8 @@ async def create( ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -906,57 +874,48 @@ async def create( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) async def get( - self, batch_id: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> AsyncHttpResponse[BatchSummary]: + self, batch_uuid: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> AsyncHttpResponse[Batch]: """ - Get a batch summary, including runtime progress when the batch has been processed. - Parameters ---------- - batch_id : str - The batch ID. + batch_uuid : str + Batch UUID request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - AsyncHttpResponse[BatchSummary] - Batch summary + AsyncHttpResponse[Batch] + OK """ _response = await self._client_wrapper.httpx_client.request( - f"batches/{jsonable_encoder(batch_id)}", + f"batches/{jsonable_encoder(batch_uuid)}", method="GET", request_options=request_options, ) try: if 200 <= _response.status_code < 300: _data = typing.cast( - BatchSummary, + Batch, parse_obj_as( - type_=BatchSummary, # type: ignore + type_=Batch, # type: ignore object_=_response.json(), ), ) return AsyncHttpResponse(response=_response, data=_data) if _response.status_code == 400: raise BadRequestError( - headers=dict(_response.headers), - body=typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ), - ) - if _response.status_code == 403: - raise ForbiddenError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -966,8 +925,8 @@ async def get( ), ), ) - if _response.status_code == 404: - raise NotFoundError( + if _response.status_code == 401: + raise UnauthorizedError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -977,8 +936,8 @@ async def get( ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -993,68 +952,49 @@ async def get( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) async def delete( - self, batch_id: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> AsyncHttpResponse[SuccessResponse]: + self, + batch_uuid: str, + *, + idempotency_key: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[None]: """ - Delete a draft or invalid unprocessed batch. Processed batches cannot be deleted. - Parameters ---------- - batch_id : str - The batch ID. + batch_uuid : str + Batch UUID + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - AsyncHttpResponse[SuccessResponse] - Deleted batch + AsyncHttpResponse[None] """ _response = await self._client_wrapper.httpx_client.request( - f"batches/{jsonable_encoder(batch_id)}", + f"batches/{jsonable_encoder(batch_uuid)}", method="DELETE", + headers={ + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, + }, request_options=request_options, ) try: if 200 <= _response.status_code < 300: - _data = typing.cast( - SuccessResponse, - parse_obj_as( - type_=SuccessResponse, # type: ignore - object_=_response.json(), - ), - ) - return AsyncHttpResponse(response=_response, data=_data) + return AsyncHttpResponse(response=_response, data=None) if _response.status_code == 400: raise BadRequestError( - headers=dict(_response.headers), - body=typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ), - ) - if _response.status_code == 403: - raise ForbiddenError( - headers=dict(_response.headers), - body=typing.cast( - types_api_error_ApiError, - parse_obj_as( - type_=types_api_error_ApiError, # type: ignore - object_=_response.json(), - ), - ), - ) - if _response.status_code == 404: - raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -1064,8 +1004,8 @@ async def delete( ), ), ) - if _response.status_code == 409: - raise ConflictError( + if _response.status_code == 401: + raise UnauthorizedError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -1075,8 +1015,8 @@ async def delete( ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -1091,77 +1031,75 @@ async def delete( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) async def list_items( self, - batch_id: str, + batch_uuid: str, *, limit: typing.Optional[int] = None, - cursor: typing.Optional[int] = None, - status: typing.Optional[str] = None, + cursor: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> AsyncHttpResponse[BatchItemListResponse]: + ) -> AsyncPager[JsonObject, JsonObjectPage]: """ - List items in a batch, including derived runtime status when the batch has been processed. - Parameters ---------- - batch_id : str - The batch ID. + batch_uuid : str + Batch UUID limit : typing.Optional[int] - Maximum number of batch items to return. + Page size - cursor : typing.Optional[int] - Pagination cursor from a previous response. - - status : typing.Optional[str] - Batch item status filter. + cursor : typing.Optional[str] + Opaque page cursor request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - AsyncHttpResponse[BatchItemListResponse] - Batch item list + AsyncPager[JsonObject, JsonObjectPage] + OK """ _response = await self._client_wrapper.httpx_client.request( - f"batches/{jsonable_encoder(batch_id)}/items", + f"batches/{jsonable_encoder(batch_uuid)}/items", method="GET", params={ "limit": limit, "cursor": cursor, - "status": status, }, request_options=request_options, ) try: if 200 <= _response.status_code < 300: - _data = typing.cast( - BatchItemListResponse, + _parsed_response = typing.cast( + JsonObjectPage, parse_obj_as( - type_=BatchItemListResponse, # type: ignore + type_=JsonObjectPage, # type: ignore object_=_response.json(), ), ) - return AsyncHttpResponse(response=_response, data=_data) + _items = _parsed_response.items + _parsed_next = _parsed_response.next_cursor + _has_next = _parsed_next is not None and _parsed_next != "" + + async def _get_next(): + return await self.list_items( + batch_uuid, + limit=limit, + cursor=_parsed_next, + request_options=request_options, + ) + + return AsyncPager(has_next=_has_next, items=_items, get_next=_get_next, response=_parsed_response) if _response.status_code == 400: raise BadRequestError( - headers=dict(_response.headers), - body=typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ), - ) - if _response.status_code == 403: - raise ForbiddenError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -1171,8 +1109,8 @@ async def list_items( ), ), ) - if _response.status_code == 404: - raise NotFoundError( + if _response.status_code == 401: + raise UnauthorizedError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -1182,8 +1120,8 @@ async def list_items( ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -1198,45 +1136,49 @@ async def list_items( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - async def add( + async def add_items( self, - batch_id: str, + batch_uuid: str, *, - items: typing.Sequence[BatchAddItem], + items: typing.Optional[typing.Sequence[typing.Dict[str, typing.Any]]] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> AsyncHttpResponse[typing.List[BatchItemDetail]]: + ) -> AsyncHttpResponse[BatchItemsResponse]: """ - Add graph episodes and thread messages to a draft batch. Items are appended in request order. - Parameters ---------- - batch_id : str - The batch ID. + batch_uuid : str + Batch UUID + + items : typing.Optional[typing.Sequence[typing.Dict[str, typing.Any]]] - items : typing.Sequence[BatchAddItem] + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - AsyncHttpResponse[typing.List[BatchItemDetail]] - Added batch items + AsyncHttpResponse[BatchItemsResponse] + OK """ _response = await self._client_wrapper.httpx_client.request( - f"batches/{jsonable_encoder(batch_id)}/items", + f"batches/{jsonable_encoder(batch_uuid)}/items", method="POST", json={ - "items": convert_and_respect_annotation_metadata( - object_=items, annotation=typing.Sequence[BatchAddItem], direction="write" - ), + "items": items, }, headers={ "content-type": "application/json", + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, }, request_options=request_options, omit=OMIT, @@ -1244,37 +1186,15 @@ async def add( try: if 200 <= _response.status_code < 300: _data = typing.cast( - typing.List[BatchItemDetail], + BatchItemsResponse, parse_obj_as( - type_=typing.List[BatchItemDetail], # type: ignore + type_=BatchItemsResponse, # type: ignore object_=_response.json(), ), ) return AsyncHttpResponse(response=_response, data=_data) if _response.status_code == 400: raise BadRequestError( - headers=dict(_response.headers), - body=typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ), - ) - if _response.status_code == 403: - raise ForbiddenError( - headers=dict(_response.headers), - body=typing.cast( - types_api_error_ApiError, - parse_obj_as( - type_=types_api_error_ApiError, # type: ignore - object_=_response.json(), - ), - ), - ) - if _response.status_code == 404: - raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -1284,8 +1204,8 @@ async def add( ), ), ) - if _response.status_code == 409: - raise ConflictError( + if _response.status_code == 401: + raise UnauthorizedError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -1295,8 +1215,8 @@ async def add( ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -1311,57 +1231,57 @@ async def add( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) async def process( - self, batch_id: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> AsyncHttpResponse[BatchSummary]: + self, + batch_uuid: str, + *, + idempotency_key: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[ProcessBatchResult]: """ - Start processing a filled batch. Repeated calls return a conflict. - Parameters ---------- - batch_id : str - The batch ID. + batch_uuid : str + Batch UUID + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - AsyncHttpResponse[BatchSummary] - Batch processing state + AsyncHttpResponse[ProcessBatchResult] + Accepted """ _response = await self._client_wrapper.httpx_client.request( - f"batches/{jsonable_encoder(batch_id)}/process", + f"batches/{jsonable_encoder(batch_uuid)}/process", method="POST", + headers={ + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, + }, request_options=request_options, ) try: if 200 <= _response.status_code < 300: _data = typing.cast( - BatchSummary, + ProcessBatchResult, parse_obj_as( - type_=BatchSummary, # type: ignore + type_=ProcessBatchResult, # type: ignore object_=_response.json(), ), ) return AsyncHttpResponse(response=_response, data=_data) if _response.status_code == 400: raise BadRequestError( - headers=dict(_response.headers), - body=typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ), - ) - if _response.status_code == 403: - raise ForbiddenError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -1371,8 +1291,8 @@ async def process( ), ), ) - if _response.status_code == 404: - raise NotFoundError( + if _response.status_code == 401: + raise UnauthorizedError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -1382,19 +1302,8 @@ async def process( ), ), ) - if _response.status_code == 409: - raise ConflictError( - 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( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -1409,6 +1318,10 @@ async def process( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) diff --git a/src/zep_cloud/context/client.py b/src/zep_cloud/context/client.py index 583c9edf..8ed77ced 100644 --- a/src/zep_cloud/context/client.py +++ b/src/zep_cloud/context/client.py @@ -3,10 +3,10 @@ import typing from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper +from ..core.pagination import AsyncPager, SyncPager from ..core.request_options import RequestOptions -from ..types.context_template_response import ContextTemplateResponse -from ..types.list_context_templates_response import ListContextTemplatesResponse -from ..types.success_response import SuccessResponse +from ..types.context_template import ContextTemplate +from ..types.context_template_page import ContextTemplatePage from .raw_client import AsyncRawContextClient, RawContextClient # this is used as the default value for optional parameters @@ -28,21 +28,30 @@ def with_raw_response(self) -> RawContextClient: """ return self._raw_client - def list_context_templates( - self, *, request_options: typing.Optional[RequestOptions] = None - ) -> ListContextTemplatesResponse: + def create_template( + self, + *, + name: typing.Optional[str] = OMIT, + template: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> ContextTemplate: """ - Lists all context templates. - Parameters ---------- + name : typing.Optional[str] + + template : typing.Optional[str] + + idempotency_key : typing.Optional[str] + request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - ListContextTemplatesResponse - The list of context templates. + ContextTemplate + Created Examples -------- @@ -51,32 +60,42 @@ def list_context_templates( client = Zep( api_key="YOUR_API_KEY", ) - client.context.list_context_templates() + client.context.create_template() """ - _response = self._raw_client.list_context_templates(request_options=request_options) + _response = self._raw_client.create_template( + name=name, template=template, idempotency_key=idempotency_key, request_options=request_options + ) return _response.data - def create_context_template( - self, *, template: str, template_id: str, request_options: typing.Optional[RequestOptions] = None - ) -> ContextTemplateResponse: + def list_templates( + self, + *, + limit: typing.Optional[int] = None, + cursor: typing.Optional[str] = None, + name: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> SyncPager[ContextTemplate, ContextTemplatePage]: """ - Creates a new context template. - Parameters ---------- - template : str - The template content (max 1200 characters). + limit : typing.Optional[int] + Page size + + cursor : typing.Optional[str] + Opaque page cursor - template_id : str - Unique identifier for the template (max 100 characters). + name : typing.Optional[str] + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - ContextTemplateResponse - The created context template. + SyncPager[ContextTemplate, ContextTemplatePage] + OK Examples -------- @@ -85,34 +104,36 @@ def create_context_template( client = Zep( api_key="YOUR_API_KEY", ) - client.context.create_context_template( - template="template", - template_id="template_id", + response = client.context.list_templates( + limit=1, + cursor="cursor", ) + for item in response: + yield item + # alternatively, you can paginate page-by-page + for page in response.iter_pages(): + yield page """ - _response = self._raw_client.create_context_template( - template=template, template_id=template_id, request_options=request_options + return self._raw_client.list_templates( + limit=limit, cursor=cursor, name=name, idempotency_key=idempotency_key, request_options=request_options ) - return _response.data - def get_context_template( - self, template_id: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> ContextTemplateResponse: + def get_template( + self, template_uuid: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> ContextTemplate: """ - Retrieves a context template by template_id. - Parameters ---------- - template_id : str - Template ID + template_uuid : str + Template UUID request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - ContextTemplateResponse - The context template. + ContextTemplate + OK Examples -------- @@ -121,34 +142,41 @@ def get_context_template( client = Zep( api_key="YOUR_API_KEY", ) - client.context.get_context_template( - template_id="template_id", + client.context.get_template( + template_uuid="template_uuid", ) """ - _response = self._raw_client.get_context_template(template_id, request_options=request_options) + _response = self._raw_client.get_template(template_uuid, request_options=request_options) return _response.data - def update_context_template( - self, template_id: str, *, template: str, request_options: typing.Optional[RequestOptions] = None - ) -> ContextTemplateResponse: + def update_template( + self, + template_uuid: str, + *, + name: typing.Optional[str] = OMIT, + template: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> ContextTemplate: """ - Updates an existing context template by template_id. - Parameters ---------- - template_id : str - Template ID + template_uuid : str + Template UUID + + name : typing.Optional[str] + + template : typing.Optional[str] - template : str - The template content (max 1200 characters). + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - ContextTemplateResponse - The updated context template. + ContextTemplate + OK Examples -------- @@ -157,34 +185,40 @@ def update_context_template( client = Zep( api_key="YOUR_API_KEY", ) - client.context.update_context_template( - template_id="template_id", - template="template", + client.context.update_template( + template_uuid="template_uuid", ) """ - _response = self._raw_client.update_context_template( - template_id, template=template, request_options=request_options + _response = self._raw_client.update_template( + template_uuid, + name=name, + template=template, + idempotency_key=idempotency_key, + request_options=request_options, ) return _response.data - def delete_context_template( - self, template_id: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> SuccessResponse: + def delete_template( + self, + template_uuid: str, + *, + idempotency_key: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> None: """ - Deletes a context template by template_id. - Parameters ---------- - template_id : str - Template ID + template_uuid : str + Template UUID + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - SuccessResponse - Template deleted successfully + None Examples -------- @@ -193,11 +227,13 @@ def delete_context_template( client = Zep( api_key="YOUR_API_KEY", ) - client.context.delete_context_template( - template_id="template_id", + client.context.delete_template( + template_uuid="template_uuid", ) """ - _response = self._raw_client.delete_context_template(template_id, request_options=request_options) + _response = self._raw_client.delete_template( + template_uuid, idempotency_key=idempotency_key, request_options=request_options + ) return _response.data @@ -216,21 +252,30 @@ def with_raw_response(self) -> AsyncRawContextClient: """ return self._raw_client - async def list_context_templates( - self, *, request_options: typing.Optional[RequestOptions] = None - ) -> ListContextTemplatesResponse: + async def create_template( + self, + *, + name: typing.Optional[str] = OMIT, + template: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> ContextTemplate: """ - Lists all context templates. - Parameters ---------- + name : typing.Optional[str] + + template : typing.Optional[str] + + idempotency_key : typing.Optional[str] + request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - ListContextTemplatesResponse - The list of context templates. + ContextTemplate + Created Examples -------- @@ -244,35 +289,45 @@ async def list_context_templates( async def main() -> None: - await client.context.list_context_templates() + await client.context.create_template() asyncio.run(main()) """ - _response = await self._raw_client.list_context_templates(request_options=request_options) + _response = await self._raw_client.create_template( + name=name, template=template, idempotency_key=idempotency_key, request_options=request_options + ) return _response.data - async def create_context_template( - self, *, template: str, template_id: str, request_options: typing.Optional[RequestOptions] = None - ) -> ContextTemplateResponse: + async def list_templates( + self, + *, + limit: typing.Optional[int] = None, + cursor: typing.Optional[str] = None, + name: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncPager[ContextTemplate, ContextTemplatePage]: """ - Creates a new context template. - Parameters ---------- - template : str - The template content (max 1200 characters). + limit : typing.Optional[int] + Page size + + cursor : typing.Optional[str] + Opaque page cursor - template_id : str - Unique identifier for the template (max 100 characters). + name : typing.Optional[str] + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - ContextTemplateResponse - The created context template. + AsyncPager[ContextTemplate, ContextTemplatePage] + OK Examples -------- @@ -286,37 +341,40 @@ async def create_context_template( async def main() -> None: - await client.context.create_context_template( - template="template", - template_id="template_id", + response = await client.context.list_templates( + limit=1, + cursor="cursor", ) + async for item in response: + yield item + + # alternatively, you can paginate page-by-page + async for page in response.iter_pages(): + yield page asyncio.run(main()) """ - _response = await self._raw_client.create_context_template( - template=template, template_id=template_id, request_options=request_options + return await self._raw_client.list_templates( + limit=limit, cursor=cursor, name=name, idempotency_key=idempotency_key, request_options=request_options ) - return _response.data - async def get_context_template( - self, template_id: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> ContextTemplateResponse: + async def get_template( + self, template_uuid: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> ContextTemplate: """ - Retrieves a context template by template_id. - Parameters ---------- - template_id : str - Template ID + template_uuid : str + Template UUID request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - ContextTemplateResponse - The context template. + ContextTemplate + OK Examples -------- @@ -330,37 +388,44 @@ async def get_context_template( async def main() -> None: - await client.context.get_context_template( - template_id="template_id", + await client.context.get_template( + template_uuid="template_uuid", ) asyncio.run(main()) """ - _response = await self._raw_client.get_context_template(template_id, request_options=request_options) + _response = await self._raw_client.get_template(template_uuid, request_options=request_options) return _response.data - async def update_context_template( - self, template_id: str, *, template: str, request_options: typing.Optional[RequestOptions] = None - ) -> ContextTemplateResponse: + async def update_template( + self, + template_uuid: str, + *, + name: typing.Optional[str] = OMIT, + template: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> ContextTemplate: """ - Updates an existing context template by template_id. - Parameters ---------- - template_id : str - Template ID + template_uuid : str + Template UUID + + name : typing.Optional[str] - template : str - The template content (max 1200 characters). + template : typing.Optional[str] + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - ContextTemplateResponse - The updated context template. + ContextTemplate + OK Examples -------- @@ -374,37 +439,43 @@ async def update_context_template( async def main() -> None: - await client.context.update_context_template( - template_id="template_id", - template="template", + await client.context.update_template( + template_uuid="template_uuid", ) asyncio.run(main()) """ - _response = await self._raw_client.update_context_template( - template_id, template=template, request_options=request_options + _response = await self._raw_client.update_template( + template_uuid, + name=name, + template=template, + idempotency_key=idempotency_key, + request_options=request_options, ) return _response.data - async def delete_context_template( - self, template_id: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> SuccessResponse: + async def delete_template( + self, + template_uuid: str, + *, + idempotency_key: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> None: """ - Deletes a context template by template_id. - Parameters ---------- - template_id : str - Template ID + template_uuid : str + Template UUID + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - SuccessResponse - Template deleted successfully + None Examples -------- @@ -418,12 +489,14 @@ async def delete_context_template( async def main() -> None: - await client.context.delete_context_template( - template_id="template_id", + await client.context.delete_template( + template_uuid="template_uuid", ) asyncio.run(main()) """ - _response = await self._raw_client.delete_context_template(template_id, request_options=request_options) + _response = await self._raw_client.delete_template( + template_uuid, idempotency_key=idempotency_key, request_options=request_options + ) return _response.data diff --git a/src/zep_cloud/context/raw_client.py b/src/zep_cloud/context/raw_client.py index 4fe59872..a843e543 100644 --- a/src/zep_cloud/context/raw_client.py +++ b/src/zep_cloud/context/raw_client.py @@ -7,15 +7,17 @@ from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper from ..core.http_response import AsyncHttpResponse, HttpResponse from ..core.jsonable_encoder import jsonable_encoder +from ..core.pagination import AsyncPager, SyncPager +from ..core.parse_error import ParsingError from ..core.pydantic_utilities import parse_obj_as from ..core.request_options import RequestOptions from ..errors.bad_request_error import BadRequestError -from ..errors.internal_server_error import InternalServerError from ..errors.not_found_error import NotFoundError +from ..errors.unauthorized_error import UnauthorizedError from ..types.api_error import ApiError as types_api_error_ApiError -from ..types.context_template_response import ContextTemplateResponse -from ..types.list_context_templates_response import ListContextTemplatesResponse -from ..types.success_response import SuccessResponse +from ..types.context_template import ContextTemplate +from ..types.context_template_page import ContextTemplatePage +from pydantic import ValidationError # this is used as the default value for optional parameters OMIT = typing.cast(typing.Any, ...) @@ -25,33 +27,51 @@ class RawContextClient: def __init__(self, *, client_wrapper: SyncClientWrapper): self._client_wrapper = client_wrapper - def list_context_templates( - self, *, request_options: typing.Optional[RequestOptions] = None - ) -> HttpResponse[ListContextTemplatesResponse]: + def create_template( + self, + *, + name: typing.Optional[str] = OMIT, + template: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[ContextTemplate]: """ - Lists all context templates. - Parameters ---------- + name : typing.Optional[str] + + template : typing.Optional[str] + + idempotency_key : typing.Optional[str] + request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - HttpResponse[ListContextTemplatesResponse] - The list of context templates. + HttpResponse[ContextTemplate] + Created """ _response = self._client_wrapper.httpx_client.request( "context-templates", - method="GET", + method="POST", + json={ + "name": name, + "template": template, + }, + headers={ + "content-type": "application/json", + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, + }, request_options=request_options, + omit=OMIT, ) try: if 200 <= _response.status_code < 300: _data = typing.cast( - ListContextTemplatesResponse, + ContextTemplate, parse_obj_as( - type_=ListContextTemplatesResponse, # type: ignore + type_=ContextTemplate, # type: ignore object_=_response.json(), ), ) @@ -60,15 +80,26 @@ def list_context_templates( raise BadRequestError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore object_=_response.json(), ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 401: + raise UnauthorizedError( + 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, @@ -83,68 +114,105 @@ def list_context_templates( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - def create_context_template( - self, *, template: str, template_id: str, request_options: typing.Optional[RequestOptions] = None - ) -> HttpResponse[ContextTemplateResponse]: + def list_templates( + self, + *, + limit: typing.Optional[int] = None, + cursor: typing.Optional[str] = None, + name: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> SyncPager[ContextTemplate, ContextTemplatePage]: """ - Creates a new context template. - Parameters ---------- - template : str - The template content (max 1200 characters). + limit : typing.Optional[int] + Page size - template_id : str - Unique identifier for the template (max 100 characters). + cursor : typing.Optional[str] + Opaque page cursor + + name : typing.Optional[str] + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - HttpResponse[ContextTemplateResponse] - The created context template. + SyncPager[ContextTemplate, ContextTemplatePage] + OK """ _response = self._client_wrapper.httpx_client.request( - "context-templates", + "context-templates/list", method="POST", + params={ + "limit": limit, + "cursor": cursor, + }, json={ - "template": template, - "template_id": template_id, + "name": name, }, headers={ "content-type": "application/json", + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, }, request_options=request_options, omit=OMIT, ) try: if 200 <= _response.status_code < 300: - _data = typing.cast( - ContextTemplateResponse, + _parsed_response = typing.cast( + ContextTemplatePage, parse_obj_as( - type_=ContextTemplateResponse, # type: ignore + type_=ContextTemplatePage, # type: ignore object_=_response.json(), ), ) - return HttpResponse(response=_response, data=_data) + _items = _parsed_response.items + _parsed_next = _parsed_response.next_cursor + _has_next = _parsed_next is not None and _parsed_next != "" + _get_next = lambda: self.list_templates( + limit=limit, + cursor=_parsed_next, + name=name, + idempotency_key=idempotency_key, + request_options=request_options, + ) + return SyncPager(has_next=_has_next, items=_items, get_next=_get_next, response=_parsed_response) if _response.status_code == 400: raise BadRequestError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore object_=_response.json(), ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -159,40 +227,42 @@ def create_context_template( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - def get_context_template( - self, template_id: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> HttpResponse[ContextTemplateResponse]: + def get_template( + self, template_uuid: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> HttpResponse[ContextTemplate]: """ - Retrieves a context template by template_id. - Parameters ---------- - template_id : str - Template ID + template_uuid : str + Template UUID request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - HttpResponse[ContextTemplateResponse] - The context template. + HttpResponse[ContextTemplate] + OK """ _response = self._client_wrapper.httpx_client.request( - f"context-templates/{jsonable_encoder(template_id)}", + f"context-templates/{jsonable_encoder(template_uuid)}", method="GET", request_options=request_options, ) try: if 200 <= _response.status_code < 300: _data = typing.cast( - ContextTemplateResponse, + ContextTemplate, parse_obj_as( - type_=ContextTemplateResponse, # type: ignore + type_=ContextTemplate, # type: ignore object_=_response.json(), ), ) @@ -201,15 +271,15 @@ def get_context_template( raise BadRequestError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore object_=_response.json(), ), ), ) - if _response.status_code == 404: - raise NotFoundError( + if _response.status_code == 401: + raise UnauthorizedError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -219,8 +289,8 @@ def get_context_template( ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -235,40 +305,53 @@ def get_context_template( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - def update_context_template( - self, template_id: str, *, template: str, request_options: typing.Optional[RequestOptions] = None - ) -> HttpResponse[ContextTemplateResponse]: + def update_template( + self, + template_uuid: str, + *, + name: typing.Optional[str] = OMIT, + template: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[ContextTemplate]: """ - Updates an existing context template by template_id. - Parameters ---------- - template_id : str - Template ID + template_uuid : str + Template UUID + + name : typing.Optional[str] - template : str - The template content (max 1200 characters). + template : typing.Optional[str] + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - HttpResponse[ContextTemplateResponse] - The updated context template. + HttpResponse[ContextTemplate] + OK """ _response = self._client_wrapper.httpx_client.request( - f"context-templates/{jsonable_encoder(template_id)}", + f"context-templates/{jsonable_encoder(template_uuid)}", method="PUT", json={ + "name": name, "template": template, }, headers={ "content-type": "application/json", + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, }, request_options=request_options, omit=OMIT, @@ -276,9 +359,9 @@ def update_context_template( try: if 200 <= _response.status_code < 300: _data = typing.cast( - ContextTemplateResponse, + ContextTemplate, parse_obj_as( - type_=ContextTemplateResponse, # type: ignore + type_=ContextTemplate, # type: ignore object_=_response.json(), ), ) @@ -287,15 +370,15 @@ def update_context_template( raise BadRequestError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore object_=_response.json(), ), ), ) - if _response.status_code == 404: - raise NotFoundError( + if _response.status_code == 401: + raise UnauthorizedError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -305,8 +388,8 @@ def update_context_template( ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -321,57 +404,60 @@ def update_context_template( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - def delete_context_template( - self, template_id: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> HttpResponse[SuccessResponse]: + def delete_template( + self, + template_uuid: str, + *, + idempotency_key: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[None]: """ - Deletes a context template by template_id. - Parameters ---------- - template_id : str - Template ID + template_uuid : str + Template UUID + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - HttpResponse[SuccessResponse] - Template deleted successfully + HttpResponse[None] """ _response = self._client_wrapper.httpx_client.request( - f"context-templates/{jsonable_encoder(template_id)}", + f"context-templates/{jsonable_encoder(template_uuid)}", method="DELETE", + headers={ + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, + }, request_options=request_options, ) try: if 200 <= _response.status_code < 300: - _data = typing.cast( - SuccessResponse, - parse_obj_as( - type_=SuccessResponse, # type: ignore - object_=_response.json(), - ), - ) - return HttpResponse(response=_response, data=_data) + return HttpResponse(response=_response, data=None) if _response.status_code == 400: raise BadRequestError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore object_=_response.json(), ), ), ) - if _response.status_code == 404: - raise NotFoundError( + if _response.status_code == 401: + raise UnauthorizedError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -381,8 +467,8 @@ def delete_context_template( ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -397,6 +483,10 @@ def delete_context_template( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) @@ -406,33 +496,51 @@ class AsyncRawContextClient: def __init__(self, *, client_wrapper: AsyncClientWrapper): self._client_wrapper = client_wrapper - async def list_context_templates( - self, *, request_options: typing.Optional[RequestOptions] = None - ) -> AsyncHttpResponse[ListContextTemplatesResponse]: + async def create_template( + self, + *, + name: typing.Optional[str] = OMIT, + template: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[ContextTemplate]: """ - Lists all context templates. - Parameters ---------- + name : typing.Optional[str] + + template : typing.Optional[str] + + idempotency_key : typing.Optional[str] + request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - AsyncHttpResponse[ListContextTemplatesResponse] - The list of context templates. + AsyncHttpResponse[ContextTemplate] + Created """ _response = await self._client_wrapper.httpx_client.request( "context-templates", - method="GET", + method="POST", + json={ + "name": name, + "template": template, + }, + headers={ + "content-type": "application/json", + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, + }, request_options=request_options, + omit=OMIT, ) try: if 200 <= _response.status_code < 300: _data = typing.cast( - ListContextTemplatesResponse, + ContextTemplate, parse_obj_as( - type_=ListContextTemplatesResponse, # type: ignore + type_=ContextTemplate, # type: ignore object_=_response.json(), ), ) @@ -441,15 +549,26 @@ async def list_context_templates( raise BadRequestError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore object_=_response.json(), ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 401: + raise UnauthorizedError( + 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, @@ -464,68 +583,108 @@ async def list_context_templates( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - async def create_context_template( - self, *, template: str, template_id: str, request_options: typing.Optional[RequestOptions] = None - ) -> AsyncHttpResponse[ContextTemplateResponse]: + async def list_templates( + self, + *, + limit: typing.Optional[int] = None, + cursor: typing.Optional[str] = None, + name: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncPager[ContextTemplate, ContextTemplatePage]: """ - Creates a new context template. - Parameters ---------- - template : str - The template content (max 1200 characters). + limit : typing.Optional[int] + Page size + + cursor : typing.Optional[str] + Opaque page cursor - template_id : str - Unique identifier for the template (max 100 characters). + name : typing.Optional[str] + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - AsyncHttpResponse[ContextTemplateResponse] - The created context template. + AsyncPager[ContextTemplate, ContextTemplatePage] + OK """ _response = await self._client_wrapper.httpx_client.request( - "context-templates", + "context-templates/list", method="POST", + params={ + "limit": limit, + "cursor": cursor, + }, json={ - "template": template, - "template_id": template_id, + "name": name, }, headers={ "content-type": "application/json", + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, }, request_options=request_options, omit=OMIT, ) try: if 200 <= _response.status_code < 300: - _data = typing.cast( - ContextTemplateResponse, + _parsed_response = typing.cast( + ContextTemplatePage, parse_obj_as( - type_=ContextTemplateResponse, # type: ignore + type_=ContextTemplatePage, # type: ignore object_=_response.json(), ), ) - return AsyncHttpResponse(response=_response, data=_data) + _items = _parsed_response.items + _parsed_next = _parsed_response.next_cursor + _has_next = _parsed_next is not None and _parsed_next != "" + + async def _get_next(): + return await self.list_templates( + limit=limit, + cursor=_parsed_next, + name=name, + idempotency_key=idempotency_key, + request_options=request_options, + ) + + return AsyncPager(has_next=_has_next, items=_items, get_next=_get_next, response=_parsed_response) if _response.status_code == 400: raise BadRequestError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore object_=_response.json(), ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 401: + raise UnauthorizedError( + 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, @@ -540,40 +699,42 @@ async def create_context_template( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - async def get_context_template( - self, template_id: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> AsyncHttpResponse[ContextTemplateResponse]: + async def get_template( + self, template_uuid: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> AsyncHttpResponse[ContextTemplate]: """ - Retrieves a context template by template_id. - Parameters ---------- - template_id : str - Template ID + template_uuid : str + Template UUID request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - AsyncHttpResponse[ContextTemplateResponse] - The context template. + AsyncHttpResponse[ContextTemplate] + OK """ _response = await self._client_wrapper.httpx_client.request( - f"context-templates/{jsonable_encoder(template_id)}", + f"context-templates/{jsonable_encoder(template_uuid)}", method="GET", request_options=request_options, ) try: if 200 <= _response.status_code < 300: _data = typing.cast( - ContextTemplateResponse, + ContextTemplate, parse_obj_as( - type_=ContextTemplateResponse, # type: ignore + type_=ContextTemplate, # type: ignore object_=_response.json(), ), ) @@ -582,15 +743,15 @@ async def get_context_template( raise BadRequestError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore object_=_response.json(), ), ), ) - if _response.status_code == 404: - raise NotFoundError( + if _response.status_code == 401: + raise UnauthorizedError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -600,8 +761,8 @@ async def get_context_template( ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -616,40 +777,53 @@ async def get_context_template( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - async def update_context_template( - self, template_id: str, *, template: str, request_options: typing.Optional[RequestOptions] = None - ) -> AsyncHttpResponse[ContextTemplateResponse]: + async def update_template( + self, + template_uuid: str, + *, + name: typing.Optional[str] = OMIT, + template: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[ContextTemplate]: """ - Updates an existing context template by template_id. - Parameters ---------- - template_id : str - Template ID + template_uuid : str + Template UUID - template : str - The template content (max 1200 characters). + name : typing.Optional[str] + + template : typing.Optional[str] + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - AsyncHttpResponse[ContextTemplateResponse] - The updated context template. + AsyncHttpResponse[ContextTemplate] + OK """ _response = await self._client_wrapper.httpx_client.request( - f"context-templates/{jsonable_encoder(template_id)}", + f"context-templates/{jsonable_encoder(template_uuid)}", method="PUT", json={ + "name": name, "template": template, }, headers={ "content-type": "application/json", + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, }, request_options=request_options, omit=OMIT, @@ -657,9 +831,9 @@ async def update_context_template( try: if 200 <= _response.status_code < 300: _data = typing.cast( - ContextTemplateResponse, + ContextTemplate, parse_obj_as( - type_=ContextTemplateResponse, # type: ignore + type_=ContextTemplate, # type: ignore object_=_response.json(), ), ) @@ -668,15 +842,15 @@ async def update_context_template( raise BadRequestError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore object_=_response.json(), ), ), ) - if _response.status_code == 404: - raise NotFoundError( + if _response.status_code == 401: + raise UnauthorizedError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -686,8 +860,8 @@ async def update_context_template( ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -702,57 +876,60 @@ async def update_context_template( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - async def delete_context_template( - self, template_id: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> AsyncHttpResponse[SuccessResponse]: + async def delete_template( + self, + template_uuid: str, + *, + idempotency_key: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[None]: """ - Deletes a context template by template_id. - Parameters ---------- - template_id : str - Template ID + template_uuid : str + Template UUID + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - AsyncHttpResponse[SuccessResponse] - Template deleted successfully + AsyncHttpResponse[None] """ _response = await self._client_wrapper.httpx_client.request( - f"context-templates/{jsonable_encoder(template_id)}", + f"context-templates/{jsonable_encoder(template_uuid)}", method="DELETE", + headers={ + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, + }, request_options=request_options, ) try: if 200 <= _response.status_code < 300: - _data = typing.cast( - SuccessResponse, - parse_obj_as( - type_=SuccessResponse, # type: ignore - object_=_response.json(), - ), - ) - return AsyncHttpResponse(response=_response, data=_data) + return AsyncHttpResponse(response=_response, data=None) if _response.status_code == 400: raise BadRequestError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore object_=_response.json(), ), ), ) - if _response.status_code == 404: - raise NotFoundError( + if _response.status_code == 401: + raise UnauthorizedError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -762,8 +939,8 @@ async def delete_context_template( ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -778,6 +955,10 @@ async def delete_context_template( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) diff --git a/src/zep_cloud/core/__init__.py b/src/zep_cloud/core/__init__.py index 31bbb818..2a2b56e7 100644 --- a/src/zep_cloud/core/__init__.py +++ b/src/zep_cloud/core/__init__.py @@ -2,47 +2,125 @@ # isort: skip_file -from .api_error import ApiError -from .client_wrapper import AsyncClientWrapper, BaseClientWrapper, SyncClientWrapper -from .datetime_utils import serialize_datetime -from .file import File, convert_file_dict_to_httpx_tuples, with_content_type -from .http_client import AsyncHttpClient, HttpClient -from .http_response import AsyncHttpResponse, HttpResponse -from .jsonable_encoder import jsonable_encoder -from .pydantic_utilities import ( - IS_PYDANTIC_V2, - UniversalBaseModel, - UniversalRootModel, - parse_obj_as, - universal_field_validator, - universal_root_validator, - update_forward_refs, -) -from .query_encoder import encode_query -from .remove_none_from_dict import remove_none_from_dict -from .request_options import RequestOptions -from .serialization import FieldMetadata, convert_and_respect_annotation_metadata +import typing +from importlib import import_module + +if typing.TYPE_CHECKING: + from .api_error import ApiError + from .client_wrapper import AsyncClientWrapper, BaseClientWrapper, SyncClientWrapper + from .datetime_utils import Rfc2822DateTime, parse_rfc2822_datetime, serialize_datetime + from .file import File, convert_file_dict_to_httpx_tuples, with_content_type + from .http_client import AsyncHttpClient, HttpClient + from .http_response import AsyncHttpResponse, HttpResponse + from .jsonable_encoder import jsonable_encoder + from .logging import ConsoleLogger, ILogger, LogConfig, LogLevel, Logger, create_logger + from .pagination import AsyncPager, SyncPager + from .parse_error import ParsingError + from .pydantic_utilities import ( + IS_PYDANTIC_V2, + UniversalBaseModel, + UniversalRootModel, + parse_obj_as, + universal_field_validator, + universal_root_validator, + update_forward_refs, + ) + from .query_encoder import encode_query + from .remove_none_from_dict import remove_none_from_dict + from .request_options import RequestOptions + from .serialization import FieldMetadata, convert_and_respect_annotation_metadata +_dynamic_imports: typing.Dict[str, str] = { + "ApiError": ".api_error", + "AsyncClientWrapper": ".client_wrapper", + "AsyncHttpClient": ".http_client", + "AsyncHttpResponse": ".http_response", + "AsyncPager": ".pagination", + "BaseClientWrapper": ".client_wrapper", + "ConsoleLogger": ".logging", + "FieldMetadata": ".serialization", + "File": ".file", + "HttpClient": ".http_client", + "HttpResponse": ".http_response", + "ILogger": ".logging", + "IS_PYDANTIC_V2": ".pydantic_utilities", + "LogConfig": ".logging", + "LogLevel": ".logging", + "Logger": ".logging", + "ParsingError": ".parse_error", + "RequestOptions": ".request_options", + "Rfc2822DateTime": ".datetime_utils", + "SyncClientWrapper": ".client_wrapper", + "SyncPager": ".pagination", + "UniversalBaseModel": ".pydantic_utilities", + "UniversalRootModel": ".pydantic_utilities", + "convert_and_respect_annotation_metadata": ".serialization", + "convert_file_dict_to_httpx_tuples": ".file", + "create_logger": ".logging", + "encode_query": ".query_encoder", + "jsonable_encoder": ".jsonable_encoder", + "parse_obj_as": ".pydantic_utilities", + "parse_rfc2822_datetime": ".datetime_utils", + "remove_none_from_dict": ".remove_none_from_dict", + "serialize_datetime": ".datetime_utils", + "universal_field_validator": ".pydantic_utilities", + "universal_root_validator": ".pydantic_utilities", + "update_forward_refs": ".pydantic_utilities", + "with_content_type": ".file", +} + + +def __getattr__(attr_name: str) -> typing.Any: + module_name = _dynamic_imports.get(attr_name) + if module_name is None: + raise AttributeError(f"No {attr_name} found in _dynamic_imports for module name -> {__name__}") + try: + module = import_module(module_name, __package__) + if module_name == f".{attr_name}": + return module + else: + return getattr(module, attr_name) + except ImportError as e: + raise ImportError(f"Failed to import {attr_name} from {module_name}: {e}") from e + except AttributeError as e: + raise AttributeError(f"Failed to get {attr_name} from {module_name}: {e}") from e + + +def __dir__(): + lazy_attrs = list(_dynamic_imports.keys()) + return sorted(lazy_attrs) + __all__ = [ "ApiError", "AsyncClientWrapper", "AsyncHttpClient", "AsyncHttpResponse", + "AsyncPager", "BaseClientWrapper", + "ConsoleLogger", "FieldMetadata", "File", "HttpClient", "HttpResponse", + "ILogger", "IS_PYDANTIC_V2", + "LogConfig", + "LogLevel", + "Logger", + "ParsingError", "RequestOptions", + "Rfc2822DateTime", "SyncClientWrapper", + "SyncPager", "UniversalBaseModel", "UniversalRootModel", "convert_and_respect_annotation_metadata", "convert_file_dict_to_httpx_tuples", + "create_logger", "encode_query", "jsonable_encoder", "parse_obj_as", + "parse_rfc2822_datetime", "remove_none_from_dict", "serialize_datetime", "universal_field_validator", diff --git a/src/zep_cloud/core/client_wrapper.py b/src/zep_cloud/core/client_wrapper.py index dde7c3ad..4daaa20a 100644 --- a/src/zep_cloud/core/client_wrapper.py +++ b/src/zep_cloud/core/client_wrapper.py @@ -4,6 +4,7 @@ import httpx from .http_client import AsyncHttpClient, HttpClient +from .logging import LogConfig, Logger class BaseClientWrapper: @@ -14,18 +15,24 @@ def __init__( headers: typing.Optional[typing.Dict[str, str]] = None, base_url: str, timeout: typing.Optional[float] = None, + logging: typing.Optional[typing.Union[LogConfig, Logger]] = None, ): self.api_key = api_key self._headers = headers self._base_url = base_url self._timeout = timeout + self._logging = logging def get_headers(self) -> typing.Dict[str, str]: + import platform + headers: typing.Dict[str, str] = { - "User-Agent": "zep-cloud/3.28.0", + "User-Agent": "zep-cloud/4.0.0a1", "X-Fern-Language": "Python", + "X-Fern-Runtime": f"python/{platform.python_version()}", + "X-Fern-Platform": f"{platform.system().lower()}/{platform.release()}", "X-Fern-SDK-Name": "zep-cloud", - "X-Fern-SDK-Version": "3.28.0", + "X-Fern-SDK-Version": "4.0.0a1", **(self.get_custom_headers() or {}), } headers["Authorization"] = f"Api-Key {self.api_key}" @@ -49,14 +56,16 @@ def __init__( headers: typing.Optional[typing.Dict[str, str]] = None, base_url: str, timeout: typing.Optional[float] = None, + logging: typing.Optional[typing.Union[LogConfig, Logger]] = None, httpx_client: httpx.Client, ): - super().__init__(api_key=api_key, headers=headers, base_url=base_url, timeout=timeout) + super().__init__(api_key=api_key, headers=headers, base_url=base_url, timeout=timeout, logging=logging) self.httpx_client = HttpClient( httpx_client=httpx_client, base_headers=self.get_headers, base_timeout=self.get_timeout, base_url=self.get_base_url, + logging_config=self._logging, ) @@ -68,12 +77,24 @@ def __init__( headers: typing.Optional[typing.Dict[str, str]] = None, base_url: str, timeout: typing.Optional[float] = None, + logging: typing.Optional[typing.Union[LogConfig, Logger]] = None, + async_token: typing.Optional[typing.Callable[[], typing.Awaitable[str]]] = None, httpx_client: httpx.AsyncClient, ): - super().__init__(api_key=api_key, headers=headers, base_url=base_url, timeout=timeout) + super().__init__(api_key=api_key, headers=headers, base_url=base_url, timeout=timeout, logging=logging) + self._async_token = async_token self.httpx_client = AsyncHttpClient( httpx_client=httpx_client, base_headers=self.get_headers, base_timeout=self.get_timeout, base_url=self.get_base_url, + async_base_headers=self.async_get_headers, + logging_config=self._logging, ) + + async def async_get_headers(self) -> typing.Dict[str, str]: + headers = self.get_headers() + if self._async_token is not None: + token = await self._async_token() + headers["Authorization"] = f"Bearer {token}" + return headers diff --git a/src/zep_cloud/core/datetime_utils.py b/src/zep_cloud/core/datetime_utils.py index 7c9864a9..a12b2ad0 100644 --- a/src/zep_cloud/core/datetime_utils.py +++ b/src/zep_cloud/core/datetime_utils.py @@ -1,6 +1,48 @@ # This file was auto-generated by Fern from our API Definition. import datetime as dt +from email.utils import parsedate_to_datetime +from typing import Any + +import pydantic + +IS_PYDANTIC_V2 = pydantic.VERSION.startswith("2.") + + +def parse_rfc2822_datetime(v: Any) -> dt.datetime: + """ + Parse an RFC 2822 datetime string (e.g., "Wed, 02 Oct 2002 13:00:00 GMT") + into a datetime object. If the value is already a datetime, return it as-is. + Falls back to ISO 8601 parsing if RFC 2822 parsing fails. + """ + if isinstance(v, dt.datetime): + return v + if isinstance(v, str): + try: + return parsedate_to_datetime(v) + except Exception: + pass + # Fallback to ISO 8601 parsing + return dt.datetime.fromisoformat(v.replace("Z", "+00:00")) + raise ValueError(f"Expected str or datetime, got {type(v)}") + + +class Rfc2822DateTime(dt.datetime): + """A datetime subclass that parses RFC 2822 date strings. + + On Pydantic V1, uses __get_validators__ for pre-validation. + On Pydantic V2, uses __get_pydantic_core_schema__ for BeforeValidator-style parsing. + """ + + @classmethod + def __get_validators__(cls): # type: ignore[no-untyped-def] + yield parse_rfc2822_datetime + + @classmethod + def __get_pydantic_core_schema__(cls, _source_type: Any, _handler: Any) -> Any: # type: ignore[override] + from pydantic_core import core_schema + + return core_schema.no_info_before_validator_function(parse_rfc2822_datetime, core_schema.datetime_schema()) def serialize_datetime(v: dt.datetime) -> str: diff --git a/src/zep_cloud/core/force_multipart.py b/src/zep_cloud/core/force_multipart.py index ae24ccff..5440913f 100644 --- a/src/zep_cloud/core/force_multipart.py +++ b/src/zep_cloud/core/force_multipart.py @@ -1,7 +1,9 @@ # This file was auto-generated by Fern from our API Definition. +from typing import Any, Dict -class ForceMultipartDict(dict): + +class ForceMultipartDict(Dict[str, Any]): """ A dictionary subclass that always evaluates to True in boolean contexts. @@ -9,7 +11,7 @@ class ForceMultipartDict(dict): the dictionary is empty, which would normally evaluate to False. """ - def __bool__(self): + def __bool__(self) -> bool: return True diff --git a/src/zep_cloud/core/http_client.py b/src/zep_cloud/core/http_client.py index e4173f99..ee937589 100644 --- a/src/zep_cloud/core/http_client.py +++ b/src/zep_cloud/core/http_client.py @@ -5,7 +5,6 @@ import re import time import typing -import urllib.parse from contextlib import asynccontextmanager, contextmanager from random import random @@ -13,14 +12,15 @@ from .file import File, convert_file_dict_to_httpx_tuples from .force_multipart import FORCE_MULTIPART from .jsonable_encoder import jsonable_encoder +from .logging import LogConfig, Logger, create_logger from .query_encoder import encode_query -from .remove_none_from_dict import remove_none_from_dict +from .remove_none_from_dict import remove_none_from_dict as remove_none_from_dict from .request_options import RequestOptions from httpx._types import RequestFiles -INITIAL_RETRY_DELAY_SECONDS = 0.5 -MAX_RETRY_DELAY_SECONDS = 10 -MAX_RETRY_DELAY_SECONDS_FROM_HEADER = 30 +INITIAL_RETRY_DELAY_SECONDS = 1.0 +MAX_RETRY_DELAY_SECONDS = 60.0 +JITTER_FACTOR = 0.2 # 20% random jitter def _parse_retry_after(response_headers: httpx.Headers) -> typing.Optional[float]: @@ -64,6 +64,38 @@ def _parse_retry_after(response_headers: httpx.Headers) -> typing.Optional[float return seconds +def _add_positive_jitter(delay: float) -> float: + """Add positive jitter (0-20%) to prevent thundering herd.""" + jitter_multiplier = 1 + random() * JITTER_FACTOR + return delay * jitter_multiplier + + +def _add_symmetric_jitter(delay: float) -> float: + """Add symmetric jitter (±10%) for exponential backoff.""" + jitter_multiplier = 1 + (random() - 0.5) * JITTER_FACTOR + return delay * jitter_multiplier + + +def _parse_x_ratelimit_reset(response_headers: httpx.Headers) -> typing.Optional[float]: + """ + Parse the X-RateLimit-Reset header (Unix timestamp in seconds). + Returns seconds to wait, or None if header is missing/invalid. + """ + reset_time_str = response_headers.get("x-ratelimit-reset") + if reset_time_str is None: + return None + + try: + reset_time = int(reset_time_str) + delay = reset_time - time.time() + if delay > 0: + return delay + except (ValueError, TypeError): + pass + + return None + + def _retry_timeout(response: httpx.Response, retries: int) -> float: """ Determine the amount of time to wait before retrying a request. @@ -71,17 +103,19 @@ def _retry_timeout(response: httpx.Response, retries: int) -> float: with a jitter to determine the number of seconds to wait. """ - # If the API asks us to wait a certain amount of time (and it's a reasonable amount), just do what it says. + # 1. Check Retry-After header first retry_after = _parse_retry_after(response.headers) - if retry_after is not None and retry_after <= MAX_RETRY_DELAY_SECONDS_FROM_HEADER: - return retry_after + if retry_after is not None and retry_after > 0: + return min(retry_after, MAX_RETRY_DELAY_SECONDS) - # Apply exponential backoff, capped at MAX_RETRY_DELAY_SECONDS. - retry_delay = min(INITIAL_RETRY_DELAY_SECONDS * pow(2.0, retries), MAX_RETRY_DELAY_SECONDS) + # 2. Check X-RateLimit-Reset header (with positive jitter) + ratelimit_reset = _parse_x_ratelimit_reset(response.headers) + if ratelimit_reset is not None: + return _add_positive_jitter(min(ratelimit_reset, MAX_RETRY_DELAY_SECONDS)) - # Add a randomness / jitter to the retry delay to avoid overwhelming the server with retries. - timeout = retry_delay * (1 - 0.25 * random()) - return timeout if timeout >= 0 else 0 + # 3. Fall back to exponential backoff (with symmetric jitter) + backoff = min(INITIAL_RETRY_DELAY_SECONDS * pow(2.0, retries), MAX_RETRY_DELAY_SECONDS) + return _add_symmetric_jitter(backoff) def _should_retry(response: httpx.Response) -> bool: @@ -89,6 +123,71 @@ def _should_retry(response: httpx.Response) -> bool: return response.status_code >= 500 or response.status_code in retryable_400s +_SENSITIVE_HEADERS = frozenset( + { + "authorization", + "www-authenticate", + "x-api-key", + "api-key", + "apikey", + "x-api-token", + "x-auth-token", + "auth-token", + "cookie", + "set-cookie", + "proxy-authorization", + "proxy-authenticate", + "x-csrf-token", + "x-xsrf-token", + "x-session-token", + "x-access-token", + } +) + + +def _redact_headers(headers: typing.Dict[str, str]) -> typing.Dict[str, str]: + return {k: ("[REDACTED]" if k.lower() in _SENSITIVE_HEADERS else v) for k, v in headers.items()} + + +def _build_url(base_url: str, path: typing.Optional[str]) -> str: + """ + Build a full URL by joining a base URL with a path. + + This function correctly handles base URLs that contain path prefixes (e.g., tenant-based URLs) + by using string concatenation instead of urllib.parse.urljoin(), which would incorrectly + strip path components when the path starts with '/'. + + Example: + >>> _build_url("https://cloud.example.com/org/tenant/api", "/users") + 'https://cloud.example.com/org/tenant/api/users' + + Args: + base_url: The base URL, which may contain path prefixes. + path: The path to append. Can be None or empty string. + + Returns: + The full URL with base_url and path properly joined. + """ + if not path: + return base_url + return f"{base_url.rstrip('/')}/{path.lstrip('/')}" + + +def _maybe_filter_none_from_multipart_data( + data: typing.Optional[typing.Any], + request_files: typing.Optional[RequestFiles], + force_multipart: typing.Optional[bool], +) -> typing.Optional[typing.Any]: + """ + Filter None values from data body for multipart/form requests. + This prevents httpx from converting None to empty strings in multipart encoding. + Only applies when files are present or force_multipart is True. + """ + if data is not None and isinstance(data, typing.Mapping) and (request_files or force_multipart): + return remove_none_from_dict(data) + return data + + def remove_omit_from_dict( original: typing.Dict[str, typing.Optional[typing.Any]], omit: typing.Optional[typing.Any], @@ -143,8 +242,19 @@ def get_request_body( # If both data and json are None, we send json data in the event extra properties are specified json_body = maybe_filter_request_body(json, request_options, omit) - # If you have an empty JSON body, you should just send None - return (json_body if json_body != {} else None), data_body if data_body != {} else None + has_additional_body_parameters = bool( + request_options is not None and request_options.get("additional_body_parameters") + ) + + # Only collapse empty dict to None when the body was not explicitly provided + # and there are no additional body parameters. This preserves explicit empty + # bodies (e.g., when an endpoint has a request body type but all fields are optional). + if json_body == {} and json is None and not has_additional_body_parameters: + json_body = None + if data_body == {} and data is None and not has_additional_body_parameters: + data_body = None + + return json_body, data_body class HttpClient: @@ -155,11 +265,13 @@ def __init__( base_timeout: typing.Callable[[], typing.Optional[float]], base_headers: typing.Callable[[], typing.Dict[str, str]], base_url: typing.Optional[typing.Callable[[], str]] = None, + logging_config: typing.Optional[typing.Union[LogConfig, Logger]] = None, ): self.base_url = base_url self.base_timeout = base_timeout self.base_headers = base_headers self.httpx_client = httpx_client + self.logger = create_logger(logging_config) def get_base_url(self, maybe_base_url: typing.Optional[str]) -> str: base_url = maybe_base_url @@ -188,7 +300,7 @@ def request( ] = None, headers: typing.Optional[typing.Dict[str, typing.Any]] = None, request_options: typing.Optional[RequestOptions] = None, - retries: int = 2, + retries: int = 0, omit: typing.Optional[typing.Any] = None, force_multipart: typing.Optional[bool] = None, ) -> httpx.Response: @@ -210,35 +322,53 @@ def request( if (request_files is None or len(request_files) == 0) and force_multipart: request_files = FORCE_MULTIPART - response = self.httpx_client.request( - method=method, - url=urllib.parse.urljoin(f"{base_url}/", path), - headers=jsonable_encoder( + data_body = _maybe_filter_none_from_multipart_data(data_body, request_files, force_multipart) + + # Compute encoded params separately to avoid passing empty list to httpx + # (httpx strips existing query params from URL when params=[] is passed) + _encoded_params = encode_query( + jsonable_encoder( remove_none_from_dict( - { - **self.base_headers(), - **(headers if headers is not None else {}), - **(request_options.get("additional_headers", {}) or {} if request_options is not None else {}), - } - ) - ), - params=encode_query( - jsonable_encoder( - remove_none_from_dict( - remove_omit_from_dict( - { - **(params if params is not None else {}), - **( - request_options.get("additional_query_parameters", {}) or {} - if request_options is not None - else {} - ), - }, - omit, - ) + remove_omit_from_dict( + { + **(params if params is not None else {}), + **( + request_options.get("additional_query_parameters", {}) or {} + if request_options is not None + else {} + ), + }, + omit, ) ) - ), + ) + ) + + _request_url = _build_url(base_url, path) + _request_headers = jsonable_encoder( + remove_none_from_dict( + { + **self.base_headers(), + **(headers if headers is not None else {}), + **(request_options.get("additional_headers", {}) or {} if request_options is not None else {}), + } + ) + ) + + if self.logger.is_debug(): + self.logger.debug( + "Making HTTP request", + method=method, + url=_request_url, + headers=_redact_headers(_request_headers), + has_body=json_body is not None or data_body is not None, + ) + + response = self.httpx_client.request( + method=method, + url=_request_url, + headers=_request_headers, + params=_encoded_params if _encoded_params else None, json=json_body, data=data_body, content=content, @@ -246,9 +376,9 @@ def request( timeout=timeout, ) - max_retries: int = request_options.get("max_retries", 0) if request_options is not None else 0 + max_retries: int = request_options.get("max_retries", 2) if request_options is not None else 2 if _should_retry(response=response): - if max_retries > retries: + if retries < max_retries: time.sleep(_retry_timeout(response=response, retries=retries)) return self.request( path=path, @@ -264,6 +394,24 @@ def request( omit=omit, ) + if self.logger.is_debug(): + if 200 <= response.status_code < 400: + self.logger.debug( + "HTTP request succeeded", + method=method, + url=_request_url, + status_code=response.status_code, + ) + + if self.logger.is_error(): + if response.status_code >= 400: + self.logger.error( + "HTTP request failed with error status", + method=method, + url=_request_url, + status_code=response.status_code, + ) + return response @contextmanager @@ -285,7 +433,7 @@ def stream( ] = None, headers: typing.Optional[typing.Dict[str, typing.Any]] = None, request_options: typing.Optional[RequestOptions] = None, - retries: int = 2, + retries: int = 0, omit: typing.Optional[typing.Any] = None, force_multipart: typing.Optional[bool] = None, ) -> typing.Iterator[httpx.Response]: @@ -307,35 +455,52 @@ def stream( json_body, data_body = get_request_body(json=json, data=data, request_options=request_options, omit=omit) - with self.httpx_client.stream( - method=method, - url=urllib.parse.urljoin(f"{base_url}/", path), - headers=jsonable_encoder( + data_body = _maybe_filter_none_from_multipart_data(data_body, request_files, force_multipart) + + # Compute encoded params separately to avoid passing empty list to httpx + # (httpx strips existing query params from URL when params=[] is passed) + _encoded_params = encode_query( + jsonable_encoder( remove_none_from_dict( - { - **self.base_headers(), - **(headers if headers is not None else {}), - **(request_options.get("additional_headers", {}) if request_options is not None else {}), - } - ) - ), - params=encode_query( - jsonable_encoder( - remove_none_from_dict( - remove_omit_from_dict( - { - **(params if params is not None else {}), - **( - request_options.get("additional_query_parameters", {}) - if request_options is not None - else {} - ), - }, - omit, - ) + remove_omit_from_dict( + { + **(params if params is not None else {}), + **( + request_options.get("additional_query_parameters", {}) + if request_options is not None + else {} + ), + }, + omit, ) ) - ), + ) + ) + + _request_url = _build_url(base_url, path) + _request_headers = jsonable_encoder( + remove_none_from_dict( + { + **self.base_headers(), + **(headers if headers is not None else {}), + **(request_options.get("additional_headers", {}) if request_options is not None else {}), + } + ) + ) + + if self.logger.is_debug(): + self.logger.debug( + "Making streaming HTTP request", + method=method, + url=_request_url, + headers=_redact_headers(_request_headers), + ) + + with self.httpx_client.stream( + method=method, + url=_request_url, + headers=_request_headers, + params=_encoded_params if _encoded_params else None, json=json_body, data=data_body, content=content, @@ -353,11 +518,20 @@ def __init__( base_timeout: typing.Callable[[], typing.Optional[float]], base_headers: typing.Callable[[], typing.Dict[str, str]], base_url: typing.Optional[typing.Callable[[], str]] = None, + async_base_headers: typing.Optional[typing.Callable[[], typing.Awaitable[typing.Dict[str, str]]]] = None, + logging_config: typing.Optional[typing.Union[LogConfig, Logger]] = None, ): self.base_url = base_url self.base_timeout = base_timeout self.base_headers = base_headers + self.async_base_headers = async_base_headers self.httpx_client = httpx_client + self.logger = create_logger(logging_config) + + async def _get_headers(self) -> typing.Dict[str, str]: + if self.async_base_headers is not None: + return await self.async_base_headers() + return self.base_headers() def get_base_url(self, maybe_base_url: typing.Optional[str]) -> str: base_url = maybe_base_url @@ -386,7 +560,7 @@ async def request( ] = None, headers: typing.Optional[typing.Dict[str, typing.Any]] = None, request_options: typing.Optional[RequestOptions] = None, - retries: int = 2, + retries: int = 0, omit: typing.Optional[typing.Any] = None, force_multipart: typing.Optional[bool] = None, ) -> httpx.Response: @@ -408,36 +582,56 @@ async def request( json_body, data_body = get_request_body(json=json, data=data, request_options=request_options, omit=omit) - # Add the input to each of these and do None-safety checks - response = await self.httpx_client.request( - method=method, - url=urllib.parse.urljoin(f"{base_url}/", path), - headers=jsonable_encoder( + data_body = _maybe_filter_none_from_multipart_data(data_body, request_files, force_multipart) + + # Get headers (supports async token providers) + _headers = await self._get_headers() + + # Compute encoded params separately to avoid passing empty list to httpx + # (httpx strips existing query params from URL when params=[] is passed) + _encoded_params = encode_query( + jsonable_encoder( remove_none_from_dict( - { - **self.base_headers(), - **(headers if headers is not None else {}), - **(request_options.get("additional_headers", {}) or {} if request_options is not None else {}), - } - ) - ), - params=encode_query( - jsonable_encoder( - remove_none_from_dict( - remove_omit_from_dict( - { - **(params if params is not None else {}), - **( - request_options.get("additional_query_parameters", {}) or {} - if request_options is not None - else {} - ), - }, - omit, - ) + remove_omit_from_dict( + { + **(params if params is not None else {}), + **( + request_options.get("additional_query_parameters", {}) or {} + if request_options is not None + else {} + ), + }, + omit, ) ) - ), + ) + ) + + _request_url = _build_url(base_url, path) + _request_headers = jsonable_encoder( + remove_none_from_dict( + { + **_headers, + **(headers if headers is not None else {}), + **(request_options.get("additional_headers", {}) or {} if request_options is not None else {}), + } + ) + ) + + if self.logger.is_debug(): + self.logger.debug( + "Making HTTP request", + method=method, + url=_request_url, + headers=_redact_headers(_request_headers), + has_body=json_body is not None or data_body is not None, + ) + + response = await self.httpx_client.request( + method=method, + url=_request_url, + headers=_request_headers, + params=_encoded_params if _encoded_params else None, json=json_body, data=data_body, content=content, @@ -445,9 +639,9 @@ async def request( timeout=timeout, ) - max_retries: int = request_options.get("max_retries", 0) if request_options is not None else 0 + max_retries: int = request_options.get("max_retries", 2) if request_options is not None else 2 if _should_retry(response=response): - if max_retries > retries: + if retries < max_retries: await asyncio.sleep(_retry_timeout(response=response, retries=retries)) return await self.request( path=path, @@ -462,6 +656,25 @@ async def request( retries=retries + 1, omit=omit, ) + + if self.logger.is_debug(): + if 200 <= response.status_code < 400: + self.logger.debug( + "HTTP request succeeded", + method=method, + url=_request_url, + status_code=response.status_code, + ) + + if self.logger.is_error(): + if response.status_code >= 400: + self.logger.error( + "HTTP request failed with error status", + method=method, + url=_request_url, + status_code=response.status_code, + ) + return response @asynccontextmanager @@ -483,7 +696,7 @@ async def stream( ] = None, headers: typing.Optional[typing.Dict[str, typing.Any]] = None, request_options: typing.Optional[RequestOptions] = None, - retries: int = 2, + retries: int = 0, omit: typing.Optional[typing.Any] = None, force_multipart: typing.Optional[bool] = None, ) -> typing.AsyncIterator[httpx.Response]: @@ -505,35 +718,55 @@ async def stream( json_body, data_body = get_request_body(json=json, data=data, request_options=request_options, omit=omit) - async with self.httpx_client.stream( - method=method, - url=urllib.parse.urljoin(f"{base_url}/", path), - headers=jsonable_encoder( + data_body = _maybe_filter_none_from_multipart_data(data_body, request_files, force_multipart) + + # Get headers (supports async token providers) + _headers = await self._get_headers() + + # Compute encoded params separately to avoid passing empty list to httpx + # (httpx strips existing query params from URL when params=[] is passed) + _encoded_params = encode_query( + jsonable_encoder( remove_none_from_dict( - { - **self.base_headers(), - **(headers if headers is not None else {}), - **(request_options.get("additional_headers", {}) if request_options is not None else {}), - } - ) - ), - params=encode_query( - jsonable_encoder( - remove_none_from_dict( - remove_omit_from_dict( - { - **(params if params is not None else {}), - **( - request_options.get("additional_query_parameters", {}) - if request_options is not None - else {} - ), - }, - omit=omit, - ) + remove_omit_from_dict( + { + **(params if params is not None else {}), + **( + request_options.get("additional_query_parameters", {}) + if request_options is not None + else {} + ), + }, + omit=omit, ) ) - ), + ) + ) + + _request_url = _build_url(base_url, path) + _request_headers = jsonable_encoder( + remove_none_from_dict( + { + **_headers, + **(headers if headers is not None else {}), + **(request_options.get("additional_headers", {}) if request_options is not None else {}), + } + ) + ) + + if self.logger.is_debug(): + self.logger.debug( + "Making streaming HTTP request", + method=method, + url=_request_url, + headers=_redact_headers(_request_headers), + ) + + async with self.httpx_client.stream( + method=method, + url=_request_url, + headers=_request_headers, + params=_encoded_params if _encoded_params else None, json=json_body, data=data_body, content=content, diff --git a/src/zep_cloud/core/http_response.py b/src/zep_cloud/core/http_response.py index 48a1798a..00bb1096 100644 --- a/src/zep_cloud/core/http_response.py +++ b/src/zep_cloud/core/http_response.py @@ -4,12 +4,12 @@ import httpx +# Generic to represent the underlying type of the data wrapped by the HTTP response. T = TypeVar("T") -"""Generic to represent the underlying type of the data wrapped by the HTTP response.""" class BaseHttpResponse: - """Minimalist HTTP response wrapper that exposes response headers.""" + """Minimalist HTTP response wrapper that exposes response headers and status code.""" _response: httpx.Response @@ -20,6 +20,10 @@ def __init__(self, response: httpx.Response): def headers(self) -> Dict[str, str]: return dict(self._response.headers) + @property + def status_code(self) -> int: + return self._response.status_code + class HttpResponse(Generic[T], BaseHttpResponse): """HTTP response wrapper that exposes response headers and data.""" diff --git a/src/zep_cloud/core/http_sse/__init__.py b/src/zep_cloud/core/http_sse/__init__.py new file mode 100644 index 00000000..730e5a33 --- /dev/null +++ b/src/zep_cloud/core/http_sse/__init__.py @@ -0,0 +1,42 @@ +# This file was auto-generated by Fern from our API Definition. + +# isort: skip_file + +import typing +from importlib import import_module + +if typing.TYPE_CHECKING: + from ._api import EventSource, aconnect_sse, connect_sse + from ._exceptions import SSEError + from ._models import ServerSentEvent +_dynamic_imports: typing.Dict[str, str] = { + "EventSource": "._api", + "SSEError": "._exceptions", + "ServerSentEvent": "._models", + "aconnect_sse": "._api", + "connect_sse": "._api", +} + + +def __getattr__(attr_name: str) -> typing.Any: + module_name = _dynamic_imports.get(attr_name) + if module_name is None: + raise AttributeError(f"No {attr_name} found in _dynamic_imports for module name -> {__name__}") + try: + module = import_module(module_name, __package__) + if module_name == f".{attr_name}": + return module + else: + return getattr(module, attr_name) + except ImportError as e: + raise ImportError(f"Failed to import {attr_name} from {module_name}: {e}") from e + except AttributeError as e: + raise AttributeError(f"Failed to get {attr_name} from {module_name}: {e}") from e + + +def __dir__(): + lazy_attrs = list(_dynamic_imports.keys()) + return sorted(lazy_attrs) + + +__all__ = ["EventSource", "SSEError", "ServerSentEvent", "aconnect_sse", "connect_sse"] diff --git a/src/zep_cloud/core/http_sse/_api.py b/src/zep_cloud/core/http_sse/_api.py new file mode 100644 index 00000000..f900b3b6 --- /dev/null +++ b/src/zep_cloud/core/http_sse/_api.py @@ -0,0 +1,112 @@ +# This file was auto-generated by Fern from our API Definition. + +import re +from contextlib import asynccontextmanager, contextmanager +from typing import Any, AsyncGenerator, AsyncIterator, Iterator, cast + +import httpx +from ._decoders import SSEDecoder +from ._exceptions import SSEError +from ._models import ServerSentEvent + + +class EventSource: + def __init__(self, response: httpx.Response) -> None: + self._response = response + + def _check_content_type(self) -> None: + content_type = self._response.headers.get("content-type", "").partition(";")[0] + if "text/event-stream" not in content_type: + raise SSEError( + f"Expected response header Content-Type to contain 'text/event-stream', got {content_type!r}" + ) + + def _get_charset(self) -> str: + """Extract charset from Content-Type header, fallback to UTF-8.""" + content_type = self._response.headers.get("content-type", "") + + # Parse charset parameter using regex + charset_match = re.search(r"charset=([^;\s]+)", content_type, re.IGNORECASE) + if charset_match: + charset = charset_match.group(1).strip("\"'") + # Validate that it's a known encoding + try: + # Test if the charset is valid by trying to encode/decode + "test".encode(charset).decode(charset) + return charset + except (LookupError, UnicodeError): + # If charset is invalid, fall back to UTF-8 + pass + + # Default to UTF-8 if no charset specified or invalid charset + return "utf-8" + + @property + def response(self) -> httpx.Response: + return self._response + + def iter_sse(self) -> Iterator[ServerSentEvent]: + self._check_content_type() + decoder = SSEDecoder() + charset = self._get_charset() + + buffer = "" + for chunk in self._response.iter_bytes(): + # Decode chunk using detected charset + text_chunk = chunk.decode(charset, errors="replace") + buffer += text_chunk + + # Process complete lines + while "\n" in buffer: + line, buffer = buffer.split("\n", 1) + line = line.rstrip("\r") + sse = decoder.decode(line) + # when we reach a "\n\n" => line = '' + # => decoder will attempt to return an SSE Event + if sse is not None: + yield sse + + # Process any remaining data in buffer + if buffer.strip(): + line = buffer.rstrip("\r") + sse = decoder.decode(line) + if sse is not None: + yield sse + + async def aiter_sse(self) -> AsyncGenerator[ServerSentEvent, None]: + self._check_content_type() + decoder = SSEDecoder() + lines = cast(AsyncGenerator[str, None], self._response.aiter_lines()) + try: + async for line in lines: + line = line.rstrip("\n") + sse = decoder.decode(line) + if sse is not None: + yield sse + finally: + await lines.aclose() + + +@contextmanager +def connect_sse(client: httpx.Client, method: str, url: str, **kwargs: Any) -> Iterator[EventSource]: + headers = kwargs.pop("headers", {}) + headers["Accept"] = "text/event-stream" + headers["Cache-Control"] = "no-store" + + with client.stream(method, url, headers=headers, **kwargs) as response: + yield EventSource(response) + + +@asynccontextmanager +async def aconnect_sse( + client: httpx.AsyncClient, + method: str, + url: str, + **kwargs: Any, +) -> AsyncIterator[EventSource]: + headers = kwargs.pop("headers", {}) + headers["Accept"] = "text/event-stream" + headers["Cache-Control"] = "no-store" + + async with client.stream(method, url, headers=headers, **kwargs) as response: + yield EventSource(response) diff --git a/src/zep_cloud/core/http_sse/_decoders.py b/src/zep_cloud/core/http_sse/_decoders.py new file mode 100644 index 00000000..339b0890 --- /dev/null +++ b/src/zep_cloud/core/http_sse/_decoders.py @@ -0,0 +1,61 @@ +# This file was auto-generated by Fern from our API Definition. + +from typing import List, Optional + +from ._models import ServerSentEvent + + +class SSEDecoder: + def __init__(self) -> None: + self._event = "" + self._data: List[str] = [] + self._last_event_id = "" + self._retry: Optional[int] = None + + def decode(self, line: str) -> Optional[ServerSentEvent]: + # See: https://html.spec.whatwg.org/multipage/server-sent-events.html#event-stream-interpretation # noqa: E501 + + if not line: + if not self._event and not self._data and not self._last_event_id and self._retry is None: + return None + + sse = ServerSentEvent( + event=self._event, + data="\n".join(self._data), + id=self._last_event_id, + retry=self._retry, + ) + + # NOTE: as per the SSE spec, do not reset last_event_id. + self._event = "" + self._data = [] + self._retry = None + + return sse + + if line.startswith(":"): + return None + + fieldname, _, value = line.partition(":") + + if value.startswith(" "): + value = value[1:] + + if fieldname == "event": + self._event = value + elif fieldname == "data": + self._data.append(value) + elif fieldname == "id": + if "\0" in value: + pass + else: + self._last_event_id = value + elif fieldname == "retry": + try: + self._retry = int(value) + except (TypeError, ValueError): + pass + else: + pass # Field is ignored. + + return None diff --git a/src/zep_cloud/core/http_sse/_exceptions.py b/src/zep_cloud/core/http_sse/_exceptions.py new file mode 100644 index 00000000..81605a8a --- /dev/null +++ b/src/zep_cloud/core/http_sse/_exceptions.py @@ -0,0 +1,7 @@ +# This file was auto-generated by Fern from our API Definition. + +import httpx + + +class SSEError(httpx.TransportError): + pass diff --git a/src/zep_cloud/core/http_sse/_models.py b/src/zep_cloud/core/http_sse/_models.py new file mode 100644 index 00000000..1af57f8f --- /dev/null +++ b/src/zep_cloud/core/http_sse/_models.py @@ -0,0 +1,17 @@ +# This file was auto-generated by Fern from our API Definition. + +import json +from dataclasses import dataclass +from typing import Any, Optional + + +@dataclass(frozen=True) +class ServerSentEvent: + event: str = "message" + data: str = "" + id: str = "" + retry: Optional[int] = None + + def json(self) -> Any: + """Parse the data field as JSON.""" + return json.loads(self.data) diff --git a/src/zep_cloud/core/jsonable_encoder.py b/src/zep_cloud/core/jsonable_encoder.py index afee3662..f8beaeaf 100644 --- a/src/zep_cloud/core/jsonable_encoder.py +++ b/src/zep_cloud/core/jsonable_encoder.py @@ -30,6 +30,10 @@ def jsonable_encoder(obj: Any, custom_encoder: Optional[Dict[Any, Callable[[Any], Any]]] = None) -> Any: custom_encoder = custom_encoder or {} + # Generated SDKs use Ellipsis (`...`) as the sentinel value for "OMIT". + # OMIT values should be excluded from serialized payloads. + if obj is Ellipsis: + return None if custom_encoder: if type(obj) in custom_encoder: return custom_encoder[type(obj)](obj) @@ -70,6 +74,8 @@ def jsonable_encoder(obj: Any, custom_encoder: Optional[Dict[Any, Callable[[Any] allowed_keys = set(obj.keys()) for key, value in obj.items(): if key in allowed_keys: + if value is Ellipsis: + continue encoded_key = jsonable_encoder(key, custom_encoder=custom_encoder) encoded_value = jsonable_encoder(value, custom_encoder=custom_encoder) encoded_dict[encoded_key] = encoded_value @@ -77,6 +83,8 @@ def jsonable_encoder(obj: Any, custom_encoder: Optional[Dict[Any, Callable[[Any] if isinstance(obj, (list, set, frozenset, GeneratorType, tuple)): encoded_list = [] for item in obj: + if item is Ellipsis: + continue encoded_list.append(jsonable_encoder(item, custom_encoder=custom_encoder)) return encoded_list diff --git a/src/zep_cloud/core/logging.py b/src/zep_cloud/core/logging.py new file mode 100644 index 00000000..e5e57245 --- /dev/null +++ b/src/zep_cloud/core/logging.py @@ -0,0 +1,107 @@ +# This file was auto-generated by Fern from our API Definition. + +import logging +import typing + +LogLevel = typing.Literal["debug", "info", "warn", "error"] + +_LOG_LEVEL_MAP: typing.Dict[LogLevel, int] = { + "debug": 1, + "info": 2, + "warn": 3, + "error": 4, +} + + +class ILogger(typing.Protocol): + def debug(self, message: str, **kwargs: typing.Any) -> None: ... + def info(self, message: str, **kwargs: typing.Any) -> None: ... + def warn(self, message: str, **kwargs: typing.Any) -> None: ... + def error(self, message: str, **kwargs: typing.Any) -> None: ... + + +class ConsoleLogger: + _logger: logging.Logger + + def __init__(self) -> None: + self._logger = logging.getLogger("fern") + if not self._logger.handlers: + handler = logging.StreamHandler() + handler.setFormatter(logging.Formatter("%(levelname)s - %(message)s")) + self._logger.addHandler(handler) + self._logger.setLevel(logging.DEBUG) + + def debug(self, message: str, **kwargs: typing.Any) -> None: + self._logger.debug(message, extra=kwargs) + + def info(self, message: str, **kwargs: typing.Any) -> None: + self._logger.info(message, extra=kwargs) + + def warn(self, message: str, **kwargs: typing.Any) -> None: + self._logger.warning(message, extra=kwargs) + + def error(self, message: str, **kwargs: typing.Any) -> None: + self._logger.error(message, extra=kwargs) + + +class LogConfig(typing.TypedDict, total=False): + level: LogLevel + logger: ILogger + silent: bool + + +class Logger: + _level: int + _logger: ILogger + _silent: bool + + def __init__(self, *, level: LogLevel, logger: ILogger, silent: bool) -> None: + self._level = _LOG_LEVEL_MAP[level] + self._logger = logger + self._silent = silent + + def _should_log(self, level: LogLevel) -> bool: + return not self._silent and self._level <= _LOG_LEVEL_MAP[level] + + def is_debug(self) -> bool: + return self._should_log("debug") + + def is_info(self) -> bool: + return self._should_log("info") + + def is_warn(self) -> bool: + return self._should_log("warn") + + def is_error(self) -> bool: + return self._should_log("error") + + def debug(self, message: str, **kwargs: typing.Any) -> None: + if self.is_debug(): + self._logger.debug(message, **kwargs) + + def info(self, message: str, **kwargs: typing.Any) -> None: + if self.is_info(): + self._logger.info(message, **kwargs) + + def warn(self, message: str, **kwargs: typing.Any) -> None: + if self.is_warn(): + self._logger.warn(message, **kwargs) + + def error(self, message: str, **kwargs: typing.Any) -> None: + if self.is_error(): + self._logger.error(message, **kwargs) + + +_default_logger: Logger = Logger(level="info", logger=ConsoleLogger(), silent=True) + + +def create_logger(config: typing.Optional[typing.Union[LogConfig, Logger]] = None) -> Logger: + if config is None: + return _default_logger + if isinstance(config, Logger): + return config + return Logger( + level=config.get("level", "info"), + logger=config.get("logger", ConsoleLogger()), + silent=config.get("silent", True), + ) diff --git a/src/zep_cloud/core/pagination.py b/src/zep_cloud/core/pagination.py new file mode 100644 index 00000000..760b0899 --- /dev/null +++ b/src/zep_cloud/core/pagination.py @@ -0,0 +1,82 @@ +# This file was auto-generated by Fern from our API Definition. + +from __future__ import annotations + +from dataclasses import dataclass +from typing import AsyncIterator, Awaitable, Callable, Generic, Iterator, List, Optional, TypeVar + +# Generic to represent the underlying type of the results within a page +T = TypeVar("T") +# Generic to represent the type of the API response +R = TypeVar("R") + + +# SDKs implement a Page ABC per-pagination request, the endpoint then returns a pager that wraps this type +# for example, an endpoint will return SyncPager[UserPage] where UserPage implements the Page ABC. ex: +# +# SyncPager( +# has_next=response.list_metadata.after is not None, +# items=response.data, +# # This should be the outer function that returns the SyncPager again +# get_next=lambda: list(..., cursor: response.cursor) (or list(..., offset: offset + 1)) +# ) + + +@dataclass(frozen=True) +class SyncPager(Generic[T, R]): + get_next: Optional[Callable[[], Optional[SyncPager[T, R]]]] + has_next: bool + items: Optional[List[T]] + response: R + + # Here we type ignore the iterator to avoid a mypy error + # caused by the type conflict with Pydanitc's __iter__ method + # brought in by extending the base model + def __iter__(self) -> Iterator[T]: # type: ignore[override] + for page in self.iter_pages(): + if page.items is not None: + yield from page.items + + def iter_pages(self) -> Iterator[SyncPager[T, R]]: + page: Optional[SyncPager[T, R]] = self + while page is not None: + yield page + + if not page.has_next or page.get_next is None: + return + + page = page.get_next() + if page is None or page.items is None or len(page.items) == 0: + return + + def next_page(self) -> Optional[SyncPager[T, R]]: + return self.get_next() if self.get_next is not None else None + + +@dataclass(frozen=True) +class AsyncPager(Generic[T, R]): + get_next: Optional[Callable[[], Awaitable[Optional[AsyncPager[T, R]]]]] + has_next: bool + items: Optional[List[T]] + response: R + + async def __aiter__(self) -> AsyncIterator[T]: + async for page in self.iter_pages(): + if page.items is not None: + for item in page.items: + yield item + + async def iter_pages(self) -> AsyncIterator[AsyncPager[T, R]]: + page: Optional[AsyncPager[T, R]] = self + while page is not None: + yield page + + if not page.has_next or page.get_next is None: + return + + page = await page.get_next() + if page is None or page.items is None or len(page.items) == 0: + return + + async def next_page(self) -> Optional[AsyncPager[T, R]]: + return await self.get_next() if self.get_next is not None else None diff --git a/src/zep_cloud/core/parse_error.py b/src/zep_cloud/core/parse_error.py new file mode 100644 index 00000000..4527c6a8 --- /dev/null +++ b/src/zep_cloud/core/parse_error.py @@ -0,0 +1,36 @@ +# This file was auto-generated by Fern from our API Definition. + +from typing import Any, Dict, Optional + + +class ParsingError(Exception): + """ + Raised when the SDK fails to parse/validate a response from the server. + This typically indicates that the server returned a response whose shape + does not match the expected schema. + """ + + headers: Optional[Dict[str, str]] + status_code: Optional[int] + body: Any + cause: Optional[Exception] + + def __init__( + self, + *, + headers: Optional[Dict[str, str]] = None, + status_code: Optional[int] = None, + body: Any = None, + cause: Optional[Exception] = None, + ) -> None: + self.headers = headers + self.status_code = status_code + self.body = body + self.cause = cause + super().__init__() + if cause is not None: + self.__cause__ = cause + + def __str__(self) -> str: + cause_str = f", cause: {self.cause}" if self.cause is not None else "" + return f"headers: {self.headers}, status_code: {self.status_code}, body: {self.body}{cause_str}" diff --git a/src/zep_cloud/core/pydantic_utilities.py b/src/zep_cloud/core/pydantic_utilities.py index 7db29500..fea3a08d 100644 --- a/src/zep_cloud/core/pydantic_utilities.py +++ b/src/zep_cloud/core/pydantic_utilities.py @@ -2,30 +2,129 @@ # nopycln: file import datetime as dt +import inspect +import json +import logging from collections import defaultdict -from typing import Any, Callable, ClassVar, Dict, List, Mapping, Optional, Set, Tuple, Type, TypeVar, Union, cast +from dataclasses import asdict +from typing import ( + TYPE_CHECKING, + Any, + Callable, + ClassVar, + Dict, + List, + Mapping, + Optional, + Set, + Tuple, + Type, + TypeVar, + Union, + cast, +) import pydantic +import typing_extensions +from pydantic.fields import FieldInfo as _FieldInfo + +_logger = logging.getLogger(__name__) + +if TYPE_CHECKING: + from .http_sse._models import ServerSentEvent IS_PYDANTIC_V2 = pydantic.VERSION.startswith("2.") if IS_PYDANTIC_V2: - from pydantic.v1.datetime_parse import parse_date as parse_date - from pydantic.v1.datetime_parse import parse_datetime as parse_datetime - from pydantic.v1.fields import ModelField as ModelField - from pydantic.v1.json import ENCODERS_BY_TYPE as encoders_by_type # type: ignore[attr-defined] - from pydantic.v1.typing import get_args as get_args - from pydantic.v1.typing import get_origin as get_origin - from pydantic.v1.typing import is_literal_type as is_literal_type - from pydantic.v1.typing import is_union as is_union + _datetime_adapter = pydantic.TypeAdapter(dt.datetime) # type: ignore[attr-defined] + _date_adapter = pydantic.TypeAdapter(dt.date) # type: ignore[attr-defined] + + def parse_datetime(value: Any) -> dt.datetime: # type: ignore[misc] + if isinstance(value, dt.datetime): + return value + return _datetime_adapter.validate_python(value) + + def parse_date(value: Any) -> dt.date: # type: ignore[misc] + if isinstance(value, dt.datetime): + return value.date() + if isinstance(value, dt.date): + return value + return _date_adapter.validate_python(value) + + # Avoid importing from pydantic.v1 to maintain Python 3.14 compatibility. + from typing import get_args as get_args # type: ignore[assignment] + from typing import get_origin as get_origin # type: ignore[assignment] + + def is_literal_type(tp: Optional[Type[Any]]) -> bool: # type: ignore[misc] + return typing_extensions.get_origin(tp) is typing_extensions.Literal + + def is_union(tp: Optional[Type[Any]]) -> bool: # type: ignore[misc] + return tp is Union or typing_extensions.get_origin(tp) is Union # type: ignore[comparison-overlap] + + # Inline encoders_by_type to avoid importing from pydantic.v1.json + import re as _re + from collections import deque as _deque + from decimal import Decimal as _Decimal + from enum import Enum as _Enum + from ipaddress import ( + IPv4Address as _IPv4Address, + ) + from ipaddress import ( + IPv4Interface as _IPv4Interface, + ) + from ipaddress import ( + IPv4Network as _IPv4Network, + ) + from ipaddress import ( + IPv6Address as _IPv6Address, + ) + from ipaddress import ( + IPv6Interface as _IPv6Interface, + ) + from ipaddress import ( + IPv6Network as _IPv6Network, + ) + from pathlib import Path as _Path + from types import GeneratorType as _GeneratorType + from uuid import UUID as _UUID + + from pydantic.fields import FieldInfo as ModelField # type: ignore[no-redef, assignment] + + def _decimal_encoder(dec_value: Any) -> Any: + if dec_value.as_tuple().exponent >= 0: + return int(dec_value) + return float(dec_value) + + encoders_by_type: Dict[Type[Any], Callable[[Any], Any]] = { # type: ignore[no-redef] + bytes: lambda o: o.decode(), + dt.date: lambda o: o.isoformat(), + dt.datetime: lambda o: o.isoformat(), + dt.time: lambda o: o.isoformat(), + dt.timedelta: lambda td: td.total_seconds(), + _Decimal: _decimal_encoder, + _Enum: lambda o: o.value, + frozenset: list, + _deque: list, + _GeneratorType: list, + _IPv4Address: str, + _IPv4Interface: str, + _IPv4Network: str, + _IPv6Address: str, + _IPv6Interface: str, + _IPv6Network: str, + _Path: str, + _re.Pattern: lambda o: o.pattern, + set: list, + _UUID: str, + } else: from pydantic.datetime_parse import parse_date as parse_date # type: ignore[no-redef] from pydantic.datetime_parse import parse_datetime as parse_datetime # type: ignore[no-redef] - from pydantic.fields import ModelField as ModelField # type: ignore[attr-defined, no-redef] + from pydantic.fields import ModelField as ModelField # type: ignore[attr-defined, no-redef, assignment] from pydantic.json import ENCODERS_BY_TYPE as encoders_by_type # type: ignore[no-redef] from pydantic.typing import get_args as get_args # type: ignore[no-redef] from pydantic.typing import get_origin as get_origin # type: ignore[no-redef] - from pydantic.typing import is_literal_type as is_literal_type # type: ignore[no-redef] + from pydantic.typing import is_literal_type as is_literal_type # type: ignore[no-redef, assignment] from pydantic.typing import is_union as is_union # type: ignore[no-redef] from .datetime_utils import serialize_datetime @@ -36,8 +135,212 @@ Model = TypeVar("Model", bound=pydantic.BaseModel) +def _get_discriminator_and_variants(type_: Type[Any]) -> Tuple[Optional[str], Optional[List[Type[Any]]]]: + """ + Extract the discriminator field name and union variants from a discriminated union type. + Supports Annotated[Union[...], Field(discriminator=...)] patterns. + Returns (discriminator, variants) or (None, None) if not a discriminated union. + """ + origin = typing_extensions.get_origin(type_) + + if origin is typing_extensions.Annotated: + args = typing_extensions.get_args(type_) + if len(args) >= 2: + inner_type = args[0] + # Check annotations for discriminator + discriminator = None + for annotation in args[1:]: + if hasattr(annotation, "discriminator"): + discriminator = getattr(annotation, "discriminator", None) + break + + if discriminator: + inner_origin = typing_extensions.get_origin(inner_type) + if inner_origin is Union: + variants = list(typing_extensions.get_args(inner_type)) + return discriminator, variants + return None, None + + +def _get_field_annotation(model: Type[Any], field_name: str) -> Optional[Type[Any]]: + """Get the type annotation of a field from a Pydantic model.""" + if IS_PYDANTIC_V2: + fields = getattr(model, "model_fields", {}) + field_info = fields.get(field_name) + if field_info: + return cast(Optional[Type[Any]], field_info.annotation) + else: + fields = getattr(model, "__fields__", {}) + field_info = fields.get(field_name) + if field_info: + return cast(Optional[Type[Any]], field_info.outer_type_) + return None + + +def _find_variant_by_discriminator( + variants: List[Type[Any]], + discriminator: str, + discriminator_value: Any, +) -> Optional[Type[Any]]: + """Find the union variant that matches the discriminator value.""" + for variant in variants: + if not (inspect.isclass(variant) and issubclass(variant, pydantic.BaseModel)): + continue + + disc_annotation = _get_field_annotation(variant, discriminator) + if disc_annotation and is_literal_type(disc_annotation): + literal_args = get_args(disc_annotation) + if literal_args and literal_args[0] == discriminator_value: + return variant + return None + + +def _is_string_type(type_: Type[Any]) -> bool: + """Check if a type is str or Optional[str].""" + if type_ is str: + return True + + origin = typing_extensions.get_origin(type_) + if origin is Union: + args = typing_extensions.get_args(type_) + # Optional[str] = Union[str, None] + non_none_args = [a for a in args if a is not type(None)] + if len(non_none_args) == 1 and non_none_args[0] is str: + return True + + return False + + +def parse_sse_obj(sse: "ServerSentEvent", type_: Type[T]) -> T: + """ + Parse a ServerSentEvent into the appropriate type. + + Handles two scenarios based on where the discriminator field is located: + + 1. Data-level discrimination: The discriminator (e.g., 'type') is inside the 'data' payload. + The union describes the data content, not the SSE envelope. + -> Returns: json.loads(data) parsed into the type + + Example: ChatStreamResponse with discriminator='type' + Input: ServerSentEvent(event="message", data='{"type": "content-delta", ...}', id="") + Output: ContentDeltaEvent (parsed from data, SSE envelope stripped) + + 2. Event-level discrimination: The discriminator (e.g., 'event') is at the SSE event level. + The union describes the full SSE event structure. + -> Returns: SSE envelope with 'data' field JSON-parsed only if the variant expects non-string + + Example: JobStreamResponse with discriminator='event' + Input: ServerSentEvent(event="ERROR", data='{"code": "FAILED", ...}', id="123") + Output: JobStreamResponse_Error with data as ErrorData object + + But for variants where data is str (like STATUS_UPDATE): + Input: ServerSentEvent(event="STATUS_UPDATE", data='{"status": "processing"}', id="1") + Output: JobStreamResponse_StatusUpdate with data as string (not parsed) + + Args: + sse: The ServerSentEvent object to parse + type_: The target discriminated union type + + Returns: + The parsed object of type T + + Note: + This function is only available in SDK contexts where http_sse module exists. + """ + sse_event = asdict(sse) + discriminator, variants = _get_discriminator_and_variants(type_) + + if discriminator is None or variants is None: + # Not a discriminated union - parse the data field as JSON + data_value = sse_event.get("data") + if isinstance(data_value, str) and data_value: + try: + parsed_data = json.loads(data_value) + return parse_obj_as(type_, parsed_data) + except json.JSONDecodeError as e: + _logger.warning( + "Failed to parse SSE data field as JSON: %s, data: %s", + e, + data_value[:100] if len(data_value) > 100 else data_value, + ) + return parse_obj_as(type_, sse_event) + + data_value = sse_event.get("data") + + # Check if discriminator is at the top level (event-level discrimination) + if discriminator in sse_event: + # Case 2: Event-level discrimination + # Find the matching variant to check if 'data' field needs JSON parsing + disc_value = sse_event.get(discriminator) + matching_variant = _find_variant_by_discriminator(variants, discriminator, disc_value) + + if matching_variant is not None: + # Check what type the variant expects for 'data' + data_type = _get_field_annotation(matching_variant, "data") + if data_type is not None and not _is_string_type(data_type): + # Variant expects non-string data - parse JSON + if isinstance(data_value, str) and data_value: + try: + parsed_data = json.loads(data_value) + new_object = dict(sse_event) + new_object["data"] = parsed_data + return parse_obj_as(type_, new_object) + except json.JSONDecodeError as e: + _logger.warning( + "Failed to parse SSE data field as JSON for event-level discrimination: %s, data: %s", + e, + data_value[:100] if len(data_value) > 100 else data_value, + ) + # Either no matching variant, data is string type, or JSON parse failed + return parse_obj_as(type_, sse_event) + + else: + # Case 1: Data-level discrimination + # The discriminator is inside the data payload - extract and parse data only + if isinstance(data_value, str) and data_value: + try: + parsed_data = json.loads(data_value) + return parse_obj_as(type_, parsed_data) + except json.JSONDecodeError as e: + _logger.warning( + "Failed to parse SSE data field as JSON for data-level discrimination: %s, data: %s", + e, + data_value[:100] if len(data_value) > 100 else data_value, + ) + return parse_obj_as(type_, sse_event) + + def parse_obj_as(type_: Type[T], object_: Any) -> T: - dealiased_object = convert_and_respect_annotation_metadata(object_=object_, annotation=type_, direction="read") + # convert_and_respect_annotation_metadata is required for TypedDict aliasing. + # + # For Pydantic models, whether we should pre-dealias depends on how the model encodes aliasing: + # - If the model uses real Pydantic aliases (pydantic.Field(alias=...)), then we must pass wire keys through + # unchanged so Pydantic can validate them. + # - If the model encodes aliasing only via FieldMetadata annotations, then we MUST pre-dealias because Pydantic + # will not recognize those aliases during validation. + if inspect.isclass(type_) and issubclass(type_, pydantic.BaseModel): + has_pydantic_aliases = False + if IS_PYDANTIC_V2: + for field_name, field_info in getattr(type_, "model_fields", {}).items(): # type: ignore[attr-defined] + alias = getattr(field_info, "alias", None) + if alias is not None and alias != field_name: + has_pydantic_aliases = True + break + else: + for field in getattr(type_, "__fields__", {}).values(): + alias = getattr(field, "alias", None) + name = getattr(field, "name", None) + if alias is not None and name is not None and alias != name: + has_pydantic_aliases = True + break + + dealiased_object = ( + object_ + if has_pydantic_aliases + else convert_and_respect_annotation_metadata(object_=object_, annotation=type_, direction="read") + ) + else: + dealiased_object = convert_and_respect_annotation_metadata(object_=object_, annotation=type_, direction="read") if IS_PYDANTIC_V2: adapter = pydantic.TypeAdapter(type_) # type: ignore[attr-defined] return adapter.validate_python(dealiased_object) @@ -59,9 +362,46 @@ class UniversalBaseModel(pydantic.BaseModel): protected_namespaces=(), ) + @pydantic.model_validator(mode="before") # type: ignore[attr-defined] + @classmethod + def _coerce_field_names_to_aliases(cls, data: Any) -> Any: + """ + Accept Python field names in input by rewriting them to their Pydantic aliases, + while avoiding silent collisions when a key could refer to multiple fields. + """ + if not isinstance(data, Mapping): + return data + + fields = getattr(cls, "model_fields", {}) # type: ignore[attr-defined] + name_to_alias: Dict[str, str] = {} + alias_to_name: Dict[str, str] = {} + + for name, field_info in fields.items(): + alias = getattr(field_info, "alias", None) or name + name_to_alias[name] = alias + if alias != name: + alias_to_name[alias] = name + + # Detect ambiguous keys: a key that is an alias for one field and a name for another. + ambiguous_keys = set(alias_to_name.keys()).intersection(set(name_to_alias.keys())) + for key in ambiguous_keys: + if key in data and name_to_alias[key] not in data: + raise ValueError( + f"Ambiguous input key '{key}': it is both a field name and an alias. " + "Provide the explicit alias key to disambiguate." + ) + + original_keys = set(data.keys()) + rewritten: Dict[str, Any] = dict(data) + for name, alias in name_to_alias.items(): + if alias != name and name in original_keys and alias not in rewritten: + rewritten[alias] = rewritten.pop(name) + + return rewritten + @pydantic.model_serializer(mode="plain", when_used="json") # type: ignore[attr-defined] def serialize_model(self) -> Any: # type: ignore[name-defined] - serialized = self.model_dump() + serialized = self.dict() # type: ignore[attr-defined] data = {k: serialize_datetime(v) if isinstance(v, dt.datetime) else v for k, v in serialized.items()} return data @@ -71,6 +411,40 @@ class Config: smart_union = True json_encoders = {dt.datetime: serialize_datetime} + @pydantic.root_validator(pre=True) + def _coerce_field_names_to_aliases(cls, values: Any) -> Any: + """ + Pydantic v1 equivalent of _coerce_field_names_to_aliases. + """ + if not isinstance(values, Mapping): + return values + + fields = getattr(cls, "__fields__", {}) + name_to_alias: Dict[str, str] = {} + alias_to_name: Dict[str, str] = {} + + for name, field in fields.items(): + alias = getattr(field, "alias", None) or name + name_to_alias[name] = alias + if alias != name: + alias_to_name[alias] = name + + ambiguous_keys = set(alias_to_name.keys()).intersection(set(name_to_alias.keys())) + for key in ambiguous_keys: + if key in values and name_to_alias[key] not in values: + raise ValueError( + f"Ambiguous input key '{key}': it is both a field name and an alias. " + "Provide the explicit alias key to disambiguate." + ) + + original_keys = set(values.keys()) + rewritten: Dict[str, Any] = dict(values) + for name, alias in name_to_alias.items(): + if alias != name and name in original_keys and alias not in rewritten: + rewritten[alias] = rewritten.pop(name) + + return rewritten + @classmethod def model_construct(cls: Type["Model"], _fields_set: Optional[Set[str]] = None, **values: Any) -> "Model": dealiased_object = convert_and_respect_annotation_metadata(object_=values, annotation=cls, direction="read") @@ -147,7 +521,10 @@ def dict(self, **kwargs: Any) -> Dict[str, Any]: dict_dump = super().dict(**kwargs_with_defaults_exclude_unset_include_fields) - return convert_and_respect_annotation_metadata(object_=dict_dump, annotation=self.__class__, direction="write") + return cast( + Dict[str, Any], + convert_and_respect_annotation_metadata(object_=dict_dump, annotation=self.__class__, direction="write"), + ) def _union_list_of_pydantic_dicts(source: List[Any], destination: List[Any]) -> List[Any]: @@ -217,7 +594,9 @@ def universal_root_validator( ) -> Callable[[AnyCallable], AnyCallable]: def decorator(func: AnyCallable) -> AnyCallable: if IS_PYDANTIC_V2: - return cast(AnyCallable, pydantic.model_validator(mode="before" if pre else "after")(func)) # type: ignore[attr-defined] + # In Pydantic v2, for RootModel we always use "before" mode + # The custom validators transform the input value before the model is created + return cast(AnyCallable, pydantic.model_validator(mode="before")(func)) # type: ignore[attr-defined] return cast(AnyCallable, pydantic.root_validator(pre=pre)(func)) # type: ignore[call-overload] return decorator @@ -232,7 +611,7 @@ def decorator(func: AnyCallable) -> AnyCallable: return decorator -PydanticField = Union[ModelField, pydantic.fields.FieldInfo] +PydanticField = Union[ModelField, _FieldInfo] def _get_model_fields(model: Type["Model"]) -> Mapping[str, PydanticField]: diff --git a/src/zep_cloud/environment.py b/src/zep_cloud/environment.py index b8424b82..f5a5d282 100644 --- a/src/zep_cloud/environment.py +++ b/src/zep_cloud/environment.py @@ -4,4 +4,4 @@ class ZepEnvironment(enum.Enum): - DEFAULT = "https://api.getzep.com/api/v2" + DEFAULT = "https://api.getzep.com/api/v4" diff --git a/src/zep_cloud/errors/__init__.py b/src/zep_cloud/errors/__init__.py index 28fad1dd..370c6048 100644 --- a/src/zep_cloud/errors/__init__.py +++ b/src/zep_cloud/errors/__init__.py @@ -2,10 +2,39 @@ # isort: skip_file -from .bad_request_error import BadRequestError -from .conflict_error import ConflictError -from .forbidden_error import ForbiddenError -from .internal_server_error import InternalServerError -from .not_found_error import NotFoundError +import typing +from importlib import import_module -__all__ = ["BadRequestError", "ConflictError", "ForbiddenError", "InternalServerError", "NotFoundError"] +if typing.TYPE_CHECKING: + from .bad_request_error import BadRequestError + from .not_found_error import NotFoundError + from .unauthorized_error import UnauthorizedError +_dynamic_imports: typing.Dict[str, str] = { + "BadRequestError": ".bad_request_error", + "NotFoundError": ".not_found_error", + "UnauthorizedError": ".unauthorized_error", +} + + +def __getattr__(attr_name: str) -> typing.Any: + module_name = _dynamic_imports.get(attr_name) + if module_name is None: + raise AttributeError(f"No {attr_name} found in _dynamic_imports for module name -> {__name__}") + try: + module = import_module(module_name, __package__) + if module_name == f".{attr_name}": + return module + else: + return getattr(module, attr_name) + except ImportError as e: + raise ImportError(f"Failed to import {attr_name} from {module_name}: {e}") from e + except AttributeError as e: + raise AttributeError(f"Failed to get {attr_name} from {module_name}: {e}") from e + + +def __dir__(): + lazy_attrs = list(_dynamic_imports.keys()) + return sorted(lazy_attrs) + + +__all__ = ["BadRequestError", "NotFoundError", "UnauthorizedError"] diff --git a/src/zep_cloud/errors/bad_request_error.py b/src/zep_cloud/errors/bad_request_error.py index baf5be4f..3cf1d9ca 100644 --- a/src/zep_cloud/errors/bad_request_error.py +++ b/src/zep_cloud/errors/bad_request_error.py @@ -2,9 +2,10 @@ import typing -from ..core.api_error import ApiError +from ..core.api_error import ApiError as core_api_error_ApiError +from ..types.api_error import ApiError as types_api_error_ApiError -class BadRequestError(ApiError): - def __init__(self, body: typing.Optional[typing.Any], headers: typing.Optional[typing.Dict[str, str]] = None): +class BadRequestError(core_api_error_ApiError): + def __init__(self, body: types_api_error_ApiError, headers: typing.Optional[typing.Dict[str, str]] = None): super().__init__(status_code=400, headers=headers, body=body) diff --git a/src/zep_cloud/errors/forbidden_error.py b/src/zep_cloud/errors/forbidden_error.py deleted file mode 100644 index 80e15e0f..00000000 --- a/src/zep_cloud/errors/forbidden_error.py +++ /dev/null @@ -1,11 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import typing - -from ..core.api_error import ApiError as core_api_error_ApiError -from ..types.api_error import ApiError as types_api_error_ApiError - - -class ForbiddenError(core_api_error_ApiError): - def __init__(self, body: types_api_error_ApiError, headers: typing.Optional[typing.Dict[str, str]] = None): - super().__init__(status_code=403, headers=headers, body=body) diff --git a/src/zep_cloud/errors/internal_server_error.py b/src/zep_cloud/errors/internal_server_error.py deleted file mode 100644 index 42082d1f..00000000 --- a/src/zep_cloud/errors/internal_server_error.py +++ /dev/null @@ -1,11 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import typing - -from ..core.api_error import ApiError as core_api_error_ApiError -from ..types.api_error import ApiError as types_api_error_ApiError - - -class InternalServerError(core_api_error_ApiError): - def __init__(self, body: types_api_error_ApiError, headers: typing.Optional[typing.Dict[str, str]] = None): - super().__init__(status_code=500, headers=headers, body=body) diff --git a/src/zep_cloud/errors/conflict_error.py b/src/zep_cloud/errors/unauthorized_error.py similarity index 74% rename from src/zep_cloud/errors/conflict_error.py rename to src/zep_cloud/errors/unauthorized_error.py index a1954586..da573a2e 100644 --- a/src/zep_cloud/errors/conflict_error.py +++ b/src/zep_cloud/errors/unauthorized_error.py @@ -6,6 +6,6 @@ from ..types.api_error import ApiError as types_api_error_ApiError -class ConflictError(core_api_error_ApiError): +class UnauthorizedError(core_api_error_ApiError): def __init__(self, body: types_api_error_ApiError, headers: typing.Optional[typing.Dict[str, str]] = None): - super().__init__(status_code=409, headers=headers, body=body) + super().__init__(status_code=401, headers=headers, body=body) diff --git a/src/zep_cloud/graph/__init__.py b/src/zep_cloud/graph/__init__.py index 49f0683f..a82cd113 100644 --- a/src/zep_cloud/graph/__init__.py +++ b/src/zep_cloud/graph/__init__.py @@ -2,6 +2,40 @@ # isort: skip_file -from . import edge, episode, node, observation, thread_summary +import typing +from importlib import import_module -__all__ = ["edge", "episode", "node", "observation", "thread_summary"] +if typing.TYPE_CHECKING: + from . import document_summary, edge, episode, node, observation, thread_summary +_dynamic_imports: typing.Dict[str, str] = { + "document_summary": ".document_summary", + "edge": ".edge", + "episode": ".episode", + "node": ".node", + "observation": ".observation", + "thread_summary": ".thread_summary", +} + + +def __getattr__(attr_name: str) -> typing.Any: + module_name = _dynamic_imports.get(attr_name) + if module_name is None: + raise AttributeError(f"No {attr_name} found in _dynamic_imports for module name -> {__name__}") + try: + module = import_module(module_name, __package__) + if module_name == f".{attr_name}": + return module + else: + return getattr(module, attr_name) + except ImportError as e: + raise ImportError(f"Failed to import {attr_name} from {module_name}: {e}") from e + except AttributeError as e: + raise AttributeError(f"Failed to get {attr_name} from {module_name}: {e}") from e + + +def __dir__(): + lazy_attrs = list(_dynamic_imports.keys()) + return sorted(lazy_attrs) + + +__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..ad483707 100644 --- a/src/zep_cloud/graph/client.py +++ b/src/zep_cloud/graph/client.py @@ -1,40 +1,32 @@ # This file was auto-generated by Fern from our API Definition. +from __future__ import annotations + import typing from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper +from ..core.pagination import AsyncPager, SyncPager from ..core.request_options import RequestOptions -from ..types.add_node_item import AddNodeItem -from ..types.add_nodes_response import AddNodesResponse -from ..types.add_triple_response import AddTripleResponse -from ..types.clone_graph_response import CloneGraphResponse -from ..types.custom_instruction import CustomInstruction -from ..types.detect_config import DetectConfig -from ..types.detect_patterns_response import DetectPatternsResponse -from ..types.edge_type import EdgeType -from ..types.entity_type import EntityType -from ..types.entity_type_response import EntityTypeResponse -from ..types.episode import Episode -from ..types.episode_data import EpisodeData +from ..types.async_result import AsyncResult +from ..types.clone_graph_result import CloneGraphResult from ..types.graph import Graph -from ..types.graph_data_type import GraphDataType -from ..types.graph_list_response import GraphListResponse -from ..types.graph_search_results import GraphSearchResults -from ..types.graph_search_scope import GraphSearchScope -from ..types.graph_subgraph_response import GraphSubgraphResponse -from ..types.list_custom_instructions_response import ListCustomInstructionsResponse -from ..types.pattern_seeds import PatternSeeds -from ..types.recency_weight import RecencyWeight -from ..types.reranker import Reranker -from ..types.search_filters import SearchFilters -from ..types.success_response import SuccessResponse -from .edge.client import AsyncEdgeClient, EdgeClient -from .episode.client import AsyncEpisodeClient, EpisodeClient -from .node.client import AsyncNodeClient, NodeClient -from .observation.client import AsyncObservationClient, ObservationClient +from ..types.graph_context_response import GraphContextResponse +from ..types.graph_delete_result import GraphDeleteResult +from ..types.graph_page import GraphPage +from ..types.instructions import Instructions +from ..types.json_object import JsonObject +from ..types.json_object_page import JsonObjectPage +from ..types.observation_steering import ObservationSteering +from ..types.ontology import Ontology from .raw_client import AsyncRawGraphClient, RawGraphClient -from .thread_summary.client import AsyncThreadSummaryClient, ThreadSummaryClient +if typing.TYPE_CHECKING: + 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 + from .observation.client import AsyncObservationClient, ObservationClient + from .thread_summary.client import AsyncThreadSummaryClient, ThreadSummaryClient # this is used as the default value for optional parameters OMIT = typing.cast(typing.Any, ...) @@ -42,15 +34,13 @@ class GraphClient: def __init__(self, *, client_wrapper: SyncClientWrapper): self._raw_client = RawGraphClient(client_wrapper=client_wrapper) - self.edge = EdgeClient(client_wrapper=client_wrapper) - - self.episode = EpisodeClient(client_wrapper=client_wrapper) - - self.node = NodeClient(client_wrapper=client_wrapper) - - self.observation = ObservationClient(client_wrapper=client_wrapper) - - self.thread_summary = ThreadSummaryClient(client_wrapper=client_wrapper) + self._client_wrapper = client_wrapper + self._document_summary: typing.Optional[DocumentSummaryClient] = None + self._episode: typing.Optional[EpisodeClient] = None + self._edge: typing.Optional[EdgeClient] = None + self._node: typing.Optional[NodeClient] = None + self._observation: typing.Optional[ObservationClient] = None + self._thread_summary: typing.Optional[ThreadSummaryClient] = None @property def with_raw_response(self) -> RawGraphClient: @@ -63,31 +53,36 @@ def with_raw_response(self) -> RawGraphClient: """ return self._raw_client - def list_custom_instructions( + def create( self, *, - user_id: typing.Optional[str] = None, - graph_id: typing.Optional[str] = None, + description: typing.Optional[str] = OMIT, + graph_id: typing.Optional[str] = OMIT, + name: typing.Optional[str] = OMIT, + time_zone: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> ListCustomInstructionsResponse: + ) -> Graph: """ - Lists all custom instructions for a project, user, or graph. - Parameters ---------- - user_id : typing.Optional[str] - User ID to get user-specific instructions + description : typing.Optional[str] graph_id : typing.Optional[str] - Graph ID to get graph-specific instructions + + name : typing.Optional[str] + + time_zone : typing.Optional[str] + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - ListCustomInstructionsResponse - The list of instructions. + Graph + Created Examples -------- @@ -96,96 +91,112 @@ def list_custom_instructions( client = Zep( api_key="YOUR_API_KEY", ) - client.graph.list_custom_instructions( - user_id="user_id", - graph_id="graph_id", - ) + client.graph.create() """ - _response = self._raw_client.list_custom_instructions( - user_id=user_id, graph_id=graph_id, request_options=request_options + _response = self._raw_client.create( + description=description, + graph_id=graph_id, + name=name, + time_zone=time_zone, + idempotency_key=idempotency_key, + request_options=request_options, ) return _response.data - def add_custom_instructions( + def list( self, *, - instructions: typing.Sequence[CustomInstruction], - graph_ids: typing.Optional[typing.Sequence[str]] = OMIT, - user_ids: typing.Optional[typing.Sequence[str]] = OMIT, + limit: typing.Optional[int] = None, + cursor: typing.Optional[str] = None, + order_by: typing.Optional[str] = None, + order: typing.Optional[str] = None, + search: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> SuccessResponse: + ) -> SyncPager[Graph, GraphPage]: """ - Adds new custom instructions for graphs without removing existing ones. If user_ids or graph_ids is empty, adds to project-wide default instructions. - Parameters ---------- - instructions : typing.Sequence[CustomInstruction] - Instructions to add to the graph. + limit : typing.Optional[int] + Page size + + cursor : typing.Optional[str] + Opaque page cursor - graph_ids : typing.Optional[typing.Sequence[str]] - Graph IDs to add the instructions to. If empty, the instructions are added to the project-wide default. + order_by : typing.Optional[str] + Sort field + + order : typing.Optional[str] + asc or desc + + search : typing.Optional[str] - user_ids : typing.Optional[typing.Sequence[str]] - User IDs to add the instructions to. If empty, the instructions are added to the project-wide default. + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - SuccessResponse - Instructions added successfully + SyncPager[Graph, GraphPage] + OK Examples -------- - from zep_cloud import CustomInstruction, Zep + from zep_cloud import Zep client = Zep( api_key="YOUR_API_KEY", ) - client.graph.add_custom_instructions( - instructions=[ - CustomInstruction( - name="name", - text="text", - ) - ], + response = client.graph.list( + limit=1, + cursor="cursor", + order_by="order_by", + order="order", ) + for item in response: + yield item + # alternatively, you can paginate page-by-page + for page in response.iter_pages(): + yield page """ - _response = self._raw_client.add_custom_instructions( - instructions=instructions, graph_ids=graph_ids, user_ids=user_ids, request_options=request_options + return self._raw_client.list( + limit=limit, + cursor=cursor, + order_by=order_by, + order=order, + search=search, + idempotency_key=idempotency_key, + request_options=request_options, ) - return _response.data - def delete_custom_instructions( + def lookup( self, *, - graph_ids: typing.Optional[typing.Sequence[str]] = OMIT, - instruction_names: typing.Optional[typing.Sequence[str]] = OMIT, - user_ids: typing.Optional[typing.Sequence[str]] = OMIT, + graph_id: typing.Optional[str] = OMIT, + thread_id: typing.Optional[str] = OMIT, + user_id: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> SuccessResponse: + ) -> Graph: """ - Deletes custom instructions for graphs or project wide defaults. - Parameters ---------- - graph_ids : typing.Optional[typing.Sequence[str]] - Determines which group graphs will have their custom instructions deleted. If no graphs are provided, the project-wide custom instructions will be affected. + graph_id : typing.Optional[str] - instruction_names : typing.Optional[typing.Sequence[str]] - Unique identifier for the instructions to be deleted. If empty deletes all instructions. + thread_id : typing.Optional[str] - user_ids : typing.Optional[typing.Sequence[str]] - Determines which user graphs will have their custom instructions deleted. If no users are provided, the project-wide custom instructions will be affected. + user_id : typing.Optional[str] + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - SuccessResponse - Instructions deleted successfully + Graph + OK Examples -------- @@ -194,38 +205,31 @@ def delete_custom_instructions( client = Zep( api_key="YOUR_API_KEY", ) - client.graph.delete_custom_instructions() + client.graph.lookup() """ - _response = self._raw_client.delete_custom_instructions( - graph_ids=graph_ids, instruction_names=instruction_names, user_ids=user_ids, request_options=request_options + _response = self._raw_client.lookup( + graph_id=graph_id, + thread_id=thread_id, + user_id=user_id, + idempotency_key=idempotency_key, + request_options=request_options, ) return _response.data - def list_entity_types( - self, - *, - user_id: typing.Optional[str] = None, - graph_id: typing.Optional[str] = None, - request_options: typing.Optional[RequestOptions] = None, - ) -> EntityTypeResponse: + def get(self, graph_uuid: str, *, request_options: typing.Optional[RequestOptions] = None) -> Graph: """ - Returns all entity types for a project, user, or graph. - Parameters ---------- - user_id : typing.Optional[str] - User ID to get user-specific entity types - - graph_id : typing.Optional[str] - Graph ID to get graph-specific entity types + graph_uuid : str + Graph UUID request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - EntityTypeResponse - The list of entity types. + Graph + OK Examples -------- @@ -234,45 +238,35 @@ def list_entity_types( client = Zep( api_key="YOUR_API_KEY", ) - client.graph.list_entity_types( - user_id="user_id", - graph_id="graph_id", + client.graph.get( + graph_uuid="graph_uuid", ) """ - _response = self._raw_client.list_entity_types( - user_id=user_id, graph_id=graph_id, request_options=request_options - ) + _response = self._raw_client.get(graph_uuid, request_options=request_options) return _response.data - def set_entity_types_internal( + def delete( self, + graph_uuid: str, *, - edge_types: typing.Optional[typing.Sequence[EdgeType]] = OMIT, - entity_types: typing.Optional[typing.Sequence[EntityType]] = OMIT, - graph_ids: typing.Optional[typing.Sequence[str]] = OMIT, - user_ids: typing.Optional[typing.Sequence[str]] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> SuccessResponse: + ) -> GraphDeleteResult: """ - Sets the entity types for multiple users and graphs, replacing any existing ones. - Parameters ---------- - edge_types : typing.Optional[typing.Sequence[EdgeType]] - - entity_types : typing.Optional[typing.Sequence[EntityType]] + graph_uuid : str + Graph UUID - graph_ids : typing.Optional[typing.Sequence[str]] - - user_ids : typing.Optional[typing.Sequence[str]] + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - SuccessResponse - Entity types set successfully + GraphDeleteResult + Accepted Examples -------- @@ -281,62 +275,49 @@ def set_entity_types_internal( client = Zep( api_key="YOUR_API_KEY", ) - client.graph.set_entity_types_internal() + client.graph.delete( + graph_uuid="graph_uuid", + ) """ - _response = self._raw_client.set_entity_types_internal( - edge_types=edge_types, - entity_types=entity_types, - graph_ids=graph_ids, - user_ids=user_ids, - request_options=request_options, + _response = self._raw_client.delete( + graph_uuid, idempotency_key=idempotency_key, request_options=request_options ) return _response.data - def add( + def update( self, + graph_uuid: str, *, - data: str, - type: GraphDataType, - created_at: 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, - strict_ontology: typing.Optional[bool] = OMIT, - user_id: typing.Optional[str] = OMIT, + description: typing.Optional[str] = OMIT, + name: typing.Optional[str] = OMIT, + time_zone: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> Episode: + ) -> Graph: """ - Add data to the graph. - Parameters ---------- - data : str - - type : GraphDataType - - created_at : typing.Optional[str] - - 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. + graph_uuid : str + Graph UUID - metadata : typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] - Optional metadata key-value pairs. Max 10 keys. Values must be strings, numbers, booleans, or arrays of scalars. + description : typing.Optional[str] + Omit to leave unchanged, send JSON null to clear, or send a value to set. - source_description : typing.Optional[str] + name : typing.Optional[str] + Omit to leave unchanged, send JSON null to clear, or send a value to set. - strict_ontology : typing.Optional[bool] - When true, prevents extraction of generic Entity nodes that do not match the configured ontology. + time_zone : typing.Optional[str] + Omit to leave unchanged, send JSON null to clear, or send a value to set. - user_id : typing.Optional[str] - User ID is the ID of the user to which the data will be added. If not adding to a user graph, please use graph_id field instead. + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - Episode - Added episode + Graph + OK Examples -------- @@ -345,191 +326,146 @@ def add( client = Zep( api_key="YOUR_API_KEY", ) - client.graph.add( - data="data", - type="text", + client.graph.update( + graph_uuid="graph_uuid", ) """ - _response = self._raw_client.add( - data=data, - type=type, - created_at=created_at, - graph_id=graph_id, - metadata=metadata, - source_description=source_description, - strict_ontology=strict_ontology, - user_id=user_id, + _response = self._raw_client.update( + graph_uuid, + description=description, + name=name, + time_zone=time_zone, + idempotency_key=idempotency_key, request_options=request_options, ) return _response.data - def add_batch( + def clone( self, + graph_uuid: str, *, - episodes: typing.Sequence[EpisodeData], - graph_id: typing.Optional[str] = OMIT, - strict_ontology: typing.Optional[bool] = OMIT, - user_id: typing.Optional[str] = OMIT, + target_graph_id: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> typing.List[Episode]: + ) -> CloneGraphResult: """ - Deprecated. Use the [Batch API](/adding-batch-data) (`client.batch.*`) instead. - - Adds data to the graph in batch mode, processing episodes concurrently. - Parameters ---------- - episodes : typing.Sequence[EpisodeData] + graph_uuid : str + Graph UUID - 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. - - strict_ontology : typing.Optional[bool] - When true, prevents extraction of generic Entity nodes that do not match the configured ontology. + target_graph_id : typing.Optional[str] - user_id : typing.Optional[str] - User ID is the ID of the user to which the data will be added. If not adding to a user graph, please use graph_id field instead. + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - typing.List[Episode] - Added episodes + CloneGraphResult + Accepted Examples -------- - from zep_cloud import EpisodeData, Zep + from zep_cloud import Zep client = Zep( api_key="YOUR_API_KEY", ) - client.graph.add_batch( - episodes=[ - EpisodeData( - data="data", - type="text", - ) - ], + client.graph.clone( + graph_uuid="graph_uuid", ) """ - _response = self._raw_client.add_batch( - episodes=episodes, - graph_id=graph_id, - strict_ontology=strict_ontology, - user_id=user_id, + _response = self._raw_client.clone( + graph_uuid, + target_graph_id=target_graph_id, + idempotency_key=idempotency_key, request_options=request_options, ) return _response.data - def add_fact_triple( + def get_context( self, + graph_uuid: str, *, - fact: str, - fact_name: str, - created_at: typing.Optional[str] = OMIT, - edge_attributes: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = OMIT, - expired_at: typing.Optional[str] = OMIT, - graph_id: typing.Optional[str] = OMIT, - invalid_at: typing.Optional[str] = OMIT, - metadata: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = OMIT, - source_node_attributes: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = OMIT, - source_node_labels: typing.Optional[typing.Sequence[str]] = OMIT, - source_node_name: typing.Optional[str] = OMIT, - source_node_summary: typing.Optional[str] = OMIT, - source_node_uuid: typing.Optional[str] = OMIT, - target_node_attributes: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = OMIT, - target_node_labels: typing.Optional[typing.Sequence[str]] = OMIT, - target_node_name: typing.Optional[str] = OMIT, - target_node_summary: typing.Optional[str] = OMIT, - target_node_uuid: typing.Optional[str] = OMIT, - user_id: typing.Optional[str] = OMIT, - valid_at: typing.Optional[str] = OMIT, + filters: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + include_results: typing.Optional[bool] = OMIT, + max_characters: typing.Optional[int] = OMIT, + query: typing.Optional[str] = OMIT, + recency_bias: typing.Optional[str] = OMIT, + template_uuid: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> AddTripleResponse: + ) -> GraphContextResponse: """ - Add a fact triple for a user or group - Parameters ---------- - fact : str - The fact relating the two nodes that this edge represents - - fact_name : str - The name of the edge to add. Should be all caps using snake case (eg RELATES_TO) + graph_uuid : str + Graph UUID - created_at : typing.Optional[str] - The timestamp of the message + filters : typing.Optional[typing.Dict[str, typing.Any]] - edge_attributes : typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] - Additional attributes of the edge. Values must be scalar types (string, number, boolean, or null). - Nested objects and arrays are not allowed. + include_results : typing.Optional[bool] - expired_at : typing.Optional[str] - The time (if any) at which the edge expires - - graph_id : typing.Optional[str] - - invalid_at : typing.Optional[str] - The time (if any) at which the fact stops being true - - metadata : typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] - Optional metadata key-value pairs for the shadow episode created for this fact triple. - Max 10 keys. Values must be strings, numbers, or booleans. - - source_node_attributes : typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] - Additional attributes of the source node. Values must be scalar types (string, number, boolean, or null). - Nested objects and arrays are not allowed. - - source_node_labels : typing.Optional[typing.Sequence[str]] - The labels for the source node. At most one entity-type label may be - provided so that manually-added triples remain consistent with automatic - episode extraction, which assigns one best-match entity type per node. - The base "Entity" label is added implicitly by the graph layer on save - and does not need to be supplied here. - - source_node_name : typing.Optional[str] - The name of the source node to add + max_characters : typing.Optional[int] - source_node_summary : typing.Optional[str] - The summary of the source node to add + query : typing.Optional[str] - source_node_uuid : typing.Optional[str] - The source node uuid + recency_bias : typing.Optional[str] - target_node_attributes : typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] - Additional attributes of the target node. Values must be scalar types (string, number, boolean, or null). - Nested objects and arrays are not allowed. + template_uuid : typing.Optional[str] - target_node_labels : typing.Optional[typing.Sequence[str]] - The labels for the target node. At most one entity-type label may be - provided so that manually-added triples remain consistent with automatic - episode extraction, which assigns one best-match entity type per node. - The base "Entity" label is added implicitly by the graph layer on save - and does not need to be supplied here. + idempotency_key : typing.Optional[str] - target_node_name : typing.Optional[str] - The name of the target node to add + request_options : typing.Optional[RequestOptions] + Request-specific configuration. - target_node_summary : typing.Optional[str] - The summary of the target node to add + Returns + ------- + GraphContextResponse + OK - target_node_uuid : typing.Optional[str] - The target node uuid + Examples + -------- + from zep_cloud import Zep - user_id : typing.Optional[str] + client = Zep( + api_key="YOUR_API_KEY", + ) + client.graph.get_context( + graph_uuid="graph_uuid", + ) + """ + _response = self._raw_client.get_context( + graph_uuid, + filters=filters, + include_results=include_results, + max_characters=max_characters, + query=query, + recency_bias=recency_bias, + template_uuid=template_uuid, + idempotency_key=idempotency_key, + request_options=request_options, + ) + return _response.data - valid_at : typing.Optional[str] - The time at which the fact becomes true + def get_instructions( + self, graph_uuid: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> Instructions: + """ + Parameters + ---------- + graph_uuid : str + Graph UUID request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - AddTripleResponse - Resulting triple + Instructions + OK Examples -------- @@ -538,69 +474,41 @@ def add_fact_triple( client = Zep( api_key="YOUR_API_KEY", ) - client.graph.add_fact_triple( - fact="fact", - fact_name="fact_name", + client.graph.get_instructions( + graph_uuid="graph_uuid", ) """ - _response = self._raw_client.add_fact_triple( - fact=fact, - fact_name=fact_name, - created_at=created_at, - edge_attributes=edge_attributes, - expired_at=expired_at, - graph_id=graph_id, - invalid_at=invalid_at, - metadata=metadata, - source_node_attributes=source_node_attributes, - source_node_labels=source_node_labels, - source_node_name=source_node_name, - source_node_summary=source_node_summary, - source_node_uuid=source_node_uuid, - target_node_attributes=target_node_attributes, - target_node_labels=target_node_labels, - target_node_name=target_node_name, - target_node_summary=target_node_summary, - target_node_uuid=target_node_uuid, - user_id=user_id, - valid_at=valid_at, - request_options=request_options, - ) + _response = self._raw_client.get_instructions(graph_uuid, request_options=request_options) return _response.data - def clone( + def set_instructions( self, + graph_uuid: str, *, - source_graph_id: typing.Optional[str] = OMIT, - source_user_id: typing.Optional[str] = OMIT, - target_graph_id: typing.Optional[str] = OMIT, - target_user_id: typing.Optional[str] = OMIT, + inherited: typing.Optional[bool] = OMIT, + instructions: typing.Optional[typing.Sequence[typing.Dict[str, typing.Any]]] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> CloneGraphResponse: + ) -> Instructions: """ - Clone a user or group graph. - Parameters ---------- - source_graph_id : typing.Optional[str] - source_graph_id is the ID of the graph to be cloned. Required if source_user_id is not provided + graph_uuid : str + Graph UUID - source_user_id : typing.Optional[str] - user_id of the user whose graph is being cloned. Required if source_graph_id is not provided + inherited : typing.Optional[bool] - target_graph_id : typing.Optional[str] - target_graph_id is the ID to be set on the cloned graph. Must not point to an existing graph. Required if target_user_id is not provided. + instructions : typing.Optional[typing.Sequence[typing.Dict[str, typing.Any]]] - target_user_id : typing.Optional[str] - user_id to be set on the cloned user. Must not point to an existing user. Required if target_graph_id is not provided. + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - CloneGraphResponse - Response object containing graph_id or user_id pointing to the new graph + Instructions + OK Examples -------- @@ -609,47 +517,35 @@ def clone( client = Zep( api_key="YOUR_API_KEY", ) - client.graph.clone() + client.graph.set_instructions( + graph_uuid="graph_uuid", + ) """ - _response = self._raw_client.clone( - source_graph_id=source_graph_id, - source_user_id=source_user_id, - target_graph_id=target_graph_id, - target_user_id=target_user_id, + _response = self._raw_client.set_instructions( + graph_uuid, + inherited=inherited, + instructions=instructions, + idempotency_key=idempotency_key, request_options=request_options, ) return _response.data - def create( - self, - *, - graph_id: str, - description: typing.Optional[str] = OMIT, - name: typing.Optional[str] = OMIT, - time_zone: typing.Optional[str] = OMIT, - request_options: typing.Optional[RequestOptions] = None, - ) -> Graph: + def get_observation_steering( + self, graph_uuid: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> ObservationSteering: """ - Creates a new graph. - Parameters ---------- - graph_id : str - - description : typing.Optional[str] - - name : typing.Optional[str] - - time_zone : typing.Optional[str] - The graph's IANA time zone. Stored on its group-backed subject. + graph_uuid : str + Graph UUID request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - Graph - The added graph + ObservationSteering + OK Examples -------- @@ -658,52 +554,44 @@ def create( client = Zep( api_key="YOUR_API_KEY", ) - client.graph.create( - graph_id="graph_id", + client.graph.get_observation_steering( + graph_uuid="graph_uuid", ) """ - _response = self._raw_client.create( - graph_id=graph_id, description=description, name=name, time_zone=time_zone, request_options=request_options - ) + _response = self._raw_client.get_observation_steering(graph_uuid, request_options=request_options) return _response.data - def list_all( + def set_observation_steering( self, + graph_uuid: str, *, - page_number: typing.Optional[int] = None, - page_size: typing.Optional[int] = None, - search: typing.Optional[str] = None, - order_by: typing.Optional[str] = None, - asc: typing.Optional[bool] = None, + inherited: typing.Optional[bool] = OMIT, + instruction: typing.Optional[str] = OMIT, + types: typing.Optional[typing.Sequence[typing.Dict[str, typing.Any]]] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> GraphListResponse: + ) -> ObservationSteering: """ - Returns all graphs. In order to list users, use user.list_ordered instead - Parameters ---------- - page_number : typing.Optional[int] - Page number for pagination, starting from 1. + graph_uuid : str + Graph UUID - page_size : typing.Optional[int] - Number of graphs to retrieve per page (default 50, range 1-100; explicit 0 is invalid). + inherited : typing.Optional[bool] - search : typing.Optional[str] - Search term for filtering graphs by graph_id, name, or description. Queries longer than 200 Unicode code points after whitespace normalization are invalid. + instruction : typing.Optional[str] - order_by : typing.Optional[str] - Column to sort by (created_at, graph_id, name). + types : typing.Optional[typing.Sequence[typing.Dict[str, typing.Any]]] - asc : typing.Optional[bool] - Sort in ascending order. + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - GraphListResponse - Successfully retrieved list of graphs. + ObservationSteering + OK Examples -------- @@ -712,141 +600,80 @@ def list_all( client = Zep( api_key="YOUR_API_KEY", ) - client.graph.list_all( - page_number=1, - page_size=1, - search="search", - order_by="order_by", - asc=True, + client.graph.set_observation_steering( + graph_uuid="graph_uuid", ) """ - _response = self._raw_client.list_all( - page_number=page_number, - page_size=page_size, - search=search, - order_by=order_by, - asc=asc, + _response = self._raw_client.set_observation_steering( + graph_uuid, + inherited=inherited, + instruction=instruction, + types=types, + idempotency_key=idempotency_key, request_options=request_options, ) return _response.data - def add_nodes( - self, - *, - nodes: typing.Sequence[AddNodeItem], - graph_id: typing.Optional[str] = OMIT, - user_id: typing.Optional[str] = OMIT, - request_options: typing.Optional[RequestOptions] = None, - ) -> AddNodesResponse: + def get_ontology(self, graph_uuid: str, *, request_options: typing.Optional[RequestOptions] = None) -> Ontology: """ - Add entity nodes to a user or graph directly, without episode ingestion. Up to 100 nodes per request. - Parameters ---------- - nodes : typing.Sequence[AddNodeItem] - The nodes to add. 1 to 100 items. - - graph_id : typing.Optional[str] - - user_id : typing.Optional[str] + graph_uuid : str + Graph UUID request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - AddNodesResponse - Accepted + Ontology + OK Examples -------- - from zep_cloud import AddNodeItem, Zep + from zep_cloud import Zep client = Zep( api_key="YOUR_API_KEY", ) - client.graph.add_nodes( - nodes=[ - AddNodeItem( - name="name", - ) - ], + client.graph.get_ontology( + graph_uuid="graph_uuid", ) """ - _response = self._raw_client.add_nodes( - nodes=nodes, graph_id=graph_id, user_id=user_id, request_options=request_options - ) + _response = self._raw_client.get_ontology(graph_uuid, request_options=request_options) return _response.data - def detect_patterns( + def set_ontology( self, + graph_uuid: str, *, - detect: typing.Optional[DetectConfig] = OMIT, - edge_limit: typing.Optional[int] = OMIT, - graph_id: typing.Optional[str] = OMIT, - limit: typing.Optional[int] = OMIT, - min_occurrences: typing.Optional[int] = OMIT, - query: typing.Optional[str] = OMIT, - query_limit: typing.Optional[int] = OMIT, - recency_weight: typing.Optional[RecencyWeight] = OMIT, - search_filters: typing.Optional[SearchFilters] = OMIT, - seeds: typing.Optional[PatternSeeds] = OMIT, - user_id: typing.Optional[str] = OMIT, + edge_types: typing.Optional[typing.Sequence[typing.Dict[str, typing.Any]]] = OMIT, + entity_types: typing.Optional[typing.Sequence[typing.Dict[str, typing.Any]]] = OMIT, + inherited: typing.Optional[bool] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> DetectPatternsResponse: + ) -> Ontology: """ - 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, - detects triple-frequency patterns, and returns resolved edges ranked by relevance. - Parameters ---------- - detect : typing.Optional[DetectConfig] - Which pattern types to detect with type-specific configuration. - Omit to detect all types with defaults. Ignored when query is set. - - edge_limit : typing.Optional[int] - Max resolved edges per pattern. Default: 10, Max: 100. Only used with query. - - graph_id : typing.Optional[str] - Graph ID when detecting patterns on a named graph - - limit : typing.Optional[int] - Max patterns to return. Default: 50, Max: 200 + graph_uuid : str + Graph UUID - min_occurrences : typing.Optional[int] - Minimum occurrence count to report a pattern. Default: 2 + edge_types : typing.Optional[typing.Sequence[typing.Dict[str, typing.Any]]] - query : typing.Optional[str] - Search query for discovering seed nodes via hybrid search. - When set, forces triple-frequency detection only and enables edge resolution - with cross-encoder reranking. Mutually exclusive with seeds. - - query_limit : typing.Optional[int] - Max seed nodes from search. Default: 10, Max: 50. Only used with query. - - recency_weight : typing.Optional[RecencyWeight] - Exponential half-life decay applied to edge created_at timestamps. - Valid values: none, 7_days, 30_days, 90_days. Default: none - - search_filters : typing.Optional[SearchFilters] - Filters which edges/nodes participate in pattern detection. - Reuses the same filter format as /graph/search. + entity_types : typing.Optional[typing.Sequence[typing.Dict[str, typing.Any]]] - seeds : typing.Optional[PatternSeeds] - Seed selection. If omitted, analyzes the entire graph. Mutually exclusive with query. + inherited : typing.Optional[bool] - user_id : typing.Optional[str] - User ID when detecting patterns on a user graph + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - DetectPatternsResponse - Detected patterns + Ontology + OK Examples -------- @@ -855,95 +682,68 @@ def detect_patterns( client = Zep( api_key="YOUR_API_KEY", ) - client.graph.detect_patterns() + client.graph.set_ontology( + graph_uuid="graph_uuid", + ) """ - _response = self._raw_client.detect_patterns( - detect=detect, - edge_limit=edge_limit, - graph_id=graph_id, - limit=limit, - min_occurrences=min_occurrences, - query=query, - query_limit=query_limit, - recency_weight=recency_weight, - search_filters=search_filters, - seeds=seeds, - user_id=user_id, + _response = self._raw_client.set_ontology( + graph_uuid, + edge_types=edge_types, + entity_types=entity_types, + inherited=inherited, + idempotency_key=idempotency_key, request_options=request_options, ) return _response.data - def search( + def search_edges( self, + graph_uuid: str, *, - query: str, + limit: typing.Optional[int] = None, + cursor: typing.Optional[str] = None, bfs_origin_node_uuids: typing.Optional[typing.Sequence[str]] = OMIT, center_node_uuid: typing.Optional[str] = OMIT, - graph_id: typing.Optional[str] = OMIT, - limit: typing.Optional[int] = OMIT, - max_characters: typing.Optional[int] = OMIT, + filters: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, mmr_lambda: typing.Optional[float] = OMIT, - reranker: typing.Optional[Reranker] = OMIT, - return_raw_results: typing.Optional[bool] = OMIT, - scope: typing.Optional[GraphSearchScope] = OMIT, - search_filters: typing.Optional[SearchFilters] = OMIT, - user_id: typing.Optional[str] = OMIT, + query: typing.Optional[str] = OMIT, + reranker: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> GraphSearchResults: + ) -> SyncPager[JsonObject, JsonObjectPage]: """ - Perform a graph search query. - Parameters ---------- - query : str - The string to search for (required) + graph_uuid : str + Graph UUID - bfs_origin_node_uuids : typing.Optional[typing.Sequence[str]] - Nodes that are the origins of the BFS searches + limit : typing.Optional[int] + Page size - center_node_uuid : typing.Optional[str] - Node to rerank around for node distance reranking + cursor : typing.Optional[str] + Opaque page cursor - graph_id : typing.Optional[str] - The graph_id to search in. When searching user graph, please use user_id instead. + bfs_origin_node_uuids : typing.Optional[typing.Sequence[str]] - limit : typing.Optional[int] - The maximum number of facts to retrieve for non-auto scopes. Defaults to 10. Limited to 50. Ignored when scope=auto. + center_node_uuid : typing.Optional[str] - max_characters : typing.Optional[int] - Maximum total characters across all selected results when scope=auto. Defaults to 2500. Limited to 50000. + filters : typing.Optional[typing.Dict[str, typing.Any]] mmr_lambda : typing.Optional[float] - weighting for maximal marginal relevance - - reranker : typing.Optional[Reranker] - Defaults to RRF. Ignored when scope=auto except node_distance and episode_mentions are rejected; - auto search always uses RRF retrieval and applies its own internal rerank after retrieval. - episode_mentions ranks edge candidates by how many of the episodes listed - in search_filters.episode_uuids mention them; without episode_uuids it has - no effect and results are ranked as if no reranker were specified. - return_raw_results : typing.Optional[bool] - When scope=auto, include the selected raw graph results alongside the materialized context block. - For graph-service-backed auto mode, selected raw results may include episodes, - edges, nodes, observations, and thread_summaries. - - scope : typing.Optional[GraphSearchScope] - Defaults to Edges. + query : typing.Optional[str] - search_filters : typing.Optional[SearchFilters] - Search filters to apply to the search + reranker : typing.Optional[str] - user_id : typing.Optional[str] - The user_id when searching user graph. If not searching user graph, please use graph_id instead. + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - GraphSearchResults - Graph search results or auto-context block + SyncPager[JsonObject, JsonObjectPage] + OK Examples -------- @@ -952,85 +752,79 @@ def search( client = Zep( api_key="YOUR_API_KEY", ) - client.graph.search( - query="query", + response = client.graph.search_edges( + graph_uuid="graph_uuid", + limit=1, + cursor="cursor", ) + for item in response: + yield item + # alternatively, you can paginate page-by-page + for page in response.iter_pages(): + yield page """ - _response = self._raw_client.search( - query=query, + return self._raw_client.search_edges( + graph_uuid, + limit=limit, + cursor=cursor, bfs_origin_node_uuids=bfs_origin_node_uuids, center_node_uuid=center_node_uuid, - graph_id=graph_id, - limit=limit, - max_characters=max_characters, + filters=filters, mmr_lambda=mmr_lambda, + query=query, reranker=reranker, - return_raw_results=return_raw_results, - scope=scope, - search_filters=search_filters, - user_id=user_id, + idempotency_key=idempotency_key, request_options=request_options, ) - return _response.data - def get_subgraph( + def search_episodes( self, + graph_uuid: str, *, - seed_node_uuids: typing.Sequence[str], - depth: typing.Optional[int] = OMIT, - direction: typing.Optional[str] = OMIT, - graph_id: typing.Optional[str] = OMIT, - max_edges: typing.Optional[int] = OMIT, - max_nodes: typing.Optional[int] = OMIT, - search_filters: typing.Optional[SearchFilters] = OMIT, - user_id: typing.Optional[str] = OMIT, + limit: typing.Optional[int] = None, + cursor: typing.Optional[str] = None, + bfs_origin_node_uuids: typing.Optional[typing.Sequence[str]] = OMIT, + center_node_uuid: typing.Optional[str] = OMIT, + filters: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + mmr_lambda: typing.Optional[float] = OMIT, + query: typing.Optional[str] = OMIT, + reranker: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> GraphSubgraphResponse: + ) -> SyncPager[JsonObject, JsonObjectPage]: """ - Returns the bounded neighborhood of a set of seed nodes as a single {nodes, edges} payload: breadth-first expansion up to a caller-specified depth, subject to explicit budgets, with explicit truncation reporting. - Parameters ---------- - seed_node_uuids : typing.Sequence[str] - Seed node UUIDs to expand from, in traversal-priority order: seeds are - admitted before any expansion, in this order, and count toward - max_nodes first. 1-20 entries, required. Seeds that do not exist in - the target graph are ignored, not an error. + graph_uuid : str + Graph UUID - depth : typing.Optional[int] - Maximum traversal depth from the seeds. 1-3. Defaults to 1. + limit : typing.Optional[int] + Page size - direction : typing.Optional[str] - Edge orientation followed during expansion, relative to each frontier - node: "in" | "out" | "both". Defaults to "both". + cursor : typing.Optional[str] + Opaque page cursor - graph_id : typing.Optional[str] - graph_id identifies the target named graph. Exactly one of user_id or - graph_id is required. + bfs_origin_node_uuids : typing.Optional[typing.Sequence[str]] - max_edges : typing.Optional[int] - Maximum number of edges in the response. 1-1000. Defaults to 200. + center_node_uuid : typing.Optional[str] - max_nodes : typing.Optional[int] - Maximum number of nodes in the response, including admitted seeds. - 1-500. Defaults to 100. + filters : typing.Optional[typing.Dict[str, typing.Any]] - 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). + mmr_lambda : typing.Optional[float] - user_id : typing.Optional[str] - user_id identifies the target user graph. Exactly one of user_id or - graph_id is required. + query : typing.Optional[str] + + reranker : typing.Optional[str] + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - GraphSubgraphResponse - Subgraph + SyncPager[JsonObject, JsonObjectPage] + OK Examples -------- @@ -1039,39 +833,79 @@ def get_subgraph( client = Zep( api_key="YOUR_API_KEY", ) - client.graph.get_subgraph( - seed_node_uuids=["seed_node_uuids"], + response = client.graph.search_episodes( + graph_uuid="graph_uuid", + limit=1, + cursor="cursor", ) + for item in response: + yield item + # alternatively, you can paginate page-by-page + for page in response.iter_pages(): + yield page """ - _response = self._raw_client.get_subgraph( - seed_node_uuids=seed_node_uuids, - depth=depth, - direction=direction, - graph_id=graph_id, - max_edges=max_edges, - max_nodes=max_nodes, - search_filters=search_filters, - user_id=user_id, + return self._raw_client.search_episodes( + graph_uuid, + limit=limit, + cursor=cursor, + bfs_origin_node_uuids=bfs_origin_node_uuids, + center_node_uuid=center_node_uuid, + filters=filters, + mmr_lambda=mmr_lambda, + query=query, + reranker=reranker, + idempotency_key=idempotency_key, request_options=request_options, ) - return _response.data - def get(self, graph_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> Graph: + def search_nodes( + self, + graph_uuid: str, + *, + limit: typing.Optional[int] = None, + cursor: typing.Optional[str] = None, + bfs_origin_node_uuids: typing.Optional[typing.Sequence[str]] = OMIT, + center_node_uuid: typing.Optional[str] = OMIT, + filters: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + mmr_lambda: typing.Optional[float] = OMIT, + query: typing.Optional[str] = OMIT, + reranker: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> SyncPager[JsonObject, JsonObjectPage]: """ - Returns a graph. - Parameters ---------- - graph_id : str - The graph_id of the graph to get. + graph_uuid : str + Graph UUID + + limit : typing.Optional[int] + Page size + + cursor : typing.Optional[str] + Opaque page cursor + + bfs_origin_node_uuids : typing.Optional[typing.Sequence[str]] + + center_node_uuid : typing.Optional[str] + + filters : typing.Optional[typing.Dict[str, typing.Any]] + + mmr_lambda : typing.Optional[float] + + query : typing.Optional[str] + + reranker : typing.Optional[str] + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - Graph - The graph that was retrieved. + SyncPager[JsonObject, JsonObjectPage] + OK Examples -------- @@ -1080,29 +914,79 @@ def get(self, graph_id: str, *, request_options: typing.Optional[RequestOptions] client = Zep( api_key="YOUR_API_KEY", ) - client.graph.get( - graph_id="graphId", + response = client.graph.search_nodes( + graph_uuid="graph_uuid", + limit=1, + cursor="cursor", ) + for item in response: + yield item + # alternatively, you can paginate page-by-page + for page in response.iter_pages(): + yield page """ - _response = self._raw_client.get(graph_id, request_options=request_options) - return _response.data + return self._raw_client.search_nodes( + graph_uuid, + limit=limit, + cursor=cursor, + bfs_origin_node_uuids=bfs_origin_node_uuids, + center_node_uuid=center_node_uuid, + filters=filters, + mmr_lambda=mmr_lambda, + query=query, + reranker=reranker, + idempotency_key=idempotency_key, + request_options=request_options, + ) - def delete(self, graph_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> SuccessResponse: + def search_observations( + self, + graph_uuid: str, + *, + limit: typing.Optional[int] = None, + cursor: typing.Optional[str] = None, + bfs_origin_node_uuids: typing.Optional[typing.Sequence[str]] = OMIT, + center_node_uuid: typing.Optional[str] = OMIT, + filters: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + mmr_lambda: typing.Optional[float] = OMIT, + query: typing.Optional[str] = OMIT, + reranker: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> SyncPager[JsonObject, JsonObjectPage]: """ - Deletes a graph. If you would like to delete a user graph, make sure to use user.delete instead. - Parameters ---------- - graph_id : str - Graph ID + graph_uuid : str + Graph UUID + + limit : typing.Optional[int] + Page size + + cursor : typing.Optional[str] + Opaque page cursor + + bfs_origin_node_uuids : typing.Optional[typing.Sequence[str]] + + center_node_uuid : typing.Optional[str] + + filters : typing.Optional[typing.Dict[str, typing.Any]] + + mmr_lambda : typing.Optional[float] + + query : typing.Optional[str] + + reranker : typing.Optional[str] + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - SuccessResponse - Deleted + SyncPager[JsonObject, JsonObjectPage] + OK Examples -------- @@ -1111,44 +995,152 @@ def delete(self, graph_id: str, *, request_options: typing.Optional[RequestOptio client = Zep( api_key="YOUR_API_KEY", ) - client.graph.delete( - graph_id="graphId", + response = client.graph.search_observations( + graph_uuid="graph_uuid", + limit=1, + cursor="cursor", ) + for item in response: + yield item + # alternatively, you can paginate page-by-page + for page in response.iter_pages(): + yield page """ - _response = self._raw_client.delete(graph_id, request_options=request_options) - return _response.data + return self._raw_client.search_observations( + graph_uuid, + limit=limit, + cursor=cursor, + bfs_origin_node_uuids=bfs_origin_node_uuids, + center_node_uuid=center_node_uuid, + filters=filters, + mmr_lambda=mmr_lambda, + query=query, + reranker=reranker, + idempotency_key=idempotency_key, + request_options=request_options, + ) - def update( + def search_thread_summaries( self, - graph_id: str, + graph_uuid: str, *, - description: typing.Optional[str] = OMIT, - name: typing.Optional[str] = OMIT, - time_zone: typing.Optional[str] = OMIT, + limit: typing.Optional[int] = None, + cursor: typing.Optional[str] = None, + bfs_origin_node_uuids: typing.Optional[typing.Sequence[str]] = OMIT, + center_node_uuid: typing.Optional[str] = OMIT, + filters: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + mmr_lambda: typing.Optional[float] = OMIT, + query: typing.Optional[str] = OMIT, + reranker: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> Graph: + ) -> SyncPager[JsonObject, JsonObjectPage]: """ - Updates information about a graph. + Parameters + ---------- + graph_uuid : str + Graph UUID + + limit : typing.Optional[int] + Page size + + cursor : typing.Optional[str] + Opaque page cursor + + bfs_origin_node_uuids : typing.Optional[typing.Sequence[str]] + + center_node_uuid : typing.Optional[str] + + filters : typing.Optional[typing.Dict[str, typing.Any]] + + mmr_lambda : typing.Optional[float] + + query : typing.Optional[str] + + reranker : typing.Optional[str] + + idempotency_key : typing.Optional[str] + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + SyncPager[JsonObject, JsonObjectPage] + OK + Examples + -------- + from zep_cloud import Zep + + client = Zep( + api_key="YOUR_API_KEY", + ) + response = client.graph.search_thread_summaries( + graph_uuid="graph_uuid", + limit=1, + cursor="cursor", + ) + for item in response: + yield item + # alternatively, you can paginate page-by-page + for page in response.iter_pages(): + yield page + """ + return self._raw_client.search_thread_summaries( + graph_uuid, + limit=limit, + cursor=cursor, + bfs_origin_node_uuids=bfs_origin_node_uuids, + center_node_uuid=center_node_uuid, + filters=filters, + mmr_lambda=mmr_lambda, + query=query, + reranker=reranker, + idempotency_key=idempotency_key, + request_options=request_options, + ) + + def get_subgraph( + self, + graph_uuid: str, + *, + depth: typing.Optional[int] = OMIT, + direction: typing.Optional[str] = OMIT, + filters: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + max_edges: typing.Optional[int] = OMIT, + max_nodes: typing.Optional[int] = OMIT, + seed_node_uuids: typing.Optional[typing.Sequence[str]] = OMIT, + idempotency_key: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> JsonObject: + """ Parameters ---------- - graph_id : str - Graph ID + graph_uuid : str + Graph UUID - description : typing.Optional[str] + depth : typing.Optional[int] - name : typing.Optional[str] + direction : typing.Optional[str] - time_zone : typing.Optional[str] - The graph's IANA time zone. Stored on its group-backed subject. + filters : typing.Optional[typing.Dict[str, typing.Any]] + + max_edges : typing.Optional[int] + + max_nodes : typing.Optional[int] + + seed_node_uuids : typing.Optional[typing.Sequence[str]] + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - Graph - The updated graph object + JsonObject + OK Examples -------- @@ -1157,31 +1149,45 @@ def update( client = Zep( api_key="YOUR_API_KEY", ) - client.graph.update( - graph_id="graphId", + client.graph.get_subgraph( + graph_uuid="graph_uuid", ) """ - _response = self._raw_client.update( - graph_id, description=description, name=name, time_zone=time_zone, request_options=request_options + _response = self._raw_client.get_subgraph( + graph_uuid, + depth=depth, + direction=direction, + filters=filters, + max_edges=max_edges, + max_nodes=max_nodes, + seed_node_uuids=seed_node_uuids, + idempotency_key=idempotency_key, + request_options=request_options, ) return _response.data - def warm(self, graph_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> SuccessResponse: + def warm( + self, + graph_uuid: str, + *, + idempotency_key: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncResult: """ - Hints Zep to warm a graph for low-latency search - Parameters ---------- - graph_id : str - The graph_id of the graph to warm. + graph_uuid : str + Graph UUID + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - SuccessResponse - Warm hint accepted + AsyncResult + Accepted Examples -------- @@ -1191,25 +1197,71 @@ def warm(self, graph_id: str, *, request_options: typing.Optional[RequestOptions api_key="YOUR_API_KEY", ) client.graph.warm( - graph_id="graphId", + graph_uuid="graph_uuid", ) """ - _response = self._raw_client.warm(graph_id, request_options=request_options) + _response = self._raw_client.warm(graph_uuid, idempotency_key=idempotency_key, request_options=request_options) return _response.data + @property + def document_summary(self): + if self._document_summary is None: + from .document_summary.client import DocumentSummaryClient # noqa: E402 -class AsyncGraphClient: - def __init__(self, *, client_wrapper: AsyncClientWrapper): - self._raw_client = AsyncRawGraphClient(client_wrapper=client_wrapper) - self.edge = AsyncEdgeClient(client_wrapper=client_wrapper) + self._document_summary = DocumentSummaryClient(client_wrapper=self._client_wrapper) + return self._document_summary + + @property + def episode(self): + if self._episode is None: + from .episode.client import EpisodeClient # noqa: E402 + + self._episode = EpisodeClient(client_wrapper=self._client_wrapper) + return self._episode + + @property + def edge(self): + if self._edge is None: + from .edge.client import EdgeClient # noqa: E402 + + self._edge = EdgeClient(client_wrapper=self._client_wrapper) + return self._edge + + @property + def node(self): + if self._node is None: + from .node.client import NodeClient # noqa: E402 + + self._node = NodeClient(client_wrapper=self._client_wrapper) + return self._node + + @property + def observation(self): + if self._observation is None: + from .observation.client import ObservationClient # noqa: E402 + + self._observation = ObservationClient(client_wrapper=self._client_wrapper) + return self._observation - self.episode = AsyncEpisodeClient(client_wrapper=client_wrapper) + @property + def thread_summary(self): + if self._thread_summary is None: + from .thread_summary.client import ThreadSummaryClient # noqa: E402 - self.node = AsyncNodeClient(client_wrapper=client_wrapper) + self._thread_summary = ThreadSummaryClient(client_wrapper=self._client_wrapper) + return self._thread_summary - self.observation = AsyncObservationClient(client_wrapper=client_wrapper) - self.thread_summary = AsyncThreadSummaryClient(client_wrapper=client_wrapper) +class AsyncGraphClient: + def __init__(self, *, client_wrapper: AsyncClientWrapper): + self._raw_client = AsyncRawGraphClient(client_wrapper=client_wrapper) + self._client_wrapper = client_wrapper + self._document_summary: typing.Optional[AsyncDocumentSummaryClient] = None + self._episode: typing.Optional[AsyncEpisodeClient] = None + self._edge: typing.Optional[AsyncEdgeClient] = None + self._node: typing.Optional[AsyncNodeClient] = None + self._observation: typing.Optional[AsyncObservationClient] = None + self._thread_summary: typing.Optional[AsyncThreadSummaryClient] = None @property def with_raw_response(self) -> AsyncRawGraphClient: @@ -1222,31 +1274,36 @@ def with_raw_response(self) -> AsyncRawGraphClient: """ return self._raw_client - async def list_custom_instructions( + async def create( self, *, - user_id: typing.Optional[str] = None, - graph_id: typing.Optional[str] = None, + description: typing.Optional[str] = OMIT, + graph_id: typing.Optional[str] = OMIT, + name: typing.Optional[str] = OMIT, + time_zone: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> ListCustomInstructionsResponse: + ) -> Graph: """ - Lists all custom instructions for a project, user, or graph. - Parameters ---------- - user_id : typing.Optional[str] - User ID to get user-specific instructions + description : typing.Optional[str] graph_id : typing.Optional[str] - Graph ID to get graph-specific instructions + + name : typing.Optional[str] + + time_zone : typing.Optional[str] + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - ListCustomInstructionsResponse - The list of instructions. + Graph + Created Examples -------- @@ -1260,54 +1317,64 @@ async def list_custom_instructions( async def main() -> None: - await client.graph.list_custom_instructions( - user_id="user_id", - graph_id="graph_id", - ) + await client.graph.create() asyncio.run(main()) """ - _response = await self._raw_client.list_custom_instructions( - user_id=user_id, graph_id=graph_id, request_options=request_options + _response = await self._raw_client.create( + description=description, + graph_id=graph_id, + name=name, + time_zone=time_zone, + idempotency_key=idempotency_key, + request_options=request_options, ) return _response.data - async def add_custom_instructions( + async def list( self, *, - instructions: typing.Sequence[CustomInstruction], - graph_ids: typing.Optional[typing.Sequence[str]] = OMIT, - user_ids: typing.Optional[typing.Sequence[str]] = OMIT, + limit: typing.Optional[int] = None, + cursor: typing.Optional[str] = None, + order_by: typing.Optional[str] = None, + order: typing.Optional[str] = None, + search: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> SuccessResponse: + ) -> AsyncPager[Graph, GraphPage]: """ - Adds new custom instructions for graphs without removing existing ones. If user_ids or graph_ids is empty, adds to project-wide default instructions. - Parameters ---------- - instructions : typing.Sequence[CustomInstruction] - Instructions to add to the graph. + limit : typing.Optional[int] + Page size + + cursor : typing.Optional[str] + Opaque page cursor + + order_by : typing.Optional[str] + Sort field + + order : typing.Optional[str] + asc or desc - graph_ids : typing.Optional[typing.Sequence[str]] - Graph IDs to add the instructions to. If empty, the instructions are added to the project-wide default. + search : typing.Optional[str] - user_ids : typing.Optional[typing.Sequence[str]] - User IDs to add the instructions to. If empty, the instructions are added to the project-wide default. + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - SuccessResponse - Instructions added successfully + AsyncPager[Graph, GraphPage] + OK Examples -------- import asyncio - from zep_cloud import AsyncZep, CustomInstruction + from zep_cloud import AsyncZep client = AsyncZep( api_key="YOUR_API_KEY", @@ -1315,52 +1382,59 @@ async def add_custom_instructions( async def main() -> None: - await client.graph.add_custom_instructions( - instructions=[ - CustomInstruction( - name="name", - text="text", - ) - ], + response = await client.graph.list( + limit=1, + cursor="cursor", + order_by="order_by", + order="order", ) + async for item in response: + yield item + + # alternatively, you can paginate page-by-page + async for page in response.iter_pages(): + yield page asyncio.run(main()) """ - _response = await self._raw_client.add_custom_instructions( - instructions=instructions, graph_ids=graph_ids, user_ids=user_ids, request_options=request_options + return await self._raw_client.list( + limit=limit, + cursor=cursor, + order_by=order_by, + order=order, + search=search, + idempotency_key=idempotency_key, + request_options=request_options, ) - return _response.data - async def delete_custom_instructions( + async def lookup( self, *, - graph_ids: typing.Optional[typing.Sequence[str]] = OMIT, - instruction_names: typing.Optional[typing.Sequence[str]] = OMIT, - user_ids: typing.Optional[typing.Sequence[str]] = OMIT, + graph_id: typing.Optional[str] = OMIT, + thread_id: typing.Optional[str] = OMIT, + user_id: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> SuccessResponse: + ) -> Graph: """ - Deletes custom instructions for graphs or project wide defaults. - Parameters ---------- - graph_ids : typing.Optional[typing.Sequence[str]] - Determines which group graphs will have their custom instructions deleted. If no graphs are provided, the project-wide custom instructions will be affected. + graph_id : typing.Optional[str] + + thread_id : typing.Optional[str] - instruction_names : typing.Optional[typing.Sequence[str]] - Unique identifier for the instructions to be deleted. If empty deletes all instructions. + user_id : typing.Optional[str] - user_ids : typing.Optional[typing.Sequence[str]] - Determines which user graphs will have their custom instructions deleted. If no users are provided, the project-wide custom instructions will be affected. + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - SuccessResponse - Instructions deleted successfully + Graph + OK Examples -------- @@ -1374,41 +1448,34 @@ async def delete_custom_instructions( async def main() -> None: - await client.graph.delete_custom_instructions() + await client.graph.lookup() asyncio.run(main()) """ - _response = await self._raw_client.delete_custom_instructions( - graph_ids=graph_ids, instruction_names=instruction_names, user_ids=user_ids, request_options=request_options + _response = await self._raw_client.lookup( + graph_id=graph_id, + thread_id=thread_id, + user_id=user_id, + idempotency_key=idempotency_key, + request_options=request_options, ) return _response.data - async def list_entity_types( - self, - *, - user_id: typing.Optional[str] = None, - graph_id: typing.Optional[str] = None, - request_options: typing.Optional[RequestOptions] = None, - ) -> EntityTypeResponse: + async def get(self, graph_uuid: str, *, request_options: typing.Optional[RequestOptions] = None) -> Graph: """ - Returns all entity types for a project, user, or graph. - Parameters ---------- - user_id : typing.Optional[str] - User ID to get user-specific entity types - - graph_id : typing.Optional[str] - Graph ID to get graph-specific entity types + graph_uuid : str + Graph UUID request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - EntityTypeResponse - The list of entity types. + Graph + OK Examples -------- @@ -1422,48 +1489,38 @@ async def list_entity_types( async def main() -> None: - await client.graph.list_entity_types( - user_id="user_id", - graph_id="graph_id", + await client.graph.get( + graph_uuid="graph_uuid", ) asyncio.run(main()) """ - _response = await self._raw_client.list_entity_types( - user_id=user_id, graph_id=graph_id, request_options=request_options - ) + _response = await self._raw_client.get(graph_uuid, request_options=request_options) return _response.data - async def set_entity_types_internal( + async def delete( self, + graph_uuid: str, *, - edge_types: typing.Optional[typing.Sequence[EdgeType]] = OMIT, - entity_types: typing.Optional[typing.Sequence[EntityType]] = OMIT, - graph_ids: typing.Optional[typing.Sequence[str]] = OMIT, - user_ids: typing.Optional[typing.Sequence[str]] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> SuccessResponse: + ) -> GraphDeleteResult: """ - Sets the entity types for multiple users and graphs, replacing any existing ones. - Parameters ---------- - edge_types : typing.Optional[typing.Sequence[EdgeType]] - - entity_types : typing.Optional[typing.Sequence[EntityType]] + graph_uuid : str + Graph UUID - graph_ids : typing.Optional[typing.Sequence[str]] - - user_ids : typing.Optional[typing.Sequence[str]] + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - SuccessResponse - Entity types set successfully + GraphDeleteResult + Accepted Examples -------- @@ -1477,65 +1534,52 @@ async def set_entity_types_internal( async def main() -> None: - await client.graph.set_entity_types_internal() + await client.graph.delete( + graph_uuid="graph_uuid", + ) asyncio.run(main()) """ - _response = await self._raw_client.set_entity_types_internal( - edge_types=edge_types, - entity_types=entity_types, - graph_ids=graph_ids, - user_ids=user_ids, - request_options=request_options, + _response = await self._raw_client.delete( + graph_uuid, idempotency_key=idempotency_key, request_options=request_options ) return _response.data - async def add( + async def update( self, + graph_uuid: str, *, - data: str, - type: GraphDataType, - created_at: 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, - strict_ontology: typing.Optional[bool] = OMIT, - user_id: typing.Optional[str] = OMIT, + description: typing.Optional[str] = OMIT, + name: typing.Optional[str] = OMIT, + time_zone: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> Episode: + ) -> Graph: """ - Add data to the graph. - Parameters ---------- - data : str + graph_uuid : str + Graph UUID - type : GraphDataType - - created_at : typing.Optional[str] - - 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. - - metadata : typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] - Optional metadata key-value pairs. Max 10 keys. Values must be strings, numbers, booleans, or arrays of scalars. + description : typing.Optional[str] + Omit to leave unchanged, send JSON null to clear, or send a value to set. - source_description : typing.Optional[str] + name : typing.Optional[str] + Omit to leave unchanged, send JSON null to clear, or send a value to set. - strict_ontology : typing.Optional[bool] - When true, prevents extraction of generic Entity nodes that do not match the configured ontology. + time_zone : typing.Optional[str] + Omit to leave unchanged, send JSON null to clear, or send a value to set. - user_id : typing.Optional[str] - User ID is the ID of the user to which the data will be added. If not adding to a user graph, please use graph_id field instead. + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - Episode - Added episode + Graph + OK Examples -------- @@ -1549,67 +1593,54 @@ async def add( async def main() -> None: - await client.graph.add( - data="data", - type="text", + await client.graph.update( + graph_uuid="graph_uuid", ) asyncio.run(main()) """ - _response = await self._raw_client.add( - data=data, - type=type, - created_at=created_at, - graph_id=graph_id, - metadata=metadata, - source_description=source_description, - strict_ontology=strict_ontology, - user_id=user_id, + _response = await self._raw_client.update( + graph_uuid, + description=description, + name=name, + time_zone=time_zone, + idempotency_key=idempotency_key, request_options=request_options, ) return _response.data - async def add_batch( + async def clone( self, + graph_uuid: str, *, - episodes: typing.Sequence[EpisodeData], - graph_id: typing.Optional[str] = OMIT, - strict_ontology: typing.Optional[bool] = OMIT, - user_id: typing.Optional[str] = OMIT, + target_graph_id: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> typing.List[Episode]: + ) -> CloneGraphResult: """ - Deprecated. Use the [Batch API](/adding-batch-data) (`client.batch.*`) instead. - - Adds data to the graph in batch mode, processing episodes concurrently. - Parameters ---------- - episodes : typing.Sequence[EpisodeData] - - 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. + graph_uuid : str + Graph UUID - strict_ontology : typing.Optional[bool] - When true, prevents extraction of generic Entity nodes that do not match the configured ontology. + target_graph_id : typing.Optional[str] - user_id : typing.Optional[str] - User ID is the ID of the user to which the data will be added. If not adding to a user graph, please use graph_id field instead. + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - typing.List[Episode] - Added episodes + CloneGraphResult + Accepted Examples -------- import asyncio - from zep_cloud import AsyncZep, EpisodeData + from zep_cloud import AsyncZep client = AsyncZep( api_key="YOUR_API_KEY", @@ -1617,134 +1648,110 @@ async def add_batch( async def main() -> None: - await client.graph.add_batch( - episodes=[ - EpisodeData( - data="data", - type="text", - ) - ], + await client.graph.clone( + graph_uuid="graph_uuid", ) asyncio.run(main()) """ - _response = await self._raw_client.add_batch( - episodes=episodes, - graph_id=graph_id, - strict_ontology=strict_ontology, - user_id=user_id, + _response = await self._raw_client.clone( + graph_uuid, + target_graph_id=target_graph_id, + idempotency_key=idempotency_key, request_options=request_options, ) return _response.data - async def add_fact_triple( + async def get_context( self, + graph_uuid: str, *, - fact: str, - fact_name: str, - created_at: typing.Optional[str] = OMIT, - edge_attributes: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = OMIT, - expired_at: typing.Optional[str] = OMIT, - graph_id: typing.Optional[str] = OMIT, - invalid_at: typing.Optional[str] = OMIT, - metadata: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = OMIT, - source_node_attributes: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = OMIT, - source_node_labels: typing.Optional[typing.Sequence[str]] = OMIT, - source_node_name: typing.Optional[str] = OMIT, - source_node_summary: typing.Optional[str] = OMIT, - source_node_uuid: typing.Optional[str] = OMIT, - target_node_attributes: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = OMIT, - target_node_labels: typing.Optional[typing.Sequence[str]] = OMIT, - target_node_name: typing.Optional[str] = OMIT, - target_node_summary: typing.Optional[str] = OMIT, - target_node_uuid: typing.Optional[str] = OMIT, - user_id: typing.Optional[str] = OMIT, - valid_at: typing.Optional[str] = OMIT, + filters: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + include_results: typing.Optional[bool] = OMIT, + max_characters: typing.Optional[int] = OMIT, + query: typing.Optional[str] = OMIT, + recency_bias: typing.Optional[str] = OMIT, + template_uuid: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> AddTripleResponse: + ) -> GraphContextResponse: """ - Add a fact triple for a user or group - Parameters ---------- - fact : str - The fact relating the two nodes that this edge represents - - fact_name : str - The name of the edge to add. Should be all caps using snake case (eg RELATES_TO) + graph_uuid : str + Graph UUID - created_at : typing.Optional[str] - The timestamp of the message + filters : typing.Optional[typing.Dict[str, typing.Any]] - edge_attributes : typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] - Additional attributes of the edge. Values must be scalar types (string, number, boolean, or null). - Nested objects and arrays are not allowed. + include_results : typing.Optional[bool] - expired_at : typing.Optional[str] - The time (if any) at which the edge expires - - graph_id : typing.Optional[str] + max_characters : typing.Optional[int] - invalid_at : typing.Optional[str] - The time (if any) at which the fact stops being true + query : typing.Optional[str] - metadata : typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] - Optional metadata key-value pairs for the shadow episode created for this fact triple. - Max 10 keys. Values must be strings, numbers, or booleans. + recency_bias : typing.Optional[str] - source_node_attributes : typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] - Additional attributes of the source node. Values must be scalar types (string, number, boolean, or null). - Nested objects and arrays are not allowed. + template_uuid : typing.Optional[str] - source_node_labels : typing.Optional[typing.Sequence[str]] - The labels for the source node. At most one entity-type label may be - provided so that manually-added triples remain consistent with automatic - episode extraction, which assigns one best-match entity type per node. - The base "Entity" label is added implicitly by the graph layer on save - and does not need to be supplied here. + idempotency_key : typing.Optional[str] - source_node_name : typing.Optional[str] - The name of the source node to add + request_options : typing.Optional[RequestOptions] + Request-specific configuration. - source_node_summary : typing.Optional[str] - The summary of the source node to add + Returns + ------- + GraphContextResponse + OK - source_node_uuid : typing.Optional[str] - The source node uuid + Examples + -------- + import asyncio - target_node_attributes : typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] - Additional attributes of the target node. Values must be scalar types (string, number, boolean, or null). - Nested objects and arrays are not allowed. + from zep_cloud import AsyncZep - target_node_labels : typing.Optional[typing.Sequence[str]] - The labels for the target node. At most one entity-type label may be - provided so that manually-added triples remain consistent with automatic - episode extraction, which assigns one best-match entity type per node. - The base "Entity" label is added implicitly by the graph layer on save - and does not need to be supplied here. + client = AsyncZep( + api_key="YOUR_API_KEY", + ) - target_node_name : typing.Optional[str] - The name of the target node to add - target_node_summary : typing.Optional[str] - The summary of the target node to add + async def main() -> None: + await client.graph.get_context( + graph_uuid="graph_uuid", + ) - target_node_uuid : typing.Optional[str] - The target node uuid - user_id : typing.Optional[str] + asyncio.run(main()) + """ + _response = await self._raw_client.get_context( + graph_uuid, + filters=filters, + include_results=include_results, + max_characters=max_characters, + query=query, + recency_bias=recency_bias, + template_uuid=template_uuid, + idempotency_key=idempotency_key, + request_options=request_options, + ) + return _response.data - valid_at : typing.Optional[str] - The time at which the fact becomes true + async def get_instructions( + self, graph_uuid: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> Instructions: + """ + Parameters + ---------- + graph_uuid : str + Graph UUID request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - AddTripleResponse - Resulting triple + Instructions + OK Examples -------- @@ -1758,72 +1765,44 @@ async def add_fact_triple( async def main() -> None: - await client.graph.add_fact_triple( - fact="fact", - fact_name="fact_name", + await client.graph.get_instructions( + graph_uuid="graph_uuid", ) asyncio.run(main()) """ - _response = await self._raw_client.add_fact_triple( - fact=fact, - fact_name=fact_name, - created_at=created_at, - edge_attributes=edge_attributes, - expired_at=expired_at, - graph_id=graph_id, - invalid_at=invalid_at, - metadata=metadata, - source_node_attributes=source_node_attributes, - source_node_labels=source_node_labels, - source_node_name=source_node_name, - source_node_summary=source_node_summary, - source_node_uuid=source_node_uuid, - target_node_attributes=target_node_attributes, - target_node_labels=target_node_labels, - target_node_name=target_node_name, - target_node_summary=target_node_summary, - target_node_uuid=target_node_uuid, - user_id=user_id, - valid_at=valid_at, - request_options=request_options, - ) + _response = await self._raw_client.get_instructions(graph_uuid, request_options=request_options) return _response.data - async def clone( + async def set_instructions( self, + graph_uuid: str, *, - source_graph_id: typing.Optional[str] = OMIT, - source_user_id: typing.Optional[str] = OMIT, - target_graph_id: typing.Optional[str] = OMIT, - target_user_id: typing.Optional[str] = OMIT, + inherited: typing.Optional[bool] = OMIT, + instructions: typing.Optional[typing.Sequence[typing.Dict[str, typing.Any]]] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> CloneGraphResponse: + ) -> Instructions: """ - Clone a user or group graph. - Parameters ---------- - source_graph_id : typing.Optional[str] - source_graph_id is the ID of the graph to be cloned. Required if source_user_id is not provided + graph_uuid : str + Graph UUID - source_user_id : typing.Optional[str] - user_id of the user whose graph is being cloned. Required if source_graph_id is not provided + inherited : typing.Optional[bool] - target_graph_id : typing.Optional[str] - target_graph_id is the ID to be set on the cloned graph. Must not point to an existing graph. Required if target_user_id is not provided. + instructions : typing.Optional[typing.Sequence[typing.Dict[str, typing.Any]]] - target_user_id : typing.Optional[str] - user_id to be set on the cloned user. Must not point to an existing user. Required if target_graph_id is not provided. + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - CloneGraphResponse - Response object containing graph_id or user_id pointing to the new graph + Instructions + OK Examples -------- @@ -1837,50 +1816,92 @@ async def clone( async def main() -> None: - await client.graph.clone() + await client.graph.set_instructions( + graph_uuid="graph_uuid", + ) asyncio.run(main()) """ - _response = await self._raw_client.clone( - source_graph_id=source_graph_id, - source_user_id=source_user_id, - target_graph_id=target_graph_id, - target_user_id=target_user_id, + _response = await self._raw_client.set_instructions( + graph_uuid, + inherited=inherited, + instructions=instructions, + idempotency_key=idempotency_key, request_options=request_options, ) return _response.data - async def create( + async def get_observation_steering( + self, graph_uuid: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> ObservationSteering: + """ + Parameters + ---------- + graph_uuid : str + Graph UUID + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + ObservationSteering + OK + + Examples + -------- + import asyncio + + from zep_cloud import AsyncZep + + client = AsyncZep( + api_key="YOUR_API_KEY", + ) + + + async def main() -> None: + await client.graph.get_observation_steering( + graph_uuid="graph_uuid", + ) + + + asyncio.run(main()) + """ + _response = await self._raw_client.get_observation_steering(graph_uuid, request_options=request_options) + return _response.data + + async def set_observation_steering( self, + graph_uuid: str, *, - graph_id: str, - description: typing.Optional[str] = OMIT, - name: typing.Optional[str] = OMIT, - time_zone: typing.Optional[str] = OMIT, + inherited: typing.Optional[bool] = OMIT, + instruction: typing.Optional[str] = OMIT, + types: typing.Optional[typing.Sequence[typing.Dict[str, typing.Any]]] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> Graph: + ) -> ObservationSteering: """ - Creates a new graph. - Parameters ---------- - graph_id : str + graph_uuid : str + Graph UUID - description : typing.Optional[str] + inherited : typing.Optional[bool] - name : typing.Optional[str] + instruction : typing.Optional[str] - time_zone : typing.Optional[str] - The graph's IANA time zone. Stored on its group-backed subject. + types : typing.Optional[typing.Sequence[typing.Dict[str, typing.Any]]] + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - Graph - The added graph + ObservationSteering + OK Examples -------- @@ -1894,55 +1915,39 @@ async def create( async def main() -> None: - await client.graph.create( - graph_id="graph_id", + await client.graph.set_observation_steering( + graph_uuid="graph_uuid", ) asyncio.run(main()) """ - _response = await self._raw_client.create( - graph_id=graph_id, description=description, name=name, time_zone=time_zone, request_options=request_options + _response = await self._raw_client.set_observation_steering( + graph_uuid, + inherited=inherited, + instruction=instruction, + types=types, + idempotency_key=idempotency_key, + request_options=request_options, ) return _response.data - async def list_all( - self, - *, - page_number: typing.Optional[int] = None, - page_size: typing.Optional[int] = None, - search: typing.Optional[str] = None, - order_by: typing.Optional[str] = None, - asc: typing.Optional[bool] = None, - request_options: typing.Optional[RequestOptions] = None, - ) -> GraphListResponse: + async def get_ontology( + self, graph_uuid: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> Ontology: """ - Returns all graphs. In order to list users, use user.list_ordered instead - Parameters ---------- - page_number : typing.Optional[int] - Page number for pagination, starting from 1. - - page_size : typing.Optional[int] - Number of graphs to retrieve per page (default 50, range 1-100; explicit 0 is invalid). - - search : typing.Optional[str] - Search term for filtering graphs by graph_id, name, or description. Queries longer than 200 Unicode code points after whitespace normalization are invalid. - - order_by : typing.Optional[str] - Column to sort by (created_at, graph_id, name). - - asc : typing.Optional[bool] - Sort in ascending order. + graph_uuid : str + Graph UUID request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - GraphListResponse - Successfully retrieved list of graphs. + Ontology + OK Examples -------- @@ -1956,60 +1961,53 @@ async def list_all( async def main() -> None: - await client.graph.list_all( - page_number=1, - page_size=1, - search="search", - order_by="order_by", - asc=True, + await client.graph.get_ontology( + graph_uuid="graph_uuid", ) asyncio.run(main()) """ - _response = await self._raw_client.list_all( - page_number=page_number, - page_size=page_size, - search=search, - order_by=order_by, - asc=asc, - request_options=request_options, - ) + _response = await self._raw_client.get_ontology(graph_uuid, request_options=request_options) return _response.data - async def add_nodes( + async def set_ontology( self, + graph_uuid: str, *, - nodes: typing.Sequence[AddNodeItem], - graph_id: typing.Optional[str] = OMIT, - user_id: typing.Optional[str] = OMIT, + edge_types: typing.Optional[typing.Sequence[typing.Dict[str, typing.Any]]] = OMIT, + entity_types: typing.Optional[typing.Sequence[typing.Dict[str, typing.Any]]] = OMIT, + inherited: typing.Optional[bool] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> AddNodesResponse: + ) -> Ontology: """ - Add entity nodes to a user or graph directly, without episode ingestion. Up to 100 nodes per request. - Parameters ---------- - nodes : typing.Sequence[AddNodeItem] - The nodes to add. 1 to 100 items. + graph_uuid : str + Graph UUID - graph_id : typing.Optional[str] + edge_types : typing.Optional[typing.Sequence[typing.Dict[str, typing.Any]]] - user_id : typing.Optional[str] + entity_types : typing.Optional[typing.Sequence[typing.Dict[str, typing.Any]]] + + inherited : typing.Optional[bool] + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - AddNodesResponse - Accepted + Ontology + OK Examples -------- import asyncio - from zep_cloud import AddNodeItem, AsyncZep + from zep_cloud import AsyncZep client = AsyncZep( api_key="YOUR_API_KEY", @@ -2017,91 +2015,71 @@ async def add_nodes( async def main() -> None: - await client.graph.add_nodes( - nodes=[ - AddNodeItem( - name="name", - ) - ], + await client.graph.set_ontology( + graph_uuid="graph_uuid", ) asyncio.run(main()) """ - _response = await self._raw_client.add_nodes( - nodes=nodes, graph_id=graph_id, user_id=user_id, request_options=request_options + _response = await self._raw_client.set_ontology( + graph_uuid, + edge_types=edge_types, + entity_types=entity_types, + inherited=inherited, + idempotency_key=idempotency_key, + request_options=request_options, ) return _response.data - async def detect_patterns( + async def search_edges( self, + graph_uuid: str, *, - detect: typing.Optional[DetectConfig] = OMIT, - edge_limit: typing.Optional[int] = OMIT, - graph_id: typing.Optional[str] = OMIT, - limit: typing.Optional[int] = OMIT, - min_occurrences: typing.Optional[int] = OMIT, + limit: typing.Optional[int] = None, + cursor: typing.Optional[str] = None, + bfs_origin_node_uuids: typing.Optional[typing.Sequence[str]] = OMIT, + center_node_uuid: typing.Optional[str] = OMIT, + filters: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + mmr_lambda: typing.Optional[float] = OMIT, query: typing.Optional[str] = OMIT, - query_limit: typing.Optional[int] = OMIT, - recency_weight: typing.Optional[RecencyWeight] = OMIT, - search_filters: typing.Optional[SearchFilters] = OMIT, - seeds: typing.Optional[PatternSeeds] = OMIT, - user_id: typing.Optional[str] = OMIT, + reranker: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> DetectPatternsResponse: + ) -> AsyncPager[JsonObject, JsonObjectPage]: """ - 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, - detects triple-frequency patterns, and returns resolved edges ranked by relevance. - Parameters ---------- - detect : typing.Optional[DetectConfig] - Which pattern types to detect with type-specific configuration. - Omit to detect all types with defaults. Ignored when query is set. - - edge_limit : typing.Optional[int] - Max resolved edges per pattern. Default: 10, Max: 100. Only used with query. - - graph_id : typing.Optional[str] - Graph ID when detecting patterns on a named graph + graph_uuid : str + Graph UUID limit : typing.Optional[int] - Max patterns to return. Default: 50, Max: 200 + Page size - min_occurrences : typing.Optional[int] - Minimum occurrence count to report a pattern. Default: 2 + cursor : typing.Optional[str] + Opaque page cursor - query : typing.Optional[str] - Search query for discovering seed nodes via hybrid search. - When set, forces triple-frequency detection only and enables edge resolution - with cross-encoder reranking. Mutually exclusive with seeds. + bfs_origin_node_uuids : typing.Optional[typing.Sequence[str]] - query_limit : typing.Optional[int] - Max seed nodes from search. Default: 10, Max: 50. Only used with query. + center_node_uuid : typing.Optional[str] - recency_weight : typing.Optional[RecencyWeight] - Exponential half-life decay applied to edge created_at timestamps. - Valid values: none, 7_days, 30_days, 90_days. Default: none + filters : typing.Optional[typing.Dict[str, typing.Any]] - search_filters : typing.Optional[SearchFilters] - Filters which edges/nodes participate in pattern detection. - Reuses the same filter format as /graph/search. + mmr_lambda : typing.Optional[float] - seeds : typing.Optional[PatternSeeds] - Seed selection. If omitted, analyzes the entire graph. Mutually exclusive with query. + query : typing.Optional[str] - user_id : typing.Optional[str] - User ID when detecting patterns on a user graph + reranker : typing.Optional[str] + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - DetectPatternsResponse - Detected patterns + AsyncPager[JsonObject, JsonObjectPage] + OK Examples -------- @@ -2115,98 +2093,83 @@ async def detect_patterns( async def main() -> None: - await client.graph.detect_patterns() + response = await client.graph.search_edges( + graph_uuid="graph_uuid", + limit=1, + cursor="cursor", + ) + async for item in response: + yield item + + # alternatively, you can paginate page-by-page + async for page in response.iter_pages(): + yield page asyncio.run(main()) """ - _response = await self._raw_client.detect_patterns( - detect=detect, - edge_limit=edge_limit, - graph_id=graph_id, + return await self._raw_client.search_edges( + graph_uuid, limit=limit, - min_occurrences=min_occurrences, + cursor=cursor, + bfs_origin_node_uuids=bfs_origin_node_uuids, + center_node_uuid=center_node_uuid, + filters=filters, + mmr_lambda=mmr_lambda, query=query, - query_limit=query_limit, - recency_weight=recency_weight, - search_filters=search_filters, - seeds=seeds, - user_id=user_id, + reranker=reranker, + idempotency_key=idempotency_key, request_options=request_options, ) - return _response.data - async def search( + async def search_episodes( self, + graph_uuid: str, *, - query: str, + limit: typing.Optional[int] = None, + cursor: typing.Optional[str] = None, bfs_origin_node_uuids: typing.Optional[typing.Sequence[str]] = OMIT, center_node_uuid: typing.Optional[str] = OMIT, - graph_id: typing.Optional[str] = OMIT, - limit: typing.Optional[int] = OMIT, - max_characters: typing.Optional[int] = OMIT, + filters: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, mmr_lambda: typing.Optional[float] = OMIT, - reranker: typing.Optional[Reranker] = OMIT, - return_raw_results: typing.Optional[bool] = OMIT, - scope: typing.Optional[GraphSearchScope] = OMIT, - search_filters: typing.Optional[SearchFilters] = OMIT, - user_id: typing.Optional[str] = OMIT, + query: typing.Optional[str] = OMIT, + reranker: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> GraphSearchResults: + ) -> AsyncPager[JsonObject, JsonObjectPage]: """ - Perform a graph search query. - Parameters ---------- - query : str - The string to search for (required) + graph_uuid : str + Graph UUID - bfs_origin_node_uuids : typing.Optional[typing.Sequence[str]] - Nodes that are the origins of the BFS searches + limit : typing.Optional[int] + Page size - center_node_uuid : typing.Optional[str] - Node to rerank around for node distance reranking + cursor : typing.Optional[str] + Opaque page cursor - graph_id : typing.Optional[str] - The graph_id to search in. When searching user graph, please use user_id instead. + bfs_origin_node_uuids : typing.Optional[typing.Sequence[str]] - limit : typing.Optional[int] - The maximum number of facts to retrieve for non-auto scopes. Defaults to 10. Limited to 50. Ignored when scope=auto. + center_node_uuid : typing.Optional[str] - max_characters : typing.Optional[int] - Maximum total characters across all selected results when scope=auto. Defaults to 2500. Limited to 50000. + filters : typing.Optional[typing.Dict[str, typing.Any]] mmr_lambda : typing.Optional[float] - weighting for maximal marginal relevance - - reranker : typing.Optional[Reranker] - Defaults to RRF. Ignored when scope=auto except node_distance and episode_mentions are rejected; - auto search always uses RRF retrieval and applies its own internal rerank after retrieval. - episode_mentions ranks edge candidates by how many of the episodes listed - in search_filters.episode_uuids mention them; without episode_uuids it has - no effect and results are ranked as if no reranker were specified. - return_raw_results : typing.Optional[bool] - When scope=auto, include the selected raw graph results alongside the materialized context block. - For graph-service-backed auto mode, selected raw results may include episodes, - edges, nodes, observations, and thread_summaries. - - scope : typing.Optional[GraphSearchScope] - Defaults to Edges. + query : typing.Optional[str] - search_filters : typing.Optional[SearchFilters] - Search filters to apply to the search + reranker : typing.Optional[str] - user_id : typing.Optional[str] - The user_id when searching user graph. If not searching user graph, please use graph_id instead. + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - GraphSearchResults - Graph search results or auto-context block + AsyncPager[JsonObject, JsonObjectPage] + OK Examples -------- @@ -2220,88 +2183,83 @@ async def search( async def main() -> None: - await client.graph.search( - query="query", + response = await client.graph.search_episodes( + graph_uuid="graph_uuid", + limit=1, + cursor="cursor", ) + async for item in response: + yield item + + # alternatively, you can paginate page-by-page + async for page in response.iter_pages(): + yield page asyncio.run(main()) """ - _response = await self._raw_client.search( - query=query, + return await self._raw_client.search_episodes( + graph_uuid, + limit=limit, + cursor=cursor, bfs_origin_node_uuids=bfs_origin_node_uuids, center_node_uuid=center_node_uuid, - graph_id=graph_id, - limit=limit, - max_characters=max_characters, + filters=filters, mmr_lambda=mmr_lambda, + query=query, reranker=reranker, - return_raw_results=return_raw_results, - scope=scope, - search_filters=search_filters, - user_id=user_id, + idempotency_key=idempotency_key, request_options=request_options, ) - return _response.data - async def get_subgraph( + async def search_nodes( self, + graph_uuid: str, *, - seed_node_uuids: typing.Sequence[str], - depth: typing.Optional[int] = OMIT, - direction: typing.Optional[str] = OMIT, - graph_id: typing.Optional[str] = OMIT, - max_edges: typing.Optional[int] = OMIT, - max_nodes: typing.Optional[int] = OMIT, - search_filters: typing.Optional[SearchFilters] = OMIT, - user_id: typing.Optional[str] = OMIT, + limit: typing.Optional[int] = None, + cursor: typing.Optional[str] = None, + bfs_origin_node_uuids: typing.Optional[typing.Sequence[str]] = OMIT, + center_node_uuid: typing.Optional[str] = OMIT, + filters: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + mmr_lambda: typing.Optional[float] = OMIT, + query: typing.Optional[str] = OMIT, + reranker: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> GraphSubgraphResponse: + ) -> AsyncPager[JsonObject, JsonObjectPage]: """ - Returns the bounded neighborhood of a set of seed nodes as a single {nodes, edges} payload: breadth-first expansion up to a caller-specified depth, subject to explicit budgets, with explicit truncation reporting. - Parameters ---------- - seed_node_uuids : typing.Sequence[str] - Seed node UUIDs to expand from, in traversal-priority order: seeds are - admitted before any expansion, in this order, and count toward - max_nodes first. 1-20 entries, required. Seeds that do not exist in - the target graph are ignored, not an error. + graph_uuid : str + Graph UUID - depth : typing.Optional[int] - Maximum traversal depth from the seeds. 1-3. Defaults to 1. + limit : typing.Optional[int] + Page size - direction : typing.Optional[str] - Edge orientation followed during expansion, relative to each frontier - node: "in" | "out" | "both". Defaults to "both". + cursor : typing.Optional[str] + Opaque page cursor - graph_id : typing.Optional[str] - graph_id identifies the target named graph. Exactly one of user_id or - graph_id is required. + bfs_origin_node_uuids : typing.Optional[typing.Sequence[str]] - max_edges : typing.Optional[int] - Maximum number of edges in the response. 1-1000. Defaults to 200. + center_node_uuid : typing.Optional[str] - max_nodes : typing.Optional[int] - Maximum number of nodes in the response, including admitted seeds. - 1-500. Defaults to 100. + filters : typing.Optional[typing.Dict[str, typing.Any]] - 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). + mmr_lambda : typing.Optional[float] - user_id : typing.Optional[str] - user_id identifies the target user graph. Exactly one of user_id or - graph_id is required. + query : typing.Optional[str] + + reranker : typing.Optional[str] + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - GraphSubgraphResponse - Subgraph + AsyncPager[JsonObject, JsonObjectPage] + OK Examples -------- @@ -2315,42 +2273,83 @@ async def get_subgraph( async def main() -> None: - await client.graph.get_subgraph( - seed_node_uuids=["seed_node_uuids"], + response = await client.graph.search_nodes( + graph_uuid="graph_uuid", + limit=1, + cursor="cursor", ) + async for item in response: + yield item + + # alternatively, you can paginate page-by-page + async for page in response.iter_pages(): + yield page asyncio.run(main()) """ - _response = await self._raw_client.get_subgraph( - seed_node_uuids=seed_node_uuids, - depth=depth, - direction=direction, - graph_id=graph_id, - max_edges=max_edges, - max_nodes=max_nodes, - search_filters=search_filters, - user_id=user_id, + return await self._raw_client.search_nodes( + graph_uuid, + limit=limit, + cursor=cursor, + bfs_origin_node_uuids=bfs_origin_node_uuids, + center_node_uuid=center_node_uuid, + filters=filters, + mmr_lambda=mmr_lambda, + query=query, + reranker=reranker, + idempotency_key=idempotency_key, request_options=request_options, ) - return _response.data - async def get(self, graph_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> Graph: + async def search_observations( + self, + graph_uuid: str, + *, + limit: typing.Optional[int] = None, + cursor: typing.Optional[str] = None, + bfs_origin_node_uuids: typing.Optional[typing.Sequence[str]] = OMIT, + center_node_uuid: typing.Optional[str] = OMIT, + filters: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + mmr_lambda: typing.Optional[float] = OMIT, + query: typing.Optional[str] = OMIT, + reranker: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncPager[JsonObject, JsonObjectPage]: """ - Returns a graph. - Parameters ---------- - graph_id : str - The graph_id of the graph to get. + graph_uuid : str + Graph UUID + + limit : typing.Optional[int] + Page size + + cursor : typing.Optional[str] + Opaque page cursor + + bfs_origin_node_uuids : typing.Optional[typing.Sequence[str]] + + center_node_uuid : typing.Optional[str] + + filters : typing.Optional[typing.Dict[str, typing.Any]] + + mmr_lambda : typing.Optional[float] + + query : typing.Optional[str] + + reranker : typing.Optional[str] + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - Graph - The graph that was retrieved. + AsyncPager[JsonObject, JsonObjectPage] + OK Examples -------- @@ -2364,34 +2363,83 @@ async def get(self, graph_id: str, *, request_options: typing.Optional[RequestOp async def main() -> None: - await client.graph.get( - graph_id="graphId", + response = await client.graph.search_observations( + graph_uuid="graph_uuid", + limit=1, + cursor="cursor", ) + async for item in response: + yield item + + # alternatively, you can paginate page-by-page + async for page in response.iter_pages(): + yield page asyncio.run(main()) """ - _response = await self._raw_client.get(graph_id, request_options=request_options) - return _response.data + return await self._raw_client.search_observations( + graph_uuid, + limit=limit, + cursor=cursor, + bfs_origin_node_uuids=bfs_origin_node_uuids, + center_node_uuid=center_node_uuid, + filters=filters, + mmr_lambda=mmr_lambda, + query=query, + reranker=reranker, + idempotency_key=idempotency_key, + request_options=request_options, + ) - async def delete( - self, graph_id: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> SuccessResponse: + async def search_thread_summaries( + self, + graph_uuid: str, + *, + limit: typing.Optional[int] = None, + cursor: typing.Optional[str] = None, + bfs_origin_node_uuids: typing.Optional[typing.Sequence[str]] = OMIT, + center_node_uuid: typing.Optional[str] = OMIT, + filters: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + mmr_lambda: typing.Optional[float] = OMIT, + query: typing.Optional[str] = OMIT, + reranker: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncPager[JsonObject, JsonObjectPage]: """ - Deletes a graph. If you would like to delete a user graph, make sure to use user.delete instead. - Parameters ---------- - graph_id : str - Graph ID + graph_uuid : str + Graph UUID + + limit : typing.Optional[int] + Page size + + cursor : typing.Optional[str] + Opaque page cursor + + bfs_origin_node_uuids : typing.Optional[typing.Sequence[str]] + + center_node_uuid : typing.Optional[str] + + filters : typing.Optional[typing.Dict[str, typing.Any]] + + mmr_lambda : typing.Optional[float] + + query : typing.Optional[str] + + reranker : typing.Optional[str] + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - SuccessResponse - Deleted + AsyncPager[JsonObject, JsonObjectPage] + OK Examples -------- @@ -2405,47 +2453,75 @@ async def delete( async def main() -> None: - await client.graph.delete( - graph_id="graphId", + response = await client.graph.search_thread_summaries( + graph_uuid="graph_uuid", + limit=1, + cursor="cursor", ) + async for item in response: + yield item + + # alternatively, you can paginate page-by-page + async for page in response.iter_pages(): + yield page asyncio.run(main()) """ - _response = await self._raw_client.delete(graph_id, request_options=request_options) - return _response.data + return await self._raw_client.search_thread_summaries( + graph_uuid, + limit=limit, + cursor=cursor, + bfs_origin_node_uuids=bfs_origin_node_uuids, + center_node_uuid=center_node_uuid, + filters=filters, + mmr_lambda=mmr_lambda, + query=query, + reranker=reranker, + idempotency_key=idempotency_key, + request_options=request_options, + ) - async def update( + async def get_subgraph( self, - graph_id: str, + graph_uuid: str, *, - description: typing.Optional[str] = OMIT, - name: typing.Optional[str] = OMIT, - time_zone: typing.Optional[str] = OMIT, + depth: typing.Optional[int] = OMIT, + direction: typing.Optional[str] = OMIT, + filters: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + max_edges: typing.Optional[int] = OMIT, + max_nodes: typing.Optional[int] = OMIT, + seed_node_uuids: typing.Optional[typing.Sequence[str]] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> Graph: + ) -> JsonObject: """ - Updates information about a graph. - Parameters ---------- - graph_id : str - Graph ID + graph_uuid : str + Graph UUID - description : typing.Optional[str] + depth : typing.Optional[int] - name : typing.Optional[str] + direction : typing.Optional[str] - time_zone : typing.Optional[str] - The graph's IANA time zone. Stored on its group-backed subject. + filters : typing.Optional[typing.Dict[str, typing.Any]] + + max_edges : typing.Optional[int] + + max_nodes : typing.Optional[int] + + seed_node_uuids : typing.Optional[typing.Sequence[str]] + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - Graph - The updated graph object + JsonObject + OK Examples -------- @@ -2459,34 +2535,48 @@ async def update( async def main() -> None: - await client.graph.update( - graph_id="graphId", + await client.graph.get_subgraph( + graph_uuid="graph_uuid", ) asyncio.run(main()) """ - _response = await self._raw_client.update( - graph_id, description=description, name=name, time_zone=time_zone, request_options=request_options + _response = await self._raw_client.get_subgraph( + graph_uuid, + depth=depth, + direction=direction, + filters=filters, + max_edges=max_edges, + max_nodes=max_nodes, + seed_node_uuids=seed_node_uuids, + idempotency_key=idempotency_key, + request_options=request_options, ) return _response.data - async def warm(self, graph_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> SuccessResponse: + async def warm( + self, + graph_uuid: str, + *, + idempotency_key: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncResult: """ - Hints Zep to warm a graph for low-latency search - Parameters ---------- - graph_id : str - The graph_id of the graph to warm. + graph_uuid : str + Graph UUID + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - SuccessResponse - Warm hint accepted + AsyncResult + Accepted Examples -------- @@ -2501,11 +2591,61 @@ async def warm(self, graph_id: str, *, request_options: typing.Optional[RequestO async def main() -> None: await client.graph.warm( - graph_id="graphId", + graph_uuid="graph_uuid", ) asyncio.run(main()) """ - _response = await self._raw_client.warm(graph_id, request_options=request_options) + _response = await self._raw_client.warm( + graph_uuid, idempotency_key=idempotency_key, request_options=request_options + ) return _response.data + + @property + def document_summary(self): + if self._document_summary is None: + from .document_summary.client import AsyncDocumentSummaryClient # noqa: E402 + + self._document_summary = AsyncDocumentSummaryClient(client_wrapper=self._client_wrapper) + return self._document_summary + + @property + def episode(self): + if self._episode is None: + from .episode.client import AsyncEpisodeClient # noqa: E402 + + self._episode = AsyncEpisodeClient(client_wrapper=self._client_wrapper) + return self._episode + + @property + def edge(self): + if self._edge is None: + from .edge.client import AsyncEdgeClient # noqa: E402 + + self._edge = AsyncEdgeClient(client_wrapper=self._client_wrapper) + return self._edge + + @property + def node(self): + if self._node is None: + from .node.client import AsyncNodeClient # noqa: E402 + + self._node = AsyncNodeClient(client_wrapper=self._client_wrapper) + return self._node + + @property + def observation(self): + if self._observation is None: + from .observation.client import AsyncObservationClient # noqa: E402 + + self._observation = AsyncObservationClient(client_wrapper=self._client_wrapper) + return self._observation + + @property + def thread_summary(self): + if self._thread_summary is None: + from .thread_summary.client import AsyncThreadSummaryClient # noqa: E402 + + self._thread_summary = AsyncThreadSummaryClient(client_wrapper=self._client_wrapper) + return self._thread_summary diff --git a/src/zep_cloud/user_group/__init__.py b/src/zep_cloud/graph/document_summary/__init__.py similarity index 100% rename from src/zep_cloud/user_group/__init__.py rename to src/zep_cloud/graph/document_summary/__init__.py 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..dc14d6b7 --- /dev/null +++ b/src/zep_cloud/graph/document_summary/client.py @@ -0,0 +1,176 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +from ...core.client_wrapper import AsyncClientWrapper, SyncClientWrapper +from ...core.pagination import AsyncPager, SyncPager +from ...core.request_options import RequestOptions +from ...types.json_object import JsonObject +from ...types.json_object_page import JsonObjectPage +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 list( + self, + graph_uuid: str, + *, + limit: typing.Optional[int] = None, + cursor: typing.Optional[str] = None, + filters: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + idempotency_key: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> SyncPager[JsonObject, JsonObjectPage]: + """ + Parameters + ---------- + graph_uuid : str + Graph UUID + + limit : typing.Optional[int] + Page size + + cursor : typing.Optional[str] + Opaque page cursor + + filters : typing.Optional[typing.Dict[str, typing.Any]] + + idempotency_key : typing.Optional[str] + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + SyncPager[JsonObject, JsonObjectPage] + OK + + Examples + -------- + from zep_cloud import Zep + + client = Zep( + api_key="YOUR_API_KEY", + ) + response = client.graph.document_summary.list( + graph_uuid="graph_uuid", + limit=1, + cursor="cursor", + ) + for item in response: + yield item + # alternatively, you can paginate page-by-page + for page in response.iter_pages(): + yield page + """ + return self._raw_client.list( + graph_uuid, + limit=limit, + cursor=cursor, + filters=filters, + idempotency_key=idempotency_key, + request_options=request_options, + ) + + +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 list( + self, + graph_uuid: str, + *, + limit: typing.Optional[int] = None, + cursor: typing.Optional[str] = None, + filters: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + idempotency_key: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncPager[JsonObject, JsonObjectPage]: + """ + Parameters + ---------- + graph_uuid : str + Graph UUID + + limit : typing.Optional[int] + Page size + + cursor : typing.Optional[str] + Opaque page cursor + + filters : typing.Optional[typing.Dict[str, typing.Any]] + + idempotency_key : typing.Optional[str] + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncPager[JsonObject, JsonObjectPage] + OK + + Examples + -------- + import asyncio + + from zep_cloud import AsyncZep + + client = AsyncZep( + api_key="YOUR_API_KEY", + ) + + + async def main() -> None: + response = await client.graph.document_summary.list( + graph_uuid="graph_uuid", + limit=1, + cursor="cursor", + ) + async for item in response: + yield item + + # alternatively, you can paginate page-by-page + async for page in response.iter_pages(): + yield page + + + asyncio.run(main()) + """ + return await self._raw_client.list( + graph_uuid, + limit=limit, + cursor=cursor, + filters=filters, + idempotency_key=idempotency_key, + request_options=request_options, + ) 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..6484c773 --- /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.jsonable_encoder import jsonable_encoder +from ...core.pagination import AsyncPager, SyncPager +from ...core.parse_error import ParsingError +from ...core.pydantic_utilities import parse_obj_as +from ...core.request_options import RequestOptions +from ...errors.bad_request_error import BadRequestError +from ...errors.not_found_error import NotFoundError +from ...errors.unauthorized_error import UnauthorizedError +from ...types.api_error import ApiError as types_api_error_ApiError +from ...types.json_object import JsonObject +from ...types.json_object_page import JsonObjectPage +from pydantic import ValidationError + +# 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 list( + self, + graph_uuid: str, + *, + limit: typing.Optional[int] = None, + cursor: typing.Optional[str] = None, + filters: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + idempotency_key: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> SyncPager[JsonObject, JsonObjectPage]: + """ + Parameters + ---------- + graph_uuid : str + Graph UUID + + limit : typing.Optional[int] + Page size + + cursor : typing.Optional[str] + Opaque page cursor + + filters : typing.Optional[typing.Dict[str, typing.Any]] + + idempotency_key : typing.Optional[str] + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + SyncPager[JsonObject, JsonObjectPage] + OK + """ + _response = self._client_wrapper.httpx_client.request( + f"graphs/{jsonable_encoder(graph_uuid)}/document-summaries/list", + method="POST", + params={ + "limit": limit, + "cursor": cursor, + }, + json={ + "filters": filters, + }, + headers={ + "content-type": "application/json", + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + _parsed_response = typing.cast( + JsonObjectPage, + parse_obj_as( + type_=JsonObjectPage, # type: ignore + object_=_response.json(), + ), + ) + _items = _parsed_response.items + _parsed_next = _parsed_response.next_cursor + _has_next = _parsed_next is not None and _parsed_next != "" + _get_next = lambda: self.list( + graph_uuid, + limit=limit, + cursor=_parsed_next, + filters=filters, + idempotency_key=idempotency_key, + request_options=request_options, + ) + return SyncPager(has_next=_has_next, items=_items, get_next=_get_next, response=_parsed_response) + if _response.status_code == 400: + raise BadRequestError( + 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 == 401: + raise UnauthorizedError( + 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(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise core_api_error_ApiError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.text + ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) + 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 list( + self, + graph_uuid: str, + *, + limit: typing.Optional[int] = None, + cursor: typing.Optional[str] = None, + filters: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + idempotency_key: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncPager[JsonObject, JsonObjectPage]: + """ + Parameters + ---------- + graph_uuid : str + Graph UUID + + limit : typing.Optional[int] + Page size + + cursor : typing.Optional[str] + Opaque page cursor + + filters : typing.Optional[typing.Dict[str, typing.Any]] + + idempotency_key : typing.Optional[str] + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncPager[JsonObject, JsonObjectPage] + OK + """ + _response = await self._client_wrapper.httpx_client.request( + f"graphs/{jsonable_encoder(graph_uuid)}/document-summaries/list", + method="POST", + params={ + "limit": limit, + "cursor": cursor, + }, + json={ + "filters": filters, + }, + headers={ + "content-type": "application/json", + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + _parsed_response = typing.cast( + JsonObjectPage, + parse_obj_as( + type_=JsonObjectPage, # type: ignore + object_=_response.json(), + ), + ) + _items = _parsed_response.items + _parsed_next = _parsed_response.next_cursor + _has_next = _parsed_next is not None and _parsed_next != "" + + async def _get_next(): + return await self.list( + graph_uuid, + limit=limit, + cursor=_parsed_next, + filters=filters, + idempotency_key=idempotency_key, + request_options=request_options, + ) + + return AsyncPager(has_next=_has_next, items=_items, get_next=_get_next, response=_parsed_response) + if _response.status_code == 400: + raise BadRequestError( + 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 == 401: + raise UnauthorizedError( + 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(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise core_api_error_ApiError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.text + ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) + raise core_api_error_ApiError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response_json + ) diff --git a/src/zep_cloud/graph/edge/client.py b/src/zep_cloud/graph/edge/client.py index 2835015e..53a7f355 100644 --- a/src/zep_cloud/graph/edge/client.py +++ b/src/zep_cloud/graph/edge/client.py @@ -3,10 +3,12 @@ import typing from ...core.client_wrapper import AsyncClientWrapper, SyncClientWrapper +from ...core.pagination import AsyncPager, SyncPager from ...core.request_options import RequestOptions -from ...types.entity_edge import EntityEdge -from ...types.search_filters import SearchFilters -from ...types.success_response import SuccessResponse +from ...types.add_edge_result import AddEdgeResult +from ...types.async_result import AsyncResult +from ...types.json_object import JsonObject +from ...types.json_object_page import JsonObjectPage from .raw_client import AsyncRawEdgeClient, RawEdgeClient # this is used as the default value for optional parameters @@ -28,54 +30,55 @@ def with_raw_response(self) -> RawEdgeClient: """ return self._raw_client - def get_by_graph_id( + def add( self, - graph_id: str, + graph_uuid: 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, + attributes: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + expired_at: typing.Optional[str] = OMIT, + fact: typing.Optional[str] = OMIT, + fact_name: typing.Optional[str] = OMIT, + invalid_at: typing.Optional[str] = OMIT, + metadata: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + source_node: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + target_node: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + valid_at: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> typing.List[EntityEdge]: + ) -> AddEdgeResult: """ - Returns all edges for a graph. - Parameters ---------- - graph_id : str - Graph ID + graph_uuid : str + Graph UUID - 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. + attributes : typing.Optional[typing.Dict[str, typing.Any]] + + expired_at : typing.Optional[str] - direction : typing.Optional[str] - Sort direction. One of "asc" or "desc" (default "desc"). + fact : typing.Optional[str] - filters : typing.Optional[SearchFilters] - Optional filters applied to the listed artifacts. Reuses the graph.search filter type. + fact_name : typing.Optional[str] - limit : typing.Optional[int] - Maximum number of items to return + invalid_at : typing.Optional[str] - order_by : typing.Optional[str] - Field to sort by. One of "created_at", "valid_at", or "uuid" (default "uuid"). + metadata : typing.Optional[typing.Dict[str, typing.Any]] - uuid_cursor : typing.Optional[str] - UUID based cursor, used for pagination. Should be the UUID of the last item in the previous page. + source_node : typing.Optional[typing.Dict[str, typing.Any]] + + target_node : typing.Optional[typing.Dict[str, typing.Any]] + + valid_at : typing.Optional[str] - Deprecated: prefer Cursor, the opaque cursor returned via the Zep-Next-Cursor response header. + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - typing.List[EntityEdge] - Edges + AddEdgeResult + Accepted Examples -------- @@ -84,70 +87,59 @@ def get_by_graph_id( client = Zep( api_key="YOUR_API_KEY", ) - client.graph.edge.get_by_graph_id( - graph_id="graph_id", + client.graph.edge.add( + graph_uuid="graph_uuid", ) """ - _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, + _response = self._raw_client.add( + graph_uuid, + attributes=attributes, + expired_at=expired_at, + fact=fact, + fact_name=fact_name, + invalid_at=invalid_at, + metadata=metadata, + source_node=source_node, + target_node=target_node, + valid_at=valid_at, + idempotency_key=idempotency_key, request_options=request_options, ) return _response.data - def get_by_user_id( + def list( self, - user_id: str, + graph_uuid: 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, + limit: typing.Optional[int] = None, + cursor: typing.Optional[str] = None, + filters: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> typing.List[EntityEdge]: + ) -> SyncPager[JsonObject, JsonObjectPage]: """ - Returns all edges for a user. - Parameters ---------- - user_id : str - User ID - - cursor : typing.Optional[str] - Opaque cursor for pagination, obtained from the Zep-Next-Cursor response header - of the previous page. 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. + graph_uuid : str + Graph UUID limit : typing.Optional[int] - Maximum number of items to return + Page size - order_by : typing.Optional[str] - Field to sort by. One of "created_at", "valid_at", or "uuid" (default "uuid"). + cursor : typing.Optional[str] + Opaque page cursor - uuid_cursor : typing.Optional[str] - UUID based cursor, used for pagination. Should be the UUID of the last item in the previous page. + filters : typing.Optional[typing.Dict[str, typing.Any]] - Deprecated: prefer Cursor, the opaque cursor returned via the Zep-Next-Cursor response header. + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - typing.List[EntityEdge] - Edges + SyncPager[JsonObject, JsonObjectPage] + OK Examples -------- @@ -156,29 +148,36 @@ def get_by_user_id( client = Zep( api_key="YOUR_API_KEY", ) - client.graph.edge.get_by_user_id( - user_id="user_id", + response = client.graph.edge.list( + graph_uuid="graph_uuid", + limit=1, + cursor="cursor", ) + for item in response: + yield item + # alternatively, you can paginate page-by-page + for page in response.iter_pages(): + yield page """ - _response = self._raw_client.get_by_user_id( - user_id, + return self._raw_client.list( + graph_uuid, + limit=limit, cursor=cursor, - direction=direction, filters=filters, - limit=limit, - order_by=order_by, - uuid_cursor=uuid_cursor, + idempotency_key=idempotency_key, request_options=request_options, ) - return _response.data - def get(self, uuid_: str, *, request_options: typing.Optional[RequestOptions] = None) -> EntityEdge: + def get( + self, graph_uuid: str, edge_uuid: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> JsonObject: """ - Returns a specific edge by its UUID. - Parameters ---------- - uuid_ : str + graph_uuid : str + Graph UUID + + edge_uuid : str Edge UUID request_options : typing.Optional[RequestOptions] @@ -186,8 +185,8 @@ def get(self, uuid_: str, *, request_options: typing.Optional[RequestOptions] = Returns ------- - EntityEdge - Edge + JsonObject + OK Examples -------- @@ -197,28 +196,39 @@ def get(self, uuid_: str, *, request_options: typing.Optional[RequestOptions] = api_key="YOUR_API_KEY", ) client.graph.edge.get( - uuid_="uuid", + graph_uuid="graph_uuid", + edge_uuid="edge_uuid", ) """ - _response = self._raw_client.get(uuid_, request_options=request_options) + _response = self._raw_client.get(graph_uuid, edge_uuid, request_options=request_options) return _response.data - def delete(self, uuid_: str, *, request_options: typing.Optional[RequestOptions] = None) -> SuccessResponse: + def delete( + self, + graph_uuid: str, + edge_uuid: str, + *, + idempotency_key: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncResult: """ - Deletes an edge by UUID. - Parameters ---------- - uuid_ : str + graph_uuid : str + Graph UUID + + edge_uuid : str Edge UUID + idempotency_key : typing.Optional[str] + request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - SuccessResponse - Edge deleted + AsyncResult + Accepted Examples -------- @@ -228,57 +238,48 @@ def delete(self, uuid_: str, *, request_options: typing.Optional[RequestOptions] api_key="YOUR_API_KEY", ) client.graph.edge.delete( - uuid_="uuid", + graph_uuid="graph_uuid", + edge_uuid="edge_uuid", ) """ - _response = self._raw_client.delete(uuid_, request_options=request_options) + _response = self._raw_client.delete( + graph_uuid, edge_uuid, idempotency_key=idempotency_key, request_options=request_options + ) return _response.data def update( self, - uuid_: str, + graph_uuid: str, + edge_uuid: str, *, - attributes: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = OMIT, - expired_at: typing.Optional[str] = OMIT, + attributes: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, fact: typing.Optional[str] = OMIT, - invalid_at: typing.Optional[str] = OMIT, - name: typing.Optional[str] = OMIT, - valid_at: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> EntityEdge: + ) -> JsonObject: """ - Updates an entity edge by UUID. - Parameters ---------- - uuid_ : str + graph_uuid : str + Graph UUID + + edge_uuid : str Edge UUID - attributes : typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] - Updated attributes. Merged with existing attributes. Set a key to null to delete it. - - expired_at : typing.Optional[str] - Updated time at which the edge expires + attributes : typing.Optional[typing.Dict[str, typing.Any]] fact : typing.Optional[str] - Updated fact for the edge - - invalid_at : typing.Optional[str] - Updated time at which the fact stopped being true + Omit to leave unchanged, send JSON null to clear, or send a value to set. - name : typing.Optional[str] - Updated name (relationship type) for the edge - - valid_at : typing.Optional[str] - Updated time at which the fact becomes true + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - EntityEdge - Updated edge + JsonObject + OK Examples -------- @@ -288,17 +289,16 @@ def update( api_key="YOUR_API_KEY", ) client.graph.edge.update( - uuid_="uuid", + graph_uuid="graph_uuid", + edge_uuid="edge_uuid", ) """ _response = self._raw_client.update( - uuid_, + graph_uuid, + edge_uuid, attributes=attributes, - expired_at=expired_at, fact=fact, - invalid_at=invalid_at, - name=name, - valid_at=valid_at, + idempotency_key=idempotency_key, request_options=request_options, ) return _response.data @@ -319,54 +319,55 @@ def with_raw_response(self) -> AsyncRawEdgeClient: """ return self._raw_client - async def get_by_graph_id( + async def add( self, - graph_id: str, + graph_uuid: 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, + attributes: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + expired_at: typing.Optional[str] = OMIT, + fact: typing.Optional[str] = OMIT, + fact_name: typing.Optional[str] = OMIT, + invalid_at: typing.Optional[str] = OMIT, + metadata: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + source_node: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + target_node: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + valid_at: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> typing.List[EntityEdge]: + ) -> AddEdgeResult: """ - Returns all edges for a graph. - Parameters ---------- - graph_id : str - Graph ID + graph_uuid : str + Graph UUID - 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. + attributes : typing.Optional[typing.Dict[str, typing.Any]] + + expired_at : typing.Optional[str] - direction : typing.Optional[str] - Sort direction. One of "asc" or "desc" (default "desc"). + fact : typing.Optional[str] - filters : typing.Optional[SearchFilters] - Optional filters applied to the listed artifacts. Reuses the graph.search filter type. + fact_name : typing.Optional[str] - limit : typing.Optional[int] - Maximum number of items to return + invalid_at : typing.Optional[str] - order_by : typing.Optional[str] - Field to sort by. One of "created_at", "valid_at", or "uuid" (default "uuid"). + metadata : typing.Optional[typing.Dict[str, typing.Any]] - uuid_cursor : typing.Optional[str] - UUID based cursor, used for pagination. Should be the UUID of the last item in the previous page. + source_node : typing.Optional[typing.Dict[str, typing.Any]] - Deprecated: prefer Cursor, the opaque cursor returned via the Zep-Next-Cursor response header. + target_node : typing.Optional[typing.Dict[str, typing.Any]] + + valid_at : typing.Optional[str] + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - typing.List[EntityEdge] - Edges + AddEdgeResult + Accepted Examples -------- @@ -380,73 +381,62 @@ async def get_by_graph_id( async def main() -> None: - await client.graph.edge.get_by_graph_id( - graph_id="graph_id", + await client.graph.edge.add( + graph_uuid="graph_uuid", ) 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, + _response = await self._raw_client.add( + graph_uuid, + attributes=attributes, + expired_at=expired_at, + fact=fact, + fact_name=fact_name, + invalid_at=invalid_at, + metadata=metadata, + source_node=source_node, + target_node=target_node, + valid_at=valid_at, + idempotency_key=idempotency_key, request_options=request_options, ) return _response.data - async def get_by_user_id( + async def list( self, - user_id: str, + graph_uuid: 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, + limit: typing.Optional[int] = None, + cursor: typing.Optional[str] = None, + filters: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> typing.List[EntityEdge]: + ) -> AsyncPager[JsonObject, JsonObjectPage]: """ - Returns all edges for a user. - Parameters ---------- - user_id : str - User ID - - cursor : typing.Optional[str] - Opaque cursor for pagination, obtained from the Zep-Next-Cursor response header - of the previous page. 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. + graph_uuid : str + Graph UUID limit : typing.Optional[int] - Maximum number of items to return + Page size - order_by : typing.Optional[str] - Field to sort by. One of "created_at", "valid_at", or "uuid" (default "uuid"). + cursor : typing.Optional[str] + Opaque page cursor - uuid_cursor : typing.Optional[str] - UUID based cursor, used for pagination. Should be the UUID of the last item in the previous page. + filters : typing.Optional[typing.Dict[str, typing.Any]] - Deprecated: prefer Cursor, the opaque cursor returned via the Zep-Next-Cursor response header. + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - typing.List[EntityEdge] - Edges + AsyncPager[JsonObject, JsonObjectPage] + OK Examples -------- @@ -460,32 +450,40 @@ async def get_by_user_id( async def main() -> None: - await client.graph.edge.get_by_user_id( - user_id="user_id", + response = await client.graph.edge.list( + graph_uuid="graph_uuid", + limit=1, + cursor="cursor", ) + async for item in response: + yield item + + # alternatively, you can paginate page-by-page + async for page in response.iter_pages(): + yield page asyncio.run(main()) """ - _response = await self._raw_client.get_by_user_id( - user_id, + return await self._raw_client.list( + graph_uuid, + limit=limit, cursor=cursor, - direction=direction, filters=filters, - limit=limit, - order_by=order_by, - uuid_cursor=uuid_cursor, + idempotency_key=idempotency_key, request_options=request_options, ) - return _response.data - async def get(self, uuid_: str, *, request_options: typing.Optional[RequestOptions] = None) -> EntityEdge: + async def get( + self, graph_uuid: str, edge_uuid: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> JsonObject: """ - Returns a specific edge by its UUID. - Parameters ---------- - uuid_ : str + graph_uuid : str + Graph UUID + + edge_uuid : str Edge UUID request_options : typing.Optional[RequestOptions] @@ -493,8 +491,8 @@ async def get(self, uuid_: str, *, request_options: typing.Optional[RequestOptio Returns ------- - EntityEdge - Edge + JsonObject + OK Examples -------- @@ -509,31 +507,42 @@ async def get(self, uuid_: str, *, request_options: typing.Optional[RequestOptio async def main() -> None: await client.graph.edge.get( - uuid_="uuid", + graph_uuid="graph_uuid", + edge_uuid="edge_uuid", ) asyncio.run(main()) """ - _response = await self._raw_client.get(uuid_, request_options=request_options) + _response = await self._raw_client.get(graph_uuid, edge_uuid, request_options=request_options) return _response.data - async def delete(self, uuid_: str, *, request_options: typing.Optional[RequestOptions] = None) -> SuccessResponse: + async def delete( + self, + graph_uuid: str, + edge_uuid: str, + *, + idempotency_key: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncResult: """ - Deletes an edge by UUID. - Parameters ---------- - uuid_ : str + graph_uuid : str + Graph UUID + + edge_uuid : str Edge UUID + idempotency_key : typing.Optional[str] + request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - SuccessResponse - Edge deleted + AsyncResult + Accepted Examples -------- @@ -548,60 +557,51 @@ async def delete(self, uuid_: str, *, request_options: typing.Optional[RequestOp async def main() -> None: await client.graph.edge.delete( - uuid_="uuid", + graph_uuid="graph_uuid", + edge_uuid="edge_uuid", ) asyncio.run(main()) """ - _response = await self._raw_client.delete(uuid_, request_options=request_options) + _response = await self._raw_client.delete( + graph_uuid, edge_uuid, idempotency_key=idempotency_key, request_options=request_options + ) return _response.data async def update( self, - uuid_: str, + graph_uuid: str, + edge_uuid: str, *, - attributes: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = OMIT, - expired_at: typing.Optional[str] = OMIT, + attributes: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, fact: typing.Optional[str] = OMIT, - invalid_at: typing.Optional[str] = OMIT, - name: typing.Optional[str] = OMIT, - valid_at: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> EntityEdge: + ) -> JsonObject: """ - Updates an entity edge by UUID. - Parameters ---------- - uuid_ : str - Edge UUID + graph_uuid : str + Graph UUID - attributes : typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] - Updated attributes. Merged with existing attributes. Set a key to null to delete it. + edge_uuid : str + Edge UUID - expired_at : typing.Optional[str] - Updated time at which the edge expires + attributes : typing.Optional[typing.Dict[str, typing.Any]] fact : typing.Optional[str] - Updated fact for the edge + Omit to leave unchanged, send JSON null to clear, or send a value to set. - invalid_at : typing.Optional[str] - Updated time at which the fact stopped being true - - name : typing.Optional[str] - Updated name (relationship type) for the edge - - valid_at : typing.Optional[str] - Updated time at which the fact becomes true + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - EntityEdge - Updated edge + JsonObject + OK Examples -------- @@ -616,20 +616,19 @@ async def update( async def main() -> None: await client.graph.edge.update( - uuid_="uuid", + graph_uuid="graph_uuid", + edge_uuid="edge_uuid", ) asyncio.run(main()) """ _response = await self._raw_client.update( - uuid_, + graph_uuid, + edge_uuid, attributes=attributes, - expired_at=expired_at, fact=fact, - invalid_at=invalid_at, - name=name, - valid_at=valid_at, + idempotency_key=idempotency_key, request_options=request_options, ) return _response.data diff --git a/src/zep_cloud/graph/edge/raw_client.py b/src/zep_cloud/graph/edge/raw_client.py index 4375c21b..80597a0c 100644 --- a/src/zep_cloud/graph/edge/raw_client.py +++ b/src/zep_cloud/graph/edge/raw_client.py @@ -7,16 +7,19 @@ from ...core.client_wrapper import AsyncClientWrapper, SyncClientWrapper from ...core.http_response import AsyncHttpResponse, HttpResponse from ...core.jsonable_encoder import jsonable_encoder +from ...core.pagination import AsyncPager, SyncPager +from ...core.parse_error import ParsingError 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 ...errors.unauthorized_error import UnauthorizedError +from ...types.add_edge_result import AddEdgeResult from ...types.api_error import ApiError as types_api_error_ApiError -from ...types.entity_edge import EntityEdge -from ...types.search_filters import SearchFilters -from ...types.success_response import SuccessResponse +from ...types.async_result import AsyncResult +from ...types.json_object import JsonObject +from ...types.json_object_page import JsonObjectPage +from pydantic import ValidationError # this is used as the default value for optional parameters OMIT = typing.cast(typing.Any, ...) @@ -26,67 +29,73 @@ class RawEdgeClient: def __init__(self, *, client_wrapper: SyncClientWrapper): self._client_wrapper = client_wrapper - def get_by_graph_id( + def add( self, - graph_id: str, + graph_uuid: 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, + attributes: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + expired_at: typing.Optional[str] = OMIT, + fact: typing.Optional[str] = OMIT, + fact_name: typing.Optional[str] = OMIT, + invalid_at: typing.Optional[str] = OMIT, + metadata: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + source_node: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + target_node: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + valid_at: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> HttpResponse[typing.List[EntityEdge]]: + ) -> HttpResponse[AddEdgeResult]: """ - Returns all edges for a graph. - Parameters ---------- - graph_id : str - Graph ID + graph_uuid : str + Graph UUID - 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. + attributes : typing.Optional[typing.Dict[str, typing.Any]] - direction : typing.Optional[str] - Sort direction. One of "asc" or "desc" (default "desc"). + expired_at : typing.Optional[str] - filters : typing.Optional[SearchFilters] - Optional filters applied to the listed artifacts. Reuses the graph.search filter type. + fact : typing.Optional[str] - limit : typing.Optional[int] - Maximum number of items to return + fact_name : typing.Optional[str] + + invalid_at : typing.Optional[str] - order_by : typing.Optional[str] - Field to sort by. One of "created_at", "valid_at", or "uuid" (default "uuid"). + metadata : typing.Optional[typing.Dict[str, typing.Any]] - uuid_cursor : typing.Optional[str] - UUID based cursor, used for pagination. Should be the UUID of the last item in the previous page. + source_node : typing.Optional[typing.Dict[str, typing.Any]] - Deprecated: prefer Cursor, the opaque cursor returned via the Zep-Next-Cursor response header. + target_node : typing.Optional[typing.Dict[str, typing.Any]] + + valid_at : typing.Optional[str] + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - HttpResponse[typing.List[EntityEdge]] - Edges + HttpResponse[AddEdgeResult] + Accepted """ _response = self._client_wrapper.httpx_client.request( - f"graph/edge/graph/{jsonable_encoder(graph_id)}", + f"graphs/{jsonable_encoder(graph_uuid)}/edges", 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, + "attributes": attributes, + "expired_at": expired_at, + "fact": fact, + "fact_name": fact_name, + "invalid_at": invalid_at, + "metadata": metadata, + "source_node": source_node, + "target_node": target_node, + "valid_at": valid_at, + }, + headers={ + "content-type": "application/json", + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, }, request_options=request_options, omit=OMIT, @@ -94,9 +103,9 @@ def get_by_graph_id( try: if 200 <= _response.status_code < 300: _data = typing.cast( - typing.List[EntityEdge], + AddEdgeResult, parse_obj_as( - type_=typing.List[EntityEdge], # type: ignore + type_=AddEdgeResult, # type: ignore object_=_response.json(), ), ) @@ -105,15 +114,26 @@ def get_by_graph_id( raise BadRequestError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore object_=_response.json(), ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 401: + raise UnauthorizedError( + 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, @@ -128,98 +148,110 @@ def get_by_graph_id( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - def get_by_user_id( + def list( self, - user_id: str, + graph_uuid: 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, + limit: typing.Optional[int] = None, + cursor: typing.Optional[str] = None, + filters: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> HttpResponse[typing.List[EntityEdge]]: + ) -> SyncPager[JsonObject, JsonObjectPage]: """ - Returns all edges for a user. - Parameters ---------- - user_id : str - User ID - - cursor : typing.Optional[str] - Opaque cursor for pagination, obtained from the Zep-Next-Cursor response header - of the previous page. 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. + graph_uuid : str + Graph UUID limit : typing.Optional[int] - Maximum number of items to return + Page size - order_by : typing.Optional[str] - Field to sort by. One of "created_at", "valid_at", or "uuid" (default "uuid"). + cursor : typing.Optional[str] + Opaque page cursor - uuid_cursor : typing.Optional[str] - UUID based cursor, used for pagination. Should be the UUID of the last item in the previous page. + filters : typing.Optional[typing.Dict[str, typing.Any]] - Deprecated: prefer Cursor, the opaque cursor returned via the Zep-Next-Cursor response header. + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - HttpResponse[typing.List[EntityEdge]] - Edges + SyncPager[JsonObject, JsonObjectPage] + OK """ _response = self._client_wrapper.httpx_client.request( - f"graph/edge/user/{jsonable_encoder(user_id)}", + f"graphs/{jsonable_encoder(graph_uuid)}/edges/list", method="POST", - json={ - "cursor": cursor, - "direction": direction, - "filters": convert_and_respect_annotation_metadata( - object_=filters, annotation=SearchFilters, direction="write" - ), + params={ "limit": limit, - "order_by": order_by, - "uuid_cursor": uuid_cursor, + "cursor": cursor, + }, + json={ + "filters": filters, + }, + headers={ + "content-type": "application/json", + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, }, request_options=request_options, omit=OMIT, ) try: if 200 <= _response.status_code < 300: - _data = typing.cast( - typing.List[EntityEdge], + _parsed_response = typing.cast( + JsonObjectPage, parse_obj_as( - type_=typing.List[EntityEdge], # type: ignore + type_=JsonObjectPage, # type: ignore object_=_response.json(), ), ) - return HttpResponse(response=_response, data=_data) + _items = _parsed_response.items + _parsed_next = _parsed_response.next_cursor + _has_next = _parsed_next is not None and _parsed_next != "" + _get_next = lambda: self.list( + graph_uuid, + limit=limit, + cursor=_parsed_next, + filters=filters, + idempotency_key=idempotency_key, + request_options=request_options, + ) + return SyncPager(has_next=_has_next, items=_items, get_next=_get_next, response=_parsed_response) if _response.status_code == 400: raise BadRequestError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore object_=_response.json(), ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -234,17 +266,24 @@ def get_by_user_id( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - def get(self, uuid_: str, *, request_options: typing.Optional[RequestOptions] = None) -> HttpResponse[EntityEdge]: + def get( + self, graph_uuid: str, edge_uuid: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> HttpResponse[JsonObject]: """ - Returns a specific edge by its UUID. - Parameters ---------- - uuid_ : str + graph_uuid : str + Graph UUID + + edge_uuid : str Edge UUID request_options : typing.Optional[RequestOptions] @@ -252,20 +291,20 @@ def get(self, uuid_: str, *, request_options: typing.Optional[RequestOptions] = Returns ------- - HttpResponse[EntityEdge] - Edge + HttpResponse[JsonObject] + OK """ _response = self._client_wrapper.httpx_client.request( - f"graph/edge/{jsonable_encoder(uuid_)}", + f"graphs/{jsonable_encoder(graph_uuid)}/edges/{jsonable_encoder(edge_uuid)}", method="GET", request_options=request_options, ) try: if 200 <= _response.status_code < 300: _data = typing.cast( - EntityEdge, + JsonObject, parse_obj_as( - type_=EntityEdge, # type: ignore + type_=JsonObject, # type: ignore object_=_response.json(), ), ) @@ -274,15 +313,15 @@ def get(self, uuid_: str, *, request_options: typing.Optional[RequestOptions] = raise BadRequestError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore object_=_response.json(), ), ), ) - if _response.status_code == 404: - raise NotFoundError( + if _response.status_code == 401: + raise UnauthorizedError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -292,8 +331,8 @@ def get(self, uuid_: str, *, request_options: typing.Optional[RequestOptions] = ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -308,40 +347,55 @@ def get(self, uuid_: str, *, request_options: typing.Optional[RequestOptions] = raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) def delete( - self, uuid_: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> HttpResponse[SuccessResponse]: + self, + graph_uuid: str, + edge_uuid: str, + *, + idempotency_key: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[AsyncResult]: """ - Deletes an edge by UUID. - Parameters ---------- - uuid_ : str + graph_uuid : str + Graph UUID + + edge_uuid : str Edge UUID + idempotency_key : typing.Optional[str] + request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - HttpResponse[SuccessResponse] - Edge deleted + HttpResponse[AsyncResult] + Accepted """ _response = self._client_wrapper.httpx_client.request( - f"graph/edge/{jsonable_encoder(uuid_)}", + f"graphs/{jsonable_encoder(graph_uuid)}/edges/{jsonable_encoder(edge_uuid)}", method="DELETE", + headers={ + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, + }, request_options=request_options, ) try: if 200 <= _response.status_code < 300: _data = typing.cast( - SuccessResponse, + AsyncResult, parse_obj_as( - type_=SuccessResponse, # type: ignore + type_=AsyncResult, # type: ignore object_=_response.json(), ), ) @@ -350,15 +404,15 @@ def delete( raise BadRequestError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore object_=_response.json(), ), ), ) - if _response.status_code == 404: - raise NotFoundError( + if _response.status_code == 401: + raise UnauthorizedError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -368,8 +422,8 @@ def delete( ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -384,69 +438,58 @@ def delete( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) def update( self, - uuid_: str, + graph_uuid: str, + edge_uuid: str, *, - attributes: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = OMIT, - expired_at: typing.Optional[str] = OMIT, + attributes: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, fact: typing.Optional[str] = OMIT, - invalid_at: typing.Optional[str] = OMIT, - name: typing.Optional[str] = OMIT, - valid_at: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> HttpResponse[EntityEdge]: + ) -> HttpResponse[JsonObject]: """ - Updates an entity edge by UUID. - Parameters ---------- - uuid_ : str - Edge UUID + graph_uuid : str + Graph UUID - attributes : typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] - Updated attributes. Merged with existing attributes. Set a key to null to delete it. + edge_uuid : str + Edge UUID - expired_at : typing.Optional[str] - Updated time at which the edge expires + attributes : typing.Optional[typing.Dict[str, typing.Any]] fact : typing.Optional[str] - Updated fact for the edge + Omit to leave unchanged, send JSON null to clear, or send a value to set. - invalid_at : typing.Optional[str] - Updated time at which the fact stopped being true - - name : typing.Optional[str] - Updated name (relationship type) for the edge - - valid_at : typing.Optional[str] - Updated time at which the fact becomes true + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - HttpResponse[EntityEdge] - Updated edge + HttpResponse[JsonObject] + OK """ _response = self._client_wrapper.httpx_client.request( - f"graph/edge/{jsonable_encoder(uuid_)}", + f"graphs/{jsonable_encoder(graph_uuid)}/edges/{jsonable_encoder(edge_uuid)}", method="PATCH", json={ "attributes": attributes, - "expired_at": expired_at, "fact": fact, - "invalid_at": invalid_at, - "name": name, - "valid_at": valid_at, }, headers={ "content-type": "application/json", + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, }, request_options=request_options, omit=OMIT, @@ -454,9 +497,9 @@ def update( try: if 200 <= _response.status_code < 300: _data = typing.cast( - EntityEdge, + JsonObject, parse_obj_as( - type_=EntityEdge, # type: ignore + type_=JsonObject, # type: ignore object_=_response.json(), ), ) @@ -465,15 +508,15 @@ def update( raise BadRequestError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore object_=_response.json(), ), ), ) - if _response.status_code == 404: - raise NotFoundError( + if _response.status_code == 401: + raise UnauthorizedError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -483,8 +526,8 @@ def update( ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -499,6 +542,10 @@ def update( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) @@ -508,67 +555,73 @@ class AsyncRawEdgeClient: def __init__(self, *, client_wrapper: AsyncClientWrapper): self._client_wrapper = client_wrapper - async def get_by_graph_id( + async def add( self, - graph_id: str, + graph_uuid: 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, + attributes: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + expired_at: typing.Optional[str] = OMIT, + fact: typing.Optional[str] = OMIT, + fact_name: typing.Optional[str] = OMIT, + invalid_at: typing.Optional[str] = OMIT, + metadata: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + source_node: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + target_node: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + valid_at: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> AsyncHttpResponse[typing.List[EntityEdge]]: + ) -> AsyncHttpResponse[AddEdgeResult]: """ - Returns all edges for a graph. - Parameters ---------- - graph_id : str - Graph ID + graph_uuid : str + Graph UUID - 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. + attributes : typing.Optional[typing.Dict[str, typing.Any]] - direction : typing.Optional[str] - Sort direction. One of "asc" or "desc" (default "desc"). + expired_at : typing.Optional[str] - filters : typing.Optional[SearchFilters] - Optional filters applied to the listed artifacts. Reuses the graph.search filter type. + fact : typing.Optional[str] - limit : typing.Optional[int] - Maximum number of items to return + fact_name : typing.Optional[str] + + invalid_at : typing.Optional[str] - order_by : typing.Optional[str] - Field to sort by. One of "created_at", "valid_at", or "uuid" (default "uuid"). + metadata : typing.Optional[typing.Dict[str, typing.Any]] - uuid_cursor : typing.Optional[str] - UUID based cursor, used for pagination. Should be the UUID of the last item in the previous page. + source_node : typing.Optional[typing.Dict[str, typing.Any]] - Deprecated: prefer Cursor, the opaque cursor returned via the Zep-Next-Cursor response header. + target_node : typing.Optional[typing.Dict[str, typing.Any]] + + valid_at : typing.Optional[str] + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - AsyncHttpResponse[typing.List[EntityEdge]] - Edges + AsyncHttpResponse[AddEdgeResult] + Accepted """ _response = await self._client_wrapper.httpx_client.request( - f"graph/edge/graph/{jsonable_encoder(graph_id)}", + f"graphs/{jsonable_encoder(graph_uuid)}/edges", 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, + "attributes": attributes, + "expired_at": expired_at, + "fact": fact, + "fact_name": fact_name, + "invalid_at": invalid_at, + "metadata": metadata, + "source_node": source_node, + "target_node": target_node, + "valid_at": valid_at, + }, + headers={ + "content-type": "application/json", + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, }, request_options=request_options, omit=OMIT, @@ -576,9 +629,9 @@ async def get_by_graph_id( try: if 200 <= _response.status_code < 300: _data = typing.cast( - typing.List[EntityEdge], + AddEdgeResult, parse_obj_as( - type_=typing.List[EntityEdge], # type: ignore + type_=AddEdgeResult, # type: ignore object_=_response.json(), ), ) @@ -587,15 +640,26 @@ async def get_by_graph_id( raise BadRequestError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore object_=_response.json(), ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 401: + raise UnauthorizedError( + 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, @@ -610,98 +674,113 @@ async def get_by_graph_id( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - async def get_by_user_id( + async def list( self, - user_id: str, + graph_uuid: 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, + limit: typing.Optional[int] = None, + cursor: typing.Optional[str] = None, + filters: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> AsyncHttpResponse[typing.List[EntityEdge]]: + ) -> AsyncPager[JsonObject, JsonObjectPage]: """ - Returns all edges for a user. - Parameters ---------- - user_id : str - User ID - - cursor : typing.Optional[str] - Opaque cursor for pagination, obtained from the Zep-Next-Cursor response header - of the previous page. 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. + graph_uuid : str + Graph UUID limit : typing.Optional[int] - Maximum number of items to return + Page size - order_by : typing.Optional[str] - Field to sort by. One of "created_at", "valid_at", or "uuid" (default "uuid"). + cursor : typing.Optional[str] + Opaque page cursor - uuid_cursor : typing.Optional[str] - UUID based cursor, used for pagination. Should be the UUID of the last item in the previous page. + filters : typing.Optional[typing.Dict[str, typing.Any]] - Deprecated: prefer Cursor, the opaque cursor returned via the Zep-Next-Cursor response header. + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - AsyncHttpResponse[typing.List[EntityEdge]] - Edges + AsyncPager[JsonObject, JsonObjectPage] + OK """ _response = await self._client_wrapper.httpx_client.request( - f"graph/edge/user/{jsonable_encoder(user_id)}", + f"graphs/{jsonable_encoder(graph_uuid)}/edges/list", method="POST", - json={ - "cursor": cursor, - "direction": direction, - "filters": convert_and_respect_annotation_metadata( - object_=filters, annotation=SearchFilters, direction="write" - ), + params={ "limit": limit, - "order_by": order_by, - "uuid_cursor": uuid_cursor, + "cursor": cursor, + }, + json={ + "filters": filters, + }, + headers={ + "content-type": "application/json", + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, }, request_options=request_options, omit=OMIT, ) try: if 200 <= _response.status_code < 300: - _data = typing.cast( - typing.List[EntityEdge], + _parsed_response = typing.cast( + JsonObjectPage, parse_obj_as( - type_=typing.List[EntityEdge], # type: ignore + type_=JsonObjectPage, # type: ignore object_=_response.json(), ), ) - return AsyncHttpResponse(response=_response, data=_data) + _items = _parsed_response.items + _parsed_next = _parsed_response.next_cursor + _has_next = _parsed_next is not None and _parsed_next != "" + + async def _get_next(): + return await self.list( + graph_uuid, + limit=limit, + cursor=_parsed_next, + filters=filters, + idempotency_key=idempotency_key, + request_options=request_options, + ) + + return AsyncPager(has_next=_has_next, items=_items, get_next=_get_next, response=_parsed_response) if _response.status_code == 400: raise BadRequestError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore object_=_response.json(), ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 401: + raise UnauthorizedError( + 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, @@ -716,19 +795,24 @@ async def get_by_user_id( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) async def get( - self, uuid_: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> AsyncHttpResponse[EntityEdge]: + self, graph_uuid: str, edge_uuid: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> AsyncHttpResponse[JsonObject]: """ - Returns a specific edge by its UUID. - Parameters ---------- - uuid_ : str + graph_uuid : str + Graph UUID + + edge_uuid : str Edge UUID request_options : typing.Optional[RequestOptions] @@ -736,20 +820,20 @@ async def get( Returns ------- - AsyncHttpResponse[EntityEdge] - Edge + AsyncHttpResponse[JsonObject] + OK """ _response = await self._client_wrapper.httpx_client.request( - f"graph/edge/{jsonable_encoder(uuid_)}", + f"graphs/{jsonable_encoder(graph_uuid)}/edges/{jsonable_encoder(edge_uuid)}", method="GET", request_options=request_options, ) try: if 200 <= _response.status_code < 300: _data = typing.cast( - EntityEdge, + JsonObject, parse_obj_as( - type_=EntityEdge, # type: ignore + type_=JsonObject, # type: ignore object_=_response.json(), ), ) @@ -758,15 +842,15 @@ async def get( raise BadRequestError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore object_=_response.json(), ), ), ) - if _response.status_code == 404: - raise NotFoundError( + if _response.status_code == 401: + raise UnauthorizedError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -776,8 +860,8 @@ async def get( ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -792,40 +876,55 @@ async def get( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) async def delete( - self, uuid_: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> AsyncHttpResponse[SuccessResponse]: + self, + graph_uuid: str, + edge_uuid: str, + *, + idempotency_key: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[AsyncResult]: """ - Deletes an edge by UUID. - Parameters ---------- - uuid_ : str + graph_uuid : str + Graph UUID + + edge_uuid : str Edge UUID + idempotency_key : typing.Optional[str] + request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - AsyncHttpResponse[SuccessResponse] - Edge deleted + AsyncHttpResponse[AsyncResult] + Accepted """ _response = await self._client_wrapper.httpx_client.request( - f"graph/edge/{jsonable_encoder(uuid_)}", + f"graphs/{jsonable_encoder(graph_uuid)}/edges/{jsonable_encoder(edge_uuid)}", method="DELETE", + headers={ + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, + }, request_options=request_options, ) try: if 200 <= _response.status_code < 300: _data = typing.cast( - SuccessResponse, + AsyncResult, parse_obj_as( - type_=SuccessResponse, # type: ignore + type_=AsyncResult, # type: ignore object_=_response.json(), ), ) @@ -834,15 +933,15 @@ async def delete( raise BadRequestError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore object_=_response.json(), ), ), ) - if _response.status_code == 404: - raise NotFoundError( + if _response.status_code == 401: + raise UnauthorizedError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -852,8 +951,8 @@ async def delete( ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -868,69 +967,58 @@ async def delete( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) async def update( self, - uuid_: str, + graph_uuid: str, + edge_uuid: str, *, - attributes: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = OMIT, - expired_at: typing.Optional[str] = OMIT, + attributes: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, fact: typing.Optional[str] = OMIT, - invalid_at: typing.Optional[str] = OMIT, - name: typing.Optional[str] = OMIT, - valid_at: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> AsyncHttpResponse[EntityEdge]: + ) -> AsyncHttpResponse[JsonObject]: """ - Updates an entity edge by UUID. - Parameters ---------- - uuid_ : str - Edge UUID + graph_uuid : str + Graph UUID - attributes : typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] - Updated attributes. Merged with existing attributes. Set a key to null to delete it. + edge_uuid : str + Edge UUID - expired_at : typing.Optional[str] - Updated time at which the edge expires + attributes : typing.Optional[typing.Dict[str, typing.Any]] fact : typing.Optional[str] - Updated fact for the edge + Omit to leave unchanged, send JSON null to clear, or send a value to set. - invalid_at : typing.Optional[str] - Updated time at which the fact stopped being true - - name : typing.Optional[str] - Updated name (relationship type) for the edge - - valid_at : typing.Optional[str] - Updated time at which the fact becomes true + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - AsyncHttpResponse[EntityEdge] - Updated edge + AsyncHttpResponse[JsonObject] + OK """ _response = await self._client_wrapper.httpx_client.request( - f"graph/edge/{jsonable_encoder(uuid_)}", + f"graphs/{jsonable_encoder(graph_uuid)}/edges/{jsonable_encoder(edge_uuid)}", method="PATCH", json={ "attributes": attributes, - "expired_at": expired_at, "fact": fact, - "invalid_at": invalid_at, - "name": name, - "valid_at": valid_at, }, headers={ "content-type": "application/json", + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, }, request_options=request_options, omit=OMIT, @@ -938,9 +1026,9 @@ async def update( try: if 200 <= _response.status_code < 300: _data = typing.cast( - EntityEdge, + JsonObject, parse_obj_as( - type_=EntityEdge, # type: ignore + type_=JsonObject, # type: ignore object_=_response.json(), ), ) @@ -949,15 +1037,15 @@ async def update( raise BadRequestError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore object_=_response.json(), ), ), ) - if _response.status_code == 404: - raise NotFoundError( + if _response.status_code == 401: + raise UnauthorizedError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -967,8 +1055,8 @@ async def update( ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -983,6 +1071,10 @@ async def update( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) 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..4cd8f129 100644 --- a/src/zep_cloud/graph/episode/client.py +++ b/src/zep_cloud/graph/episode/client.py @@ -3,11 +3,12 @@ import typing from ...core.client_wrapper import AsyncClientWrapper, SyncClientWrapper +from ...core.pagination import AsyncPager, SyncPager from ...core.request_options import RequestOptions -from ...types.episode import Episode -from ...types.episode_mentions import EpisodeMentions -from ...types.episode_response import EpisodeResponse -from ...types.success_response import SuccessResponse +from ...types.add_episode_result import AddEpisodeResult +from ...types.async_result import AsyncResult +from ...types.json_object import JsonObject +from ...types.json_object_page import JsonObjectPage from .raw_client import AsyncRawEpisodeClient, RawEpisodeClient # this is used as the default value for optional parameters @@ -29,31 +30,37 @@ def with_raw_response(self) -> RawEpisodeClient: """ return self._raw_client - def get_by_graph_id( + def list_for_document( self, - graph_id: str, + graph_uuid: str, + document_id: str, *, - lastn: typing.Optional[int] = None, + limit: typing.Optional[int] = None, + cursor: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> EpisodeResponse: + ) -> SyncPager[JsonObject, JsonObjectPage]: """ - Returns episodes by graph id. - Parameters ---------- - graph_id : str - Graph ID + graph_uuid : str + Graph UUID + + document_id : str + Document ID + + limit : typing.Optional[int] + Page size - lastn : typing.Optional[int] - The number of most recent episodes to retrieve. + cursor : typing.Optional[str] + Opaque page cursor request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - EpisodeResponse - Episodes + SyncPager[JsonObject, JsonObjectPage] + OK Examples -------- @@ -62,106 +69,65 @@ def get_by_graph_id( client = Zep( api_key="YOUR_API_KEY", ) - client.graph.episode.get_by_graph_id( - graph_id="graph_id", - lastn=1, + response = client.graph.episode.list_for_document( + graph_uuid="graph_uuid", + document_id="document_id", + limit=1, + cursor="cursor", + ) + for item in response: + yield item + # alternatively, you can paginate page-by-page + for page in response.iter_pages(): + yield page + """ + return self._raw_client.list_for_document( + graph_uuid, document_id, limit=limit, cursor=cursor, request_options=request_options ) - """ - _response = self._raw_client.get_by_graph_id(graph_id, lastn=lastn, request_options=request_options) - return _response.data - def list_by_graph_id( + def add( self, - graph_id: str, + graph_uuid: str, *, - cursor: typing.Optional[str] = OMIT, - direction: typing.Optional[str] = OMIT, - limit: typing.Optional[int] = OMIT, - mentioned_node_uuids: typing.Optional[typing.Sequence[str]] = OMIT, - order_by: typing.Optional[str] = OMIT, + created_at: typing.Optional[str] = OMIT, + data: typing.Optional[str] = OMIT, + document_id: typing.Optional[str] = OMIT, + metadata: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + source_description: typing.Optional[str] = OMIT, + strict_ontology: typing.Optional[bool] = OMIT, + type: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> typing.List[Episode]: + ) -> AddEpisodeResult: """ - Returns a paginated, filterable list of episodes for a graph. - Parameters ---------- - graph_id : str - Graph ID + graph_uuid : str + Graph UUID - cursor : typing.Optional[str] - Opaque cursor for pagination, obtained from the Zep-Next-Cursor - response header of the previous page. - - direction : typing.Optional[str] - Sort direction. One of "asc" or "desc". Defaults to "desc". + created_at : typing.Optional[str] - 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. + data : typing.Optional[str] - 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. + document_id : typing.Optional[str] - order_by : typing.Optional[str] - Field to sort by. One of "uuid" or "created_at". Defaults to "uuid". + metadata : typing.Optional[typing.Dict[str, typing.Any]] - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - typing.List[Episode] - Episodes - - Examples - -------- - from zep_cloud import Zep - - client = Zep( - api_key="YOUR_API_KEY", - ) - client.graph.episode.list_by_graph_id( - graph_id="graph_id", - ) - """ - _response = self._raw_client.list_by_graph_id( - graph_id, - cursor=cursor, - direction=direction, - limit=limit, - mentioned_node_uuids=mentioned_node_uuids, - order_by=order_by, - request_options=request_options, - ) - return _response.data + source_description : typing.Optional[str] - def get_by_user_id( - self, - user_id: str, - *, - lastn: typing.Optional[int] = None, - request_options: typing.Optional[RequestOptions] = None, - ) -> EpisodeResponse: - """ - Returns episodes by user id. + strict_ontology : typing.Optional[bool] - Parameters - ---------- - user_id : str - User ID + type : typing.Optional[str] - lastn : typing.Optional[int] - The number of most recent episodes entries to retrieve. + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - EpisodeResponse - Episodes + AddEpisodeResult + Accepted Examples -------- @@ -170,58 +136,57 @@ def get_by_user_id( client = Zep( api_key="YOUR_API_KEY", ) - client.graph.episode.get_by_user_id( - user_id="user_id", - lastn=1, + client.graph.episode.add( + graph_uuid="graph_uuid", ) """ - _response = self._raw_client.get_by_user_id(user_id, lastn=lastn, request_options=request_options) + _response = self._raw_client.add( + graph_uuid, + created_at=created_at, + data=data, + document_id=document_id, + metadata=metadata, + source_description=source_description, + strict_ontology=strict_ontology, + type=type, + idempotency_key=idempotency_key, + request_options=request_options, + ) return _response.data - def list_by_user_id( + def list( self, - user_id: str, + graph_uuid: str, *, - cursor: typing.Optional[str] = OMIT, - direction: typing.Optional[str] = OMIT, - limit: typing.Optional[int] = OMIT, - mentioned_node_uuids: typing.Optional[typing.Sequence[str]] = OMIT, - order_by: typing.Optional[str] = OMIT, + limit: typing.Optional[int] = None, + cursor: typing.Optional[str] = None, + filters: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> typing.List[Episode]: + ) -> SyncPager[JsonObject, JsonObjectPage]: """ - Returns a paginated, filterable list of episodes for a user's graph. - Parameters ---------- - user_id : str - User ID - - cursor : typing.Optional[str] - Opaque cursor for pagination, obtained from the Zep-Next-Cursor - response header of the previous page. - - direction : typing.Optional[str] - Sort direction. One of "asc" or "desc". Defaults to "desc". + graph_uuid : str + Graph UUID 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. + Page size + + cursor : typing.Optional[str] + Opaque page cursor - 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. + filters : typing.Optional[typing.Dict[str, typing.Any]] - order_by : typing.Optional[str] - Field to sort by. One of "uuid" or "created_at". Defaults to "uuid". + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - typing.List[Episode] - Episodes + SyncPager[JsonObject, JsonObjectPage] + OK Examples -------- @@ -230,28 +195,36 @@ def list_by_user_id( client = Zep( api_key="YOUR_API_KEY", ) - client.graph.episode.list_by_user_id( - user_id="user_id", + response = client.graph.episode.list( + graph_uuid="graph_uuid", + limit=1, + cursor="cursor", ) - """ - _response = self._raw_client.list_by_user_id( - user_id, - cursor=cursor, - direction=direction, + for item in response: + yield item + # alternatively, you can paginate page-by-page + for page in response.iter_pages(): + yield page + """ + return self._raw_client.list( + graph_uuid, limit=limit, - mentioned_node_uuids=mentioned_node_uuids, - order_by=order_by, + cursor=cursor, + filters=filters, + idempotency_key=idempotency_key, request_options=request_options, ) - return _response.data - def get(self, uuid_: str, *, request_options: typing.Optional[RequestOptions] = None) -> Episode: + def get( + self, graph_uuid: str, episode_uuid: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> JsonObject: """ - Returns episodes by UUID - Parameters ---------- - uuid_ : str + graph_uuid : str + Graph UUID + + episode_uuid : str Episode UUID request_options : typing.Optional[RequestOptions] @@ -259,8 +232,8 @@ def get(self, uuid_: str, *, request_options: typing.Optional[RequestOptions] = Returns ------- - Episode - Episode + JsonObject + OK Examples -------- @@ -270,28 +243,39 @@ def get(self, uuid_: str, *, request_options: typing.Optional[RequestOptions] = api_key="YOUR_API_KEY", ) client.graph.episode.get( - uuid_="uuid", + graph_uuid="graph_uuid", + episode_uuid="episode_uuid", ) """ - _response = self._raw_client.get(uuid_, request_options=request_options) + _response = self._raw_client.get(graph_uuid, episode_uuid, request_options=request_options) return _response.data - def delete(self, uuid_: str, *, request_options: typing.Optional[RequestOptions] = None) -> SuccessResponse: + def delete( + self, + graph_uuid: str, + episode_uuid: str, + *, + idempotency_key: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncResult: """ - Deletes an episode by its UUID. - Parameters ---------- - uuid_ : str + graph_uuid : str + Graph UUID + + episode_uuid : str Episode UUID + idempotency_key : typing.Optional[str] + request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - SuccessResponse - Episode deleted + AsyncResult + Accepted Examples -------- @@ -301,37 +285,44 @@ def delete(self, uuid_: str, *, request_options: typing.Optional[RequestOptions] api_key="YOUR_API_KEY", ) client.graph.episode.delete( - uuid_="uuid", + graph_uuid="graph_uuid", + episode_uuid="episode_uuid", ) """ - _response = self._raw_client.delete(uuid_, request_options=request_options) + _response = self._raw_client.delete( + graph_uuid, episode_uuid, idempotency_key=idempotency_key, request_options=request_options + ) return _response.data def update( self, - uuid_: str, + graph_uuid: str, + episode_uuid: str, *, - metadata: typing.Dict[str, typing.Optional[typing.Any]], + metadata: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> Episode: + ) -> JsonObject: """ - Update episode metadata with merge semantics. Supplied keys overwrite or add to existing metadata; keys set to null are removed. - Parameters ---------- - uuid_ : str + graph_uuid : str + Graph UUID + + episode_uuid : str Episode UUID - metadata : typing.Dict[str, typing.Optional[typing.Any]] - Updated metadata. Merged with existing metadata: supplied keys overwrite/add, keys set to null are removed. Maximum 10 keys. Values must be scalars (string, number, boolean, null) or arrays of scalars. + metadata : typing.Optional[typing.Dict[str, typing.Any]] + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - Episode - Updated episode + JsonObject + OK Examples -------- @@ -341,44 +332,17 @@ def update( api_key="YOUR_API_KEY", ) client.graph.episode.update( - uuid_="uuid", - metadata={"key": "value"}, + graph_uuid="graph_uuid", + episode_uuid="episode_uuid", ) """ - _response = self._raw_client.update(uuid_, metadata=metadata, request_options=request_options) - return _response.data - - def get_nodes_and_edges( - self, uuid_: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> EpisodeMentions: - """ - Deprecated. Use edge and node listing with `filters.episode_uuids` instead. Returns nodes and edges mentioned in an episode, subject to an internal cap; responses reduced by that cap set the Zep-Truncated header. - - Parameters - ---------- - uuid_ : str - Episode uuid - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - EpisodeMentions - Edges and nodes mentioned in an episode - - Examples - -------- - from zep_cloud import Zep - - client = Zep( - api_key="YOUR_API_KEY", - ) - client.graph.episode.get_nodes_and_edges( - uuid_="uuid", + _response = self._raw_client.update( + graph_uuid, + episode_uuid, + metadata=metadata, + idempotency_key=idempotency_key, + request_options=request_options, ) - """ - _response = self._raw_client.get_nodes_and_edges(uuid_, request_options=request_options) return _response.data @@ -397,31 +361,37 @@ def with_raw_response(self) -> AsyncRawEpisodeClient: """ return self._raw_client - async def get_by_graph_id( + async def list_for_document( self, - graph_id: str, + graph_uuid: str, + document_id: str, *, - lastn: typing.Optional[int] = None, + limit: typing.Optional[int] = None, + cursor: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> EpisodeResponse: + ) -> AsyncPager[JsonObject, JsonObjectPage]: """ - Returns episodes by graph id. - Parameters ---------- - graph_id : str - Graph ID + graph_uuid : str + Graph UUID + + document_id : str + Document ID - lastn : typing.Optional[int] - The number of most recent episodes to retrieve. + limit : typing.Optional[int] + Page size + + cursor : typing.Optional[str] + Opaque page cursor request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - EpisodeResponse - Episodes + AsyncPager[JsonObject, JsonObjectPage] + OK Examples -------- @@ -435,117 +405,69 @@ async def get_by_graph_id( async def main() -> None: - await client.graph.episode.get_by_graph_id( - graph_id="graph_id", - lastn=1, + response = await client.graph.episode.list_for_document( + graph_uuid="graph_uuid", + document_id="document_id", + limit=1, + cursor="cursor", ) + async for item in response: + yield item + + # alternatively, you can paginate page-by-page + async for page in response.iter_pages(): + yield page asyncio.run(main()) """ - _response = await self._raw_client.get_by_graph_id(graph_id, lastn=lastn, request_options=request_options) - return _response.data + return await self._raw_client.list_for_document( + graph_uuid, document_id, limit=limit, cursor=cursor, request_options=request_options + ) - async def list_by_graph_id( + async def add( self, - graph_id: str, + graph_uuid: str, *, - cursor: typing.Optional[str] = OMIT, - direction: typing.Optional[str] = OMIT, - limit: typing.Optional[int] = OMIT, - mentioned_node_uuids: typing.Optional[typing.Sequence[str]] = OMIT, - order_by: typing.Optional[str] = OMIT, + created_at: typing.Optional[str] = OMIT, + data: typing.Optional[str] = OMIT, + document_id: typing.Optional[str] = OMIT, + metadata: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + source_description: typing.Optional[str] = OMIT, + strict_ontology: typing.Optional[bool] = OMIT, + type: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> typing.List[Episode]: + ) -> AddEpisodeResult: """ - Returns a paginated, filterable list of episodes for a graph. - Parameters ---------- - graph_id : str - Graph ID - - cursor : typing.Optional[str] - Opaque cursor for pagination, obtained from the Zep-Next-Cursor - response header of the previous page. - - direction : typing.Optional[str] - Sort direction. One of "asc" or "desc". Defaults to "desc". - - limit : typing.Optional[int] - Maximum number of episodes to return. An explicit value is clamped to - 50; when omitted, the default page size (100) applies. + graph_uuid : str + Graph UUID - mentioned_node_uuids : typing.Optional[typing.Sequence[str]] - Restricts results to episodes that mention any of the listed node - UUIDs. At most 256 entries; each must be a syntactically valid UUID. - - order_by : typing.Optional[str] - Field to sort by. One of "uuid" or "created_at". Defaults to "uuid". - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - typing.List[Episode] - Episodes - - Examples - -------- - import asyncio - - from zep_cloud import AsyncZep - - client = AsyncZep( - api_key="YOUR_API_KEY", - ) + created_at : typing.Optional[str] + data : typing.Optional[str] - async def main() -> None: - await client.graph.episode.list_by_graph_id( - graph_id="graph_id", - ) + document_id : typing.Optional[str] + metadata : typing.Optional[typing.Dict[str, typing.Any]] - asyncio.run(main()) - """ - _response = await self._raw_client.list_by_graph_id( - graph_id, - cursor=cursor, - direction=direction, - limit=limit, - mentioned_node_uuids=mentioned_node_uuids, - order_by=order_by, - request_options=request_options, - ) - return _response.data + source_description : typing.Optional[str] - async def get_by_user_id( - self, - user_id: str, - *, - lastn: typing.Optional[int] = None, - request_options: typing.Optional[RequestOptions] = None, - ) -> EpisodeResponse: - """ - Returns episodes by user id. + strict_ontology : typing.Optional[bool] - Parameters - ---------- - user_id : str - User ID + type : typing.Optional[str] - lastn : typing.Optional[int] - The number of most recent episodes entries to retrieve. + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - EpisodeResponse - Episodes + AddEpisodeResult + Accepted Examples -------- @@ -559,61 +481,60 @@ async def get_by_user_id( async def main() -> None: - await client.graph.episode.get_by_user_id( - user_id="user_id", - lastn=1, + await client.graph.episode.add( + graph_uuid="graph_uuid", ) asyncio.run(main()) """ - _response = await self._raw_client.get_by_user_id(user_id, lastn=lastn, request_options=request_options) + _response = await self._raw_client.add( + graph_uuid, + created_at=created_at, + data=data, + document_id=document_id, + metadata=metadata, + source_description=source_description, + strict_ontology=strict_ontology, + type=type, + idempotency_key=idempotency_key, + request_options=request_options, + ) return _response.data - async def list_by_user_id( + async def list( self, - user_id: str, + graph_uuid: str, *, - cursor: typing.Optional[str] = OMIT, - direction: typing.Optional[str] = OMIT, - limit: typing.Optional[int] = OMIT, - mentioned_node_uuids: typing.Optional[typing.Sequence[str]] = OMIT, - order_by: typing.Optional[str] = OMIT, + limit: typing.Optional[int] = None, + cursor: typing.Optional[str] = None, + filters: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> typing.List[Episode]: + ) -> AsyncPager[JsonObject, JsonObjectPage]: """ - Returns a paginated, filterable list of episodes for a user's graph. - Parameters ---------- - user_id : str - User ID - - cursor : typing.Optional[str] - Opaque cursor for pagination, obtained from the Zep-Next-Cursor - response header of the previous page. - - direction : typing.Optional[str] - Sort direction. One of "asc" or "desc". Defaults to "desc". + graph_uuid : str + Graph UUID 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. + Page size + + cursor : typing.Optional[str] + Opaque page cursor - 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. + filters : typing.Optional[typing.Dict[str, typing.Any]] - order_by : typing.Optional[str] - Field to sort by. One of "uuid" or "created_at". Defaults to "uuid". + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - typing.List[Episode] - Episodes + AsyncPager[JsonObject, JsonObjectPage] + OK Examples -------- @@ -627,31 +548,40 @@ async def list_by_user_id( async def main() -> None: - await client.graph.episode.list_by_user_id( - user_id="user_id", + response = await client.graph.episode.list( + graph_uuid="graph_uuid", + limit=1, + cursor="cursor", ) + async for item in response: + yield item + + # alternatively, you can paginate page-by-page + async for page in response.iter_pages(): + yield page asyncio.run(main()) """ - _response = await self._raw_client.list_by_user_id( - user_id, - cursor=cursor, - direction=direction, + return await self._raw_client.list( + graph_uuid, limit=limit, - mentioned_node_uuids=mentioned_node_uuids, - order_by=order_by, + cursor=cursor, + filters=filters, + idempotency_key=idempotency_key, request_options=request_options, ) - return _response.data - async def get(self, uuid_: str, *, request_options: typing.Optional[RequestOptions] = None) -> Episode: + async def get( + self, graph_uuid: str, episode_uuid: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> JsonObject: """ - Returns episodes by UUID - Parameters ---------- - uuid_ : str + graph_uuid : str + Graph UUID + + episode_uuid : str Episode UUID request_options : typing.Optional[RequestOptions] @@ -659,8 +589,8 @@ async def get(self, uuid_: str, *, request_options: typing.Optional[RequestOptio Returns ------- - Episode - Episode + JsonObject + OK Examples -------- @@ -675,31 +605,42 @@ async def get(self, uuid_: str, *, request_options: typing.Optional[RequestOptio async def main() -> None: await client.graph.episode.get( - uuid_="uuid", + graph_uuid="graph_uuid", + episode_uuid="episode_uuid", ) asyncio.run(main()) """ - _response = await self._raw_client.get(uuid_, request_options=request_options) + _response = await self._raw_client.get(graph_uuid, episode_uuid, request_options=request_options) return _response.data - async def delete(self, uuid_: str, *, request_options: typing.Optional[RequestOptions] = None) -> SuccessResponse: + async def delete( + self, + graph_uuid: str, + episode_uuid: str, + *, + idempotency_key: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncResult: """ - Deletes an episode by its UUID. - Parameters ---------- - uuid_ : str + graph_uuid : str + Graph UUID + + episode_uuid : str Episode UUID + idempotency_key : typing.Optional[str] + request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - SuccessResponse - Episode deleted + AsyncResult + Accepted Examples -------- @@ -714,40 +655,47 @@ async def delete(self, uuid_: str, *, request_options: typing.Optional[RequestOp async def main() -> None: await client.graph.episode.delete( - uuid_="uuid", + graph_uuid="graph_uuid", + episode_uuid="episode_uuid", ) asyncio.run(main()) """ - _response = await self._raw_client.delete(uuid_, request_options=request_options) + _response = await self._raw_client.delete( + graph_uuid, episode_uuid, idempotency_key=idempotency_key, request_options=request_options + ) return _response.data async def update( self, - uuid_: str, + graph_uuid: str, + episode_uuid: str, *, - metadata: typing.Dict[str, typing.Optional[typing.Any]], + metadata: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> Episode: + ) -> JsonObject: """ - Update episode metadata with merge semantics. Supplied keys overwrite or add to existing metadata; keys set to null are removed. - Parameters ---------- - uuid_ : str + graph_uuid : str + Graph UUID + + episode_uuid : str Episode UUID - metadata : typing.Dict[str, typing.Optional[typing.Any]] - Updated metadata. Merged with existing metadata: supplied keys overwrite/add, keys set to null are removed. Maximum 10 keys. Values must be scalars (string, number, boolean, null) or arrays of scalars. + metadata : typing.Optional[typing.Dict[str, typing.Any]] + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - Episode - Updated episode + JsonObject + OK Examples -------- @@ -762,53 +710,18 @@ async def update( async def main() -> None: await client.graph.episode.update( - uuid_="uuid", - metadata={"key": "value"}, + graph_uuid="graph_uuid", + episode_uuid="episode_uuid", ) asyncio.run(main()) """ - _response = await self._raw_client.update(uuid_, metadata=metadata, request_options=request_options) - return _response.data - - async def get_nodes_and_edges( - self, uuid_: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> EpisodeMentions: - """ - Deprecated. Use edge and node listing with `filters.episode_uuids` instead. Returns nodes and edges mentioned in an episode, subject to an internal cap; responses reduced by that cap set the Zep-Truncated header. - - Parameters - ---------- - uuid_ : str - Episode uuid - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - EpisodeMentions - Edges and nodes mentioned in an episode - - Examples - -------- - import asyncio - - from zep_cloud import AsyncZep - - client = AsyncZep( - api_key="YOUR_API_KEY", + _response = await self._raw_client.update( + graph_uuid, + episode_uuid, + metadata=metadata, + idempotency_key=idempotency_key, + request_options=request_options, ) - - - async def main() -> None: - await client.graph.episode.get_nodes_and_edges( - uuid_="uuid", - ) - - - asyncio.run(main()) - """ - _response = await self._raw_client.get_nodes_and_edges(uuid_, request_options=request_options) return _response.data diff --git a/src/zep_cloud/graph/episode/raw_client.py b/src/zep_cloud/graph/episode/raw_client.py index 0c449529..e52745b5 100644 --- a/src/zep_cloud/graph/episode/raw_client.py +++ b/src/zep_cloud/graph/episode/raw_client.py @@ -7,17 +7,19 @@ from ...core.client_wrapper import AsyncClientWrapper, SyncClientWrapper from ...core.http_response import AsyncHttpResponse, HttpResponse from ...core.jsonable_encoder import jsonable_encoder +from ...core.pagination import AsyncPager, SyncPager +from ...core.parse_error import ParsingError from ...core.pydantic_utilities import parse_obj_as from ...core.request_options import RequestOptions from ...errors.bad_request_error import BadRequestError -from ...errors.forbidden_error import ForbiddenError -from ...errors.internal_server_error import InternalServerError from ...errors.not_found_error import NotFoundError +from ...errors.unauthorized_error import UnauthorizedError +from ...types.add_episode_result import AddEpisodeResult from ...types.api_error import ApiError as types_api_error_ApiError -from ...types.episode import Episode -from ...types.episode_mentions import EpisodeMentions -from ...types.episode_response import EpisodeResponse -from ...types.success_response import SuccessResponse +from ...types.async_result import AsyncResult +from ...types.json_object import JsonObject +from ...types.json_object_page import JsonObjectPage +from pydantic import ValidationError # this is used as the default value for optional parameters OMIT = typing.cast(typing.Any, ...) @@ -27,63 +29,91 @@ class RawEpisodeClient: def __init__(self, *, client_wrapper: SyncClientWrapper): self._client_wrapper = client_wrapper - def get_by_graph_id( + def list_for_document( self, - graph_id: str, + graph_uuid: str, + document_id: str, *, - lastn: typing.Optional[int] = None, + limit: typing.Optional[int] = None, + cursor: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> HttpResponse[EpisodeResponse]: + ) -> SyncPager[JsonObject, JsonObjectPage]: """ - Returns episodes by graph id. - Parameters ---------- - graph_id : str - Graph ID + graph_uuid : str + Graph UUID + + document_id : str + Document ID - lastn : typing.Optional[int] - The number of most recent episodes to retrieve. + limit : typing.Optional[int] + Page size + + cursor : typing.Optional[str] + Opaque page cursor request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - HttpResponse[EpisodeResponse] - Episodes + SyncPager[JsonObject, JsonObjectPage] + OK """ _response = self._client_wrapper.httpx_client.request( - f"graph/episodes/graph/{jsonable_encoder(graph_id)}", + f"graphs/{jsonable_encoder(graph_uuid)}/documents/{jsonable_encoder(document_id)}/episodes", method="GET", params={ - "lastn": lastn, + "limit": limit, + "cursor": cursor, }, request_options=request_options, ) try: if 200 <= _response.status_code < 300: - _data = typing.cast( - EpisodeResponse, + _parsed_response = typing.cast( + JsonObjectPage, parse_obj_as( - type_=EpisodeResponse, # type: ignore + type_=JsonObjectPage, # type: ignore object_=_response.json(), ), ) - return HttpResponse(response=_response, data=_data) + _items = _parsed_response.items + _parsed_next = _parsed_response.next_cursor + _has_next = _parsed_next is not None and _parsed_next != "" + _get_next = lambda: self.list_for_document( + graph_uuid, + document_id, + limit=limit, + cursor=_parsed_next, + request_options=request_options, + ) + return SyncPager(has_next=_has_next, items=_items, get_next=_get_next, response=_parsed_response) if _response.status_code == 400: raise BadRequestError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore object_=_response.json(), ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 401: + raise UnauthorizedError( + 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, @@ -98,64 +128,73 @@ def get_by_graph_id( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - def list_by_graph_id( + def add( self, - graph_id: str, + graph_uuid: str, *, - cursor: typing.Optional[str] = OMIT, - direction: typing.Optional[str] = OMIT, - limit: typing.Optional[int] = OMIT, - mentioned_node_uuids: typing.Optional[typing.Sequence[str]] = OMIT, - order_by: typing.Optional[str] = OMIT, + created_at: typing.Optional[str] = OMIT, + data: typing.Optional[str] = OMIT, + document_id: typing.Optional[str] = OMIT, + metadata: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + source_description: typing.Optional[str] = OMIT, + strict_ontology: typing.Optional[bool] = OMIT, + type: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> HttpResponse[typing.List[Episode]]: + ) -> HttpResponse[AddEpisodeResult]: """ - Returns a paginated, filterable list of episodes for a graph. - Parameters ---------- - graph_id : str - Graph ID + graph_uuid : str + Graph UUID - cursor : typing.Optional[str] - Opaque cursor for pagination, obtained from the Zep-Next-Cursor - response header of the previous page. + created_at : typing.Optional[str] - direction : typing.Optional[str] - Sort direction. One of "asc" or "desc". Defaults to "desc". + data : typing.Optional[str] - 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. + document_id : typing.Optional[str] - 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. + metadata : typing.Optional[typing.Dict[str, typing.Any]] - order_by : typing.Optional[str] - Field to sort by. One of "uuid" or "created_at". Defaults to "uuid". + source_description : typing.Optional[str] + + strict_ontology : typing.Optional[bool] + + type : typing.Optional[str] + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - HttpResponse[typing.List[Episode]] - Episodes + HttpResponse[AddEpisodeResult] + Accepted """ _response = self._client_wrapper.httpx_client.request( - f"graph/episodes/graph/{jsonable_encoder(graph_id)}", + f"graphs/{jsonable_encoder(graph_uuid)}/episodes", method="POST", json={ - "cursor": cursor, - "direction": direction, - "limit": limit, - "mentioned_node_uuids": mentioned_node_uuids, - "order_by": order_by, + "created_at": created_at, + "data": data, + "document_id": document_id, + "metadata": metadata, + "source_description": source_description, + "strict_ontology": strict_ontology, + "type": type, + }, + headers={ + "content-type": "application/json", + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, }, request_options=request_options, omit=OMIT, @@ -163,26 +202,15 @@ def list_by_graph_id( try: if 200 <= _response.status_code < 300: _data = typing.cast( - typing.List[Episode], + AddEpisodeResult, parse_obj_as( - type_=typing.List[Episode], # type: ignore + type_=AddEpisodeResult, # type: ignore object_=_response.json(), ), ) return HttpResponse(response=_response, data=_data) if _response.status_code == 400: raise BadRequestError( - headers=dict(_response.headers), - body=typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ), - ) - if _response.status_code == 500: - raise InternalServerError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -192,72 +220,19 @@ def list_by_graph_id( ), ), ) - _response_json = _response.json() - except JSONDecodeError: - raise core_api_error_ApiError( - status_code=_response.status_code, headers=dict(_response.headers), body=_response.text - ) - raise core_api_error_ApiError( - status_code=_response.status_code, headers=dict(_response.headers), body=_response_json - ) - - def get_by_user_id( - self, - user_id: str, - *, - lastn: typing.Optional[int] = None, - request_options: typing.Optional[RequestOptions] = None, - ) -> HttpResponse[EpisodeResponse]: - """ - Returns episodes by user id. - - Parameters - ---------- - user_id : str - User ID - - lastn : typing.Optional[int] - The number of most recent episodes entries to retrieve. - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - HttpResponse[EpisodeResponse] - Episodes - """ - _response = self._client_wrapper.httpx_client.request( - f"graph/episodes/user/{jsonable_encoder(user_id)}", - method="GET", - params={ - "lastn": lastn, - }, - 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( + if _response.status_code == 401: + raise UnauthorizedError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore object_=_response.json(), ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -272,91 +247,110 @@ def get_by_user_id( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - def list_by_user_id( + def list( self, - user_id: str, + graph_uuid: str, *, - cursor: typing.Optional[str] = OMIT, - direction: typing.Optional[str] = OMIT, - limit: typing.Optional[int] = OMIT, - mentioned_node_uuids: typing.Optional[typing.Sequence[str]] = OMIT, - order_by: typing.Optional[str] = OMIT, + limit: typing.Optional[int] = None, + cursor: typing.Optional[str] = None, + filters: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> HttpResponse[typing.List[Episode]]: + ) -> SyncPager[JsonObject, JsonObjectPage]: """ - Returns a paginated, filterable list of episodes for a user's graph. - Parameters ---------- - user_id : str - User ID - - cursor : typing.Optional[str] - Opaque cursor for pagination, obtained from the Zep-Next-Cursor - response header of the previous page. - - direction : typing.Optional[str] - Sort direction. One of "asc" or "desc". Defaults to "desc". + graph_uuid : str + Graph UUID 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. + Page size + + cursor : typing.Optional[str] + Opaque page cursor - 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. + filters : typing.Optional[typing.Dict[str, typing.Any]] - order_by : typing.Optional[str] - Field to sort by. One of "uuid" or "created_at". Defaults to "uuid". + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - HttpResponse[typing.List[Episode]] - Episodes + SyncPager[JsonObject, JsonObjectPage] + OK """ _response = self._client_wrapper.httpx_client.request( - f"graph/episodes/user/{jsonable_encoder(user_id)}", + f"graphs/{jsonable_encoder(graph_uuid)}/episodes/list", method="POST", - json={ - "cursor": cursor, - "direction": direction, + params={ "limit": limit, - "mentioned_node_uuids": mentioned_node_uuids, - "order_by": order_by, + "cursor": cursor, + }, + json={ + "filters": filters, + }, + headers={ + "content-type": "application/json", + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, }, request_options=request_options, omit=OMIT, ) try: if 200 <= _response.status_code < 300: - _data = typing.cast( - typing.List[Episode], + _parsed_response = typing.cast( + JsonObjectPage, parse_obj_as( - type_=typing.List[Episode], # type: ignore + type_=JsonObjectPage, # type: ignore object_=_response.json(), ), ) - return HttpResponse(response=_response, data=_data) + _items = _parsed_response.items + _parsed_next = _parsed_response.next_cursor + _has_next = _parsed_next is not None and _parsed_next != "" + _get_next = lambda: self.list( + graph_uuid, + limit=limit, + cursor=_parsed_next, + filters=filters, + idempotency_key=idempotency_key, + request_options=request_options, + ) + return SyncPager(has_next=_has_next, items=_items, get_next=_get_next, response=_parsed_response) if _response.status_code == 400: raise BadRequestError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + 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( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -371,17 +365,24 @@ def list_by_user_id( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - def get(self, uuid_: str, *, request_options: typing.Optional[RequestOptions] = None) -> HttpResponse[Episode]: + def get( + self, graph_uuid: str, episode_uuid: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> HttpResponse[JsonObject]: """ - Returns episodes by UUID - Parameters ---------- - uuid_ : str + graph_uuid : str + Graph UUID + + episode_uuid : str Episode UUID request_options : typing.Optional[RequestOptions] @@ -389,20 +390,20 @@ def get(self, uuid_: str, *, request_options: typing.Optional[RequestOptions] = Returns ------- - HttpResponse[Episode] - Episode + HttpResponse[JsonObject] + OK """ _response = self._client_wrapper.httpx_client.request( - f"graph/episodes/{jsonable_encoder(uuid_)}", + f"graphs/{jsonable_encoder(graph_uuid)}/episodes/{jsonable_encoder(episode_uuid)}", method="GET", request_options=request_options, ) try: if 200 <= _response.status_code < 300: _data = typing.cast( - Episode, + JsonObject, parse_obj_as( - type_=Episode, # type: ignore + type_=JsonObject, # type: ignore object_=_response.json(), ), ) @@ -411,15 +412,26 @@ def get(self, uuid_: str, *, request_options: typing.Optional[RequestOptions] = raise BadRequestError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore object_=_response.json(), ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 401: + raise UnauthorizedError( + 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, @@ -434,40 +446,55 @@ def get(self, uuid_: str, *, request_options: typing.Optional[RequestOptions] = raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) def delete( - self, uuid_: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> HttpResponse[SuccessResponse]: + self, + graph_uuid: str, + episode_uuid: str, + *, + idempotency_key: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[AsyncResult]: """ - Deletes an episode by its UUID. - Parameters ---------- - uuid_ : str + graph_uuid : str + Graph UUID + + episode_uuid : str Episode UUID + idempotency_key : typing.Optional[str] + request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - HttpResponse[SuccessResponse] - Episode deleted + HttpResponse[AsyncResult] + Accepted """ _response = self._client_wrapper.httpx_client.request( - f"graph/episodes/{jsonable_encoder(uuid_)}", + f"graphs/{jsonable_encoder(graph_uuid)}/episodes/{jsonable_encoder(episode_uuid)}", method="DELETE", + headers={ + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, + }, request_options=request_options, ) try: if 200 <= _response.status_code < 300: _data = typing.cast( - SuccessResponse, + AsyncResult, parse_obj_as( - type_=SuccessResponse, # type: ignore + type_=AsyncResult, # type: ignore object_=_response.json(), ), ) @@ -476,15 +503,15 @@ def delete( raise BadRequestError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore object_=_response.json(), ), ), ) - if _response.status_code == 404: - raise NotFoundError( + if _response.status_code == 401: + raise UnauthorizedError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -494,8 +521,8 @@ def delete( ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -510,44 +537,53 @@ def delete( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) def update( self, - uuid_: str, + graph_uuid: str, + episode_uuid: str, *, - metadata: typing.Dict[str, typing.Optional[typing.Any]], + metadata: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> HttpResponse[Episode]: + ) -> HttpResponse[JsonObject]: """ - Update episode metadata with merge semantics. Supplied keys overwrite or add to existing metadata; keys set to null are removed. - Parameters ---------- - uuid_ : str + graph_uuid : str + Graph UUID + + episode_uuid : str Episode UUID - metadata : typing.Dict[str, typing.Optional[typing.Any]] - Updated metadata. Merged with existing metadata: supplied keys overwrite/add, keys set to null are removed. Maximum 10 keys. Values must be scalars (string, number, boolean, null) or arrays of scalars. + metadata : typing.Optional[typing.Dict[str, typing.Any]] + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - HttpResponse[Episode] - Updated episode + HttpResponse[JsonObject] + OK """ _response = self._client_wrapper.httpx_client.request( - f"graph/episodes/{jsonable_encoder(uuid_)}", + f"graphs/{jsonable_encoder(graph_uuid)}/episodes/{jsonable_encoder(episode_uuid)}", method="PATCH", json={ "metadata": metadata, }, headers={ "content-type": "application/json", + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, }, request_options=request_options, omit=OMIT, @@ -555,26 +591,15 @@ def update( try: if 200 <= _response.status_code < 300: _data = typing.cast( - Episode, + JsonObject, parse_obj_as( - type_=Episode, # type: ignore + type_=JsonObject, # type: ignore object_=_response.json(), ), ) return HttpResponse(response=_response, data=_data) if _response.status_code == 400: raise BadRequestError( - headers=dict(_response.headers), - body=typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ), - ) - if _response.status_code == 403: - raise ForbiddenError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -584,8 +609,8 @@ def update( ), ), ) - if _response.status_code == 404: - raise NotFoundError( + if _response.status_code == 401: + raise UnauthorizedError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -595,8 +620,8 @@ def update( ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -611,70 +636,9 @@ def update( 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_nodes_and_edges( - self, uuid_: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> HttpResponse[EpisodeMentions]: - """ - Deprecated. Use edge and node listing with `filters.episode_uuids` instead. Returns nodes and edges mentioned in an episode, subject to an internal cap; responses reduced by that cap set the Zep-Truncated header. - - Parameters - ---------- - uuid_ : str - Episode uuid - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - HttpResponse[EpisodeMentions] - Edges and nodes mentioned in an episode - """ - _response = self._client_wrapper.httpx_client.request( - f"graph/episodes/{jsonable_encoder(uuid_)}/mentions", - method="GET", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - _data = typing.cast( - EpisodeMentions, - parse_obj_as( - type_=EpisodeMentions, # type: ignore - object_=_response.json(), - ), - ) - return HttpResponse(response=_response, data=_data) - if _response.status_code == 400: - raise BadRequestError( - headers=dict(_response.headers), - body=typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ), - ) - if _response.status_code == 500: - raise InternalServerError( - headers=dict(_response.headers), - body=typing.cast( - types_api_error_ApiError, - parse_obj_as( - type_=types_api_error_ApiError, # type: ignore - object_=_response.json(), - ), - ), - ) - _response_json = _response.json() - except JSONDecodeError: - raise core_api_error_ApiError( - status_code=_response.status_code, headers=dict(_response.headers), body=_response.text + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json @@ -685,63 +649,94 @@ class AsyncRawEpisodeClient: def __init__(self, *, client_wrapper: AsyncClientWrapper): self._client_wrapper = client_wrapper - async def get_by_graph_id( + async def list_for_document( self, - graph_id: str, + graph_uuid: str, + document_id: str, *, - lastn: typing.Optional[int] = None, + limit: typing.Optional[int] = None, + cursor: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> AsyncHttpResponse[EpisodeResponse]: + ) -> AsyncPager[JsonObject, JsonObjectPage]: """ - Returns episodes by graph id. - Parameters ---------- - graph_id : str - Graph ID + graph_uuid : str + Graph UUID - lastn : typing.Optional[int] - The number of most recent episodes to retrieve. + document_id : str + Document ID + + limit : typing.Optional[int] + Page size + + cursor : typing.Optional[str] + Opaque page cursor request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - AsyncHttpResponse[EpisodeResponse] - Episodes + AsyncPager[JsonObject, JsonObjectPage] + OK """ _response = await self._client_wrapper.httpx_client.request( - f"graph/episodes/graph/{jsonable_encoder(graph_id)}", + f"graphs/{jsonable_encoder(graph_uuid)}/documents/{jsonable_encoder(document_id)}/episodes", method="GET", params={ - "lastn": lastn, + "limit": limit, + "cursor": cursor, }, request_options=request_options, ) try: if 200 <= _response.status_code < 300: - _data = typing.cast( - EpisodeResponse, + _parsed_response = typing.cast( + JsonObjectPage, parse_obj_as( - type_=EpisodeResponse, # type: ignore + type_=JsonObjectPage, # type: ignore object_=_response.json(), ), ) - return AsyncHttpResponse(response=_response, data=_data) + _items = _parsed_response.items + _parsed_next = _parsed_response.next_cursor + _has_next = _parsed_next is not None and _parsed_next != "" + + async def _get_next(): + return await self.list_for_document( + graph_uuid, + document_id, + limit=limit, + cursor=_parsed_next, + request_options=request_options, + ) + + return AsyncPager(has_next=_has_next, items=_items, get_next=_get_next, response=_parsed_response) if _response.status_code == 400: raise BadRequestError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore object_=_response.json(), ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 401: + raise UnauthorizedError( + 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, @@ -756,64 +751,73 @@ async def get_by_graph_id( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - async def list_by_graph_id( + async def add( self, - graph_id: str, + graph_uuid: str, *, - cursor: typing.Optional[str] = OMIT, - direction: typing.Optional[str] = OMIT, - limit: typing.Optional[int] = OMIT, - mentioned_node_uuids: typing.Optional[typing.Sequence[str]] = OMIT, - order_by: typing.Optional[str] = OMIT, + created_at: typing.Optional[str] = OMIT, + data: typing.Optional[str] = OMIT, + document_id: typing.Optional[str] = OMIT, + metadata: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + source_description: typing.Optional[str] = OMIT, + strict_ontology: typing.Optional[bool] = OMIT, + type: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> AsyncHttpResponse[typing.List[Episode]]: + ) -> AsyncHttpResponse[AddEpisodeResult]: """ - Returns a paginated, filterable list of episodes for a graph. - Parameters ---------- - graph_id : str - Graph ID + graph_uuid : str + Graph UUID - cursor : typing.Optional[str] - Opaque cursor for pagination, obtained from the Zep-Next-Cursor - response header of the previous page. + created_at : typing.Optional[str] - direction : typing.Optional[str] - Sort direction. One of "asc" or "desc". Defaults to "desc". + data : typing.Optional[str] - 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. + document_id : typing.Optional[str] - 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. + metadata : typing.Optional[typing.Dict[str, typing.Any]] - order_by : typing.Optional[str] - Field to sort by. One of "uuid" or "created_at". Defaults to "uuid". + source_description : typing.Optional[str] + + strict_ontology : typing.Optional[bool] + + type : typing.Optional[str] + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - AsyncHttpResponse[typing.List[Episode]] - Episodes + AsyncHttpResponse[AddEpisodeResult] + Accepted """ _response = await self._client_wrapper.httpx_client.request( - f"graph/episodes/graph/{jsonable_encoder(graph_id)}", + f"graphs/{jsonable_encoder(graph_uuid)}/episodes", method="POST", json={ - "cursor": cursor, - "direction": direction, - "limit": limit, - "mentioned_node_uuids": mentioned_node_uuids, - "order_by": order_by, + "created_at": created_at, + "data": data, + "document_id": document_id, + "metadata": metadata, + "source_description": source_description, + "strict_ontology": strict_ontology, + "type": type, + }, + headers={ + "content-type": "application/json", + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, }, request_options=request_options, omit=OMIT, @@ -821,26 +825,15 @@ async def list_by_graph_id( try: if 200 <= _response.status_code < 300: _data = typing.cast( - typing.List[Episode], + AddEpisodeResult, parse_obj_as( - type_=typing.List[Episode], # type: ignore + type_=AddEpisodeResult, # type: ignore object_=_response.json(), ), ) return AsyncHttpResponse(response=_response, data=_data) if _response.status_code == 400: raise BadRequestError( - headers=dict(_response.headers), - body=typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ), - ) - if _response.status_code == 500: - raise InternalServerError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -850,72 +843,19 @@ async def list_by_graph_id( ), ), ) - _response_json = _response.json() - except JSONDecodeError: - raise core_api_error_ApiError( - status_code=_response.status_code, headers=dict(_response.headers), body=_response.text - ) - raise core_api_error_ApiError( - status_code=_response.status_code, headers=dict(_response.headers), body=_response_json - ) - - async def get_by_user_id( - self, - user_id: str, - *, - lastn: typing.Optional[int] = None, - request_options: typing.Optional[RequestOptions] = None, - ) -> AsyncHttpResponse[EpisodeResponse]: - """ - Returns episodes by user id. - - Parameters - ---------- - user_id : str - User ID - - lastn : typing.Optional[int] - The number of most recent episodes entries to retrieve. - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - AsyncHttpResponse[EpisodeResponse] - Episodes - """ - _response = await self._client_wrapper.httpx_client.request( - f"graph/episodes/user/{jsonable_encoder(user_id)}", - method="GET", - params={ - "lastn": lastn, - }, - 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( + if _response.status_code == 401: + raise UnauthorizedError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore object_=_response.json(), ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -930,91 +870,113 @@ async def get_by_user_id( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - async def list_by_user_id( + async def list( self, - user_id: str, + graph_uuid: str, *, - cursor: typing.Optional[str] = OMIT, - direction: typing.Optional[str] = OMIT, - limit: typing.Optional[int] = OMIT, - mentioned_node_uuids: typing.Optional[typing.Sequence[str]] = OMIT, - order_by: typing.Optional[str] = OMIT, + limit: typing.Optional[int] = None, + cursor: typing.Optional[str] = None, + filters: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> AsyncHttpResponse[typing.List[Episode]]: + ) -> AsyncPager[JsonObject, JsonObjectPage]: """ - Returns a paginated, filterable list of episodes for a user's graph. - Parameters ---------- - user_id : str - User ID - - cursor : typing.Optional[str] - Opaque cursor for pagination, obtained from the Zep-Next-Cursor - response header of the previous page. - - direction : typing.Optional[str] - Sort direction. One of "asc" or "desc". Defaults to "desc". + graph_uuid : str + Graph UUID 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. + Page size + + cursor : typing.Optional[str] + Opaque page cursor - 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. + filters : typing.Optional[typing.Dict[str, typing.Any]] - order_by : typing.Optional[str] - Field to sort by. One of "uuid" or "created_at". Defaults to "uuid". + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - AsyncHttpResponse[typing.List[Episode]] - Episodes + AsyncPager[JsonObject, JsonObjectPage] + OK """ _response = await self._client_wrapper.httpx_client.request( - f"graph/episodes/user/{jsonable_encoder(user_id)}", + f"graphs/{jsonable_encoder(graph_uuid)}/episodes/list", method="POST", - json={ - "cursor": cursor, - "direction": direction, + params={ "limit": limit, - "mentioned_node_uuids": mentioned_node_uuids, - "order_by": order_by, + "cursor": cursor, + }, + json={ + "filters": filters, + }, + headers={ + "content-type": "application/json", + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, }, request_options=request_options, omit=OMIT, ) try: if 200 <= _response.status_code < 300: - _data = typing.cast( - typing.List[Episode], + _parsed_response = typing.cast( + JsonObjectPage, parse_obj_as( - type_=typing.List[Episode], # type: ignore + type_=JsonObjectPage, # type: ignore object_=_response.json(), ), ) - return AsyncHttpResponse(response=_response, data=_data) + _items = _parsed_response.items + _parsed_next = _parsed_response.next_cursor + _has_next = _parsed_next is not None and _parsed_next != "" + + async def _get_next(): + return await self.list( + graph_uuid, + limit=limit, + cursor=_parsed_next, + filters=filters, + idempotency_key=idempotency_key, + request_options=request_options, + ) + + return AsyncPager(has_next=_has_next, items=_items, get_next=_get_next, response=_parsed_response) if _response.status_code == 400: raise BadRequestError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore object_=_response.json(), ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 401: + raise UnauthorizedError( + 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, @@ -1029,19 +991,24 @@ async def list_by_user_id( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) async def get( - self, uuid_: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> AsyncHttpResponse[Episode]: + self, graph_uuid: str, episode_uuid: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> AsyncHttpResponse[JsonObject]: """ - Returns episodes by UUID - Parameters ---------- - uuid_ : str + graph_uuid : str + Graph UUID + + episode_uuid : str Episode UUID request_options : typing.Optional[RequestOptions] @@ -1049,20 +1016,20 @@ async def get( Returns ------- - AsyncHttpResponse[Episode] - Episode + AsyncHttpResponse[JsonObject] + OK """ _response = await self._client_wrapper.httpx_client.request( - f"graph/episodes/{jsonable_encoder(uuid_)}", + f"graphs/{jsonable_encoder(graph_uuid)}/episodes/{jsonable_encoder(episode_uuid)}", method="GET", request_options=request_options, ) try: if 200 <= _response.status_code < 300: _data = typing.cast( - Episode, + JsonObject, parse_obj_as( - type_=Episode, # type: ignore + type_=JsonObject, # type: ignore object_=_response.json(), ), ) @@ -1071,15 +1038,26 @@ async def get( raise BadRequestError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore object_=_response.json(), ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 401: + raise UnauthorizedError( + 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, @@ -1094,40 +1072,55 @@ async def get( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) async def delete( - self, uuid_: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> AsyncHttpResponse[SuccessResponse]: + self, + graph_uuid: str, + episode_uuid: str, + *, + idempotency_key: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[AsyncResult]: """ - Deletes an episode by its UUID. - Parameters ---------- - uuid_ : str + graph_uuid : str + Graph UUID + + episode_uuid : str Episode UUID + idempotency_key : typing.Optional[str] + request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - AsyncHttpResponse[SuccessResponse] - Episode deleted + AsyncHttpResponse[AsyncResult] + Accepted """ _response = await self._client_wrapper.httpx_client.request( - f"graph/episodes/{jsonable_encoder(uuid_)}", + f"graphs/{jsonable_encoder(graph_uuid)}/episodes/{jsonable_encoder(episode_uuid)}", method="DELETE", + headers={ + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, + }, request_options=request_options, ) try: if 200 <= _response.status_code < 300: _data = typing.cast( - SuccessResponse, + AsyncResult, parse_obj_as( - type_=SuccessResponse, # type: ignore + type_=AsyncResult, # type: ignore object_=_response.json(), ), ) @@ -1136,15 +1129,15 @@ async def delete( raise BadRequestError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore object_=_response.json(), ), ), ) - if _response.status_code == 404: - raise NotFoundError( + if _response.status_code == 401: + raise UnauthorizedError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -1154,8 +1147,8 @@ async def delete( ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -1170,44 +1163,53 @@ async def delete( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) async def update( self, - uuid_: str, + graph_uuid: str, + episode_uuid: str, *, - metadata: typing.Dict[str, typing.Optional[typing.Any]], + metadata: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> AsyncHttpResponse[Episode]: + ) -> AsyncHttpResponse[JsonObject]: """ - Update episode metadata with merge semantics. Supplied keys overwrite or add to existing metadata; keys set to null are removed. - Parameters ---------- - uuid_ : str + graph_uuid : str + Graph UUID + + episode_uuid : str Episode UUID - metadata : typing.Dict[str, typing.Optional[typing.Any]] - Updated metadata. Merged with existing metadata: supplied keys overwrite/add, keys set to null are removed. Maximum 10 keys. Values must be scalars (string, number, boolean, null) or arrays of scalars. + metadata : typing.Optional[typing.Dict[str, typing.Any]] + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - AsyncHttpResponse[Episode] - Updated episode + AsyncHttpResponse[JsonObject] + OK """ _response = await self._client_wrapper.httpx_client.request( - f"graph/episodes/{jsonable_encoder(uuid_)}", + f"graphs/{jsonable_encoder(graph_uuid)}/episodes/{jsonable_encoder(episode_uuid)}", method="PATCH", json={ "metadata": metadata, }, headers={ "content-type": "application/json", + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, }, request_options=request_options, omit=OMIT, @@ -1215,26 +1217,15 @@ async def update( try: if 200 <= _response.status_code < 300: _data = typing.cast( - Episode, + JsonObject, parse_obj_as( - type_=Episode, # type: ignore + type_=JsonObject, # type: ignore object_=_response.json(), ), ) return AsyncHttpResponse(response=_response, data=_data) if _response.status_code == 400: raise BadRequestError( - headers=dict(_response.headers), - body=typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ), - ) - if _response.status_code == 403: - raise ForbiddenError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -1244,8 +1235,8 @@ async def update( ), ), ) - if _response.status_code == 404: - raise NotFoundError( + if _response.status_code == 401: + raise UnauthorizedError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -1255,8 +1246,8 @@ async def update( ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -1271,70 +1262,9 @@ async def update( 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_nodes_and_edges( - self, uuid_: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> AsyncHttpResponse[EpisodeMentions]: - """ - Deprecated. Use edge and node listing with `filters.episode_uuids` instead. Returns nodes and edges mentioned in an episode, subject to an internal cap; responses reduced by that cap set the Zep-Truncated header. - - Parameters - ---------- - uuid_ : str - Episode uuid - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - AsyncHttpResponse[EpisodeMentions] - Edges and nodes mentioned in an episode - """ - _response = await self._client_wrapper.httpx_client.request( - f"graph/episodes/{jsonable_encoder(uuid_)}/mentions", - method="GET", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - _data = typing.cast( - EpisodeMentions, - parse_obj_as( - type_=EpisodeMentions, # type: ignore - object_=_response.json(), - ), - ) - return AsyncHttpResponse(response=_response, data=_data) - if _response.status_code == 400: - raise BadRequestError( - headers=dict(_response.headers), - body=typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ), - ) - if _response.status_code == 500: - raise InternalServerError( - headers=dict(_response.headers), - body=typing.cast( - types_api_error_ApiError, - parse_obj_as( - type_=types_api_error_ApiError, # type: ignore - object_=_response.json(), - ), - ), - ) - _response_json = _response.json() - except JSONDecodeError: - raise core_api_error_ApiError( - status_code=_response.status_code, headers=dict(_response.headers), body=_response.text + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json diff --git a/src/zep_cloud/graph/node/client.py b/src/zep_cloud/graph/node/client.py index 8fafd397..561ac5c7 100644 --- a/src/zep_cloud/graph/node/client.py +++ b/src/zep_cloud/graph/node/client.py @@ -3,13 +3,14 @@ import typing from ...core.client_wrapper import AsyncClientWrapper, SyncClientWrapper +from ...core.pagination import AsyncPager, SyncPager from ...core.request_options import RequestOptions -from ...types.entity_edge import EntityEdge -from ...types.entity_node import EntityNode -from ...types.episode_response import EpisodeResponse -from ...types.graph_node_neighbor import GraphNodeNeighbor -from ...types.search_filters import SearchFilters -from ...types.success_response import SuccessResponse +from ...types.add_nodes_result import AddNodesResult +from ...types.async_result import AsyncResult +from ...types.json_object import JsonObject +from ...types.json_object_page import JsonObjectPage +from ...types.neighbor_entry import NeighborEntry +from ...types.neighbor_page import NeighborPage from .raw_client import AsyncRawNodeClient, RawNodeClient # this is used as the default value for optional parameters @@ -31,54 +32,31 @@ def with_raw_response(self) -> RawNodeClient: """ return self._raw_client - def get_by_graph_id( + def add( self, - graph_id: str, + graph_uuid: 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, + nodes: typing.Optional[typing.Sequence[typing.Dict[str, typing.Any]]] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> typing.List[EntityNode]: + ) -> AddNodesResult: """ - Returns all nodes for a graph. - Parameters ---------- - graph_id : str - Graph ID - - cursor : typing.Optional[str] - Opaque cursor for pagination, obtained from the Zep-Next-Cursor response header - of the previous page. 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 + graph_uuid : str + Graph UUID - order_by : typing.Optional[str] - Field to sort by. One of "created_at", "valid_at", or "uuid" (default "uuid"). + nodes : typing.Optional[typing.Sequence[typing.Dict[str, typing.Any]]] - 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. + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - typing.List[EntityNode] - Nodes + AddNodesResult + Accepted Examples -------- @@ -87,70 +65,48 @@ def get_by_graph_id( client = Zep( api_key="YOUR_API_KEY", ) - client.graph.node.get_by_graph_id( - graph_id="graph_id", + client.graph.node.add( + graph_uuid="graph_uuid", ) """ - _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, + _response = self._raw_client.add( + graph_uuid, nodes=nodes, idempotency_key=idempotency_key, request_options=request_options ) return _response.data - def get_by_user_id( + def list( self, - user_id: str, + graph_uuid: 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, + limit: typing.Optional[int] = None, + cursor: typing.Optional[str] = None, + filters: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> typing.List[EntityNode]: + ) -> SyncPager[JsonObject, JsonObjectPage]: """ - Returns all nodes for a user - Parameters ---------- - user_id : str - User ID - - cursor : typing.Optional[str] - Opaque cursor for pagination, obtained from the Zep-Next-Cursor response header - of the previous page. 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. + graph_uuid : str + Graph UUID limit : typing.Optional[int] - Maximum number of items to return + Page size - order_by : typing.Optional[str] - Field to sort by. One of "created_at", "valid_at", or "uuid" (default "uuid"). + cursor : typing.Optional[str] + Opaque page cursor - uuid_cursor : typing.Optional[str] - UUID based cursor, used for pagination. Should be the UUID of the last item in the previous page. + filters : typing.Optional[typing.Dict[str, typing.Any]] - Deprecated: prefer Cursor, the opaque cursor returned via the Zep-Next-Cursor response header. + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - typing.List[EntityNode] - Nodes + SyncPager[JsonObject, JsonObjectPage] + OK Examples -------- @@ -159,30 +115,35 @@ def get_by_user_id( client = Zep( api_key="YOUR_API_KEY", ) - client.graph.node.get_by_user_id( - user_id="user_id", + response = client.graph.node.list( + graph_uuid="graph_uuid", + limit=1, + cursor="cursor", ) + for item in response: + yield item + # alternatively, you can paginate page-by-page + for page in response.iter_pages(): + yield page """ - _response = self._raw_client.get_by_user_id( - user_id, + return self._raw_client.list( + graph_uuid, + limit=limit, cursor=cursor, - direction=direction, filters=filters, - limit=limit, - order_by=order_by, - uuid_cursor=uuid_cursor, + idempotency_key=idempotency_key, request_options=request_options, ) - return _response.data - def get_edges( - self, node_uuid: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> typing.List[EntityEdge]: + def get( + self, graph_uuid: str, node_uuid: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> JsonObject: """ - Deprecated. Use edge listing with `filters.connected_node_uuids`, or the neighbors endpoint (`POST /graph/node/{node_uuid}/neighbors`), instead. Returns all edges for a node, subject to an internal cap; responses reduced by that cap set the Zep-Truncated header. - Parameters ---------- + graph_uuid : str + Graph UUID + node_uuid : str Node UUID @@ -191,8 +152,8 @@ def get_edges( Returns ------- - typing.List[EntityEdge] - Edges + JsonObject + OK Examples -------- @@ -201,31 +162,40 @@ def get_edges( client = Zep( api_key="YOUR_API_KEY", ) - client.graph.node.get_edges( + client.graph.node.get( + graph_uuid="graph_uuid", node_uuid="node_uuid", ) """ - _response = self._raw_client.get_edges(node_uuid, request_options=request_options) + _response = self._raw_client.get(graph_uuid, node_uuid, request_options=request_options) return _response.data - def get_episodes( - self, node_uuid: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> EpisodeResponse: + def delete( + self, + graph_uuid: str, + node_uuid: str, + *, + idempotency_key: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncResult: """ - Deprecated. Use episode listing with `mentioned_node_uuids` (`POST /graph/episodes/graph/{graph_id}` or `POST /graph/episodes/user/{user_id}`) instead. Returns episodes that mentioned a given node, subject to an internal cap; responses reduced by that cap set the Zep-Truncated header. - Parameters ---------- + graph_uuid : str + Graph UUID + node_uuid : str Node UUID + idempotency_key : typing.Optional[str] + request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - EpisodeResponse - Episodes + AsyncResult + Accepted Examples -------- @@ -234,68 +204,53 @@ def get_episodes( client = Zep( api_key="YOUR_API_KEY", ) - client.graph.node.get_episodes( + client.graph.node.delete( + graph_uuid="graph_uuid", node_uuid="node_uuid", ) """ - _response = self._raw_client.get_episodes(node_uuid, request_options=request_options) + _response = self._raw_client.delete( + graph_uuid, node_uuid, idempotency_key=idempotency_key, request_options=request_options + ) return _response.data - def get_neighbors( + def update( self, + graph_uuid: str, node_uuid: str, *, - cursor: typing.Optional[str] = OMIT, - direction: typing.Optional[str] = OMIT, - direction_sort: typing.Optional[str] = OMIT, - filters: typing.Optional[SearchFilters] = OMIT, - limit: typing.Optional[int] = OMIT, - order_by: typing.Optional[str] = OMIT, + attributes: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + name: typing.Optional[str] = OMIT, + summary: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> typing.List[GraphNodeNeighbor]: + ) -> JsonObject: """ - Enumerates the distinct entity nodes directly connected to a node, together with the edges connecting each to it. - Parameters ---------- + graph_uuid : str + Graph UUID + node_uuid : str Node UUID - cursor : typing.Optional[str] - Opaque cursor for pagination, obtained from the Zep-Next-Cursor - response header of the previous page. - - direction : typing.Optional[str] - Orientation of the connecting edge relative to the anchor node: "out" - (anchor is the edge's source), "in" (anchor is the edge's target), or - "both" (either). Defaults to "both". - - direction_sort : typing.Optional[str] - Sort direction for order_by. One of "asc" or "desc". Defaults to - "desc". Named direction_sort to avoid clashing with the traversal - Direction field above. + attributes : typing.Optional[typing.Dict[str, typing.Any]] - filters : typing.Optional[SearchFilters] - Filters constraining the connecting edges (edge types, dates, and the - section-3 node-/episode-anchored fields) and the neighbor nodes - (node_labels/exclude_node_labels). Reuses the graph.search filter - type. + name : typing.Optional[str] + Omit to leave unchanged, send JSON null to clear, or send a value to set. - limit : typing.Optional[int] - Maximum number of neighbor nodes to return. An explicit value is - clamped to 50; when omitted, the default page size (100) applies. + summary : typing.Optional[str] + Omit to leave unchanged, send JSON null to clear, or send a value to set. - order_by : typing.Optional[str] - Field to sort neighbor nodes by. One of "uuid" or "created_at". - Defaults to "uuid". + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - typing.List[GraphNodeNeighbor] - Neighbors + JsonObject + OK Examples -------- @@ -304,121 +259,62 @@ def get_neighbors( client = Zep( api_key="YOUR_API_KEY", ) - client.graph.node.get_neighbors( + client.graph.node.update( + graph_uuid="graph_uuid", node_uuid="node_uuid", ) """ - _response = self._raw_client.get_neighbors( + _response = self._raw_client.update( + graph_uuid, node_uuid, - cursor=cursor, - direction=direction, - direction_sort=direction_sort, - filters=filters, - limit=limit, - order_by=order_by, + attributes=attributes, + name=name, + summary=summary, + idempotency_key=idempotency_key, request_options=request_options, ) return _response.data - def get(self, uuid_: str, *, request_options: typing.Optional[RequestOptions] = None) -> EntityNode: - """ - Returns a specific node by its UUID. - - Parameters - ---------- - uuid_ : str - Node UUID - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - EntityNode - Node - - Examples - -------- - from zep_cloud import Zep - - client = Zep( - api_key="YOUR_API_KEY", - ) - client.graph.node.get( - uuid_="uuid", - ) - """ - _response = self._raw_client.get(uuid_, request_options=request_options) - return _response.data - - def delete(self, uuid_: str, *, request_options: typing.Optional[RequestOptions] = None) -> SuccessResponse: - """ - Deletes a node by UUID. - - Parameters - ---------- - uuid_ : str - Node UUID - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - SuccessResponse - Node deleted - - Examples - -------- - from zep_cloud import Zep - - client = Zep( - api_key="YOUR_API_KEY", - ) - client.graph.node.delete( - uuid_="uuid", - ) - """ - _response = self._raw_client.delete(uuid_, request_options=request_options) - return _response.data - - def update( + def list_neighbors( self, - uuid_: str, + graph_uuid: str, + node_uuid: str, *, - attributes: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = OMIT, - labels: typing.Optional[typing.Sequence[str]] = OMIT, - name: typing.Optional[str] = OMIT, - summary: typing.Optional[str] = OMIT, + limit: typing.Optional[int] = None, + cursor: typing.Optional[str] = None, + direction: typing.Optional[str] = OMIT, + filters: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> EntityNode: + ) -> SyncPager[NeighborEntry, NeighborPage]: """ - Updates an entity node by UUID. - Parameters ---------- - uuid_ : str + graph_uuid : str + Graph UUID + + node_uuid : str Node UUID - attributes : typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] - Updated attributes. Merged with existing attributes. Set a key to null to delete it. + limit : typing.Optional[int] + Page size - labels : typing.Optional[typing.Sequence[str]] - Updated labels for the node + cursor : typing.Optional[str] + Opaque page cursor - name : typing.Optional[str] - Updated name for the node + direction : typing.Optional[str] - summary : typing.Optional[str] - Updated summary for the node + filters : typing.Optional[typing.Dict[str, typing.Any]] + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - EntityNode - Updated node + SyncPager[NeighborEntry, NeighborPage] + OK Examples -------- @@ -427,14 +323,28 @@ def update( client = Zep( api_key="YOUR_API_KEY", ) - client.graph.node.update( - uuid_="uuid", + response = client.graph.node.list_neighbors( + graph_uuid="graph_uuid", + node_uuid="node_uuid", + limit=1, + cursor="cursor", ) + for item in response: + yield item + # alternatively, you can paginate page-by-page + for page in response.iter_pages(): + yield page """ - _response = self._raw_client.update( - uuid_, attributes=attributes, labels=labels, name=name, summary=summary, request_options=request_options + return self._raw_client.list_neighbors( + graph_uuid, + node_uuid, + limit=limit, + cursor=cursor, + direction=direction, + filters=filters, + idempotency_key=idempotency_key, + request_options=request_options, ) - return _response.data class AsyncNodeClient: @@ -452,54 +362,31 @@ def with_raw_response(self) -> AsyncRawNodeClient: """ return self._raw_client - async def get_by_graph_id( + async def add( self, - graph_id: str, + graph_uuid: 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, + nodes: typing.Optional[typing.Sequence[typing.Dict[str, typing.Any]]] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> typing.List[EntityNode]: + ) -> AddNodesResult: """ - Returns all nodes for a graph. - Parameters ---------- - graph_id : str - Graph ID - - cursor : typing.Optional[str] - Opaque cursor for pagination, obtained from the Zep-Next-Cursor response header - of the previous page. 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 + graph_uuid : str + Graph UUID - order_by : typing.Optional[str] - Field to sort by. One of "created_at", "valid_at", or "uuid" (default "uuid"). + nodes : typing.Optional[typing.Sequence[typing.Dict[str, typing.Any]]] - 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. + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - typing.List[EntityNode] - Nodes + AddNodesResult + Accepted Examples -------- @@ -513,73 +400,51 @@ async def get_by_graph_id( async def main() -> None: - await client.graph.node.get_by_graph_id( - graph_id="graph_id", + await client.graph.node.add( + graph_uuid="graph_uuid", ) 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, + _response = await self._raw_client.add( + graph_uuid, nodes=nodes, idempotency_key=idempotency_key, request_options=request_options ) return _response.data - async def get_by_user_id( + async def list( self, - user_id: str, + graph_uuid: 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, + limit: typing.Optional[int] = None, + cursor: typing.Optional[str] = None, + filters: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> typing.List[EntityNode]: + ) -> AsyncPager[JsonObject, JsonObjectPage]: """ - Returns all nodes for a user - Parameters ---------- - user_id : str - User ID - - cursor : typing.Optional[str] - Opaque cursor for pagination, obtained from the Zep-Next-Cursor response header - of the previous page. 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. + graph_uuid : str + Graph UUID limit : typing.Optional[int] - Maximum number of items to return + Page size - order_by : typing.Optional[str] - Field to sort by. One of "created_at", "valid_at", or "uuid" (default "uuid"). + cursor : typing.Optional[str] + Opaque page cursor - uuid_cursor : typing.Optional[str] - UUID based cursor, used for pagination. Should be the UUID of the last item in the previous page. + filters : typing.Optional[typing.Dict[str, typing.Any]] - Deprecated: prefer Cursor, the opaque cursor returned via the Zep-Next-Cursor response header. + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - typing.List[EntityNode] - Nodes + AsyncPager[JsonObject, JsonObjectPage] + OK Examples -------- @@ -593,33 +458,39 @@ async def get_by_user_id( async def main() -> None: - await client.graph.node.get_by_user_id( - user_id="user_id", + response = await client.graph.node.list( + graph_uuid="graph_uuid", + limit=1, + cursor="cursor", ) + async for item in response: + yield item + + # alternatively, you can paginate page-by-page + async for page in response.iter_pages(): + yield page asyncio.run(main()) """ - _response = await self._raw_client.get_by_user_id( - user_id, + return await self._raw_client.list( + graph_uuid, + limit=limit, cursor=cursor, - direction=direction, filters=filters, - limit=limit, - order_by=order_by, - uuid_cursor=uuid_cursor, + idempotency_key=idempotency_key, request_options=request_options, ) - return _response.data - async def get_edges( - self, node_uuid: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> typing.List[EntityEdge]: + async def get( + self, graph_uuid: str, node_uuid: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> JsonObject: """ - Deprecated. Use edge listing with `filters.connected_node_uuids`, or the neighbors endpoint (`POST /graph/node/{node_uuid}/neighbors`), instead. Returns all edges for a node, subject to an internal cap; responses reduced by that cap set the Zep-Truncated header. - Parameters ---------- + graph_uuid : str + Graph UUID + node_uuid : str Node UUID @@ -628,8 +499,8 @@ async def get_edges( Returns ------- - typing.List[EntityEdge] - Edges + JsonObject + OK Examples -------- @@ -643,34 +514,43 @@ async def get_edges( async def main() -> None: - await client.graph.node.get_edges( + await client.graph.node.get( + graph_uuid="graph_uuid", node_uuid="node_uuid", ) asyncio.run(main()) """ - _response = await self._raw_client.get_edges(node_uuid, request_options=request_options) + _response = await self._raw_client.get(graph_uuid, node_uuid, request_options=request_options) return _response.data - async def get_episodes( - self, node_uuid: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> EpisodeResponse: + async def delete( + self, + graph_uuid: str, + node_uuid: str, + *, + idempotency_key: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncResult: """ - Deprecated. Use episode listing with `mentioned_node_uuids` (`POST /graph/episodes/graph/{graph_id}` or `POST /graph/episodes/user/{user_id}`) instead. Returns episodes that mentioned a given node, subject to an internal cap; responses reduced by that cap set the Zep-Truncated header. - Parameters ---------- + graph_uuid : str + Graph UUID + node_uuid : str Node UUID + idempotency_key : typing.Optional[str] + request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - EpisodeResponse - Episodes + AsyncResult + Accepted Examples -------- @@ -684,71 +564,56 @@ async def get_episodes( async def main() -> None: - await client.graph.node.get_episodes( + await client.graph.node.delete( + graph_uuid="graph_uuid", node_uuid="node_uuid", ) asyncio.run(main()) """ - _response = await self._raw_client.get_episodes(node_uuid, request_options=request_options) + _response = await self._raw_client.delete( + graph_uuid, node_uuid, idempotency_key=idempotency_key, request_options=request_options + ) return _response.data - async def get_neighbors( + async def update( self, + graph_uuid: str, node_uuid: str, *, - cursor: typing.Optional[str] = OMIT, - direction: typing.Optional[str] = OMIT, - direction_sort: typing.Optional[str] = OMIT, - filters: typing.Optional[SearchFilters] = OMIT, - limit: typing.Optional[int] = OMIT, - order_by: typing.Optional[str] = OMIT, + attributes: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + name: typing.Optional[str] = OMIT, + summary: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> typing.List[GraphNodeNeighbor]: + ) -> JsonObject: """ - Enumerates the distinct entity nodes directly connected to a node, together with the edges connecting each to it. - Parameters ---------- + graph_uuid : str + Graph UUID + node_uuid : str Node UUID - cursor : typing.Optional[str] - Opaque cursor for pagination, obtained from the Zep-Next-Cursor - response header of the previous page. - - direction : typing.Optional[str] - Orientation of the connecting edge relative to the anchor node: "out" - (anchor is the edge's source), "in" (anchor is the edge's target), or - "both" (either). Defaults to "both". + attributes : typing.Optional[typing.Dict[str, typing.Any]] - direction_sort : typing.Optional[str] - Sort direction for order_by. One of "asc" or "desc". Defaults to - "desc". Named direction_sort to avoid clashing with the traversal - Direction field above. - - filters : typing.Optional[SearchFilters] - Filters constraining the connecting edges (edge types, dates, and the - section-3 node-/episode-anchored fields) and the neighbor nodes - (node_labels/exclude_node_labels). Reuses the graph.search filter - type. + name : typing.Optional[str] + Omit to leave unchanged, send JSON null to clear, or send a value to set. - limit : typing.Optional[int] - Maximum number of neighbor nodes to return. An explicit value is - clamped to 50; when omitted, the default page size (100) applies. + summary : typing.Optional[str] + Omit to leave unchanged, send JSON null to clear, or send a value to set. - order_by : typing.Optional[str] - Field to sort neighbor nodes by. One of "uuid" or "created_at". - Defaults to "uuid". + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - typing.List[GraphNodeNeighbor] - Neighbors + JsonObject + OK Examples -------- @@ -762,140 +627,65 @@ async def get_neighbors( async def main() -> None: - await client.graph.node.get_neighbors( + await client.graph.node.update( + graph_uuid="graph_uuid", node_uuid="node_uuid", ) asyncio.run(main()) """ - _response = await self._raw_client.get_neighbors( + _response = await self._raw_client.update( + graph_uuid, node_uuid, - cursor=cursor, - direction=direction, - direction_sort=direction_sort, - filters=filters, - limit=limit, - order_by=order_by, + attributes=attributes, + name=name, + summary=summary, + idempotency_key=idempotency_key, request_options=request_options, ) return _response.data - async def get(self, uuid_: str, *, request_options: typing.Optional[RequestOptions] = None) -> EntityNode: - """ - Returns a specific node by its UUID. - - Parameters - ---------- - uuid_ : str - Node UUID - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - EntityNode - Node - - Examples - -------- - import asyncio - - from zep_cloud import AsyncZep - - client = AsyncZep( - api_key="YOUR_API_KEY", - ) - - - async def main() -> None: - await client.graph.node.get( - uuid_="uuid", - ) - - - asyncio.run(main()) - """ - _response = await self._raw_client.get(uuid_, request_options=request_options) - return _response.data - - async def delete(self, uuid_: str, *, request_options: typing.Optional[RequestOptions] = None) -> SuccessResponse: - """ - Deletes a node by UUID. - - Parameters - ---------- - uuid_ : str - Node UUID - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - SuccessResponse - Node deleted - - Examples - -------- - import asyncio - - from zep_cloud import AsyncZep - - client = AsyncZep( - api_key="YOUR_API_KEY", - ) - - - async def main() -> None: - await client.graph.node.delete( - uuid_="uuid", - ) - - - asyncio.run(main()) - """ - _response = await self._raw_client.delete(uuid_, request_options=request_options) - return _response.data - - async def update( + async def list_neighbors( self, - uuid_: str, + graph_uuid: str, + node_uuid: str, *, - attributes: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = OMIT, - labels: typing.Optional[typing.Sequence[str]] = OMIT, - name: typing.Optional[str] = OMIT, - summary: typing.Optional[str] = OMIT, + limit: typing.Optional[int] = None, + cursor: typing.Optional[str] = None, + direction: typing.Optional[str] = OMIT, + filters: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> EntityNode: + ) -> AsyncPager[NeighborEntry, NeighborPage]: """ - Updates an entity node by UUID. - Parameters ---------- - uuid_ : str + graph_uuid : str + Graph UUID + + node_uuid : str Node UUID - attributes : typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] - Updated attributes. Merged with existing attributes. Set a key to null to delete it. + limit : typing.Optional[int] + Page size - labels : typing.Optional[typing.Sequence[str]] - Updated labels for the node + cursor : typing.Optional[str] + Opaque page cursor - name : typing.Optional[str] - Updated name for the node + direction : typing.Optional[str] - summary : typing.Optional[str] - Updated summary for the node + filters : typing.Optional[typing.Dict[str, typing.Any]] + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - EntityNode - Updated node + AsyncPager[NeighborEntry, NeighborPage] + OK Examples -------- @@ -909,14 +699,29 @@ async def update( async def main() -> None: - await client.graph.node.update( - uuid_="uuid", + response = await client.graph.node.list_neighbors( + graph_uuid="graph_uuid", + node_uuid="node_uuid", + limit=1, + cursor="cursor", ) + async for item in response: + yield item + + # alternatively, you can paginate page-by-page + async for page in response.iter_pages(): + yield page asyncio.run(main()) """ - _response = await self._raw_client.update( - uuid_, attributes=attributes, labels=labels, name=name, summary=summary, request_options=request_options + return await self._raw_client.list_neighbors( + graph_uuid, + node_uuid, + limit=limit, + cursor=cursor, + direction=direction, + filters=filters, + idempotency_key=idempotency_key, + request_options=request_options, ) - return _response.data diff --git a/src/zep_cloud/graph/node/raw_client.py b/src/zep_cloud/graph/node/raw_client.py index 879bf2f6..f98e5867 100644 --- a/src/zep_cloud/graph/node/raw_client.py +++ b/src/zep_cloud/graph/node/raw_client.py @@ -7,19 +7,21 @@ from ...core.client_wrapper import AsyncClientWrapper, SyncClientWrapper from ...core.http_response import AsyncHttpResponse, HttpResponse from ...core.jsonable_encoder import jsonable_encoder +from ...core.pagination import AsyncPager, SyncPager +from ...core.parse_error import ParsingError 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 ...errors.unauthorized_error import UnauthorizedError +from ...types.add_nodes_result import AddNodesResult from ...types.api_error import ApiError as types_api_error_ApiError -from ...types.entity_edge import EntityEdge -from ...types.entity_node import EntityNode -from ...types.episode_response import EpisodeResponse -from ...types.graph_node_neighbor import GraphNodeNeighbor -from ...types.search_filters import SearchFilters -from ...types.success_response import SuccessResponse +from ...types.async_result import AsyncResult +from ...types.json_object import JsonObject +from ...types.json_object_page import JsonObjectPage +from ...types.neighbor_entry import NeighborEntry +from ...types.neighbor_page import NeighborPage +from pydantic import ValidationError # this is used as the default value for optional parameters OMIT = typing.cast(typing.Any, ...) @@ -29,67 +31,41 @@ class RawNodeClient: def __init__(self, *, client_wrapper: SyncClientWrapper): self._client_wrapper = client_wrapper - def get_by_graph_id( + def add( self, - graph_id: str, + graph_uuid: 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, + nodes: typing.Optional[typing.Sequence[typing.Dict[str, typing.Any]]] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> HttpResponse[typing.List[EntityNode]]: + ) -> HttpResponse[AddNodesResult]: """ - Returns all nodes for a graph. - Parameters ---------- - graph_id : str - Graph ID - - cursor : typing.Optional[str] - Opaque cursor for pagination, obtained from the Zep-Next-Cursor response header - of the previous page. 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"). + graph_uuid : str + Graph UUID - uuid_cursor : typing.Optional[str] - UUID based cursor, used for pagination. Should be the UUID of the last item in the previous page. + nodes : typing.Optional[typing.Sequence[typing.Dict[str, typing.Any]]] - Deprecated: prefer Cursor, the opaque cursor returned via the Zep-Next-Cursor response header. + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - HttpResponse[typing.List[EntityNode]] - Nodes + HttpResponse[AddNodesResult] + Accepted """ _response = self._client_wrapper.httpx_client.request( - f"graph/node/graph/{jsonable_encoder(graph_id)}", + f"graphs/{jsonable_encoder(graph_uuid)}/nodes", 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, + "nodes": nodes, + }, + headers={ + "content-type": "application/json", + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, }, request_options=request_options, omit=OMIT, @@ -97,9 +73,9 @@ def get_by_graph_id( try: if 200 <= _response.status_code < 300: _data = typing.cast( - typing.List[EntityNode], + AddNodesResult, parse_obj_as( - type_=typing.List[EntityNode], # type: ignore + type_=AddNodesResult, # type: ignore object_=_response.json(), ), ) @@ -108,15 +84,26 @@ def get_by_graph_id( raise BadRequestError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore object_=_response.json(), ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -131,98 +118,110 @@ def get_by_graph_id( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - def get_by_user_id( + def list( self, - user_id: str, + graph_uuid: 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, + limit: typing.Optional[int] = None, + cursor: typing.Optional[str] = None, + filters: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> HttpResponse[typing.List[EntityNode]]: + ) -> SyncPager[JsonObject, JsonObjectPage]: """ - Returns all nodes for a user - Parameters ---------- - user_id : str - User ID - - cursor : typing.Optional[str] - Opaque cursor for pagination, obtained from the Zep-Next-Cursor response header - of the previous page. 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. + graph_uuid : str + Graph UUID limit : typing.Optional[int] - Maximum number of items to return + Page size - order_by : typing.Optional[str] - Field to sort by. One of "created_at", "valid_at", or "uuid" (default "uuid"). + cursor : typing.Optional[str] + Opaque page cursor - uuid_cursor : typing.Optional[str] - UUID based cursor, used for pagination. Should be the UUID of the last item in the previous page. + filters : typing.Optional[typing.Dict[str, typing.Any]] - Deprecated: prefer Cursor, the opaque cursor returned via the Zep-Next-Cursor response header. + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - HttpResponse[typing.List[EntityNode]] - Nodes + SyncPager[JsonObject, JsonObjectPage] + OK """ _response = self._client_wrapper.httpx_client.request( - f"graph/node/user/{jsonable_encoder(user_id)}", + f"graphs/{jsonable_encoder(graph_uuid)}/nodes/list", method="POST", - json={ - "cursor": cursor, - "direction": direction, - "filters": convert_and_respect_annotation_metadata( - object_=filters, annotation=SearchFilters, direction="write" - ), + params={ "limit": limit, - "order_by": order_by, - "uuid_cursor": uuid_cursor, + "cursor": cursor, + }, + json={ + "filters": filters, + }, + headers={ + "content-type": "application/json", + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, }, request_options=request_options, omit=OMIT, ) try: if 200 <= _response.status_code < 300: - _data = typing.cast( - typing.List[EntityNode], + _parsed_response = typing.cast( + JsonObjectPage, parse_obj_as( - type_=typing.List[EntityNode], # type: ignore + type_=JsonObjectPage, # type: ignore object_=_response.json(), ), ) - return HttpResponse(response=_response, data=_data) + _items = _parsed_response.items + _parsed_next = _parsed_response.next_cursor + _has_next = _parsed_next is not None and _parsed_next != "" + _get_next = lambda: self.list( + graph_uuid, + limit=limit, + cursor=_parsed_next, + filters=filters, + idempotency_key=idempotency_key, + request_options=request_options, + ) + return SyncPager(has_next=_has_next, items=_items, get_next=_get_next, response=_parsed_response) if _response.status_code == 400: raise BadRequestError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore object_=_response.json(), ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -237,18 +236,23 @@ def get_by_user_id( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - def get_edges( - self, node_uuid: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> HttpResponse[typing.List[EntityEdge]]: + def get( + self, graph_uuid: str, node_uuid: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> HttpResponse[JsonObject]: """ - Deprecated. Use edge listing with `filters.connected_node_uuids`, or the neighbors endpoint (`POST /graph/node/{node_uuid}/neighbors`), instead. Returns all edges for a node, subject to an internal cap; responses reduced by that cap set the Zep-Truncated header. - Parameters ---------- + graph_uuid : str + Graph UUID + node_uuid : str Node UUID @@ -257,20 +261,20 @@ def get_edges( Returns ------- - HttpResponse[typing.List[EntityEdge]] - Edges + HttpResponse[JsonObject] + OK """ _response = self._client_wrapper.httpx_client.request( - f"graph/node/{jsonable_encoder(node_uuid)}/entity-edges", + f"graphs/{jsonable_encoder(graph_uuid)}/nodes/{jsonable_encoder(node_uuid)}", method="GET", request_options=request_options, ) try: if 200 <= _response.status_code < 300: _data = typing.cast( - typing.List[EntityEdge], + JsonObject, parse_obj_as( - type_=typing.List[EntityEdge], # type: ignore + type_=JsonObject, # type: ignore object_=_response.json(), ), ) @@ -279,15 +283,26 @@ def get_edges( raise BadRequestError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore object_=_response.json(), ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -302,40 +317,55 @@ def get_edges( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - def get_episodes( - self, node_uuid: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> HttpResponse[EpisodeResponse]: + def delete( + self, + graph_uuid: str, + node_uuid: str, + *, + idempotency_key: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[AsyncResult]: """ - Deprecated. Use episode listing with `mentioned_node_uuids` (`POST /graph/episodes/graph/{graph_id}` or `POST /graph/episodes/user/{user_id}`) instead. Returns episodes that mentioned a given node, subject to an internal cap; responses reduced by that cap set the Zep-Truncated header. - Parameters ---------- + graph_uuid : str + Graph UUID + node_uuid : str Node UUID + idempotency_key : typing.Optional[str] + request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - HttpResponse[EpisodeResponse] - Episodes + HttpResponse[AsyncResult] + Accepted """ _response = self._client_wrapper.httpx_client.request( - f"graph/node/{jsonable_encoder(node_uuid)}/episodes", - method="GET", + f"graphs/{jsonable_encoder(graph_uuid)}/nodes/{jsonable_encoder(node_uuid)}", + method="DELETE", + headers={ + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, + }, request_options=request_options, ) try: if 200 <= _response.status_code < 300: _data = typing.cast( - EpisodeResponse, + AsyncResult, parse_obj_as( - type_=EpisodeResponse, # type: ignore + type_=AsyncResult, # type: ignore object_=_response.json(), ), ) @@ -344,15 +374,26 @@ def get_episodes( raise BadRequestError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore object_=_response.json(), ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -367,81 +408,63 @@ def get_episodes( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - def get_neighbors( + def update( self, + graph_uuid: str, node_uuid: str, *, - cursor: typing.Optional[str] = OMIT, - direction: typing.Optional[str] = OMIT, - direction_sort: typing.Optional[str] = OMIT, - filters: typing.Optional[SearchFilters] = OMIT, - limit: typing.Optional[int] = OMIT, - order_by: typing.Optional[str] = OMIT, + attributes: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + name: typing.Optional[str] = OMIT, + summary: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> HttpResponse[typing.List[GraphNodeNeighbor]]: + ) -> HttpResponse[JsonObject]: """ - Enumerates the distinct entity nodes directly connected to a node, together with the edges connecting each to it. - Parameters ---------- + graph_uuid : str + Graph UUID + node_uuid : str Node UUID - cursor : typing.Optional[str] - Opaque cursor for pagination, obtained from the Zep-Next-Cursor - response header of the previous page. - - direction : typing.Optional[str] - Orientation of the connecting edge relative to the anchor node: "out" - (anchor is the edge's source), "in" (anchor is the edge's target), or - "both" (either). Defaults to "both". - - direction_sort : typing.Optional[str] - Sort direction for order_by. One of "asc" or "desc". Defaults to - "desc". Named direction_sort to avoid clashing with the traversal - Direction field above. + attributes : typing.Optional[typing.Dict[str, typing.Any]] - filters : typing.Optional[SearchFilters] - Filters constraining the connecting edges (edge types, dates, and the - section-3 node-/episode-anchored fields) and the neighbor nodes - (node_labels/exclude_node_labels). Reuses the graph.search filter - type. + name : typing.Optional[str] + Omit to leave unchanged, send JSON null to clear, or send a value to set. - limit : typing.Optional[int] - Maximum number of neighbor nodes to return. An explicit value is - clamped to 50; when omitted, the default page size (100) applies. + summary : typing.Optional[str] + Omit to leave unchanged, send JSON null to clear, or send a value to set. - order_by : typing.Optional[str] - Field to sort neighbor nodes by. One of "uuid" or "created_at". - Defaults to "uuid". + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - HttpResponse[typing.List[GraphNodeNeighbor]] - Neighbors + HttpResponse[JsonObject] + OK """ _response = self._client_wrapper.httpx_client.request( - f"graph/node/{jsonable_encoder(node_uuid)}/neighbors", - method="POST", + f"graphs/{jsonable_encoder(graph_uuid)}/nodes/{jsonable_encoder(node_uuid)}", + method="PATCH", json={ - "cursor": cursor, - "direction": direction, - "direction_sort": direction_sort, - "filters": convert_and_respect_annotation_metadata( - object_=filters, annotation=SearchFilters, direction="write" - ), - "limit": limit, - "order_by": order_by, + "attributes": attributes, + "name": name, + "summary": summary, }, headers={ "content-type": "application/json", + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, }, request_options=request_options, omit=OMIT, @@ -449,9 +472,9 @@ def get_neighbors( try: if 200 <= _response.status_code < 300: _data = typing.cast( - typing.List[GraphNodeNeighbor], + JsonObject, parse_obj_as( - type_=typing.List[GraphNodeNeighbor], # type: ignore + type_=JsonObject, # type: ignore object_=_response.json(), ), ) @@ -460,15 +483,15 @@ def get_neighbors( raise BadRequestError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore object_=_response.json(), ), ), ) - if _response.status_code == 404: - raise NotFoundError( + if _response.status_code == 401: + raise UnauthorizedError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -478,8 +501,8 @@ def get_neighbors( ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -494,55 +517,109 @@ def get_neighbors( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - def get(self, uuid_: str, *, request_options: typing.Optional[RequestOptions] = None) -> HttpResponse[EntityNode]: + def list_neighbors( + self, + graph_uuid: str, + node_uuid: str, + *, + limit: typing.Optional[int] = None, + cursor: typing.Optional[str] = None, + direction: typing.Optional[str] = OMIT, + filters: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + idempotency_key: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> SyncPager[NeighborEntry, NeighborPage]: """ - Returns a specific node by its UUID. - Parameters ---------- - uuid_ : str + graph_uuid : str + Graph UUID + + node_uuid : str Node UUID + limit : typing.Optional[int] + Page size + + cursor : typing.Optional[str] + Opaque page cursor + + direction : typing.Optional[str] + + filters : typing.Optional[typing.Dict[str, typing.Any]] + + idempotency_key : typing.Optional[str] + request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - HttpResponse[EntityNode] - Node + SyncPager[NeighborEntry, NeighborPage] + OK """ _response = self._client_wrapper.httpx_client.request( - f"graph/node/{jsonable_encoder(uuid_)}", - method="GET", + f"graphs/{jsonable_encoder(graph_uuid)}/nodes/{jsonable_encoder(node_uuid)}/neighbors", + method="POST", + params={ + "limit": limit, + "cursor": cursor, + }, + json={ + "direction": direction, + "filters": filters, + }, + headers={ + "content-type": "application/json", + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, + }, request_options=request_options, + omit=OMIT, ) try: if 200 <= _response.status_code < 300: - _data = typing.cast( - EntityNode, + _parsed_response = typing.cast( + NeighborPage, parse_obj_as( - type_=EntityNode, # type: ignore + type_=NeighborPage, # type: ignore object_=_response.json(), ), ) - return HttpResponse(response=_response, data=_data) + _items = _parsed_response.items + _parsed_next = _parsed_response.next_cursor + _has_next = _parsed_next is not None and _parsed_next != "" + _get_next = lambda: self.list_neighbors( + graph_uuid, + node_uuid, + limit=limit, + cursor=_parsed_next, + direction=direction, + filters=filters, + idempotency_key=idempotency_key, + request_options=request_options, + ) + return SyncPager(has_next=_has_next, items=_items, get_next=_get_next, response=_parsed_response) if _response.status_code == 400: raise BadRequestError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore object_=_response.json(), ), ), ) - if _response.status_code == 404: - raise NotFoundError( + if _response.status_code == 401: + raise UnauthorizedError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -552,8 +629,8 @@ def get(self, uuid_: str, *, request_options: typing.Optional[RequestOptions] = ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -568,57 +645,81 @@ def get(self, uuid_: str, *, request_options: typing.Optional[RequestOptions] = raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - def delete( - self, uuid_: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> HttpResponse[SuccessResponse]: - """ - Deletes a node by UUID. +class AsyncRawNodeClient: + def __init__(self, *, client_wrapper: AsyncClientWrapper): + self._client_wrapper = client_wrapper + + async def add( + self, + graph_uuid: str, + *, + nodes: typing.Optional[typing.Sequence[typing.Dict[str, typing.Any]]] = OMIT, + idempotency_key: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[AddNodesResult]: + """ Parameters ---------- - uuid_ : str - Node UUID + graph_uuid : str + Graph UUID + + nodes : typing.Optional[typing.Sequence[typing.Dict[str, typing.Any]]] + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - HttpResponse[SuccessResponse] - Node deleted + AsyncHttpResponse[AddNodesResult] + Accepted """ - _response = self._client_wrapper.httpx_client.request( - f"graph/node/{jsonable_encoder(uuid_)}", - method="DELETE", + _response = await self._client_wrapper.httpx_client.request( + f"graphs/{jsonable_encoder(graph_uuid)}/nodes", + method="POST", + json={ + "nodes": nodes, + }, + headers={ + "content-type": "application/json", + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, + }, request_options=request_options, + omit=OMIT, ) try: if 200 <= _response.status_code < 300: _data = typing.cast( - SuccessResponse, + AddNodesResult, parse_obj_as( - type_=SuccessResponse, # type: ignore + type_=AddNodesResult, # type: ignore object_=_response.json(), ), ) - return HttpResponse(response=_response, data=_data) + return AsyncHttpResponse(response=_response, data=_data) if _response.status_code == 400: raise BadRequestError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore object_=_response.json(), ), ), ) - if _response.status_code == 404: - raise NotFoundError( + if _response.status_code == 401: + raise UnauthorizedError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -628,8 +729,8 @@ def delete( ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -644,86 +745,102 @@ def delete( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - def update( + async def list( self, - uuid_: str, + graph_uuid: str, *, - attributes: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = OMIT, - labels: typing.Optional[typing.Sequence[str]] = OMIT, - name: typing.Optional[str] = OMIT, - summary: typing.Optional[str] = OMIT, + limit: typing.Optional[int] = None, + cursor: typing.Optional[str] = None, + filters: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> HttpResponse[EntityNode]: + ) -> AsyncPager[JsonObject, JsonObjectPage]: """ - Updates an entity node by UUID. - Parameters ---------- - uuid_ : str - Node UUID + graph_uuid : str + Graph UUID - attributes : typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] - Updated attributes. Merged with existing attributes. Set a key to null to delete it. + limit : typing.Optional[int] + Page size - labels : typing.Optional[typing.Sequence[str]] - Updated labels for the node + cursor : typing.Optional[str] + Opaque page cursor - name : typing.Optional[str] - Updated name for the node + filters : typing.Optional[typing.Dict[str, typing.Any]] - summary : typing.Optional[str] - Updated summary for the node + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - HttpResponse[EntityNode] - Updated node + AsyncPager[JsonObject, JsonObjectPage] + OK """ - _response = self._client_wrapper.httpx_client.request( - f"graph/node/{jsonable_encoder(uuid_)}", - method="PATCH", + _response = await self._client_wrapper.httpx_client.request( + f"graphs/{jsonable_encoder(graph_uuid)}/nodes/list", + method="POST", + params={ + "limit": limit, + "cursor": cursor, + }, json={ - "attributes": attributes, - "labels": labels, - "name": name, - "summary": summary, + "filters": filters, }, headers={ "content-type": "application/json", + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, }, request_options=request_options, omit=OMIT, ) try: if 200 <= _response.status_code < 300: - _data = typing.cast( - EntityNode, + _parsed_response = typing.cast( + JsonObjectPage, parse_obj_as( - type_=EntityNode, # type: ignore + type_=JsonObjectPage, # type: ignore object_=_response.json(), ), ) - return HttpResponse(response=_response, data=_data) + _items = _parsed_response.items + _parsed_next = _parsed_response.next_cursor + _has_next = _parsed_next is not None and _parsed_next != "" + + async def _get_next(): + return await self.list( + graph_uuid, + limit=limit, + cursor=_parsed_next, + filters=filters, + idempotency_key=idempotency_key, + request_options=request_options, + ) + + return AsyncPager(has_next=_has_next, items=_items, get_next=_get_next, response=_parsed_response) if _response.status_code == 400: raise BadRequestError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore object_=_response.json(), ), ), ) - if _response.status_code == 404: - raise NotFoundError( + if _response.status_code == 401: + raise UnauthorizedError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -733,8 +850,8 @@ def update( ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -749,103 +866,51 @@ def update( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - -class AsyncRawNodeClient: - 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[EntityNode]]: + async def get( + self, graph_uuid: str, node_uuid: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> AsyncHttpResponse[JsonObject]: """ - Returns all nodes for a graph. - Parameters ---------- - graph_id : str - Graph ID - - cursor : typing.Optional[str] - Opaque cursor for pagination, obtained from the Zep-Next-Cursor response header - of the previous page. 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. + graph_uuid : str + Graph UUID - 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. + node_uuid : str + Node UUID request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - AsyncHttpResponse[typing.List[EntityNode]] - Nodes + AsyncHttpResponse[JsonObject] + OK """ _response = await self._client_wrapper.httpx_client.request( - f"graph/node/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, - }, + f"graphs/{jsonable_encoder(graph_uuid)}/nodes/{jsonable_encoder(node_uuid)}", + method="GET", request_options=request_options, - omit=OMIT, ) try: if 200 <= _response.status_code < 300: _data = typing.cast( - typing.List[EntityNode], + JsonObject, parse_obj_as( - type_=typing.List[EntityNode], # type: ignore + type_=JsonObject, # type: ignore object_=_response.json(), ), ) return AsyncHttpResponse(response=_response, data=_data) if _response.status_code == 400: raise BadRequestError( - headers=dict(_response.headers), - body=typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ), - ) - if _response.status_code == 500: - raise InternalServerError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -855,103 +920,19 @@ async def get_by_graph_id( ), ), ) - _response_json = _response.json() - except JSONDecodeError: - raise core_api_error_ApiError( - status_code=_response.status_code, headers=dict(_response.headers), body=_response.text - ) - raise core_api_error_ApiError( - status_code=_response.status_code, headers=dict(_response.headers), body=_response_json - ) - - async def get_by_user_id( - self, - user_id: str, - *, - 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[EntityNode]]: - """ - Returns all nodes for a user - - Parameters - ---------- - user_id : str - User ID - - cursor : typing.Optional[str] - Opaque cursor for pagination, obtained from the Zep-Next-Cursor response header - of the previous page. 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[EntityNode]] - Nodes - """ - _response = await self._client_wrapper.httpx_client.request( - f"graph/node/user/{jsonable_encoder(user_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, - }, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - _data = typing.cast( - typing.List[EntityNode], - parse_obj_as( - type_=typing.List[EntityNode], # type: ignore - object_=_response.json(), - ), - ) - return AsyncHttpResponse(response=_response, data=_data) - if _response.status_code == 400: - raise BadRequestError( + if _response.status_code == 401: + raise UnauthorizedError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore object_=_response.json(), ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -966,57 +947,61 @@ async def get_by_user_id( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - async def get_edges( - self, node_uuid: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> AsyncHttpResponse[typing.List[EntityEdge]]: + async def delete( + self, + graph_uuid: str, + node_uuid: str, + *, + idempotency_key: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[AsyncResult]: """ - Deprecated. Use edge listing with `filters.connected_node_uuids`, or the neighbors endpoint (`POST /graph/node/{node_uuid}/neighbors`), instead. Returns all edges for a node, subject to an internal cap; responses reduced by that cap set the Zep-Truncated header. - Parameters ---------- + graph_uuid : str + Graph UUID + node_uuid : str Node UUID + idempotency_key : typing.Optional[str] + request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - AsyncHttpResponse[typing.List[EntityEdge]] - Edges + AsyncHttpResponse[AsyncResult] + Accepted """ _response = await self._client_wrapper.httpx_client.request( - f"graph/node/{jsonable_encoder(node_uuid)}/entity-edges", - method="GET", + f"graphs/{jsonable_encoder(graph_uuid)}/nodes/{jsonable_encoder(node_uuid)}", + method="DELETE", + headers={ + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, + }, request_options=request_options, ) try: if 200 <= _response.status_code < 300: _data = typing.cast( - typing.List[EntityEdge], + AsyncResult, parse_obj_as( - type_=typing.List[EntityEdge], # type: ignore + type_=AsyncResult, # type: ignore object_=_response.json(), ), ) return AsyncHttpResponse(response=_response, data=_data) if _response.status_code == 400: raise BadRequestError( - headers=dict(_response.headers), - body=typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ), - ) - if _response.status_code == 500: - raise InternalServerError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -1026,62 +1011,19 @@ async def get_edges( ), ), ) - _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_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. - - Parameters - ---------- - node_uuid : str - Node UUID - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - AsyncHttpResponse[EpisodeResponse] - Episodes - """ - _response = await self._client_wrapper.httpx_client.request( - f"graph/node/{jsonable_encoder(node_uuid)}/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 == 400: - raise BadRequestError( + if _response.status_code == 401: + raise UnauthorizedError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore object_=_response.json(), ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -1096,81 +1038,63 @@ async def get_episodes( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - async def get_neighbors( + async def update( self, + graph_uuid: str, node_uuid: str, *, - cursor: typing.Optional[str] = OMIT, - direction: typing.Optional[str] = OMIT, - direction_sort: typing.Optional[str] = OMIT, - filters: typing.Optional[SearchFilters] = OMIT, - limit: typing.Optional[int] = OMIT, - order_by: typing.Optional[str] = OMIT, + attributes: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + name: typing.Optional[str] = OMIT, + summary: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> AsyncHttpResponse[typing.List[GraphNodeNeighbor]]: + ) -> AsyncHttpResponse[JsonObject]: """ - Enumerates the distinct entity nodes directly connected to a node, together with the edges connecting each to it. - Parameters ---------- + graph_uuid : str + Graph UUID + node_uuid : str Node UUID - cursor : typing.Optional[str] - Opaque cursor for pagination, obtained from the Zep-Next-Cursor - response header of the previous page. - - direction : typing.Optional[str] - Orientation of the connecting edge relative to the anchor node: "out" - (anchor is the edge's source), "in" (anchor is the edge's target), or - "both" (either). Defaults to "both". - - direction_sort : typing.Optional[str] - Sort direction for order_by. One of "asc" or "desc". Defaults to - "desc". Named direction_sort to avoid clashing with the traversal - Direction field above. + attributes : typing.Optional[typing.Dict[str, typing.Any]] - filters : typing.Optional[SearchFilters] - Filters constraining the connecting edges (edge types, dates, and the - section-3 node-/episode-anchored fields) and the neighbor nodes - (node_labels/exclude_node_labels). Reuses the graph.search filter - type. + name : typing.Optional[str] + Omit to leave unchanged, send JSON null to clear, or send a value to set. - limit : typing.Optional[int] - Maximum number of neighbor nodes to return. An explicit value is - clamped to 50; when omitted, the default page size (100) applies. + summary : typing.Optional[str] + Omit to leave unchanged, send JSON null to clear, or send a value to set. - order_by : typing.Optional[str] - Field to sort neighbor nodes by. One of "uuid" or "created_at". - Defaults to "uuid". + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - AsyncHttpResponse[typing.List[GraphNodeNeighbor]] - Neighbors + AsyncHttpResponse[JsonObject] + OK """ _response = await self._client_wrapper.httpx_client.request( - f"graph/node/{jsonable_encoder(node_uuid)}/neighbors", - method="POST", + f"graphs/{jsonable_encoder(graph_uuid)}/nodes/{jsonable_encoder(node_uuid)}", + method="PATCH", json={ - "cursor": cursor, - "direction": direction, - "direction_sort": direction_sort, - "filters": convert_and_respect_annotation_metadata( - object_=filters, annotation=SearchFilters, direction="write" - ), - "limit": limit, - "order_by": order_by, + "attributes": attributes, + "name": name, + "summary": summary, }, headers={ "content-type": "application/json", + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, }, request_options=request_options, omit=OMIT, @@ -1178,26 +1102,15 @@ async def get_neighbors( try: if 200 <= _response.status_code < 300: _data = typing.cast( - typing.List[GraphNodeNeighbor], + JsonObject, parse_obj_as( - type_=typing.List[GraphNodeNeighbor], # type: ignore + type_=JsonObject, # 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, @@ -1207,8 +1120,8 @@ async def get_neighbors( ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 401: + raise UnauthorizedError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -1218,60 +1131,6 @@ async def get_neighbors( ), ), ) - _response_json = _response.json() - except JSONDecodeError: - raise core_api_error_ApiError( - status_code=_response.status_code, headers=dict(_response.headers), body=_response.text - ) - raise core_api_error_ApiError( - status_code=_response.status_code, headers=dict(_response.headers), body=_response_json - ) - - async def get( - self, uuid_: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> AsyncHttpResponse[EntityNode]: - """ - Returns a specific node by its UUID. - - Parameters - ---------- - uuid_ : str - Node UUID - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - AsyncHttpResponse[EntityNode] - Node - """ - _response = await self._client_wrapper.httpx_client.request( - f"graph/node/{jsonable_encoder(uuid_)}", - method="GET", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - _data = typing.cast( - EntityNode, - parse_obj_as( - type_=EntityNode, # 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), @@ -1283,178 +1142,117 @@ async def get( ), ), ) - 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 delete( - self, uuid_: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> AsyncHttpResponse[SuccessResponse]: - """ - Deletes a node by UUID. - - Parameters - ---------- - uuid_ : str - Node UUID - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - AsyncHttpResponse[SuccessResponse] - Node deleted - """ - _response = await self._client_wrapper.httpx_client.request( - f"graph/node/{jsonable_encoder(uuid_)}", - method="DELETE", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - _data = typing.cast( - SuccessResponse, - parse_obj_as( - type_=SuccessResponse, # 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 + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - async def update( + async def list_neighbors( self, - uuid_: str, + graph_uuid: str, + node_uuid: str, *, - attributes: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = OMIT, - labels: typing.Optional[typing.Sequence[str]] = OMIT, - name: typing.Optional[str] = OMIT, - summary: typing.Optional[str] = OMIT, + limit: typing.Optional[int] = None, + cursor: typing.Optional[str] = None, + direction: typing.Optional[str] = OMIT, + filters: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> AsyncHttpResponse[EntityNode]: + ) -> AsyncPager[NeighborEntry, NeighborPage]: """ - Updates an entity node by UUID. - Parameters ---------- - uuid_ : str + graph_uuid : str + Graph UUID + + node_uuid : str Node UUID - attributes : typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] - Updated attributes. Merged with existing attributes. Set a key to null to delete it. + limit : typing.Optional[int] + Page size - labels : typing.Optional[typing.Sequence[str]] - Updated labels for the node + cursor : typing.Optional[str] + Opaque page cursor - name : typing.Optional[str] - Updated name for the node + direction : typing.Optional[str] - summary : typing.Optional[str] - Updated summary for the node + filters : typing.Optional[typing.Dict[str, typing.Any]] + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - AsyncHttpResponse[EntityNode] - Updated node + AsyncPager[NeighborEntry, NeighborPage] + OK """ _response = await self._client_wrapper.httpx_client.request( - f"graph/node/{jsonable_encoder(uuid_)}", - method="PATCH", + f"graphs/{jsonable_encoder(graph_uuid)}/nodes/{jsonable_encoder(node_uuid)}/neighbors", + method="POST", + params={ + "limit": limit, + "cursor": cursor, + }, json={ - "attributes": attributes, - "labels": labels, - "name": name, - "summary": summary, + "direction": direction, + "filters": filters, }, headers={ "content-type": "application/json", + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, }, request_options=request_options, omit=OMIT, ) try: if 200 <= _response.status_code < 300: - _data = typing.cast( - EntityNode, + _parsed_response = typing.cast( + NeighborPage, parse_obj_as( - type_=EntityNode, # type: ignore + type_=NeighborPage, # type: ignore object_=_response.json(), ), ) - return AsyncHttpResponse(response=_response, data=_data) + _items = _parsed_response.items + _parsed_next = _parsed_response.next_cursor + _has_next = _parsed_next is not None and _parsed_next != "" + + async def _get_next(): + return await self.list_neighbors( + graph_uuid, + node_uuid, + limit=limit, + cursor=_parsed_next, + direction=direction, + filters=filters, + idempotency_key=idempotency_key, + request_options=request_options, + ) + + return AsyncPager(has_next=_has_next, items=_items, get_next=_get_next, response=_parsed_response) if _response.status_code == 400: raise BadRequestError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore object_=_response.json(), ), ), ) - if _response.status_code == 404: - raise NotFoundError( + if _response.status_code == 401: + raise UnauthorizedError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -1464,8 +1262,8 @@ async def update( ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -1480,6 +1278,10 @@ async def update( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) diff --git a/src/zep_cloud/graph/observation/client.py b/src/zep_cloud/graph/observation/client.py index cdd97fb5..39420139 100644 --- a/src/zep_cloud/graph/observation/client.py +++ b/src/zep_cloud/graph/observation/client.py @@ -3,9 +3,10 @@ import typing from ...core.client_wrapper import AsyncClientWrapper, SyncClientWrapper +from ...core.pagination import AsyncPager, SyncPager from ...core.request_options import RequestOptions -from ...types.derived_node import DerivedNode -from ...types.search_filters import SearchFilters +from ...types.json_object import JsonObject +from ...types.json_object_page import JsonObjectPage from .raw_client import AsyncRawObservationClient, RawObservationClient # this is used as the default value for optional parameters @@ -27,126 +28,39 @@ def with_raw_response(self) -> RawObservationClient: """ return self._raw_client - def get_by_graph_id( + def list( self, - graph_id: str, + graph_uuid: 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, + limit: typing.Optional[int] = None, + cursor: typing.Optional[str] = None, + filters: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> typing.List[DerivedNode]: + ) -> SyncPager[JsonObject, JsonObjectPage]: """ - Returns read-only observation nodes for a graph. - Parameters ---------- - graph_id : str - Graph ID - - cursor : typing.Optional[str] - Opaque cursor for pagination, obtained from the Zep-Next-Cursor response header - of the previous page. 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. + graph_uuid : str + Graph UUID 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[DerivedNode] - Observations - - Examples - -------- - from zep_cloud import Zep - - client = Zep( - api_key="YOUR_API_KEY", - ) - client.graph.observation.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 - - def get_by_user_id( - self, - user_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[DerivedNode]: - """ - Returns read-only observation nodes for a user's graph. - - Parameters - ---------- - user_id : str - User ID + Page size 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. + Opaque page cursor - 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"). + filters : typing.Optional[typing.Dict[str, typing.Any]] - 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. + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - typing.List[DerivedNode] - Observations + SyncPager[JsonObject, JsonObjectPage] + OK Examples -------- @@ -155,29 +69,36 @@ def get_by_user_id( client = Zep( api_key="YOUR_API_KEY", ) - client.graph.observation.get_by_user_id( - user_id="user_id", + response = client.graph.observation.list( + graph_uuid="graph_uuid", + limit=1, + cursor="cursor", ) - """ - _response = self._raw_client.get_by_user_id( - user_id, + for item in response: + yield item + # alternatively, you can paginate page-by-page + for page in response.iter_pages(): + yield page + """ + return self._raw_client.list( + graph_uuid, + limit=limit, cursor=cursor, - direction=direction, filters=filters, - limit=limit, - order_by=order_by, - uuid_cursor=uuid_cursor, + idempotency_key=idempotency_key, request_options=request_options, ) - return _response.data - def get(self, uuid_: str, *, request_options: typing.Optional[RequestOptions] = None) -> DerivedNode: + def get( + self, graph_uuid: str, observation_uuid: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> JsonObject: """ - Returns a specific observation node by UUID. Observation nodes are read-only. - Parameters ---------- - uuid_ : str + graph_uuid : str + Graph UUID + + observation_uuid : str Observation UUID request_options : typing.Optional[RequestOptions] @@ -185,8 +106,8 @@ def get(self, uuid_: str, *, request_options: typing.Optional[RequestOptions] = Returns ------- - DerivedNode - Observation + JsonObject + OK Examples -------- @@ -196,10 +117,11 @@ def get(self, uuid_: str, *, request_options: typing.Optional[RequestOptions] = api_key="YOUR_API_KEY", ) client.graph.observation.get( - uuid_="uuid", + graph_uuid="graph_uuid", + observation_uuid="observation_uuid", ) """ - _response = self._raw_client.get(uuid_, request_options=request_options) + _response = self._raw_client.get(graph_uuid, observation_uuid, request_options=request_options) return _response.data @@ -218,134 +140,39 @@ def with_raw_response(self) -> AsyncRawObservationClient: """ return self._raw_client - async def get_by_graph_id( + async def list( self, - graph_id: str, + graph_uuid: 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, + limit: typing.Optional[int] = None, + cursor: typing.Optional[str] = None, + filters: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> typing.List[DerivedNode]: + ) -> AsyncPager[JsonObject, JsonObjectPage]: """ - Returns read-only observation nodes for a graph. - Parameters ---------- - graph_id : str - Graph ID - - cursor : typing.Optional[str] - Opaque cursor for pagination, obtained from the Zep-Next-Cursor response header - of the previous page. 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. + graph_uuid : str + Graph UUID 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[DerivedNode] - Observations - - Examples - -------- - import asyncio - - from zep_cloud import AsyncZep - - client = AsyncZep( - api_key="YOUR_API_KEY", - ) - - - async def main() -> None: - await client.graph.observation.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 - - async def get_by_user_id( - self, - user_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[DerivedNode]: - """ - Returns read-only observation nodes for a user's graph. - - Parameters - ---------- - user_id : str - User ID + Page size 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"). + Opaque page cursor - uuid_cursor : typing.Optional[str] - UUID based cursor, used for pagination. Should be the UUID of the last item in the previous page. + filters : typing.Optional[typing.Dict[str, typing.Any]] - Deprecated: prefer Cursor, the opaque cursor returned via the Zep-Next-Cursor response header. + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - typing.List[DerivedNode] - Observations + AsyncPager[JsonObject, JsonObjectPage] + OK Examples -------- @@ -359,32 +186,40 @@ async def get_by_user_id( async def main() -> None: - await client.graph.observation.get_by_user_id( - user_id="user_id", + response = await client.graph.observation.list( + graph_uuid="graph_uuid", + limit=1, + cursor="cursor", ) + async for item in response: + yield item + + # alternatively, you can paginate page-by-page + async for page in response.iter_pages(): + yield page asyncio.run(main()) """ - _response = await self._raw_client.get_by_user_id( - user_id, + return await self._raw_client.list( + graph_uuid, + limit=limit, cursor=cursor, - direction=direction, filters=filters, - limit=limit, - order_by=order_by, - uuid_cursor=uuid_cursor, + idempotency_key=idempotency_key, request_options=request_options, ) - return _response.data - async def get(self, uuid_: str, *, request_options: typing.Optional[RequestOptions] = None) -> DerivedNode: + async def get( + self, graph_uuid: str, observation_uuid: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> JsonObject: """ - Returns a specific observation node by UUID. Observation nodes are read-only. - Parameters ---------- - uuid_ : str + graph_uuid : str + Graph UUID + + observation_uuid : str Observation UUID request_options : typing.Optional[RequestOptions] @@ -392,8 +227,8 @@ async def get(self, uuid_: str, *, request_options: typing.Optional[RequestOptio Returns ------- - DerivedNode - Observation + JsonObject + OK Examples -------- @@ -408,11 +243,12 @@ async def get(self, uuid_: str, *, request_options: typing.Optional[RequestOptio async def main() -> None: await client.graph.observation.get( - uuid_="uuid", + graph_uuid="graph_uuid", + observation_uuid="observation_uuid", ) asyncio.run(main()) """ - _response = await self._raw_client.get(uuid_, request_options=request_options) + _response = await self._raw_client.get(graph_uuid, observation_uuid, request_options=request_options) return _response.data diff --git a/src/zep_cloud/graph/observation/raw_client.py b/src/zep_cloud/graph/observation/raw_client.py index b677dfa4..c6567261 100644 --- a/src/zep_cloud/graph/observation/raw_client.py +++ b/src/zep_cloud/graph/observation/raw_client.py @@ -7,15 +7,17 @@ from ...core.client_wrapper import AsyncClientWrapper, SyncClientWrapper from ...core.http_response import AsyncHttpResponse, HttpResponse from ...core.jsonable_encoder import jsonable_encoder +from ...core.pagination import AsyncPager, SyncPager +from ...core.parse_error import ParsingError 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 ...errors.unauthorized_error import UnauthorizedError from ...types.api_error import ApiError as types_api_error_ApiError -from ...types.derived_node import DerivedNode -from ...types.search_filters import SearchFilters +from ...types.json_object import JsonObject +from ...types.json_object_page import JsonObjectPage +from pydantic import ValidationError # this is used as the default value for optional parameters OMIT = typing.cast(typing.Any, ...) @@ -25,94 +27,80 @@ class RawObservationClient: def __init__(self, *, client_wrapper: SyncClientWrapper): self._client_wrapper = client_wrapper - def get_by_graph_id( + def list( self, - graph_id: str, + graph_uuid: 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, + limit: typing.Optional[int] = None, + cursor: typing.Optional[str] = None, + filters: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> HttpResponse[typing.List[DerivedNode]]: + ) -> SyncPager[JsonObject, JsonObjectPage]: """ - Returns read-only observation nodes for a graph. - Parameters ---------- - graph_id : str - Graph ID - - cursor : typing.Optional[str] - Opaque cursor for pagination, obtained from the Zep-Next-Cursor response header - of the previous page. 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. + graph_uuid : str + Graph UUID limit : typing.Optional[int] - Maximum number of items to return + Page size - order_by : typing.Optional[str] - Field to sort by. One of "created_at", "valid_at", or "uuid" (default "uuid"). + cursor : typing.Optional[str] + Opaque page cursor - uuid_cursor : typing.Optional[str] - UUID based cursor, used for pagination. Should be the UUID of the last item in the previous page. + filters : typing.Optional[typing.Dict[str, typing.Any]] - Deprecated: prefer Cursor, the opaque cursor returned via the Zep-Next-Cursor response header. + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - HttpResponse[typing.List[DerivedNode]] - Observations + SyncPager[JsonObject, JsonObjectPage] + OK """ _response = self._client_wrapper.httpx_client.request( - f"graph/observation/graph/{jsonable_encoder(graph_id)}", + f"graphs/{jsonable_encoder(graph_uuid)}/observations/list", method="POST", - json={ - "cursor": cursor, - "direction": direction, - "filters": convert_and_respect_annotation_metadata( - object_=filters, annotation=SearchFilters, direction="write" - ), + params={ "limit": limit, - "order_by": order_by, - "uuid_cursor": uuid_cursor, + "cursor": cursor, + }, + json={ + "filters": filters, + }, + headers={ + "content-type": "application/json", + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, }, request_options=request_options, omit=OMIT, ) try: if 200 <= _response.status_code < 300: - _data = typing.cast( - typing.List[DerivedNode], + _parsed_response = typing.cast( + JsonObjectPage, parse_obj_as( - type_=typing.List[DerivedNode], # type: ignore + type_=JsonObjectPage, # type: ignore object_=_response.json(), ), ) - return HttpResponse(response=_response, data=_data) + _items = _parsed_response.items + _parsed_next = _parsed_response.next_cursor + _has_next = _parsed_next is not None and _parsed_next != "" + _get_next = lambda: self.list( + graph_uuid, + limit=limit, + cursor=_parsed_next, + filters=filters, + idempotency_key=idempotency_key, + request_options=request_options, + ) + return SyncPager(has_next=_has_next, items=_items, get_next=_get_next, response=_parsed_response) 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, @@ -122,8 +110,8 @@ def get_by_graph_id( ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 401: + raise UnauthorizedError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -133,101 +121,6 @@ def get_by_graph_id( ), ), ) - _response_json = _response.json() - except JSONDecodeError: - raise core_api_error_ApiError( - status_code=_response.status_code, headers=dict(_response.headers), body=_response.text - ) - raise core_api_error_ApiError( - status_code=_response.status_code, headers=dict(_response.headers), body=_response_json - ) - - def get_by_user_id( - self, - user_id: str, - *, - 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[DerivedNode]]: - """ - Returns read-only observation nodes for a user's graph. - - Parameters - ---------- - user_id : str - User ID - - cursor : typing.Optional[str] - Opaque cursor for pagination, obtained from the Zep-Next-Cursor response header - of the previous page. 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[DerivedNode]] - Observations - """ - _response = self._client_wrapper.httpx_client.request( - f"graph/observation/user/{jsonable_encoder(user_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, - }, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - _data = typing.cast( - typing.List[DerivedNode], - parse_obj_as( - type_=typing.List[DerivedNode], # 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), @@ -239,33 +132,29 @@ def get_by_user_id( ), ), ) - 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 ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - def get(self, uuid_: str, *, request_options: typing.Optional[RequestOptions] = None) -> HttpResponse[DerivedNode]: + def get( + self, graph_uuid: str, observation_uuid: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> HttpResponse[JsonObject]: """ - Returns a specific observation node by UUID. Observation nodes are read-only. - Parameters ---------- - uuid_ : str + graph_uuid : str + Graph UUID + + observation_uuid : str Observation UUID request_options : typing.Optional[RequestOptions] @@ -273,20 +162,20 @@ def get(self, uuid_: str, *, request_options: typing.Optional[RequestOptions] = Returns ------- - HttpResponse[DerivedNode] - Observation + HttpResponse[JsonObject] + OK """ _response = self._client_wrapper.httpx_client.request( - f"graph/observation/{jsonable_encoder(uuid_)}", + f"graphs/{jsonable_encoder(graph_uuid)}/observations/{jsonable_encoder(observation_uuid)}", method="GET", request_options=request_options, ) try: if 200 <= _response.status_code < 300: _data = typing.cast( - DerivedNode, + JsonObject, parse_obj_as( - type_=DerivedNode, # type: ignore + type_=JsonObject, # type: ignore object_=_response.json(), ), ) @@ -295,15 +184,15 @@ def get(self, uuid_: str, *, request_options: typing.Optional[RequestOptions] = raise BadRequestError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore object_=_response.json(), ), ), ) - if _response.status_code == 404: - raise NotFoundError( + if _response.status_code == 401: + raise UnauthorizedError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -313,8 +202,8 @@ def get(self, uuid_: str, *, request_options: typing.Optional[RequestOptions] = ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -329,6 +218,10 @@ def get(self, uuid_: str, *, request_options: typing.Optional[RequestOptions] = raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) @@ -338,94 +231,83 @@ class AsyncRawObservationClient: def __init__(self, *, client_wrapper: AsyncClientWrapper): self._client_wrapper = client_wrapper - async def get_by_graph_id( + async def list( self, - graph_id: str, + graph_uuid: 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, + limit: typing.Optional[int] = None, + cursor: typing.Optional[str] = None, + filters: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> AsyncHttpResponse[typing.List[DerivedNode]]: + ) -> AsyncPager[JsonObject, JsonObjectPage]: """ - Returns read-only observation nodes for a graph. - Parameters ---------- - graph_id : str - Graph ID - - cursor : typing.Optional[str] - Opaque cursor for pagination, obtained from the Zep-Next-Cursor response header - of the previous page. 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. + graph_uuid : str + Graph UUID limit : typing.Optional[int] - Maximum number of items to return + Page size - order_by : typing.Optional[str] - Field to sort by. One of "created_at", "valid_at", or "uuid" (default "uuid"). + cursor : typing.Optional[str] + Opaque page cursor - uuid_cursor : typing.Optional[str] - UUID based cursor, used for pagination. Should be the UUID of the last item in the previous page. + filters : typing.Optional[typing.Dict[str, typing.Any]] - Deprecated: prefer Cursor, the opaque cursor returned via the Zep-Next-Cursor response header. + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - AsyncHttpResponse[typing.List[DerivedNode]] - Observations + AsyncPager[JsonObject, JsonObjectPage] + OK """ _response = await self._client_wrapper.httpx_client.request( - f"graph/observation/graph/{jsonable_encoder(graph_id)}", + f"graphs/{jsonable_encoder(graph_uuid)}/observations/list", method="POST", - json={ - "cursor": cursor, - "direction": direction, - "filters": convert_and_respect_annotation_metadata( - object_=filters, annotation=SearchFilters, direction="write" - ), + params={ "limit": limit, - "order_by": order_by, - "uuid_cursor": uuid_cursor, + "cursor": cursor, + }, + json={ + "filters": filters, + }, + headers={ + "content-type": "application/json", + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, }, request_options=request_options, omit=OMIT, ) try: if 200 <= _response.status_code < 300: - _data = typing.cast( - typing.List[DerivedNode], + _parsed_response = typing.cast( + JsonObjectPage, parse_obj_as( - type_=typing.List[DerivedNode], # type: ignore + type_=JsonObjectPage, # type: ignore object_=_response.json(), ), ) - return AsyncHttpResponse(response=_response, data=_data) + _items = _parsed_response.items + _parsed_next = _parsed_response.next_cursor + _has_next = _parsed_next is not None and _parsed_next != "" + + async def _get_next(): + return await self.list( + graph_uuid, + limit=limit, + cursor=_parsed_next, + filters=filters, + idempotency_key=idempotency_key, + request_options=request_options, + ) + + return AsyncPager(has_next=_has_next, items=_items, get_next=_get_next, response=_parsed_response) 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, @@ -435,8 +317,8 @@ async def get_by_graph_id( ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 401: + raise UnauthorizedError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -446,101 +328,6 @@ async def get_by_graph_id( ), ), ) - _response_json = _response.json() - except JSONDecodeError: - raise core_api_error_ApiError( - status_code=_response.status_code, headers=dict(_response.headers), body=_response.text - ) - raise core_api_error_ApiError( - status_code=_response.status_code, headers=dict(_response.headers), body=_response_json - ) - - async def get_by_user_id( - self, - user_id: str, - *, - 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[DerivedNode]]: - """ - Returns read-only observation nodes for a user's graph. - - Parameters - ---------- - user_id : str - User ID - - cursor : typing.Optional[str] - Opaque cursor for pagination, obtained from the Zep-Next-Cursor response header - of the previous page. 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[DerivedNode]] - Observations - """ - _response = await self._client_wrapper.httpx_client.request( - f"graph/observation/user/{jsonable_encoder(user_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, - }, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - _data = typing.cast( - typing.List[DerivedNode], - parse_obj_as( - type_=typing.List[DerivedNode], # 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), @@ -552,35 +339,29 @@ async def get_by_user_id( ), ), ) - 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 ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) async def get( - self, uuid_: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> AsyncHttpResponse[DerivedNode]: + self, graph_uuid: str, observation_uuid: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> AsyncHttpResponse[JsonObject]: """ - Returns a specific observation node by UUID. Observation nodes are read-only. - Parameters ---------- - uuid_ : str + graph_uuid : str + Graph UUID + + observation_uuid : str Observation UUID request_options : typing.Optional[RequestOptions] @@ -588,20 +369,20 @@ async def get( Returns ------- - AsyncHttpResponse[DerivedNode] - Observation + AsyncHttpResponse[JsonObject] + OK """ _response = await self._client_wrapper.httpx_client.request( - f"graph/observation/{jsonable_encoder(uuid_)}", + f"graphs/{jsonable_encoder(graph_uuid)}/observations/{jsonable_encoder(observation_uuid)}", method="GET", request_options=request_options, ) try: if 200 <= _response.status_code < 300: _data = typing.cast( - DerivedNode, + JsonObject, parse_obj_as( - type_=DerivedNode, # type: ignore + type_=JsonObject, # type: ignore object_=_response.json(), ), ) @@ -610,15 +391,15 @@ async def get( raise BadRequestError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore object_=_response.json(), ), ), ) - if _response.status_code == 404: - raise NotFoundError( + if _response.status_code == 401: + raise UnauthorizedError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -628,8 +409,8 @@ async def get( ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -644,6 +425,10 @@ async def get( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) diff --git a/src/zep_cloud/graph/raw_client.py b/src/zep_cloud/graph/raw_client.py index 4527e28d..b45cf07e 100644 --- a/src/zep_cloud/graph/raw_client.py +++ b/src/zep_cloud/graph/raw_client.py @@ -7,38 +7,26 @@ from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper from ..core.http_response import AsyncHttpResponse, HttpResponse from ..core.jsonable_encoder import jsonable_encoder +from ..core.pagination import AsyncPager, SyncPager +from ..core.parse_error import ParsingError 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 from ..errors.not_found_error import NotFoundError -from ..types.add_node_item import AddNodeItem -from ..types.add_nodes_response import AddNodesResponse -from ..types.add_triple_response import AddTripleResponse +from ..errors.unauthorized_error import UnauthorizedError from ..types.api_error import ApiError as types_api_error_ApiError -from ..types.clone_graph_response import CloneGraphResponse -from ..types.custom_instruction import CustomInstruction -from ..types.detect_config import DetectConfig -from ..types.detect_patterns_response import DetectPatternsResponse -from ..types.edge_type import EdgeType -from ..types.entity_type import EntityType -from ..types.entity_type_response import EntityTypeResponse -from ..types.episode import Episode -from ..types.episode_data import EpisodeData +from ..types.async_result import AsyncResult +from ..types.clone_graph_result import CloneGraphResult from ..types.graph import Graph -from ..types.graph_data_type import GraphDataType -from ..types.graph_list_response import GraphListResponse -from ..types.graph_search_results import GraphSearchResults -from ..types.graph_search_scope import GraphSearchScope -from ..types.graph_subgraph_response import GraphSubgraphResponse -from ..types.list_custom_instructions_response import ListCustomInstructionsResponse -from ..types.pattern_seeds import PatternSeeds -from ..types.recency_weight import RecencyWeight -from ..types.reranker import Reranker -from ..types.search_filters import SearchFilters -from ..types.success_response import SuccessResponse +from ..types.graph_context_response import GraphContextResponse +from ..types.graph_delete_result import GraphDeleteResult +from ..types.graph_page import GraphPage +from ..types.instructions import Instructions +from ..types.json_object import JsonObject +from ..types.json_object_page import JsonObjectPage +from ..types.observation_steering import ObservationSteering +from ..types.ontology import Ontology +from pydantic import ValidationError # this is used as the default value for optional parameters OMIT = typing.cast(typing.Any, ...) @@ -48,47 +36,59 @@ class RawGraphClient: def __init__(self, *, client_wrapper: SyncClientWrapper): self._client_wrapper = client_wrapper - def list_custom_instructions( + def create( self, *, - user_id: typing.Optional[str] = None, - graph_id: typing.Optional[str] = None, + description: typing.Optional[str] = OMIT, + graph_id: typing.Optional[str] = OMIT, + name: typing.Optional[str] = OMIT, + time_zone: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> HttpResponse[ListCustomInstructionsResponse]: + ) -> HttpResponse[Graph]: """ - Lists all custom instructions for a project, user, or graph. - Parameters ---------- - user_id : typing.Optional[str] - User ID to get user-specific instructions + description : typing.Optional[str] graph_id : typing.Optional[str] - Graph ID to get graph-specific instructions + + name : typing.Optional[str] + + time_zone : typing.Optional[str] + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - HttpResponse[ListCustomInstructionsResponse] - The list of instructions. + HttpResponse[Graph] + Created """ _response = self._client_wrapper.httpx_client.request( - "custom-instructions", - method="GET", - params={ - "user_id": user_id, + "graphs", + method="POST", + json={ + "description": description, "graph_id": graph_id, + "name": name, + "time_zone": time_zone, + }, + headers={ + "content-type": "application/json", + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, }, request_options=request_options, + omit=OMIT, ) try: if 200 <= _response.status_code < 300: _data = typing.cast( - ListCustomInstructionsResponse, + Graph, parse_obj_as( - type_=ListCustomInstructionsResponse, # type: ignore + type_=Graph, # type: ignore object_=_response.json(), ), ) @@ -97,15 +97,15 @@ def list_custom_instructions( raise BadRequestError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore object_=_response.json(), ), ), ) - if _response.status_code == 404: - raise NotFoundError( + if _response.status_code == 401: + raise UnauthorizedError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -115,8 +115,8 @@ def list_custom_instructions( ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -131,79 +131,106 @@ def list_custom_instructions( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - def add_custom_instructions( + def list( self, *, - instructions: typing.Sequence[CustomInstruction], - graph_ids: typing.Optional[typing.Sequence[str]] = OMIT, - user_ids: typing.Optional[typing.Sequence[str]] = OMIT, + limit: typing.Optional[int] = None, + cursor: typing.Optional[str] = None, + order_by: typing.Optional[str] = None, + order: typing.Optional[str] = None, + search: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> HttpResponse[SuccessResponse]: + ) -> SyncPager[Graph, GraphPage]: """ - Adds new custom instructions for graphs without removing existing ones. If user_ids or graph_ids is empty, adds to project-wide default instructions. - Parameters ---------- - instructions : typing.Sequence[CustomInstruction] - Instructions to add to the graph. + limit : typing.Optional[int] + Page size + + cursor : typing.Optional[str] + Opaque page cursor - graph_ids : typing.Optional[typing.Sequence[str]] - Graph IDs to add the instructions to. If empty, the instructions are added to the project-wide default. + order_by : typing.Optional[str] + Sort field + + order : typing.Optional[str] + asc or desc + + search : typing.Optional[str] - user_ids : typing.Optional[typing.Sequence[str]] - User IDs to add the instructions to. If empty, the instructions are added to the project-wide default. + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - HttpResponse[SuccessResponse] - Instructions added successfully + SyncPager[Graph, GraphPage] + OK """ _response = self._client_wrapper.httpx_client.request( - "custom-instructions", + "graphs/list", method="POST", + params={ + "limit": limit, + "cursor": cursor, + "order_by": order_by, + "order": order, + }, json={ - "graph_ids": graph_ids, - "instructions": convert_and_respect_annotation_metadata( - object_=instructions, annotation=typing.Sequence[CustomInstruction], direction="write" - ), - "user_ids": user_ids, + "search": search, }, headers={ "content-type": "application/json", + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, }, request_options=request_options, omit=OMIT, ) try: if 200 <= _response.status_code < 300: - _data = typing.cast( - SuccessResponse, + _parsed_response = typing.cast( + GraphPage, parse_obj_as( - type_=SuccessResponse, # type: ignore + type_=GraphPage, # type: ignore object_=_response.json(), ), ) - return HttpResponse(response=_response, data=_data) + _items = _parsed_response.items + _parsed_next = _parsed_response.next_cursor + _has_next = _parsed_next is not None and _parsed_next != "" + _get_next = lambda: self.list( + limit=limit, + cursor=_parsed_next, + order_by=order_by, + order=order, + search=search, + idempotency_key=idempotency_key, + request_options=request_options, + ) + return SyncPager(has_next=_has_next, items=_items, get_next=_get_next, response=_parsed_response) if _response.status_code == 400: raise BadRequestError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore object_=_response.json(), ), ), ) - if _response.status_code == 404: - raise NotFoundError( + if _response.status_code == 401: + raise UnauthorizedError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -213,8 +240,8 @@ def add_custom_instructions( ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -229,50 +256,53 @@ def add_custom_instructions( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - def delete_custom_instructions( + def lookup( self, *, - graph_ids: typing.Optional[typing.Sequence[str]] = OMIT, - instruction_names: typing.Optional[typing.Sequence[str]] = OMIT, - user_ids: typing.Optional[typing.Sequence[str]] = OMIT, + graph_id: typing.Optional[str] = OMIT, + thread_id: typing.Optional[str] = OMIT, + user_id: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> HttpResponse[SuccessResponse]: + ) -> HttpResponse[Graph]: """ - Deletes custom instructions for graphs or project wide defaults. - Parameters ---------- - graph_ids : typing.Optional[typing.Sequence[str]] - Determines which group graphs will have their custom instructions deleted. If no graphs are provided, the project-wide custom instructions will be affected. + graph_id : typing.Optional[str] - instruction_names : typing.Optional[typing.Sequence[str]] - Unique identifier for the instructions to be deleted. If empty deletes all instructions. + thread_id : typing.Optional[str] - user_ids : typing.Optional[typing.Sequence[str]] - Determines which user graphs will have their custom instructions deleted. If no users are provided, the project-wide custom instructions will be affected. + user_id : typing.Optional[str] + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - HttpResponse[SuccessResponse] - Instructions deleted successfully + HttpResponse[Graph] + OK """ _response = self._client_wrapper.httpx_client.request( - "custom-instructions", - method="DELETE", + "graphs/lookup", + method="POST", json={ - "graph_ids": graph_ids, - "instruction_names": instruction_names, - "user_ids": user_ids, + "graph_id": graph_id, + "thread_id": thread_id, + "user_id": user_id, }, headers={ "content-type": "application/json", + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, }, request_options=request_options, omit=OMIT, @@ -280,9 +310,9 @@ def delete_custom_instructions( try: if 200 <= _response.status_code < 300: _data = typing.cast( - SuccessResponse, + Graph, parse_obj_as( - type_=SuccessResponse, # type: ignore + type_=Graph, # type: ignore object_=_response.json(), ), ) @@ -291,15 +321,15 @@ def delete_custom_instructions( raise BadRequestError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore object_=_response.json(), ), ), ) - if _response.status_code == 404: - raise NotFoundError( + if _response.status_code == 401: + raise UnauthorizedError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -309,8 +339,8 @@ def delete_custom_instructions( ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -325,51 +355,40 @@ def delete_custom_instructions( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - def list_entity_types( - self, - *, - user_id: typing.Optional[str] = None, - graph_id: typing.Optional[str] = None, - request_options: typing.Optional[RequestOptions] = None, - ) -> HttpResponse[EntityTypeResponse]: + def get(self, graph_uuid: str, *, request_options: typing.Optional[RequestOptions] = None) -> HttpResponse[Graph]: """ - Returns all entity types for a project, user, or graph. - Parameters ---------- - user_id : typing.Optional[str] - User ID to get user-specific entity types - - graph_id : typing.Optional[str] - Graph ID to get graph-specific entity types + graph_uuid : str + Graph UUID request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - HttpResponse[EntityTypeResponse] - The list of entity types. + HttpResponse[Graph] + OK """ _response = self._client_wrapper.httpx_client.request( - "entity-types", + f"graphs/{jsonable_encoder(graph_uuid)}", method="GET", - params={ - "user_id": user_id, - "graph_id": graph_id, - }, request_options=request_options, ) try: if 200 <= _response.status_code < 300: _data = typing.cast( - EntityTypeResponse, + Graph, parse_obj_as( - type_=EntityTypeResponse, # type: ignore + type_=Graph, # type: ignore object_=_response.json(), ), ) @@ -378,15 +397,15 @@ def list_entity_types( raise BadRequestError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore object_=_response.json(), ), ), ) - if _response.status_code == 404: - raise NotFoundError( + if _response.status_code == 401: + raise UnauthorizedError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -396,8 +415,8 @@ def list_entity_types( ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -412,65 +431,51 @@ def list_entity_types( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - def set_entity_types_internal( + def delete( self, + graph_uuid: str, *, - edge_types: typing.Optional[typing.Sequence[EdgeType]] = OMIT, - entity_types: typing.Optional[typing.Sequence[EntityType]] = OMIT, - graph_ids: typing.Optional[typing.Sequence[str]] = OMIT, - user_ids: typing.Optional[typing.Sequence[str]] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> HttpResponse[SuccessResponse]: + ) -> HttpResponse[GraphDeleteResult]: """ - Sets the entity types for multiple users and graphs, replacing any existing ones. - Parameters ---------- - edge_types : typing.Optional[typing.Sequence[EdgeType]] - - entity_types : typing.Optional[typing.Sequence[EntityType]] + graph_uuid : str + Graph UUID - graph_ids : typing.Optional[typing.Sequence[str]] - - user_ids : typing.Optional[typing.Sequence[str]] + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - HttpResponse[SuccessResponse] - Entity types set successfully + HttpResponse[GraphDeleteResult] + Accepted """ _response = self._client_wrapper.httpx_client.request( - "entity-types", - method="PUT", - json={ - "edge_types": convert_and_respect_annotation_metadata( - object_=edge_types, annotation=typing.Sequence[EdgeType], direction="write" - ), - "entity_types": convert_and_respect_annotation_metadata( - object_=entity_types, annotation=typing.Sequence[EntityType], direction="write" - ), - "graph_ids": graph_ids, - "user_ids": user_ids, - }, + f"graphs/{jsonable_encoder(graph_uuid)}", + method="DELETE", headers={ - "content-type": "application/json", + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, }, request_options=request_options, - omit=OMIT, ) try: if 200 <= _response.status_code < 300: _data = typing.cast( - SuccessResponse, + GraphDeleteResult, parse_obj_as( - type_=SuccessResponse, # type: ignore + type_=GraphDeleteResult, # type: ignore object_=_response.json(), ), ) @@ -479,15 +484,15 @@ def set_entity_types_internal( raise BadRequestError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore object_=_response.json(), ), ), ) - if _response.status_code == 404: - raise NotFoundError( + if _response.status_code == 401: + raise UnauthorizedError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -497,8 +502,8 @@ def set_entity_types_internal( ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -513,71 +518,60 @@ def set_entity_types_internal( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - def add( + def update( self, + graph_uuid: str, *, - data: str, - type: GraphDataType, - created_at: 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, - strict_ontology: typing.Optional[bool] = OMIT, - user_id: typing.Optional[str] = OMIT, + description: typing.Optional[str] = OMIT, + name: typing.Optional[str] = OMIT, + time_zone: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> HttpResponse[Episode]: + ) -> HttpResponse[Graph]: """ - Add data to the graph. - Parameters ---------- - data : str - - type : GraphDataType + graph_uuid : str + Graph UUID - created_at : typing.Optional[str] - - 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. - - metadata : typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] - Optional metadata key-value pairs. Max 10 keys. Values must be strings, numbers, booleans, or arrays of scalars. + description : typing.Optional[str] + Omit to leave unchanged, send JSON null to clear, or send a value to set. - source_description : typing.Optional[str] + name : typing.Optional[str] + Omit to leave unchanged, send JSON null to clear, or send a value to set. - strict_ontology : typing.Optional[bool] - When true, prevents extraction of generic Entity nodes that do not match the configured ontology. + time_zone : typing.Optional[str] + Omit to leave unchanged, send JSON null to clear, or send a value to set. - user_id : typing.Optional[str] - User ID is the ID of the user to which the data will be added. If not adding to a user graph, please use graph_id field instead. + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - HttpResponse[Episode] - Added episode + HttpResponse[Graph] + OK """ _response = self._client_wrapper.httpx_client.request( - "graph", - method="POST", + f"graphs/{jsonable_encoder(graph_uuid)}", + method="PATCH", json={ - "created_at": created_at, - "data": data, - "graph_id": graph_id, - "metadata": metadata, - "source_description": source_description, - "strict_ontology": strict_ontology, - "type": type, - "user_id": user_id, + "description": description, + "name": name, + "time_zone": time_zone, }, headers={ "content-type": "application/json", + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, }, request_options=request_options, omit=OMIT, @@ -585,9 +579,9 @@ def add( try: if 200 <= _response.status_code < 300: _data = typing.cast( - Episode, + Graph, parse_obj_as( - type_=Episode, # type: ignore + type_=Graph, # type: ignore object_=_response.json(), ), ) @@ -596,15 +590,26 @@ def add( raise BadRequestError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore object_=_response.json(), ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -619,58 +624,49 @@ def add( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - def add_batch( + def clone( self, + graph_uuid: str, *, - episodes: typing.Sequence[EpisodeData], - graph_id: typing.Optional[str] = OMIT, - strict_ontology: typing.Optional[bool] = OMIT, - user_id: typing.Optional[str] = OMIT, + target_graph_id: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> HttpResponse[typing.List[Episode]]: + ) -> HttpResponse[CloneGraphResult]: """ - Deprecated. Use the [Batch API](/adding-batch-data) (`client.batch.*`) instead. - - Adds data to the graph in batch mode, processing episodes concurrently. - Parameters ---------- - episodes : typing.Sequence[EpisodeData] - - 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. + graph_uuid : str + Graph UUID - strict_ontology : typing.Optional[bool] - When true, prevents extraction of generic Entity nodes that do not match the configured ontology. + target_graph_id : typing.Optional[str] - user_id : typing.Optional[str] - User ID is the ID of the user to which the data will be added. If not adding to a user graph, please use graph_id field instead. + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - HttpResponse[typing.List[Episode]] - Added episodes + HttpResponse[CloneGraphResult] + Accepted """ _response = self._client_wrapper.httpx_client.request( - "graph-batch", + f"graphs/{jsonable_encoder(graph_uuid)}/clone", method="POST", json={ - "episodes": convert_and_respect_annotation_metadata( - object_=episodes, annotation=typing.Sequence[EpisodeData], direction="write" - ), - "graph_id": graph_id, - "strict_ontology": strict_ontology, - "user_id": user_id, + "target_graph_id": target_graph_id, }, headers={ "content-type": "application/json", + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, }, request_options=request_options, omit=OMIT, @@ -678,9 +674,9 @@ def add_batch( try: if 200 <= _response.status_code < 300: _data = typing.cast( - typing.List[Episode], + CloneGraphResult, parse_obj_as( - type_=typing.List[Episode], # type: ignore + type_=CloneGraphResult, # type: ignore object_=_response.json(), ), ) @@ -689,15 +685,26 @@ def add_batch( raise BadRequestError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore object_=_response.json(), ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -712,145 +719,69 @@ def add_batch( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - def add_fact_triple( + def get_context( self, + graph_uuid: str, *, - fact: str, - fact_name: str, - created_at: typing.Optional[str] = OMIT, - edge_attributes: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = OMIT, - expired_at: typing.Optional[str] = OMIT, - graph_id: typing.Optional[str] = OMIT, - invalid_at: typing.Optional[str] = OMIT, - metadata: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = OMIT, - source_node_attributes: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = OMIT, - source_node_labels: typing.Optional[typing.Sequence[str]] = OMIT, - source_node_name: typing.Optional[str] = OMIT, - source_node_summary: typing.Optional[str] = OMIT, - source_node_uuid: typing.Optional[str] = OMIT, - target_node_attributes: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = OMIT, - target_node_labels: typing.Optional[typing.Sequence[str]] = OMIT, - target_node_name: typing.Optional[str] = OMIT, - target_node_summary: typing.Optional[str] = OMIT, - target_node_uuid: typing.Optional[str] = OMIT, - user_id: typing.Optional[str] = OMIT, - valid_at: typing.Optional[str] = OMIT, + filters: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + include_results: typing.Optional[bool] = OMIT, + max_characters: typing.Optional[int] = OMIT, + query: typing.Optional[str] = OMIT, + recency_bias: typing.Optional[str] = OMIT, + template_uuid: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> HttpResponse[AddTripleResponse]: + ) -> HttpResponse[GraphContextResponse]: """ - Add a fact triple for a user or group - Parameters ---------- - fact : str - The fact relating the two nodes that this edge represents + graph_uuid : str + Graph UUID - fact_name : str - The name of the edge to add. Should be all caps using snake case (eg RELATES_TO) + filters : typing.Optional[typing.Dict[str, typing.Any]] - created_at : typing.Optional[str] - The timestamp of the message + include_results : typing.Optional[bool] - edge_attributes : typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] - Additional attributes of the edge. Values must be scalar types (string, number, boolean, or null). - Nested objects and arrays are not allowed. - - expired_at : typing.Optional[str] - The time (if any) at which the edge expires - - graph_id : typing.Optional[str] - - invalid_at : typing.Optional[str] - The time (if any) at which the fact stops being true - - metadata : typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] - Optional metadata key-value pairs for the shadow episode created for this fact triple. - Max 10 keys. Values must be strings, numbers, or booleans. - - source_node_attributes : typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] - Additional attributes of the source node. Values must be scalar types (string, number, boolean, or null). - Nested objects and arrays are not allowed. - - source_node_labels : typing.Optional[typing.Sequence[str]] - The labels for the source node. At most one entity-type label may be - provided so that manually-added triples remain consistent with automatic - episode extraction, which assigns one best-match entity type per node. - The base "Entity" label is added implicitly by the graph layer on save - and does not need to be supplied here. - - source_node_name : typing.Optional[str] - The name of the source node to add - - source_node_summary : typing.Optional[str] - The summary of the source node to add - - source_node_uuid : typing.Optional[str] - The source node uuid - - target_node_attributes : typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] - Additional attributes of the target node. Values must be scalar types (string, number, boolean, or null). - Nested objects and arrays are not allowed. - - target_node_labels : typing.Optional[typing.Sequence[str]] - The labels for the target node. At most one entity-type label may be - provided so that manually-added triples remain consistent with automatic - episode extraction, which assigns one best-match entity type per node. - The base "Entity" label is added implicitly by the graph layer on save - and does not need to be supplied here. - - target_node_name : typing.Optional[str] - The name of the target node to add + max_characters : typing.Optional[int] - target_node_summary : typing.Optional[str] - The summary of the target node to add + query : typing.Optional[str] - target_node_uuid : typing.Optional[str] - The target node uuid + recency_bias : typing.Optional[str] - user_id : typing.Optional[str] + template_uuid : typing.Optional[str] - valid_at : typing.Optional[str] - The time at which the fact becomes true + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - HttpResponse[AddTripleResponse] - Resulting triple + HttpResponse[GraphContextResponse] + OK """ _response = self._client_wrapper.httpx_client.request( - "graph/add-fact-triple", + f"graphs/{jsonable_encoder(graph_uuid)}/context", method="POST", json={ - "created_at": created_at, - "edge_attributes": edge_attributes, - "expired_at": expired_at, - "fact": fact, - "fact_name": fact_name, - "graph_id": graph_id, - "invalid_at": invalid_at, - "metadata": metadata, - "source_node_attributes": source_node_attributes, - "source_node_labels": source_node_labels, - "source_node_name": source_node_name, - "source_node_summary": source_node_summary, - "source_node_uuid": source_node_uuid, - "target_node_attributes": target_node_attributes, - "target_node_labels": target_node_labels, - "target_node_name": target_node_name, - "target_node_summary": target_node_summary, - "target_node_uuid": target_node_uuid, - "user_id": user_id, - "valid_at": valid_at, + "filters": filters, + "include_results": include_results, + "max_characters": max_characters, + "query": query, + "recency_bias": recency_bias, + "template_uuid": template_uuid, }, headers={ "content-type": "application/json", + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, }, request_options=request_options, omit=OMIT, @@ -858,9 +789,9 @@ def add_fact_triple( try: if 200 <= _response.status_code < 300: _data = typing.cast( - AddTripleResponse, + GraphContextResponse, parse_obj_as( - type_=AddTripleResponse, # type: ignore + type_=GraphContextResponse, # type: ignore object_=_response.json(), ), ) @@ -869,15 +800,26 @@ def add_fact_triple( raise BadRequestError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore object_=_response.json(), ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -892,65 +834,42 @@ def add_fact_triple( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - def clone( - self, - *, - source_graph_id: typing.Optional[str] = OMIT, - source_user_id: typing.Optional[str] = OMIT, - target_graph_id: typing.Optional[str] = OMIT, - target_user_id: typing.Optional[str] = OMIT, - request_options: typing.Optional[RequestOptions] = None, - ) -> HttpResponse[CloneGraphResponse]: + def get_instructions( + self, graph_uuid: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> HttpResponse[Instructions]: """ - Clone a user or group graph. - Parameters ---------- - source_graph_id : typing.Optional[str] - source_graph_id is the ID of the graph to be cloned. Required if source_user_id is not provided - - source_user_id : typing.Optional[str] - user_id of the user whose graph is being cloned. Required if source_graph_id is not provided - - target_graph_id : typing.Optional[str] - target_graph_id is the ID to be set on the cloned graph. Must not point to an existing graph. Required if target_user_id is not provided. - - target_user_id : typing.Optional[str] - user_id to be set on the cloned user. Must not point to an existing user. Required if target_graph_id is not provided. + graph_uuid : str + Graph UUID request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - HttpResponse[CloneGraphResponse] - Response object containing graph_id or user_id pointing to the new graph + HttpResponse[Instructions] + OK """ _response = self._client_wrapper.httpx_client.request( - "graph/clone", - method="POST", - json={ - "source_graph_id": source_graph_id, - "source_user_id": source_user_id, - "target_graph_id": target_graph_id, - "target_user_id": target_user_id, - }, - headers={ - "content-type": "application/json", - }, + f"graphs/{jsonable_encoder(graph_uuid)}/instructions", + method="GET", request_options=request_options, - omit=OMIT, ) try: if 200 <= _response.status_code < 300: _data = typing.cast( - CloneGraphResponse, + Instructions, parse_obj_as( - type_=CloneGraphResponse, # type: ignore + type_=Instructions, # type: ignore object_=_response.json(), ), ) @@ -959,15 +878,15 @@ def clone( raise BadRequestError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore object_=_response.json(), ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 401: + raise UnauthorizedError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -977,57 +896,69 @@ def clone( ), ), ) - _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 create( + 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(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise core_api_error_ApiError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.text + ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) + raise core_api_error_ApiError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response_json + ) + + def set_instructions( self, + graph_uuid: str, *, - graph_id: str, - description: typing.Optional[str] = OMIT, - name: typing.Optional[str] = OMIT, - time_zone: typing.Optional[str] = OMIT, + inherited: typing.Optional[bool] = OMIT, + instructions: typing.Optional[typing.Sequence[typing.Dict[str, typing.Any]]] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> HttpResponse[Graph]: + ) -> HttpResponse[Instructions]: """ - Creates a new graph. - Parameters ---------- - graph_id : str + graph_uuid : str + Graph UUID - description : typing.Optional[str] + inherited : typing.Optional[bool] - name : typing.Optional[str] + instructions : typing.Optional[typing.Sequence[typing.Dict[str, typing.Any]]] - time_zone : typing.Optional[str] - The graph's IANA time zone. Stored on its group-backed subject. + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - HttpResponse[Graph] - The added graph + HttpResponse[Instructions] + OK """ _response = self._client_wrapper.httpx_client.request( - "graph/create", - method="POST", + f"graphs/{jsonable_encoder(graph_uuid)}/instructions", + method="PUT", json={ - "description": description, - "graph_id": graph_id, - "name": name, - "time_zone": time_zone, + "inherited": inherited, + "instructions": instructions, }, headers={ "content-type": "application/json", + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, }, request_options=request_options, omit=OMIT, @@ -1035,9 +966,9 @@ def create( try: if 200 <= _response.status_code < 300: _data = typing.cast( - Graph, + Instructions, parse_obj_as( - type_=Graph, # type: ignore + type_=Instructions, # type: ignore object_=_response.json(), ), ) @@ -1046,15 +977,26 @@ def create( raise BadRequestError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore object_=_response.json(), ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -1069,66 +1011,42 @@ def create( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - def list_all( - self, - *, - page_number: typing.Optional[int] = None, - page_size: typing.Optional[int] = None, - search: typing.Optional[str] = None, - order_by: typing.Optional[str] = None, - asc: typing.Optional[bool] = None, - request_options: typing.Optional[RequestOptions] = None, - ) -> HttpResponse[GraphListResponse]: + def get_observation_steering( + self, graph_uuid: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> HttpResponse[ObservationSteering]: """ - Returns all graphs. In order to list users, use user.list_ordered instead - Parameters ---------- - page_number : typing.Optional[int] - Page number for pagination, starting from 1. - - page_size : typing.Optional[int] - Number of graphs to retrieve per page (default 50, range 1-100; explicit 0 is invalid). - - search : typing.Optional[str] - Search term for filtering graphs by graph_id, name, or description. Queries longer than 200 Unicode code points after whitespace normalization are invalid. - - order_by : typing.Optional[str] - Column to sort by (created_at, graph_id, name). - - asc : typing.Optional[bool] - Sort in ascending order. + graph_uuid : str + Graph UUID request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - HttpResponse[GraphListResponse] - Successfully retrieved list of graphs. + HttpResponse[ObservationSteering] + OK """ _response = self._client_wrapper.httpx_client.request( - "graph/list-all", + f"graphs/{jsonable_encoder(graph_uuid)}/observation-steering", method="GET", - params={ - "pageNumber": page_number, - "pageSize": page_size, - "search": search, - "order_by": order_by, - "asc": asc, - }, request_options=request_options, ) try: if 200 <= _response.status_code < 300: _data = typing.cast( - GraphListResponse, + ObservationSteering, parse_obj_as( - type_=GraphListResponse, # type: ignore + type_=ObservationSteering, # type: ignore object_=_response.json(), ), ) @@ -1137,15 +1055,26 @@ def list_all( raise BadRequestError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore object_=_response.json(), ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -1160,50 +1089,57 @@ def list_all( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - def add_nodes( + def set_observation_steering( self, + graph_uuid: str, *, - nodes: typing.Sequence[AddNodeItem], - graph_id: typing.Optional[str] = OMIT, - user_id: typing.Optional[str] = OMIT, + inherited: typing.Optional[bool] = OMIT, + instruction: typing.Optional[str] = OMIT, + types: typing.Optional[typing.Sequence[typing.Dict[str, typing.Any]]] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> HttpResponse[AddNodesResponse]: + ) -> HttpResponse[ObservationSteering]: """ - Add entity nodes to a user or graph directly, without episode ingestion. Up to 100 nodes per request. - Parameters ---------- - nodes : typing.Sequence[AddNodeItem] - The nodes to add. 1 to 100 items. + graph_uuid : str + Graph UUID - graph_id : typing.Optional[str] + inherited : typing.Optional[bool] - user_id : typing.Optional[str] + instruction : typing.Optional[str] + + types : typing.Optional[typing.Sequence[typing.Dict[str, typing.Any]]] + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - HttpResponse[AddNodesResponse] - Accepted + HttpResponse[ObservationSteering] + OK """ _response = self._client_wrapper.httpx_client.request( - "graph/nodes", - method="POST", + f"graphs/{jsonable_encoder(graph_uuid)}/observation-steering", + method="PUT", json={ - "graph_id": graph_id, - "nodes": convert_and_respect_annotation_metadata( - object_=nodes, annotation=typing.Sequence[AddNodeItem], direction="write" - ), - "user_id": user_id, + "inherited": inherited, + "instruction": instruction, + "types": types, }, headers={ "content-type": "application/json", + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, }, request_options=request_options, omit=OMIT, @@ -1211,9 +1147,9 @@ def add_nodes( try: if 200 <= _response.status_code < 300: _data = typing.cast( - AddNodesResponse, + ObservationSteering, parse_obj_as( - type_=AddNodesResponse, # type: ignore + type_=ObservationSteering, # type: ignore object_=_response.json(), ), ) @@ -1222,15 +1158,26 @@ def add_nodes( raise BadRequestError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore object_=_response.json(), ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -1245,131 +1192,48 @@ def add_nodes( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - def detect_patterns( - self, - *, - detect: typing.Optional[DetectConfig] = OMIT, - edge_limit: typing.Optional[int] = OMIT, - graph_id: typing.Optional[str] = OMIT, - limit: typing.Optional[int] = OMIT, - min_occurrences: typing.Optional[int] = OMIT, - query: typing.Optional[str] = OMIT, - query_limit: typing.Optional[int] = OMIT, - recency_weight: typing.Optional[RecencyWeight] = OMIT, - search_filters: typing.Optional[SearchFilters] = OMIT, - seeds: typing.Optional[PatternSeeds] = OMIT, - user_id: typing.Optional[str] = OMIT, - request_options: typing.Optional[RequestOptions] = None, - ) -> HttpResponse[DetectPatternsResponse]: + def get_ontology( + self, graph_uuid: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> HttpResponse[Ontology]: """ - 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, - detects triple-frequency patterns, and returns resolved edges ranked by relevance. - Parameters ---------- - detect : typing.Optional[DetectConfig] - Which pattern types to detect with type-specific configuration. - Omit to detect all types with defaults. Ignored when query is set. - - edge_limit : typing.Optional[int] - Max resolved edges per pattern. Default: 10, Max: 100. Only used with query. - - graph_id : typing.Optional[str] - Graph ID when detecting patterns on a named graph - - limit : typing.Optional[int] - Max patterns to return. Default: 50, Max: 200 - - min_occurrences : typing.Optional[int] - Minimum occurrence count to report a pattern. Default: 2 - - query : typing.Optional[str] - Search query for discovering seed nodes via hybrid search. - When set, forces triple-frequency detection only and enables edge resolution - with cross-encoder reranking. Mutually exclusive with seeds. - - query_limit : typing.Optional[int] - Max seed nodes from search. Default: 10, Max: 50. Only used with query. - - recency_weight : typing.Optional[RecencyWeight] - Exponential half-life decay applied to edge created_at timestamps. - Valid values: none, 7_days, 30_days, 90_days. Default: none - - search_filters : typing.Optional[SearchFilters] - Filters which edges/nodes participate in pattern detection. - Reuses the same filter format as /graph/search. - - seeds : typing.Optional[PatternSeeds] - Seed selection. If omitted, analyzes the entire graph. Mutually exclusive with query. - - user_id : typing.Optional[str] - User ID when detecting patterns on a user graph + graph_uuid : str + Graph UUID request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - HttpResponse[DetectPatternsResponse] - Detected patterns + HttpResponse[Ontology] + OK """ _response = self._client_wrapper.httpx_client.request( - "graph/patterns", - method="POST", - json={ - "detect": convert_and_respect_annotation_metadata( - object_=detect, annotation=DetectConfig, direction="write" - ), - "edge_limit": edge_limit, - "graph_id": graph_id, - "limit": limit, - "min_occurrences": min_occurrences, - "query": query, - "query_limit": query_limit, - "recency_weight": recency_weight, - "search_filters": convert_and_respect_annotation_metadata( - object_=search_filters, annotation=SearchFilters, direction="write" - ), - "seeds": convert_and_respect_annotation_metadata( - object_=seeds, annotation=PatternSeeds, direction="write" - ), - "user_id": user_id, - }, - headers={ - "content-type": "application/json", - }, + f"graphs/{jsonable_encoder(graph_uuid)}/ontology", + method="GET", request_options=request_options, - omit=OMIT, ) try: if 200 <= _response.status_code < 300: _data = typing.cast( - DetectPatternsResponse, + Ontology, parse_obj_as( - type_=DetectPatternsResponse, # type: ignore + type_=Ontology, # type: ignore object_=_response.json(), ), ) return HttpResponse(response=_response, data=_data) if _response.status_code == 400: raise BadRequestError( - headers=dict(_response.headers), - body=typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ), - ) - if _response.status_code == 403: - raise ForbiddenError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -1379,8 +1243,8 @@ def detect_patterns( ), ), ) - if _response.status_code == 404: - raise NotFoundError( + if _response.status_code == 401: + raise UnauthorizedError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -1390,8 +1254,8 @@ def detect_patterns( ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -1406,103 +1270,57 @@ def detect_patterns( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - def search( + def set_ontology( self, + graph_uuid: str, *, - query: str, - bfs_origin_node_uuids: typing.Optional[typing.Sequence[str]] = OMIT, - center_node_uuid: typing.Optional[str] = OMIT, - graph_id: typing.Optional[str] = OMIT, - limit: typing.Optional[int] = OMIT, - max_characters: typing.Optional[int] = OMIT, - mmr_lambda: typing.Optional[float] = OMIT, - reranker: typing.Optional[Reranker] = OMIT, - return_raw_results: typing.Optional[bool] = OMIT, - scope: typing.Optional[GraphSearchScope] = OMIT, - search_filters: typing.Optional[SearchFilters] = OMIT, - user_id: typing.Optional[str] = OMIT, + edge_types: typing.Optional[typing.Sequence[typing.Dict[str, typing.Any]]] = OMIT, + entity_types: typing.Optional[typing.Sequence[typing.Dict[str, typing.Any]]] = OMIT, + inherited: typing.Optional[bool] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> HttpResponse[GraphSearchResults]: + ) -> HttpResponse[Ontology]: """ - Perform a graph search query. - Parameters ---------- - query : str - The string to search for (required) + graph_uuid : str + Graph UUID - bfs_origin_node_uuids : typing.Optional[typing.Sequence[str]] - Nodes that are the origins of the BFS searches - - center_node_uuid : typing.Optional[str] - Node to rerank around for node distance reranking - - graph_id : typing.Optional[str] - The graph_id to search in. When searching user graph, please use user_id instead. - - limit : typing.Optional[int] - The maximum number of facts to retrieve for non-auto scopes. Defaults to 10. Limited to 50. Ignored when scope=auto. - - max_characters : typing.Optional[int] - Maximum total characters across all selected results when scope=auto. Defaults to 2500. Limited to 50000. - - mmr_lambda : typing.Optional[float] - weighting for maximal marginal relevance - - reranker : typing.Optional[Reranker] - Defaults to RRF. Ignored when scope=auto except node_distance and episode_mentions are rejected; - auto search always uses RRF retrieval and applies its own internal rerank after retrieval. - episode_mentions ranks edge candidates by how many of the episodes listed - in search_filters.episode_uuids mention them; without episode_uuids it has - no effect and results are ranked as if no reranker were specified. + edge_types : typing.Optional[typing.Sequence[typing.Dict[str, typing.Any]]] - return_raw_results : typing.Optional[bool] - When scope=auto, include the selected raw graph results alongside the materialized context block. - For graph-service-backed auto mode, selected raw results may include episodes, - edges, nodes, observations, and thread_summaries. + entity_types : typing.Optional[typing.Sequence[typing.Dict[str, typing.Any]]] - scope : typing.Optional[GraphSearchScope] - Defaults to Edges. + inherited : typing.Optional[bool] - search_filters : typing.Optional[SearchFilters] - Search filters to apply to the search - - user_id : typing.Optional[str] - The user_id when searching user graph. If not searching user graph, please use graph_id instead. + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - HttpResponse[GraphSearchResults] - Graph search results or auto-context block + HttpResponse[Ontology] + OK """ _response = self._client_wrapper.httpx_client.request( - "graph/search", - method="POST", + f"graphs/{jsonable_encoder(graph_uuid)}/ontology", + method="PUT", json={ - "bfs_origin_node_uuids": bfs_origin_node_uuids, - "center_node_uuid": center_node_uuid, - "graph_id": graph_id, - "limit": limit, - "max_characters": max_characters, - "mmr_lambda": mmr_lambda, - "query": query, - "reranker": reranker, - "return_raw_results": return_raw_results, - "scope": scope, - "search_filters": convert_and_respect_annotation_metadata( - object_=search_filters, annotation=SearchFilters, direction="write" - ), - "user_id": user_id, + "edge_types": edge_types, + "entity_types": entity_types, + "inherited": inherited, }, headers={ "content-type": "application/json", + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, }, request_options=request_options, omit=OMIT, @@ -1510,9 +1328,9 @@ def search( try: if 200 <= _response.status_code < 300: _data = typing.cast( - GraphSearchResults, + Ontology, parse_obj_as( - type_=GraphSearchResults, # type: ignore + type_=Ontology, # type: ignore object_=_response.json(), ), ) @@ -1521,15 +1339,26 @@ def search( raise BadRequestError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore object_=_response.json(), ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -1544,113 +1373,113 @@ def search( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - def get_subgraph( + def search_edges( self, + graph_uuid: str, *, - seed_node_uuids: typing.Sequence[str], - depth: typing.Optional[int] = OMIT, - direction: typing.Optional[str] = OMIT, - graph_id: typing.Optional[str] = OMIT, - max_edges: typing.Optional[int] = OMIT, - max_nodes: typing.Optional[int] = OMIT, - search_filters: typing.Optional[SearchFilters] = OMIT, - user_id: typing.Optional[str] = OMIT, + limit: typing.Optional[int] = None, + cursor: typing.Optional[str] = None, + bfs_origin_node_uuids: typing.Optional[typing.Sequence[str]] = OMIT, + center_node_uuid: typing.Optional[str] = OMIT, + filters: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + mmr_lambda: typing.Optional[float] = OMIT, + query: typing.Optional[str] = OMIT, + reranker: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> HttpResponse[GraphSubgraphResponse]: + ) -> SyncPager[JsonObject, JsonObjectPage]: """ - Returns the bounded neighborhood of a set of seed nodes as a single {nodes, edges} payload: breadth-first expansion up to a caller-specified depth, subject to explicit budgets, with explicit truncation reporting. - Parameters ---------- - seed_node_uuids : typing.Sequence[str] - Seed node UUIDs to expand from, in traversal-priority order: seeds are - admitted before any expansion, in this order, and count toward - max_nodes first. 1-20 entries, required. Seeds that do not exist in - the target graph are ignored, not an error. + graph_uuid : str + Graph UUID - depth : typing.Optional[int] - Maximum traversal depth from the seeds. 1-3. Defaults to 1. + limit : typing.Optional[int] + Page size - direction : typing.Optional[str] - Edge orientation followed during expansion, relative to each frontier - node: "in" | "out" | "both". Defaults to "both". + cursor : typing.Optional[str] + Opaque page cursor - graph_id : typing.Optional[str] - graph_id identifies the target named graph. Exactly one of user_id or - graph_id is required. + bfs_origin_node_uuids : typing.Optional[typing.Sequence[str]] - max_edges : typing.Optional[int] - Maximum number of edges in the response. 1-1000. Defaults to 200. + center_node_uuid : typing.Optional[str] - max_nodes : typing.Optional[int] - Maximum number of nodes in the response, including admitted seeds. - 1-500. Defaults to 100. + filters : typing.Optional[typing.Dict[str, typing.Any]] + + mmr_lambda : typing.Optional[float] + + query : typing.Optional[str] - 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). + reranker : typing.Optional[str] - user_id : typing.Optional[str] - user_id identifies the target user graph. Exactly one of user_id or - graph_id is required. + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - HttpResponse[GraphSubgraphResponse] - Subgraph + SyncPager[JsonObject, JsonObjectPage] + OK """ _response = self._client_wrapper.httpx_client.request( - "graph/subgraph", + f"graphs/{jsonable_encoder(graph_uuid)}/search/edges", method="POST", + params={ + "limit": limit, + "cursor": cursor, + }, json={ - "depth": depth, - "direction": direction, - "graph_id": graph_id, - "max_edges": max_edges, - "max_nodes": max_nodes, - "search_filters": convert_and_respect_annotation_metadata( - object_=search_filters, annotation=SearchFilters, direction="write" - ), - "seed_node_uuids": seed_node_uuids, - "user_id": user_id, + "bfs_origin_node_uuids": bfs_origin_node_uuids, + "center_node_uuid": center_node_uuid, + "filters": filters, + "mmr_lambda": mmr_lambda, + "query": query, + "reranker": reranker, }, headers={ "content-type": "application/json", + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, }, request_options=request_options, omit=OMIT, ) try: if 200 <= _response.status_code < 300: - _data = typing.cast( - GraphSubgraphResponse, + _parsed_response = typing.cast( + JsonObjectPage, parse_obj_as( - type_=GraphSubgraphResponse, # type: ignore + type_=JsonObjectPage, # type: ignore object_=_response.json(), ), ) - return HttpResponse(response=_response, data=_data) + _items = _parsed_response.items + _parsed_next = _parsed_response.next_cursor + _has_next = _parsed_next is not None and _parsed_next != "" + _get_next = lambda: self.search_edges( + graph_uuid, + limit=limit, + cursor=_parsed_next, + bfs_origin_node_uuids=bfs_origin_node_uuids, + center_node_uuid=center_node_uuid, + filters=filters, + mmr_lambda=mmr_lambda, + query=query, + reranker=reranker, + idempotency_key=idempotency_key, + request_options=request_options, + ) + return SyncPager(has_next=_has_next, items=_items, get_next=_get_next, response=_parsed_response) if _response.status_code == 400: raise BadRequestError( - headers=dict(_response.headers), - body=typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ), - ) - if _response.status_code == 403: - raise ForbiddenError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -1660,8 +1489,8 @@ def get_subgraph( ), ), ) - if _response.status_code == 404: - raise NotFoundError( + if _response.status_code == 401: + raise UnauthorizedError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -1671,8 +1500,8 @@ def get_subgraph( ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -1687,44 +1516,668 @@ def get_subgraph( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - def get(self, graph_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> HttpResponse[Graph]: - """ - Returns a graph. - - Parameters + def search_episodes( + self, + graph_uuid: str, + *, + limit: typing.Optional[int] = None, + cursor: typing.Optional[str] = None, + bfs_origin_node_uuids: typing.Optional[typing.Sequence[str]] = OMIT, + center_node_uuid: typing.Optional[str] = OMIT, + filters: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + mmr_lambda: typing.Optional[float] = OMIT, + query: typing.Optional[str] = OMIT, + reranker: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> SyncPager[JsonObject, JsonObjectPage]: + """ + Parameters ---------- - graph_id : str - The graph_id of the graph to get. + graph_uuid : str + Graph UUID + + limit : typing.Optional[int] + Page size + + cursor : typing.Optional[str] + Opaque page cursor + + bfs_origin_node_uuids : typing.Optional[typing.Sequence[str]] + + center_node_uuid : typing.Optional[str] + + filters : typing.Optional[typing.Dict[str, typing.Any]] + + mmr_lambda : typing.Optional[float] + + query : typing.Optional[str] + + reranker : typing.Optional[str] + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - HttpResponse[Graph] - The graph that was retrieved. + SyncPager[JsonObject, JsonObjectPage] + OK """ _response = self._client_wrapper.httpx_client.request( - f"graph/{jsonable_encoder(graph_id)}", - method="GET", + f"graphs/{jsonable_encoder(graph_uuid)}/search/episodes", + method="POST", + params={ + "limit": limit, + "cursor": cursor, + }, + json={ + "bfs_origin_node_uuids": bfs_origin_node_uuids, + "center_node_uuid": center_node_uuid, + "filters": filters, + "mmr_lambda": mmr_lambda, + "query": query, + "reranker": reranker, + }, + headers={ + "content-type": "application/json", + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + _parsed_response = typing.cast( + JsonObjectPage, + parse_obj_as( + type_=JsonObjectPage, # type: ignore + object_=_response.json(), + ), + ) + _items = _parsed_response.items + _parsed_next = _parsed_response.next_cursor + _has_next = _parsed_next is not None and _parsed_next != "" + _get_next = lambda: self.search_episodes( + graph_uuid, + limit=limit, + cursor=_parsed_next, + bfs_origin_node_uuids=bfs_origin_node_uuids, + center_node_uuid=center_node_uuid, + filters=filters, + mmr_lambda=mmr_lambda, + query=query, + reranker=reranker, + idempotency_key=idempotency_key, + request_options=request_options, + ) + return SyncPager(has_next=_has_next, items=_items, get_next=_get_next, response=_parsed_response) + if _response.status_code == 400: + raise BadRequestError( + 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 == 401: + raise UnauthorizedError( + 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(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise core_api_error_ApiError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.text + ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) + raise core_api_error_ApiError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response_json + ) + + def search_nodes( + self, + graph_uuid: str, + *, + limit: typing.Optional[int] = None, + cursor: typing.Optional[str] = None, + bfs_origin_node_uuids: typing.Optional[typing.Sequence[str]] = OMIT, + center_node_uuid: typing.Optional[str] = OMIT, + filters: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + mmr_lambda: typing.Optional[float] = OMIT, + query: typing.Optional[str] = OMIT, + reranker: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> SyncPager[JsonObject, JsonObjectPage]: + """ + Parameters + ---------- + graph_uuid : str + Graph UUID + + limit : typing.Optional[int] + Page size + + cursor : typing.Optional[str] + Opaque page cursor + + bfs_origin_node_uuids : typing.Optional[typing.Sequence[str]] + + center_node_uuid : typing.Optional[str] + + filters : typing.Optional[typing.Dict[str, typing.Any]] + + mmr_lambda : typing.Optional[float] + + query : typing.Optional[str] + + reranker : typing.Optional[str] + + idempotency_key : typing.Optional[str] + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + SyncPager[JsonObject, JsonObjectPage] + OK + """ + _response = self._client_wrapper.httpx_client.request( + f"graphs/{jsonable_encoder(graph_uuid)}/search/nodes", + method="POST", + params={ + "limit": limit, + "cursor": cursor, + }, + json={ + "bfs_origin_node_uuids": bfs_origin_node_uuids, + "center_node_uuid": center_node_uuid, + "filters": filters, + "mmr_lambda": mmr_lambda, + "query": query, + "reranker": reranker, + }, + headers={ + "content-type": "application/json", + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, + }, request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + _parsed_response = typing.cast( + JsonObjectPage, + parse_obj_as( + type_=JsonObjectPage, # type: ignore + object_=_response.json(), + ), + ) + _items = _parsed_response.items + _parsed_next = _parsed_response.next_cursor + _has_next = _parsed_next is not None and _parsed_next != "" + _get_next = lambda: self.search_nodes( + graph_uuid, + limit=limit, + cursor=_parsed_next, + bfs_origin_node_uuids=bfs_origin_node_uuids, + center_node_uuid=center_node_uuid, + filters=filters, + mmr_lambda=mmr_lambda, + query=query, + reranker=reranker, + idempotency_key=idempotency_key, + request_options=request_options, + ) + return SyncPager(has_next=_has_next, items=_items, get_next=_get_next, response=_parsed_response) + if _response.status_code == 400: + raise BadRequestError( + 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 == 401: + raise UnauthorizedError( + 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(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise core_api_error_ApiError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.text + ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) + raise core_api_error_ApiError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response_json + ) + + def search_observations( + self, + graph_uuid: str, + *, + limit: typing.Optional[int] = None, + cursor: typing.Optional[str] = None, + bfs_origin_node_uuids: typing.Optional[typing.Sequence[str]] = OMIT, + center_node_uuid: typing.Optional[str] = OMIT, + filters: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + mmr_lambda: typing.Optional[float] = OMIT, + query: typing.Optional[str] = OMIT, + reranker: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> SyncPager[JsonObject, JsonObjectPage]: + """ + Parameters + ---------- + graph_uuid : str + Graph UUID + + limit : typing.Optional[int] + Page size + + cursor : typing.Optional[str] + Opaque page cursor + + bfs_origin_node_uuids : typing.Optional[typing.Sequence[str]] + + center_node_uuid : typing.Optional[str] + + filters : typing.Optional[typing.Dict[str, typing.Any]] + + mmr_lambda : typing.Optional[float] + + query : typing.Optional[str] + + reranker : typing.Optional[str] + + idempotency_key : typing.Optional[str] + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + SyncPager[JsonObject, JsonObjectPage] + OK + """ + _response = self._client_wrapper.httpx_client.request( + f"graphs/{jsonable_encoder(graph_uuid)}/search/observations", + method="POST", + params={ + "limit": limit, + "cursor": cursor, + }, + json={ + "bfs_origin_node_uuids": bfs_origin_node_uuids, + "center_node_uuid": center_node_uuid, + "filters": filters, + "mmr_lambda": mmr_lambda, + "query": query, + "reranker": reranker, + }, + headers={ + "content-type": "application/json", + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + _parsed_response = typing.cast( + JsonObjectPage, + parse_obj_as( + type_=JsonObjectPage, # type: ignore + object_=_response.json(), + ), + ) + _items = _parsed_response.items + _parsed_next = _parsed_response.next_cursor + _has_next = _parsed_next is not None and _parsed_next != "" + _get_next = lambda: self.search_observations( + graph_uuid, + limit=limit, + cursor=_parsed_next, + bfs_origin_node_uuids=bfs_origin_node_uuids, + center_node_uuid=center_node_uuid, + filters=filters, + mmr_lambda=mmr_lambda, + query=query, + reranker=reranker, + idempotency_key=idempotency_key, + request_options=request_options, + ) + return SyncPager(has_next=_has_next, items=_items, get_next=_get_next, response=_parsed_response) + if _response.status_code == 400: + raise BadRequestError( + 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 == 401: + raise UnauthorizedError( + 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(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise core_api_error_ApiError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.text + ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) + raise core_api_error_ApiError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response_json + ) + + def search_thread_summaries( + self, + graph_uuid: str, + *, + limit: typing.Optional[int] = None, + cursor: typing.Optional[str] = None, + bfs_origin_node_uuids: typing.Optional[typing.Sequence[str]] = OMIT, + center_node_uuid: typing.Optional[str] = OMIT, + filters: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + mmr_lambda: typing.Optional[float] = OMIT, + query: typing.Optional[str] = OMIT, + reranker: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> SyncPager[JsonObject, JsonObjectPage]: + """ + Parameters + ---------- + graph_uuid : str + Graph UUID + + limit : typing.Optional[int] + Page size + + cursor : typing.Optional[str] + Opaque page cursor + + bfs_origin_node_uuids : typing.Optional[typing.Sequence[str]] + + center_node_uuid : typing.Optional[str] + + filters : typing.Optional[typing.Dict[str, typing.Any]] + + mmr_lambda : typing.Optional[float] + + query : typing.Optional[str] + + reranker : typing.Optional[str] + + idempotency_key : typing.Optional[str] + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + SyncPager[JsonObject, JsonObjectPage] + OK + """ + _response = self._client_wrapper.httpx_client.request( + f"graphs/{jsonable_encoder(graph_uuid)}/search/thread-summaries", + method="POST", + params={ + "limit": limit, + "cursor": cursor, + }, + json={ + "bfs_origin_node_uuids": bfs_origin_node_uuids, + "center_node_uuid": center_node_uuid, + "filters": filters, + "mmr_lambda": mmr_lambda, + "query": query, + "reranker": reranker, + }, + headers={ + "content-type": "application/json", + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + _parsed_response = typing.cast( + JsonObjectPage, + parse_obj_as( + type_=JsonObjectPage, # type: ignore + object_=_response.json(), + ), + ) + _items = _parsed_response.items + _parsed_next = _parsed_response.next_cursor + _has_next = _parsed_next is not None and _parsed_next != "" + _get_next = lambda: self.search_thread_summaries( + graph_uuid, + limit=limit, + cursor=_parsed_next, + bfs_origin_node_uuids=bfs_origin_node_uuids, + center_node_uuid=center_node_uuid, + filters=filters, + mmr_lambda=mmr_lambda, + query=query, + reranker=reranker, + idempotency_key=idempotency_key, + request_options=request_options, + ) + return SyncPager(has_next=_has_next, items=_items, get_next=_get_next, response=_parsed_response) + if _response.status_code == 400: + raise BadRequestError( + 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 == 401: + raise UnauthorizedError( + 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(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise core_api_error_ApiError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.text + ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) + raise core_api_error_ApiError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response_json + ) + + def get_subgraph( + self, + graph_uuid: str, + *, + depth: typing.Optional[int] = OMIT, + direction: typing.Optional[str] = OMIT, + filters: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + max_edges: typing.Optional[int] = OMIT, + max_nodes: typing.Optional[int] = OMIT, + seed_node_uuids: typing.Optional[typing.Sequence[str]] = OMIT, + idempotency_key: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[JsonObject]: + """ + Parameters + ---------- + graph_uuid : str + Graph UUID + + depth : typing.Optional[int] + + direction : typing.Optional[str] + + filters : typing.Optional[typing.Dict[str, typing.Any]] + + max_edges : typing.Optional[int] + + max_nodes : typing.Optional[int] + + seed_node_uuids : typing.Optional[typing.Sequence[str]] + + idempotency_key : typing.Optional[str] + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[JsonObject] + OK + """ + _response = self._client_wrapper.httpx_client.request( + f"graphs/{jsonable_encoder(graph_uuid)}/subgraph", + method="POST", + json={ + "depth": depth, + "direction": direction, + "filters": filters, + "max_edges": max_edges, + "max_nodes": max_nodes, + "seed_node_uuids": seed_node_uuids, + }, + headers={ + "content-type": "application/json", + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, + }, + request_options=request_options, + omit=OMIT, ) try: if 200 <= _response.status_code < 300: _data = typing.cast( - Graph, + JsonObject, parse_obj_as( - type_=Graph, # type: ignore + type_=JsonObject, # type: ignore object_=_response.json(), ), ) - return HttpResponse(response=_response, data=_data) - if _response.status_code == 404: - raise NotFoundError( + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise BadRequestError( + 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 == 401: + raise UnauthorizedError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -1734,8 +2187,8 @@ def get(self, graph_id: str, *, request_options: typing.Optional[RequestOptions] ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -1750,40 +2203,51 @@ def get(self, graph_id: str, *, request_options: typing.Optional[RequestOptions] raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - def delete( - self, graph_id: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> HttpResponse[SuccessResponse]: + def warm( + self, + graph_uuid: str, + *, + idempotency_key: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[AsyncResult]: """ - Deletes a graph. If you would like to delete a user graph, make sure to use user.delete instead. - Parameters ---------- - graph_id : str - Graph ID + graph_uuid : str + Graph UUID + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - HttpResponse[SuccessResponse] - Deleted + HttpResponse[AsyncResult] + Accepted """ _response = self._client_wrapper.httpx_client.request( - f"graph/{jsonable_encoder(graph_id)}", - method="DELETE", + f"graphs/{jsonable_encoder(graph_uuid)}/warm", + method="POST", + headers={ + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, + }, request_options=request_options, ) try: if 200 <= _response.status_code < 300: _data = typing.cast( - SuccessResponse, + AsyncResult, parse_obj_as( - type_=SuccessResponse, # type: ignore + type_=AsyncResult, # type: ignore object_=_response.json(), ), ) @@ -1792,15 +2256,15 @@ def delete( raise BadRequestError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore object_=_response.json(), ), ), ) - if _response.status_code == 404: - raise NotFoundError( + if _response.status_code == 401: + raise UnauthorizedError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -1810,8 +2274,8 @@ def delete( ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -1826,52 +2290,62 @@ def delete( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - def update( + +class AsyncRawGraphClient: + def __init__(self, *, client_wrapper: AsyncClientWrapper): + self._client_wrapper = client_wrapper + + async def create( self, - graph_id: str, *, description: typing.Optional[str] = OMIT, + graph_id: typing.Optional[str] = OMIT, name: typing.Optional[str] = OMIT, time_zone: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> HttpResponse[Graph]: + ) -> AsyncHttpResponse[Graph]: """ - Updates information about a graph. - Parameters ---------- - graph_id : str - Graph ID - description : typing.Optional[str] + graph_id : typing.Optional[str] + name : typing.Optional[str] time_zone : typing.Optional[str] - The graph's IANA time zone. Stored on its group-backed subject. + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - HttpResponse[Graph] - The updated graph object + AsyncHttpResponse[Graph] + Created """ - _response = self._client_wrapper.httpx_client.request( - f"graph/{jsonable_encoder(graph_id)}", - method="PATCH", + _response = await self._client_wrapper.httpx_client.request( + "graphs", + method="POST", json={ "description": description, + "graph_id": graph_id, "name": name, "time_zone": time_zone, }, headers={ "content-type": "application/json", + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, }, request_options=request_options, omit=OMIT, @@ -1885,20 +2359,20 @@ def update( object_=_response.json(), ), ) - return HttpResponse(response=_response, data=_data) + return AsyncHttpResponse(response=_response, data=_data) if _response.status_code == 400: raise BadRequestError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore object_=_response.json(), ), ), ) - if _response.status_code == 404: - raise NotFoundError( + if _response.status_code == 401: + raise UnauthorizedError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -1908,8 +2382,8 @@ def update( ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -1924,46 +2398,109 @@ def update( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - def warm( - self, graph_id: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> HttpResponse[SuccessResponse]: + async def list( + self, + *, + limit: typing.Optional[int] = None, + cursor: typing.Optional[str] = None, + order_by: typing.Optional[str] = None, + order: typing.Optional[str] = None, + search: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncPager[Graph, GraphPage]: """ - Hints Zep to warm a graph for low-latency search - Parameters ---------- - graph_id : str - The graph_id of the graph to warm. + limit : typing.Optional[int] + Page size + + cursor : typing.Optional[str] + Opaque page cursor + + order_by : typing.Optional[str] + Sort field + + order : typing.Optional[str] + asc or desc + + search : typing.Optional[str] + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - HttpResponse[SuccessResponse] - Warm hint accepted + AsyncPager[Graph, GraphPage] + OK """ - _response = self._client_wrapper.httpx_client.request( - f"graph/{jsonable_encoder(graph_id)}/warm", - method="GET", + _response = await self._client_wrapper.httpx_client.request( + "graphs/list", + method="POST", + params={ + "limit": limit, + "cursor": cursor, + "order_by": order_by, + "order": order, + }, + json={ + "search": search, + }, + headers={ + "content-type": "application/json", + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, + }, request_options=request_options, + omit=OMIT, ) try: if 200 <= _response.status_code < 300: - _data = typing.cast( - SuccessResponse, + _parsed_response = typing.cast( + GraphPage, parse_obj_as( - type_=SuccessResponse, # type: ignore + type_=GraphPage, # type: ignore object_=_response.json(), ), ) - return HttpResponse(response=_response, data=_data) - if _response.status_code == 404: - raise NotFoundError( + _items = _parsed_response.items + _parsed_next = _parsed_response.next_cursor + _has_next = _parsed_next is not None and _parsed_next != "" + + async def _get_next(): + return await self.list( + limit=limit, + cursor=_parsed_next, + order_by=order_by, + order=order, + search=search, + idempotency_key=idempotency_key, + request_options=request_options, + ) + + return AsyncPager(has_next=_has_next, items=_items, get_next=_get_next, response=_parsed_response) + if _response.status_code == 400: + raise BadRequestError( + 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 == 401: + raise UnauthorizedError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -1973,8 +2510,8 @@ def warm( ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -1989,56 +2526,63 @@ def warm( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - -class AsyncRawGraphClient: - def __init__(self, *, client_wrapper: AsyncClientWrapper): - self._client_wrapper = client_wrapper - - async def list_custom_instructions( + async def lookup( self, *, - user_id: typing.Optional[str] = None, - graph_id: typing.Optional[str] = None, + graph_id: typing.Optional[str] = OMIT, + thread_id: typing.Optional[str] = OMIT, + user_id: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> AsyncHttpResponse[ListCustomInstructionsResponse]: + ) -> AsyncHttpResponse[Graph]: """ - Lists all custom instructions for a project, user, or graph. - Parameters ---------- + graph_id : typing.Optional[str] + + thread_id : typing.Optional[str] + user_id : typing.Optional[str] - User ID to get user-specific instructions - graph_id : typing.Optional[str] - Graph ID to get graph-specific instructions + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - AsyncHttpResponse[ListCustomInstructionsResponse] - The list of instructions. + AsyncHttpResponse[Graph] + OK """ _response = await self._client_wrapper.httpx_client.request( - "custom-instructions", - method="GET", - params={ - "user_id": user_id, + "graphs/lookup", + method="POST", + json={ "graph_id": graph_id, + "thread_id": thread_id, + "user_id": user_id, + }, + headers={ + "content-type": "application/json", + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, }, request_options=request_options, + omit=OMIT, ) try: if 200 <= _response.status_code < 300: _data = typing.cast( - ListCustomInstructionsResponse, + Graph, parse_obj_as( - type_=ListCustomInstructionsResponse, # type: ignore + type_=Graph, # type: ignore object_=_response.json(), ), ) @@ -2047,15 +2591,15 @@ async def list_custom_instructions( raise BadRequestError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore object_=_response.json(), ), ), ) - if _response.status_code == 404: - raise NotFoundError( + if _response.status_code == 401: + raise UnauthorizedError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -2065,8 +2609,8 @@ async def list_custom_instructions( ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -2081,62 +2625,42 @@ async def list_custom_instructions( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - async def add_custom_instructions( - self, - *, - instructions: typing.Sequence[CustomInstruction], - graph_ids: typing.Optional[typing.Sequence[str]] = OMIT, - user_ids: typing.Optional[typing.Sequence[str]] = OMIT, - request_options: typing.Optional[RequestOptions] = None, - ) -> AsyncHttpResponse[SuccessResponse]: + async def get( + self, graph_uuid: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> AsyncHttpResponse[Graph]: """ - Adds new custom instructions for graphs without removing existing ones. If user_ids or graph_ids is empty, adds to project-wide default instructions. - Parameters ---------- - instructions : typing.Sequence[CustomInstruction] - Instructions to add to the graph. - - graph_ids : typing.Optional[typing.Sequence[str]] - Graph IDs to add the instructions to. If empty, the instructions are added to the project-wide default. - - user_ids : typing.Optional[typing.Sequence[str]] - User IDs to add the instructions to. If empty, the instructions are added to the project-wide default. + graph_uuid : str + Graph UUID request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - AsyncHttpResponse[SuccessResponse] - Instructions added successfully + AsyncHttpResponse[Graph] + OK """ _response = await self._client_wrapper.httpx_client.request( - "custom-instructions", - method="POST", - json={ - "graph_ids": graph_ids, - "instructions": convert_and_respect_annotation_metadata( - object_=instructions, annotation=typing.Sequence[CustomInstruction], direction="write" - ), - "user_ids": user_ids, - }, - headers={ - "content-type": "application/json", - }, + f"graphs/{jsonable_encoder(graph_uuid)}", + method="GET", request_options=request_options, - omit=OMIT, ) try: if 200 <= _response.status_code < 300: _data = typing.cast( - SuccessResponse, + Graph, parse_obj_as( - type_=SuccessResponse, # type: ignore + type_=Graph, # type: ignore object_=_response.json(), ), ) @@ -2145,15 +2669,15 @@ async def add_custom_instructions( raise BadRequestError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore object_=_response.json(), ), ), ) - if _response.status_code == 404: - raise NotFoundError( + if _response.status_code == 401: + raise UnauthorizedError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -2163,8 +2687,8 @@ async def add_custom_instructions( ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -2179,60 +2703,51 @@ async def add_custom_instructions( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - async def delete_custom_instructions( + async def delete( self, + graph_uuid: str, *, - graph_ids: typing.Optional[typing.Sequence[str]] = OMIT, - instruction_names: typing.Optional[typing.Sequence[str]] = OMIT, - user_ids: typing.Optional[typing.Sequence[str]] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> AsyncHttpResponse[SuccessResponse]: + ) -> AsyncHttpResponse[GraphDeleteResult]: """ - Deletes custom instructions for graphs or project wide defaults. - Parameters ---------- - graph_ids : typing.Optional[typing.Sequence[str]] - Determines which group graphs will have their custom instructions deleted. If no graphs are provided, the project-wide custom instructions will be affected. + graph_uuid : str + Graph UUID - instruction_names : typing.Optional[typing.Sequence[str]] - Unique identifier for the instructions to be deleted. If empty deletes all instructions. - - user_ids : typing.Optional[typing.Sequence[str]] - Determines which user graphs will have their custom instructions deleted. If no users are provided, the project-wide custom instructions will be affected. + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - AsyncHttpResponse[SuccessResponse] - Instructions deleted successfully + AsyncHttpResponse[GraphDeleteResult] + Accepted """ _response = await self._client_wrapper.httpx_client.request( - "custom-instructions", + f"graphs/{jsonable_encoder(graph_uuid)}", method="DELETE", - json={ - "graph_ids": graph_ids, - "instruction_names": instruction_names, - "user_ids": user_ids, - }, headers={ - "content-type": "application/json", + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, }, request_options=request_options, - omit=OMIT, ) try: if 200 <= _response.status_code < 300: _data = typing.cast( - SuccessResponse, + GraphDeleteResult, parse_obj_as( - type_=SuccessResponse, # type: ignore + type_=GraphDeleteResult, # type: ignore object_=_response.json(), ), ) @@ -2241,15 +2756,15 @@ async def delete_custom_instructions( raise BadRequestError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore object_=_response.json(), ), ), ) - if _response.status_code == 404: - raise NotFoundError( + if _response.status_code == 401: + raise UnauthorizedError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -2259,8 +2774,8 @@ async def delete_custom_instructions( ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -2275,51 +2790,70 @@ async def delete_custom_instructions( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - async def list_entity_types( + async def update( self, + graph_uuid: str, *, - user_id: typing.Optional[str] = None, - graph_id: typing.Optional[str] = None, + description: typing.Optional[str] = OMIT, + name: typing.Optional[str] = OMIT, + time_zone: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> AsyncHttpResponse[EntityTypeResponse]: + ) -> AsyncHttpResponse[Graph]: """ - Returns all entity types for a project, user, or graph. - Parameters ---------- - user_id : typing.Optional[str] - User ID to get user-specific entity types + graph_uuid : str + Graph UUID - graph_id : typing.Optional[str] - Graph ID to get graph-specific entity types + description : typing.Optional[str] + Omit to leave unchanged, send JSON null to clear, or send a value to set. + + name : typing.Optional[str] + Omit to leave unchanged, send JSON null to clear, or send a value to set. + + time_zone : typing.Optional[str] + Omit to leave unchanged, send JSON null to clear, or send a value to set. + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - AsyncHttpResponse[EntityTypeResponse] - The list of entity types. + AsyncHttpResponse[Graph] + OK """ _response = await self._client_wrapper.httpx_client.request( - "entity-types", - method="GET", - params={ - "user_id": user_id, - "graph_id": graph_id, + f"graphs/{jsonable_encoder(graph_uuid)}", + method="PATCH", + json={ + "description": description, + "name": name, + "time_zone": time_zone, + }, + headers={ + "content-type": "application/json", + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, }, request_options=request_options, + omit=OMIT, ) try: if 200 <= _response.status_code < 300: _data = typing.cast( - EntityTypeResponse, + Graph, parse_obj_as( - type_=EntityTypeResponse, # type: ignore + type_=Graph, # type: ignore object_=_response.json(), ), ) @@ -2328,15 +2862,15 @@ async def list_entity_types( raise BadRequestError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore object_=_response.json(), ), ), ) - if _response.status_code == 404: - raise NotFoundError( + if _response.status_code == 401: + raise UnauthorizedError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -2346,8 +2880,8 @@ async def list_entity_types( ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -2362,55 +2896,49 @@ async def list_entity_types( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - async def set_entity_types_internal( + async def clone( self, + graph_uuid: str, *, - edge_types: typing.Optional[typing.Sequence[EdgeType]] = OMIT, - entity_types: typing.Optional[typing.Sequence[EntityType]] = OMIT, - graph_ids: typing.Optional[typing.Sequence[str]] = OMIT, - user_ids: typing.Optional[typing.Sequence[str]] = OMIT, + target_graph_id: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> AsyncHttpResponse[SuccessResponse]: + ) -> AsyncHttpResponse[CloneGraphResult]: """ - Sets the entity types for multiple users and graphs, replacing any existing ones. - Parameters ---------- - edge_types : typing.Optional[typing.Sequence[EdgeType]] - - entity_types : typing.Optional[typing.Sequence[EntityType]] + graph_uuid : str + Graph UUID - graph_ids : typing.Optional[typing.Sequence[str]] + target_graph_id : typing.Optional[str] - user_ids : typing.Optional[typing.Sequence[str]] + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - AsyncHttpResponse[SuccessResponse] - Entity types set successfully + AsyncHttpResponse[CloneGraphResult] + Accepted """ _response = await self._client_wrapper.httpx_client.request( - "entity-types", - method="PUT", + f"graphs/{jsonable_encoder(graph_uuid)}/clone", + method="POST", json={ - "edge_types": convert_and_respect_annotation_metadata( - object_=edge_types, annotation=typing.Sequence[EdgeType], direction="write" - ), - "entity_types": convert_and_respect_annotation_metadata( - object_=entity_types, annotation=typing.Sequence[EntityType], direction="write" - ), - "graph_ids": graph_ids, - "user_ids": user_ids, + "target_graph_id": target_graph_id, }, headers={ "content-type": "application/json", + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, }, request_options=request_options, omit=OMIT, @@ -2418,9 +2946,9 @@ async def set_entity_types_internal( try: if 200 <= _response.status_code < 300: _data = typing.cast( - SuccessResponse, + CloneGraphResult, parse_obj_as( - type_=SuccessResponse, # type: ignore + type_=CloneGraphResult, # type: ignore object_=_response.json(), ), ) @@ -2429,15 +2957,15 @@ async def set_entity_types_internal( raise BadRequestError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore object_=_response.json(), ), ), ) - if _response.status_code == 404: - raise NotFoundError( + if _response.status_code == 401: + raise UnauthorizedError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -2447,8 +2975,8 @@ async def set_entity_types_internal( ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -2463,71 +2991,69 @@ async def set_entity_types_internal( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - async def add( + async def get_context( self, + graph_uuid: str, *, - data: str, - type: GraphDataType, - created_at: 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, - strict_ontology: typing.Optional[bool] = OMIT, - user_id: typing.Optional[str] = OMIT, + filters: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + include_results: typing.Optional[bool] = OMIT, + max_characters: typing.Optional[int] = OMIT, + query: typing.Optional[str] = OMIT, + recency_bias: typing.Optional[str] = OMIT, + template_uuid: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> AsyncHttpResponse[Episode]: + ) -> AsyncHttpResponse[GraphContextResponse]: """ - Add data to the graph. - Parameters ---------- - data : str + graph_uuid : str + Graph UUID - type : GraphDataType + filters : typing.Optional[typing.Dict[str, typing.Any]] - created_at : typing.Optional[str] + include_results : typing.Optional[bool] - 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. + max_characters : typing.Optional[int] - metadata : typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] - Optional metadata key-value pairs. Max 10 keys. Values must be strings, numbers, booleans, or arrays of scalars. + query : typing.Optional[str] - source_description : typing.Optional[str] + recency_bias : typing.Optional[str] - strict_ontology : typing.Optional[bool] - When true, prevents extraction of generic Entity nodes that do not match the configured ontology. + template_uuid : typing.Optional[str] - user_id : typing.Optional[str] - User ID is the ID of the user to which the data will be added. If not adding to a user graph, please use graph_id field instead. + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - AsyncHttpResponse[Episode] - Added episode + AsyncHttpResponse[GraphContextResponse] + OK """ _response = await self._client_wrapper.httpx_client.request( - "graph", + f"graphs/{jsonable_encoder(graph_uuid)}/context", method="POST", json={ - "created_at": created_at, - "data": data, - "graph_id": graph_id, - "metadata": metadata, - "source_description": source_description, - "strict_ontology": strict_ontology, - "type": type, - "user_id": user_id, + "filters": filters, + "include_results": include_results, + "max_characters": max_characters, + "query": query, + "recency_bias": recency_bias, + "template_uuid": template_uuid, }, headers={ "content-type": "application/json", + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, }, request_options=request_options, omit=OMIT, @@ -2535,9 +3061,9 @@ async def add( try: if 200 <= _response.status_code < 300: _data = typing.cast( - Episode, + GraphContextResponse, parse_obj_as( - type_=Episode, # type: ignore + type_=GraphContextResponse, # type: ignore object_=_response.json(), ), ) @@ -2546,15 +3072,26 @@ async def add( raise BadRequestError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore object_=_response.json(), ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -2569,68 +3106,42 @@ async def add( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - async def add_batch( - self, - *, - episodes: typing.Sequence[EpisodeData], - graph_id: typing.Optional[str] = OMIT, - strict_ontology: typing.Optional[bool] = OMIT, - user_id: typing.Optional[str] = OMIT, - request_options: typing.Optional[RequestOptions] = None, - ) -> AsyncHttpResponse[typing.List[Episode]]: + async def get_instructions( + self, graph_uuid: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> AsyncHttpResponse[Instructions]: """ - Deprecated. Use the [Batch API](/adding-batch-data) (`client.batch.*`) instead. - - Adds data to the graph in batch mode, processing episodes concurrently. - Parameters ---------- - episodes : typing.Sequence[EpisodeData] - - 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. - - strict_ontology : typing.Optional[bool] - When true, prevents extraction of generic Entity nodes that do not match the configured ontology. - - user_id : typing.Optional[str] - User ID is the ID of the user to which the data will be added. If not adding to a user graph, please use graph_id field instead. + graph_uuid : str + Graph UUID request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - AsyncHttpResponse[typing.List[Episode]] - Added episodes + AsyncHttpResponse[Instructions] + OK """ _response = await self._client_wrapper.httpx_client.request( - "graph-batch", - method="POST", - json={ - "episodes": convert_and_respect_annotation_metadata( - object_=episodes, annotation=typing.Sequence[EpisodeData], direction="write" - ), - "graph_id": graph_id, - "strict_ontology": strict_ontology, - "user_id": user_id, - }, - headers={ - "content-type": "application/json", - }, + f"graphs/{jsonable_encoder(graph_uuid)}/instructions", + method="GET", request_options=request_options, - omit=OMIT, ) try: if 200 <= _response.status_code < 300: _data = typing.cast( - typing.List[Episode], + Instructions, parse_obj_as( - type_=typing.List[Episode], # type: ignore + type_=Instructions, # type: ignore object_=_response.json(), ), ) @@ -2639,15 +3150,26 @@ async def add_batch( raise BadRequestError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore object_=_response.json(), ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -2662,145 +3184,53 @@ async def add_batch( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - async def add_fact_triple( + async def set_instructions( self, + graph_uuid: str, *, - fact: str, - fact_name: str, - created_at: typing.Optional[str] = OMIT, - edge_attributes: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = OMIT, - expired_at: typing.Optional[str] = OMIT, - graph_id: typing.Optional[str] = OMIT, - invalid_at: typing.Optional[str] = OMIT, - metadata: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = OMIT, - source_node_attributes: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = OMIT, - source_node_labels: typing.Optional[typing.Sequence[str]] = OMIT, - source_node_name: typing.Optional[str] = OMIT, - source_node_summary: typing.Optional[str] = OMIT, - source_node_uuid: typing.Optional[str] = OMIT, - target_node_attributes: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = OMIT, - target_node_labels: typing.Optional[typing.Sequence[str]] = OMIT, - target_node_name: typing.Optional[str] = OMIT, - target_node_summary: typing.Optional[str] = OMIT, - target_node_uuid: typing.Optional[str] = OMIT, - user_id: typing.Optional[str] = OMIT, - valid_at: typing.Optional[str] = OMIT, + inherited: typing.Optional[bool] = OMIT, + instructions: typing.Optional[typing.Sequence[typing.Dict[str, typing.Any]]] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> AsyncHttpResponse[AddTripleResponse]: + ) -> AsyncHttpResponse[Instructions]: """ - Add a fact triple for a user or group - Parameters ---------- - fact : str - The fact relating the two nodes that this edge represents - - fact_name : str - The name of the edge to add. Should be all caps using snake case (eg RELATES_TO) - - created_at : typing.Optional[str] - The timestamp of the message - - edge_attributes : typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] - Additional attributes of the edge. Values must be scalar types (string, number, boolean, or null). - Nested objects and arrays are not allowed. - - expired_at : typing.Optional[str] - The time (if any) at which the edge expires + graph_uuid : str + Graph UUID - graph_id : typing.Optional[str] - - invalid_at : typing.Optional[str] - The time (if any) at which the fact stops being true - - metadata : typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] - Optional metadata key-value pairs for the shadow episode created for this fact triple. - Max 10 keys. Values must be strings, numbers, or booleans. - - source_node_attributes : typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] - Additional attributes of the source node. Values must be scalar types (string, number, boolean, or null). - Nested objects and arrays are not allowed. - - source_node_labels : typing.Optional[typing.Sequence[str]] - The labels for the source node. At most one entity-type label may be - provided so that manually-added triples remain consistent with automatic - episode extraction, which assigns one best-match entity type per node. - The base "Entity" label is added implicitly by the graph layer on save - and does not need to be supplied here. - - source_node_name : typing.Optional[str] - The name of the source node to add - - source_node_summary : typing.Optional[str] - The summary of the source node to add - - source_node_uuid : typing.Optional[str] - The source node uuid + inherited : typing.Optional[bool] - target_node_attributes : typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] - Additional attributes of the target node. Values must be scalar types (string, number, boolean, or null). - Nested objects and arrays are not allowed. + instructions : typing.Optional[typing.Sequence[typing.Dict[str, typing.Any]]] - target_node_labels : typing.Optional[typing.Sequence[str]] - The labels for the target node. At most one entity-type label may be - provided so that manually-added triples remain consistent with automatic - episode extraction, which assigns one best-match entity type per node. - The base "Entity" label is added implicitly by the graph layer on save - and does not need to be supplied here. - - target_node_name : typing.Optional[str] - The name of the target node to add - - target_node_summary : typing.Optional[str] - The summary of the target node to add - - target_node_uuid : typing.Optional[str] - The target node uuid - - user_id : typing.Optional[str] - - valid_at : typing.Optional[str] - The time at which the fact becomes true + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - AsyncHttpResponse[AddTripleResponse] - Resulting triple + AsyncHttpResponse[Instructions] + OK """ _response = await self._client_wrapper.httpx_client.request( - "graph/add-fact-triple", - method="POST", + f"graphs/{jsonable_encoder(graph_uuid)}/instructions", + method="PUT", json={ - "created_at": created_at, - "edge_attributes": edge_attributes, - "expired_at": expired_at, - "fact": fact, - "fact_name": fact_name, - "graph_id": graph_id, - "invalid_at": invalid_at, - "metadata": metadata, - "source_node_attributes": source_node_attributes, - "source_node_labels": source_node_labels, - "source_node_name": source_node_name, - "source_node_summary": source_node_summary, - "source_node_uuid": source_node_uuid, - "target_node_attributes": target_node_attributes, - "target_node_labels": target_node_labels, - "target_node_name": target_node_name, - "target_node_summary": target_node_summary, - "target_node_uuid": target_node_uuid, - "user_id": user_id, - "valid_at": valid_at, + "inherited": inherited, + "instructions": instructions, }, headers={ "content-type": "application/json", + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, }, request_options=request_options, omit=OMIT, @@ -2808,9 +3238,9 @@ async def add_fact_triple( try: if 200 <= _response.status_code < 300: _data = typing.cast( - AddTripleResponse, + Instructions, parse_obj_as( - type_=AddTripleResponse, # type: ignore + type_=Instructions, # type: ignore object_=_response.json(), ), ) @@ -2819,15 +3249,26 @@ async def add_fact_triple( raise BadRequestError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore object_=_response.json(), ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -2842,65 +3283,42 @@ async def add_fact_triple( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - async def clone( - self, - *, - source_graph_id: typing.Optional[str] = OMIT, - source_user_id: typing.Optional[str] = OMIT, - target_graph_id: typing.Optional[str] = OMIT, - target_user_id: typing.Optional[str] = OMIT, - request_options: typing.Optional[RequestOptions] = None, - ) -> AsyncHttpResponse[CloneGraphResponse]: + async def get_observation_steering( + self, graph_uuid: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> AsyncHttpResponse[ObservationSteering]: """ - Clone a user or group graph. - Parameters ---------- - source_graph_id : typing.Optional[str] - source_graph_id is the ID of the graph to be cloned. Required if source_user_id is not provided - - source_user_id : typing.Optional[str] - user_id of the user whose graph is being cloned. Required if source_graph_id is not provided - - target_graph_id : typing.Optional[str] - target_graph_id is the ID to be set on the cloned graph. Must not point to an existing graph. Required if target_user_id is not provided. - - target_user_id : typing.Optional[str] - user_id to be set on the cloned user. Must not point to an existing user. Required if target_graph_id is not provided. + graph_uuid : str + Graph UUID request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - AsyncHttpResponse[CloneGraphResponse] - Response object containing graph_id or user_id pointing to the new graph + AsyncHttpResponse[ObservationSteering] + OK """ _response = await self._client_wrapper.httpx_client.request( - "graph/clone", - method="POST", - json={ - "source_graph_id": source_graph_id, - "source_user_id": source_user_id, - "target_graph_id": target_graph_id, - "target_user_id": target_user_id, - }, - headers={ - "content-type": "application/json", - }, + f"graphs/{jsonable_encoder(graph_uuid)}/observation-steering", + method="GET", request_options=request_options, - omit=OMIT, ) try: if 200 <= _response.status_code < 300: _data = typing.cast( - CloneGraphResponse, + ObservationSteering, parse_obj_as( - type_=CloneGraphResponse, # type: ignore + type_=ObservationSteering, # type: ignore object_=_response.json(), ), ) @@ -2909,15 +3327,26 @@ async def clone( raise BadRequestError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore object_=_response.json(), ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -2932,52 +3361,57 @@ async def clone( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - async def create( + async def set_observation_steering( self, + graph_uuid: str, *, - graph_id: str, - description: typing.Optional[str] = OMIT, - name: typing.Optional[str] = OMIT, - time_zone: typing.Optional[str] = OMIT, + inherited: typing.Optional[bool] = OMIT, + instruction: typing.Optional[str] = OMIT, + types: typing.Optional[typing.Sequence[typing.Dict[str, typing.Any]]] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> AsyncHttpResponse[Graph]: + ) -> AsyncHttpResponse[ObservationSteering]: """ - Creates a new graph. - Parameters ---------- - graph_id : str + graph_uuid : str + Graph UUID - description : typing.Optional[str] + inherited : typing.Optional[bool] - name : typing.Optional[str] + instruction : typing.Optional[str] - time_zone : typing.Optional[str] - The graph's IANA time zone. Stored on its group-backed subject. + types : typing.Optional[typing.Sequence[typing.Dict[str, typing.Any]]] + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - AsyncHttpResponse[Graph] - The added graph + AsyncHttpResponse[ObservationSteering] + OK """ _response = await self._client_wrapper.httpx_client.request( - "graph/create", - method="POST", + f"graphs/{jsonable_encoder(graph_uuid)}/observation-steering", + method="PUT", json={ - "description": description, - "graph_id": graph_id, - "name": name, - "time_zone": time_zone, + "inherited": inherited, + "instruction": instruction, + "types": types, }, headers={ "content-type": "application/json", + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, }, request_options=request_options, omit=OMIT, @@ -2985,9 +3419,9 @@ async def create( try: if 200 <= _response.status_code < 300: _data = typing.cast( - Graph, + ObservationSteering, parse_obj_as( - type_=Graph, # type: ignore + type_=ObservationSteering, # type: ignore object_=_response.json(), ), ) @@ -2996,15 +3430,26 @@ async def create( raise BadRequestError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore object_=_response.json(), ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -3019,66 +3464,42 @@ async def create( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - async def list_all( - self, - *, - page_number: typing.Optional[int] = None, - page_size: typing.Optional[int] = None, - search: typing.Optional[str] = None, - order_by: typing.Optional[str] = None, - asc: typing.Optional[bool] = None, - request_options: typing.Optional[RequestOptions] = None, - ) -> AsyncHttpResponse[GraphListResponse]: + async def get_ontology( + self, graph_uuid: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> AsyncHttpResponse[Ontology]: """ - Returns all graphs. In order to list users, use user.list_ordered instead - Parameters ---------- - page_number : typing.Optional[int] - Page number for pagination, starting from 1. - - page_size : typing.Optional[int] - Number of graphs to retrieve per page (default 50, range 1-100; explicit 0 is invalid). - - search : typing.Optional[str] - Search term for filtering graphs by graph_id, name, or description. Queries longer than 200 Unicode code points after whitespace normalization are invalid. - - order_by : typing.Optional[str] - Column to sort by (created_at, graph_id, name). - - asc : typing.Optional[bool] - Sort in ascending order. + graph_uuid : str + Graph UUID request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - AsyncHttpResponse[GraphListResponse] - Successfully retrieved list of graphs. + AsyncHttpResponse[Ontology] + OK """ _response = await self._client_wrapper.httpx_client.request( - "graph/list-all", + f"graphs/{jsonable_encoder(graph_uuid)}/ontology", method="GET", - params={ - "pageNumber": page_number, - "pageSize": page_size, - "search": search, - "order_by": order_by, - "asc": asc, - }, request_options=request_options, ) try: if 200 <= _response.status_code < 300: _data = typing.cast( - GraphListResponse, + Ontology, parse_obj_as( - type_=GraphListResponse, # type: ignore + type_=Ontology, # type: ignore object_=_response.json(), ), ) @@ -3087,15 +3508,26 @@ async def list_all( raise BadRequestError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore object_=_response.json(), ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -3110,50 +3542,57 @@ async def list_all( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - async def add_nodes( + async def set_ontology( self, + graph_uuid: str, *, - nodes: typing.Sequence[AddNodeItem], - graph_id: typing.Optional[str] = OMIT, - user_id: typing.Optional[str] = OMIT, + edge_types: typing.Optional[typing.Sequence[typing.Dict[str, typing.Any]]] = OMIT, + entity_types: typing.Optional[typing.Sequence[typing.Dict[str, typing.Any]]] = OMIT, + inherited: typing.Optional[bool] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> AsyncHttpResponse[AddNodesResponse]: + ) -> AsyncHttpResponse[Ontology]: """ - Add entity nodes to a user or graph directly, without episode ingestion. Up to 100 nodes per request. - Parameters ---------- - nodes : typing.Sequence[AddNodeItem] - The nodes to add. 1 to 100 items. + graph_uuid : str + Graph UUID - graph_id : typing.Optional[str] + edge_types : typing.Optional[typing.Sequence[typing.Dict[str, typing.Any]]] - user_id : typing.Optional[str] + entity_types : typing.Optional[typing.Sequence[typing.Dict[str, typing.Any]]] + + inherited : typing.Optional[bool] + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - AsyncHttpResponse[AddNodesResponse] - Accepted + AsyncHttpResponse[Ontology] + OK """ _response = await self._client_wrapper.httpx_client.request( - "graph/nodes", - method="POST", + f"graphs/{jsonable_encoder(graph_uuid)}/ontology", + method="PUT", json={ - "graph_id": graph_id, - "nodes": convert_and_respect_annotation_metadata( - object_=nodes, annotation=typing.Sequence[AddNodeItem], direction="write" - ), - "user_id": user_id, + "edge_types": edge_types, + "entity_types": entity_types, + "inherited": inherited, }, headers={ "content-type": "application/json", + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, }, request_options=request_options, omit=OMIT, @@ -3161,9 +3600,9 @@ async def add_nodes( try: if 200 <= _response.status_code < 300: _data = typing.cast( - AddNodesResponse, + Ontology, parse_obj_as( - type_=AddNodesResponse, # type: ignore + type_=Ontology, # type: ignore object_=_response.json(), ), ) @@ -3172,15 +3611,26 @@ async def add_nodes( raise BadRequestError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore object_=_response.json(), ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -3195,131 +3645,116 @@ async def add_nodes( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - async def detect_patterns( + async def search_edges( self, + graph_uuid: str, *, - detect: typing.Optional[DetectConfig] = OMIT, - edge_limit: typing.Optional[int] = OMIT, - graph_id: typing.Optional[str] = OMIT, - limit: typing.Optional[int] = OMIT, - min_occurrences: typing.Optional[int] = OMIT, + limit: typing.Optional[int] = None, + cursor: typing.Optional[str] = None, + bfs_origin_node_uuids: typing.Optional[typing.Sequence[str]] = OMIT, + center_node_uuid: typing.Optional[str] = OMIT, + filters: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + mmr_lambda: typing.Optional[float] = OMIT, query: typing.Optional[str] = OMIT, - query_limit: typing.Optional[int] = OMIT, - recency_weight: typing.Optional[RecencyWeight] = OMIT, - search_filters: typing.Optional[SearchFilters] = OMIT, - seeds: typing.Optional[PatternSeeds] = OMIT, - user_id: typing.Optional[str] = OMIT, + reranker: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> AsyncHttpResponse[DetectPatternsResponse]: + ) -> AsyncPager[JsonObject, JsonObjectPage]: """ - 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, - detects triple-frequency patterns, and returns resolved edges ranked by relevance. - Parameters ---------- - detect : typing.Optional[DetectConfig] - Which pattern types to detect with type-specific configuration. - Omit to detect all types with defaults. Ignored when query is set. - - edge_limit : typing.Optional[int] - Max resolved edges per pattern. Default: 10, Max: 100. Only used with query. - - graph_id : typing.Optional[str] - Graph ID when detecting patterns on a named graph + graph_uuid : str + Graph UUID limit : typing.Optional[int] - Max patterns to return. Default: 50, Max: 200 + Page size - min_occurrences : typing.Optional[int] - Minimum occurrence count to report a pattern. Default: 2 + cursor : typing.Optional[str] + Opaque page cursor - query : typing.Optional[str] - Search query for discovering seed nodes via hybrid search. - When set, forces triple-frequency detection only and enables edge resolution - with cross-encoder reranking. Mutually exclusive with seeds. + bfs_origin_node_uuids : typing.Optional[typing.Sequence[str]] - query_limit : typing.Optional[int] - Max seed nodes from search. Default: 10, Max: 50. Only used with query. + center_node_uuid : typing.Optional[str] - recency_weight : typing.Optional[RecencyWeight] - Exponential half-life decay applied to edge created_at timestamps. - Valid values: none, 7_days, 30_days, 90_days. Default: none + filters : typing.Optional[typing.Dict[str, typing.Any]] - search_filters : typing.Optional[SearchFilters] - Filters which edges/nodes participate in pattern detection. - Reuses the same filter format as /graph/search. + mmr_lambda : typing.Optional[float] - seeds : typing.Optional[PatternSeeds] - Seed selection. If omitted, analyzes the entire graph. Mutually exclusive with query. + query : typing.Optional[str] - user_id : typing.Optional[str] - User ID when detecting patterns on a user graph + reranker : typing.Optional[str] + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - AsyncHttpResponse[DetectPatternsResponse] - Detected patterns + AsyncPager[JsonObject, JsonObjectPage] + OK """ _response = await self._client_wrapper.httpx_client.request( - "graph/patterns", + f"graphs/{jsonable_encoder(graph_uuid)}/search/edges", method="POST", - json={ - "detect": convert_and_respect_annotation_metadata( - object_=detect, annotation=DetectConfig, direction="write" - ), - "edge_limit": edge_limit, - "graph_id": graph_id, + params={ "limit": limit, - "min_occurrences": min_occurrences, + "cursor": cursor, + }, + json={ + "bfs_origin_node_uuids": bfs_origin_node_uuids, + "center_node_uuid": center_node_uuid, + "filters": filters, + "mmr_lambda": mmr_lambda, "query": query, - "query_limit": query_limit, - "recency_weight": recency_weight, - "search_filters": convert_and_respect_annotation_metadata( - object_=search_filters, annotation=SearchFilters, direction="write" - ), - "seeds": convert_and_respect_annotation_metadata( - object_=seeds, annotation=PatternSeeds, direction="write" - ), - "user_id": user_id, + "reranker": reranker, }, headers={ "content-type": "application/json", + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, }, request_options=request_options, omit=OMIT, ) try: if 200 <= _response.status_code < 300: - _data = typing.cast( - DetectPatternsResponse, + _parsed_response = typing.cast( + JsonObjectPage, parse_obj_as( - type_=DetectPatternsResponse, # type: ignore + type_=JsonObjectPage, # type: ignore object_=_response.json(), ), ) - return AsyncHttpResponse(response=_response, data=_data) + _items = _parsed_response.items + _parsed_next = _parsed_response.next_cursor + _has_next = _parsed_next is not None and _parsed_next != "" + + async def _get_next(): + return await self.search_edges( + graph_uuid, + limit=limit, + cursor=_parsed_next, + bfs_origin_node_uuids=bfs_origin_node_uuids, + center_node_uuid=center_node_uuid, + filters=filters, + mmr_lambda=mmr_lambda, + query=query, + reranker=reranker, + idempotency_key=idempotency_key, + request_options=request_options, + ) + + return AsyncPager(has_next=_has_next, items=_items, get_next=_get_next, response=_parsed_response) if _response.status_code == 400: raise BadRequestError( - headers=dict(_response.headers), - body=typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ), - ) - if _response.status_code == 403: - raise ForbiddenError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -3329,8 +3764,8 @@ async def detect_patterns( ), ), ) - if _response.status_code == 404: - raise NotFoundError( + if _response.status_code == 401: + raise UnauthorizedError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -3340,8 +3775,8 @@ async def detect_patterns( ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -3356,130 +3791,138 @@ async def detect_patterns( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - async def search( + async def search_episodes( self, + graph_uuid: str, *, - query: str, + limit: typing.Optional[int] = None, + cursor: typing.Optional[str] = None, bfs_origin_node_uuids: typing.Optional[typing.Sequence[str]] = OMIT, center_node_uuid: typing.Optional[str] = OMIT, - graph_id: typing.Optional[str] = OMIT, - limit: typing.Optional[int] = OMIT, - max_characters: typing.Optional[int] = OMIT, + filters: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, mmr_lambda: typing.Optional[float] = OMIT, - reranker: typing.Optional[Reranker] = OMIT, - return_raw_results: typing.Optional[bool] = OMIT, - scope: typing.Optional[GraphSearchScope] = OMIT, - search_filters: typing.Optional[SearchFilters] = OMIT, - user_id: typing.Optional[str] = OMIT, + query: typing.Optional[str] = OMIT, + reranker: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> AsyncHttpResponse[GraphSearchResults]: + ) -> AsyncPager[JsonObject, JsonObjectPage]: """ - Perform a graph search query. - Parameters ---------- - query : str - The string to search for (required) + graph_uuid : str + Graph UUID - bfs_origin_node_uuids : typing.Optional[typing.Sequence[str]] - Nodes that are the origins of the BFS searches + limit : typing.Optional[int] + Page size - center_node_uuid : typing.Optional[str] - Node to rerank around for node distance reranking + cursor : typing.Optional[str] + Opaque page cursor - graph_id : typing.Optional[str] - The graph_id to search in. When searching user graph, please use user_id instead. + bfs_origin_node_uuids : typing.Optional[typing.Sequence[str]] - limit : typing.Optional[int] - The maximum number of facts to retrieve for non-auto scopes. Defaults to 10. Limited to 50. Ignored when scope=auto. + center_node_uuid : typing.Optional[str] - max_characters : typing.Optional[int] - Maximum total characters across all selected results when scope=auto. Defaults to 2500. Limited to 50000. + filters : typing.Optional[typing.Dict[str, typing.Any]] mmr_lambda : typing.Optional[float] - weighting for maximal marginal relevance - - reranker : typing.Optional[Reranker] - Defaults to RRF. Ignored when scope=auto except node_distance and episode_mentions are rejected; - auto search always uses RRF retrieval and applies its own internal rerank after retrieval. - episode_mentions ranks edge candidates by how many of the episodes listed - in search_filters.episode_uuids mention them; without episode_uuids it has - no effect and results are ranked as if no reranker were specified. - - return_raw_results : typing.Optional[bool] - When scope=auto, include the selected raw graph results alongside the materialized context block. - For graph-service-backed auto mode, selected raw results may include episodes, - edges, nodes, observations, and thread_summaries. - scope : typing.Optional[GraphSearchScope] - Defaults to Edges. + query : typing.Optional[str] - search_filters : typing.Optional[SearchFilters] - Search filters to apply to the search + reranker : typing.Optional[str] - user_id : typing.Optional[str] - The user_id when searching user graph. If not searching user graph, please use graph_id instead. + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - AsyncHttpResponse[GraphSearchResults] - Graph search results or auto-context block + AsyncPager[JsonObject, JsonObjectPage] + OK """ _response = await self._client_wrapper.httpx_client.request( - "graph/search", + f"graphs/{jsonable_encoder(graph_uuid)}/search/episodes", method="POST", + params={ + "limit": limit, + "cursor": cursor, + }, json={ "bfs_origin_node_uuids": bfs_origin_node_uuids, "center_node_uuid": center_node_uuid, - "graph_id": graph_id, - "limit": limit, - "max_characters": max_characters, + "filters": filters, "mmr_lambda": mmr_lambda, "query": query, "reranker": reranker, - "return_raw_results": return_raw_results, - "scope": scope, - "search_filters": convert_and_respect_annotation_metadata( - object_=search_filters, annotation=SearchFilters, direction="write" - ), - "user_id": user_id, }, headers={ "content-type": "application/json", + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, }, request_options=request_options, omit=OMIT, ) try: if 200 <= _response.status_code < 300: - _data = typing.cast( - GraphSearchResults, + _parsed_response = typing.cast( + JsonObjectPage, parse_obj_as( - type_=GraphSearchResults, # type: ignore + type_=JsonObjectPage, # type: ignore object_=_response.json(), ), ) - return AsyncHttpResponse(response=_response, data=_data) + _items = _parsed_response.items + _parsed_next = _parsed_response.next_cursor + _has_next = _parsed_next is not None and _parsed_next != "" + + async def _get_next(): + return await self.search_episodes( + graph_uuid, + limit=limit, + cursor=_parsed_next, + bfs_origin_node_uuids=bfs_origin_node_uuids, + center_node_uuid=center_node_uuid, + filters=filters, + mmr_lambda=mmr_lambda, + query=query, + reranker=reranker, + idempotency_key=idempotency_key, + request_options=request_options, + ) + + return AsyncPager(has_next=_has_next, items=_items, get_next=_get_next, response=_parsed_response) if _response.status_code == 400: raise BadRequestError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore object_=_response.json(), ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -3494,113 +3937,116 @@ async def search( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - async def get_subgraph( + async def search_nodes( self, + graph_uuid: str, *, - seed_node_uuids: typing.Sequence[str], - depth: typing.Optional[int] = OMIT, - direction: typing.Optional[str] = OMIT, - graph_id: typing.Optional[str] = OMIT, - max_edges: typing.Optional[int] = OMIT, - max_nodes: typing.Optional[int] = OMIT, - search_filters: typing.Optional[SearchFilters] = OMIT, - user_id: typing.Optional[str] = OMIT, + limit: typing.Optional[int] = None, + cursor: typing.Optional[str] = None, + bfs_origin_node_uuids: typing.Optional[typing.Sequence[str]] = OMIT, + center_node_uuid: typing.Optional[str] = OMIT, + filters: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + mmr_lambda: typing.Optional[float] = OMIT, + query: typing.Optional[str] = OMIT, + reranker: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> AsyncHttpResponse[GraphSubgraphResponse]: + ) -> AsyncPager[JsonObject, JsonObjectPage]: """ - Returns the bounded neighborhood of a set of seed nodes as a single {nodes, edges} payload: breadth-first expansion up to a caller-specified depth, subject to explicit budgets, with explicit truncation reporting. - Parameters ---------- - seed_node_uuids : typing.Sequence[str] - Seed node UUIDs to expand from, in traversal-priority order: seeds are - admitted before any expansion, in this order, and count toward - max_nodes first. 1-20 entries, required. Seeds that do not exist in - the target graph are ignored, not an error. + graph_uuid : str + Graph UUID - depth : typing.Optional[int] - Maximum traversal depth from the seeds. 1-3. Defaults to 1. + limit : typing.Optional[int] + Page size - direction : typing.Optional[str] - Edge orientation followed during expansion, relative to each frontier - node: "in" | "out" | "both". Defaults to "both". + cursor : typing.Optional[str] + Opaque page cursor - graph_id : typing.Optional[str] - graph_id identifies the target named graph. Exactly one of user_id or - graph_id is required. + bfs_origin_node_uuids : typing.Optional[typing.Sequence[str]] - max_edges : typing.Optional[int] - Maximum number of edges in the response. 1-1000. Defaults to 200. + center_node_uuid : typing.Optional[str] - max_nodes : typing.Optional[int] - Maximum number of nodes in the response, including admitted seeds. - 1-500. Defaults to 100. + filters : typing.Optional[typing.Dict[str, typing.Any]] - 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). + mmr_lambda : typing.Optional[float] - user_id : typing.Optional[str] - user_id identifies the target user graph. Exactly one of user_id or - graph_id is required. + query : typing.Optional[str] + + reranker : typing.Optional[str] + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - AsyncHttpResponse[GraphSubgraphResponse] - Subgraph + AsyncPager[JsonObject, JsonObjectPage] + OK """ _response = await self._client_wrapper.httpx_client.request( - "graph/subgraph", + f"graphs/{jsonable_encoder(graph_uuid)}/search/nodes", method="POST", + params={ + "limit": limit, + "cursor": cursor, + }, json={ - "depth": depth, - "direction": direction, - "graph_id": graph_id, - "max_edges": max_edges, - "max_nodes": max_nodes, - "search_filters": convert_and_respect_annotation_metadata( - object_=search_filters, annotation=SearchFilters, direction="write" - ), - "seed_node_uuids": seed_node_uuids, - "user_id": user_id, + "bfs_origin_node_uuids": bfs_origin_node_uuids, + "center_node_uuid": center_node_uuid, + "filters": filters, + "mmr_lambda": mmr_lambda, + "query": query, + "reranker": reranker, }, headers={ "content-type": "application/json", + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, }, request_options=request_options, omit=OMIT, ) try: if 200 <= _response.status_code < 300: - _data = typing.cast( - GraphSubgraphResponse, + _parsed_response = typing.cast( + JsonObjectPage, parse_obj_as( - type_=GraphSubgraphResponse, # type: ignore + type_=JsonObjectPage, # type: ignore object_=_response.json(), ), ) - return AsyncHttpResponse(response=_response, data=_data) + _items = _parsed_response.items + _parsed_next = _parsed_response.next_cursor + _has_next = _parsed_next is not None and _parsed_next != "" + + async def _get_next(): + return await self.search_nodes( + graph_uuid, + limit=limit, + cursor=_parsed_next, + bfs_origin_node_uuids=bfs_origin_node_uuids, + center_node_uuid=center_node_uuid, + filters=filters, + mmr_lambda=mmr_lambda, + query=query, + reranker=reranker, + idempotency_key=idempotency_key, + request_options=request_options, + ) + + return AsyncPager(has_next=_has_next, items=_items, get_next=_get_next, response=_parsed_response) if _response.status_code == 400: raise BadRequestError( - headers=dict(_response.headers), - body=typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ), - ) - if _response.status_code == 403: - raise ForbiddenError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -3610,8 +4056,8 @@ async def get_subgraph( ), ), ) - if _response.status_code == 404: - raise NotFoundError( + if _response.status_code == 401: + raise UnauthorizedError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -3621,8 +4067,8 @@ async def get_subgraph( ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -3637,46 +4083,116 @@ async def get_subgraph( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - async def get( - self, graph_id: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> AsyncHttpResponse[Graph]: + async def search_observations( + self, + graph_uuid: str, + *, + limit: typing.Optional[int] = None, + cursor: typing.Optional[str] = None, + bfs_origin_node_uuids: typing.Optional[typing.Sequence[str]] = OMIT, + center_node_uuid: typing.Optional[str] = OMIT, + filters: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + mmr_lambda: typing.Optional[float] = OMIT, + query: typing.Optional[str] = OMIT, + reranker: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncPager[JsonObject, JsonObjectPage]: """ - Returns a graph. - Parameters ---------- - graph_id : str - The graph_id of the graph to get. + graph_uuid : str + Graph UUID + + limit : typing.Optional[int] + Page size + + cursor : typing.Optional[str] + Opaque page cursor + + bfs_origin_node_uuids : typing.Optional[typing.Sequence[str]] + + center_node_uuid : typing.Optional[str] + + filters : typing.Optional[typing.Dict[str, typing.Any]] + + mmr_lambda : typing.Optional[float] + + query : typing.Optional[str] + + reranker : typing.Optional[str] + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - AsyncHttpResponse[Graph] - The graph that was retrieved. + AsyncPager[JsonObject, JsonObjectPage] + OK """ _response = await self._client_wrapper.httpx_client.request( - f"graph/{jsonable_encoder(graph_id)}", - method="GET", + f"graphs/{jsonable_encoder(graph_uuid)}/search/observations", + method="POST", + params={ + "limit": limit, + "cursor": cursor, + }, + json={ + "bfs_origin_node_uuids": bfs_origin_node_uuids, + "center_node_uuid": center_node_uuid, + "filters": filters, + "mmr_lambda": mmr_lambda, + "query": query, + "reranker": reranker, + }, + headers={ + "content-type": "application/json", + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, + }, request_options=request_options, + omit=OMIT, ) try: if 200 <= _response.status_code < 300: - _data = typing.cast( - Graph, + _parsed_response = typing.cast( + JsonObjectPage, parse_obj_as( - type_=Graph, # type: ignore + type_=JsonObjectPage, # type: ignore object_=_response.json(), ), ) - return AsyncHttpResponse(response=_response, data=_data) - if _response.status_code == 404: - raise NotFoundError( + _items = _parsed_response.items + _parsed_next = _parsed_response.next_cursor + _has_next = _parsed_next is not None and _parsed_next != "" + + async def _get_next(): + return await self.search_observations( + graph_uuid, + limit=limit, + cursor=_parsed_next, + bfs_origin_node_uuids=bfs_origin_node_uuids, + center_node_uuid=center_node_uuid, + filters=filters, + mmr_lambda=mmr_lambda, + query=query, + reranker=reranker, + idempotency_key=idempotency_key, + request_options=request_options, + ) + + return AsyncPager(has_next=_has_next, items=_items, get_next=_get_next, response=_parsed_response) + if _response.status_code == 400: + raise BadRequestError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -3686,8 +4202,19 @@ async def get( ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 401: + raise UnauthorizedError( + 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, @@ -3702,57 +4229,127 @@ async def get( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - async def delete( - self, graph_id: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> AsyncHttpResponse[SuccessResponse]: + async def search_thread_summaries( + self, + graph_uuid: str, + *, + limit: typing.Optional[int] = None, + cursor: typing.Optional[str] = None, + bfs_origin_node_uuids: typing.Optional[typing.Sequence[str]] = OMIT, + center_node_uuid: typing.Optional[str] = OMIT, + filters: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + mmr_lambda: typing.Optional[float] = OMIT, + query: typing.Optional[str] = OMIT, + reranker: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncPager[JsonObject, JsonObjectPage]: """ - Deletes a graph. If you would like to delete a user graph, make sure to use user.delete instead. - Parameters ---------- - graph_id : str - Graph ID + graph_uuid : str + Graph UUID + + limit : typing.Optional[int] + Page size + + cursor : typing.Optional[str] + Opaque page cursor + + bfs_origin_node_uuids : typing.Optional[typing.Sequence[str]] + + center_node_uuid : typing.Optional[str] + + filters : typing.Optional[typing.Dict[str, typing.Any]] + + mmr_lambda : typing.Optional[float] + + query : typing.Optional[str] + + reranker : typing.Optional[str] + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - AsyncHttpResponse[SuccessResponse] - Deleted + AsyncPager[JsonObject, JsonObjectPage] + OK """ _response = await self._client_wrapper.httpx_client.request( - f"graph/{jsonable_encoder(graph_id)}", - method="DELETE", + f"graphs/{jsonable_encoder(graph_uuid)}/search/thread-summaries", + method="POST", + params={ + "limit": limit, + "cursor": cursor, + }, + json={ + "bfs_origin_node_uuids": bfs_origin_node_uuids, + "center_node_uuid": center_node_uuid, + "filters": filters, + "mmr_lambda": mmr_lambda, + "query": query, + "reranker": reranker, + }, + headers={ + "content-type": "application/json", + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, + }, request_options=request_options, + omit=OMIT, ) try: if 200 <= _response.status_code < 300: - _data = typing.cast( - SuccessResponse, + _parsed_response = typing.cast( + JsonObjectPage, parse_obj_as( - type_=SuccessResponse, # type: ignore + type_=JsonObjectPage, # type: ignore object_=_response.json(), ), ) - return AsyncHttpResponse(response=_response, data=_data) + _items = _parsed_response.items + _parsed_next = _parsed_response.next_cursor + _has_next = _parsed_next is not None and _parsed_next != "" + + async def _get_next(): + return await self.search_thread_summaries( + graph_uuid, + limit=limit, + cursor=_parsed_next, + bfs_origin_node_uuids=bfs_origin_node_uuids, + center_node_uuid=center_node_uuid, + filters=filters, + mmr_lambda=mmr_lambda, + query=query, + reranker=reranker, + idempotency_key=idempotency_key, + request_options=request_options, + ) + + return AsyncPager(has_next=_has_next, items=_items, get_next=_get_next, response=_parsed_response) if _response.status_code == 400: raise BadRequestError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore object_=_response.json(), ), ), ) - if _response.status_code == 404: - raise NotFoundError( + if _response.status_code == 401: + raise UnauthorizedError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -3762,8 +4359,8 @@ async def delete( ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -3778,52 +4375,69 @@ async def delete( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - async def update( + async def get_subgraph( self, - graph_id: str, + graph_uuid: str, *, - description: typing.Optional[str] = OMIT, - name: typing.Optional[str] = OMIT, - time_zone: typing.Optional[str] = OMIT, + depth: typing.Optional[int] = OMIT, + direction: typing.Optional[str] = OMIT, + filters: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + max_edges: typing.Optional[int] = OMIT, + max_nodes: typing.Optional[int] = OMIT, + seed_node_uuids: typing.Optional[typing.Sequence[str]] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> AsyncHttpResponse[Graph]: + ) -> AsyncHttpResponse[JsonObject]: """ - Updates information about a graph. - Parameters ---------- - graph_id : str - Graph ID + graph_uuid : str + Graph UUID - description : typing.Optional[str] + depth : typing.Optional[int] - name : typing.Optional[str] + direction : typing.Optional[str] - time_zone : typing.Optional[str] - The graph's IANA time zone. Stored on its group-backed subject. + filters : typing.Optional[typing.Dict[str, typing.Any]] + + max_edges : typing.Optional[int] + + max_nodes : typing.Optional[int] + + seed_node_uuids : typing.Optional[typing.Sequence[str]] + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - AsyncHttpResponse[Graph] - The updated graph object + AsyncHttpResponse[JsonObject] + OK """ _response = await self._client_wrapper.httpx_client.request( - f"graph/{jsonable_encoder(graph_id)}", - method="PATCH", + f"graphs/{jsonable_encoder(graph_uuid)}/subgraph", + method="POST", json={ - "description": description, - "name": name, - "time_zone": time_zone, + "depth": depth, + "direction": direction, + "filters": filters, + "max_edges": max_edges, + "max_nodes": max_nodes, + "seed_node_uuids": seed_node_uuids, }, headers={ "content-type": "application/json", + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, }, request_options=request_options, omit=OMIT, @@ -3831,9 +4445,9 @@ async def update( try: if 200 <= _response.status_code < 300: _data = typing.cast( - Graph, + JsonObject, parse_obj_as( - type_=Graph, # type: ignore + type_=JsonObject, # type: ignore object_=_response.json(), ), ) @@ -3842,15 +4456,15 @@ async def update( raise BadRequestError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore object_=_response.json(), ), ), ) - if _response.status_code == 404: - raise NotFoundError( + if _response.status_code == 401: + raise UnauthorizedError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -3860,8 +4474,8 @@ async def update( ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -3876,46 +4490,68 @@ async def update( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) async def warm( - self, graph_id: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> AsyncHttpResponse[SuccessResponse]: + self, + graph_uuid: str, + *, + idempotency_key: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[AsyncResult]: """ - Hints Zep to warm a graph for low-latency search - Parameters ---------- - graph_id : str - The graph_id of the graph to warm. + graph_uuid : str + Graph UUID + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - AsyncHttpResponse[SuccessResponse] - Warm hint accepted + AsyncHttpResponse[AsyncResult] + Accepted """ _response = await self._client_wrapper.httpx_client.request( - f"graph/{jsonable_encoder(graph_id)}/warm", - method="GET", + f"graphs/{jsonable_encoder(graph_uuid)}/warm", + method="POST", + headers={ + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, + }, request_options=request_options, ) try: if 200 <= _response.status_code < 300: _data = typing.cast( - SuccessResponse, + AsyncResult, parse_obj_as( - type_=SuccessResponse, # type: ignore + type_=AsyncResult, # type: ignore object_=_response.json(), ), ) return AsyncHttpResponse(response=_response, data=_data) - if _response.status_code == 404: - raise NotFoundError( + if _response.status_code == 400: + raise BadRequestError( + 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 == 401: + raise UnauthorizedError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -3925,8 +4561,8 @@ async def warm( ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -3941,6 +4577,10 @@ async def warm( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) diff --git a/src/zep_cloud/graph/thread_summary/client.py b/src/zep_cloud/graph/thread_summary/client.py index 02b8db7f..3f9f78cc 100644 --- a/src/zep_cloud/graph/thread_summary/client.py +++ b/src/zep_cloud/graph/thread_summary/client.py @@ -3,9 +3,10 @@ import typing from ...core.client_wrapper import AsyncClientWrapper, SyncClientWrapper +from ...core.pagination import AsyncPager, SyncPager from ...core.request_options import RequestOptions -from ...types.search_filters import SearchFilters -from ...types.thread_summary import ThreadSummary +from ...types.json_object import JsonObject +from ...types.json_object_page import JsonObjectPage from .raw_client import AsyncRawThreadSummaryClient, RawThreadSummaryClient # this is used as the default value for optional parameters @@ -27,126 +28,39 @@ def with_raw_response(self) -> RawThreadSummaryClient: """ return self._raw_client - def get_by_graph_id( + def list( self, - graph_id: str, + graph_uuid: 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, + limit: typing.Optional[int] = None, + cursor: typing.Optional[str] = None, + filters: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> typing.List[ThreadSummary]: + ) -> SyncPager[JsonObject, JsonObjectPage]: """ - Returns incremental thread summaries associated with the graph. - Parameters ---------- - graph_id : str - Graph ID - - cursor : typing.Optional[str] - Opaque cursor for pagination, obtained from the Zep-Next-Cursor response header - of the previous page. 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. + graph_uuid : str + Graph UUID 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[ThreadSummary] - Thread summaries - - Examples - -------- - from zep_cloud import Zep - - client = Zep( - api_key="YOUR_API_KEY", - ) - client.graph.thread_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 - - def get_by_user_id( - self, - user_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[ThreadSummary]: - """ - Returns incremental thread summaries generated from messages in each thread associated with the user's graph. - - Parameters - ---------- - user_id : str - User ID + Page size 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. + Opaque page cursor - direction : typing.Optional[str] - Sort direction. One of "asc" or "desc" (default "desc"). + filters : typing.Optional[typing.Dict[str, typing.Any]] - 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. + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - typing.List[ThreadSummary] - Thread summaries + SyncPager[JsonObject, JsonObjectPage] + OK Examples -------- @@ -155,21 +69,25 @@ def get_by_user_id( client = Zep( api_key="YOUR_API_KEY", ) - client.graph.thread_summary.get_by_user_id( - user_id="user_id", + response = client.graph.thread_summary.list( + graph_uuid="graph_uuid", + limit=1, + cursor="cursor", ) + for item in response: + yield item + # alternatively, you can paginate page-by-page + for page in response.iter_pages(): + yield page """ - _response = self._raw_client.get_by_user_id( - user_id, + return self._raw_client.list( + graph_uuid, + limit=limit, cursor=cursor, - direction=direction, filters=filters, - limit=limit, - order_by=order_by, - uuid_cursor=uuid_cursor, + idempotency_key=idempotency_key, request_options=request_options, ) - return _response.data class AsyncThreadSummaryClient: @@ -187,134 +105,39 @@ def with_raw_response(self) -> AsyncRawThreadSummaryClient: """ return self._raw_client - async def get_by_graph_id( + async def list( self, - graph_id: str, + graph_uuid: 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, + limit: typing.Optional[int] = None, + cursor: typing.Optional[str] = None, + filters: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> typing.List[ThreadSummary]: + ) -> AsyncPager[JsonObject, JsonObjectPage]: """ - Returns incremental thread summaries associated with the graph. - Parameters ---------- - graph_id : str - Graph ID - - cursor : typing.Optional[str] - Opaque cursor for pagination, obtained from the Zep-Next-Cursor response header - of the previous page. 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. + graph_uuid : str + Graph UUID 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[ThreadSummary] - Thread summaries - - Examples - -------- - import asyncio - - from zep_cloud import AsyncZep - - client = AsyncZep( - api_key="YOUR_API_KEY", - ) - - - async def main() -> None: - await client.graph.thread_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 - - async def get_by_user_id( - self, - user_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[ThreadSummary]: - """ - Returns incremental thread summaries generated from messages in each thread associated with the user's graph. - - Parameters - ---------- - user_id : str - User ID + Page size 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. + Opaque page cursor - 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. + filters : typing.Optional[typing.Dict[str, typing.Any]] - Deprecated: prefer Cursor, the opaque cursor returned via the Zep-Next-Cursor response header. + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - typing.List[ThreadSummary] - Thread summaries + AsyncPager[JsonObject, JsonObjectPage] + OK Examples -------- @@ -328,21 +151,26 @@ async def get_by_user_id( async def main() -> None: - await client.graph.thread_summary.get_by_user_id( - user_id="user_id", + response = await client.graph.thread_summary.list( + graph_uuid="graph_uuid", + limit=1, + cursor="cursor", ) + async for item in response: + yield item + + # alternatively, you can paginate page-by-page + async for page in response.iter_pages(): + yield page asyncio.run(main()) """ - _response = await self._raw_client.get_by_user_id( - user_id, + return await self._raw_client.list( + graph_uuid, + limit=limit, cursor=cursor, - direction=direction, filters=filters, - limit=limit, - order_by=order_by, - uuid_cursor=uuid_cursor, + idempotency_key=idempotency_key, request_options=request_options, ) - return _response.data diff --git a/src/zep_cloud/graph/thread_summary/raw_client.py b/src/zep_cloud/graph/thread_summary/raw_client.py index 063a02f1..3b2dc808 100644 --- a/src/zep_cloud/graph/thread_summary/raw_client.py +++ b/src/zep_cloud/graph/thread_summary/raw_client.py @@ -5,17 +5,18 @@ 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.pagination import AsyncPager, SyncPager +from ...core.parse_error import ParsingError 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 ...errors.unauthorized_error import UnauthorizedError from ...types.api_error import ApiError as types_api_error_ApiError -from ...types.search_filters import SearchFilters -from ...types.thread_summary import ThreadSummary +from ...types.json_object import JsonObject +from ...types.json_object_page import JsonObjectPage +from pydantic import ValidationError # this is used as the default value for optional parameters OMIT = typing.cast(typing.Any, ...) @@ -25,94 +26,80 @@ class RawThreadSummaryClient: def __init__(self, *, client_wrapper: SyncClientWrapper): self._client_wrapper = client_wrapper - def get_by_graph_id( + def list( self, - graph_id: str, + graph_uuid: 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, + limit: typing.Optional[int] = None, + cursor: typing.Optional[str] = None, + filters: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> HttpResponse[typing.List[ThreadSummary]]: + ) -> SyncPager[JsonObject, JsonObjectPage]: """ - Returns incremental thread summaries associated with the graph. - Parameters ---------- - graph_id : str - Graph ID - - cursor : typing.Optional[str] - Opaque cursor for pagination, obtained from the Zep-Next-Cursor response header - of the previous page. 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. + graph_uuid : str + Graph UUID limit : typing.Optional[int] - Maximum number of items to return + Page size - order_by : typing.Optional[str] - Field to sort by. One of "created_at", "valid_at", or "uuid" (default "uuid"). + cursor : typing.Optional[str] + Opaque page cursor - uuid_cursor : typing.Optional[str] - UUID based cursor, used for pagination. Should be the UUID of the last item in the previous page. + filters : typing.Optional[typing.Dict[str, typing.Any]] - Deprecated: prefer Cursor, the opaque cursor returned via the Zep-Next-Cursor response header. + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - HttpResponse[typing.List[ThreadSummary]] - Thread summaries + SyncPager[JsonObject, JsonObjectPage] + OK """ _response = self._client_wrapper.httpx_client.request( - f"graph/thread-summary/graph/{jsonable_encoder(graph_id)}", + f"graphs/{jsonable_encoder(graph_uuid)}/thread-summaries/list", method="POST", - json={ - "cursor": cursor, - "direction": direction, - "filters": convert_and_respect_annotation_metadata( - object_=filters, annotation=SearchFilters, direction="write" - ), + params={ "limit": limit, - "order_by": order_by, - "uuid_cursor": uuid_cursor, + "cursor": cursor, + }, + json={ + "filters": filters, + }, + headers={ + "content-type": "application/json", + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, }, request_options=request_options, omit=OMIT, ) try: if 200 <= _response.status_code < 300: - _data = typing.cast( - typing.List[ThreadSummary], + _parsed_response = typing.cast( + JsonObjectPage, parse_obj_as( - type_=typing.List[ThreadSummary], # type: ignore + type_=JsonObjectPage, # type: ignore object_=_response.json(), ), ) - return HttpResponse(response=_response, data=_data) + _items = _parsed_response.items + _parsed_next = _parsed_response.next_cursor + _has_next = _parsed_next is not None and _parsed_next != "" + _get_next = lambda: self.list( + graph_uuid, + limit=limit, + cursor=_parsed_next, + filters=filters, + idempotency_key=idempotency_key, + request_options=request_options, + ) + return SyncPager(has_next=_has_next, items=_items, get_next=_get_next, response=_parsed_response) 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, @@ -122,8 +109,8 @@ def get_by_graph_id( ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 401: + raise UnauthorizedError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -133,101 +120,6 @@ def get_by_graph_id( ), ), ) - _response_json = _response.json() - except JSONDecodeError: - raise core_api_error_ApiError( - status_code=_response.status_code, headers=dict(_response.headers), body=_response.text - ) - raise core_api_error_ApiError( - status_code=_response.status_code, headers=dict(_response.headers), body=_response_json - ) - - def get_by_user_id( - self, - user_id: str, - *, - 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[ThreadSummary]]: - """ - Returns incremental thread summaries generated from messages in each thread associated with the user's graph. - - Parameters - ---------- - user_id : str - User ID - - cursor : typing.Optional[str] - Opaque cursor for pagination, obtained from the Zep-Next-Cursor response header - of the previous page. 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[ThreadSummary]] - Thread summaries - """ - _response = self._client_wrapper.httpx_client.request( - f"graph/thread-summary/user/{jsonable_encoder(user_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, - }, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - _data = typing.cast( - typing.List[ThreadSummary], - parse_obj_as( - type_=typing.List[ThreadSummary], # 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), @@ -239,22 +131,15 @@ def get_by_user_id( ), ), ) - 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 ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) @@ -264,94 +149,83 @@ class AsyncRawThreadSummaryClient: def __init__(self, *, client_wrapper: AsyncClientWrapper): self._client_wrapper = client_wrapper - async def get_by_graph_id( + async def list( self, - graph_id: str, + graph_uuid: 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, + limit: typing.Optional[int] = None, + cursor: typing.Optional[str] = None, + filters: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> AsyncHttpResponse[typing.List[ThreadSummary]]: + ) -> AsyncPager[JsonObject, JsonObjectPage]: """ - Returns incremental thread summaries associated with the graph. - Parameters ---------- - graph_id : str - Graph ID - - cursor : typing.Optional[str] - Opaque cursor for pagination, obtained from the Zep-Next-Cursor response header - of the previous page. 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. + graph_uuid : str + Graph UUID limit : typing.Optional[int] - Maximum number of items to return + Page size - order_by : typing.Optional[str] - Field to sort by. One of "created_at", "valid_at", or "uuid" (default "uuid"). + cursor : typing.Optional[str] + Opaque page cursor - uuid_cursor : typing.Optional[str] - UUID based cursor, used for pagination. Should be the UUID of the last item in the previous page. + filters : typing.Optional[typing.Dict[str, typing.Any]] - Deprecated: prefer Cursor, the opaque cursor returned via the Zep-Next-Cursor response header. + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - AsyncHttpResponse[typing.List[ThreadSummary]] - Thread summaries + AsyncPager[JsonObject, JsonObjectPage] + OK """ _response = await self._client_wrapper.httpx_client.request( - f"graph/thread-summary/graph/{jsonable_encoder(graph_id)}", + f"graphs/{jsonable_encoder(graph_uuid)}/thread-summaries/list", method="POST", - json={ - "cursor": cursor, - "direction": direction, - "filters": convert_and_respect_annotation_metadata( - object_=filters, annotation=SearchFilters, direction="write" - ), + params={ "limit": limit, - "order_by": order_by, - "uuid_cursor": uuid_cursor, + "cursor": cursor, + }, + json={ + "filters": filters, + }, + headers={ + "content-type": "application/json", + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, }, request_options=request_options, omit=OMIT, ) try: if 200 <= _response.status_code < 300: - _data = typing.cast( - typing.List[ThreadSummary], + _parsed_response = typing.cast( + JsonObjectPage, parse_obj_as( - type_=typing.List[ThreadSummary], # type: ignore + type_=JsonObjectPage, # type: ignore object_=_response.json(), ), ) - return AsyncHttpResponse(response=_response, data=_data) + _items = _parsed_response.items + _parsed_next = _parsed_response.next_cursor + _has_next = _parsed_next is not None and _parsed_next != "" + + async def _get_next(): + return await self.list( + graph_uuid, + limit=limit, + cursor=_parsed_next, + filters=filters, + idempotency_key=idempotency_key, + request_options=request_options, + ) + + return AsyncPager(has_next=_has_next, items=_items, get_next=_get_next, response=_parsed_response) 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, @@ -361,8 +235,8 @@ async def get_by_graph_id( ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 401: + raise UnauthorizedError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -372,101 +246,6 @@ async def get_by_graph_id( ), ), ) - _response_json = _response.json() - except JSONDecodeError: - raise core_api_error_ApiError( - status_code=_response.status_code, headers=dict(_response.headers), body=_response.text - ) - raise core_api_error_ApiError( - status_code=_response.status_code, headers=dict(_response.headers), body=_response_json - ) - - async def get_by_user_id( - self, - user_id: str, - *, - 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[ThreadSummary]]: - """ - Returns incremental thread summaries generated from messages in each thread associated with the user's graph. - - Parameters - ---------- - user_id : str - User ID - - cursor : typing.Optional[str] - Opaque cursor for pagination, obtained from the Zep-Next-Cursor response header - of the previous page. 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[ThreadSummary]] - Thread summaries - """ - _response = await self._client_wrapper.httpx_client.request( - f"graph/thread-summary/user/{jsonable_encoder(user_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, - }, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - _data = typing.cast( - typing.List[ThreadSummary], - parse_obj_as( - type_=typing.List[ThreadSummary], # 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), @@ -478,22 +257,15 @@ async def get_by_user_id( ), ), ) - 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 ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) diff --git a/src/zep_cloud/lookup/__init__.py b/src/zep_cloud/lookup/__init__.py new file mode 100644 index 00000000..5cde0202 --- /dev/null +++ b/src/zep_cloud/lookup/__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/lookup/client.py b/src/zep_cloud/lookup/client.py new file mode 100644 index 00000000..03e3fc6f --- /dev/null +++ b/src/zep_cloud/lookup/client.py @@ -0,0 +1,143 @@ +# 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.lookup_batch_response import LookupBatchResponse +from .raw_client import AsyncRawLookupClient, RawLookupClient + +# this is used as the default value for optional parameters +OMIT = typing.cast(typing.Any, ...) + + +class LookupClient: + def __init__(self, *, client_wrapper: SyncClientWrapper): + self._raw_client = RawLookupClient(client_wrapper=client_wrapper) + + @property + def with_raw_response(self) -> RawLookupClient: + """ + Retrieves a raw implementation of this client that returns raw responses. + + Returns + ------- + RawLookupClient + """ + return self._raw_client + + def batch( + self, + *, + graphs: typing.Optional[typing.Sequence[str]] = OMIT, + threads: typing.Optional[typing.Sequence[str]] = OMIT, + users: typing.Optional[typing.Sequence[str]] = OMIT, + idempotency_key: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> LookupBatchResponse: + """ + Parameters + ---------- + graphs : typing.Optional[typing.Sequence[str]] + + threads : typing.Optional[typing.Sequence[str]] + + users : typing.Optional[typing.Sequence[str]] + + idempotency_key : typing.Optional[str] + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + LookupBatchResponse + OK + + Examples + -------- + from zep_cloud import Zep + + client = Zep( + api_key="YOUR_API_KEY", + ) + client.lookup.batch() + """ + _response = self._raw_client.batch( + graphs=graphs, + threads=threads, + users=users, + idempotency_key=idempotency_key, + request_options=request_options, + ) + return _response.data + + +class AsyncLookupClient: + def __init__(self, *, client_wrapper: AsyncClientWrapper): + self._raw_client = AsyncRawLookupClient(client_wrapper=client_wrapper) + + @property + def with_raw_response(self) -> AsyncRawLookupClient: + """ + Retrieves a raw implementation of this client that returns raw responses. + + Returns + ------- + AsyncRawLookupClient + """ + return self._raw_client + + async def batch( + self, + *, + graphs: typing.Optional[typing.Sequence[str]] = OMIT, + threads: typing.Optional[typing.Sequence[str]] = OMIT, + users: typing.Optional[typing.Sequence[str]] = OMIT, + idempotency_key: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> LookupBatchResponse: + """ + Parameters + ---------- + graphs : typing.Optional[typing.Sequence[str]] + + threads : typing.Optional[typing.Sequence[str]] + + users : typing.Optional[typing.Sequence[str]] + + idempotency_key : typing.Optional[str] + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + LookupBatchResponse + OK + + Examples + -------- + import asyncio + + from zep_cloud import AsyncZep + + client = AsyncZep( + api_key="YOUR_API_KEY", + ) + + + async def main() -> None: + await client.lookup.batch() + + + asyncio.run(main()) + """ + _response = await self._raw_client.batch( + graphs=graphs, + threads=threads, + users=users, + idempotency_key=idempotency_key, + request_options=request_options, + ) + return _response.data diff --git a/src/zep_cloud/lookup/raw_client.py b/src/zep_cloud/lookup/raw_client.py new file mode 100644 index 00000000..621630a7 --- /dev/null +++ b/src/zep_cloud/lookup/raw_client.py @@ -0,0 +1,228 @@ +# 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.parse_error import ParsingError +from ..core.pydantic_utilities import parse_obj_as +from ..core.request_options import RequestOptions +from ..errors.bad_request_error import BadRequestError +from ..errors.not_found_error import NotFoundError +from ..errors.unauthorized_error import UnauthorizedError +from ..types.api_error import ApiError as types_api_error_ApiError +from ..types.lookup_batch_response import LookupBatchResponse +from pydantic import ValidationError + +# this is used as the default value for optional parameters +OMIT = typing.cast(typing.Any, ...) + + +class RawLookupClient: + def __init__(self, *, client_wrapper: SyncClientWrapper): + self._client_wrapper = client_wrapper + + def batch( + self, + *, + graphs: typing.Optional[typing.Sequence[str]] = OMIT, + threads: typing.Optional[typing.Sequence[str]] = OMIT, + users: typing.Optional[typing.Sequence[str]] = OMIT, + idempotency_key: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[LookupBatchResponse]: + """ + Parameters + ---------- + graphs : typing.Optional[typing.Sequence[str]] + + threads : typing.Optional[typing.Sequence[str]] + + users : typing.Optional[typing.Sequence[str]] + + idempotency_key : typing.Optional[str] + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[LookupBatchResponse] + OK + """ + _response = self._client_wrapper.httpx_client.request( + "lookup", + method="POST", + json={ + "graphs": graphs, + "threads": threads, + "users": users, + }, + headers={ + "content-type": "application/json", + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + LookupBatchResponse, + parse_obj_as( + type_=LookupBatchResponse, # 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( + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + 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(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise core_api_error_ApiError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.text + ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) + raise core_api_error_ApiError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response_json + ) + + +class AsyncRawLookupClient: + def __init__(self, *, client_wrapper: AsyncClientWrapper): + self._client_wrapper = client_wrapper + + async def batch( + self, + *, + graphs: typing.Optional[typing.Sequence[str]] = OMIT, + threads: typing.Optional[typing.Sequence[str]] = OMIT, + users: typing.Optional[typing.Sequence[str]] = OMIT, + idempotency_key: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[LookupBatchResponse]: + """ + Parameters + ---------- + graphs : typing.Optional[typing.Sequence[str]] + + threads : typing.Optional[typing.Sequence[str]] + + users : typing.Optional[typing.Sequence[str]] + + idempotency_key : typing.Optional[str] + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[LookupBatchResponse] + OK + """ + _response = await self._client_wrapper.httpx_client.request( + "lookup", + method="POST", + json={ + "graphs": graphs, + "threads": threads, + "users": users, + }, + headers={ + "content-type": "application/json", + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + LookupBatchResponse, + parse_obj_as( + type_=LookupBatchResponse, # 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( + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + 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(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise core_api_error_ApiError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.text + ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) + raise core_api_error_ApiError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response_json + ) diff --git a/src/zep_cloud/project/client.py b/src/zep_cloud/project/client.py index a5ba6f38..810aeb9f 100644 --- a/src/zep_cloud/project/client.py +++ b/src/zep_cloud/project/client.py @@ -4,9 +4,11 @@ from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper from ..core.request_options import RequestOptions -from ..types.observation_steering_config import ObservationSteeringConfig -from ..types.observation_type import ObservationType -from ..types.project_info_response import ProjectInfoResponse +from ..types.instructions import Instructions +from ..types.observation_steering import ObservationSteering +from ..types.ontology import Ontology +from ..types.project import Project +from ..types.user_summary_instructions import UserSummaryInstructions from .raw_client import AsyncRawProjectClient, RawProjectClient # this is used as the default value for optional parameters @@ -28,10 +30,8 @@ def with_raw_response(self) -> RawProjectClient: """ return self._raw_client - def get(self, *, request_options: typing.Optional[RequestOptions] = None) -> ProjectInfoResponse: + def get(self, *, request_options: typing.Optional[RequestOptions] = None) -> Project: """ - Retrieve project info based on the provided api key. - Parameters ---------- request_options : typing.Optional[RequestOptions] @@ -39,8 +39,8 @@ def get(self, *, request_options: typing.Optional[RequestOptions] = None) -> Pro Returns ------- - ProjectInfoResponse - Retrieved + Project + OK Examples -------- @@ -55,23 +55,27 @@ def get(self, *, request_options: typing.Optional[RequestOptions] = None) -> Pro return _response.data def update( - self, *, default_time_zone: typing.Optional[str] = OMIT, request_options: typing.Optional[RequestOptions] = None - ) -> ProjectInfoResponse: + self, + *, + default_time_zone: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> Project: """ - Sets or clears the project-level fallback time zone for the API key's project. - Parameters ---------- default_time_zone : typing.Optional[str] - The project's IANA fallback time zone. Null clears the existing value. + Omit to leave unchanged, send JSON null to clear, or send a value to set. + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - ProjectInfoResponse - Updated + Project + OK Examples -------- @@ -82,34 +86,59 @@ def update( ) client.project.update() """ - _response = self._raw_client.update(default_time_zone=default_time_zone, request_options=request_options) + _response = self._raw_client.update( + default_time_zone=default_time_zone, idempotency_key=idempotency_key, request_options=request_options + ) return _response.data - def get_observation_steering( + def get_instructions(self, *, request_options: typing.Optional[RequestOptions] = None) -> Instructions: + """ + Parameters + ---------- + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + Instructions + OK + + Examples + -------- + from zep_cloud import Zep + + client = Zep( + api_key="YOUR_API_KEY", + ) + client.project.get_instructions() + """ + _response = self._raw_client.get_instructions(request_options=request_options) + return _response.data + + def set_instructions( self, *, - user_id: typing.Optional[str] = None, - graph_id: typing.Optional[str] = None, + inherited: typing.Optional[bool] = OMIT, + instructions: typing.Optional[typing.Sequence[typing.Dict[str, typing.Any]]] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> ObservationSteeringConfig: + ) -> Instructions: """ - Returns project steering or the effective user/graph steering with project fallback. This API is experimental and may change in future releases. - Parameters ---------- - user_id : typing.Optional[str] - User ID for user-specific steering + inherited : typing.Optional[bool] + + instructions : typing.Optional[typing.Sequence[typing.Dict[str, typing.Any]]] - graph_id : typing.Optional[str] - Graph ID for graph-specific steering + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - ObservationSteeringConfig - Retrieved + Instructions + OK Examples -------- @@ -118,47 +147,139 @@ def get_observation_steering( client = Zep( api_key="YOUR_API_KEY", ) - client.project.get_observation_steering( - user_id="user_id", - graph_id="graph_id", + client.project.set_instructions() + """ + _response = self._raw_client.set_instructions( + inherited=inherited, + instructions=instructions, + idempotency_key=idempotency_key, + request_options=request_options, ) + return _response.data + + def get_observation_steering( + self, *, request_options: typing.Optional[RequestOptions] = None + ) -> ObservationSteering: """ - _response = self._raw_client.get_observation_steering( - user_id=user_id, graph_id=graph_id, request_options=request_options + Parameters + ---------- + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + ObservationSteering + OK + + Examples + -------- + from zep_cloud import Zep + + client = Zep( + api_key="YOUR_API_KEY", ) + client.project.get_observation_steering() + """ + _response = self._raw_client.get_observation_steering(request_options=request_options) return _response.data def set_observation_steering( self, *, - user_id: typing.Optional[str] = None, - graph_id: typing.Optional[str] = None, + inherited: typing.Optional[bool] = OMIT, instruction: typing.Optional[str] = OMIT, - types: typing.Optional[typing.Sequence[ObservationType]] = OMIT, + types: typing.Optional[typing.Sequence[typing.Dict[str, typing.Any]]] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> ObservationSteeringConfig: + ) -> ObservationSteering: """ - Replaces project, user, or graph steering. An empty configuration clears the project default or removes the user/graph override. Changes affect later materializer runs only. This API is experimental and may change in future releases. + Parameters + ---------- + inherited : typing.Optional[bool] + + instruction : typing.Optional[str] + + types : typing.Optional[typing.Sequence[typing.Dict[str, typing.Any]]] + idempotency_key : typing.Optional[str] + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + ObservationSteering + OK + + Examples + -------- + from zep_cloud import Zep + + client = Zep( + api_key="YOUR_API_KEY", + ) + client.project.set_observation_steering() + """ + _response = self._raw_client.set_observation_steering( + inherited=inherited, + instruction=instruction, + types=types, + idempotency_key=idempotency_key, + request_options=request_options, + ) + return _response.data + + def get_ontology(self, *, request_options: typing.Optional[RequestOptions] = None) -> Ontology: + """ Parameters ---------- - user_id : typing.Optional[str] - User ID for user-specific steering + request_options : typing.Optional[RequestOptions] + Request-specific configuration. - graph_id : typing.Optional[str] - Graph ID for graph-specific steering + Returns + ------- + Ontology + OK - instruction : typing.Optional[str] + Examples + -------- + from zep_cloud import Zep + + client = Zep( + api_key="YOUR_API_KEY", + ) + client.project.get_ontology() + """ + _response = self._raw_client.get_ontology(request_options=request_options) + return _response.data + + def set_ontology( + self, + *, + edge_types: typing.Optional[typing.Sequence[typing.Dict[str, typing.Any]]] = OMIT, + entity_types: typing.Optional[typing.Sequence[typing.Dict[str, typing.Any]]] = OMIT, + inherited: typing.Optional[bool] = OMIT, + idempotency_key: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> Ontology: + """ + Parameters + ---------- + edge_types : typing.Optional[typing.Sequence[typing.Dict[str, typing.Any]]] - types : typing.Optional[typing.Sequence[ObservationType]] + entity_types : typing.Optional[typing.Sequence[typing.Dict[str, typing.Any]]] + + inherited : typing.Optional[bool] + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - ObservationSteeringConfig - Updated + Ontology + OK Examples -------- @@ -167,13 +288,82 @@ def set_observation_steering( client = Zep( api_key="YOUR_API_KEY", ) - client.project.set_observation_steering( - user_id="user_id", - graph_id="graph_id", + client.project.set_ontology() + """ + _response = self._raw_client.set_ontology( + edge_types=edge_types, + entity_types=entity_types, + inherited=inherited, + idempotency_key=idempotency_key, + request_options=request_options, ) + return _response.data + + def get_user_summary_instructions( + self, *, request_options: typing.Optional[RequestOptions] = None + ) -> UserSummaryInstructions: """ - _response = self._raw_client.set_observation_steering( - user_id=user_id, graph_id=graph_id, instruction=instruction, types=types, request_options=request_options + Parameters + ---------- + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + UserSummaryInstructions + OK + + Examples + -------- + from zep_cloud import Zep + + client = Zep( + api_key="YOUR_API_KEY", + ) + client.project.get_user_summary_instructions() + """ + _response = self._raw_client.get_user_summary_instructions(request_options=request_options) + return _response.data + + def set_user_summary_instructions( + self, + *, + inherited: typing.Optional[bool] = OMIT, + instructions: typing.Optional[typing.Sequence[typing.Dict[str, typing.Any]]] = OMIT, + idempotency_key: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> UserSummaryInstructions: + """ + Parameters + ---------- + inherited : typing.Optional[bool] + + instructions : typing.Optional[typing.Sequence[typing.Dict[str, typing.Any]]] + + idempotency_key : typing.Optional[str] + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + UserSummaryInstructions + OK + + Examples + -------- + from zep_cloud import Zep + + client = Zep( + api_key="YOUR_API_KEY", + ) + client.project.set_user_summary_instructions() + """ + _response = self._raw_client.set_user_summary_instructions( + inherited=inherited, + instructions=instructions, + idempotency_key=idempotency_key, + request_options=request_options, ) return _response.data @@ -193,10 +383,8 @@ def with_raw_response(self) -> AsyncRawProjectClient: """ return self._raw_client - async def get(self, *, request_options: typing.Optional[RequestOptions] = None) -> ProjectInfoResponse: + async def get(self, *, request_options: typing.Optional[RequestOptions] = None) -> Project: """ - Retrieve project info based on the provided api key. - Parameters ---------- request_options : typing.Optional[RequestOptions] @@ -204,8 +392,8 @@ async def get(self, *, request_options: typing.Optional[RequestOptions] = None) Returns ------- - ProjectInfoResponse - Retrieved + Project + OK Examples -------- @@ -228,23 +416,27 @@ async def main() -> None: return _response.data async def update( - self, *, default_time_zone: typing.Optional[str] = OMIT, request_options: typing.Optional[RequestOptions] = None - ) -> ProjectInfoResponse: + self, + *, + default_time_zone: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> Project: """ - Sets or clears the project-level fallback time zone for the API key's project. - Parameters ---------- default_time_zone : typing.Optional[str] - The project's IANA fallback time zone. Null clears the existing value. + Omit to leave unchanged, send JSON null to clear, or send a value to set. + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - ProjectInfoResponse - Updated + Project + OK Examples -------- @@ -263,34 +455,67 @@ async def main() -> None: asyncio.run(main()) """ - _response = await self._raw_client.update(default_time_zone=default_time_zone, request_options=request_options) + _response = await self._raw_client.update( + default_time_zone=default_time_zone, idempotency_key=idempotency_key, request_options=request_options + ) return _response.data - async def get_observation_steering( + async def get_instructions(self, *, request_options: typing.Optional[RequestOptions] = None) -> Instructions: + """ + Parameters + ---------- + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + Instructions + OK + + Examples + -------- + import asyncio + + from zep_cloud import AsyncZep + + client = AsyncZep( + api_key="YOUR_API_KEY", + ) + + + async def main() -> None: + await client.project.get_instructions() + + + asyncio.run(main()) + """ + _response = await self._raw_client.get_instructions(request_options=request_options) + return _response.data + + async def set_instructions( self, *, - user_id: typing.Optional[str] = None, - graph_id: typing.Optional[str] = None, + inherited: typing.Optional[bool] = OMIT, + instructions: typing.Optional[typing.Sequence[typing.Dict[str, typing.Any]]] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> ObservationSteeringConfig: + ) -> Instructions: """ - Returns project steering or the effective user/graph steering with project fallback. This API is experimental and may change in future releases. - Parameters ---------- - user_id : typing.Optional[str] - User ID for user-specific steering + inherited : typing.Optional[bool] - graph_id : typing.Optional[str] - Graph ID for graph-specific steering + instructions : typing.Optional[typing.Sequence[typing.Dict[str, typing.Any]]] + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - ObservationSteeringConfig - Retrieved + Instructions + OK Examples -------- @@ -304,50 +529,80 @@ async def get_observation_steering( async def main() -> None: - await client.project.get_observation_steering( - user_id="user_id", - graph_id="graph_id", - ) + await client.project.set_instructions() asyncio.run(main()) """ - _response = await self._raw_client.get_observation_steering( - user_id=user_id, graph_id=graph_id, request_options=request_options + _response = await self._raw_client.set_instructions( + inherited=inherited, + instructions=instructions, + idempotency_key=idempotency_key, + request_options=request_options, + ) + return _response.data + + async def get_observation_steering( + self, *, request_options: typing.Optional[RequestOptions] = None + ) -> ObservationSteering: + """ + Parameters + ---------- + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + ObservationSteering + OK + + Examples + -------- + import asyncio + + from zep_cloud import AsyncZep + + client = AsyncZep( + api_key="YOUR_API_KEY", ) + + + async def main() -> None: + await client.project.get_observation_steering() + + + asyncio.run(main()) + """ + _response = await self._raw_client.get_observation_steering(request_options=request_options) return _response.data async def set_observation_steering( self, *, - user_id: typing.Optional[str] = None, - graph_id: typing.Optional[str] = None, + inherited: typing.Optional[bool] = OMIT, instruction: typing.Optional[str] = OMIT, - types: typing.Optional[typing.Sequence[ObservationType]] = OMIT, + types: typing.Optional[typing.Sequence[typing.Dict[str, typing.Any]]] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> ObservationSteeringConfig: + ) -> ObservationSteering: """ - Replaces project, user, or graph steering. An empty configuration clears the project default or removes the user/graph override. Changes affect later materializer runs only. This API is experimental and may change in future releases. - Parameters ---------- - user_id : typing.Optional[str] - User ID for user-specific steering - - graph_id : typing.Optional[str] - Graph ID for graph-specific steering + inherited : typing.Optional[bool] instruction : typing.Optional[str] - types : typing.Optional[typing.Sequence[ObservationType]] + types : typing.Optional[typing.Sequence[typing.Dict[str, typing.Any]]] + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - ObservationSteeringConfig - Updated + ObservationSteering + OK Examples -------- @@ -361,15 +616,186 @@ async def set_observation_steering( async def main() -> None: - await client.project.set_observation_steering( - user_id="user_id", - graph_id="graph_id", - ) + await client.project.set_observation_steering() asyncio.run(main()) """ _response = await self._raw_client.set_observation_steering( - user_id=user_id, graph_id=graph_id, instruction=instruction, types=types, request_options=request_options + inherited=inherited, + instruction=instruction, + types=types, + idempotency_key=idempotency_key, + request_options=request_options, + ) + return _response.data + + async def get_ontology(self, *, request_options: typing.Optional[RequestOptions] = None) -> Ontology: + """ + Parameters + ---------- + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + Ontology + OK + + Examples + -------- + import asyncio + + from zep_cloud import AsyncZep + + client = AsyncZep( + api_key="YOUR_API_KEY", + ) + + + async def main() -> None: + await client.project.get_ontology() + + + asyncio.run(main()) + """ + _response = await self._raw_client.get_ontology(request_options=request_options) + return _response.data + + async def set_ontology( + self, + *, + edge_types: typing.Optional[typing.Sequence[typing.Dict[str, typing.Any]]] = OMIT, + entity_types: typing.Optional[typing.Sequence[typing.Dict[str, typing.Any]]] = OMIT, + inherited: typing.Optional[bool] = OMIT, + idempotency_key: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> Ontology: + """ + Parameters + ---------- + edge_types : typing.Optional[typing.Sequence[typing.Dict[str, typing.Any]]] + + entity_types : typing.Optional[typing.Sequence[typing.Dict[str, typing.Any]]] + + inherited : typing.Optional[bool] + + idempotency_key : typing.Optional[str] + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + Ontology + OK + + Examples + -------- + import asyncio + + from zep_cloud import AsyncZep + + client = AsyncZep( + api_key="YOUR_API_KEY", + ) + + + async def main() -> None: + await client.project.set_ontology() + + + asyncio.run(main()) + """ + _response = await self._raw_client.set_ontology( + edge_types=edge_types, + entity_types=entity_types, + inherited=inherited, + idempotency_key=idempotency_key, + request_options=request_options, + ) + return _response.data + + async def get_user_summary_instructions( + self, *, request_options: typing.Optional[RequestOptions] = None + ) -> UserSummaryInstructions: + """ + Parameters + ---------- + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + UserSummaryInstructions + OK + + Examples + -------- + import asyncio + + from zep_cloud import AsyncZep + + client = AsyncZep( + api_key="YOUR_API_KEY", + ) + + + async def main() -> None: + await client.project.get_user_summary_instructions() + + + asyncio.run(main()) + """ + _response = await self._raw_client.get_user_summary_instructions(request_options=request_options) + return _response.data + + async def set_user_summary_instructions( + self, + *, + inherited: typing.Optional[bool] = OMIT, + instructions: typing.Optional[typing.Sequence[typing.Dict[str, typing.Any]]] = OMIT, + idempotency_key: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> UserSummaryInstructions: + """ + Parameters + ---------- + inherited : typing.Optional[bool] + + instructions : typing.Optional[typing.Sequence[typing.Dict[str, typing.Any]]] + + idempotency_key : typing.Optional[str] + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + UserSummaryInstructions + OK + + Examples + -------- + import asyncio + + from zep_cloud import AsyncZep + + client = AsyncZep( + api_key="YOUR_API_KEY", + ) + + + async def main() -> None: + await client.project.set_user_summary_instructions() + + + asyncio.run(main()) + """ + _response = await self._raw_client.set_user_summary_instructions( + inherited=inherited, + instructions=instructions, + idempotency_key=idempotency_key, + request_options=request_options, ) return _response.data diff --git a/src/zep_cloud/project/raw_client.py b/src/zep_cloud/project/raw_client.py index a8ce469c..fcc4d593 100644 --- a/src/zep_cloud/project/raw_client.py +++ b/src/zep_cloud/project/raw_client.py @@ -6,16 +6,19 @@ 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.parse_error import ParsingError 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 ..errors.unauthorized_error import UnauthorizedError from ..types.api_error import ApiError as types_api_error_ApiError -from ..types.observation_steering_config import ObservationSteeringConfig -from ..types.observation_type import ObservationType -from ..types.project_info_response import ProjectInfoResponse +from ..types.instructions import Instructions +from ..types.observation_steering import ObservationSteering +from ..types.ontology import Ontology +from ..types.project import Project +from ..types.user_summary_instructions import UserSummaryInstructions +from pydantic import ValidationError # this is used as the default value for optional parameters OMIT = typing.cast(typing.Any, ...) @@ -25,42 +28,999 @@ class RawProjectClient: def __init__(self, *, client_wrapper: SyncClientWrapper): self._client_wrapper = client_wrapper - def get(self, *, request_options: typing.Optional[RequestOptions] = None) -> HttpResponse[ProjectInfoResponse]: + def get(self, *, request_options: typing.Optional[RequestOptions] = None) -> HttpResponse[Project]: """ - Retrieve project info based on the provided api key. + Parameters + ---------- + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[Project] + OK + """ + _response = self._client_wrapper.httpx_client.request( + "project", + method="GET", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + Project, + parse_obj_as( + type_=Project, # 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( + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + 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(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise core_api_error_ApiError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.text + ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) + raise core_api_error_ApiError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response_json + ) + + def update( + self, + *, + default_time_zone: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[Project]: + """ + Parameters + ---------- + default_time_zone : typing.Optional[str] + Omit to leave unchanged, send JSON null to clear, or send a value to set. + + idempotency_key : typing.Optional[str] + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[Project] + OK + """ + _response = self._client_wrapper.httpx_client.request( + "project", + method="PATCH", + json={ + "default_time_zone": default_time_zone, + }, + headers={ + "content-type": "application/json", + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + Project, + parse_obj_as( + type_=Project, # 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( + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + 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(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise core_api_error_ApiError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.text + ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) + raise core_api_error_ApiError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response_json + ) + + def get_instructions( + self, *, request_options: typing.Optional[RequestOptions] = None + ) -> HttpResponse[Instructions]: + """ + Parameters + ---------- + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[Instructions] + OK + """ + _response = self._client_wrapper.httpx_client.request( + "project/instructions", + method="GET", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + Instructions, + parse_obj_as( + type_=Instructions, # 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( + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + 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(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise core_api_error_ApiError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.text + ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) + raise core_api_error_ApiError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response_json + ) + + def set_instructions( + self, + *, + inherited: typing.Optional[bool] = OMIT, + instructions: typing.Optional[typing.Sequence[typing.Dict[str, typing.Any]]] = OMIT, + idempotency_key: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[Instructions]: + """ + Parameters + ---------- + inherited : typing.Optional[bool] + + instructions : typing.Optional[typing.Sequence[typing.Dict[str, typing.Any]]] + + idempotency_key : typing.Optional[str] + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[Instructions] + OK + """ + _response = self._client_wrapper.httpx_client.request( + "project/instructions", + method="PUT", + json={ + "inherited": inherited, + "instructions": instructions, + }, + headers={ + "content-type": "application/json", + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + Instructions, + parse_obj_as( + type_=Instructions, # 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( + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + 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(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise core_api_error_ApiError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.text + ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) + raise core_api_error_ApiError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response_json + ) + + def get_observation_steering( + self, *, request_options: typing.Optional[RequestOptions] = None + ) -> HttpResponse[ObservationSteering]: + """ + Parameters + ---------- + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[ObservationSteering] + OK + """ + _response = self._client_wrapper.httpx_client.request( + "project/observation-steering", + method="GET", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + ObservationSteering, + parse_obj_as( + type_=ObservationSteering, # 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( + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + 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(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise core_api_error_ApiError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.text + ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) + raise core_api_error_ApiError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response_json + ) + + def set_observation_steering( + self, + *, + inherited: typing.Optional[bool] = OMIT, + instruction: typing.Optional[str] = OMIT, + types: typing.Optional[typing.Sequence[typing.Dict[str, typing.Any]]] = OMIT, + idempotency_key: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[ObservationSteering]: + """ + Parameters + ---------- + inherited : typing.Optional[bool] + + instruction : typing.Optional[str] + + types : typing.Optional[typing.Sequence[typing.Dict[str, typing.Any]]] + + idempotency_key : typing.Optional[str] + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[ObservationSteering] + OK + """ + _response = self._client_wrapper.httpx_client.request( + "project/observation-steering", + method="PUT", + json={ + "inherited": inherited, + "instruction": instruction, + "types": types, + }, + headers={ + "content-type": "application/json", + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + ObservationSteering, + parse_obj_as( + type_=ObservationSteering, # 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( + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + 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(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise core_api_error_ApiError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.text + ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) + raise core_api_error_ApiError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response_json + ) + + def get_ontology(self, *, request_options: typing.Optional[RequestOptions] = None) -> HttpResponse[Ontology]: + """ + Parameters + ---------- + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[Ontology] + OK + """ + _response = self._client_wrapper.httpx_client.request( + "project/ontology", + method="GET", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + Ontology, + parse_obj_as( + type_=Ontology, # 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( + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + 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(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise core_api_error_ApiError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.text + ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) + raise core_api_error_ApiError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response_json + ) + + def set_ontology( + self, + *, + edge_types: typing.Optional[typing.Sequence[typing.Dict[str, typing.Any]]] = OMIT, + entity_types: typing.Optional[typing.Sequence[typing.Dict[str, typing.Any]]] = OMIT, + inherited: typing.Optional[bool] = OMIT, + idempotency_key: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[Ontology]: + """ + Parameters + ---------- + edge_types : typing.Optional[typing.Sequence[typing.Dict[str, typing.Any]]] + + entity_types : typing.Optional[typing.Sequence[typing.Dict[str, typing.Any]]] + + inherited : typing.Optional[bool] + + idempotency_key : typing.Optional[str] + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[Ontology] + OK + """ + _response = self._client_wrapper.httpx_client.request( + "project/ontology", + method="PUT", + json={ + "edge_types": edge_types, + "entity_types": entity_types, + "inherited": inherited, + }, + headers={ + "content-type": "application/json", + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + Ontology, + parse_obj_as( + type_=Ontology, # 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( + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + 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(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise core_api_error_ApiError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.text + ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) + raise core_api_error_ApiError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response_json + ) + + def get_user_summary_instructions( + self, *, request_options: typing.Optional[RequestOptions] = None + ) -> HttpResponse[UserSummaryInstructions]: + """ + Parameters + ---------- + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[UserSummaryInstructions] + OK + """ + _response = self._client_wrapper.httpx_client.request( + "project/user-summary-instructions", + method="GET", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + UserSummaryInstructions, + parse_obj_as( + type_=UserSummaryInstructions, # 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( + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + 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(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise core_api_error_ApiError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.text + ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) + raise core_api_error_ApiError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response_json + ) + + def set_user_summary_instructions( + self, + *, + inherited: typing.Optional[bool] = OMIT, + instructions: typing.Optional[typing.Sequence[typing.Dict[str, typing.Any]]] = OMIT, + idempotency_key: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[UserSummaryInstructions]: + """ + Parameters + ---------- + inherited : typing.Optional[bool] + + instructions : typing.Optional[typing.Sequence[typing.Dict[str, typing.Any]]] + + idempotency_key : typing.Optional[str] + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[UserSummaryInstructions] + OK + """ + _response = self._client_wrapper.httpx_client.request( + "project/user-summary-instructions", + method="PUT", + json={ + "inherited": inherited, + "instructions": instructions, + }, + headers={ + "content-type": "application/json", + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + UserSummaryInstructions, + parse_obj_as( + type_=UserSummaryInstructions, # 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( + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + 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(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise core_api_error_ApiError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.text + ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) + raise core_api_error_ApiError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response_json + ) + + +class AsyncRawProjectClient: + def __init__(self, *, client_wrapper: AsyncClientWrapper): + self._client_wrapper = client_wrapper + + async def get(self, *, request_options: typing.Optional[RequestOptions] = None) -> AsyncHttpResponse[Project]: + """ + Parameters + ---------- + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[Project] + OK + """ + _response = await self._client_wrapper.httpx_client.request( + "project", + method="GET", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + Project, + parse_obj_as( + type_=Project, # 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( + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + 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(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise core_api_error_ApiError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.text + ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) + raise core_api_error_ApiError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response_json + ) + async def update( + self, + *, + default_time_zone: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[Project]: + """ Parameters ---------- + default_time_zone : typing.Optional[str] + Omit to leave unchanged, send JSON null to clear, or send a value to set. + + idempotency_key : typing.Optional[str] + request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - HttpResponse[ProjectInfoResponse] - Retrieved + AsyncHttpResponse[Project] + OK """ - _response = self._client_wrapper.httpx_client.request( - "projects/info", - method="GET", + _response = await self._client_wrapper.httpx_client.request( + "project", + method="PATCH", + json={ + "default_time_zone": default_time_zone, + }, + headers={ + "content-type": "application/json", + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, + }, request_options=request_options, + omit=OMIT, ) try: if 200 <= _response.status_code < 300: _data = typing.cast( - ProjectInfoResponse, + Project, parse_obj_as( - type_=ProjectInfoResponse, # type: ignore + type_=Project, # type: ignore object_=_response.json(), ), ) - return HttpResponse(response=_response, data=_data) + return AsyncHttpResponse(response=_response, data=_data) if _response.status_code == 400: raise BadRequestError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore object_=_response.json(), ), ), @@ -76,8 +1036,72 @@ def get(self, *, request_options: typing.Optional[RequestOptions] = None) -> Htt ), ), ) - if _response.status_code == 500: - raise InternalServerError( + _response_json = _response.json() + except JSONDecodeError: + raise core_api_error_ApiError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.text + ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) + raise core_api_error_ApiError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response_json + ) + + async def get_instructions( + self, *, request_options: typing.Optional[RequestOptions] = None + ) -> AsyncHttpResponse[Instructions]: + """ + Parameters + ---------- + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[Instructions] + OK + """ + _response = await self._client_wrapper.httpx_client.request( + "project/instructions", + method="GET", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + Instructions, + parse_obj_as( + type_=Instructions, # 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( + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + 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, @@ -92,37 +1116,49 @@ def get(self, *, request_options: typing.Optional[RequestOptions] = None) -> Htt raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - def update( - self, *, default_time_zone: typing.Optional[str] = OMIT, request_options: typing.Optional[RequestOptions] = None - ) -> HttpResponse[ProjectInfoResponse]: + async def set_instructions( + self, + *, + inherited: typing.Optional[bool] = OMIT, + instructions: typing.Optional[typing.Sequence[typing.Dict[str, typing.Any]]] = OMIT, + idempotency_key: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[Instructions]: """ - Sets or clears the project-level fallback time zone for the API key's project. - Parameters ---------- - default_time_zone : typing.Optional[str] - The project's IANA fallback time zone. Null clears the existing value. + inherited : typing.Optional[bool] + + instructions : typing.Optional[typing.Sequence[typing.Dict[str, typing.Any]]] + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - HttpResponse[ProjectInfoResponse] - Updated + AsyncHttpResponse[Instructions] + OK """ - _response = self._client_wrapper.httpx_client.request( - "projects/info", - method="PATCH", + _response = await self._client_wrapper.httpx_client.request( + "project/instructions", + method="PUT", json={ - "default_time_zone": default_time_zone, + "inherited": inherited, + "instructions": instructions, }, headers={ "content-type": "application/json", + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, }, request_options=request_options, omit=OMIT, @@ -130,26 +1166,26 @@ def update( try: if 200 <= _response.status_code < 300: _data = typing.cast( - ProjectInfoResponse, + Instructions, parse_obj_as( - type_=ProjectInfoResponse, # type: ignore + type_=Instructions, # type: ignore object_=_response.json(), ), ) - return HttpResponse(response=_response, data=_data) + return AsyncHttpResponse(response=_response, data=_data) if _response.status_code == 400: raise BadRequestError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore object_=_response.json(), ), ), ) - if _response.status_code == 404: - raise NotFoundError( + if _response.status_code == 401: + raise UnauthorizedError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -159,8 +1195,8 @@ def update( ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -175,68 +1211,67 @@ def update( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - def get_observation_steering( - self, - *, - user_id: typing.Optional[str] = None, - graph_id: typing.Optional[str] = None, - request_options: typing.Optional[RequestOptions] = None, - ) -> HttpResponse[ObservationSteeringConfig]: + async def get_observation_steering( + self, *, request_options: typing.Optional[RequestOptions] = None + ) -> AsyncHttpResponse[ObservationSteering]: """ - Returns project steering or the effective user/graph steering with project fallback. This API is experimental and may change in future releases. - Parameters ---------- - user_id : typing.Optional[str] - User ID for user-specific steering - - graph_id : typing.Optional[str] - Graph ID for graph-specific steering - request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - HttpResponse[ObservationSteeringConfig] - Retrieved + AsyncHttpResponse[ObservationSteering] + OK """ - _response = self._client_wrapper.httpx_client.request( - "projects/observation-steering", + _response = await self._client_wrapper.httpx_client.request( + "project/observation-steering", method="GET", - params={ - "user_id": user_id, - "graph_id": graph_id, - }, request_options=request_options, ) try: if 200 <= _response.status_code < 300: _data = typing.cast( - ObservationSteeringConfig, + ObservationSteering, parse_obj_as( - type_=ObservationSteeringConfig, # type: ignore + type_=ObservationSteering, # type: ignore object_=_response.json(), ), ) - return HttpResponse(response=_response, data=_data) + return AsyncHttpResponse(response=_response, data=_data) if _response.status_code == 400: raise BadRequestError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore object_=_response.json(), ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -251,57 +1286,53 @@ def get_observation_steering( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - def set_observation_steering( + async def set_observation_steering( self, *, - user_id: typing.Optional[str] = None, - graph_id: typing.Optional[str] = None, + inherited: typing.Optional[bool] = OMIT, instruction: typing.Optional[str] = OMIT, - types: typing.Optional[typing.Sequence[ObservationType]] = OMIT, + types: typing.Optional[typing.Sequence[typing.Dict[str, typing.Any]]] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> HttpResponse[ObservationSteeringConfig]: + ) -> AsyncHttpResponse[ObservationSteering]: """ - Replaces project, user, or graph steering. An empty configuration clears the project default or removes the user/graph override. Changes affect later materializer runs only. This API is experimental and may change in future releases. - Parameters ---------- - user_id : typing.Optional[str] - User ID for user-specific steering - - graph_id : typing.Optional[str] - Graph ID for graph-specific steering + inherited : typing.Optional[bool] instruction : typing.Optional[str] - types : typing.Optional[typing.Sequence[ObservationType]] + types : typing.Optional[typing.Sequence[typing.Dict[str, typing.Any]]] + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - HttpResponse[ObservationSteeringConfig] - Updated + AsyncHttpResponse[ObservationSteering] + OK """ - _response = self._client_wrapper.httpx_client.request( - "projects/observation-steering", + _response = await self._client_wrapper.httpx_client.request( + "project/observation-steering", method="PUT", - params={ - "user_id": user_id, - "graph_id": graph_id, - }, json={ + "inherited": inherited, "instruction": instruction, - "types": convert_and_respect_annotation_metadata( - object_=types, annotation=typing.Sequence[ObservationType], direction="write" - ), + "types": types, }, headers={ "content-type": "application/json", + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, }, request_options=request_options, omit=OMIT, @@ -309,26 +1340,37 @@ def set_observation_steering( try: if 200 <= _response.status_code < 300: _data = typing.cast( - ObservationSteeringConfig, + ObservationSteering, parse_obj_as( - type_=ObservationSteeringConfig, # type: ignore + type_=ObservationSteering, # type: ignore object_=_response.json(), ), ) - return HttpResponse(response=_response, data=_data) + return AsyncHttpResponse(response=_response, data=_data) if _response.status_code == 400: raise BadRequestError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore object_=_response.json(), ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -343,21 +1385,18 @@ def set_observation_steering( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - -class AsyncRawProjectClient: - def __init__(self, *, client_wrapper: AsyncClientWrapper): - self._client_wrapper = client_wrapper - - async def get( + async def get_ontology( self, *, request_options: typing.Optional[RequestOptions] = None - ) -> AsyncHttpResponse[ProjectInfoResponse]: + ) -> AsyncHttpResponse[Ontology]: """ - Retrieve project info based on the provided api key. - Parameters ---------- request_options : typing.Optional[RequestOptions] @@ -365,20 +1404,20 @@ async def get( Returns ------- - AsyncHttpResponse[ProjectInfoResponse] - Retrieved + AsyncHttpResponse[Ontology] + OK """ _response = await self._client_wrapper.httpx_client.request( - "projects/info", + "project/ontology", method="GET", request_options=request_options, ) try: if 200 <= _response.status_code < 300: _data = typing.cast( - ProjectInfoResponse, + Ontology, parse_obj_as( - type_=ProjectInfoResponse, # type: ignore + type_=Ontology, # type: ignore object_=_response.json(), ), ) @@ -387,15 +1426,15 @@ async def get( raise BadRequestError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore object_=_response.json(), ), ), ) - if _response.status_code == 404: - raise NotFoundError( + if _response.status_code == 401: + raise UnauthorizedError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -405,8 +1444,8 @@ async def get( ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -421,37 +1460,53 @@ async def get( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - async def update( - self, *, default_time_zone: typing.Optional[str] = OMIT, request_options: typing.Optional[RequestOptions] = None - ) -> AsyncHttpResponse[ProjectInfoResponse]: + async def set_ontology( + self, + *, + edge_types: typing.Optional[typing.Sequence[typing.Dict[str, typing.Any]]] = OMIT, + entity_types: typing.Optional[typing.Sequence[typing.Dict[str, typing.Any]]] = OMIT, + inherited: typing.Optional[bool] = OMIT, + idempotency_key: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[Ontology]: """ - Sets or clears the project-level fallback time zone for the API key's project. - Parameters ---------- - default_time_zone : typing.Optional[str] - The project's IANA fallback time zone. Null clears the existing value. + edge_types : typing.Optional[typing.Sequence[typing.Dict[str, typing.Any]]] + + entity_types : typing.Optional[typing.Sequence[typing.Dict[str, typing.Any]]] + + inherited : typing.Optional[bool] + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - AsyncHttpResponse[ProjectInfoResponse] - Updated + AsyncHttpResponse[Ontology] + OK """ _response = await self._client_wrapper.httpx_client.request( - "projects/info", - method="PATCH", + "project/ontology", + method="PUT", json={ - "default_time_zone": default_time_zone, + "edge_types": edge_types, + "entity_types": entity_types, + "inherited": inherited, }, headers={ "content-type": "application/json", + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, }, request_options=request_options, omit=OMIT, @@ -459,9 +1514,9 @@ async def update( try: if 200 <= _response.status_code < 300: _data = typing.cast( - ProjectInfoResponse, + Ontology, parse_obj_as( - type_=ProjectInfoResponse, # type: ignore + type_=Ontology, # type: ignore object_=_response.json(), ), ) @@ -470,15 +1525,15 @@ async def update( raise BadRequestError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore object_=_response.json(), ), ), ) - if _response.status_code == 404: - raise NotFoundError( + if _response.status_code == 401: + raise UnauthorizedError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -488,8 +1543,8 @@ async def update( ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -504,51 +1559,39 @@ async def update( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - async def get_observation_steering( - self, - *, - user_id: typing.Optional[str] = None, - graph_id: typing.Optional[str] = None, - request_options: typing.Optional[RequestOptions] = None, - ) -> AsyncHttpResponse[ObservationSteeringConfig]: + async def get_user_summary_instructions( + self, *, request_options: typing.Optional[RequestOptions] = None + ) -> AsyncHttpResponse[UserSummaryInstructions]: """ - Returns project steering or the effective user/graph steering with project fallback. This API is experimental and may change in future releases. - Parameters ---------- - user_id : typing.Optional[str] - User ID for user-specific steering - - graph_id : typing.Optional[str] - Graph ID for graph-specific steering - request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - AsyncHttpResponse[ObservationSteeringConfig] - Retrieved + AsyncHttpResponse[UserSummaryInstructions] + OK """ _response = await self._client_wrapper.httpx_client.request( - "projects/observation-steering", + "project/user-summary-instructions", method="GET", - params={ - "user_id": user_id, - "graph_id": graph_id, - }, request_options=request_options, ) try: if 200 <= _response.status_code < 300: _data = typing.cast( - ObservationSteeringConfig, + UserSummaryInstructions, parse_obj_as( - type_=ObservationSteeringConfig, # type: ignore + type_=UserSummaryInstructions, # type: ignore object_=_response.json(), ), ) @@ -557,15 +1600,26 @@ async def get_observation_steering( raise BadRequestError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore object_=_response.json(), ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -580,57 +1634,49 @@ async def get_observation_steering( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - async def set_observation_steering( + async def set_user_summary_instructions( self, *, - user_id: typing.Optional[str] = None, - graph_id: typing.Optional[str] = None, - instruction: typing.Optional[str] = OMIT, - types: typing.Optional[typing.Sequence[ObservationType]] = OMIT, + inherited: typing.Optional[bool] = OMIT, + instructions: typing.Optional[typing.Sequence[typing.Dict[str, typing.Any]]] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> AsyncHttpResponse[ObservationSteeringConfig]: + ) -> AsyncHttpResponse[UserSummaryInstructions]: """ - Replaces project, user, or graph steering. An empty configuration clears the project default or removes the user/graph override. Changes affect later materializer runs only. This API is experimental and may change in future releases. - Parameters ---------- - user_id : typing.Optional[str] - User ID for user-specific steering + inherited : typing.Optional[bool] - graph_id : typing.Optional[str] - Graph ID for graph-specific steering - - instruction : typing.Optional[str] + instructions : typing.Optional[typing.Sequence[typing.Dict[str, typing.Any]]] - types : typing.Optional[typing.Sequence[ObservationType]] + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - AsyncHttpResponse[ObservationSteeringConfig] - Updated + AsyncHttpResponse[UserSummaryInstructions] + OK """ _response = await self._client_wrapper.httpx_client.request( - "projects/observation-steering", + "project/user-summary-instructions", method="PUT", - params={ - "user_id": user_id, - "graph_id": graph_id, - }, json={ - "instruction": instruction, - "types": convert_and_respect_annotation_metadata( - object_=types, annotation=typing.Sequence[ObservationType], direction="write" - ), + "inherited": inherited, + "instructions": instructions, }, headers={ "content-type": "application/json", + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, }, request_options=request_options, omit=OMIT, @@ -638,9 +1684,9 @@ async def set_observation_steering( try: if 200 <= _response.status_code < 300: _data = typing.cast( - ObservationSteeringConfig, + UserSummaryInstructions, parse_obj_as( - type_=ObservationSteeringConfig, # type: ignore + type_=UserSummaryInstructions, # type: ignore object_=_response.json(), ), ) @@ -649,15 +1695,26 @@ async def set_observation_steering( raise BadRequestError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore object_=_response.json(), ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -672,6 +1729,10 @@ async def set_observation_steering( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) diff --git a/src/zep_cloud/task/client.py b/src/zep_cloud/task/client.py index bd546161..6900d8dd 100644 --- a/src/zep_cloud/task/client.py +++ b/src/zep_cloud/task/client.py @@ -3,8 +3,10 @@ import typing from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper +from ..core.pagination import AsyncPager, SyncPager from ..core.request_options import RequestOptions -from ..types.get_task_response import GetTaskResponse +from ..types.task import Task +from ..types.task_page import TaskPage from .raw_client import AsyncRawTaskClient, RawTaskClient @@ -23,22 +25,63 @@ def with_raw_response(self) -> RawTaskClient: """ return self._raw_client - def get(self, task_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> GetTaskResponse: + def list( + self, + *, + limit: typing.Optional[int] = None, + cursor: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> SyncPager[Task, TaskPage]: """ - Gets a task by its ID + Parameters + ---------- + limit : typing.Optional[int] + Page size + + cursor : typing.Optional[str] + Opaque page cursor + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + SyncPager[Task, TaskPage] + OK + + Examples + -------- + from zep_cloud import Zep + client = Zep( + api_key="YOUR_API_KEY", + ) + response = client.task.list( + limit=1, + cursor="cursor", + ) + for item in response: + yield item + # alternatively, you can paginate page-by-page + for page in response.iter_pages(): + yield page + """ + return self._raw_client.list(limit=limit, cursor=cursor, request_options=request_options) + + def get(self, task_uuid: str, *, request_options: typing.Optional[RequestOptions] = None) -> Task: + """ Parameters ---------- - task_id : str - Task ID + task_uuid : str + Task UUID request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - GetTaskResponse - Task + Task + OK Examples -------- @@ -48,10 +91,10 @@ def get(self, task_id: str, *, request_options: typing.Optional[RequestOptions] api_key="YOUR_API_KEY", ) client.task.get( - task_id="task_id", + task_uuid="task_uuid", ) """ - _response = self._raw_client.get(task_id, request_options=request_options) + _response = self._raw_client.get(task_uuid, request_options=request_options) return _response.data @@ -70,22 +113,72 @@ def with_raw_response(self) -> AsyncRawTaskClient: """ return self._raw_client - async def get(self, task_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> GetTaskResponse: + async def list( + self, + *, + limit: typing.Optional[int] = None, + cursor: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncPager[Task, TaskPage]: """ - Gets a task by its ID + Parameters + ---------- + limit : typing.Optional[int] + Page size + cursor : typing.Optional[str] + Opaque page cursor + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncPager[Task, TaskPage] + OK + + Examples + -------- + import asyncio + + from zep_cloud import AsyncZep + + client = AsyncZep( + api_key="YOUR_API_KEY", + ) + + + async def main() -> None: + response = await client.task.list( + limit=1, + cursor="cursor", + ) + async for item in response: + yield item + + # alternatively, you can paginate page-by-page + async for page in response.iter_pages(): + yield page + + + asyncio.run(main()) + """ + return await self._raw_client.list(limit=limit, cursor=cursor, request_options=request_options) + + async def get(self, task_uuid: str, *, request_options: typing.Optional[RequestOptions] = None) -> Task: + """ Parameters ---------- - task_id : str - Task ID + task_uuid : str + Task UUID request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - GetTaskResponse - Task + Task + OK Examples -------- @@ -100,11 +193,11 @@ async def get(self, task_id: str, *, request_options: typing.Optional[RequestOpt async def main() -> None: await client.task.get( - task_id="task_id", + task_uuid="task_uuid", ) asyncio.run(main()) """ - _response = await self._raw_client.get(task_id, request_options=request_options) + _response = await self._raw_client.get(task_uuid, request_options=request_options) return _response.data diff --git a/src/zep_cloud/task/raw_client.py b/src/zep_cloud/task/raw_client.py index 1089a3ef..6a40ba70 100644 --- a/src/zep_cloud/task/raw_client.py +++ b/src/zep_cloud/task/raw_client.py @@ -7,54 +7,152 @@ from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper from ..core.http_response import AsyncHttpResponse, HttpResponse from ..core.jsonable_encoder import jsonable_encoder +from ..core.pagination import AsyncPager, SyncPager +from ..core.parse_error import ParsingError from ..core.pydantic_utilities import parse_obj_as from ..core.request_options import RequestOptions -from ..errors.internal_server_error import InternalServerError +from ..errors.bad_request_error import BadRequestError from ..errors.not_found_error import NotFoundError +from ..errors.unauthorized_error import UnauthorizedError from ..types.api_error import ApiError as types_api_error_ApiError -from ..types.get_task_response import GetTaskResponse +from ..types.task import Task +from ..types.task_page import TaskPage +from pydantic import ValidationError class RawTaskClient: def __init__(self, *, client_wrapper: SyncClientWrapper): self._client_wrapper = client_wrapper - def get( - self, task_id: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> HttpResponse[GetTaskResponse]: + def list( + self, + *, + limit: typing.Optional[int] = None, + cursor: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> SyncPager[Task, TaskPage]: """ - Gets a task by its ID + Parameters + ---------- + limit : typing.Optional[int] + Page size + + cursor : typing.Optional[str] + Opaque page cursor + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + SyncPager[Task, TaskPage] + OK + """ + _response = self._client_wrapper.httpx_client.request( + "tasks", + method="GET", + params={ + "limit": limit, + "cursor": cursor, + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _parsed_response = typing.cast( + TaskPage, + parse_obj_as( + type_=TaskPage, # type: ignore + object_=_response.json(), + ), + ) + _items = _parsed_response.items + _parsed_next = _parsed_response.next_cursor + _has_next = _parsed_next is not None and _parsed_next != "" + _get_next = lambda: self.list( + limit=limit, + cursor=_parsed_next, + request_options=request_options, + ) + return SyncPager(has_next=_has_next, items=_items, get_next=_get_next, response=_parsed_response) + if _response.status_code == 400: + raise BadRequestError( + 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 == 401: + raise UnauthorizedError( + 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(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise core_api_error_ApiError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.text + ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) + raise core_api_error_ApiError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response_json + ) + def get(self, task_uuid: str, *, request_options: typing.Optional[RequestOptions] = None) -> HttpResponse[Task]: + """ Parameters ---------- - task_id : str - Task ID + task_uuid : str + Task UUID request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - HttpResponse[GetTaskResponse] - Task + HttpResponse[Task] + OK """ _response = self._client_wrapper.httpx_client.request( - f"tasks/{jsonable_encoder(task_id)}", + f"tasks/{jsonable_encoder(task_uuid)}", method="GET", request_options=request_options, ) try: if 200 <= _response.status_code < 300: _data = typing.cast( - GetTaskResponse, + Task, parse_obj_as( - type_=GetTaskResponse, # type: ignore + type_=Task, # type: ignore object_=_response.json(), ), ) return HttpResponse(response=_response, data=_data) - if _response.status_code == 404: - raise NotFoundError( + if _response.status_code == 400: + raise BadRequestError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -64,8 +162,19 @@ def get( ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 401: + raise UnauthorizedError( + 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, @@ -80,6 +189,10 @@ def get( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) @@ -89,42 +202,151 @@ class AsyncRawTaskClient: def __init__(self, *, client_wrapper: AsyncClientWrapper): self._client_wrapper = client_wrapper - async def get( - self, task_id: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> AsyncHttpResponse[GetTaskResponse]: + async def list( + self, + *, + limit: typing.Optional[int] = None, + cursor: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncPager[Task, TaskPage]: """ - Gets a task by its ID + Parameters + ---------- + limit : typing.Optional[int] + Page size + + cursor : typing.Optional[str] + Opaque page cursor + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncPager[Task, TaskPage] + OK + """ + _response = await self._client_wrapper.httpx_client.request( + "tasks", + method="GET", + params={ + "limit": limit, + "cursor": cursor, + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _parsed_response = typing.cast( + TaskPage, + parse_obj_as( + type_=TaskPage, # type: ignore + object_=_response.json(), + ), + ) + _items = _parsed_response.items + _parsed_next = _parsed_response.next_cursor + _has_next = _parsed_next is not None and _parsed_next != "" + async def _get_next(): + return await self.list( + limit=limit, + cursor=_parsed_next, + request_options=request_options, + ) + + return AsyncPager(has_next=_has_next, items=_items, get_next=_get_next, response=_parsed_response) + if _response.status_code == 400: + raise BadRequestError( + 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 == 401: + raise UnauthorizedError( + 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(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise core_api_error_ApiError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.text + ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) + raise core_api_error_ApiError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response_json + ) + + async def get( + self, task_uuid: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> AsyncHttpResponse[Task]: + """ Parameters ---------- - task_id : str - Task ID + task_uuid : str + Task UUID request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - AsyncHttpResponse[GetTaskResponse] - Task + AsyncHttpResponse[Task] + OK """ _response = await self._client_wrapper.httpx_client.request( - f"tasks/{jsonable_encoder(task_id)}", + f"tasks/{jsonable_encoder(task_uuid)}", method="GET", request_options=request_options, ) try: if 200 <= _response.status_code < 300: _data = typing.cast( - GetTaskResponse, + Task, parse_obj_as( - type_=GetTaskResponse, # type: ignore + type_=Task, # type: ignore object_=_response.json(), ), ) return AsyncHttpResponse(response=_response, data=_data) - if _response.status_code == 404: - raise NotFoundError( + if _response.status_code == 400: + raise BadRequestError( + 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 == 401: + raise UnauthorizedError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -134,8 +356,8 @@ async def get( ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -150,6 +372,10 @@ async def get( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) diff --git a/src/zep_cloud/thread/__init__.py b/src/zep_cloud/thread/__init__.py index 4144d499..d917233f 100644 --- a/src/zep_cloud/thread/__init__.py +++ b/src/zep_cloud/thread/__init__.py @@ -2,6 +2,33 @@ # isort: skip_file -from . import message +import typing +from importlib import import_module + +if typing.TYPE_CHECKING: + from . import message +_dynamic_imports: typing.Dict[str, str] = {"message": ".message"} + + +def __getattr__(attr_name: str) -> typing.Any: + module_name = _dynamic_imports.get(attr_name) + if module_name is None: + raise AttributeError(f"No {attr_name} found in _dynamic_imports for module name -> {__name__}") + try: + module = import_module(module_name, __package__) + if module_name == f".{attr_name}": + return module + else: + return getattr(module, attr_name) + except ImportError as e: + raise ImportError(f"Failed to import {attr_name} from {module_name}: {e}") from e + except AttributeError as e: + raise AttributeError(f"Failed to get {attr_name} from {module_name}: {e}") from e + + +def __dir__(): + lazy_attrs = list(_dynamic_imports.keys()) + return sorted(lazy_attrs) + __all__ = ["message"] diff --git a/src/zep_cloud/thread/client.py b/src/zep_cloud/thread/client.py index e4a8add5..7c85bcb5 100644 --- a/src/zep_cloud/thread/client.py +++ b/src/zep_cloud/thread/client.py @@ -1,21 +1,27 @@ # This file was auto-generated by Fern from our API Definition. +from __future__ import annotations + import typing from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper +from ..core.pagination import AsyncPager, SyncPager from ..core.request_options import RequestOptions -from ..types.add_thread_messages_response import AddThreadMessagesResponse +from ..types.add_message import AddMessage +from ..types.add_messages_result import AddMessagesResult +from ..types.json_object import JsonObject +from ..types.json_object_page import JsonObjectPage from ..types.message import Message -from ..types.message_list_response import MessageListResponse -from ..types.role_type import RoleType -from ..types.success_response import SuccessResponse +from ..types.message_page import MessagePage from ..types.thread import Thread from ..types.thread_context_response import ThreadContextResponse -from ..types.thread_list_response import ThreadListResponse +from ..types.thread_delete_result import ThreadDeleteResult +from ..types.thread_page import ThreadPage from ..types.thread_summary import ThreadSummary -from .message.client import AsyncMessageClient, MessageClient from .raw_client import AsyncRawThreadClient, RawThreadClient +if typing.TYPE_CHECKING: + from .message.client import AsyncMessageClient, MessageClient # this is used as the default value for optional parameters OMIT = typing.cast(typing.Any, ...) @@ -23,7 +29,8 @@ class ThreadClient: def __init__(self, *, client_wrapper: SyncClientWrapper): self._raw_client = RawThreadClient(client_wrapper=client_wrapper) - self.message = MessageClient(client_wrapper=client_wrapper) + self._client_wrapper = client_wrapper + self._message: typing.Optional[MessageClient] = None @property def with_raw_response(self) -> RawThreadClient: @@ -36,39 +43,41 @@ def with_raw_response(self) -> RawThreadClient: """ return self._raw_client - def list_all( + def list( self, *, - page_number: typing.Optional[int] = None, - page_size: typing.Optional[int] = None, + limit: typing.Optional[int] = None, + cursor: typing.Optional[str] = None, order_by: typing.Optional[str] = None, - asc: typing.Optional[bool] = None, + order: typing.Optional[str] = None, + user_uuid: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> ThreadListResponse: + ) -> SyncPager[Thread, ThreadPage]: """ - Returns all threads. - Parameters ---------- - page_number : typing.Optional[int] - Page number for pagination, starting from 1 + limit : typing.Optional[int] + Page size - page_size : typing.Optional[int] - Number of threads to retrieve per page. + cursor : typing.Optional[str] + Opaque page cursor order_by : typing.Optional[str] - Field to order the results by: created_at, updated_at, user_id, thread_id. + Sort field - asc : typing.Optional[bool] - Order direction: true for ascending, false for descending. + order : typing.Optional[str] + asc or desc + + user_uuid : typing.Optional[str] + Filter by user UUID request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - ThreadListResponse - List of threads + SyncPager[Thread, ThreadPage] + OK Examples -------- @@ -77,31 +86,44 @@ def list_all( client = Zep( api_key="YOUR_API_KEY", ) - client.thread.list_all( - page_number=1, - page_size=1, + response = client.thread.list( + limit=1, + cursor="cursor", order_by="order_by", - asc=True, + order="order", + user_uuid="user_uuid", ) + for item in response: + yield item + # alternatively, you can paginate page-by-page + for page in response.iter_pages(): + yield page """ - _response = self._raw_client.list_all( - page_number=page_number, page_size=page_size, order_by=order_by, asc=asc, request_options=request_options + return self._raw_client.list( + limit=limit, + cursor=cursor, + order_by=order_by, + order=order, + user_uuid=user_uuid, + request_options=request_options, ) - return _response.data def create( - self, *, thread_id: str, user_id: str, request_options: typing.Optional[RequestOptions] = None + self, + *, + thread_id: typing.Optional[str] = OMIT, + user_uuid: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, ) -> Thread: """ - Start a new thread. - Parameters ---------- - thread_id : str - The unique identifier of the thread. + thread_id : typing.Optional[str] + + user_uuid : typing.Optional[str] - user_id : str - The unique identifier of the user associated with the thread + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -109,7 +131,7 @@ def create( Returns ------- Thread - The thread object. + Created Examples -------- @@ -118,62 +140,142 @@ def create( client = Zep( api_key="YOUR_API_KEY", ) - client.thread.create( - thread_id="thread_id", - user_id="user_id", - ) + client.thread.create() """ - _response = self._raw_client.create(thread_id=thread_id, user_id=user_id, request_options=request_options) + _response = self._raw_client.create( + thread_id=thread_id, user_uuid=user_uuid, idempotency_key=idempotency_key, request_options=request_options + ) return _response.data - def delete(self, thread_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> SuccessResponse: + def lookup( + self, + *, + graph_id: typing.Optional[str] = OMIT, + thread_id: typing.Optional[str] = OMIT, + user_id: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> Thread: + """ + Parameters + ---------- + graph_id : typing.Optional[str] + + thread_id : typing.Optional[str] + + user_id : typing.Optional[str] + + idempotency_key : typing.Optional[str] + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + Thread + OK + + Examples + -------- + from zep_cloud import Zep + + client = Zep( + api_key="YOUR_API_KEY", + ) + client.thread.lookup() """ - Deletes a thread. + _response = self._raw_client.lookup( + graph_id=graph_id, + thread_id=thread_id, + user_id=user_id, + idempotency_key=idempotency_key, + request_options=request_options, + ) + return _response.data + def get(self, thread_uuid: str, *, request_options: typing.Optional[RequestOptions] = None) -> Thread: + """ Parameters ---------- - thread_id : str - The ID of the thread for which memory should be deleted. + thread_uuid : str + Thread UUID request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - SuccessResponse + Thread OK Examples -------- from zep_cloud import Zep + client = Zep( + api_key="YOUR_API_KEY", + ) + client.thread.get( + thread_uuid="thread_uuid", + ) + """ + _response = self._raw_client.get(thread_uuid, request_options=request_options) + return _response.data + + def delete( + self, + thread_uuid: str, + *, + idempotency_key: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> ThreadDeleteResult: + """ + Parameters + ---------- + thread_uuid : str + Thread UUID + + idempotency_key : typing.Optional[str] + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + ThreadDeleteResult + Accepted + + Examples + -------- + from zep_cloud import Zep + client = Zep( api_key="YOUR_API_KEY", ) client.thread.delete( - thread_id="threadId", + thread_uuid="thread_uuid", ) """ - _response = self._raw_client.delete(thread_id, request_options=request_options) + _response = self._raw_client.delete( + thread_uuid, idempotency_key=idempotency_key, request_options=request_options + ) return _response.data - def get_user_context( + def get_context( self, - thread_id: str, + thread_uuid: str, *, - template_id: typing.Optional[str] = None, + template_uuid: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, ) -> ThreadContextResponse: """ - Returns most relevant context from the user graph (including memory from any/all past threads) based on the content of the past few messages of the given thread. - Parameters ---------- - thread_id : str - The ID of the current thread (for which context is being retrieved). + thread_uuid : str + Thread UUID - template_id : typing.Optional[str] - Optional template ID to use for custom context rendering. + template_uuid : typing.Optional[str] + Context template UUID request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -190,48 +292,42 @@ def get_user_context( client = Zep( api_key="YOUR_API_KEY", ) - client.thread.get_user_context( - thread_id="threadId", - template_id="template_id", + client.thread.get_context( + thread_uuid="thread_uuid", + template_uuid="template_uuid", ) """ - _response = self._raw_client.get_user_context( - thread_id, template_id=template_id, request_options=request_options + _response = self._raw_client.get_context( + thread_uuid, template_uuid=template_uuid, request_options=request_options ) return _response.data - def get( + def list_episodes( self, - thread_id: str, + thread_uuid: str, *, limit: typing.Optional[int] = None, - cursor: typing.Optional[int] = None, - lastn: typing.Optional[int] = None, + cursor: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> MessageListResponse: + ) -> SyncPager[JsonObject, JsonObjectPage]: """ - Returns messages for a thread. - Parameters ---------- - thread_id : str - Thread ID + thread_uuid : str + Thread UUID limit : typing.Optional[int] - Limit the number of results returned + Page size - cursor : typing.Optional[int] - Cursor for pagination - - lastn : typing.Optional[int] - Number of most recent messages to return (overrides limit and cursor) + cursor : typing.Optional[str] + Opaque page cursor request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - MessageListResponse + SyncPager[JsonObject, JsonObjectPage] OK Examples @@ -241,162 +337,132 @@ def get( client = Zep( api_key="YOUR_API_KEY", ) - client.thread.get( - thread_id="threadId", + response = client.thread.list_episodes( + thread_uuid="thread_uuid", limit=1, - cursor=1, - lastn=1, + cursor="cursor", ) + for item in response: + yield item + # alternatively, you can paginate page-by-page + for page in response.iter_pages(): + yield page """ - _response = self._raw_client.get( - thread_id, limit=limit, cursor=cursor, lastn=lastn, request_options=request_options - ) - return _response.data + return self._raw_client.list_episodes(thread_uuid, limit=limit, cursor=cursor, request_options=request_options) - def add_messages( + def list_messages( self, - thread_id: str, + thread_uuid: str, *, - messages: typing.Sequence[Message], - ignore_roles: typing.Optional[typing.Sequence[RoleType]] = OMIT, - return_context: typing.Optional[bool] = OMIT, - strict_ontology: typing.Optional[bool] = OMIT, + limit: typing.Optional[int] = None, + cursor: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> AddThreadMessagesResponse: + ) -> SyncPager[Message, MessagePage]: """ - Add messages to a thread. - Parameters ---------- - thread_id : str - The ID of the thread to which messages should be added. - - messages : typing.Sequence[Message] - A list of message objects, where each message contains a role and content. + thread_uuid : str + Thread UUID - ignore_roles : typing.Optional[typing.Sequence[RoleType]] - Optional list of role types to ignore when adding messages to graph memory. - The message itself will still be added, retained and used as context for messages - that are added to a user's graph. - - return_context : typing.Optional[bool] - Optionally return context block relevant to the most recent messages. + limit : typing.Optional[int] + Page size - strict_ontology : typing.Optional[bool] - When true, prevents extraction of generic Entity nodes that do not match the configured ontology. + cursor : typing.Optional[str] + Opaque page cursor request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - AddThreadMessagesResponse - An object, optionally containing user context retrieved for the last thread message + SyncPager[Message, MessagePage] + OK Examples -------- - from zep_cloud import Message, Zep + from zep_cloud import Zep client = Zep( api_key="YOUR_API_KEY", ) - client.thread.add_messages( - thread_id="threadId", - messages=[ - Message( - content="content", - role="norole", - ) - ], + response = client.thread.list_messages( + thread_uuid="thread_uuid", + limit=1, + cursor="cursor", ) + for item in response: + yield item + # alternatively, you can paginate page-by-page + for page in response.iter_pages(): + yield page """ - _response = self._raw_client.add_messages( - thread_id, - messages=messages, - ignore_roles=ignore_roles, - return_context=return_context, - strict_ontology=strict_ontology, - request_options=request_options, - ) - return _response.data + return self._raw_client.list_messages(thread_uuid, limit=limit, cursor=cursor, request_options=request_options) - def add_messages_batch( + def add_messages( self, - thread_id: str, + thread_uuid: str, *, - messages: typing.Sequence[Message], - ignore_roles: typing.Optional[typing.Sequence[RoleType]] = OMIT, + ignore_roles: typing.Optional[typing.Sequence[str]] = OMIT, + messages: typing.Optional[typing.Sequence[AddMessage]] = OMIT, return_context: typing.Optional[bool] = OMIT, strict_ontology: typing.Optional[bool] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> AddThreadMessagesResponse: + ) -> AddMessagesResult: """ - Deprecated. Use the [Batch API](/adding-batch-data) (`client.batch.*` with `type: "thread_message"`) instead. - - Adds messages to a thread in batch mode, processing messages concurrently. - Parameters ---------- - thread_id : str - The ID of the thread to which messages should be added. + thread_uuid : str + Thread UUID - messages : typing.Sequence[Message] - A list of message objects, where each message contains a role and content. + ignore_roles : typing.Optional[typing.Sequence[str]] - ignore_roles : typing.Optional[typing.Sequence[RoleType]] - Optional list of role types to ignore when adding messages to graph memory. - The message itself will still be added, retained and used as context for messages - that are added to a user's graph. + messages : typing.Optional[typing.Sequence[AddMessage]] return_context : typing.Optional[bool] - Optionally return context block relevant to the most recent messages. strict_ontology : typing.Optional[bool] - When true, prevents extraction of generic Entity nodes that do not match the configured ontology. + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - AddThreadMessagesResponse - An object, optionally containing user context retrieved for the last thread message + AddMessagesResult + Accepted Examples -------- - from zep_cloud import Message, Zep + from zep_cloud import Zep client = Zep( api_key="YOUR_API_KEY", ) - client.thread.add_messages_batch( - thread_id="threadId", - messages=[ - Message( - content="content", - role="norole", - ) - ], + client.thread.add_messages( + thread_uuid="thread_uuid", ) """ - _response = self._raw_client.add_messages_batch( - thread_id, - messages=messages, + _response = self._raw_client.add_messages( + thread_uuid, ignore_roles=ignore_roles, + messages=messages, return_context=return_context, strict_ontology=strict_ontology, + idempotency_key=idempotency_key, request_options=request_options, ) return _response.data - def get_summary(self, thread_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> ThreadSummary: + def get_summary( + self, thread_uuid: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> ThreadSummary: """ - Returns the incremental summary generated from messages in the thread. Returns 404 if no summary exists for the thread. - Parameters ---------- - thread_id : str - The thread ID. + thread_uuid : str + Thread UUID request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -414,17 +480,26 @@ def get_summary(self, thread_id: str, *, request_options: typing.Optional[Reques api_key="YOUR_API_KEY", ) client.thread.get_summary( - thread_id="threadId", + thread_uuid="thread_uuid", ) """ - _response = self._raw_client.get_summary(thread_id, request_options=request_options) + _response = self._raw_client.get_summary(thread_uuid, request_options=request_options) return _response.data + @property + def message(self): + if self._message is None: + from .message.client import MessageClient # noqa: E402 + + self._message = MessageClient(client_wrapper=self._client_wrapper) + return self._message + class AsyncThreadClient: def __init__(self, *, client_wrapper: AsyncClientWrapper): self._raw_client = AsyncRawThreadClient(client_wrapper=client_wrapper) - self.message = AsyncMessageClient(client_wrapper=client_wrapper) + self._client_wrapper = client_wrapper + self._message: typing.Optional[AsyncMessageClient] = None @property def with_raw_response(self) -> AsyncRawThreadClient: @@ -437,39 +512,41 @@ def with_raw_response(self) -> AsyncRawThreadClient: """ return self._raw_client - async def list_all( + async def list( self, *, - page_number: typing.Optional[int] = None, - page_size: typing.Optional[int] = None, + limit: typing.Optional[int] = None, + cursor: typing.Optional[str] = None, order_by: typing.Optional[str] = None, - asc: typing.Optional[bool] = None, + order: typing.Optional[str] = None, + user_uuid: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> ThreadListResponse: + ) -> AsyncPager[Thread, ThreadPage]: """ - Returns all threads. - Parameters ---------- - page_number : typing.Optional[int] - Page number for pagination, starting from 1 + limit : typing.Optional[int] + Page size - page_size : typing.Optional[int] - Number of threads to retrieve per page. + cursor : typing.Optional[str] + Opaque page cursor order_by : typing.Optional[str] - Field to order the results by: created_at, updated_at, user_id, thread_id. + Sort field - asc : typing.Optional[bool] - Order direction: true for ascending, false for descending. + order : typing.Optional[str] + asc or desc + + user_uuid : typing.Optional[str] + Filter by user UUID request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - ThreadListResponse - List of threads + AsyncPager[Thread, ThreadPage] + OK Examples -------- @@ -483,34 +560,98 @@ async def list_all( async def main() -> None: - await client.thread.list_all( - page_number=1, - page_size=1, + response = await client.thread.list( + limit=1, + cursor="cursor", order_by="order_by", - asc=True, + order="order", + user_uuid="user_uuid", ) + async for item in response: + yield item + + # alternatively, you can paginate page-by-page + async for page in response.iter_pages(): + yield page asyncio.run(main()) """ - _response = await self._raw_client.list_all( - page_number=page_number, page_size=page_size, order_by=order_by, asc=asc, request_options=request_options + return await self._raw_client.list( + limit=limit, + cursor=cursor, + order_by=order_by, + order=order, + user_uuid=user_uuid, + request_options=request_options, ) - return _response.data async def create( - self, *, thread_id: str, user_id: str, request_options: typing.Optional[RequestOptions] = None + self, + *, + thread_id: typing.Optional[str] = OMIT, + user_uuid: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, ) -> Thread: """ - Start a new thread. + Parameters + ---------- + thread_id : typing.Optional[str] + + user_uuid : typing.Optional[str] + + idempotency_key : typing.Optional[str] + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + Thread + Created + + Examples + -------- + import asyncio + + from zep_cloud import AsyncZep + + client = AsyncZep( + api_key="YOUR_API_KEY", + ) + + + async def main() -> None: + await client.thread.create() + + + asyncio.run(main()) + """ + _response = await self._raw_client.create( + thread_id=thread_id, user_uuid=user_uuid, idempotency_key=idempotency_key, request_options=request_options + ) + return _response.data + async def lookup( + self, + *, + graph_id: typing.Optional[str] = OMIT, + thread_id: typing.Optional[str] = OMIT, + user_id: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> Thread: + """ Parameters ---------- - thread_id : str - The unique identifier of the thread. + graph_id : typing.Optional[str] - user_id : str - The unique identifier of the user associated with the thread + thread_id : typing.Optional[str] + + user_id : typing.Optional[str] + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -518,7 +659,7 @@ async def create( Returns ------- Thread - The thread object. + OK Examples -------- @@ -532,35 +673,79 @@ async def create( async def main() -> None: - await client.thread.create( - thread_id="thread_id", - user_id="user_id", + await client.thread.lookup() + + + asyncio.run(main()) + """ + _response = await self._raw_client.lookup( + graph_id=graph_id, + thread_id=thread_id, + user_id=user_id, + idempotency_key=idempotency_key, + request_options=request_options, + ) + return _response.data + + async def get(self, thread_uuid: str, *, request_options: typing.Optional[RequestOptions] = None) -> Thread: + """ + Parameters + ---------- + thread_uuid : str + Thread UUID + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + Thread + OK + + Examples + -------- + import asyncio + + from zep_cloud import AsyncZep + + client = AsyncZep( + api_key="YOUR_API_KEY", + ) + + + async def main() -> None: + await client.thread.get( + thread_uuid="thread_uuid", ) asyncio.run(main()) """ - _response = await self._raw_client.create(thread_id=thread_id, user_id=user_id, request_options=request_options) + _response = await self._raw_client.get(thread_uuid, request_options=request_options) return _response.data async def delete( - self, thread_id: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> SuccessResponse: + self, + thread_uuid: str, + *, + idempotency_key: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> ThreadDeleteResult: """ - Deletes a thread. - Parameters ---------- - thread_id : str - The ID of the thread for which memory should be deleted. + thread_uuid : str + Thread UUID + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - SuccessResponse - OK + ThreadDeleteResult + Accepted Examples -------- @@ -575,32 +760,32 @@ async def delete( async def main() -> None: await client.thread.delete( - thread_id="threadId", + thread_uuid="thread_uuid", ) asyncio.run(main()) """ - _response = await self._raw_client.delete(thread_id, request_options=request_options) + _response = await self._raw_client.delete( + thread_uuid, idempotency_key=idempotency_key, request_options=request_options + ) return _response.data - async def get_user_context( + async def get_context( self, - thread_id: str, + thread_uuid: str, *, - template_id: typing.Optional[str] = None, + template_uuid: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, ) -> ThreadContextResponse: """ - Returns most relevant context from the user graph (including memory from any/all past threads) based on the content of the past few messages of the given thread. - Parameters ---------- - thread_id : str - The ID of the current thread (for which context is being retrieved). + thread_uuid : str + Thread UUID - template_id : typing.Optional[str] - Optional template ID to use for custom context rendering. + template_uuid : typing.Optional[str] + Context template UUID request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -622,51 +807,45 @@ async def get_user_context( async def main() -> None: - await client.thread.get_user_context( - thread_id="threadId", - template_id="template_id", + await client.thread.get_context( + thread_uuid="thread_uuid", + template_uuid="template_uuid", ) asyncio.run(main()) """ - _response = await self._raw_client.get_user_context( - thread_id, template_id=template_id, request_options=request_options + _response = await self._raw_client.get_context( + thread_uuid, template_uuid=template_uuid, request_options=request_options ) return _response.data - async def get( + async def list_episodes( self, - thread_id: str, + thread_uuid: str, *, limit: typing.Optional[int] = None, - cursor: typing.Optional[int] = None, - lastn: typing.Optional[int] = None, + cursor: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> MessageListResponse: + ) -> AsyncPager[JsonObject, JsonObjectPage]: """ - Returns messages for a thread. - Parameters ---------- - thread_id : str - Thread ID + thread_uuid : str + Thread UUID limit : typing.Optional[int] - Limit the number of results returned + Page size - cursor : typing.Optional[int] - Cursor for pagination - - lastn : typing.Optional[int] - Number of most recent messages to return (overrides limit and cursor) + cursor : typing.Optional[str] + Opaque page cursor request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - MessageListResponse + AsyncPager[JsonObject, JsonObjectPage] OK Examples @@ -681,66 +860,58 @@ async def get( async def main() -> None: - await client.thread.get( - thread_id="threadId", + response = await client.thread.list_episodes( + thread_uuid="thread_uuid", limit=1, - cursor=1, - lastn=1, + cursor="cursor", ) + async for item in response: + yield item + + # alternatively, you can paginate page-by-page + async for page in response.iter_pages(): + yield page asyncio.run(main()) """ - _response = await self._raw_client.get( - thread_id, limit=limit, cursor=cursor, lastn=lastn, request_options=request_options + return await self._raw_client.list_episodes( + thread_uuid, limit=limit, cursor=cursor, request_options=request_options ) - return _response.data - async def add_messages( + async def list_messages( self, - thread_id: str, + thread_uuid: str, *, - messages: typing.Sequence[Message], - ignore_roles: typing.Optional[typing.Sequence[RoleType]] = OMIT, - return_context: typing.Optional[bool] = OMIT, - strict_ontology: typing.Optional[bool] = OMIT, + limit: typing.Optional[int] = None, + cursor: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> AddThreadMessagesResponse: + ) -> AsyncPager[Message, MessagePage]: """ - Add messages to a thread. - Parameters ---------- - thread_id : str - The ID of the thread to which messages should be added. + thread_uuid : str + Thread UUID - messages : typing.Sequence[Message] - A list of message objects, where each message contains a role and content. - - ignore_roles : typing.Optional[typing.Sequence[RoleType]] - Optional list of role types to ignore when adding messages to graph memory. - The message itself will still be added, retained and used as context for messages - that are added to a user's graph. - - return_context : typing.Optional[bool] - Optionally return context block relevant to the most recent messages. + limit : typing.Optional[int] + Page size - strict_ontology : typing.Optional[bool] - When true, prevents extraction of generic Entity nodes that do not match the configured ontology. + cursor : typing.Optional[str] + Opaque page cursor request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - AddThreadMessagesResponse - An object, optionally containing user context retrieved for the last thread message + AsyncPager[Message, MessagePage] + OK Examples -------- import asyncio - from zep_cloud import AsyncZep, Message + from zep_cloud import AsyncZep client = AsyncZep( api_key="YOUR_API_KEY", @@ -748,76 +919,65 @@ async def add_messages( async def main() -> None: - await client.thread.add_messages( - thread_id="threadId", - messages=[ - Message( - content="content", - role="norole", - ) - ], + response = await client.thread.list_messages( + thread_uuid="thread_uuid", + limit=1, + cursor="cursor", ) + async for item in response: + yield item + + # alternatively, you can paginate page-by-page + async for page in response.iter_pages(): + yield page asyncio.run(main()) """ - _response = await self._raw_client.add_messages( - thread_id, - messages=messages, - ignore_roles=ignore_roles, - return_context=return_context, - strict_ontology=strict_ontology, - request_options=request_options, + return await self._raw_client.list_messages( + thread_uuid, limit=limit, cursor=cursor, request_options=request_options ) - return _response.data - async def add_messages_batch( + async def add_messages( self, - thread_id: str, + thread_uuid: str, *, - messages: typing.Sequence[Message], - ignore_roles: typing.Optional[typing.Sequence[RoleType]] = OMIT, + ignore_roles: typing.Optional[typing.Sequence[str]] = OMIT, + messages: typing.Optional[typing.Sequence[AddMessage]] = OMIT, return_context: typing.Optional[bool] = OMIT, strict_ontology: typing.Optional[bool] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> AddThreadMessagesResponse: + ) -> AddMessagesResult: """ - Deprecated. Use the [Batch API](/adding-batch-data) (`client.batch.*` with `type: "thread_message"`) instead. - - Adds messages to a thread in batch mode, processing messages concurrently. - Parameters ---------- - thread_id : str - The ID of the thread to which messages should be added. + thread_uuid : str + Thread UUID - messages : typing.Sequence[Message] - A list of message objects, where each message contains a role and content. + ignore_roles : typing.Optional[typing.Sequence[str]] - ignore_roles : typing.Optional[typing.Sequence[RoleType]] - Optional list of role types to ignore when adding messages to graph memory. - The message itself will still be added, retained and used as context for messages - that are added to a user's graph. + messages : typing.Optional[typing.Sequence[AddMessage]] return_context : typing.Optional[bool] - Optionally return context block relevant to the most recent messages. strict_ontology : typing.Optional[bool] - When true, prevents extraction of generic Entity nodes that do not match the configured ontology. + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - AddThreadMessagesResponse - An object, optionally containing user context retrieved for the last thread message + AddMessagesResult + Accepted Examples -------- import asyncio - from zep_cloud import AsyncZep, Message + from zep_cloud import AsyncZep client = AsyncZep( api_key="YOUR_API_KEY", @@ -825,39 +985,32 @@ async def add_messages_batch( async def main() -> None: - await client.thread.add_messages_batch( - thread_id="threadId", - messages=[ - Message( - content="content", - role="norole", - ) - ], + await client.thread.add_messages( + thread_uuid="thread_uuid", ) asyncio.run(main()) """ - _response = await self._raw_client.add_messages_batch( - thread_id, - messages=messages, + _response = await self._raw_client.add_messages( + thread_uuid, ignore_roles=ignore_roles, + messages=messages, return_context=return_context, strict_ontology=strict_ontology, + idempotency_key=idempotency_key, request_options=request_options, ) return _response.data async def get_summary( - self, thread_id: str, *, request_options: typing.Optional[RequestOptions] = None + self, thread_uuid: str, *, request_options: typing.Optional[RequestOptions] = None ) -> ThreadSummary: """ - Returns the incremental summary generated from messages in the thread. Returns 404 if no summary exists for the thread. - Parameters ---------- - thread_id : str - The thread ID. + thread_uuid : str + Thread UUID request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -880,11 +1033,19 @@ async def get_summary( async def main() -> None: await client.thread.get_summary( - thread_id="threadId", + thread_uuid="thread_uuid", ) asyncio.run(main()) """ - _response = await self._raw_client.get_summary(thread_id, request_options=request_options) + _response = await self._raw_client.get_summary(thread_uuid, request_options=request_options) return _response.data + + @property + def message(self): + if self._message is None: + from .message.client import AsyncMessageClient # noqa: E402 + + self._message = AsyncMessageClient(client_wrapper=self._client_wrapper) + return self._message diff --git a/src/zep_cloud/thread/message/client.py b/src/zep_cloud/thread/message/client.py index 0c8adcba..6006e6c0 100644 --- a/src/zep_cloud/thread/message/client.py +++ b/src/zep_cloud/thread/message/client.py @@ -26,22 +26,62 @@ def with_raw_response(self) -> RawMessageClient: """ return self._raw_client + def get( + self, thread_uuid: str, message_uuid: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> Message: + """ + Parameters + ---------- + thread_uuid : str + Thread UUID + + message_uuid : str + Message UUID + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + Message + OK + + Examples + -------- + from zep_cloud import Zep + + client = Zep( + api_key="YOUR_API_KEY", + ) + client.thread.message.get( + thread_uuid="thread_uuid", + message_uuid="message_uuid", + ) + """ + _response = self._raw_client.get(thread_uuid, message_uuid, request_options=request_options) + return _response.data + def update( self, + thread_uuid: str, message_uuid: str, *, - metadata: typing.Dict[str, typing.Optional[typing.Any]], + metadata: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, ) -> Message: """ - Updates a message. - Parameters ---------- + thread_uuid : str + Thread UUID + message_uuid : str - The UUID of the message. + Message UUID - metadata : typing.Dict[str, typing.Optional[typing.Any]] + metadata : typing.Optional[typing.Dict[str, typing.Any]] + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -49,7 +89,7 @@ def update( Returns ------- Message - The updated message. + OK Examples -------- @@ -59,11 +99,17 @@ def update( api_key="YOUR_API_KEY", ) client.thread.message.update( - message_uuid="messageUUID", - metadata={"key": "value"}, + thread_uuid="thread_uuid", + message_uuid="message_uuid", ) """ - _response = self._raw_client.update(message_uuid, metadata=metadata, request_options=request_options) + _response = self._raw_client.update( + thread_uuid, + message_uuid, + metadata=metadata, + idempotency_key=idempotency_key, + request_options=request_options, + ) return _response.data @@ -82,22 +128,70 @@ def with_raw_response(self) -> AsyncRawMessageClient: """ return self._raw_client + async def get( + self, thread_uuid: str, message_uuid: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> Message: + """ + Parameters + ---------- + thread_uuid : str + Thread UUID + + message_uuid : str + Message UUID + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + Message + OK + + Examples + -------- + import asyncio + + from zep_cloud import AsyncZep + + client = AsyncZep( + api_key="YOUR_API_KEY", + ) + + + async def main() -> None: + await client.thread.message.get( + thread_uuid="thread_uuid", + message_uuid="message_uuid", + ) + + + asyncio.run(main()) + """ + _response = await self._raw_client.get(thread_uuid, message_uuid, request_options=request_options) + return _response.data + async def update( self, + thread_uuid: str, message_uuid: str, *, - metadata: typing.Dict[str, typing.Optional[typing.Any]], + metadata: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, ) -> Message: """ - Updates a message. - Parameters ---------- + thread_uuid : str + Thread UUID + message_uuid : str - The UUID of the message. + Message UUID - metadata : typing.Dict[str, typing.Optional[typing.Any]] + metadata : typing.Optional[typing.Dict[str, typing.Any]] + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -105,7 +199,7 @@ async def update( Returns ------- Message - The updated message. + OK Examples -------- @@ -120,12 +214,18 @@ async def update( async def main() -> None: await client.thread.message.update( - message_uuid="messageUUID", - metadata={"key": "value"}, + thread_uuid="thread_uuid", + message_uuid="message_uuid", ) asyncio.run(main()) """ - _response = await self._raw_client.update(message_uuid, metadata=metadata, request_options=request_options) + _response = await self._raw_client.update( + thread_uuid, + message_uuid, + metadata=metadata, + idempotency_key=idempotency_key, + request_options=request_options, + ) return _response.data diff --git a/src/zep_cloud/thread/message/raw_client.py b/src/zep_cloud/thread/message/raw_client.py index 20029489..97053fb5 100644 --- a/src/zep_cloud/thread/message/raw_client.py +++ b/src/zep_cloud/thread/message/raw_client.py @@ -7,12 +7,15 @@ from ...core.client_wrapper import AsyncClientWrapper, SyncClientWrapper from ...core.http_response import AsyncHttpResponse, HttpResponse from ...core.jsonable_encoder import jsonable_encoder +from ...core.parse_error import ParsingError from ...core.pydantic_utilities import parse_obj_as from ...core.request_options import RequestOptions -from ...errors.internal_server_error import InternalServerError +from ...errors.bad_request_error import BadRequestError from ...errors.not_found_error import NotFoundError +from ...errors.unauthorized_error import UnauthorizedError from ...types.api_error import ApiError as types_api_error_ApiError from ...types.message import Message +from pydantic import ValidationError # this is used as the default value for optional parameters OMIT = typing.cast(typing.Any, ...) @@ -22,22 +25,108 @@ class RawMessageClient: def __init__(self, *, client_wrapper: SyncClientWrapper): self._client_wrapper = client_wrapper + def get( + self, thread_uuid: str, message_uuid: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> HttpResponse[Message]: + """ + Parameters + ---------- + thread_uuid : str + Thread UUID + + message_uuid : str + Message UUID + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[Message] + OK + """ + _response = self._client_wrapper.httpx_client.request( + f"threads/{jsonable_encoder(thread_uuid)}/messages/{jsonable_encoder(message_uuid)}", + method="GET", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + Message, + parse_obj_as( + type_=Message, # 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( + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + 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(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise core_api_error_ApiError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.text + ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) + raise core_api_error_ApiError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response_json + ) + def update( self, + thread_uuid: str, message_uuid: str, *, - metadata: typing.Dict[str, typing.Optional[typing.Any]], + metadata: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, ) -> HttpResponse[Message]: """ - Updates a message. - Parameters ---------- + thread_uuid : str + Thread UUID + message_uuid : str - The UUID of the message. + Message UUID - metadata : typing.Dict[str, typing.Optional[typing.Any]] + metadata : typing.Optional[typing.Dict[str, typing.Any]] + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -45,16 +134,17 @@ def update( Returns ------- HttpResponse[Message] - The updated message. + OK """ _response = self._client_wrapper.httpx_client.request( - f"messages/{jsonable_encoder(message_uuid)}", + f"threads/{jsonable_encoder(thread_uuid)}/messages/{jsonable_encoder(message_uuid)}", method="PATCH", json={ "metadata": metadata, }, headers={ "content-type": "application/json", + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, }, request_options=request_options, omit=OMIT, @@ -69,8 +159,19 @@ def update( ), ) return HttpResponse(response=_response, data=_data) - if _response.status_code == 404: - raise NotFoundError( + if _response.status_code == 400: + raise BadRequestError( + 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 == 401: + raise UnauthorizedError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -80,8 +181,8 @@ def update( ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -96,6 +197,10 @@ def update( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) @@ -105,22 +210,108 @@ class AsyncRawMessageClient: def __init__(self, *, client_wrapper: AsyncClientWrapper): self._client_wrapper = client_wrapper + async def get( + self, thread_uuid: str, message_uuid: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> AsyncHttpResponse[Message]: + """ + Parameters + ---------- + thread_uuid : str + Thread UUID + + message_uuid : str + Message UUID + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[Message] + OK + """ + _response = await self._client_wrapper.httpx_client.request( + f"threads/{jsonable_encoder(thread_uuid)}/messages/{jsonable_encoder(message_uuid)}", + method="GET", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + Message, + parse_obj_as( + type_=Message, # 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( + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + 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(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise core_api_error_ApiError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.text + ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) + raise core_api_error_ApiError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response_json + ) + async def update( self, + thread_uuid: str, message_uuid: str, *, - metadata: typing.Dict[str, typing.Optional[typing.Any]], + metadata: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, ) -> AsyncHttpResponse[Message]: """ - Updates a message. - Parameters ---------- + thread_uuid : str + Thread UUID + message_uuid : str - The UUID of the message. + Message UUID - metadata : typing.Dict[str, typing.Optional[typing.Any]] + metadata : typing.Optional[typing.Dict[str, typing.Any]] + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -128,16 +319,17 @@ async def update( Returns ------- AsyncHttpResponse[Message] - The updated message. + OK """ _response = await self._client_wrapper.httpx_client.request( - f"messages/{jsonable_encoder(message_uuid)}", + f"threads/{jsonable_encoder(thread_uuid)}/messages/{jsonable_encoder(message_uuid)}", method="PATCH", json={ "metadata": metadata, }, headers={ "content-type": "application/json", + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, }, request_options=request_options, omit=OMIT, @@ -152,8 +344,19 @@ async def update( ), ) return AsyncHttpResponse(response=_response, data=_data) - if _response.status_code == 404: - raise NotFoundError( + if _response.status_code == 400: + raise BadRequestError( + 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 == 401: + raise UnauthorizedError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -163,8 +366,8 @@ async def update( ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -179,6 +382,10 @@ async def update( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) diff --git a/src/zep_cloud/thread/raw_client.py b/src/zep_cloud/thread/raw_client.py index 94237e62..a7603f39 100644 --- a/src/zep_cloud/thread/raw_client.py +++ b/src/zep_cloud/thread/raw_client.py @@ -7,23 +7,27 @@ from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper from ..core.http_response import AsyncHttpResponse, HttpResponse from ..core.jsonable_encoder import jsonable_encoder +from ..core.pagination import AsyncPager, SyncPager +from ..core.parse_error import ParsingError 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 from ..errors.not_found_error import NotFoundError -from ..types.add_thread_messages_response import AddThreadMessagesResponse +from ..errors.unauthorized_error import UnauthorizedError +from ..types.add_message import AddMessage +from ..types.add_messages_result import AddMessagesResult from ..types.api_error import ApiError as types_api_error_ApiError +from ..types.json_object import JsonObject +from ..types.json_object_page import JsonObjectPage from ..types.message import Message -from ..types.message_list_response import MessageListResponse -from ..types.role_type import RoleType -from ..types.success_response import SuccessResponse +from ..types.message_page import MessagePage from ..types.thread import Thread from ..types.thread_context_response import ThreadContextResponse -from ..types.thread_list_response import ThreadListResponse +from ..types.thread_delete_result import ThreadDeleteResult +from ..types.thread_page import ThreadPage from ..types.thread_summary import ThreadSummary +from pydantic import ValidationError # this is used as the default value for optional parameters OMIT = typing.cast(typing.Any, ...) @@ -33,74 +37,99 @@ class RawThreadClient: def __init__(self, *, client_wrapper: SyncClientWrapper): self._client_wrapper = client_wrapper - def list_all( + def list( self, *, - page_number: typing.Optional[int] = None, - page_size: typing.Optional[int] = None, + limit: typing.Optional[int] = None, + cursor: typing.Optional[str] = None, order_by: typing.Optional[str] = None, - asc: typing.Optional[bool] = None, + order: typing.Optional[str] = None, + user_uuid: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> HttpResponse[ThreadListResponse]: + ) -> SyncPager[Thread, ThreadPage]: """ - Returns all threads. - Parameters ---------- - page_number : typing.Optional[int] - Page number for pagination, starting from 1 + limit : typing.Optional[int] + Page size - page_size : typing.Optional[int] - Number of threads to retrieve per page. + cursor : typing.Optional[str] + Opaque page cursor order_by : typing.Optional[str] - Field to order the results by: created_at, updated_at, user_id, thread_id. + Sort field + + order : typing.Optional[str] + asc or desc - asc : typing.Optional[bool] - Order direction: true for ascending, false for descending. + user_uuid : typing.Optional[str] + Filter by user UUID request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - HttpResponse[ThreadListResponse] - List of threads + SyncPager[Thread, ThreadPage] + OK """ _response = self._client_wrapper.httpx_client.request( "threads", method="GET", params={ - "page_number": page_number, - "page_size": page_size, + "limit": limit, + "cursor": cursor, "order_by": order_by, - "asc": asc, + "order": order, + "user_uuid": user_uuid, }, request_options=request_options, ) try: if 200 <= _response.status_code < 300: - _data = typing.cast( - ThreadListResponse, + _parsed_response = typing.cast( + ThreadPage, parse_obj_as( - type_=ThreadListResponse, # type: ignore + type_=ThreadPage, # type: ignore object_=_response.json(), ), ) - return HttpResponse(response=_response, data=_data) + _items = _parsed_response.items + _parsed_next = _parsed_response.next_cursor + _has_next = _parsed_next is not None and _parsed_next != "" + _get_next = lambda: self.list( + limit=limit, + cursor=_parsed_next, + order_by=order_by, + order=order, + user_uuid=user_uuid, + request_options=request_options, + ) + return SyncPager(has_next=_has_next, items=_items, get_next=_get_next, response=_parsed_response) if _response.status_code == 400: raise BadRequestError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore object_=_response.json(), ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -115,23 +144,30 @@ def list_all( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) def create( - self, *, thread_id: str, user_id: str, request_options: typing.Optional[RequestOptions] = None + self, + *, + thread_id: typing.Optional[str] = OMIT, + user_uuid: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, ) -> HttpResponse[Thread]: """ - Start a new thread. - Parameters ---------- - thread_id : str - The unique identifier of the thread. + thread_id : typing.Optional[str] + + user_uuid : typing.Optional[str] - user_id : str - The unique identifier of the user associated with the thread + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -139,17 +175,18 @@ def create( Returns ------- HttpResponse[Thread] - The thread object. + Created """ _response = self._client_wrapper.httpx_client.request( "threads", method="POST", json={ "thread_id": thread_id, - "user_id": user_id, + "user_uuid": user_uuid, }, headers={ "content-type": "application/json", + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, }, request_options=request_options, omit=OMIT, @@ -168,15 +205,26 @@ def create( raise BadRequestError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore object_=_response.json(), ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 401: + raise UnauthorizedError( + 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, @@ -191,44 +239,165 @@ def create( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - def delete( - self, thread_id: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> HttpResponse[SuccessResponse]: + def lookup( + self, + *, + graph_id: typing.Optional[str] = OMIT, + thread_id: typing.Optional[str] = OMIT, + user_id: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[Thread]: """ - Deletes a thread. + Parameters + ---------- + graph_id : typing.Optional[str] + + thread_id : typing.Optional[str] + + user_id : typing.Optional[str] + idempotency_key : typing.Optional[str] + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[Thread] + OK + """ + _response = self._client_wrapper.httpx_client.request( + "threads/lookup", + method="POST", + json={ + "graph_id": graph_id, + "thread_id": thread_id, + "user_id": user_id, + }, + headers={ + "content-type": "application/json", + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + Thread, + parse_obj_as( + type_=Thread, # 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( + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + 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(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise core_api_error_ApiError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.text + ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) + raise core_api_error_ApiError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response_json + ) + + def get(self, thread_uuid: str, *, request_options: typing.Optional[RequestOptions] = None) -> HttpResponse[Thread]: + """ Parameters ---------- - thread_id : str - The ID of the thread for which memory should be deleted. + thread_uuid : str + Thread UUID request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - HttpResponse[SuccessResponse] + HttpResponse[Thread] OK """ _response = self._client_wrapper.httpx_client.request( - f"threads/{jsonable_encoder(thread_id)}", - method="DELETE", + f"threads/{jsonable_encoder(thread_uuid)}", + method="GET", request_options=request_options, ) try: if 200 <= _response.status_code < 300: _data = typing.cast( - SuccessResponse, + Thread, parse_obj_as( - type_=SuccessResponse, # type: ignore + type_=Thread, # 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( + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + 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), @@ -240,8 +409,84 @@ def delete( ), ), ) - if _response.status_code == 500: - raise InternalServerError( + _response_json = _response.json() + except JSONDecodeError: + raise core_api_error_ApiError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.text + ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) + raise core_api_error_ApiError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response_json + ) + + def delete( + self, + thread_uuid: str, + *, + idempotency_key: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[ThreadDeleteResult]: + """ + Parameters + ---------- + thread_uuid : str + Thread UUID + + idempotency_key : typing.Optional[str] + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[ThreadDeleteResult] + Accepted + """ + _response = self._client_wrapper.httpx_client.request( + f"threads/{jsonable_encoder(thread_uuid)}", + method="DELETE", + headers={ + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + ThreadDeleteResult, + parse_obj_as( + type_=ThreadDeleteResult, # 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( + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + 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, @@ -256,27 +501,29 @@ def delete( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - def get_user_context( + def get_context( self, - thread_id: str, + thread_uuid: str, *, - template_id: typing.Optional[str] = None, + template_uuid: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, ) -> HttpResponse[ThreadContextResponse]: """ - Returns most relevant context from the user graph (including memory from any/all past threads) based on the content of the past few messages of the given thread. - Parameters ---------- - thread_id : str - The ID of the current thread (for which context is being retrieved). + thread_uuid : str + Thread UUID - template_id : typing.Optional[str] - Optional template ID to use for custom context rendering. + template_uuid : typing.Optional[str] + Context template UUID request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -287,10 +534,10 @@ def get_user_context( OK """ _response = self._client_wrapper.httpx_client.request( - f"threads/{jsonable_encoder(thread_id)}/context", + f"threads/{jsonable_encoder(thread_uuid)}/context", method="GET", params={ - "template_id": template_id, + "template_uuid": template_uuid, }, request_options=request_options, ) @@ -304,8 +551,8 @@ def get_user_context( ), ) return HttpResponse(response=_response, data=_data) - if _response.status_code == 404: - raise NotFoundError( + if _response.status_code == 400: + raise BadRequestError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -315,8 +562,19 @@ def get_user_context( ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 401: + raise UnauthorizedError( + 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, @@ -331,64 +589,92 @@ def get_user_context( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - def get( + def list_episodes( self, - thread_id: str, + thread_uuid: str, *, limit: typing.Optional[int] = None, - cursor: typing.Optional[int] = None, - lastn: typing.Optional[int] = None, + cursor: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> HttpResponse[MessageListResponse]: + ) -> SyncPager[JsonObject, JsonObjectPage]: """ - Returns messages for a thread. - Parameters ---------- - thread_id : str - Thread ID + thread_uuid : str + Thread UUID limit : typing.Optional[int] - Limit the number of results returned - - cursor : typing.Optional[int] - Cursor for pagination + Page size - lastn : typing.Optional[int] - Number of most recent messages to return (overrides limit and cursor) + cursor : typing.Optional[str] + Opaque page cursor request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - HttpResponse[MessageListResponse] + SyncPager[JsonObject, JsonObjectPage] OK """ _response = self._client_wrapper.httpx_client.request( - f"threads/{jsonable_encoder(thread_id)}/messages", + f"threads/{jsonable_encoder(thread_uuid)}/episodes", method="GET", params={ "limit": limit, "cursor": cursor, - "lastn": lastn, }, request_options=request_options, ) try: if 200 <= _response.status_code < 300: - _data = typing.cast( - MessageListResponse, + _parsed_response = typing.cast( + JsonObjectPage, parse_obj_as( - type_=MessageListResponse, # type: ignore + type_=JsonObjectPage, # type: ignore object_=_response.json(), ), ) - return HttpResponse(response=_response, data=_data) + _items = _parsed_response.items + _parsed_next = _parsed_response.next_cursor + _has_next = _parsed_next is not None and _parsed_next != "" + _get_next = lambda: self.list_episodes( + thread_uuid, + limit=limit, + cursor=_parsed_next, + request_options=request_options, + ) + return SyncPager(has_next=_has_next, items=_items, get_next=_get_next, response=_parsed_response) + if _response.status_code == 400: + raise BadRequestError( + 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 == 401: + raise UnauthorizedError( + 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), @@ -400,8 +686,99 @@ def get( ), ), ) - if _response.status_code == 500: - raise InternalServerError( + _response_json = _response.json() + except JSONDecodeError: + raise core_api_error_ApiError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.text + ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) + raise core_api_error_ApiError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response_json + ) + + def list_messages( + self, + thread_uuid: str, + *, + limit: typing.Optional[int] = None, + cursor: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> SyncPager[Message, MessagePage]: + """ + Parameters + ---------- + thread_uuid : str + Thread UUID + + limit : typing.Optional[int] + Page size + + cursor : typing.Optional[str] + Opaque page cursor + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + SyncPager[Message, MessagePage] + OK + """ + _response = self._client_wrapper.httpx_client.request( + f"threads/{jsonable_encoder(thread_uuid)}/messages", + method="GET", + params={ + "limit": limit, + "cursor": cursor, + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _parsed_response = typing.cast( + MessagePage, + parse_obj_as( + type_=MessagePage, # type: ignore + object_=_response.json(), + ), + ) + _items = _parsed_response.items + _parsed_next = _parsed_response.next_cursor + _has_next = _parsed_next is not None and _parsed_next != "" + _get_next = lambda: self.list_messages( + thread_uuid, + limit=limit, + cursor=_parsed_next, + request_options=request_options, + ) + return SyncPager(has_next=_has_next, items=_items, get_next=_get_next, response=_parsed_response) + if _response.status_code == 400: + raise BadRequestError( + 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 == 401: + raise UnauthorizedError( + 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, @@ -416,76 +793,101 @@ def get( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) def add_messages( self, - thread_id: str, + thread_uuid: str, *, - messages: typing.Sequence[Message], - ignore_roles: typing.Optional[typing.Sequence[RoleType]] = OMIT, + ignore_roles: typing.Optional[typing.Sequence[str]] = OMIT, + messages: typing.Optional[typing.Sequence[AddMessage]] = OMIT, return_context: typing.Optional[bool] = OMIT, strict_ontology: typing.Optional[bool] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> HttpResponse[AddThreadMessagesResponse]: + ) -> HttpResponse[AddMessagesResult]: """ - Add messages to a thread. - Parameters ---------- - thread_id : str - The ID of the thread to which messages should be added. + thread_uuid : str + Thread UUID - messages : typing.Sequence[Message] - A list of message objects, where each message contains a role and content. + ignore_roles : typing.Optional[typing.Sequence[str]] - ignore_roles : typing.Optional[typing.Sequence[RoleType]] - Optional list of role types to ignore when adding messages to graph memory. - The message itself will still be added, retained and used as context for messages - that are added to a user's graph. + messages : typing.Optional[typing.Sequence[AddMessage]] return_context : typing.Optional[bool] - Optionally return context block relevant to the most recent messages. strict_ontology : typing.Optional[bool] - When true, prevents extraction of generic Entity nodes that do not match the configured ontology. + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - HttpResponse[AddThreadMessagesResponse] - An object, optionally containing user context retrieved for the last thread message + HttpResponse[AddMessagesResult] + Accepted """ _response = self._client_wrapper.httpx_client.request( - f"threads/{jsonable_encoder(thread_id)}/messages", + f"threads/{jsonable_encoder(thread_uuid)}/messages", method="POST", json={ "ignore_roles": ignore_roles, "messages": convert_and_respect_annotation_metadata( - object_=messages, annotation=typing.Sequence[Message], direction="write" + object_=messages, annotation=typing.Sequence[AddMessage], direction="write" ), "return_context": return_context, "strict_ontology": strict_ontology, }, + headers={ + "content-type": "application/json", + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, + }, request_options=request_options, omit=OMIT, ) try: if 200 <= _response.status_code < 300: _data = typing.cast( - AddThreadMessagesResponse, + AddMessagesResult, parse_obj_as( - type_=AddThreadMessagesResponse, # type: ignore + type_=AddMessagesResult, # type: ignore object_=_response.json(), ), ) return HttpResponse(response=_response, data=_data) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 400: + raise BadRequestError( + 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 == 401: + raise UnauthorizedError( + 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, @@ -500,78 +902,193 @@ def add_messages( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - def add_messages_batch( + def get_summary( + self, thread_uuid: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> HttpResponse[ThreadSummary]: + """ + Parameters + ---------- + thread_uuid : str + Thread UUID + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[ThreadSummary] + OK + """ + _response = self._client_wrapper.httpx_client.request( + f"threads/{jsonable_encoder(thread_uuid)}/summary", + method="GET", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + ThreadSummary, + parse_obj_as( + type_=ThreadSummary, # 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( + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + 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(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise core_api_error_ApiError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.text + ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) + raise core_api_error_ApiError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response_json + ) + + +class AsyncRawThreadClient: + def __init__(self, *, client_wrapper: AsyncClientWrapper): + self._client_wrapper = client_wrapper + + async def list( self, - thread_id: str, *, - messages: typing.Sequence[Message], - ignore_roles: typing.Optional[typing.Sequence[RoleType]] = OMIT, - return_context: typing.Optional[bool] = OMIT, - strict_ontology: typing.Optional[bool] = OMIT, + limit: typing.Optional[int] = None, + cursor: typing.Optional[str] = None, + order_by: typing.Optional[str] = None, + order: typing.Optional[str] = None, + user_uuid: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> HttpResponse[AddThreadMessagesResponse]: + ) -> AsyncPager[Thread, ThreadPage]: """ - Deprecated. Use the [Batch API](/adding-batch-data) (`client.batch.*` with `type: "thread_message"`) instead. - - Adds messages to a thread in batch mode, processing messages concurrently. - Parameters ---------- - thread_id : str - The ID of the thread to which messages should be added. + limit : typing.Optional[int] + Page size - messages : typing.Sequence[Message] - A list of message objects, where each message contains a role and content. + cursor : typing.Optional[str] + Opaque page cursor - ignore_roles : typing.Optional[typing.Sequence[RoleType]] - Optional list of role types to ignore when adding messages to graph memory. - The message itself will still be added, retained and used as context for messages - that are added to a user's graph. + order_by : typing.Optional[str] + Sort field - return_context : typing.Optional[bool] - Optionally return context block relevant to the most recent messages. + order : typing.Optional[str] + asc or desc - strict_ontology : typing.Optional[bool] - When true, prevents extraction of generic Entity nodes that do not match the configured ontology. + user_uuid : typing.Optional[str] + Filter by user UUID request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - HttpResponse[AddThreadMessagesResponse] - An object, optionally containing user context retrieved for the last thread message + AsyncPager[Thread, ThreadPage] + OK """ - _response = self._client_wrapper.httpx_client.request( - f"threads/{jsonable_encoder(thread_id)}/messages-batch", - method="POST", - json={ - "ignore_roles": ignore_roles, - "messages": convert_and_respect_annotation_metadata( - object_=messages, annotation=typing.Sequence[Message], direction="write" - ), - "return_context": return_context, - "strict_ontology": strict_ontology, + _response = await self._client_wrapper.httpx_client.request( + "threads", + method="GET", + params={ + "limit": limit, + "cursor": cursor, + "order_by": order_by, + "order": order, + "user_uuid": user_uuid, }, request_options=request_options, - omit=OMIT, ) try: if 200 <= _response.status_code < 300: - _data = typing.cast( - AddThreadMessagesResponse, + _parsed_response = typing.cast( + ThreadPage, parse_obj_as( - type_=AddThreadMessagesResponse, # type: ignore + type_=ThreadPage, # type: ignore object_=_response.json(), ), ) - return HttpResponse(response=_response, data=_data) - if _response.status_code == 500: - raise InternalServerError( + _items = _parsed_response.items + _parsed_next = _parsed_response.next_cursor + _has_next = _parsed_next is not None and _parsed_next != "" + + async def _get_next(): + return await self.list( + limit=limit, + cursor=_parsed_next, + order_by=order_by, + order=order, + user_uuid=user_uuid, + request_options=request_options, + ) + + return AsyncPager(has_next=_has_next, items=_items, get_next=_get_next, response=_parsed_response) + if _response.status_code == 400: + raise BadRequestError( + 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 == 401: + raise UnauthorizedError( + 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, @@ -586,46 +1103,65 @@ def add_messages_batch( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - def get_summary( - self, thread_id: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> HttpResponse[ThreadSummary]: + async def create( + self, + *, + thread_id: typing.Optional[str] = OMIT, + user_uuid: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[Thread]: """ - Returns the incremental summary generated from messages in the thread. Returns 404 if no summary exists for the thread. - Parameters ---------- - thread_id : str - The thread ID. + thread_id : typing.Optional[str] + + user_uuid : typing.Optional[str] + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - HttpResponse[ThreadSummary] - OK + AsyncHttpResponse[Thread] + Created """ - _response = self._client_wrapper.httpx_client.request( - f"threads/{jsonable_encoder(thread_id)}/summary", - method="GET", + _response = await self._client_wrapper.httpx_client.request( + "threads", + method="POST", + json={ + "thread_id": thread_id, + "user_uuid": user_uuid, + }, + headers={ + "content-type": "application/json", + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, + }, request_options=request_options, + omit=OMIT, ) try: if 200 <= _response.status_code < 300: _data = typing.cast( - ThreadSummary, + Thread, parse_obj_as( - type_=ThreadSummary, # type: ignore + type_=Thread, # type: ignore object_=_response.json(), ), ) - return HttpResponse(response=_response, data=_data) - if _response.status_code == 403: - raise ForbiddenError( + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise BadRequestError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -635,8 +1171,8 @@ def get_summary( ), ), ) - if _response.status_code == 404: - raise NotFoundError( + if _response.status_code == 401: + raise UnauthorizedError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -646,8 +1182,8 @@ def get_summary( ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -662,66 +1198,63 @@ def get_summary( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - -class AsyncRawThreadClient: - def __init__(self, *, client_wrapper: AsyncClientWrapper): - self._client_wrapper = client_wrapper - - async def list_all( + async def lookup( self, *, - page_number: typing.Optional[int] = None, - page_size: typing.Optional[int] = None, - order_by: typing.Optional[str] = None, - asc: typing.Optional[bool] = None, + graph_id: typing.Optional[str] = OMIT, + thread_id: typing.Optional[str] = OMIT, + user_id: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> AsyncHttpResponse[ThreadListResponse]: + ) -> AsyncHttpResponse[Thread]: """ - Returns all threads. - Parameters ---------- - page_number : typing.Optional[int] - Page number for pagination, starting from 1 + graph_id : typing.Optional[str] - page_size : typing.Optional[int] - Number of threads to retrieve per page. + thread_id : typing.Optional[str] - order_by : typing.Optional[str] - Field to order the results by: created_at, updated_at, user_id, thread_id. + user_id : typing.Optional[str] - asc : typing.Optional[bool] - Order direction: true for ascending, false for descending. + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - AsyncHttpResponse[ThreadListResponse] - List of threads + AsyncHttpResponse[Thread] + OK """ _response = await self._client_wrapper.httpx_client.request( - "threads", - method="GET", - params={ - "page_number": page_number, - "page_size": page_size, - "order_by": order_by, - "asc": asc, + "threads/lookup", + method="POST", + json={ + "graph_id": graph_id, + "thread_id": thread_id, + "user_id": user_id, + }, + headers={ + "content-type": "application/json", + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, }, request_options=request_options, + omit=OMIT, ) try: if 200 <= _response.status_code < 300: _data = typing.cast( - ThreadListResponse, + Thread, parse_obj_as( - type_=ThreadListResponse, # type: ignore + type_=Thread, # type: ignore object_=_response.json(), ), ) @@ -730,15 +1263,26 @@ async def list_all( raise BadRequestError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore object_=_response.json(), ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -753,23 +1297,22 @@ async def list_all( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - async def create( - self, *, thread_id: str, user_id: str, request_options: typing.Optional[RequestOptions] = None + async def get( + self, thread_uuid: str, *, request_options: typing.Optional[RequestOptions] = None ) -> AsyncHttpResponse[Thread]: """ - Start a new thread. - Parameters ---------- - thread_id : str - The unique identifier of the thread. - - user_id : str - The unique identifier of the user associated with the thread + thread_uuid : str + Thread UUID request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -777,20 +1320,12 @@ async def create( Returns ------- AsyncHttpResponse[Thread] - The thread object. + OK """ _response = await self._client_wrapper.httpx_client.request( - "threads", - method="POST", - json={ - "thread_id": thread_id, - "user_id": user_id, - }, - headers={ - "content-type": "application/json", - }, + f"threads/{jsonable_encoder(thread_uuid)}", + method="GET", request_options=request_options, - omit=OMIT, ) try: if 200 <= _response.status_code < 300: @@ -806,15 +1341,26 @@ async def create( raise BadRequestError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore object_=_response.json(), ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -829,46 +1375,68 @@ async def create( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) async def delete( - self, thread_id: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> AsyncHttpResponse[SuccessResponse]: + self, + thread_uuid: str, + *, + idempotency_key: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[ThreadDeleteResult]: """ - Deletes a thread. - Parameters ---------- - thread_id : str - The ID of the thread for which memory should be deleted. + thread_uuid : str + Thread UUID + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - AsyncHttpResponse[SuccessResponse] - OK + AsyncHttpResponse[ThreadDeleteResult] + Accepted """ _response = await self._client_wrapper.httpx_client.request( - f"threads/{jsonable_encoder(thread_id)}", + f"threads/{jsonable_encoder(thread_uuid)}", method="DELETE", + headers={ + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, + }, request_options=request_options, ) try: if 200 <= _response.status_code < 300: _data = typing.cast( - SuccessResponse, + ThreadDeleteResult, parse_obj_as( - type_=SuccessResponse, # type: ignore + type_=ThreadDeleteResult, # type: ignore object_=_response.json(), ), ) return AsyncHttpResponse(response=_response, data=_data) - if _response.status_code == 404: - raise NotFoundError( + if _response.status_code == 400: + raise BadRequestError( + 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 == 401: + raise UnauthorizedError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -878,8 +1446,8 @@ async def delete( ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -894,27 +1462,29 @@ async def delete( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - async def get_user_context( + async def get_context( self, - thread_id: str, + thread_uuid: str, *, - template_id: typing.Optional[str] = None, + template_uuid: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, ) -> AsyncHttpResponse[ThreadContextResponse]: """ - Returns most relevant context from the user graph (including memory from any/all past threads) based on the content of the past few messages of the given thread. - Parameters ---------- - thread_id : str - The ID of the current thread (for which context is being retrieved). + thread_uuid : str + Thread UUID - template_id : typing.Optional[str] - Optional template ID to use for custom context rendering. + template_uuid : typing.Optional[str] + Context template UUID request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -925,10 +1495,10 @@ async def get_user_context( OK """ _response = await self._client_wrapper.httpx_client.request( - f"threads/{jsonable_encoder(thread_id)}/context", + f"threads/{jsonable_encoder(thread_uuid)}/context", method="GET", params={ - "template_id": template_id, + "template_uuid": template_uuid, }, request_options=request_options, ) @@ -942,8 +1512,19 @@ async def get_user_context( ), ) return AsyncHttpResponse(response=_response, data=_data) - if _response.status_code == 404: - raise NotFoundError( + if _response.status_code == 400: + raise BadRequestError( + 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 == 401: + raise UnauthorizedError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -953,8 +1534,8 @@ async def get_user_context( ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -969,66 +1550,86 @@ async def get_user_context( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - async def get( + async def list_episodes( self, - thread_id: str, + thread_uuid: str, *, limit: typing.Optional[int] = None, - cursor: typing.Optional[int] = None, - lastn: typing.Optional[int] = None, + cursor: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> AsyncHttpResponse[MessageListResponse]: + ) -> AsyncPager[JsonObject, JsonObjectPage]: """ - Returns messages for a thread. - Parameters ---------- - thread_id : str - Thread ID + thread_uuid : str + Thread UUID limit : typing.Optional[int] - Limit the number of results returned - - cursor : typing.Optional[int] - Cursor for pagination + Page size - lastn : typing.Optional[int] - Number of most recent messages to return (overrides limit and cursor) + cursor : typing.Optional[str] + Opaque page cursor request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - AsyncHttpResponse[MessageListResponse] + AsyncPager[JsonObject, JsonObjectPage] OK """ _response = await self._client_wrapper.httpx_client.request( - f"threads/{jsonable_encoder(thread_id)}/messages", + f"threads/{jsonable_encoder(thread_uuid)}/episodes", method="GET", params={ "limit": limit, "cursor": cursor, - "lastn": lastn, }, request_options=request_options, ) try: if 200 <= _response.status_code < 300: - _data = typing.cast( - MessageListResponse, + _parsed_response = typing.cast( + JsonObjectPage, parse_obj_as( - type_=MessageListResponse, # type: ignore + type_=JsonObjectPage, # type: ignore object_=_response.json(), ), ) - return AsyncHttpResponse(response=_response, data=_data) - if _response.status_code == 404: - raise NotFoundError( + _items = _parsed_response.items + _parsed_next = _parsed_response.next_cursor + _has_next = _parsed_next is not None and _parsed_next != "" + + async def _get_next(): + return await self.list_episodes( + thread_uuid, + limit=limit, + cursor=_parsed_next, + request_options=request_options, + ) + + return AsyncPager(has_next=_has_next, items=_items, get_next=_get_next, response=_parsed_response) + if _response.status_code == 400: + raise BadRequestError( + 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 == 401: + raise UnauthorizedError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -1038,8 +1639,8 @@ async def get( ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -1054,76 +1655,97 @@ async def get( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - async def add_messages( + async def list_messages( self, - thread_id: str, + thread_uuid: str, *, - messages: typing.Sequence[Message], - ignore_roles: typing.Optional[typing.Sequence[RoleType]] = OMIT, - return_context: typing.Optional[bool] = OMIT, - strict_ontology: typing.Optional[bool] = OMIT, + limit: typing.Optional[int] = None, + cursor: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> AsyncHttpResponse[AddThreadMessagesResponse]: + ) -> AsyncPager[Message, MessagePage]: """ - Add messages to a thread. - Parameters ---------- - thread_id : str - The ID of the thread to which messages should be added. - - messages : typing.Sequence[Message] - A list of message objects, where each message contains a role and content. + thread_uuid : str + Thread UUID - ignore_roles : typing.Optional[typing.Sequence[RoleType]] - Optional list of role types to ignore when adding messages to graph memory. - The message itself will still be added, retained and used as context for messages - that are added to a user's graph. - - return_context : typing.Optional[bool] - Optionally return context block relevant to the most recent messages. + limit : typing.Optional[int] + Page size - strict_ontology : typing.Optional[bool] - When true, prevents extraction of generic Entity nodes that do not match the configured ontology. + cursor : typing.Optional[str] + Opaque page cursor request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - AsyncHttpResponse[AddThreadMessagesResponse] - An object, optionally containing user context retrieved for the last thread message + AsyncPager[Message, MessagePage] + OK """ _response = await self._client_wrapper.httpx_client.request( - f"threads/{jsonable_encoder(thread_id)}/messages", - method="POST", - json={ - "ignore_roles": ignore_roles, - "messages": convert_and_respect_annotation_metadata( - object_=messages, annotation=typing.Sequence[Message], direction="write" - ), - "return_context": return_context, - "strict_ontology": strict_ontology, + f"threads/{jsonable_encoder(thread_uuid)}/messages", + method="GET", + params={ + "limit": limit, + "cursor": cursor, }, request_options=request_options, - omit=OMIT, ) try: if 200 <= _response.status_code < 300: - _data = typing.cast( - AddThreadMessagesResponse, + _parsed_response = typing.cast( + MessagePage, parse_obj_as( - type_=AddThreadMessagesResponse, # type: ignore + type_=MessagePage, # type: ignore object_=_response.json(), ), ) - return AsyncHttpResponse(response=_response, data=_data) - if _response.status_code == 500: - raise InternalServerError( + _items = _parsed_response.items + _parsed_next = _parsed_response.next_cursor + _has_next = _parsed_next is not None and _parsed_next != "" + + async def _get_next(): + return await self.list_messages( + thread_uuid, + limit=limit, + cursor=_parsed_next, + request_options=request_options, + ) + + return AsyncPager(has_next=_has_next, items=_items, get_next=_get_next, response=_parsed_response) + if _response.status_code == 400: + raise BadRequestError( + 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 == 401: + raise UnauthorizedError( + 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, @@ -1138,78 +1760,101 @@ async def add_messages( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - async def add_messages_batch( + async def add_messages( self, - thread_id: str, + thread_uuid: str, *, - messages: typing.Sequence[Message], - ignore_roles: typing.Optional[typing.Sequence[RoleType]] = OMIT, + ignore_roles: typing.Optional[typing.Sequence[str]] = OMIT, + messages: typing.Optional[typing.Sequence[AddMessage]] = OMIT, return_context: typing.Optional[bool] = OMIT, strict_ontology: typing.Optional[bool] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> AsyncHttpResponse[AddThreadMessagesResponse]: + ) -> AsyncHttpResponse[AddMessagesResult]: """ - Deprecated. Use the [Batch API](/adding-batch-data) (`client.batch.*` with `type: "thread_message"`) instead. - - Adds messages to a thread in batch mode, processing messages concurrently. - Parameters ---------- - thread_id : str - The ID of the thread to which messages should be added. + thread_uuid : str + Thread UUID - messages : typing.Sequence[Message] - A list of message objects, where each message contains a role and content. + ignore_roles : typing.Optional[typing.Sequence[str]] - ignore_roles : typing.Optional[typing.Sequence[RoleType]] - Optional list of role types to ignore when adding messages to graph memory. - The message itself will still be added, retained and used as context for messages - that are added to a user's graph. + messages : typing.Optional[typing.Sequence[AddMessage]] return_context : typing.Optional[bool] - Optionally return context block relevant to the most recent messages. strict_ontology : typing.Optional[bool] - When true, prevents extraction of generic Entity nodes that do not match the configured ontology. + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - AsyncHttpResponse[AddThreadMessagesResponse] - An object, optionally containing user context retrieved for the last thread message + AsyncHttpResponse[AddMessagesResult] + Accepted """ _response = await self._client_wrapper.httpx_client.request( - f"threads/{jsonable_encoder(thread_id)}/messages-batch", + f"threads/{jsonable_encoder(thread_uuid)}/messages", method="POST", json={ "ignore_roles": ignore_roles, "messages": convert_and_respect_annotation_metadata( - object_=messages, annotation=typing.Sequence[Message], direction="write" + object_=messages, annotation=typing.Sequence[AddMessage], direction="write" ), "return_context": return_context, "strict_ontology": strict_ontology, }, + headers={ + "content-type": "application/json", + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, + }, request_options=request_options, omit=OMIT, ) try: if 200 <= _response.status_code < 300: _data = typing.cast( - AddThreadMessagesResponse, + AddMessagesResult, parse_obj_as( - type_=AddThreadMessagesResponse, # type: ignore + type_=AddMessagesResult, # type: ignore object_=_response.json(), ), ) return AsyncHttpResponse(response=_response, data=_data) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 400: + raise BadRequestError( + 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 == 401: + raise UnauthorizedError( + 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, @@ -1224,20 +1869,22 @@ async def add_messages_batch( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) async def get_summary( - self, thread_id: str, *, request_options: typing.Optional[RequestOptions] = None + self, thread_uuid: str, *, request_options: typing.Optional[RequestOptions] = None ) -> AsyncHttpResponse[ThreadSummary]: """ - Returns the incremental summary generated from messages in the thread. Returns 404 if no summary exists for the thread. - Parameters ---------- - thread_id : str - The thread ID. + thread_uuid : str + Thread UUID request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -1248,7 +1895,7 @@ async def get_summary( OK """ _response = await self._client_wrapper.httpx_client.request( - f"threads/{jsonable_encoder(thread_id)}/summary", + f"threads/{jsonable_encoder(thread_uuid)}/summary", method="GET", request_options=request_options, ) @@ -1262,8 +1909,8 @@ async def get_summary( ), ) return AsyncHttpResponse(response=_response, data=_data) - if _response.status_code == 403: - raise ForbiddenError( + if _response.status_code == 400: + raise BadRequestError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -1273,8 +1920,8 @@ async def get_summary( ), ), ) - if _response.status_code == 404: - raise NotFoundError( + if _response.status_code == 401: + raise UnauthorizedError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -1284,8 +1931,8 @@ async def get_summary( ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -1300,6 +1947,10 @@ async def get_summary( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) diff --git a/src/zep_cloud/types/__init__.py b/src/zep_cloud/types/__init__.py index 535b0a0d..e31f7f0e 100644 --- a/src/zep_cloud/types/__init__.py +++ b/src/zep_cloud/types/__init__.py @@ -2,206 +2,175 @@ # isort: skip_file -from .add_node_item import AddNodeItem -from .add_nodes_response import AddNodesResponse -from .add_thread_messages_request import AddThreadMessagesRequest -from .add_thread_messages_response import AddThreadMessagesResponse -from .add_triple_response import AddTripleResponse -from .added_node import AddedNode -from .api_error import ApiError -from .apidata_batch_add_item_role import ApidataBatchAddItemRole -from .apidata_batch_add_item_type import ApidataBatchAddItemType -from .attached_policy_sets_response import AttachedPolicySetsResponse -from .batch_add_item import BatchAddItem -from .batch_item_detail import BatchItemDetail -from .batch_item_kind import BatchItemKind -from .batch_item_list_response import BatchItemListResponse -from .batch_item_status import BatchItemStatus -from .batch_list_response import BatchListResponse -from .batch_progress import BatchProgress -from .batch_status import BatchStatus -from .batch_summary import BatchSummary -from .clone_graph_response import CloneGraphResponse -from .cluster_detect_config import ClusterDetectConfig -from .co_occurrence_detect_config import CoOccurrenceDetectConfig -from .comparison_operator import ComparisonOperator -from .context_template_response import ContextTemplateResponse -from .custom_instruction import CustomInstruction -from .date_filter import DateFilter -from .derived_node import DerivedNode -from .detect_config import DetectConfig -from .detect_patterns_response import DetectPatternsResponse -from .edge_type import EdgeType -from .entity_edge import EntityEdge -from .entity_edge_source_target import EntityEdgeSourceTarget -from .entity_node import EntityNode -from .entity_property import EntityProperty -from .entity_property_type import EntityPropertyType -from .entity_type import EntityType -from .entity_type_response import EntityTypeResponse -from .episode import Episode -from .episode_data import EpisodeData -from .episode_mentions import EpisodeMentions -from .episode_metadata_filter import EpisodeMetadataFilter -from .episode_response import EpisodeResponse -from .get_task_response import GetTaskResponse -from .graph import Graph -from .graph_data_type import GraphDataType -from .graph_edges_request import GraphEdgesRequest -from .graph_episode_list_request import GraphEpisodeListRequest -from .graph_list_response import GraphListResponse -from .graph_node_neighbor import GraphNodeNeighbor -from .graph_nodes_request import GraphNodesRequest -from .graph_observations_request import GraphObservationsRequest -from .graph_search_response_metadata import GraphSearchResponseMetadata -from .graph_search_results import GraphSearchResults -from .graph_search_scope import GraphSearchScope -from .graph_subgraph_response import GraphSubgraphResponse -from .graph_thread_summaries_request import GraphThreadSummariesRequest -from .graphiti_metadata_filter_group_type import GraphitiMetadataFilterGroupType -from .graphiti_saga_node import GraphitiSagaNode -from .hub_detect_config import HubDetectConfig -from .list_context_templates_response import ListContextTemplatesResponse -from .list_custom_instructions_response import ListCustomInstructionsResponse -from .list_user_instructions_response import ListUserInstructionsResponse -from .message import Message -from .message_list_response import MessageListResponse -from .metadata_filter_group import MetadataFilterGroup -from .mutate_user_group_members_request import MutateUserGroupMembersRequest -from .observation_steering_config import ObservationSteeringConfig -from .observation_type import ObservationType -from .path_detect_config import PathDetectConfig -from .pattern_metadata import PatternMetadata -from .pattern_result import PatternResult -from .pattern_seeds import PatternSeeds -from .policy_set_summary_response import PolicySetSummaryResponse -from .project_info import ProjectInfo -from .project_info_response import ProjectInfoResponse -from .property_filter import PropertyFilter -from .recency_weight import RecencyWeight -from .relationship_detect_config import RelationshipDetectConfig -from .reranker import Reranker -from .role_type import RoleType -from .search_filters import SearchFilters -from .success_response import SuccessResponse -from .task_error_response import TaskErrorResponse -from .task_progress import TaskProgress -from .thread import Thread -from .thread_context_response import ThreadContextResponse -from .thread_list_response import ThreadListResponse -from .thread_summary import ThreadSummary -from .user import User -from .user_group import UserGroup -from .user_group_kind import UserGroupKind -from .user_group_list_response import UserGroupListResponse -from .user_group_members_response import UserGroupMembersResponse -from .user_group_membership_response import UserGroupMembershipResponse -from .user_group_quota import UserGroupQuota -from .user_group_response import UserGroupResponse -from .user_instruction import UserInstruction -from .user_list_response import UserListResponse -from .user_membership_groups_response import UserMembershipGroupsResponse -from .user_node_response import UserNodeResponse +import typing +from importlib import import_module + +if typing.TYPE_CHECKING: + from .add_edge_result import AddEdgeResult + from .add_episode_result import AddEpisodeResult + from .add_message import AddMessage + from .add_messages_result import AddMessagesResult + from .add_nodes_result import AddNodesResult + from .api_error import ApiError + from .artifact_list_request import ArtifactListRequest + from .async_result import AsyncResult + from .batch import Batch + from .batch_items_response import BatchItemsResponse + from .batch_page import BatchPage + from .clone_graph_result import CloneGraphResult + from .context_template import ContextTemplate + from .context_template_page import ContextTemplatePage + from .create_context_template_request import CreateContextTemplateRequest + from .error_body import ErrorBody + from .graph import Graph + from .graph_context_response import GraphContextResponse + from .graph_delete_result import GraphDeleteResult + from .graph_page import GraphPage + from .instructions import Instructions + from .json_object import JsonObject + from .json_object_page import JsonObjectPage + from .lookup_batch_response import LookupBatchResponse + from .lookup_item import LookupItem + from .lookup_request import LookupRequest + from .message import Message + from .message_page import MessagePage + from .neighbor_entry import NeighborEntry + from .neighbor_page import NeighborPage + from .observation_steering import ObservationSteering + from .ontology import Ontology + from .process_batch_result import ProcessBatchResult + from .project import Project + from .search_request import SearchRequest + from .task import Task + from .task_page import TaskPage + from .task_progress import TaskProgress + from .thread import Thread + from .thread_context_response import ThreadContextResponse + from .thread_delete_result import ThreadDeleteResult + from .thread_page import ThreadPage + from .thread_summary import ThreadSummary + from .user import User + from .user_delete_result import UserDeleteResult + from .user_page import UserPage + from .user_summary_instructions import UserSummaryInstructions +_dynamic_imports: typing.Dict[str, str] = { + "AddEdgeResult": ".add_edge_result", + "AddEpisodeResult": ".add_episode_result", + "AddMessage": ".add_message", + "AddMessagesResult": ".add_messages_result", + "AddNodesResult": ".add_nodes_result", + "ApiError": ".api_error", + "ArtifactListRequest": ".artifact_list_request", + "AsyncResult": ".async_result", + "Batch": ".batch", + "BatchItemsResponse": ".batch_items_response", + "BatchPage": ".batch_page", + "CloneGraphResult": ".clone_graph_result", + "ContextTemplate": ".context_template", + "ContextTemplatePage": ".context_template_page", + "CreateContextTemplateRequest": ".create_context_template_request", + "ErrorBody": ".error_body", + "Graph": ".graph", + "GraphContextResponse": ".graph_context_response", + "GraphDeleteResult": ".graph_delete_result", + "GraphPage": ".graph_page", + "Instructions": ".instructions", + "JsonObject": ".json_object", + "JsonObjectPage": ".json_object_page", + "LookupBatchResponse": ".lookup_batch_response", + "LookupItem": ".lookup_item", + "LookupRequest": ".lookup_request", + "Message": ".message", + "MessagePage": ".message_page", + "NeighborEntry": ".neighbor_entry", + "NeighborPage": ".neighbor_page", + "ObservationSteering": ".observation_steering", + "Ontology": ".ontology", + "ProcessBatchResult": ".process_batch_result", + "Project": ".project", + "SearchRequest": ".search_request", + "Task": ".task", + "TaskPage": ".task_page", + "TaskProgress": ".task_progress", + "Thread": ".thread", + "ThreadContextResponse": ".thread_context_response", + "ThreadDeleteResult": ".thread_delete_result", + "ThreadPage": ".thread_page", + "ThreadSummary": ".thread_summary", + "User": ".user", + "UserDeleteResult": ".user_delete_result", + "UserPage": ".user_page", + "UserSummaryInstructions": ".user_summary_instructions", +} + + +def __getattr__(attr_name: str) -> typing.Any: + module_name = _dynamic_imports.get(attr_name) + if module_name is None: + raise AttributeError(f"No {attr_name} found in _dynamic_imports for module name -> {__name__}") + try: + module = import_module(module_name, __package__) + if module_name == f".{attr_name}": + return module + else: + return getattr(module, attr_name) + except ImportError as e: + raise ImportError(f"Failed to import {attr_name} from {module_name}: {e}") from e + except AttributeError as e: + raise AttributeError(f"Failed to get {attr_name} from {module_name}: {e}") from e + + +def __dir__(): + lazy_attrs = list(_dynamic_imports.keys()) + return sorted(lazy_attrs) + __all__ = [ - "AddNodeItem", - "AddNodesResponse", - "AddThreadMessagesRequest", - "AddThreadMessagesResponse", - "AddTripleResponse", - "AddedNode", + "AddEdgeResult", + "AddEpisodeResult", + "AddMessage", + "AddMessagesResult", + "AddNodesResult", "ApiError", - "ApidataBatchAddItemRole", - "ApidataBatchAddItemType", - "AttachedPolicySetsResponse", - "BatchAddItem", - "BatchItemDetail", - "BatchItemKind", - "BatchItemListResponse", - "BatchItemStatus", - "BatchListResponse", - "BatchProgress", - "BatchStatus", - "BatchSummary", - "CloneGraphResponse", - "ClusterDetectConfig", - "CoOccurrenceDetectConfig", - "ComparisonOperator", - "ContextTemplateResponse", - "CustomInstruction", - "DateFilter", - "DerivedNode", - "DetectConfig", - "DetectPatternsResponse", - "EdgeType", - "EntityEdge", - "EntityEdgeSourceTarget", - "EntityNode", - "EntityProperty", - "EntityPropertyType", - "EntityType", - "EntityTypeResponse", - "Episode", - "EpisodeData", - "EpisodeMentions", - "EpisodeMetadataFilter", - "EpisodeResponse", - "GetTaskResponse", + "ArtifactListRequest", + "AsyncResult", + "Batch", + "BatchItemsResponse", + "BatchPage", + "CloneGraphResult", + "ContextTemplate", + "ContextTemplatePage", + "CreateContextTemplateRequest", + "ErrorBody", "Graph", - "GraphDataType", - "GraphEdgesRequest", - "GraphEpisodeListRequest", - "GraphListResponse", - "GraphNodeNeighbor", - "GraphNodesRequest", - "GraphObservationsRequest", - "GraphSearchResponseMetadata", - "GraphSearchResults", - "GraphSearchScope", - "GraphSubgraphResponse", - "GraphThreadSummariesRequest", - "GraphitiMetadataFilterGroupType", - "GraphitiSagaNode", - "HubDetectConfig", - "ListContextTemplatesResponse", - "ListCustomInstructionsResponse", - "ListUserInstructionsResponse", + "GraphContextResponse", + "GraphDeleteResult", + "GraphPage", + "Instructions", + "JsonObject", + "JsonObjectPage", + "LookupBatchResponse", + "LookupItem", + "LookupRequest", "Message", - "MessageListResponse", - "MetadataFilterGroup", - "MutateUserGroupMembersRequest", - "ObservationSteeringConfig", - "ObservationType", - "PathDetectConfig", - "PatternMetadata", - "PatternResult", - "PatternSeeds", - "PolicySetSummaryResponse", - "ProjectInfo", - "ProjectInfoResponse", - "PropertyFilter", - "RecencyWeight", - "RelationshipDetectConfig", - "Reranker", - "RoleType", - "SearchFilters", - "SuccessResponse", - "TaskErrorResponse", + "MessagePage", + "NeighborEntry", + "NeighborPage", + "ObservationSteering", + "Ontology", + "ProcessBatchResult", + "Project", + "SearchRequest", + "Task", + "TaskPage", "TaskProgress", "Thread", "ThreadContextResponse", - "ThreadListResponse", + "ThreadDeleteResult", + "ThreadPage", "ThreadSummary", "User", - "UserGroup", - "UserGroupKind", - "UserGroupListResponse", - "UserGroupMembersResponse", - "UserGroupMembershipResponse", - "UserGroupQuota", - "UserGroupResponse", - "UserInstruction", - "UserListResponse", - "UserMembershipGroupsResponse", - "UserNodeResponse", + "UserDeleteResult", + "UserPage", + "UserSummaryInstructions", ] diff --git a/src/zep_cloud/types/entity_property.py b/src/zep_cloud/types/add_edge_result.py similarity index 73% rename from src/zep_cloud/types/entity_property.py rename to src/zep_cloud/types/add_edge_result.py index bbc8d568..58e5302c 100644 --- a/src/zep_cloud/types/entity_property.py +++ b/src/zep_cloud/types/add_edge_result.py @@ -4,13 +4,12 @@ import pydantic from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel -from .entity_property_type import EntityPropertyType +from .task import Task -class EntityProperty(UniversalBaseModel): - description: str - name: str - type: EntityPropertyType +class AddEdgeResult(UniversalBaseModel): + edge: typing.Optional[typing.Dict[str, typing.Any]] = None + task: typing.Optional[Task] = None if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 diff --git a/src/zep_cloud/types/add_episode_result.py b/src/zep_cloud/types/add_episode_result.py new file mode 100644 index 00000000..933abb22 --- /dev/null +++ b/src/zep_cloud/types/add_episode_result.py @@ -0,0 +1,21 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from .task import Task + + +class AddEpisodeResult(UniversalBaseModel): + episode: typing.Optional[typing.Dict[str, typing.Any]] = None + task: typing.Optional[Task] = None + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/zep_cloud/types/context_template_response.py b/src/zep_cloud/types/add_message.py similarity index 52% rename from src/zep_cloud/types/context_template_response.py rename to src/zep_cloud/types/add_message.py index 766a07ed..c507d014 100644 --- a/src/zep_cloud/types/context_template_response.py +++ b/src/zep_cloud/types/add_message.py @@ -8,21 +8,14 @@ from ..core.serialization import FieldMetadata -class ContextTemplateResponse(UniversalBaseModel): - template: typing.Optional[str] = pydantic.Field(default=None) - """ - The template content. - """ - - template_id: typing.Optional[str] = pydantic.Field(default=None) - """ - Unique identifier for the template (max 100 characters). - """ - - uuid_: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="uuid")] = pydantic.Field(default=None) - """ - Unique identifier for the template. - """ +class AddMessage(UniversalBaseModel): + content: typing.Optional[str] = None + metadata: typing.Optional[typing.Dict[str, typing.Any]] = None + name: typing.Optional[str] = None + role: typing.Optional[str] = None + uuid_: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="uuid"), pydantic.Field(alias="uuid") + ] = None if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 diff --git a/src/zep_cloud/types/add_messages_result.py b/src/zep_cloud/types/add_messages_result.py new file mode 100644 index 00000000..c5a1d8d5 --- /dev/null +++ b/src/zep_cloud/types/add_messages_result.py @@ -0,0 +1,23 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from .message import Message +from .task import Task + + +class AddMessagesResult(UniversalBaseModel): + context: typing.Optional[str] = None + messages: typing.Optional[typing.List[Message]] = None + task: typing.Optional[Task] = None + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/zep_cloud/types/add_node_item.py b/src/zep_cloud/types/add_node_item.py deleted file mode 100644 index c63ea100..00000000 --- a/src/zep_cloud/types/add_node_item.py +++ /dev/null @@ -1,50 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import typing - -import pydantic -from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel - - -class AddNodeItem(UniversalBaseModel): - attributes: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = pydantic.Field(default=None) - """ - Additional attributes of the node. Values must be scalar types (string, - number, boolean, or null). Nested objects and arrays are not allowed. - """ - - created_at: typing.Optional[str] = pydantic.Field(default=None) - """ - The node creation time. Defaults to the request time when absent. - """ - - label: typing.Optional[str] = pydantic.Field(default=None) - """ - The node's entity type. At most one; the base "Entity" label is added - implicitly by the graph layer on save and does not need to be supplied. - """ - - metadata: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = pydantic.Field(default=None) - """ - Optional metadata attached to the node's shadow episode. Max 10 scalar - key-value pairs. - """ - - name: str = pydantic.Field() - """ - The name of the node. Used to derive the node's search embedding. - """ - - summary: typing.Optional[str] = pydantic.Field(default=None) - """ - A regional summary of the 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/add_nodes_response.py b/src/zep_cloud/types/add_nodes_response.py deleted file mode 100644 index 5cc6db7b..00000000 --- a/src/zep_cloud/types/add_nodes_response.py +++ /dev/null @@ -1,29 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import typing - -import pydantic -from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel -from .added_node import AddedNode - - -class AddNodesResponse(UniversalBaseModel): - nodes: typing.Optional[typing.List[AddedNode]] = pydantic.Field(default=None) - """ - The accepted nodes, each carrying the UUID Zep assigned to it, in request - order. - """ - - task_id: typing.Optional[str] = pydantic.Field(default=None) - """ - Task ID of the async add-nodes task. - """ - - 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/list_custom_instructions_response.py b/src/zep_cloud/types/add_nodes_result.py similarity index 71% rename from src/zep_cloud/types/list_custom_instructions_response.py rename to src/zep_cloud/types/add_nodes_result.py index e7ac97ab..341bbda9 100644 --- a/src/zep_cloud/types/list_custom_instructions_response.py +++ b/src/zep_cloud/types/add_nodes_result.py @@ -4,11 +4,12 @@ import pydantic from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel -from .custom_instruction import CustomInstruction +from .task import Task -class ListCustomInstructionsResponse(UniversalBaseModel): - instructions: typing.Optional[typing.List[CustomInstruction]] = None +class AddNodesResult(UniversalBaseModel): + nodes: typing.Optional[typing.List[typing.Dict[str, typing.Any]]] = None + task: typing.Optional[Task] = None if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 diff --git a/src/zep_cloud/types/add_thread_messages_request.py b/src/zep_cloud/types/add_thread_messages_request.py deleted file mode 100644 index 72df5d95..00000000 --- a/src/zep_cloud/types/add_thread_messages_request.py +++ /dev/null @@ -1,41 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import typing - -import pydantic -from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel -from .message import Message -from .role_type import RoleType - - -class AddThreadMessagesRequest(UniversalBaseModel): - ignore_roles: typing.Optional[typing.List[RoleType]] = pydantic.Field(default=None) - """ - Optional list of role types to ignore when adding messages to graph memory. - The message itself will still be added, retained and used as context for messages - that are added to a user's graph. - """ - - messages: typing.List[Message] = pydantic.Field() - """ - A list of message objects, where each message contains a role and content. - """ - - return_context: typing.Optional[bool] = pydantic.Field(default=None) - """ - Optionally return context block relevant to the most recent messages. - """ - - strict_ontology: typing.Optional[bool] = pydantic.Field(default=None) - """ - When true, prevents extraction of generic Entity nodes that do not match the configured ontology. - """ - - 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/add_triple_response.py b/src/zep_cloud/types/add_triple_response.py deleted file mode 100644 index 9ad9a994..00000000 --- a/src/zep_cloud/types/add_triple_response.py +++ /dev/null @@ -1,27 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import typing - -import pydantic -from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel -from .entity_edge import EntityEdge -from .entity_node import EntityNode - - -class AddTripleResponse(UniversalBaseModel): - edge: typing.Optional[EntityEdge] = None - source_node: typing.Optional[EntityNode] = None - target_node: typing.Optional[EntityNode] = None - task_id: typing.Optional[str] = pydantic.Field(default=None) - """ - Task ID of the add triple task - """ - - 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/added_node.py b/src/zep_cloud/types/added_node.py deleted file mode 100644 index 096a05eb..00000000 --- a/src/zep_cloud/types/added_node.py +++ /dev/null @@ -1,54 +0,0 @@ -# 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 AddedNode(UniversalBaseModel): - attributes: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = pydantic.Field(default=None) - """ - Additional attributes of the node. - """ - - created_at: typing.Optional[str] = pydantic.Field(default=None) - """ - The node creation time. - """ - - label: typing.Optional[str] = pydantic.Field(default=None) - """ - The node's entity type. - """ - - metadata: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = pydantic.Field(default=None) - """ - Metadata attached to the node's shadow episode. - """ - - name: str = pydantic.Field() - """ - The name of the node. - """ - - summary: typing.Optional[str] = pydantic.Field(default=None) - """ - A regional summary of the node. - """ - - uuid_: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="uuid")] = pydantic.Field(default=None) - """ - The node UUID, assigned by Zep. - """ - - 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/api_error.py b/src/zep_cloud/types/api_error.py index fc8931eb..341bda57 100644 --- a/src/zep_cloud/types/api_error.py +++ b/src/zep_cloud/types/api_error.py @@ -4,10 +4,11 @@ import pydantic from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from .error_body import ErrorBody class ApiError(UniversalBaseModel): - message: typing.Optional[str] = None + error: typing.Optional[ErrorBody] = None if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 diff --git a/src/zep_cloud/types/apidata_batch_add_item_role.py b/src/zep_cloud/types/apidata_batch_add_item_role.py deleted file mode 100644 index 4f51bde1..00000000 --- a/src/zep_cloud/types/apidata_batch_add_item_role.py +++ /dev/null @@ -1,7 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import typing - -ApidataBatchAddItemRole = typing.Union[ - typing.Literal["norole", "system", "assistant", "user", "function", "tool"], typing.Any -] diff --git a/src/zep_cloud/types/apidata_batch_add_item_type.py b/src/zep_cloud/types/apidata_batch_add_item_type.py deleted file mode 100644 index f659edea..00000000 --- a/src/zep_cloud/types/apidata_batch_add_item_type.py +++ /dev/null @@ -1,5 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import typing - -ApidataBatchAddItemType = typing.Union[typing.Literal["graph_episode", "thread_message"], typing.Any] diff --git a/src/zep_cloud/types/artifact_list_request.py b/src/zep_cloud/types/artifact_list_request.py new file mode 100644 index 00000000..722ce371 --- /dev/null +++ b/src/zep_cloud/types/artifact_list_request.py @@ -0,0 +1,19 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel + + +class ArtifactListRequest(UniversalBaseModel): + filters: typing.Optional[typing.Dict[str, typing.Any]] = None + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/zep_cloud/types/success_response.py b/src/zep_cloud/types/async_result.py similarity index 82% rename from src/zep_cloud/types/success_response.py rename to src/zep_cloud/types/async_result.py index 08c507ea..eaa8a12c 100644 --- a/src/zep_cloud/types/success_response.py +++ b/src/zep_cloud/types/async_result.py @@ -4,10 +4,11 @@ import pydantic from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from .task import Task -class SuccessResponse(UniversalBaseModel): - message: typing.Optional[str] = None +class AsyncResult(UniversalBaseModel): + task: typing.Optional[Task] = None if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 diff --git a/src/zep_cloud/types/episode_data.py b/src/zep_cloud/types/batch.py similarity index 51% rename from src/zep_cloud/types/episode_data.py rename to src/zep_cloud/types/batch.py index c17be3d1..7f5429fc 100644 --- a/src/zep_cloud/types/episode_data.py +++ b/src/zep_cloud/types/batch.py @@ -3,20 +3,20 @@ import typing import pydantic +import typing_extensions from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel -from .graph_data_type import GraphDataType +from ..core.serialization import FieldMetadata -class EpisodeData(UniversalBaseModel): +class Batch(UniversalBaseModel): created_at: typing.Optional[str] = None - data: str - metadata: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = pydantic.Field(default=None) - """ - Optional metadata key-value pairs. Max 10 keys. Values must be strings, numbers, booleans, or arrays of scalars. - """ - - source_description: typing.Optional[str] = None - type: GraphDataType + metadata: typing.Optional[typing.Dict[str, typing.Any]] = None + progress: typing.Optional[typing.Dict[str, typing.Any]] = None + status: typing.Optional[str] = None + strict_ontology: typing.Optional[bool] = None + uuid_: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="uuid"), pydantic.Field(alias="uuid") + ] = None if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 diff --git a/src/zep_cloud/types/batch_add_item.py b/src/zep_cloud/types/batch_add_item.py deleted file mode 100644 index a95cb4ab..00000000 --- a/src/zep_cloud/types/batch_add_item.py +++ /dev/null @@ -1,33 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import typing - -import pydantic -from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel -from .apidata_batch_add_item_role import ApidataBatchAddItemRole -from .apidata_batch_add_item_type import ApidataBatchAddItemType -from .graph_data_type import GraphDataType - - -class BatchAddItem(UniversalBaseModel): - content: typing.Optional[str] = None - created_at: typing.Optional[str] = None - data: typing.Optional[str] = None - data_type: typing.Optional[GraphDataType] = None - graph_id: typing.Optional[str] = None - metadata: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = None - name: typing.Optional[str] = None - role: typing.Optional[ApidataBatchAddItemRole] = None - source_description: typing.Optional[str] = None - thread_id: typing.Optional[str] = None - type: ApidataBatchAddItemType - user_id: typing.Optional[str] = None - - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow diff --git a/src/zep_cloud/types/batch_item_detail.py b/src/zep_cloud/types/batch_item_detail.py deleted file mode 100644 index 439cd2fb..00000000 --- a/src/zep_cloud/types/batch_item_detail.py +++ /dev/null @@ -1,41 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import typing - -import pydantic -from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel -from .batch_item_kind import BatchItemKind -from .batch_item_status import BatchItemStatus - - -class BatchItemDetail(UniversalBaseModel): - created_at: 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 - for this batch item. Populated for every item kind and always equal to - SourceUUID — the underlying source row's UUID is reused as the episode - UUID during processing. - """ - - error: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = None - graph_id: typing.Optional[str] = None - graph_uuid: typing.Optional[str] = None - item_id: typing.Optional[str] = None - kind: typing.Optional[BatchItemKind] = None - sequence_index: typing.Optional[int] = None - source_uuid: typing.Optional[str] = None - status: typing.Optional[BatchItemStatus] = None - thread_id: typing.Optional[str] = None - updated_at: typing.Optional[str] = None - user_id: typing.Optional[str] = None - user_uuid: typing.Optional[str] = None - - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow diff --git a/src/zep_cloud/types/batch_item_kind.py b/src/zep_cloud/types/batch_item_kind.py deleted file mode 100644 index 5d08ec0a..00000000 --- a/src/zep_cloud/types/batch_item_kind.py +++ /dev/null @@ -1,5 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import typing - -BatchItemKind = typing.Union[typing.Literal["graph_episode", "thread_message"], typing.Any] diff --git a/src/zep_cloud/types/batch_item_status.py b/src/zep_cloud/types/batch_item_status.py deleted file mode 100644 index 276314d0..00000000 --- a/src/zep_cloud/types/batch_item_status.py +++ /dev/null @@ -1,7 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import typing - -BatchItemStatus = typing.Union[ - typing.Literal["pending", "queued", "processing", "succeeded", "failed", "skipped", "canceled"], typing.Any -] diff --git a/src/zep_cloud/types/batch_items_response.py b/src/zep_cloud/types/batch_items_response.py new file mode 100644 index 00000000..4c71cc97 --- /dev/null +++ b/src/zep_cloud/types/batch_items_response.py @@ -0,0 +1,19 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel + + +class BatchItemsResponse(UniversalBaseModel): + items: typing.Optional[typing.List[typing.Dict[str, typing.Any]]] = None + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/zep_cloud/types/attached_policy_sets_response.py b/src/zep_cloud/types/batch_page.py similarity index 69% rename from src/zep_cloud/types/attached_policy_sets_response.py rename to src/zep_cloud/types/batch_page.py index 6a53fede..b7685aad 100644 --- a/src/zep_cloud/types/attached_policy_sets_response.py +++ b/src/zep_cloud/types/batch_page.py @@ -4,11 +4,13 @@ import pydantic from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel -from .policy_set_summary_response import PolicySetSummaryResponse +from .batch import Batch -class AttachedPolicySetsResponse(UniversalBaseModel): - policy_sets: typing.Optional[typing.List[PolicySetSummaryResponse]] = None +class BatchPage(UniversalBaseModel): + items: typing.Optional[typing.List[Batch]] = None + next_cursor: typing.Optional[str] = None + total_size: typing.Optional[int] = None if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 diff --git a/src/zep_cloud/types/batch_progress.py b/src/zep_cloud/types/batch_progress.py deleted file mode 100644 index 981ff215..00000000 --- a/src/zep_cloud/types/batch_progress.py +++ /dev/null @@ -1,26 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import typing - -import pydantic -from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel - - -class BatchProgress(UniversalBaseModel): - canceled_items: typing.Optional[int] = None - failed_items: typing.Optional[int] = None - percent_complete: typing.Optional[float] = None - processing_items: typing.Optional[int] = None - queued_items: typing.Optional[int] = None - skipped_items: typing.Optional[int] = None - succeeded_items: typing.Optional[int] = None - total_items: typing.Optional[int] = None - - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow diff --git a/src/zep_cloud/types/batch_status.py b/src/zep_cloud/types/batch_status.py deleted file mode 100644 index deacee6b..00000000 --- a/src/zep_cloud/types/batch_status.py +++ /dev/null @@ -1,7 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import typing - -BatchStatus = typing.Union[ - typing.Literal["draft", "invalid", "queued", "processing", "succeeded", "partial", "failed", "canceled"], typing.Any -] diff --git a/src/zep_cloud/types/batch_summary.py b/src/zep_cloud/types/batch_summary.py deleted file mode 100644 index aaf0d40e..00000000 --- a/src/zep_cloud/types/batch_summary.py +++ /dev/null @@ -1,31 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import typing - -import pydantic -from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel -from .batch_progress import BatchProgress -from .batch_status import BatchStatus -from .role_type import RoleType - - -class BatchSummary(UniversalBaseModel): - batch_id: typing.Optional[str] = None - completed_at: typing.Optional[str] = None - created_at: typing.Optional[str] = None - ignore_roles: typing.Optional[typing.List[RoleType]] = None - item_count: typing.Optional[int] = None - metadata: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = None - processed_at: typing.Optional[str] = None - progress: typing.Optional[BatchProgress] = None - status: typing.Optional[BatchStatus] = None - updated_at: typing.Optional[str] = None - - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow diff --git a/src/zep_cloud/types/clone_graph_response.py b/src/zep_cloud/types/clone_graph_response.py deleted file mode 100644 index dec3de27..00000000 --- a/src/zep_cloud/types/clone_graph_response.py +++ /dev/null @@ -1,29 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import typing - -import pydantic -from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel - - -class CloneGraphResponse(UniversalBaseModel): - graph_id: typing.Optional[str] = pydantic.Field(default=None) - """ - graph_id is the ID of the cloned graph - """ - - task_id: typing.Optional[str] = pydantic.Field(default=None) - """ - Task ID of the clone graph task - """ - - user_id: typing.Optional[str] = None - - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow diff --git a/src/zep_cloud/types/clone_graph_result.py b/src/zep_cloud/types/clone_graph_result.py new file mode 100644 index 00000000..3bda3605 --- /dev/null +++ b/src/zep_cloud/types/clone_graph_result.py @@ -0,0 +1,22 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from .graph import Graph +from .task import Task + + +class CloneGraphResult(UniversalBaseModel): + graph: typing.Optional[Graph] = None + task: typing.Optional[Task] = None + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/zep_cloud/types/co_occurrence_detect_config.py b/src/zep_cloud/types/co_occurrence_detect_config.py deleted file mode 100644 index 4bddda33..00000000 --- a/src/zep_cloud/types/co_occurrence_detect_config.py +++ /dev/null @@ -1,22 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import typing - -import pydantic -from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel - - -class CoOccurrenceDetectConfig(UniversalBaseModel): - max_hops: typing.Optional[int] = pydantic.Field(default=None) - """ - Max hops within which to detect co-occurring node types. Default: 3, Max: 5 - """ - - 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/comparison_operator.py b/src/zep_cloud/types/comparison_operator.py deleted file mode 100644 index 8e1df62e..00000000 --- a/src/zep_cloud/types/comparison_operator.py +++ /dev/null @@ -1,7 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import typing - -ComparisonOperator = typing.Union[ - typing.Literal["=", "<>", ">", "<", ">=", "<=", "IS NULL", "is_null", "IS NOT NULL", "CONTAINS"], typing.Any -] diff --git a/src/zep_cloud/types/policy_set_summary_response.py b/src/zep_cloud/types/context_template.py similarity index 68% rename from src/zep_cloud/types/policy_set_summary_response.py rename to src/zep_cloud/types/context_template.py index a8cb071d..dc877f25 100644 --- a/src/zep_cloud/types/policy_set_summary_response.py +++ b/src/zep_cloud/types/context_template.py @@ -8,11 +8,13 @@ from ..core.serialization import FieldMetadata -class PolicySetSummaryResponse(UniversalBaseModel): - mode: typing.Optional[str] = None +class ContextTemplate(UniversalBaseModel): + created_at: typing.Optional[str] = None name: typing.Optional[str] = None - uuid_: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="uuid")] = None - version: typing.Optional[int] = None + template: typing.Optional[str] = None + uuid_: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="uuid"), pydantic.Field(alias="uuid") + ] = None if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 diff --git a/src/zep_cloud/types/context_template_page.py b/src/zep_cloud/types/context_template_page.py new file mode 100644 index 00000000..270fac05 --- /dev/null +++ b/src/zep_cloud/types/context_template_page.py @@ -0,0 +1,22 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from .context_template import ContextTemplate + + +class ContextTemplatePage(UniversalBaseModel): + items: typing.Optional[typing.List[ContextTemplate]] = None + next_cursor: typing.Optional[str] = None + total_size: typing.Optional[int] = None + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/zep_cloud/types/episode_response.py b/src/zep_cloud/types/create_context_template_request.py similarity index 77% rename from src/zep_cloud/types/episode_response.py rename to src/zep_cloud/types/create_context_template_request.py index 8548f0ca..5f81d0af 100644 --- a/src/zep_cloud/types/episode_response.py +++ b/src/zep_cloud/types/create_context_template_request.py @@ -4,11 +4,11 @@ import pydantic from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel -from .episode import Episode -class EpisodeResponse(UniversalBaseModel): - episodes: typing.Optional[typing.List[Episode]] = None +class CreateContextTemplateRequest(UniversalBaseModel): + name: typing.Optional[str] = None + template: typing.Optional[str] = None if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 diff --git a/src/zep_cloud/types/date_filter.py b/src/zep_cloud/types/date_filter.py deleted file mode 100644 index 19ab4222..00000000 --- a/src/zep_cloud/types/date_filter.py +++ /dev/null @@ -1,29 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import typing - -import pydantic -from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel -from .comparison_operator import ComparisonOperator - - -class DateFilter(UniversalBaseModel): - comparison_operator: ComparisonOperator = pydantic.Field() - """ - Comparison operator for date filter - """ - - date: typing.Optional[str] = pydantic.Field(default=None) - """ - Date to filter on. Required for non-null operators (`=`, `<>`, `>`, `<`, `>=`, `<=`). - Should be omitted for IS NULL (or is_null) and IS NOT NULL operators. - """ - - 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/derived_node.py b/src/zep_cloud/types/derived_node.py deleted file mode 100644 index 05b398d8..00000000 --- a/src/zep_cloud/types/derived_node.py +++ /dev/null @@ -1,89 +0,0 @@ -# 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 DerivedNode(UniversalBaseModel): - attributes: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = pydantic.Field(default=None) - """ - Additional attributes of the derived node. - """ - - created_at: str = pydantic.Field() - """ - Creation time of the node - """ - - end_at: typing.Optional[str] = pydantic.Field(default=None) - """ - EndAt is the close timestamp of the evidence window. Set when the - underlying pattern is no longer supported (closed observations); - nil for active observations. - """ - - episode_ids: typing.Optional[typing.List[str]] = pydantic.Field(default=None) - """ - Episode UUIDs that support this observation. Only populated for observation nodes in web API responses. - """ - - labels: typing.Optional[typing.List[str]] = pydantic.Field(default=None) - """ - Labels associated with the node - """ - - latest_evidence_at: typing.Optional[str] = pydantic.Field(default=None) - """ - LatestEvidenceAt is the most recent source-episode timestamp from - which this observation drew evidence. - """ - - name: str = pydantic.Field() - """ - Name of the node - """ - - relevance: typing.Optional[float] = pydantic.Field(default=None) - """ - Relevance is an experimental rank-aligned score in [0,1] derived from Score via logit transformation. - Only populated when using cross_encoder reranker; omitted for other reranker types (e.g., RRF). - """ - - score: typing.Optional[float] = pydantic.Field(default=None) - """ - Score is the reranker output: sigmoid-distributed logits [0,1] when using cross_encoder reranker, or RRF ordinal rank when using rrf reranker - """ - - selection_rank: typing.Optional[int] = pydantic.Field(default=None) - """ - SelectionRank is the global cross-scope rank assigned by auto scope selection. - """ - - start_at: typing.Optional[str] = pydantic.Field(default=None) - """ - StartAt is the earliest source-episode timestamp from which this - observation was derived. Only populated for observation nodes. - """ - - summary: typing.Optional[str] = pydantic.Field(default=None) - """ - Region summary of member nodes - """ - - uuid_: typing_extensions.Annotated[str, FieldMetadata(alias="uuid")] = pydantic.Field() - """ - UUID of the 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/detect_config.py b/src/zep_cloud/types/detect_config.py deleted file mode 100644 index e9a40b4d..00000000 --- a/src/zep_cloud/types/detect_config.py +++ /dev/null @@ -1,47 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import typing - -import pydantic -from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel -from .cluster_detect_config import ClusterDetectConfig -from .co_occurrence_detect_config import CoOccurrenceDetectConfig -from .hub_detect_config import HubDetectConfig -from .path_detect_config import PathDetectConfig -from .relationship_detect_config import RelationshipDetectConfig - - -class DetectConfig(UniversalBaseModel): - clusters: typing.Optional[ClusterDetectConfig] = pydantic.Field(default=None) - """ - Detect tightly interconnected groups (triangle topology) - """ - - co_occurrences: typing.Optional[CoOccurrenceDetectConfig] = pydantic.Field(default=None) - """ - Detect node types that co-occur within k hops - """ - - hubs: typing.Optional[HubDetectConfig] = pydantic.Field(default=None) - """ - Detect highly connected hub nodes (star topology) - """ - - paths: typing.Optional[PathDetectConfig] = pydantic.Field(default=None) - """ - Detect frequent multi-hop connection paths - """ - - relationships: typing.Optional[RelationshipDetectConfig] = pydantic.Field(default=None) - """ - Detect common (source_label, edge_type, target_label) relationship triples - """ - - 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/detect_patterns_response.py b/src/zep_cloud/types/detect_patterns_response.py deleted file mode 100644 index 2cc16689..00000000 --- a/src/zep_cloud/types/detect_patterns_response.py +++ /dev/null @@ -1,35 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import typing - -import pydantic -from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel -from .entity_node import EntityNode -from .pattern_metadata import PatternMetadata -from .pattern_result import PatternResult - - -class DetectPatternsResponse(UniversalBaseModel): - metadata: typing.Optional[PatternMetadata] = pydantic.Field(default=None) - """ - Statistics about the detection run - """ - - nodes: typing.Optional[typing.List[EntityNode]] = pydantic.Field(default=None) - """ - Resolved nodes referenced by pattern edges (deduplicated). Only populated when query is set. - """ - - patterns: typing.Optional[typing.List[PatternResult]] = pydantic.Field(default=None) - """ - Detected patterns, sorted by weighted_score descending - """ - - 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/edge_type.py b/src/zep_cloud/types/edge_type.py deleted file mode 100644 index 4edbe9db..00000000 --- a/src/zep_cloud/types/edge_type.py +++ /dev/null @@ -1,24 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import typing - -import pydantic -from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel -from .entity_edge_source_target import EntityEdgeSourceTarget -from .entity_property import EntityProperty - - -class EdgeType(UniversalBaseModel): - description: str - name: str - properties: typing.Optional[typing.List[EntityProperty]] = None - source_targets: typing.Optional[typing.List[EntityEdgeSourceTarget]] = None - - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow diff --git a/src/zep_cloud/types/entity_edge.py b/src/zep_cloud/types/entity_edge.py deleted file mode 100644 index 91a79a29..00000000 --- a/src/zep_cloud/types/entity_edge.py +++ /dev/null @@ -1,122 +0,0 @@ -# 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 EntityEdge(UniversalBaseModel): - attributes: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = pydantic.Field(default=None) - """ - Additional attributes of the edge. Dependent on edge types - """ - - created_at: str = pydantic.Field() - """ - Creation time of the edge - """ - - episodes: typing.Optional[typing.List[str]] = pydantic.Field(default=None) - """ - List of episode ids that reference these entity edges - """ - - expired_at: typing.Optional[str] = pydantic.Field(default=None) - """ - Datetime of when the node was invalidated - """ - - fact: str = pydantic.Field() - """ - Fact representing the edge and nodes that it connects - """ - - invalid_at: typing.Optional[str] = pydantic.Field(default=None) - """ - Datetime of when the fact stopped being true - """ - - name: str = pydantic.Field() - """ - Name of the edge, relation name - """ - - relevance: typing.Optional[float] = pydantic.Field(default=None) - """ - Relevance is an experimental rank-aligned score in [0,1] derived from Score via logit transformation. - Only populated when using cross_encoder reranker; omitted for other reranker types (e.g., RRF). - """ - - scope: typing.Optional[str] = pydantic.Field(default=None) - """ - Scope of the edge (e.g. "entity", "maybe_related") - """ - - score: typing.Optional[float] = pydantic.Field(default=None) - """ - Score is the reranker output: sigmoid-distributed logits [0,1] when using cross_encoder reranker, or RRF ordinal rank when using rrf reranker - """ - - selection_rank: typing.Optional[int] = pydantic.Field(default=None) - """ - SelectionRank is the global cross-scope rank assigned by auto scope selection. - """ - - source_node_labels: typing.Optional[typing.List[str]] = pydantic.Field(default=None) - """ - SourceNodeLabels are the labels of the source node at read time. Same - read-time-projection semantics as SourceNodeName (spec-2 §4). - """ - - source_node_name: typing.Optional[str] = pydantic.Field(default=None) - """ - SourceNodeName is the name of the source node at read time. It is a - read-time projection of current node state, not a stored edge - attribute: a subsequent node rename is reflected on the next read. - Omitted (the edge is still returned) if the source node cannot be - resolved, for example if it was deleted concurrently (spec-2 §4). - """ - - source_node_uuid: str = pydantic.Field() - """ - UUID of the source node - """ - - target_node_labels: typing.Optional[typing.List[str]] = pydantic.Field(default=None) - """ - TargetNodeLabels are the labels of the target node at read time. Same - read-time-projection semantics as SourceNodeName (spec-2 §4). - """ - - target_node_name: typing.Optional[str] = pydantic.Field(default=None) - """ - TargetNodeName is the name of the target node at read time. Same - read-time-projection semantics as SourceNodeName (spec-2 §4). - """ - - target_node_uuid: str = pydantic.Field() - """ - UUID of the target node - """ - - uuid_: typing_extensions.Annotated[str, FieldMetadata(alias="uuid")] = pydantic.Field() - """ - UUID of the edge - """ - - valid_at: typing.Optional[str] = pydantic.Field(default=None) - """ - Datetime of when the fact became true - """ - - 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_source_target.py b/src/zep_cloud/types/entity_edge_source_target.py deleted file mode 100644 index 496ed396..00000000 --- a/src/zep_cloud/types/entity_edge_source_target.py +++ /dev/null @@ -1,27 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import typing - -import pydantic -from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel - - -class EntityEdgeSourceTarget(UniversalBaseModel): - source: typing.Optional[str] = pydantic.Field(default=None) - """ - Source represents the originating node identifier in the edge type relationship. (optional) - """ - - target: typing.Optional[str] = pydantic.Field(default=None) - """ - Target represents the target node identifier in the edge type relationship. (optional) - """ - - 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_node.py b/src/zep_cloud/types/entity_node.py deleted file mode 100644 index abed7274..00000000 --- a/src/zep_cloud/types/entity_node.py +++ /dev/null @@ -1,65 +0,0 @@ -# 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 EntityNode(UniversalBaseModel): - attributes: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = pydantic.Field(default=None) - """ - Additional attributes of the node. Dependent on node labels - """ - - created_at: str = pydantic.Field() - """ - Creation time of the node - """ - - labels: typing.Optional[typing.List[str]] = pydantic.Field(default=None) - """ - Labels associated with the node - """ - - name: str = pydantic.Field() - """ - Name of the node - """ - - relevance: typing.Optional[float] = pydantic.Field(default=None) - """ - Relevance is an experimental rank-aligned score in [0,1] derived from Score via logit transformation. - Only populated when using cross_encoder reranker; omitted for other reranker types (e.g., RRF). - """ - - score: typing.Optional[float] = pydantic.Field(default=None) - """ - Score is the reranker output: sigmoid-distributed logits [0,1] when using cross_encoder reranker, or RRF ordinal rank when using rrf reranker - """ - - selection_rank: typing.Optional[int] = pydantic.Field(default=None) - """ - SelectionRank is the global cross-scope rank assigned by auto scope selection. - """ - - summary: str = pydantic.Field() - """ - Regional summary of surrounding edges - """ - - uuid_: typing_extensions.Annotated[str, FieldMetadata(alias="uuid")] = pydantic.Field() - """ - UUID of the 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_property_type.py b/src/zep_cloud/types/entity_property_type.py deleted file mode 100644 index 596fa183..00000000 --- a/src/zep_cloud/types/entity_property_type.py +++ /dev/null @@ -1,5 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import typing - -EntityPropertyType = typing.Union[typing.Literal["Text", "Int", "Float", "Boolean"], typing.Any] diff --git a/src/zep_cloud/types/entity_type_response.py b/src/zep_cloud/types/entity_type_response.py deleted file mode 100644 index 43c3032e..00000000 --- a/src/zep_cloud/types/entity_type_response.py +++ /dev/null @@ -1,22 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import typing - -import pydantic -from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel -from .edge_type import EdgeType -from .entity_type import EntityType - - -class EntityTypeResponse(UniversalBaseModel): - edge_types: typing.Optional[typing.List[EdgeType]] = None - entity_types: typing.Optional[typing.List[EntityType]] = None - - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow diff --git a/src/zep_cloud/types/episode.py b/src/zep_cloud/types/episode.py deleted file mode 100644 index fa179eb7..00000000 --- a/src/zep_cloud/types/episode.py +++ /dev/null @@ -1,65 +0,0 @@ -# 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 -from .graph_data_type import GraphDataType -from .role_type import RoleType - - -class Episode(UniversalBaseModel): - content: str - created_at: str - metadata: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = None - processed: typing.Optional[bool] = None - relevance: typing.Optional[float] = pydantic.Field(default=None) - """ - Relevance is an experimental rank-aligned score in [0,1] derived from Score via logit transformation. - Only populated when using cross_encoder reranker; omitted for other reranker types (e.g., RRF). - """ - - role: typing.Optional[str] = pydantic.Field(default=None) - """ - Optional role, will only be present if the episode was created using memory.add API - """ - - role_type: typing.Optional[RoleType] = pydantic.Field(default=None) - """ - Optional role_type, will only be present if the episode was created using memory.add API - """ - - score: typing.Optional[float] = pydantic.Field(default=None) - """ - Score is the reranker output: sigmoid-distributed logits [0,1] when using cross_encoder reranker, or RRF ordinal rank when using rrf reranker - """ - - selection_rank: typing.Optional[int] = pydantic.Field(default=None) - """ - SelectionRank is the global cross-scope rank assigned by auto scope selection. - """ - - source: typing.Optional[GraphDataType] = None - source_description: typing.Optional[str] = None - task_id: typing.Optional[str] = pydantic.Field(default=None) - """ - Optional task ID to poll episode processing status. Currently only available for batch ingestion. - """ - - thread_id: typing.Optional[str] = pydantic.Field(default=None) - """ - Optional thread ID, will be present if the episode is part of a thread - """ - - uuid_: typing_extensions.Annotated[str, FieldMetadata(alias="uuid")] - - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow diff --git a/src/zep_cloud/types/episode_mentions.py b/src/zep_cloud/types/episode_mentions.py deleted file mode 100644 index 9cbcd803..00000000 --- a/src/zep_cloud/types/episode_mentions.py +++ /dev/null @@ -1,22 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import typing - -import pydantic -from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel -from .entity_edge import EntityEdge -from .entity_node import EntityNode - - -class EpisodeMentions(UniversalBaseModel): - edges: typing.Optional[typing.List[EntityEdge]] = None - nodes: typing.Optional[typing.List[EntityNode]] = None - - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow diff --git a/src/zep_cloud/types/episode_metadata_filter.py b/src/zep_cloud/types/episode_metadata_filter.py deleted file mode 100644 index db3c39e6..00000000 --- a/src/zep_cloud/types/episode_metadata_filter.py +++ /dev/null @@ -1,33 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import typing - -import pydantic -from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel -from .comparison_operator import ComparisonOperator - - -class EpisodeMetadataFilter(UniversalBaseModel): - comparison_operator: ComparisonOperator = pydantic.Field() - """ - Comparison operator: =, <>, >, <, >=, <=, IS NULL, IS NOT NULL, IN, CONTAINS - """ - - property_name: str = pydantic.Field() - """ - Metadata key to filter on - """ - - property_value: typing.Optional[typing.Optional[typing.Any]] = pydantic.Field(default=None) - """ - Value to compare against. Not required for IS NULL / IS NOT NULL operators. - """ - - 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/task_error_response.py b/src/zep_cloud/types/error_body.py similarity index 74% rename from src/zep_cloud/types/task_error_response.py rename to src/zep_cloud/types/error_body.py index d138f3f9..7369362f 100644 --- a/src/zep_cloud/types/task_error_response.py +++ b/src/zep_cloud/types/error_body.py @@ -6,10 +6,12 @@ from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel -class TaskErrorResponse(UniversalBaseModel): +class ErrorBody(UniversalBaseModel): code: typing.Optional[str] = None - details: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = None + details: typing.Optional[typing.Dict[str, typing.Any]] = None message: typing.Optional[str] = None + param: typing.Optional[str] = None + request_id: typing.Optional[str] = None if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 diff --git a/src/zep_cloud/types/graph.py b/src/zep_cloud/types/graph.py index dd05ec34..c321f5bc 100644 --- a/src/zep_cloud/types/graph.py +++ b/src/zep_cloud/types/graph.py @@ -12,12 +12,14 @@ class Graph(UniversalBaseModel): created_at: typing.Optional[str] = None description: typing.Optional[str] = None graph_id: typing.Optional[str] = None - id: typing.Optional[int] = None name: typing.Optional[str] = None - project_uuid: typing.Optional[str] = None time_zone: typing.Optional[str] = None + type: typing.Optional[str] = None updated_at: typing.Optional[str] = None - uuid_: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="uuid")] = None + user_uuid: typing.Optional[str] = None + uuid_: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="uuid"), pydantic.Field(alias="uuid") + ] = None if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 diff --git a/src/zep_cloud/types/add_thread_messages_response.py b/src/zep_cloud/types/graph_context_response.py similarity index 76% rename from src/zep_cloud/types/add_thread_messages_response.py rename to src/zep_cloud/types/graph_context_response.py index b5d320e3..8ab64ea3 100644 --- a/src/zep_cloud/types/add_thread_messages_response.py +++ b/src/zep_cloud/types/graph_context_response.py @@ -6,10 +6,10 @@ from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel -class AddThreadMessagesResponse(UniversalBaseModel): +class GraphContextResponse(UniversalBaseModel): context: typing.Optional[str] = None - message_uuids: typing.Optional[typing.List[str]] = None - task_id: typing.Optional[str] = None + results: typing.Optional[typing.Dict[str, typing.Any]] = None + truncated: typing.Optional[bool] = None if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 diff --git a/src/zep_cloud/types/graph_data_type.py b/src/zep_cloud/types/graph_data_type.py deleted file mode 100644 index 8797795a..00000000 --- a/src/zep_cloud/types/graph_data_type.py +++ /dev/null @@ -1,5 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import typing - -GraphDataType = typing.Union[typing.Literal["text", "json", "message", "fact_triple"], typing.Any] diff --git a/src/zep_cloud/types/observation_type.py b/src/zep_cloud/types/graph_delete_result.py similarity index 81% rename from src/zep_cloud/types/observation_type.py rename to src/zep_cloud/types/graph_delete_result.py index 14166bfa..0c10eb61 100644 --- a/src/zep_cloud/types/observation_type.py +++ b/src/zep_cloud/types/graph_delete_result.py @@ -4,11 +4,11 @@ import pydantic from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from .task import Task -class ObservationType(UniversalBaseModel): - description: str - name: str +class GraphDeleteResult(UniversalBaseModel): + task: typing.Optional[Task] = None if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 diff --git a/src/zep_cloud/types/graph_edges_request.py b/src/zep_cloud/types/graph_edges_request.py deleted file mode 100644 index 77cc19a8..00000000 --- a/src/zep_cloud/types/graph_edges_request.py +++ /dev/null @@ -1,58 +0,0 @@ -# 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, update_forward_refs -from .search_filters import SearchFilters - - -class GraphEdgesRequest(UniversalBaseModel): - cursor: typing.Optional[str] = pydantic.Field(default=None) - """ - Opaque cursor for pagination, obtained from the Zep-Next-Cursor response header - of the previous page. Encodes the sort field, direction, and continuation position. - """ - - direction: typing.Optional[str] = pydantic.Field(default=None) - """ - Sort direction. One of "asc" or "desc" (default "desc"). - """ - - filters: typing.Optional[SearchFilters] = pydantic.Field(default=None) - """ - Optional filters applied to the listed artifacts. Reuses the graph.search filter type. - """ - - limit: typing.Optional[int] = pydantic.Field(default=None) - """ - Maximum number of items to return - """ - - order_by: typing.Optional[str] = pydantic.Field(default=None) - """ - Field to sort by. One of "created_at", "valid_at", or "uuid" (default "uuid"). - """ - - uuid_cursor: typing.Optional[str] = pydantic.Field(default=None) - """ - 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. - """ - - 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 - - -from .metadata_filter_group import MetadataFilterGroup # noqa: E402, F401, I001 - -update_forward_refs(GraphEdgesRequest) diff --git a/src/zep_cloud/types/graph_episode_list_request.py b/src/zep_cloud/types/graph_episode_list_request.py deleted file mode 100644 index e7bd251d..00000000 --- a/src/zep_cloud/types/graph_episode_list_request.py +++ /dev/null @@ -1,45 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import typing - -import pydantic -from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel - - -class GraphEpisodeListRequest(UniversalBaseModel): - cursor: typing.Optional[str] = pydantic.Field(default=None) - """ - Opaque cursor for pagination, obtained from the Zep-Next-Cursor - response header of the previous page. - """ - - direction: typing.Optional[str] = pydantic.Field(default=None) - """ - Sort direction. One of "asc" or "desc". Defaults to "desc". - """ - - limit: typing.Optional[int] = pydantic.Field(default=None) - """ - Maximum number of episodes to return. An explicit value is clamped to - 50; when omitted, the default page size (100) applies. - """ - - mentioned_node_uuids: typing.Optional[typing.List[str]] = pydantic.Field(default=None) - """ - Restricts results to episodes that mention any of the listed node - UUIDs. At most 256 entries; each must be a syntactically valid UUID. - """ - - order_by: typing.Optional[str] = pydantic.Field(default=None) - """ - Field to sort by. One of "uuid" or "created_at". Defaults to "uuid". - """ - - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow diff --git a/src/zep_cloud/types/graph_list_response.py b/src/zep_cloud/types/graph_list_response.py deleted file mode 100644 index eab1a25d..00000000 --- a/src/zep_cloud/types/graph_list_response.py +++ /dev/null @@ -1,24 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import typing - -import pydantic -from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel -from .graph import Graph - - -class GraphListResponse(UniversalBaseModel): - graphs: typing.Optional[typing.List[Graph]] = None - page_number: typing.Optional[int] = None - page_size: typing.Optional[int] = None - row_count: typing.Optional[int] = None - total_count: typing.Optional[int] = None - - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow diff --git a/src/zep_cloud/types/graph_node_neighbor.py b/src/zep_cloud/types/graph_node_neighbor.py deleted file mode 100644 index 22e1f369..00000000 --- a/src/zep_cloud/types/graph_node_neighbor.py +++ /dev/null @@ -1,22 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import typing - -import pydantic -from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel -from .entity_edge import EntityEdge -from .entity_node import EntityNode - - -class GraphNodeNeighbor(UniversalBaseModel): - edges: typing.Optional[typing.List[EntityEdge]] = None - node: typing.Optional[EntityNode] = None - - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow diff --git a/src/zep_cloud/types/graph_nodes_request.py b/src/zep_cloud/types/graph_nodes_request.py deleted file mode 100644 index e74a760f..00000000 --- a/src/zep_cloud/types/graph_nodes_request.py +++ /dev/null @@ -1,58 +0,0 @@ -# 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, update_forward_refs -from .search_filters import SearchFilters - - -class GraphNodesRequest(UniversalBaseModel): - cursor: typing.Optional[str] = pydantic.Field(default=None) - """ - Opaque cursor for pagination, obtained from the Zep-Next-Cursor response header - of the previous page. Encodes the sort field, direction, and continuation position. - """ - - direction: typing.Optional[str] = pydantic.Field(default=None) - """ - Sort direction. One of "asc" or "desc" (default "desc"). - """ - - filters: typing.Optional[SearchFilters] = pydantic.Field(default=None) - """ - Optional filters applied to the listed artifacts. Reuses the graph.search filter type. - """ - - limit: typing.Optional[int] = pydantic.Field(default=None) - """ - Maximum number of items to return - """ - - order_by: typing.Optional[str] = pydantic.Field(default=None) - """ - Field to sort by. One of "created_at", "valid_at", or "uuid" (default "uuid"). - """ - - uuid_cursor: typing.Optional[str] = pydantic.Field(default=None) - """ - 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. - """ - - 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 - - -from .metadata_filter_group import MetadataFilterGroup # noqa: E402, F401, I001 - -update_forward_refs(GraphNodesRequest) diff --git a/src/zep_cloud/types/graph_observations_request.py b/src/zep_cloud/types/graph_observations_request.py deleted file mode 100644 index 21f81b7e..00000000 --- a/src/zep_cloud/types/graph_observations_request.py +++ /dev/null @@ -1,58 +0,0 @@ -# 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, update_forward_refs -from .search_filters import SearchFilters - - -class GraphObservationsRequest(UniversalBaseModel): - cursor: typing.Optional[str] = pydantic.Field(default=None) - """ - Opaque cursor for pagination, obtained from the Zep-Next-Cursor response header - of the previous page. Encodes the sort field, direction, and continuation position. - """ - - direction: typing.Optional[str] = pydantic.Field(default=None) - """ - Sort direction. One of "asc" or "desc" (default "desc"). - """ - - filters: typing.Optional[SearchFilters] = pydantic.Field(default=None) - """ - Optional filters applied to the listed artifacts. Reuses the graph.search filter type. - """ - - limit: typing.Optional[int] = pydantic.Field(default=None) - """ - Maximum number of items to return - """ - - order_by: typing.Optional[str] = pydantic.Field(default=None) - """ - Field to sort by. One of "created_at", "valid_at", or "uuid" (default "uuid"). - """ - - uuid_cursor: typing.Optional[str] = pydantic.Field(default=None) - """ - 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. - """ - - 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 - - -from .metadata_filter_group import MetadataFilterGroup # noqa: E402, F401, I001 - -update_forward_refs(GraphObservationsRequest) diff --git a/src/zep_cloud/types/batch_item_list_response.py b/src/zep_cloud/types/graph_page.py similarity index 69% rename from src/zep_cloud/types/batch_item_list_response.py rename to src/zep_cloud/types/graph_page.py index b082dcea..acc12f5b 100644 --- a/src/zep_cloud/types/batch_item_list_response.py +++ b/src/zep_cloud/types/graph_page.py @@ -4,12 +4,13 @@ import pydantic from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel -from .batch_item_detail import BatchItemDetail +from .graph import Graph -class BatchItemListResponse(UniversalBaseModel): - items: typing.Optional[typing.List[BatchItemDetail]] = None - next_cursor: typing.Optional[int] = None +class GraphPage(UniversalBaseModel): + items: typing.Optional[typing.List[Graph]] = None + next_cursor: typing.Optional[str] = None + total_size: typing.Optional[int] = None if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 diff --git a/src/zep_cloud/types/graph_search_response_metadata.py b/src/zep_cloud/types/graph_search_response_metadata.py deleted file mode 100644 index 0e173e1d..00000000 --- a/src/zep_cloud/types/graph_search_response_metadata.py +++ /dev/null @@ -1,22 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import typing - -import pydantic -from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel - - -class GraphSearchResponseMetadata(UniversalBaseModel): - server_latency_ms: typing.Optional[int] = pydantic.Field(default=None) - """ - Server-side processing latency in milliseconds. - """ - - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow diff --git a/src/zep_cloud/types/graph_search_results.py b/src/zep_cloud/types/graph_search_results.py deleted file mode 100644 index ec1273ae..00000000 --- a/src/zep_cloud/types/graph_search_results.py +++ /dev/null @@ -1,31 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import typing - -import pydantic -from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel -from .derived_node import DerivedNode -from .entity_edge import EntityEdge -from .entity_node import EntityNode -from .episode import Episode -from .graph_search_response_metadata import GraphSearchResponseMetadata -from .graphiti_saga_node import GraphitiSagaNode - - -class GraphSearchResults(UniversalBaseModel): - context: typing.Optional[str] = None - edges: typing.Optional[typing.List[EntityEdge]] = None - episodes: typing.Optional[typing.List[Episode]] = None - nodes: typing.Optional[typing.List[EntityNode]] = None - observations: typing.Optional[typing.List[DerivedNode]] = None - response: typing.Optional[GraphSearchResponseMetadata] = None - thread_summaries: typing.Optional[typing.List[GraphitiSagaNode]] = None - - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow diff --git a/src/zep_cloud/types/graph_search_scope.py b/src/zep_cloud/types/graph_search_scope.py deleted file mode 100644 index 3f117827..00000000 --- a/src/zep_cloud/types/graph_search_scope.py +++ /dev/null @@ -1,7 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import typing - -GraphSearchScope = typing.Union[ - typing.Literal["edges", "nodes", "episodes", "thread_summaries", "observations", "auto"], typing.Any -] diff --git a/src/zep_cloud/types/graph_subgraph_response.py b/src/zep_cloud/types/graph_subgraph_response.py deleted file mode 100644 index 8be98728..00000000 --- a/src/zep_cloud/types/graph_subgraph_response.py +++ /dev/null @@ -1,41 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import typing - -import pydantic -from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel -from .entity_edge import EntityEdge -from .entity_node import EntityNode - - -class GraphSubgraphResponse(UniversalBaseModel): - edges: typing.Optional[typing.List[EntityEdge]] = pydantic.Field(default=None) - """ - Every traversed edge that passed the request filters. Both endpoints - of every edge are present in Nodes (edge-endpoint closure). - """ - - nodes: typing.Optional[typing.List[EntityNode]] = pydantic.Field(default=None) - """ - Every admitted seed and every node reached within budget. - """ - - truncated: typing.Optional[bool] = pydantic.Field(default=None) - """ - True whenever any budget or internal limit reduced the result. - """ - - truncation_reason: typing.Optional[str] = pydantic.Field(default=None) - """ - Names the binding limit (for example "max_nodes", "max_edges") when - Truncated is true; nil otherwise. - """ - - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow diff --git a/src/zep_cloud/types/graph_thread_summaries_request.py b/src/zep_cloud/types/graph_thread_summaries_request.py deleted file mode 100644 index 0f835d73..00000000 --- a/src/zep_cloud/types/graph_thread_summaries_request.py +++ /dev/null @@ -1,58 +0,0 @@ -# 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, update_forward_refs -from .search_filters import SearchFilters - - -class GraphThreadSummariesRequest(UniversalBaseModel): - cursor: typing.Optional[str] = pydantic.Field(default=None) - """ - Opaque cursor for pagination, obtained from the Zep-Next-Cursor response header - of the previous page. Encodes the sort field, direction, and continuation position. - """ - - direction: typing.Optional[str] = pydantic.Field(default=None) - """ - Sort direction. One of "asc" or "desc" (default "desc"). - """ - - filters: typing.Optional[SearchFilters] = pydantic.Field(default=None) - """ - Optional filters applied to the listed artifacts. Reuses the graph.search filter type. - """ - - limit: typing.Optional[int] = pydantic.Field(default=None) - """ - Maximum number of items to return - """ - - order_by: typing.Optional[str] = pydantic.Field(default=None) - """ - Field to sort by. One of "created_at", "valid_at", or "uuid" (default "uuid"). - """ - - uuid_cursor: typing.Optional[str] = pydantic.Field(default=None) - """ - 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. - """ - - 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 - - -from .metadata_filter_group import MetadataFilterGroup # noqa: E402, F401, I001 - -update_forward_refs(GraphThreadSummariesRequest) diff --git a/src/zep_cloud/types/graphiti_metadata_filter_group_type.py b/src/zep_cloud/types/graphiti_metadata_filter_group_type.py deleted file mode 100644 index c788e943..00000000 --- a/src/zep_cloud/types/graphiti_metadata_filter_group_type.py +++ /dev/null @@ -1,5 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import typing - -GraphitiMetadataFilterGroupType = typing.Union[typing.Literal["and", "or"], typing.Any] diff --git a/src/zep_cloud/types/graphiti_saga_node.py b/src/zep_cloud/types/graphiti_saga_node.py deleted file mode 100644 index 739d35a6..00000000 --- a/src/zep_cloud/types/graphiti_saga_node.py +++ /dev/null @@ -1,73 +0,0 @@ -# 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 GraphitiSagaNode(UniversalBaseModel): - created_at: str = pydantic.Field() - """ - Creation time of the node - """ - - labels: typing.Optional[typing.List[str]] = pydantic.Field(default=None) - """ - Labels associated with the node - """ - - last_summarized_at: typing.Optional[str] = pydantic.Field(default=None) - """ - Wall-clock timestamp of the most recent summary update. Used internally - as the watermark for filtering new episodes by ingestion time. - """ - - last_summarized_episode_valid_at: typing.Optional[str] = pydantic.Field(default=None) - """ - Maximum episode reference time (valid_at) covered by the most recent - summary. Use this field — not LastSummarizedAt — when answering "how - recent is this summary's content in event-time?". - """ - - name: str = pydantic.Field() - """ - Name of the node - """ - - relevance: typing.Optional[float] = pydantic.Field(default=None) - """ - Relevance is an experimental rank-aligned score in [0,1] derived from Score via logit transformation. - Only populated when using cross_encoder reranker; omitted for other reranker types (e.g., RRF). - """ - - score: typing.Optional[float] = pydantic.Field(default=None) - """ - Score is the reranker output: sigmoid-distributed logits [0,1] when using cross_encoder reranker, or RRF ordinal rank when using rrf reranker - """ - - selection_rank: typing.Optional[int] = pydantic.Field(default=None) - """ - SelectionRank is the global cross-scope rank assigned by auto scope selection. - """ - - summary: typing.Optional[str] = pydantic.Field(default=None) - """ - Incremental summary of the thread. - """ - - uuid_: typing_extensions.Annotated[str, FieldMetadata(alias="uuid")] = pydantic.Field() - """ - UUID of the 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/hub_detect_config.py b/src/zep_cloud/types/hub_detect_config.py deleted file mode 100644 index ca45f15d..00000000 --- a/src/zep_cloud/types/hub_detect_config.py +++ /dev/null @@ -1,22 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import typing - -import pydantic -from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel - - -class HubDetectConfig(UniversalBaseModel): - min_degree: typing.Optional[int] = pydantic.Field(default=None) - """ - Minimum number of connections for a node to be considered a hub. Default: 3, Min: 2 - """ - - 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/instructions.py b/src/zep_cloud/types/instructions.py new file mode 100644 index 00000000..a308ddc6 --- /dev/null +++ b/src/zep_cloud/types/instructions.py @@ -0,0 +1,20 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel + + +class Instructions(UniversalBaseModel): + inherited: typing.Optional[bool] = None + instructions: typing.Optional[typing.List[typing.Dict[str, typing.Any]]] = None + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/zep_cloud/types/cluster_detect_config.py b/src/zep_cloud/types/json_object.py similarity index 54% rename from src/zep_cloud/types/cluster_detect_config.py rename to src/zep_cloud/types/json_object.py index fa051315..73a4701b 100644 --- a/src/zep_cloud/types/cluster_detect_config.py +++ b/src/zep_cloud/types/json_object.py @@ -2,4 +2,4 @@ import typing -ClusterDetectConfig = typing.Dict[str, typing.Optional[typing.Any]] +JsonObject = typing.Dict[str, typing.Any] diff --git a/src/zep_cloud/types/json_object_page.py b/src/zep_cloud/types/json_object_page.py new file mode 100644 index 00000000..93c8942a --- /dev/null +++ b/src/zep_cloud/types/json_object_page.py @@ -0,0 +1,22 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from .json_object import JsonObject + + +class JsonObjectPage(UniversalBaseModel): + items: typing.Optional[typing.List[JsonObject]] = None + next_cursor: typing.Optional[str] = None + total_size: typing.Optional[int] = None + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/zep_cloud/types/list_context_templates_response.py b/src/zep_cloud/types/list_context_templates_response.py deleted file mode 100644 index 8b185456..00000000 --- a/src/zep_cloud/types/list_context_templates_response.py +++ /dev/null @@ -1,20 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import typing - -import pydantic -from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel -from .context_template_response import ContextTemplateResponse - - -class ListContextTemplatesResponse(UniversalBaseModel): - templates: typing.Optional[typing.List[ContextTemplateResponse]] = None - - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow diff --git a/src/zep_cloud/types/lookup_batch_response.py b/src/zep_cloud/types/lookup_batch_response.py new file mode 100644 index 00000000..3aff393d --- /dev/null +++ b/src/zep_cloud/types/lookup_batch_response.py @@ -0,0 +1,20 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from .lookup_item import LookupItem + + +class LookupBatchResponse(UniversalBaseModel): + items: typing.Optional[typing.List[LookupItem]] = None + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/zep_cloud/types/lookup_item.py b/src/zep_cloud/types/lookup_item.py new file mode 100644 index 00000000..20775236 --- /dev/null +++ b/src/zep_cloud/types/lookup_item.py @@ -0,0 +1,26 @@ +# 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 LookupItem(UniversalBaseModel): + found: typing.Optional[bool] = None + legacy_id: typing.Optional[str] = None + resource_type: typing.Optional[str] = None + uuid_: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="uuid"), pydantic.Field(alias="uuid") + ] = None + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/zep_cloud/types/lookup_request.py b/src/zep_cloud/types/lookup_request.py new file mode 100644 index 00000000..6783e396 --- /dev/null +++ b/src/zep_cloud/types/lookup_request.py @@ -0,0 +1,21 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel + + +class LookupRequest(UniversalBaseModel): + graph_id: typing.Optional[str] = None + thread_id: typing.Optional[str] = None + user_id: typing.Optional[str] = None + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/zep_cloud/types/message.py b/src/zep_cloud/types/message.py index 6fa51810..4cb810fd 100644 --- a/src/zep_cloud/types/message.py +++ b/src/zep_cloud/types/message.py @@ -6,44 +6,19 @@ import typing_extensions from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel from ..core.serialization import FieldMetadata -from .role_type import RoleType class Message(UniversalBaseModel): - content: str = pydantic.Field() - """ - The content of the message. - """ - - created_at: typing.Optional[str] = pydantic.Field(default=None) - """ - The timestamp of when the message was created. - """ - - metadata: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = pydantic.Field(default=None) - """ - The metadata associated with the message. - """ - - name: typing.Optional[str] = pydantic.Field(default=None) - """ - Customizable name of the sender of the message (e.g., "john", "sales_agent"). - """ - - processed: typing.Optional[bool] = pydantic.Field(default=None) - """ - Whether the message has been processed. - """ - - role: RoleType = pydantic.Field() - """ - The role of message sender (e.g., "user", "system"). - """ - - uuid_: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="uuid")] = pydantic.Field(default=None) - """ - The unique identifier of the message. - """ + content: typing.Optional[str] = None + created_at: typing.Optional[str] = None + metadata: typing.Optional[typing.Dict[str, typing.Any]] = None + name: typing.Optional[str] = None + processed: typing.Optional[bool] = None + role: typing.Optional[str] = None + thread_uuid: typing.Optional[str] = None + uuid_: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="uuid"), pydantic.Field(alias="uuid") + ] = None if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 diff --git a/src/zep_cloud/types/message_list_response.py b/src/zep_cloud/types/message_list_response.py deleted file mode 100644 index 0e6edb3e..00000000 --- a/src/zep_cloud/types/message_list_response.py +++ /dev/null @@ -1,48 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import typing - -import pydantic -from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel -from .message import Message - - -class MessageListResponse(UniversalBaseModel): - messages: typing.Optional[typing.List[Message]] = pydantic.Field(default=None) - """ - A list of message objects. - """ - - row_count: typing.Optional[int] = pydantic.Field(default=None) - """ - The number of messages returned. - """ - - thread_created_at: typing.Optional[str] = pydantic.Field(default=None) - """ - The thread creation timestamp. - """ - - total_count: typing.Optional[int] = pydantic.Field(default=None) - """ - The total number of messages. - """ - - user_id: typing.Optional[str] = pydantic.Field(default=None) - """ - The user ID associated with this thread. - """ - - user_uuid: typing.Optional[str] = pydantic.Field(default=None) - """ - The opaque user identifier used by dashboard routes. - """ - - 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/message_page.py b/src/zep_cloud/types/message_page.py new file mode 100644 index 00000000..7da041cb --- /dev/null +++ b/src/zep_cloud/types/message_page.py @@ -0,0 +1,22 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from .message import Message + + +class MessagePage(UniversalBaseModel): + items: typing.Optional[typing.List[Message]] = None + next_cursor: typing.Optional[str] = None + total_size: typing.Optional[int] = None + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/zep_cloud/types/metadata_filter_group.py b/src/zep_cloud/types/metadata_filter_group.py deleted file mode 100644 index 4c662e35..00000000 --- a/src/zep_cloud/types/metadata_filter_group.py +++ /dev/null @@ -1,39 +0,0 @@ -# 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, update_forward_refs -from .episode_metadata_filter import EpisodeMetadataFilter -from .graphiti_metadata_filter_group_type import GraphitiMetadataFilterGroupType - - -class MetadataFilterGroup(UniversalBaseModel): - filters: typing.Optional[typing.List[EpisodeMetadataFilter]] = pydantic.Field(default=None) - """ - Leaf filters (predicates on metadata key-value pairs) - """ - - groups: typing.Optional[typing.List["MetadataFilterGroup"]] = pydantic.Field(default=None) - """ - Nested sub-groups for composing complex boolean expressions - """ - - type: GraphitiMetadataFilterGroupType = pydantic.Field() - """ - Logical operator: "and" or "or" - """ - - 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 - - -update_forward_refs(MetadataFilterGroup) diff --git a/src/zep_cloud/types/neighbor_entry.py b/src/zep_cloud/types/neighbor_entry.py new file mode 100644 index 00000000..8a548e54 --- /dev/null +++ b/src/zep_cloud/types/neighbor_entry.py @@ -0,0 +1,20 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel + + +class NeighborEntry(UniversalBaseModel): + edges: typing.Optional[typing.List[typing.Dict[str, typing.Any]]] = None + node: typing.Optional[typing.Dict[str, typing.Any]] = None + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/zep_cloud/types/neighbor_page.py b/src/zep_cloud/types/neighbor_page.py new file mode 100644 index 00000000..e353facc --- /dev/null +++ b/src/zep_cloud/types/neighbor_page.py @@ -0,0 +1,22 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from .neighbor_entry import NeighborEntry + + +class NeighborPage(UniversalBaseModel): + items: typing.Optional[typing.List[NeighborEntry]] = None + next_cursor: typing.Optional[str] = None + total_size: typing.Optional[int] = None + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/zep_cloud/types/observation_steering_config.py b/src/zep_cloud/types/observation_steering.py similarity index 75% rename from src/zep_cloud/types/observation_steering_config.py rename to src/zep_cloud/types/observation_steering.py index ad1d41df..f82f1abd 100644 --- a/src/zep_cloud/types/observation_steering_config.py +++ b/src/zep_cloud/types/observation_steering.py @@ -4,12 +4,12 @@ import pydantic from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel -from .observation_type import ObservationType -class ObservationSteeringConfig(UniversalBaseModel): +class ObservationSteering(UniversalBaseModel): + inherited: typing.Optional[bool] = None instruction: typing.Optional[str] = None - types: typing.Optional[typing.List[ObservationType]] = None + types: typing.Optional[typing.List[typing.Dict[str, typing.Any]]] = None if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 diff --git a/src/zep_cloud/types/ontology.py b/src/zep_cloud/types/ontology.py new file mode 100644 index 00000000..cc2f6d31 --- /dev/null +++ b/src/zep_cloud/types/ontology.py @@ -0,0 +1,21 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel + + +class Ontology(UniversalBaseModel): + edge_types: typing.Optional[typing.List[typing.Dict[str, typing.Any]]] = None + entity_types: typing.Optional[typing.List[typing.Dict[str, typing.Any]]] = None + inherited: typing.Optional[bool] = None + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/zep_cloud/types/path_detect_config.py b/src/zep_cloud/types/path_detect_config.py deleted file mode 100644 index e5921b09..00000000 --- a/src/zep_cloud/types/path_detect_config.py +++ /dev/null @@ -1,22 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import typing - -import pydantic -from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel - - -class PathDetectConfig(UniversalBaseModel): - max_hops: typing.Optional[int] = pydantic.Field(default=None) - """ - Max hops from seed nodes for path detection. Default: 3, Max: 5 - """ - - 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/pattern_metadata.py b/src/zep_cloud/types/pattern_metadata.py deleted file mode 100644 index cfc36bdd..00000000 --- a/src/zep_cloud/types/pattern_metadata.py +++ /dev/null @@ -1,32 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import typing - -import pydantic -from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel - - -class PatternMetadata(UniversalBaseModel): - edges_analyzed: typing.Optional[int] = pydantic.Field(default=None) - """ - Number of edges analyzed - """ - - elapsed_ms: typing.Optional[int] = pydantic.Field(default=None) - """ - Elapsed time in milliseconds - """ - - nodes_analyzed: typing.Optional[int] = pydantic.Field(default=None) - """ - Number of unique nodes analyzed - """ - - 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/pattern_result.py b/src/zep_cloud/types/pattern_result.py deleted file mode 100644 index d6beb767..00000000 --- a/src/zep_cloud/types/pattern_result.py +++ /dev/null @@ -1,63 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import typing - -import pydantic -from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel -from .entity_edge import EntityEdge - - -class PatternResult(UniversalBaseModel): - description: typing.Optional[str] = pydantic.Field(default=None) - """ - Human-readable structural description of the pattern (e.g. "Person -[KNOWS]-> Person"). - Omitted in query mode in favor of Summary. - """ - - edge_types: typing.Optional[typing.List[str]] = pydantic.Field(default=None) - """ - Edge types in the pattern structure - """ - - edges: typing.Optional[typing.List[EntityEdge]] = pydantic.Field(default=None) - """ - Resolved edges for this pattern, sorted by cross-encoder relevance. - Only populated when query is set. - """ - - node_labels: typing.Optional[typing.List[str]] = pydantic.Field(default=None) - """ - Node labels in the pattern structure - """ - - occurrences: typing.Optional[int] = pydantic.Field(default=None) - """ - Raw structural occurrence count (always unweighted). - Reflects pattern frequency in the graph, not the number of resolved edges after filtering. - """ - - summary: typing.Optional[str] = pydantic.Field(default=None) - """ - Fact-derived summary from top reranked edges. Only populated when query is set. - This is the primary display field for QA consumers. - """ - - type: typing.Optional[str] = pydantic.Field(default=None) - """ - Pattern type: relationship, path, co_occurrence, hub, cluster - """ - - weighted_score: typing.Optional[float] = pydantic.Field(default=None) - """ - Weighted structural support — equals occurrences when recency_weight is "none". - Reflects graph-level support, not post-enrichment edge count. - """ - - 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/pattern_seeds.py b/src/zep_cloud/types/pattern_seeds.py deleted file mode 100644 index 40b43a4d..00000000 --- a/src/zep_cloud/types/pattern_seeds.py +++ /dev/null @@ -1,32 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import typing - -import pydantic -from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel - - -class PatternSeeds(UniversalBaseModel): - edge_types: typing.Optional[typing.List[str]] = pydantic.Field(default=None) - """ - All endpoints of these edge types become seeds - """ - - node_labels: typing.Optional[typing.List[str]] = pydantic.Field(default=None) - """ - All nodes with these labels become seeds - """ - - node_uuids: typing.Optional[typing.List[str]] = pydantic.Field(default=None) - """ - Specific node UUIDs to analyze around. Max 10000 to align with pattern detection seed limits. - """ - - 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/list_user_instructions_response.py b/src/zep_cloud/types/process_batch_result.py similarity index 72% rename from src/zep_cloud/types/list_user_instructions_response.py rename to src/zep_cloud/types/process_batch_result.py index b8b27f27..3930882b 100644 --- a/src/zep_cloud/types/list_user_instructions_response.py +++ b/src/zep_cloud/types/process_batch_result.py @@ -4,11 +4,13 @@ import pydantic from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel -from .user_instruction import UserInstruction +from .batch import Batch +from .task import Task -class ListUserInstructionsResponse(UniversalBaseModel): - instructions: typing.Optional[typing.List[UserInstruction]] = None +class ProcessBatchResult(UniversalBaseModel): + batch: typing.Optional[Batch] = None + task: typing.Optional[Task] = None if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 diff --git a/src/zep_cloud/types/project_info.py b/src/zep_cloud/types/project.py similarity index 80% rename from src/zep_cloud/types/project_info.py rename to src/zep_cloud/types/project.py index 86efb2c3..9b82f0b2 100644 --- a/src/zep_cloud/types/project_info.py +++ b/src/zep_cloud/types/project.py @@ -8,12 +8,14 @@ from ..core.serialization import FieldMetadata -class ProjectInfo(UniversalBaseModel): +class Project(UniversalBaseModel): created_at: typing.Optional[str] = None default_time_zone: typing.Optional[str] = None description: typing.Optional[str] = None name: typing.Optional[str] = None - uuid_: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="uuid")] = None + uuid_: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="uuid"), pydantic.Field(alias="uuid") + ] = None if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 diff --git a/src/zep_cloud/types/project_info_response.py b/src/zep_cloud/types/project_info_response.py deleted file mode 100644 index fff68af8..00000000 --- a/src/zep_cloud/types/project_info_response.py +++ /dev/null @@ -1,20 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import typing - -import pydantic -from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel -from .project_info import ProjectInfo - - -class ProjectInfoResponse(UniversalBaseModel): - project: typing.Optional[ProjectInfo] = None - - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow diff --git a/src/zep_cloud/types/property_filter.py b/src/zep_cloud/types/property_filter.py deleted file mode 100644 index eda06aad..00000000 --- a/src/zep_cloud/types/property_filter.py +++ /dev/null @@ -1,35 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import typing - -import pydantic -from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel -from .comparison_operator import ComparisonOperator - - -class PropertyFilter(UniversalBaseModel): - comparison_operator: ComparisonOperator = pydantic.Field() - """ - Comparison operator for property filter - """ - - property_name: str = pydantic.Field() - """ - Property name to filter on - """ - - property_value: typing.Optional[typing.Optional[typing.Any]] = pydantic.Field(default=None) - """ - Property value to match on. Accepted types: string, int, float64, bool, or nil. - Invalid types (e.g., arrays, objects) will be rejected by validation. - Must be non-nil for non-null operators (`=`, `<>`, `>`, `<`, `>=`, `<=`). - """ - - 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/recency_weight.py b/src/zep_cloud/types/recency_weight.py deleted file mode 100644 index 18d33ada..00000000 --- a/src/zep_cloud/types/recency_weight.py +++ /dev/null @@ -1,5 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import typing - -RecencyWeight = typing.Union[typing.Literal["none", "7_days", "30_days", "90_days"], typing.Any] diff --git a/src/zep_cloud/types/relationship_detect_config.py b/src/zep_cloud/types/relationship_detect_config.py deleted file mode 100644 index 6339bd36..00000000 --- a/src/zep_cloud/types/relationship_detect_config.py +++ /dev/null @@ -1,5 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import typing - -RelationshipDetectConfig = typing.Dict[str, typing.Optional[typing.Any]] diff --git a/src/zep_cloud/types/reranker.py b/src/zep_cloud/types/reranker.py deleted file mode 100644 index 4a627b5e..00000000 --- a/src/zep_cloud/types/reranker.py +++ /dev/null @@ -1,5 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import typing - -Reranker = typing.Union[typing.Literal["rrf", "mmr", "node_distance", "episode_mentions", "cross_encoder"], typing.Any] diff --git a/src/zep_cloud/types/role_type.py b/src/zep_cloud/types/role_type.py deleted file mode 100644 index f7658d6a..00000000 --- a/src/zep_cloud/types/role_type.py +++ /dev/null @@ -1,5 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import typing - -RoleType = typing.Union[typing.Literal["norole", "system", "assistant", "user", "function", "tool"], typing.Any] diff --git a/src/zep_cloud/types/search_filters.py b/src/zep_cloud/types/search_filters.py deleted file mode 100644 index 50954d04..00000000 --- a/src/zep_cloud/types/search_filters.py +++ /dev/null @@ -1,127 +0,0 @@ -# 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, update_forward_refs -from .date_filter import DateFilter -from .property_filter import PropertyFilter - - -class SearchFilters(UniversalBaseModel): - connected_node_uuids: typing.Optional[typing.List[str]] = pydantic.Field(default=None) - """ - List of node UUIDs to filter edges on: an edge matches if its source OR - target node UUID is in this list. Applies to edges only; rejected on - requests whose result type contains no edges. Max 256 entries. - """ - - created_at: typing.Optional[typing.List[typing.List[DateFilter]]] = pydantic.Field(default=None) - """ - 2D array of date filters for the created_at field. - The outer array elements are combined with OR logic. - The inner array elements are combined with AND logic. - Example: `[[{">", date1}, {"<", date2}], [{"=", date3}]]` - This translates to: `(created_at > date1 AND created_at < date2) OR (created_at = date3)` - """ - - edge_types: typing.Optional[typing.List[str]] = pydantic.Field(default=None) - """ - List of edge types to filter on - """ - - edge_uuids: typing.Optional[typing.List[str]] = pydantic.Field(default=None) - """ - List of edge UUIDs to filter on. Max 256 to align with graph-service filter limits. - """ - - episode_metadata_filters: typing.Optional["MetadataFilterGroup"] = pydantic.Field(default=None) - """ - [Experimental] Episode metadata filter. Restricts results to edges/nodes derived from episodes - matching the metadata predicates. Uses explicit AND/OR groups. This feature is experimental and may change in future releases. - """ - - episode_uuids: typing.Optional[typing.List[str]] = pydantic.Field(default=None) - """ - List of episode UUIDs to filter on. An edge matches if it was derived - from any listed episode; a node matches if it is mentioned by any - listed episode. Valid for both edge and node result types. Max 256 - entries. - """ - - exclude_edge_types: typing.Optional[typing.List[str]] = pydantic.Field(default=None) - """ - List of edge types to exclude from results - """ - - exclude_node_labels: typing.Optional[typing.List[str]] = pydantic.Field(default=None) - """ - List of node labels to exclude from results - """ - - expired_at: typing.Optional[typing.List[typing.List[DateFilter]]] = pydantic.Field(default=None) - """ - 2D array of date filters for the expired_at field. - The outer array elements are combined with OR logic. - The inner array elements are combined with AND logic. - Example: `[[{">", date1}, {"<", date2}], [{"=", date3}]]` - This translates to: `(expired_at > date1 AND expired_at < date2) OR (expired_at = date3)` - """ - - invalid_at: typing.Optional[typing.List[typing.List[DateFilter]]] = pydantic.Field(default=None) - """ - 2D array of date filters for the invalid_at field. - The outer array elements are combined with OR logic. - The inner array elements are combined with AND logic. - Example: `[[{">", date1}, {"<", date2}], [{"=", date3}]]` - This translates to: `(invalid_at > date1 AND invalid_at < date2) OR (invalid_at = date3)` - """ - - node_labels: typing.Optional[typing.List[str]] = pydantic.Field(default=None) - """ - List of node labels to filter on - """ - - property_filters: typing.Optional[typing.List[PropertyFilter]] = pydantic.Field(default=None) - """ - List of property filters to apply to nodes and edges - """ - - source_node_uuids: typing.Optional[typing.List[str]] = pydantic.Field(default=None) - """ - List of node UUIDs to filter edges on: an edge matches if its source - node UUID is in this list. Applies to edges only; rejected on requests - whose result type contains no edges. Max 256 entries. - """ - - target_node_uuids: typing.Optional[typing.List[str]] = pydantic.Field(default=None) - """ - List of node UUIDs to filter edges on: an edge matches if its target - node UUID is in this list. Applies to edges only; rejected on requests - whose result type contains no edges. Max 256 entries. - """ - - valid_at: typing.Optional[typing.List[typing.List[DateFilter]]] = pydantic.Field(default=None) - """ - 2D array of date filters for the valid_at field. - The outer array elements are combined with OR logic. - The inner array elements are combined with AND logic. - Example: `[[{">", date1}, {"<", date2}], [{"=", date3}]]` - This translates to: `(valid_at > date1 AND valid_at < date2) OR (valid_at = date3)` - """ - - 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 - - -from .metadata_filter_group import MetadataFilterGroup # noqa: E402, F401, I001 - -update_forward_refs(SearchFilters) diff --git a/src/zep_cloud/types/entity_type.py b/src/zep_cloud/types/search_request.py similarity index 57% rename from src/zep_cloud/types/entity_type.py rename to src/zep_cloud/types/search_request.py index b86cd9dc..6faa83d2 100644 --- a/src/zep_cloud/types/entity_type.py +++ b/src/zep_cloud/types/search_request.py @@ -4,14 +4,15 @@ import pydantic from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel -from .entity_property import EntityProperty -class EntityType(UniversalBaseModel): - description: str - identity_properties: typing.Optional[typing.List[str]] = None - name: str - properties: typing.Optional[typing.List[EntityProperty]] = None +class SearchRequest(UniversalBaseModel): + bfs_origin_node_uuids: typing.Optional[typing.List[str]] = None + center_node_uuid: typing.Optional[str] = None + filters: typing.Optional[typing.Dict[str, typing.Any]] = None + mmr_lambda: typing.Optional[float] = None + query: typing.Optional[str] = None + reranker: typing.Optional[str] = None if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 diff --git a/src/zep_cloud/types/get_task_response.py b/src/zep_cloud/types/task.py similarity index 67% rename from src/zep_cloud/types/get_task_response.py rename to src/zep_cloud/types/task.py index 10e5e310..97f0790a 100644 --- a/src/zep_cloud/types/get_task_response.py +++ b/src/zep_cloud/types/task.py @@ -3,22 +3,26 @@ import typing import pydantic +import typing_extensions from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel -from .task_error_response import TaskErrorResponse +from ..core.serialization import FieldMetadata +from .error_body import ErrorBody from .task_progress import TaskProgress -class GetTaskResponse(UniversalBaseModel): +class Task(UniversalBaseModel): completed_at: typing.Optional[str] = None created_at: typing.Optional[str] = None - error: typing.Optional[TaskErrorResponse] = None - params: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = None + error: typing.Optional[ErrorBody] = None progress: typing.Optional[TaskProgress] = None + result: typing.Optional[typing.Dict[str, typing.Any]] = None started_at: typing.Optional[str] = None status: typing.Optional[str] = None - task_id: typing.Optional[str] = None type: typing.Optional[str] = None updated_at: typing.Optional[str] = None + uuid_: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="uuid"), pydantic.Field(alias="uuid") + ] = None if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 diff --git a/src/zep_cloud/types/batch_list_response.py b/src/zep_cloud/types/task_page.py similarity index 69% rename from src/zep_cloud/types/batch_list_response.py rename to src/zep_cloud/types/task_page.py index 0400a33f..1cdb4caf 100644 --- a/src/zep_cloud/types/batch_list_response.py +++ b/src/zep_cloud/types/task_page.py @@ -4,12 +4,13 @@ import pydantic from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel -from .batch_summary import BatchSummary +from .task import Task -class BatchListResponse(UniversalBaseModel): - batches: typing.Optional[typing.List[BatchSummary]] = None - next_cursor: typing.Optional[int] = None +class TaskPage(UniversalBaseModel): + items: typing.Optional[typing.List[Task]] = None + next_cursor: typing.Optional[str] = None + total_size: typing.Optional[int] = None if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 diff --git a/src/zep_cloud/types/task_progress.py b/src/zep_cloud/types/task_progress.py index 1172079a..460a7af3 100644 --- a/src/zep_cloud/types/task_progress.py +++ b/src/zep_cloud/types/task_progress.py @@ -7,7 +7,6 @@ class TaskProgress(UniversalBaseModel): - message: typing.Optional[str] = None stage: typing.Optional[str] = None if IS_PYDANTIC_V2: diff --git a/src/zep_cloud/types/thread.py b/src/zep_cloud/types/thread.py index 964b51c9..d7f0008e 100644 --- a/src/zep_cloud/types/thread.py +++ b/src/zep_cloud/types/thread.py @@ -10,11 +10,13 @@ class Thread(UniversalBaseModel): created_at: typing.Optional[str] = None - project_uuid: typing.Optional[str] = None + graph_uuid: typing.Optional[str] = None thread_id: typing.Optional[str] = None - user_id: typing.Optional[str] = None + updated_at: typing.Optional[str] = None user_uuid: typing.Optional[str] = None - uuid_: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="uuid")] = None + uuid_: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="uuid"), pydantic.Field(alias="uuid") + ] = None if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 diff --git a/src/zep_cloud/types/thread_context_response.py b/src/zep_cloud/types/thread_context_response.py index f6cc4d9b..48d8132c 100644 --- a/src/zep_cloud/types/thread_context_response.py +++ b/src/zep_cloud/types/thread_context_response.py @@ -7,10 +7,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: typing.Optional[str] = None if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 diff --git a/src/zep_cloud/types/custom_instruction.py b/src/zep_cloud/types/thread_delete_result.py similarity index 81% rename from src/zep_cloud/types/custom_instruction.py rename to src/zep_cloud/types/thread_delete_result.py index 38b6d159..28e377ea 100644 --- a/src/zep_cloud/types/custom_instruction.py +++ b/src/zep_cloud/types/thread_delete_result.py @@ -4,11 +4,11 @@ import pydantic from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from .task import Task -class CustomInstruction(UniversalBaseModel): - name: str - text: str +class ThreadDeleteResult(UniversalBaseModel): + task: typing.Optional[Task] = None if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 diff --git a/src/zep_cloud/types/thread_list_response.py b/src/zep_cloud/types/thread_page.py similarity index 71% rename from src/zep_cloud/types/thread_list_response.py rename to src/zep_cloud/types/thread_page.py index 8cbb2b6e..4ca285d2 100644 --- a/src/zep_cloud/types/thread_list_response.py +++ b/src/zep_cloud/types/thread_page.py @@ -7,10 +7,10 @@ from .thread import Thread -class ThreadListResponse(UniversalBaseModel): - response_count: typing.Optional[int] = None - threads: typing.Optional[typing.List[Thread]] = None - total_count: typing.Optional[int] = None +class ThreadPage(UniversalBaseModel): + items: typing.Optional[typing.List[Thread]] = None + next_cursor: typing.Optional[str] = None + total_size: typing.Optional[int] = None if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 diff --git a/src/zep_cloud/types/thread_summary.py b/src/zep_cloud/types/thread_summary.py index db33c75d..6aab7bd6 100644 --- a/src/zep_cloud/types/thread_summary.py +++ b/src/zep_cloud/types/thread_summary.py @@ -9,43 +9,14 @@ class ThreadSummary(UniversalBaseModel): - created_at: typing.Optional[str] = pydantic.Field(default=None) - """ - CreatedAt is when the summary node was first created. - """ - - last_summarized_at: typing.Optional[str] = pydantic.Field(default=None) - """ - LastSummarizedAt is the wall-clock timestamp of the most recent - summary update. This is an ingestion-time watermark; for the - event-time recency of the summary's content, use - LastSummarizedEpisodeValidAt instead. - """ - - 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. Use this when - answering "how recent is this summary's content in event-time?". - """ - - summary: typing.Optional[str] = pydantic.Field(default=None) - """ - Summary is the incremental summary content. - """ - - thread_id: typing.Optional[str] = pydantic.Field(default=None) - """ - ThreadID is the ID of the thread this summary belongs to. - When a thread was created without an explicit thread_id, this - field falls back to the thread's UUID. Clients should treat it - as an opaque identifier. - """ - - uuid_: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="uuid")] = pydantic.Field(default=None) - """ - UUID of the thread summary node. - """ + created_at: typing.Optional[str] = None + last_summarized_at: typing.Optional[str] = None + last_summarized_episode_valid_at: typing.Optional[str] = None + summary: typing.Optional[str] = None + thread_uuid: typing.Optional[str] = None + uuid_: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="uuid"), pydantic.Field(alias="uuid") + ] = None if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 diff --git a/src/zep_cloud/types/user.py b/src/zep_cloud/types/user.py index 50b8df9a..59fc484e 100644 --- a/src/zep_cloud/types/user.py +++ b/src/zep_cloud/types/user.py @@ -10,31 +10,17 @@ class User(UniversalBaseModel): created_at: typing.Optional[str] = None - deleted_at: typing.Optional[str] = None disable_default_ontology: typing.Optional[bool] = None email: typing.Optional[str] = None first_name: typing.Optional[str] = None - id: typing.Optional[int] = None + graph_uuid: typing.Optional[str] = None last_name: typing.Optional[str] = None - metadata: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = pydantic.Field(default=None) - """ - Deprecated - """ - - project_uuid: typing.Optional[str] = None - session_count: typing.Optional[int] = pydantic.Field(default=None) - """ - Deprecated - """ - + metadata: typing.Optional[typing.Dict[str, typing.Any]] = None time_zone: typing.Optional[str] = None - updated_at: typing.Optional[str] = pydantic.Field(default=None) - """ - Deprecated - """ - user_id: typing.Optional[str] = None - uuid_: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="uuid")] = None + uuid_: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="uuid"), pydantic.Field(alias="uuid") + ] = None if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 diff --git a/src/zep_cloud/types/mutate_user_group_members_request.py b/src/zep_cloud/types/user_delete_result.py similarity index 81% rename from src/zep_cloud/types/mutate_user_group_members_request.py rename to src/zep_cloud/types/user_delete_result.py index 26042828..4178a7ab 100644 --- a/src/zep_cloud/types/mutate_user_group_members_request.py +++ b/src/zep_cloud/types/user_delete_result.py @@ -4,10 +4,11 @@ import pydantic from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from .task import Task -class MutateUserGroupMembersRequest(UniversalBaseModel): - user_uuids: typing.List[str] +class UserDeleteResult(UniversalBaseModel): + task: typing.Optional[Task] = None if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 diff --git a/src/zep_cloud/types/user_group.py b/src/zep_cloud/types/user_group.py deleted file mode 100644 index dbae6dea..00000000 --- a/src/zep_cloud/types/user_group.py +++ /dev/null @@ -1,31 +0,0 @@ -# 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 -from .user_group_kind import UserGroupKind - - -class UserGroup(UniversalBaseModel): - attached_policy_set_count: typing.Optional[int] = None - created_at: typing.Optional[str] = None - description: typing.Optional[str] = None - kind: typing.Optional[UserGroupKind] = None - member_count: typing.Optional[int] = None - name: typing.Optional[str] = None - project_uuid: typing.Optional[str] = None - updated_at: typing.Optional[str] = None - uuid_: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="uuid")] = None - version: typing.Optional[int] = None - - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow diff --git a/src/zep_cloud/types/user_group_kind.py b/src/zep_cloud/types/user_group_kind.py deleted file mode 100644 index 5691b041..00000000 --- a/src/zep_cloud/types/user_group_kind.py +++ /dev/null @@ -1,5 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import typing - -UserGroupKind = typing.Union[typing.Literal["managed", "virtual"], typing.Any] diff --git a/src/zep_cloud/types/user_group_list_response.py b/src/zep_cloud/types/user_group_list_response.py deleted file mode 100644 index 8cc9ee4d..00000000 --- a/src/zep_cloud/types/user_group_list_response.py +++ /dev/null @@ -1,24 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import typing - -import pydantic -from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel -from .user_group import UserGroup -from .user_group_quota import UserGroupQuota - - -class UserGroupListResponse(UniversalBaseModel): - quota: typing.Optional[UserGroupQuota] = None - row_count: typing.Optional[int] = None - total_count: typing.Optional[int] = None - user_groups: typing.Optional[typing.List[UserGroup]] = None - - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow diff --git a/src/zep_cloud/types/user_group_members_response.py b/src/zep_cloud/types/user_group_members_response.py deleted file mode 100644 index 5e6aba81..00000000 --- a/src/zep_cloud/types/user_group_members_response.py +++ /dev/null @@ -1,22 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import typing - -import pydantic -from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel -from .user import User - - -class UserGroupMembersResponse(UniversalBaseModel): - row_count: typing.Optional[int] = None - total_count: typing.Optional[int] = None - users: typing.Optional[typing.List[User]] = None - - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow diff --git a/src/zep_cloud/types/user_group_membership_response.py b/src/zep_cloud/types/user_group_membership_response.py deleted file mode 100644 index 202da5ec..00000000 --- a/src/zep_cloud/types/user_group_membership_response.py +++ /dev/null @@ -1,21 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import typing - -import pydantic -from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel - - -class UserGroupMembershipResponse(UniversalBaseModel): - added_count: typing.Optional[int] = None - no_op_count: typing.Optional[int] = None - removed_count: typing.Optional[int] = None - - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow diff --git a/src/zep_cloud/types/user_group_quota.py b/src/zep_cloud/types/user_group_quota.py deleted file mode 100644 index c5c13ca7..00000000 --- a/src/zep_cloud/types/user_group_quota.py +++ /dev/null @@ -1,23 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import typing - -import pydantic -from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel - - -class UserGroupQuota(UniversalBaseModel): - active_managed: typing.Optional[int] = None - allocation: typing.Optional[int] = None - has_feature: typing.Optional[bool] = None - resolved: typing.Optional[bool] = None - unlimited: typing.Optional[bool] = None - - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow diff --git a/src/zep_cloud/types/user_group_response.py b/src/zep_cloud/types/user_group_response.py deleted file mode 100644 index 74e7c8df..00000000 --- a/src/zep_cloud/types/user_group_response.py +++ /dev/null @@ -1,31 +0,0 @@ -# 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 -from .user_group_kind import UserGroupKind - - -class UserGroupResponse(UniversalBaseModel): - attached_policy_set_count: typing.Optional[int] = None - created_at: typing.Optional[str] = None - description: typing.Optional[str] = None - kind: typing.Optional[UserGroupKind] = None - member_count: typing.Optional[int] = None - name: typing.Optional[str] = None - project_uuid: typing.Optional[str] = None - updated_at: typing.Optional[str] = None - uuid_: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="uuid")] = None - version: typing.Optional[int] = None - - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow diff --git a/src/zep_cloud/types/user_instruction.py b/src/zep_cloud/types/user_instruction.py deleted file mode 100644 index fd322630..00000000 --- a/src/zep_cloud/types/user_instruction.py +++ /dev/null @@ -1,20 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import typing - -import pydantic -from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel - - -class UserInstruction(UniversalBaseModel): - name: str - text: str - - 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/user_membership_groups_response.py b/src/zep_cloud/types/user_membership_groups_response.py deleted file mode 100644 index a087d993..00000000 --- a/src/zep_cloud/types/user_membership_groups_response.py +++ /dev/null @@ -1,20 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import typing - -import pydantic -from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel -from .user_group import UserGroup - - -class UserMembershipGroupsResponse(UniversalBaseModel): - user_groups: typing.Optional[typing.List[UserGroup]] = None - - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow diff --git a/src/zep_cloud/types/user_node_response.py b/src/zep_cloud/types/user_node_response.py deleted file mode 100644 index 379eb47f..00000000 --- a/src/zep_cloud/types/user_node_response.py +++ /dev/null @@ -1,20 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import typing - -import pydantic -from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel -from .entity_node import EntityNode - - -class UserNodeResponse(UniversalBaseModel): - node: typing.Optional[EntityNode] = None - - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow diff --git a/src/zep_cloud/types/user_list_response.py b/src/zep_cloud/types/user_page.py similarity index 72% rename from src/zep_cloud/types/user_list_response.py rename to src/zep_cloud/types/user_page.py index 0521800c..4c373c00 100644 --- a/src/zep_cloud/types/user_list_response.py +++ b/src/zep_cloud/types/user_page.py @@ -7,10 +7,10 @@ from .user import User -class UserListResponse(UniversalBaseModel): - row_count: typing.Optional[int] = None - total_count: typing.Optional[int] = None - users: typing.Optional[typing.List[User]] = None +class UserPage(UniversalBaseModel): + items: typing.Optional[typing.List[User]] = None + next_cursor: typing.Optional[str] = None + total_size: typing.Optional[int] = None if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 diff --git a/src/zep_cloud/types/user_summary_instructions.py b/src/zep_cloud/types/user_summary_instructions.py new file mode 100644 index 00000000..7d188ae9 --- /dev/null +++ b/src/zep_cloud/types/user_summary_instructions.py @@ -0,0 +1,20 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel + + +class UserSummaryInstructions(UniversalBaseModel): + inherited: typing.Optional[bool] = None + instructions: typing.Optional[typing.List[typing.Dict[str, typing.Any]]] = None + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/zep_cloud/user/client.py b/src/zep_cloud/user/client.py index e8a84fe4..aef29257 100644 --- a/src/zep_cloud/user/client.py +++ b/src/zep_cloud/user/client.py @@ -3,14 +3,13 @@ import typing from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper +from ..core.pagination import AsyncPager, SyncPager from ..core.request_options import RequestOptions -from ..types.list_user_instructions_response import ListUserInstructionsResponse -from ..types.success_response import SuccessResponse -from ..types.thread import Thread +from ..types.json_object import JsonObject from ..types.user import User -from ..types.user_instruction import UserInstruction -from ..types.user_list_response import UserListResponse -from ..types.user_node_response import UserNodeResponse +from ..types.user_delete_result import UserDeleteResult +from ..types.user_page import UserPage +from ..types.user_summary_instructions import UserSummaryInstructions from .raw_client import AsyncRawUserClient, RawUserClient # this is used as the default value for optional parameters @@ -32,111 +31,45 @@ def with_raw_response(self) -> RawUserClient: """ return self._raw_client - def list_user_summary_instructions( - self, *, user_id: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None - ) -> ListUserInstructionsResponse: - """ - Lists all user summary instructions for a project, user. - - Parameters - ---------- - user_id : typing.Optional[str] - User ID to get user-specific instructions - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - ListUserInstructionsResponse - The list of instructions. - - Examples - -------- - from zep_cloud import Zep - - client = Zep( - api_key="YOUR_API_KEY", - ) - client.user.list_user_summary_instructions( - user_id="user_id", - ) - """ - _response = self._raw_client.list_user_summary_instructions(user_id=user_id, request_options=request_options) - return _response.data - - def add_user_summary_instructions( + def create( self, *, - instructions: typing.Sequence[UserInstruction], - user_ids: typing.Optional[typing.Sequence[str]] = OMIT, + disable_default_ontology: typing.Optional[bool] = OMIT, + email: typing.Optional[str] = OMIT, + first_name: typing.Optional[str] = OMIT, + last_name: typing.Optional[str] = OMIT, + metadata: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + time_zone: typing.Optional[str] = OMIT, + user_id: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> SuccessResponse: + ) -> User: """ - Adds new summary instructions for users graphs without removing existing ones. If user_ids is empty, adds to project-wide default instructions. - Parameters ---------- - instructions : typing.Sequence[UserInstruction] - Instructions to add to the user summary generation. - - user_ids : typing.Optional[typing.Sequence[str]] - User IDs to add the instructions to. If empty, the instructions are added to the project-wide default. + disable_default_ontology : typing.Optional[bool] - request_options : typing.Optional[RequestOptions] - Request-specific configuration. + email : typing.Optional[str] - Returns - ------- - SuccessResponse - Instructions added successfully + first_name : typing.Optional[str] - Examples - -------- - from zep_cloud import UserInstruction, Zep + last_name : typing.Optional[str] - client = Zep( - api_key="YOUR_API_KEY", - ) - client.user.add_user_summary_instructions( - instructions=[ - UserInstruction( - name="name", - text="text", - ) - ], - ) - """ - _response = self._raw_client.add_user_summary_instructions( - instructions=instructions, user_ids=user_ids, request_options=request_options - ) - return _response.data + metadata : typing.Optional[typing.Dict[str, typing.Any]] - def delete_user_summary_instructions( - self, - *, - instruction_names: typing.Optional[typing.Sequence[str]] = OMIT, - user_ids: typing.Optional[typing.Sequence[str]] = OMIT, - request_options: typing.Optional[RequestOptions] = None, - ) -> SuccessResponse: - """ - Deletes user summary/instructions for users or project wide defaults. + time_zone : typing.Optional[str] - Parameters - ---------- - instruction_names : typing.Optional[typing.Sequence[str]] - Unique identifier for the instructions to be deleted. If empty deletes all instructions. + user_id : typing.Optional[str] - user_ids : typing.Optional[typing.Sequence[str]] - Determines which users will have their custom instructions deleted. If no users are provided, the project-wide custom instructions will be effected. + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - SuccessResponse - Instructions deleted successfully + User + Created Examples -------- @@ -145,58 +78,58 @@ def delete_user_summary_instructions( client = Zep( api_key="YOUR_API_KEY", ) - client.user.delete_user_summary_instructions() + client.user.create() """ - _response = self._raw_client.delete_user_summary_instructions( - instruction_names=instruction_names, user_ids=user_ids, request_options=request_options + _response = self._raw_client.create( + disable_default_ontology=disable_default_ontology, + email=email, + first_name=first_name, + last_name=last_name, + metadata=metadata, + time_zone=time_zone, + user_id=user_id, + idempotency_key=idempotency_key, + request_options=request_options, ) return _response.data - def add( + def list( self, *, - user_id: str, - disable_default_ontology: typing.Optional[bool] = OMIT, - email: typing.Optional[str] = OMIT, - first_name: typing.Optional[str] = OMIT, - last_name: typing.Optional[str] = OMIT, - metadata: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = OMIT, - time_zone: typing.Optional[str] = OMIT, + limit: typing.Optional[int] = None, + cursor: typing.Optional[str] = None, + order_by: typing.Optional[str] = None, + order: typing.Optional[str] = None, + search: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> User: + ) -> SyncPager[User, UserPage]: """ - Adds a user. - Parameters ---------- - user_id : str - The unique identifier of the user. + limit : typing.Optional[int] + Page size - disable_default_ontology : typing.Optional[bool] - When true, disables the use of default/fallback ontology for the user's graph. - - email : typing.Optional[str] - The email address of the user. + cursor : typing.Optional[str] + Opaque page cursor - first_name : typing.Optional[str] - The first name of the user. + order_by : typing.Optional[str] + Sort field - last_name : typing.Optional[str] - The last name of the user. + order : typing.Optional[str] + asc or desc - metadata : typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] - The metadata associated with the user. + search : typing.Optional[str] - time_zone : typing.Optional[str] - The user's IANA time zone. Null or omission leaves it unset at creation. + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - User - The user that was added. + SyncPager[User, UserPage] + OK Examples -------- @@ -205,59 +138,55 @@ def add( client = Zep( api_key="YOUR_API_KEY", ) - client.user.add( - user_id="user_id", + response = client.user.list( + limit=1, + cursor="cursor", + order_by="order_by", + order="order", ) + for item in response: + yield item + # alternatively, you can paginate page-by-page + for page in response.iter_pages(): + yield page """ - _response = self._raw_client.add( - user_id=user_id, - disable_default_ontology=disable_default_ontology, - email=email, - first_name=first_name, - last_name=last_name, - metadata=metadata, - time_zone=time_zone, + return self._raw_client.list( + limit=limit, + cursor=cursor, + order_by=order_by, + order=order, + search=search, + idempotency_key=idempotency_key, request_options=request_options, ) - return _response.data - def list_ordered( + def lookup( self, *, - page_number: typing.Optional[int] = None, - page_size: typing.Optional[int] = None, - search: typing.Optional[str] = None, - order_by: typing.Optional[str] = None, - asc: typing.Optional[bool] = None, + graph_id: typing.Optional[str] = OMIT, + thread_id: typing.Optional[str] = OMIT, + user_id: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> UserListResponse: + ) -> User: """ - Returns all users. - Parameters ---------- - page_number : typing.Optional[int] - Page number for pagination, starting from 1 - - page_size : typing.Optional[int] - Number of users to retrieve per page + graph_id : typing.Optional[str] - search : typing.Optional[str] - Search term for filtering users by user_id, name, or email + thread_id : typing.Optional[str] - order_by : typing.Optional[str] - Column to sort by (created_at, user_id, email) + user_id : typing.Optional[str] - asc : typing.Optional[bool] - Sort in ascending order + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - UserListResponse - Successfully retrieved list of users + User + OK Examples -------- @@ -266,32 +195,23 @@ def list_ordered( client = Zep( api_key="YOUR_API_KEY", ) - client.user.list_ordered( - page_number=1, - page_size=1, - search="search", - order_by="order_by", - asc=True, - ) + client.user.lookup() """ - _response = self._raw_client.list_ordered( - page_number=page_number, - page_size=page_size, - search=search, - order_by=order_by, - asc=asc, + _response = self._raw_client.lookup( + graph_id=graph_id, + thread_id=thread_id, + user_id=user_id, + idempotency_key=idempotency_key, request_options=request_options, ) return _response.data - def get(self, user_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> User: + def get(self, user_uuid: str, *, request_options: typing.Optional[RequestOptions] = None) -> User: """ - Returns a user. - Parameters ---------- - user_id : str - The user_id of the user to get. + user_uuid : str + User UUID request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -299,7 +219,7 @@ def get(self, user_id: str, *, request_options: typing.Optional[RequestOptions] Returns ------- User - The user that was retrieved. + OK Examples -------- @@ -309,28 +229,34 @@ def get(self, user_id: str, *, request_options: typing.Optional[RequestOptions] api_key="YOUR_API_KEY", ) client.user.get( - user_id="userId", + user_uuid="user_uuid", ) """ - _response = self._raw_client.get(user_id, request_options=request_options) + _response = self._raw_client.get(user_uuid, request_options=request_options) return _response.data - def delete(self, user_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> SuccessResponse: + def delete( + self, + user_uuid: str, + *, + idempotency_key: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> UserDeleteResult: """ - Deletes a user. - Parameters ---------- - user_id : str - User ID + user_uuid : str + User UUID + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - SuccessResponse - OK + UserDeleteResult + Accepted Examples -------- @@ -340,49 +266,49 @@ def delete(self, user_id: str, *, request_options: typing.Optional[RequestOption api_key="YOUR_API_KEY", ) client.user.delete( - user_id="userId", + user_uuid="user_uuid", ) """ - _response = self._raw_client.delete(user_id, request_options=request_options) + _response = self._raw_client.delete(user_uuid, idempotency_key=idempotency_key, request_options=request_options) return _response.data def update( self, - user_id: str, + user_uuid: str, *, disable_default_ontology: typing.Optional[bool] = OMIT, email: typing.Optional[str] = OMIT, first_name: typing.Optional[str] = OMIT, last_name: typing.Optional[str] = OMIT, - metadata: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = OMIT, + metadata: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, time_zone: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, ) -> User: """ - Updates a user. - Parameters ---------- - user_id : str - User ID + user_uuid : str + User UUID disable_default_ontology : typing.Optional[bool] - When true, disables the use of default/fallback ontology for the user's graph. + Omit to leave unchanged, send JSON null to clear, or send a value to set. email : typing.Optional[str] - The email address of the user. + Omit to leave unchanged, send JSON null to clear, or send a value to set. first_name : typing.Optional[str] - The first name of the user. + Omit to leave unchanged, send JSON null to clear, or send a value to set. last_name : typing.Optional[str] - The last name of the user. + Omit to leave unchanged, send JSON null to clear, or send a value to set. - metadata : typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] - The metadata to update + metadata : typing.Optional[typing.Dict[str, typing.Any]] time_zone : typing.Optional[str] - The user's IANA time zone. Null clears the existing value. + Omit to leave unchanged, send JSON null to clear, or send a value to set. + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -390,7 +316,7 @@ def update( Returns ------- User - The user that was updated. + OK Examples -------- @@ -400,37 +326,36 @@ def update( api_key="YOUR_API_KEY", ) client.user.update( - user_id="userId", + user_uuid="user_uuid", ) """ _response = self._raw_client.update( - user_id, + user_uuid, disable_default_ontology=disable_default_ontology, email=email, first_name=first_name, last_name=last_name, metadata=metadata, time_zone=time_zone, + idempotency_key=idempotency_key, request_options=request_options, ) return _response.data - def get_node(self, user_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> UserNodeResponse: + def get_node(self, user_uuid: str, *, request_options: typing.Optional[RequestOptions] = None) -> JsonObject: """ - Returns a user's node. - Parameters ---------- - user_id : str - The user_id of the user to get the node for. + user_uuid : str + User UUID request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - UserNodeResponse - Response object containing the User node. + JsonObject + OK Examples -------- @@ -440,29 +365,27 @@ def get_node(self, user_id: str, *, request_options: typing.Optional[RequestOpti api_key="YOUR_API_KEY", ) client.user.get_node( - user_id="userId", + user_uuid="user_uuid", ) """ - _response = self._raw_client.get_node(user_id, request_options=request_options) + _response = self._raw_client.get_node(user_uuid, request_options=request_options) return _response.data - def get_threads( - self, user_id: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> typing.List[Thread]: + def get_summary_instructions( + self, user_uuid: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> UserSummaryInstructions: """ - Returns all threads for a user. - Parameters ---------- - user_id : str - User ID + user_uuid : str + User UUID request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - typing.List[Thread] + UserSummaryInstructions OK Examples @@ -472,29 +395,41 @@ def get_threads( client = Zep( api_key="YOUR_API_KEY", ) - client.user.get_threads( - user_id="userId", + client.user.get_summary_instructions( + user_uuid="user_uuid", ) """ - _response = self._raw_client.get_threads(user_id, request_options=request_options) + _response = self._raw_client.get_summary_instructions(user_uuid, request_options=request_options) return _response.data - def warm(self, user_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> SuccessResponse: + def set_summary_instructions( + self, + user_uuid: str, + *, + inherited: typing.Optional[bool] = OMIT, + instructions: typing.Optional[typing.Sequence[typing.Dict[str, typing.Any]]] = OMIT, + idempotency_key: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> UserSummaryInstructions: """ - Hints Zep to warm a user's graph for low-latency search - Parameters ---------- - user_id : str - User ID + user_uuid : str + User UUID + + inherited : typing.Optional[bool] + + instructions : typing.Optional[typing.Sequence[typing.Dict[str, typing.Any]]] + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - SuccessResponse - Warm hint accepted + UserSummaryInstructions + OK Examples -------- @@ -503,11 +438,17 @@ def warm(self, user_id: str, *, request_options: typing.Optional[RequestOptions] client = Zep( api_key="YOUR_API_KEY", ) - client.user.warm( - user_id="userId", + client.user.set_summary_instructions( + user_uuid="user_uuid", ) """ - _response = self._raw_client.warm(user_id, request_options=request_options) + _response = self._raw_client.set_summary_instructions( + user_uuid, + inherited=inherited, + instructions=instructions, + idempotency_key=idempotency_key, + request_options=request_options, + ) return _response.data @@ -526,129 +467,45 @@ def with_raw_response(self) -> AsyncRawUserClient: """ return self._raw_client - async def list_user_summary_instructions( - self, *, user_id: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None - ) -> ListUserInstructionsResponse: - """ - Lists all user summary instructions for a project, user. - - Parameters - ---------- - user_id : typing.Optional[str] - User ID to get user-specific instructions - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - ListUserInstructionsResponse - The list of instructions. - - Examples - -------- - import asyncio - - from zep_cloud import AsyncZep - - client = AsyncZep( - api_key="YOUR_API_KEY", - ) - - - async def main() -> None: - await client.user.list_user_summary_instructions( - user_id="user_id", - ) - - - asyncio.run(main()) - """ - _response = await self._raw_client.list_user_summary_instructions( - user_id=user_id, request_options=request_options - ) - return _response.data - - async def add_user_summary_instructions( + async def create( self, *, - instructions: typing.Sequence[UserInstruction], - user_ids: typing.Optional[typing.Sequence[str]] = OMIT, + disable_default_ontology: typing.Optional[bool] = OMIT, + email: typing.Optional[str] = OMIT, + first_name: typing.Optional[str] = OMIT, + last_name: typing.Optional[str] = OMIT, + metadata: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + time_zone: typing.Optional[str] = OMIT, + user_id: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> SuccessResponse: + ) -> User: """ - Adds new summary instructions for users graphs without removing existing ones. If user_ids is empty, adds to project-wide default instructions. - Parameters ---------- - instructions : typing.Sequence[UserInstruction] - Instructions to add to the user summary generation. - - user_ids : typing.Optional[typing.Sequence[str]] - User IDs to add the instructions to. If empty, the instructions are added to the project-wide default. - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - SuccessResponse - Instructions added successfully - - Examples - -------- - import asyncio - - from zep_cloud import AsyncZep, UserInstruction + disable_default_ontology : typing.Optional[bool] - client = AsyncZep( - api_key="YOUR_API_KEY", - ) + email : typing.Optional[str] + first_name : typing.Optional[str] - async def main() -> None: - await client.user.add_user_summary_instructions( - instructions=[ - UserInstruction( - name="name", - text="text", - ) - ], - ) + last_name : typing.Optional[str] + metadata : typing.Optional[typing.Dict[str, typing.Any]] - asyncio.run(main()) - """ - _response = await self._raw_client.add_user_summary_instructions( - instructions=instructions, user_ids=user_ids, request_options=request_options - ) - return _response.data - - async def delete_user_summary_instructions( - self, - *, - instruction_names: typing.Optional[typing.Sequence[str]] = OMIT, - user_ids: typing.Optional[typing.Sequence[str]] = OMIT, - request_options: typing.Optional[RequestOptions] = None, - ) -> SuccessResponse: - """ - Deletes user summary/instructions for users or project wide defaults. + time_zone : typing.Optional[str] - Parameters - ---------- - instruction_names : typing.Optional[typing.Sequence[str]] - Unique identifier for the instructions to be deleted. If empty deletes all instructions. + user_id : typing.Optional[str] - user_ids : typing.Optional[typing.Sequence[str]] - Determines which users will have their custom instructions deleted. If no users are provided, the project-wide custom instructions will be effected. + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - SuccessResponse - Instructions deleted successfully + User + Created Examples -------- @@ -662,61 +519,61 @@ async def delete_user_summary_instructions( async def main() -> None: - await client.user.delete_user_summary_instructions() + await client.user.create() asyncio.run(main()) """ - _response = await self._raw_client.delete_user_summary_instructions( - instruction_names=instruction_names, user_ids=user_ids, request_options=request_options + _response = await self._raw_client.create( + disable_default_ontology=disable_default_ontology, + email=email, + first_name=first_name, + last_name=last_name, + metadata=metadata, + time_zone=time_zone, + user_id=user_id, + idempotency_key=idempotency_key, + request_options=request_options, ) return _response.data - async def add( + async def list( self, *, - user_id: str, - disable_default_ontology: typing.Optional[bool] = OMIT, - email: typing.Optional[str] = OMIT, - first_name: typing.Optional[str] = OMIT, - last_name: typing.Optional[str] = OMIT, - metadata: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = OMIT, - time_zone: typing.Optional[str] = OMIT, + limit: typing.Optional[int] = None, + cursor: typing.Optional[str] = None, + order_by: typing.Optional[str] = None, + order: typing.Optional[str] = None, + search: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> User: + ) -> AsyncPager[User, UserPage]: """ - Adds a user. - Parameters ---------- - user_id : str - The unique identifier of the user. + limit : typing.Optional[int] + Page size - disable_default_ontology : typing.Optional[bool] - When true, disables the use of default/fallback ontology for the user's graph. + cursor : typing.Optional[str] + Opaque page cursor - email : typing.Optional[str] - The email address of the user. + order_by : typing.Optional[str] + Sort field - first_name : typing.Optional[str] - The first name of the user. + order : typing.Optional[str] + asc or desc - last_name : typing.Optional[str] - The last name of the user. - - metadata : typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] - The metadata associated with the user. + search : typing.Optional[str] - time_zone : typing.Optional[str] - The user's IANA time zone. Null or omission leaves it unset at creation. + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - User - The user that was added. + AsyncPager[User, UserPage] + OK Examples -------- @@ -730,62 +587,59 @@ async def add( async def main() -> None: - await client.user.add( - user_id="user_id", + response = await client.user.list( + limit=1, + cursor="cursor", + order_by="order_by", + order="order", ) + async for item in response: + yield item + + # alternatively, you can paginate page-by-page + async for page in response.iter_pages(): + yield page asyncio.run(main()) """ - _response = await self._raw_client.add( - user_id=user_id, - disable_default_ontology=disable_default_ontology, - email=email, - first_name=first_name, - last_name=last_name, - metadata=metadata, - time_zone=time_zone, + return await self._raw_client.list( + limit=limit, + cursor=cursor, + order_by=order_by, + order=order, + search=search, + idempotency_key=idempotency_key, request_options=request_options, ) - return _response.data - async def list_ordered( + async def lookup( self, *, - page_number: typing.Optional[int] = None, - page_size: typing.Optional[int] = None, - search: typing.Optional[str] = None, - order_by: typing.Optional[str] = None, - asc: typing.Optional[bool] = None, + graph_id: typing.Optional[str] = OMIT, + thread_id: typing.Optional[str] = OMIT, + user_id: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> UserListResponse: + ) -> User: """ - Returns all users. - Parameters ---------- - page_number : typing.Optional[int] - Page number for pagination, starting from 1 - - page_size : typing.Optional[int] - Number of users to retrieve per page + graph_id : typing.Optional[str] - search : typing.Optional[str] - Search term for filtering users by user_id, name, or email + thread_id : typing.Optional[str] - order_by : typing.Optional[str] - Column to sort by (created_at, user_id, email) + user_id : typing.Optional[str] - asc : typing.Optional[bool] - Sort in ascending order + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - UserListResponse - Successfully retrieved list of users + User + OK Examples -------- @@ -799,35 +653,26 @@ async def list_ordered( async def main() -> None: - await client.user.list_ordered( - page_number=1, - page_size=1, - search="search", - order_by="order_by", - asc=True, - ) + await client.user.lookup() asyncio.run(main()) """ - _response = await self._raw_client.list_ordered( - page_number=page_number, - page_size=page_size, - search=search, - order_by=order_by, - asc=asc, + _response = await self._raw_client.lookup( + graph_id=graph_id, + thread_id=thread_id, + user_id=user_id, + idempotency_key=idempotency_key, request_options=request_options, ) return _response.data - async def get(self, user_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> User: + async def get(self, user_uuid: str, *, request_options: typing.Optional[RequestOptions] = None) -> User: """ - Returns a user. - Parameters ---------- - user_id : str - The user_id of the user to get. + user_uuid : str + User UUID request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -835,7 +680,7 @@ async def get(self, user_id: str, *, request_options: typing.Optional[RequestOpt Returns ------- User - The user that was retrieved. + OK Examples -------- @@ -850,31 +695,37 @@ async def get(self, user_id: str, *, request_options: typing.Optional[RequestOpt async def main() -> None: await client.user.get( - user_id="userId", + user_uuid="user_uuid", ) asyncio.run(main()) """ - _response = await self._raw_client.get(user_id, request_options=request_options) + _response = await self._raw_client.get(user_uuid, request_options=request_options) return _response.data - async def delete(self, user_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> SuccessResponse: + async def delete( + self, + user_uuid: str, + *, + idempotency_key: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> UserDeleteResult: """ - Deletes a user. - Parameters ---------- - user_id : str - User ID + user_uuid : str + User UUID + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - SuccessResponse - OK + UserDeleteResult + Accepted Examples -------- @@ -889,52 +740,54 @@ async def delete(self, user_id: str, *, request_options: typing.Optional[Request async def main() -> None: await client.user.delete( - user_id="userId", + user_uuid="user_uuid", ) asyncio.run(main()) """ - _response = await self._raw_client.delete(user_id, request_options=request_options) + _response = await self._raw_client.delete( + user_uuid, idempotency_key=idempotency_key, request_options=request_options + ) return _response.data async def update( self, - user_id: str, + user_uuid: str, *, disable_default_ontology: typing.Optional[bool] = OMIT, email: typing.Optional[str] = OMIT, first_name: typing.Optional[str] = OMIT, last_name: typing.Optional[str] = OMIT, - metadata: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = OMIT, + metadata: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, time_zone: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, ) -> User: """ - Updates a user. - Parameters ---------- - user_id : str - User ID + user_uuid : str + User UUID disable_default_ontology : typing.Optional[bool] - When true, disables the use of default/fallback ontology for the user's graph. + Omit to leave unchanged, send JSON null to clear, or send a value to set. email : typing.Optional[str] - The email address of the user. + Omit to leave unchanged, send JSON null to clear, or send a value to set. first_name : typing.Optional[str] - The first name of the user. + Omit to leave unchanged, send JSON null to clear, or send a value to set. last_name : typing.Optional[str] - The last name of the user. + Omit to leave unchanged, send JSON null to clear, or send a value to set. - metadata : typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] - The metadata to update + metadata : typing.Optional[typing.Dict[str, typing.Any]] time_zone : typing.Optional[str] - The user's IANA time zone. Null clears the existing value. + Omit to leave unchanged, send JSON null to clear, or send a value to set. + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -942,7 +795,7 @@ async def update( Returns ------- User - The user that was updated. + OK Examples -------- @@ -957,42 +810,39 @@ async def update( async def main() -> None: await client.user.update( - user_id="userId", + user_uuid="user_uuid", ) asyncio.run(main()) """ _response = await self._raw_client.update( - user_id, + user_uuid, disable_default_ontology=disable_default_ontology, email=email, first_name=first_name, last_name=last_name, metadata=metadata, time_zone=time_zone, + idempotency_key=idempotency_key, request_options=request_options, ) return _response.data - async def get_node( - self, user_id: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> UserNodeResponse: + async def get_node(self, user_uuid: str, *, request_options: typing.Optional[RequestOptions] = None) -> JsonObject: """ - Returns a user's node. - Parameters ---------- - user_id : str - The user_id of the user to get the node for. + user_uuid : str + User UUID request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - UserNodeResponse - Response object containing the User node. + JsonObject + OK Examples -------- @@ -1007,32 +857,30 @@ async def get_node( async def main() -> None: await client.user.get_node( - user_id="userId", + user_uuid="user_uuid", ) asyncio.run(main()) """ - _response = await self._raw_client.get_node(user_id, request_options=request_options) + _response = await self._raw_client.get_node(user_uuid, request_options=request_options) return _response.data - async def get_threads( - self, user_id: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> typing.List[Thread]: + async def get_summary_instructions( + self, user_uuid: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> UserSummaryInstructions: """ - Returns all threads for a user. - Parameters ---------- - user_id : str - User ID + user_uuid : str + User UUID request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - typing.List[Thread] + UserSummaryInstructions OK Examples @@ -1047,32 +895,44 @@ async def get_threads( async def main() -> None: - await client.user.get_threads( - user_id="userId", + await client.user.get_summary_instructions( + user_uuid="user_uuid", ) asyncio.run(main()) """ - _response = await self._raw_client.get_threads(user_id, request_options=request_options) + _response = await self._raw_client.get_summary_instructions(user_uuid, request_options=request_options) return _response.data - async def warm(self, user_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> SuccessResponse: + async def set_summary_instructions( + self, + user_uuid: str, + *, + inherited: typing.Optional[bool] = OMIT, + instructions: typing.Optional[typing.Sequence[typing.Dict[str, typing.Any]]] = OMIT, + idempotency_key: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> UserSummaryInstructions: """ - Hints Zep to warm a user's graph for low-latency search - Parameters ---------- - user_id : str - User ID + user_uuid : str + User UUID + + inherited : typing.Optional[bool] + + instructions : typing.Optional[typing.Sequence[typing.Dict[str, typing.Any]]] + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - SuccessResponse - Warm hint accepted + UserSummaryInstructions + OK Examples -------- @@ -1086,12 +946,18 @@ async def warm(self, user_id: str, *, request_options: typing.Optional[RequestOp async def main() -> None: - await client.user.warm( - user_id="userId", + await client.user.set_summary_instructions( + user_uuid="user_uuid", ) asyncio.run(main()) """ - _response = await self._raw_client.warm(user_id, request_options=request_options) + _response = await self._raw_client.set_summary_instructions( + user_uuid, + inherited=inherited, + instructions=instructions, + idempotency_key=idempotency_key, + request_options=request_options, + ) return _response.data diff --git a/src/zep_cloud/user/raw_client.py b/src/zep_cloud/user/raw_client.py index ee2aa517..93526d6d 100644 --- a/src/zep_cloud/user/raw_client.py +++ b/src/zep_cloud/user/raw_client.py @@ -7,20 +7,20 @@ from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper from ..core.http_response import AsyncHttpResponse, HttpResponse from ..core.jsonable_encoder import jsonable_encoder +from ..core.pagination import AsyncPager, SyncPager +from ..core.parse_error import ParsingError 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 ..errors.unauthorized_error import UnauthorizedError from ..types.api_error import ApiError as types_api_error_ApiError -from ..types.list_user_instructions_response import ListUserInstructionsResponse -from ..types.success_response import SuccessResponse -from ..types.thread import Thread +from ..types.json_object import JsonObject from ..types.user import User -from ..types.user_instruction import UserInstruction -from ..types.user_list_response import UserListResponse -from ..types.user_node_response import UserNodeResponse +from ..types.user_delete_result import UserDeleteResult +from ..types.user_page import UserPage +from ..types.user_summary_instructions import UserSummaryInstructions +from pydantic import ValidationError # this is used as the default value for optional parameters OMIT = typing.cast(typing.Any, ...) @@ -30,39 +30,71 @@ class RawUserClient: def __init__(self, *, client_wrapper: SyncClientWrapper): self._client_wrapper = client_wrapper - def list_user_summary_instructions( - self, *, user_id: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None - ) -> HttpResponse[ListUserInstructionsResponse]: + def create( + self, + *, + disable_default_ontology: typing.Optional[bool] = OMIT, + email: typing.Optional[str] = OMIT, + first_name: typing.Optional[str] = OMIT, + last_name: typing.Optional[str] = OMIT, + metadata: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + time_zone: typing.Optional[str] = OMIT, + user_id: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[User]: """ - Lists all user summary instructions for a project, user. - Parameters ---------- + disable_default_ontology : typing.Optional[bool] + + email : typing.Optional[str] + + first_name : typing.Optional[str] + + last_name : typing.Optional[str] + + metadata : typing.Optional[typing.Dict[str, typing.Any]] + + time_zone : typing.Optional[str] + user_id : typing.Optional[str] - User ID to get user-specific instructions + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - HttpResponse[ListUserInstructionsResponse] - The list of instructions. + HttpResponse[User] + Created """ _response = self._client_wrapper.httpx_client.request( - "user-summary-instructions", - method="GET", - params={ + "users", + method="POST", + json={ + "disable_default_ontology": disable_default_ontology, + "email": email, + "first_name": first_name, + "last_name": last_name, + "metadata": metadata, + "time_zone": time_zone, "user_id": user_id, }, + headers={ + "content-type": "application/json", + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, + }, request_options=request_options, + omit=OMIT, ) try: if 200 <= _response.status_code < 300: _data = typing.cast( - ListUserInstructionsResponse, + User, parse_obj_as( - type_=ListUserInstructionsResponse, # type: ignore + type_=User, # type: ignore object_=_response.json(), ), ) @@ -71,15 +103,15 @@ def list_user_summary_instructions( raise BadRequestError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore object_=_response.json(), ), ), ) - if _response.status_code == 404: - raise NotFoundError( + if _response.status_code == 401: + raise UnauthorizedError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -89,8 +121,8 @@ def list_user_summary_instructions( ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -105,74 +137,106 @@ def list_user_summary_instructions( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - def add_user_summary_instructions( + def list( self, *, - instructions: typing.Sequence[UserInstruction], - user_ids: typing.Optional[typing.Sequence[str]] = OMIT, + limit: typing.Optional[int] = None, + cursor: typing.Optional[str] = None, + order_by: typing.Optional[str] = None, + order: typing.Optional[str] = None, + search: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> HttpResponse[SuccessResponse]: + ) -> SyncPager[User, UserPage]: """ - Adds new summary instructions for users graphs without removing existing ones. If user_ids is empty, adds to project-wide default instructions. - Parameters ---------- - instructions : typing.Sequence[UserInstruction] - Instructions to add to the user summary generation. + limit : typing.Optional[int] + Page size + + cursor : typing.Optional[str] + Opaque page cursor + + order_by : typing.Optional[str] + Sort field + + order : typing.Optional[str] + asc or desc - user_ids : typing.Optional[typing.Sequence[str]] - User IDs to add the instructions to. If empty, the instructions are added to the project-wide default. + search : typing.Optional[str] + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - HttpResponse[SuccessResponse] - Instructions added successfully + SyncPager[User, UserPage] + OK """ _response = self._client_wrapper.httpx_client.request( - "user-summary-instructions", + "users/list", method="POST", + params={ + "limit": limit, + "cursor": cursor, + "order_by": order_by, + "order": order, + }, json={ - "instructions": convert_and_respect_annotation_metadata( - object_=instructions, annotation=typing.Sequence[UserInstruction], direction="write" - ), - "user_ids": user_ids, + "search": search, }, headers={ "content-type": "application/json", + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, }, request_options=request_options, omit=OMIT, ) try: if 200 <= _response.status_code < 300: - _data = typing.cast( - SuccessResponse, + _parsed_response = typing.cast( + UserPage, parse_obj_as( - type_=SuccessResponse, # type: ignore + type_=UserPage, # type: ignore object_=_response.json(), ), ) - return HttpResponse(response=_response, data=_data) + _items = _parsed_response.items + _parsed_next = _parsed_response.next_cursor + _has_next = _parsed_next is not None and _parsed_next != "" + _get_next = lambda: self.list( + limit=limit, + cursor=_parsed_next, + order_by=order_by, + order=order, + search=search, + idempotency_key=idempotency_key, + request_options=request_options, + ) + return SyncPager(has_next=_has_next, items=_items, get_next=_get_next, response=_parsed_response) if _response.status_code == 400: raise BadRequestError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore object_=_response.json(), ), ), ) - if _response.status_code == 404: - raise NotFoundError( + if _response.status_code == 401: + raise UnauthorizedError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -182,8 +246,8 @@ def add_user_summary_instructions( ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -198,45 +262,53 @@ def add_user_summary_instructions( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - def delete_user_summary_instructions( + def lookup( self, *, - instruction_names: typing.Optional[typing.Sequence[str]] = OMIT, - user_ids: typing.Optional[typing.Sequence[str]] = OMIT, + graph_id: typing.Optional[str] = OMIT, + thread_id: typing.Optional[str] = OMIT, + user_id: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> HttpResponse[SuccessResponse]: + ) -> HttpResponse[User]: """ - Deletes user summary/instructions for users or project wide defaults. - Parameters ---------- - instruction_names : typing.Optional[typing.Sequence[str]] - Unique identifier for the instructions to be deleted. If empty deletes all instructions. + graph_id : typing.Optional[str] + + thread_id : typing.Optional[str] - user_ids : typing.Optional[typing.Sequence[str]] - Determines which users will have their custom instructions deleted. If no users are provided, the project-wide custom instructions will be effected. + user_id : typing.Optional[str] + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - HttpResponse[SuccessResponse] - Instructions deleted successfully + HttpResponse[User] + OK """ _response = self._client_wrapper.httpx_client.request( - "user-summary-instructions", - method="DELETE", + "users/lookup", + method="POST", json={ - "instruction_names": instruction_names, - "user_ids": user_ids, + "graph_id": graph_id, + "thread_id": thread_id, + "user_id": user_id, }, headers={ "content-type": "application/json", + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, }, request_options=request_options, omit=OMIT, @@ -244,9 +316,9 @@ def delete_user_summary_instructions( try: if 200 <= _response.status_code < 300: _data = typing.cast( - SuccessResponse, + User, parse_obj_as( - type_=SuccessResponse, # type: ignore + type_=User, # type: ignore object_=_response.json(), ), ) @@ -255,15 +327,15 @@ def delete_user_summary_instructions( raise BadRequestError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore object_=_response.json(), ), ), ) - if _response.status_code == 404: - raise NotFoundError( + if _response.status_code == 401: + raise UnauthorizedError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -273,8 +345,8 @@ def delete_user_summary_instructions( ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -289,47 +361,20 @@ def delete_user_summary_instructions( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - def add( - self, - *, - user_id: str, - disable_default_ontology: typing.Optional[bool] = OMIT, - email: typing.Optional[str] = OMIT, - first_name: typing.Optional[str] = OMIT, - last_name: typing.Optional[str] = OMIT, - metadata: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = OMIT, - time_zone: typing.Optional[str] = OMIT, - request_options: typing.Optional[RequestOptions] = None, - ) -> HttpResponse[User]: + def get(self, user_uuid: str, *, request_options: typing.Optional[RequestOptions] = None) -> HttpResponse[User]: """ - Adds a user. - Parameters ---------- - user_id : str - The unique identifier of the user. - - disable_default_ontology : typing.Optional[bool] - When true, disables the use of default/fallback ontology for the user's graph. - - email : typing.Optional[str] - The email address of the user. - - first_name : typing.Optional[str] - The first name of the user. - - last_name : typing.Optional[str] - The last name of the user. - - metadata : typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] - The metadata associated with the user. - - time_zone : typing.Optional[str] - The user's IANA time zone. Null or omission leaves it unset at creation. + user_uuid : str + User UUID request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -337,25 +382,12 @@ def add( Returns ------- HttpResponse[User] - The user that was added. + OK """ _response = self._client_wrapper.httpx_client.request( - "users", - method="POST", - json={ - "disable_default_ontology": disable_default_ontology, - "email": email, - "first_name": first_name, - "last_name": last_name, - "metadata": metadata, - "time_zone": time_zone, - "user_id": user_id, - }, - headers={ - "content-type": "application/json", - }, + f"users/{jsonable_encoder(user_uuid)}", + method="GET", request_options=request_options, - omit=OMIT, ) try: if 200 <= _response.status_code < 300: @@ -369,17 +401,6 @@ def add( return HttpResponse(response=_response, data=_data) if _response.status_code == 400: raise BadRequestError( - headers=dict(_response.headers), - body=typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ), - ) - if _response.status_code == 500: - raise InternalServerError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -389,88 +410,19 @@ def add( ), ), ) - _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_ordered( - self, - *, - page_number: typing.Optional[int] = None, - page_size: typing.Optional[int] = None, - search: typing.Optional[str] = None, - order_by: typing.Optional[str] = None, - asc: typing.Optional[bool] = None, - request_options: typing.Optional[RequestOptions] = None, - ) -> HttpResponse[UserListResponse]: - """ - Returns all users. - - Parameters - ---------- - page_number : typing.Optional[int] - Page number for pagination, starting from 1 - - page_size : typing.Optional[int] - Number of users to retrieve per page - - search : typing.Optional[str] - Search term for filtering users by user_id, name, or email - - order_by : typing.Optional[str] - Column to sort by (created_at, user_id, email) - - asc : typing.Optional[bool] - Sort in ascending order - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - HttpResponse[UserListResponse] - Successfully retrieved list of users - """ - _response = self._client_wrapper.httpx_client.request( - "users-ordered", - method="GET", - params={ - "pageNumber": page_number, - "pageSize": page_size, - "search": search, - "order_by": order_by, - "asc": asc, - }, - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - _data = typing.cast( - UserListResponse, - parse_obj_as( - type_=UserListResponse, # type: ignore - object_=_response.json(), - ), - ) - return HttpResponse(response=_response, data=_data) - if _response.status_code == 400: - raise BadRequestError( + if _response.status_code == 401: + raise UnauthorizedError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore object_=_response.json(), ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -485,44 +437,57 @@ def list_ordered( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - def get(self, user_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> HttpResponse[User]: + def delete( + self, + user_uuid: str, + *, + idempotency_key: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[UserDeleteResult]: """ - Returns a user. - Parameters ---------- - user_id : str - The user_id of the user to get. + user_uuid : str + User UUID + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - HttpResponse[User] - The user that was retrieved. + HttpResponse[UserDeleteResult] + Accepted """ _response = self._client_wrapper.httpx_client.request( - f"users/{jsonable_encoder(user_id)}", - method="GET", + f"users/{jsonable_encoder(user_uuid)}", + method="DELETE", + headers={ + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, + }, request_options=request_options, ) try: if 200 <= _response.status_code < 300: _data = typing.cast( - User, + UserDeleteResult, parse_obj_as( - type_=User, # type: ignore + type_=UserDeleteResult, # type: ignore object_=_response.json(), ), ) return HttpResponse(response=_response, data=_data) - if _response.status_code == 404: - raise NotFoundError( + if _response.status_code == 400: + raise BadRequestError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -532,8 +497,8 @@ def get(self, user_id: str, *, request_options: typing.Optional[RequestOptions] ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 401: + raise UnauthorizedError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -543,49 +508,6 @@ def get(self, user_id: str, *, request_options: typing.Optional[RequestOptions] ), ), ) - _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 delete( - self, user_id: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> HttpResponse[SuccessResponse]: - """ - Deletes a user. - - Parameters - ---------- - user_id : str - User ID - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - HttpResponse[SuccessResponse] - OK - """ - _response = self._client_wrapper.httpx_client.request( - f"users/{jsonable_encoder(user_id)}", - method="DELETE", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - _data = typing.cast( - SuccessResponse, - parse_obj_as( - type_=SuccessResponse, # type: ignore - object_=_response.json(), - ), - ) - return HttpResponse(response=_response, data=_data) if _response.status_code == 404: raise NotFoundError( headers=dict(_response.headers), @@ -597,63 +519,56 @@ def delete( ), ), ) - 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 ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) def update( self, - user_id: str, + user_uuid: str, *, disable_default_ontology: typing.Optional[bool] = OMIT, email: typing.Optional[str] = OMIT, first_name: typing.Optional[str] = OMIT, last_name: typing.Optional[str] = OMIT, - metadata: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = OMIT, + metadata: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, time_zone: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, ) -> HttpResponse[User]: """ - Updates a user. - Parameters ---------- - user_id : str - User ID + user_uuid : str + User UUID disable_default_ontology : typing.Optional[bool] - When true, disables the use of default/fallback ontology for the user's graph. + Omit to leave unchanged, send JSON null to clear, or send a value to set. email : typing.Optional[str] - The email address of the user. + Omit to leave unchanged, send JSON null to clear, or send a value to set. first_name : typing.Optional[str] - The first name of the user. + Omit to leave unchanged, send JSON null to clear, or send a value to set. last_name : typing.Optional[str] - The last name of the user. + Omit to leave unchanged, send JSON null to clear, or send a value to set. - metadata : typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] - The metadata to update + metadata : typing.Optional[typing.Dict[str, typing.Any]] time_zone : typing.Optional[str] - The user's IANA time zone. Null clears the existing value. + Omit to leave unchanged, send JSON null to clear, or send a value to set. + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -661,10 +576,10 @@ def update( Returns ------- HttpResponse[User] - The user that was updated. + OK """ _response = self._client_wrapper.httpx_client.request( - f"users/{jsonable_encoder(user_id)}", + f"users/{jsonable_encoder(user_uuid)}", method="PATCH", json={ "disable_default_ontology": disable_default_ontology, @@ -676,6 +591,7 @@ def update( }, headers={ "content-type": "application/json", + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, }, request_options=request_options, omit=OMIT, @@ -694,15 +610,15 @@ def update( raise BadRequestError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore object_=_response.json(), ), ), ) - if _response.status_code == 404: - raise NotFoundError( + if _response.status_code == 401: + raise UnauthorizedError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -712,8 +628,8 @@ def update( ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -728,46 +644,48 @@ def update( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) def get_node( - self, user_id: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> HttpResponse[UserNodeResponse]: + self, user_uuid: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> HttpResponse[JsonObject]: """ - Returns a user's node. - Parameters ---------- - user_id : str - The user_id of the user to get the node for. + user_uuid : str + User UUID request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - HttpResponse[UserNodeResponse] - Response object containing the User node. + HttpResponse[JsonObject] + OK """ _response = self._client_wrapper.httpx_client.request( - f"users/{jsonable_encoder(user_id)}/node", + f"users/{jsonable_encoder(user_uuid)}/node", method="GET", request_options=request_options, ) try: if 200 <= _response.status_code < 300: _data = typing.cast( - UserNodeResponse, + JsonObject, parse_obj_as( - type_=UserNodeResponse, # type: ignore + type_=JsonObject, # type: ignore object_=_response.json(), ), ) return HttpResponse(response=_response, data=_data) - if _response.status_code == 404: - raise NotFoundError( + if _response.status_code == 400: + raise BadRequestError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -777,8 +695,19 @@ def get_node( ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 401: + raise UnauthorizedError( + 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, @@ -793,46 +722,48 @@ def get_node( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - def get_threads( - self, user_id: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> HttpResponse[typing.List[Thread]]: + def get_summary_instructions( + self, user_uuid: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> HttpResponse[UserSummaryInstructions]: """ - Returns all threads for a user. - Parameters ---------- - user_id : str - User ID + user_uuid : str + User UUID request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - HttpResponse[typing.List[Thread]] + HttpResponse[UserSummaryInstructions] OK """ _response = self._client_wrapper.httpx_client.request( - f"users/{jsonable_encoder(user_id)}/threads", + f"users/{jsonable_encoder(user_uuid)}/summary-instructions", method="GET", request_options=request_options, ) try: if 200 <= _response.status_code < 300: _data = typing.cast( - typing.List[Thread], + UserSummaryInstructions, parse_obj_as( - type_=typing.List[Thread], # type: ignore + type_=UserSummaryInstructions, # type: ignore object_=_response.json(), ), ) return HttpResponse(response=_response, data=_data) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 400: + raise BadRequestError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -842,51 +773,8 @@ def get_threads( ), ), ) - _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 warm( - self, user_id: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> HttpResponse[SuccessResponse]: - """ - Hints Zep to warm a user's graph for low-latency search - - Parameters - ---------- - user_id : str - User ID - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - HttpResponse[SuccessResponse] - Warm hint accepted - """ - _response = self._client_wrapper.httpx_client.request( - f"users/{jsonable_encoder(user_id)}/warm", - method="GET", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - _data = typing.cast( - SuccessResponse, - parse_obj_as( - type_=SuccessResponse, # type: ignore - object_=_response.json(), - ), - ) - return HttpResponse(response=_response, data=_data) - if _response.status_code == 404: - raise NotFoundError( + if _response.status_code == 401: + raise UnauthorizedError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -896,8 +784,8 @@ def warm( ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -912,65 +800,80 @@ def warm( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - -class AsyncRawUserClient: - def __init__(self, *, client_wrapper: AsyncClientWrapper): - self._client_wrapper = client_wrapper - - async def list_user_summary_instructions( - self, *, user_id: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None - ) -> AsyncHttpResponse[ListUserInstructionsResponse]: + def set_summary_instructions( + self, + user_uuid: str, + *, + inherited: typing.Optional[bool] = OMIT, + instructions: typing.Optional[typing.Sequence[typing.Dict[str, typing.Any]]] = OMIT, + idempotency_key: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[UserSummaryInstructions]: """ - Lists all user summary instructions for a project, user. - Parameters ---------- - user_id : typing.Optional[str] - User ID to get user-specific instructions + user_uuid : str + User UUID + + inherited : typing.Optional[bool] + + instructions : typing.Optional[typing.Sequence[typing.Dict[str, typing.Any]]] + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - AsyncHttpResponse[ListUserInstructionsResponse] - The list of instructions. + HttpResponse[UserSummaryInstructions] + OK """ - _response = await self._client_wrapper.httpx_client.request( - "user-summary-instructions", - method="GET", - params={ - "user_id": user_id, + _response = self._client_wrapper.httpx_client.request( + f"users/{jsonable_encoder(user_uuid)}/summary-instructions", + method="PUT", + json={ + "inherited": inherited, + "instructions": instructions, + }, + headers={ + "content-type": "application/json", + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, }, request_options=request_options, + omit=OMIT, ) try: if 200 <= _response.status_code < 300: _data = typing.cast( - ListUserInstructionsResponse, + UserSummaryInstructions, parse_obj_as( - type_=ListUserInstructionsResponse, # type: ignore + type_=UserSummaryInstructions, # type: ignore object_=_response.json(), ), ) - return AsyncHttpResponse(response=_response, data=_data) + return HttpResponse(response=_response, data=_data) if _response.status_code == 400: raise BadRequestError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore object_=_response.json(), ), ), ) - if _response.status_code == 404: - raise NotFoundError( + if _response.status_code == 401: + raise UnauthorizedError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -980,8 +883,8 @@ async def list_user_summary_instructions( ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -996,47 +899,74 @@ async def list_user_summary_instructions( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - async def add_user_summary_instructions( + +class AsyncRawUserClient: + def __init__(self, *, client_wrapper: AsyncClientWrapper): + self._client_wrapper = client_wrapper + + async def create( self, *, - instructions: typing.Sequence[UserInstruction], - user_ids: typing.Optional[typing.Sequence[str]] = OMIT, + disable_default_ontology: typing.Optional[bool] = OMIT, + email: typing.Optional[str] = OMIT, + first_name: typing.Optional[str] = OMIT, + last_name: typing.Optional[str] = OMIT, + metadata: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + time_zone: typing.Optional[str] = OMIT, + user_id: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> AsyncHttpResponse[SuccessResponse]: + ) -> AsyncHttpResponse[User]: """ - Adds new summary instructions for users graphs without removing existing ones. If user_ids is empty, adds to project-wide default instructions. + Parameters + ---------- + disable_default_ontology : typing.Optional[bool] + + email : typing.Optional[str] + + first_name : typing.Optional[str] + + last_name : typing.Optional[str] + + metadata : typing.Optional[typing.Dict[str, typing.Any]] + + time_zone : typing.Optional[str] - Parameters - ---------- - instructions : typing.Sequence[UserInstruction] - Instructions to add to the user summary generation. + user_id : typing.Optional[str] - user_ids : typing.Optional[typing.Sequence[str]] - User IDs to add the instructions to. If empty, the instructions are added to the project-wide default. + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - AsyncHttpResponse[SuccessResponse] - Instructions added successfully + AsyncHttpResponse[User] + Created """ _response = await self._client_wrapper.httpx_client.request( - "user-summary-instructions", + "users", method="POST", json={ - "instructions": convert_and_respect_annotation_metadata( - object_=instructions, annotation=typing.Sequence[UserInstruction], direction="write" - ), - "user_ids": user_ids, + "disable_default_ontology": disable_default_ontology, + "email": email, + "first_name": first_name, + "last_name": last_name, + "metadata": metadata, + "time_zone": time_zone, + "user_id": user_id, }, headers={ "content-type": "application/json", + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, }, request_options=request_options, omit=OMIT, @@ -1044,9 +974,9 @@ async def add_user_summary_instructions( try: if 200 <= _response.status_code < 300: _data = typing.cast( - SuccessResponse, + User, parse_obj_as( - type_=SuccessResponse, # type: ignore + type_=User, # type: ignore object_=_response.json(), ), ) @@ -1055,15 +985,15 @@ async def add_user_summary_instructions( raise BadRequestError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore object_=_response.json(), ), ), ) - if _response.status_code == 404: - raise NotFoundError( + if _response.status_code == 401: + raise UnauthorizedError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -1073,8 +1003,8 @@ async def add_user_summary_instructions( ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -1089,72 +1019,109 @@ async def add_user_summary_instructions( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - async def delete_user_summary_instructions( + async def list( self, *, - instruction_names: typing.Optional[typing.Sequence[str]] = OMIT, - user_ids: typing.Optional[typing.Sequence[str]] = OMIT, + limit: typing.Optional[int] = None, + cursor: typing.Optional[str] = None, + order_by: typing.Optional[str] = None, + order: typing.Optional[str] = None, + search: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> AsyncHttpResponse[SuccessResponse]: + ) -> AsyncPager[User, UserPage]: """ - Deletes user summary/instructions for users or project wide defaults. - Parameters ---------- - instruction_names : typing.Optional[typing.Sequence[str]] - Unique identifier for the instructions to be deleted. If empty deletes all instructions. + limit : typing.Optional[int] + Page size - user_ids : typing.Optional[typing.Sequence[str]] - Determines which users will have their custom instructions deleted. If no users are provided, the project-wide custom instructions will be effected. + cursor : typing.Optional[str] + Opaque page cursor + + order_by : typing.Optional[str] + Sort field + + order : typing.Optional[str] + asc or desc + + search : typing.Optional[str] + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - AsyncHttpResponse[SuccessResponse] - Instructions deleted successfully + AsyncPager[User, UserPage] + OK """ _response = await self._client_wrapper.httpx_client.request( - "user-summary-instructions", - method="DELETE", + "users/list", + method="POST", + params={ + "limit": limit, + "cursor": cursor, + "order_by": order_by, + "order": order, + }, json={ - "instruction_names": instruction_names, - "user_ids": user_ids, + "search": search, }, headers={ "content-type": "application/json", + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, }, request_options=request_options, omit=OMIT, ) try: if 200 <= _response.status_code < 300: - _data = typing.cast( - SuccessResponse, + _parsed_response = typing.cast( + UserPage, parse_obj_as( - type_=SuccessResponse, # type: ignore + type_=UserPage, # type: ignore object_=_response.json(), ), ) - return AsyncHttpResponse(response=_response, data=_data) + _items = _parsed_response.items + _parsed_next = _parsed_response.next_cursor + _has_next = _parsed_next is not None and _parsed_next != "" + + async def _get_next(): + return await self.list( + limit=limit, + cursor=_parsed_next, + order_by=order_by, + order=order, + search=search, + idempotency_key=idempotency_key, + request_options=request_options, + ) + + return AsyncPager(has_next=_has_next, items=_items, get_next=_get_next, response=_parsed_response) if _response.status_code == 400: raise BadRequestError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore object_=_response.json(), ), ), ) - if _response.status_code == 404: - raise NotFoundError( + if _response.status_code == 401: + raise UnauthorizedError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -1164,8 +1131,8 @@ async def delete_user_summary_instructions( ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -1180,47 +1147,33 @@ async def delete_user_summary_instructions( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - async def add( + async def lookup( self, *, - user_id: str, - disable_default_ontology: typing.Optional[bool] = OMIT, - email: typing.Optional[str] = OMIT, - first_name: typing.Optional[str] = OMIT, - last_name: typing.Optional[str] = OMIT, - metadata: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = OMIT, - time_zone: typing.Optional[str] = OMIT, + graph_id: typing.Optional[str] = OMIT, + thread_id: typing.Optional[str] = OMIT, + user_id: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, ) -> AsyncHttpResponse[User]: """ - Adds a user. - Parameters ---------- - user_id : str - The unique identifier of the user. - - disable_default_ontology : typing.Optional[bool] - When true, disables the use of default/fallback ontology for the user's graph. + graph_id : typing.Optional[str] - email : typing.Optional[str] - The email address of the user. - - first_name : typing.Optional[str] - The first name of the user. - - last_name : typing.Optional[str] - The last name of the user. + thread_id : typing.Optional[str] - metadata : typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] - The metadata associated with the user. + user_id : typing.Optional[str] - time_zone : typing.Optional[str] - The user's IANA time zone. Null or omission leaves it unset at creation. + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -1228,22 +1181,19 @@ async def add( Returns ------- AsyncHttpResponse[User] - The user that was added. + OK """ _response = await self._client_wrapper.httpx_client.request( - "users", + "users/lookup", method="POST", json={ - "disable_default_ontology": disable_default_ontology, - "email": email, - "first_name": first_name, - "last_name": last_name, - "metadata": metadata, - "time_zone": time_zone, + "graph_id": graph_id, + "thread_id": thread_id, "user_id": user_id, }, headers={ "content-type": "application/json", + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, }, request_options=request_options, omit=OMIT, @@ -1260,17 +1210,6 @@ async def add( return AsyncHttpResponse(response=_response, data=_data) if _response.status_code == 400: raise BadRequestError( - headers=dict(_response.headers), - body=typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ), - ) - if _response.status_code == 500: - raise InternalServerError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -1280,88 +1219,19 @@ async def add( ), ), ) - _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_ordered( - self, - *, - page_number: typing.Optional[int] = None, - page_size: typing.Optional[int] = None, - search: typing.Optional[str] = None, - order_by: typing.Optional[str] = None, - asc: typing.Optional[bool] = None, - request_options: typing.Optional[RequestOptions] = None, - ) -> AsyncHttpResponse[UserListResponse]: - """ - Returns all users. - - Parameters - ---------- - page_number : typing.Optional[int] - Page number for pagination, starting from 1 - - page_size : typing.Optional[int] - Number of users to retrieve per page - - search : typing.Optional[str] - Search term for filtering users by user_id, name, or email - - order_by : typing.Optional[str] - Column to sort by (created_at, user_id, email) - - asc : typing.Optional[bool] - Sort in ascending order - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - AsyncHttpResponse[UserListResponse] - Successfully retrieved list of users - """ - _response = await self._client_wrapper.httpx_client.request( - "users-ordered", - method="GET", - params={ - "pageNumber": page_number, - "pageSize": page_size, - "search": search, - "order_by": order_by, - "asc": asc, - }, - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - _data = typing.cast( - UserListResponse, - parse_obj_as( - type_=UserListResponse, # type: ignore - object_=_response.json(), - ), - ) - return AsyncHttpResponse(response=_response, data=_data) - if _response.status_code == 400: - raise BadRequestError( + if _response.status_code == 401: + raise UnauthorizedError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore object_=_response.json(), ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -1376,20 +1246,22 @@ async def list_ordered( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) async def get( - self, user_id: str, *, request_options: typing.Optional[RequestOptions] = None + self, user_uuid: str, *, request_options: typing.Optional[RequestOptions] = None ) -> AsyncHttpResponse[User]: """ - Returns a user. - Parameters ---------- - user_id : str - The user_id of the user to get. + user_uuid : str + User UUID request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -1397,10 +1269,10 @@ async def get( Returns ------- AsyncHttpResponse[User] - The user that was retrieved. + OK """ _response = await self._client_wrapper.httpx_client.request( - f"users/{jsonable_encoder(user_id)}", + f"users/{jsonable_encoder(user_uuid)}", method="GET", request_options=request_options, ) @@ -1414,8 +1286,19 @@ async def get( ), ) return AsyncHttpResponse(response=_response, data=_data) - if _response.status_code == 404: - raise NotFoundError( + if _response.status_code == 400: + raise BadRequestError( + 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 == 401: + raise UnauthorizedError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -1425,8 +1308,8 @@ async def get( ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -1441,46 +1324,68 @@ async def get( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) async def delete( - self, user_id: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> AsyncHttpResponse[SuccessResponse]: + self, + user_uuid: str, + *, + idempotency_key: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[UserDeleteResult]: """ - Deletes a user. - Parameters ---------- - user_id : str - User ID + user_uuid : str + User UUID + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - AsyncHttpResponse[SuccessResponse] - OK + AsyncHttpResponse[UserDeleteResult] + Accepted """ _response = await self._client_wrapper.httpx_client.request( - f"users/{jsonable_encoder(user_id)}", + f"users/{jsonable_encoder(user_uuid)}", method="DELETE", + headers={ + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, + }, request_options=request_options, ) try: if 200 <= _response.status_code < 300: _data = typing.cast( - SuccessResponse, + UserDeleteResult, parse_obj_as( - type_=SuccessResponse, # type: ignore + type_=UserDeleteResult, # type: ignore object_=_response.json(), ), ) return AsyncHttpResponse(response=_response, data=_data) - if _response.status_code == 404: - raise NotFoundError( + if _response.status_code == 400: + raise BadRequestError( + 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 == 401: + raise UnauthorizedError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -1490,8 +1395,8 @@ async def delete( ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -1506,47 +1411,51 @@ async def delete( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) async def update( self, - user_id: str, + user_uuid: str, *, disable_default_ontology: typing.Optional[bool] = OMIT, email: typing.Optional[str] = OMIT, first_name: typing.Optional[str] = OMIT, last_name: typing.Optional[str] = OMIT, - metadata: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = OMIT, + metadata: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, time_zone: typing.Optional[str] = OMIT, + idempotency_key: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, ) -> AsyncHttpResponse[User]: """ - Updates a user. - Parameters ---------- - user_id : str - User ID + user_uuid : str + User UUID disable_default_ontology : typing.Optional[bool] - When true, disables the use of default/fallback ontology for the user's graph. + Omit to leave unchanged, send JSON null to clear, or send a value to set. email : typing.Optional[str] - The email address of the user. + Omit to leave unchanged, send JSON null to clear, or send a value to set. first_name : typing.Optional[str] - The first name of the user. + Omit to leave unchanged, send JSON null to clear, or send a value to set. last_name : typing.Optional[str] - The last name of the user. + Omit to leave unchanged, send JSON null to clear, or send a value to set. - metadata : typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] - The metadata to update + metadata : typing.Optional[typing.Dict[str, typing.Any]] time_zone : typing.Optional[str] - The user's IANA time zone. Null clears the existing value. + Omit to leave unchanged, send JSON null to clear, or send a value to set. + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -1554,10 +1463,10 @@ async def update( Returns ------- AsyncHttpResponse[User] - The user that was updated. + OK """ _response = await self._client_wrapper.httpx_client.request( - f"users/{jsonable_encoder(user_id)}", + f"users/{jsonable_encoder(user_uuid)}", method="PATCH", json={ "disable_default_ontology": disable_default_ontology, @@ -1569,6 +1478,7 @@ async def update( }, headers={ "content-type": "application/json", + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, }, request_options=request_options, omit=OMIT, @@ -1587,15 +1497,15 @@ async def update( raise BadRequestError( headers=dict(_response.headers), body=typing.cast( - typing.Optional[typing.Any], + types_api_error_ApiError, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=types_api_error_ApiError, # type: ignore object_=_response.json(), ), ), ) - if _response.status_code == 404: - raise NotFoundError( + if _response.status_code == 401: + raise UnauthorizedError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -1605,8 +1515,8 @@ async def update( ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -1621,46 +1531,59 @@ async def update( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) async def get_node( - self, user_id: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> AsyncHttpResponse[UserNodeResponse]: + self, user_uuid: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> AsyncHttpResponse[JsonObject]: """ - Returns a user's node. - Parameters ---------- - user_id : str - The user_id of the user to get the node for. + user_uuid : str + User UUID request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - AsyncHttpResponse[UserNodeResponse] - Response object containing the User node. + AsyncHttpResponse[JsonObject] + OK """ _response = await self._client_wrapper.httpx_client.request( - f"users/{jsonable_encoder(user_id)}/node", + f"users/{jsonable_encoder(user_uuid)}/node", method="GET", request_options=request_options, ) try: if 200 <= _response.status_code < 300: _data = typing.cast( - UserNodeResponse, + JsonObject, parse_obj_as( - type_=UserNodeResponse, # type: ignore + type_=JsonObject, # type: ignore object_=_response.json(), ), ) return AsyncHttpResponse(response=_response, data=_data) - if _response.status_code == 404: - raise NotFoundError( + if _response.status_code == 400: + raise BadRequestError( + 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 == 401: + raise UnauthorizedError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -1670,8 +1593,8 @@ async def get_node( ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -1686,46 +1609,70 @@ async def get_node( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - async def get_threads( - self, user_id: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> AsyncHttpResponse[typing.List[Thread]]: + async def get_summary_instructions( + self, user_uuid: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> AsyncHttpResponse[UserSummaryInstructions]: """ - Returns all threads for a user. - Parameters ---------- - user_id : str - User ID + user_uuid : str + User UUID request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - AsyncHttpResponse[typing.List[Thread]] + AsyncHttpResponse[UserSummaryInstructions] OK """ _response = await self._client_wrapper.httpx_client.request( - f"users/{jsonable_encoder(user_id)}/threads", + f"users/{jsonable_encoder(user_uuid)}/summary-instructions", method="GET", request_options=request_options, ) try: if 200 <= _response.status_code < 300: _data = typing.cast( - typing.List[Thread], + UserSummaryInstructions, parse_obj_as( - type_=typing.List[Thread], # type: ignore + type_=UserSummaryInstructions, # type: ignore object_=_response.json(), ), ) return AsyncHttpResponse(response=_response, data=_data) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 400: + raise BadRequestError( + 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 == 401: + raise UnauthorizedError( + 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, @@ -1740,46 +1687,80 @@ async def get_threads( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - async def warm( - self, user_id: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> AsyncHttpResponse[SuccessResponse]: + async def set_summary_instructions( + self, + user_uuid: str, + *, + inherited: typing.Optional[bool] = OMIT, + instructions: typing.Optional[typing.Sequence[typing.Dict[str, typing.Any]]] = OMIT, + idempotency_key: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[UserSummaryInstructions]: """ - Hints Zep to warm a user's graph for low-latency search - Parameters ---------- - user_id : str - User ID + user_uuid : str + User UUID + + inherited : typing.Optional[bool] + + instructions : typing.Optional[typing.Sequence[typing.Dict[str, typing.Any]]] + + idempotency_key : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - AsyncHttpResponse[SuccessResponse] - Warm hint accepted + AsyncHttpResponse[UserSummaryInstructions] + OK """ _response = await self._client_wrapper.httpx_client.request( - f"users/{jsonable_encoder(user_id)}/warm", - method="GET", + f"users/{jsonable_encoder(user_uuid)}/summary-instructions", + method="PUT", + json={ + "inherited": inherited, + "instructions": instructions, + }, + headers={ + "content-type": "application/json", + "Idempotency-Key": str(idempotency_key) if idempotency_key is not None else None, + }, request_options=request_options, + omit=OMIT, ) try: if 200 <= _response.status_code < 300: _data = typing.cast( - SuccessResponse, + UserSummaryInstructions, parse_obj_as( - type_=SuccessResponse, # type: ignore + type_=UserSummaryInstructions, # type: ignore object_=_response.json(), ), ) return AsyncHttpResponse(response=_response, data=_data) - if _response.status_code == 404: - raise NotFoundError( + if _response.status_code == 400: + raise BadRequestError( + 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 == 401: + raise UnauthorizedError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -1789,8 +1770,8 @@ async def warm( ), ), ) - if _response.status_code == 500: - raise InternalServerError( + if _response.status_code == 404: + raise NotFoundError( headers=dict(_response.headers), body=typing.cast( types_api_error_ApiError, @@ -1805,6 +1786,10 @@ async def warm( raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response.text ) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) raise core_api_error_ApiError( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) diff --git a/src/zep_cloud/user_group/client.py b/src/zep_cloud/user_group/client.py deleted file mode 100644 index 631a7b4f..00000000 --- a/src/zep_cloud/user_group/client.py +++ /dev/null @@ -1,1450 +0,0 @@ -# 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.attached_policy_sets_response import AttachedPolicySetsResponse -from ..types.user_group_list_response import UserGroupListResponse -from ..types.user_group_members_response import UserGroupMembersResponse -from ..types.user_group_membership_response import UserGroupMembershipResponse -from ..types.user_group_response import UserGroupResponse -from ..types.user_membership_groups_response import UserMembershipGroupsResponse -from .raw_client import AsyncRawUserGroupClient, RawUserGroupClient - -# this is used as the default value for optional parameters -OMIT = typing.cast(typing.Any, ...) - - -class UserGroupClient: - def __init__(self, *, client_wrapper: SyncClientWrapper): - self._raw_client = RawUserGroupClient(client_wrapper=client_wrapper) - - @property - def with_raw_response(self) -> RawUserGroupClient: - """ - Retrieves a raw implementation of this client that returns raw responses. - - Returns - ------- - RawUserGroupClient - """ - return self._raw_client - - def list_policy_sets( - self, group_uuid: str, *, project_id: str, request_options: typing.Optional[RequestOptions] = None - ) -> AttachedPolicySetsResponse: - """ - Parameters - ---------- - group_uuid : str - UserGroup UUID - - project_id : str - Project UUID - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - AttachedPolicySetsResponse - OK - - Examples - -------- - from zep_cloud import Zep - - client = Zep( - api_key="YOUR_API_KEY", - ) - client.user_group.list_policy_sets( - group_uuid="groupUUID", - project_id="projectId", - ) - """ - _response = self._raw_client.list_policy_sets( - group_uuid, project_id=project_id, request_options=request_options - ) - return _response.data - - def attach_policy_set( - self, - group_uuid: str, - *, - project_id: str, - policy_set_uuid: str, - request_options: typing.Optional[RequestOptions] = None, - ) -> AttachedPolicySetsResponse: - """ - Parameters - ---------- - group_uuid : str - UserGroup UUID - - project_id : str - Project UUID - - policy_set_uuid : str - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - AttachedPolicySetsResponse - OK - - Examples - -------- - from zep_cloud import Zep - - client = Zep( - api_key="YOUR_API_KEY", - ) - client.user_group.attach_policy_set( - group_uuid="groupUUID", - project_id="projectId", - policy_set_uuid="policy_set_uuid", - ) - """ - _response = self._raw_client.attach_policy_set( - group_uuid, project_id=project_id, policy_set_uuid=policy_set_uuid, request_options=request_options - ) - return _response.data - - def detach_policy_set( - self, - group_uuid: str, - policy_set_uuid: str, - *, - project_id: str, - request_options: typing.Optional[RequestOptions] = None, - ) -> AttachedPolicySetsResponse: - """ - Parameters - ---------- - group_uuid : str - UserGroup UUID - - policy_set_uuid : str - Policy set UUID - - project_id : str - Project UUID - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - AttachedPolicySetsResponse - OK - - Examples - -------- - from zep_cloud import Zep - - client = Zep( - api_key="YOUR_API_KEY", - ) - client.user_group.detach_policy_set( - group_uuid="groupUUID", - policy_set_uuid="policySetUUID", - project_id="projectId", - ) - """ - _response = self._raw_client.detach_policy_set( - group_uuid, policy_set_uuid, project_id=project_id, request_options=request_options - ) - return _response.data - - def list( - self, - *, - project_id: str, - page_number: int, - page_size: int, - search: typing.Optional[str] = None, - request_options: typing.Optional[RequestOptions] = None, - ) -> UserGroupListResponse: - """ - Parameters - ---------- - project_id : str - Project UUID - - page_number : int - Page number - - page_size : int - Page size - - search : typing.Optional[str] - Name search - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - UserGroupListResponse - OK - - Examples - -------- - from zep_cloud import Zep - - client = Zep( - api_key="YOUR_API_KEY", - ) - client.user_group.list( - project_id="projectId", - page_number=1, - page_size=1, - search="search", - ) - """ - _response = self._raw_client.list( - project_id=project_id, - page_number=page_number, - page_size=page_size, - search=search, - request_options=request_options, - ) - return _response.data - - def create( - self, - *, - project_id: str, - name: str, - description: typing.Optional[str] = OMIT, - request_options: typing.Optional[RequestOptions] = None, - ) -> UserGroupResponse: - """ - Parameters - ---------- - project_id : str - Project UUID - - name : str - - description : typing.Optional[str] - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - UserGroupResponse - Created - - Examples - -------- - from zep_cloud import Zep - - client = Zep( - api_key="YOUR_API_KEY", - ) - client.user_group.create( - project_id="projectId", - name="name", - ) - """ - _response = self._raw_client.create( - project_id=project_id, name=name, description=description, request_options=request_options - ) - return _response.data - - def list_for_user( - self, user_uuid: str, *, project_id: str, request_options: typing.Optional[RequestOptions] = None - ) -> UserMembershipGroupsResponse: - """ - Parameters - ---------- - user_uuid : str - User UUID - - project_id : str - Project UUID - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - UserMembershipGroupsResponse - OK - - Examples - -------- - from zep_cloud import Zep - - client = Zep( - api_key="YOUR_API_KEY", - ) - client.user_group.list_for_user( - user_uuid="userUUID", - project_id="projectId", - ) - """ - _response = self._raw_client.list_for_user(user_uuid, project_id=project_id, request_options=request_options) - return _response.data - - def get( - self, group_uuid: str, *, project_id: str, request_options: typing.Optional[RequestOptions] = None - ) -> UserGroupResponse: - """ - Parameters - ---------- - group_uuid : str - UserGroup UUID - - project_id : str - Project UUID - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - UserGroupResponse - OK - - Examples - -------- - from zep_cloud import Zep - - client = Zep( - api_key="YOUR_API_KEY", - ) - client.user_group.get( - group_uuid="groupUUID", - project_id="projectId", - ) - """ - _response = self._raw_client.get(group_uuid, project_id=project_id, request_options=request_options) - return _response.data - - def delete( - self, group_uuid: str, *, project_id: str, request_options: typing.Optional[RequestOptions] = None - ) -> None: - """ - Parameters - ---------- - group_uuid : str - UserGroup UUID - - project_id : str - Project UUID - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - None - - Examples - -------- - from zep_cloud import Zep - - client = Zep( - api_key="YOUR_API_KEY", - ) - client.user_group.delete( - group_uuid="groupUUID", - project_id="projectId", - ) - """ - _response = self._raw_client.delete(group_uuid, project_id=project_id, request_options=request_options) - return _response.data - - def update( - self, - group_uuid: str, - *, - project_id: str, - expected_version: int, - description: typing.Optional[str] = OMIT, - name: typing.Optional[str] = OMIT, - request_options: typing.Optional[RequestOptions] = None, - ) -> UserGroupResponse: - """ - Parameters - ---------- - group_uuid : str - UserGroup UUID - - project_id : str - Project UUID - - expected_version : int - - description : typing.Optional[str] - - name : typing.Optional[str] - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - UserGroupResponse - OK - - Examples - -------- - from zep_cloud import Zep - - client = Zep( - api_key="YOUR_API_KEY", - ) - client.user_group.update( - group_uuid="groupUUID", - project_id="projectId", - expected_version=1, - ) - """ - _response = self._raw_client.update( - group_uuid, - project_id=project_id, - expected_version=expected_version, - description=description, - name=name, - request_options=request_options, - ) - return _response.data - - def list_members( - self, - group_uuid: str, - *, - project_id: str, - page_number: int, - page_size: int, - search: typing.Optional[str] = None, - request_options: typing.Optional[RequestOptions] = None, - ) -> UserGroupMembersResponse: - """ - Parameters - ---------- - group_uuid : str - UserGroup UUID - - project_id : str - Project UUID - - page_number : int - Page number - - page_size : int - Page size - - search : typing.Optional[str] - User search - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - UserGroupMembersResponse - OK - - Examples - -------- - from zep_cloud import Zep - - client = Zep( - api_key="YOUR_API_KEY", - ) - client.user_group.list_members( - group_uuid="groupUUID", - project_id="projectId", - page_number=1, - page_size=1, - search="search", - ) - """ - _response = self._raw_client.list_members( - group_uuid, - project_id=project_id, - page_number=page_number, - page_size=page_size, - search=search, - request_options=request_options, - ) - return _response.data - - def add_members( - self, - group_uuid: str, - *, - project_id: str, - user_uuids: typing.Sequence[str], - request_options: typing.Optional[RequestOptions] = None, - ) -> UserGroupMembershipResponse: - """ - Parameters - ---------- - group_uuid : str - UserGroup UUID - - project_id : str - Project UUID - - user_uuids : typing.Sequence[str] - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - UserGroupMembershipResponse - OK - - Examples - -------- - from zep_cloud import Zep - - client = Zep( - api_key="YOUR_API_KEY", - ) - client.user_group.add_members( - group_uuid="groupUUID", - project_id="projectId", - user_uuids=["user_uuids"], - ) - """ - _response = self._raw_client.add_members( - group_uuid, project_id=project_id, user_uuids=user_uuids, request_options=request_options - ) - return _response.data - - def remove_members( - self, - group_uuid: str, - *, - project_id: str, - user_uuids: typing.Sequence[str], - request_options: typing.Optional[RequestOptions] = None, - ) -> UserGroupMembershipResponse: - """ - Parameters - ---------- - group_uuid : str - UserGroup UUID - - project_id : str - Project UUID - - user_uuids : typing.Sequence[str] - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - UserGroupMembershipResponse - OK - - Examples - -------- - from zep_cloud import Zep - - client = Zep( - api_key="YOUR_API_KEY", - ) - client.user_group.remove_members( - group_uuid="groupUUID", - project_id="projectId", - user_uuids=["user_uuids"], - ) - """ - _response = self._raw_client.remove_members( - group_uuid, project_id=project_id, user_uuids=user_uuids, request_options=request_options - ) - return _response.data - - def list_member_candidates( - self, - group_uuid: str, - *, - project_id: str, - page_number: int, - page_size: int, - search: typing.Optional[str] = None, - request_options: typing.Optional[RequestOptions] = None, - ) -> UserGroupMembersResponse: - """ - Parameters - ---------- - group_uuid : str - UserGroup UUID - - project_id : str - Project UUID - - page_number : int - Page number - - page_size : int - Page size - - search : typing.Optional[str] - User search - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - UserGroupMembersResponse - OK - - Examples - -------- - from zep_cloud import Zep - - client = Zep( - api_key="YOUR_API_KEY", - ) - client.user_group.list_member_candidates( - group_uuid="groupUUID", - project_id="projectId", - page_number=1, - page_size=1, - search="search", - ) - """ - _response = self._raw_client.list_member_candidates( - group_uuid, - project_id=project_id, - page_number=page_number, - page_size=page_size, - search=search, - request_options=request_options, - ) - return _response.data - - def remove_member( - self, - group_uuid: str, - user_uuid: str, - *, - project_id: str, - request_options: typing.Optional[RequestOptions] = None, - ) -> UserGroupMembershipResponse: - """ - Parameters - ---------- - group_uuid : str - UserGroup UUID - - user_uuid : str - User UUID - - project_id : str - Project UUID - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - UserGroupMembershipResponse - OK - - Examples - -------- - from zep_cloud import Zep - - client = Zep( - api_key="YOUR_API_KEY", - ) - client.user_group.remove_member( - group_uuid="groupUUID", - user_uuid="userUUID", - project_id="projectId", - ) - """ - _response = self._raw_client.remove_member( - group_uuid, user_uuid, project_id=project_id, request_options=request_options - ) - return _response.data - - -class AsyncUserGroupClient: - def __init__(self, *, client_wrapper: AsyncClientWrapper): - self._raw_client = AsyncRawUserGroupClient(client_wrapper=client_wrapper) - - @property - def with_raw_response(self) -> AsyncRawUserGroupClient: - """ - Retrieves a raw implementation of this client that returns raw responses. - - Returns - ------- - AsyncRawUserGroupClient - """ - return self._raw_client - - async def list_policy_sets( - self, group_uuid: str, *, project_id: str, request_options: typing.Optional[RequestOptions] = None - ) -> AttachedPolicySetsResponse: - """ - Parameters - ---------- - group_uuid : str - UserGroup UUID - - project_id : str - Project UUID - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - AttachedPolicySetsResponse - OK - - Examples - -------- - import asyncio - - from zep_cloud import AsyncZep - - client = AsyncZep( - api_key="YOUR_API_KEY", - ) - - - async def main() -> None: - await client.user_group.list_policy_sets( - group_uuid="groupUUID", - project_id="projectId", - ) - - - asyncio.run(main()) - """ - _response = await self._raw_client.list_policy_sets( - group_uuid, project_id=project_id, request_options=request_options - ) - return _response.data - - async def attach_policy_set( - self, - group_uuid: str, - *, - project_id: str, - policy_set_uuid: str, - request_options: typing.Optional[RequestOptions] = None, - ) -> AttachedPolicySetsResponse: - """ - Parameters - ---------- - group_uuid : str - UserGroup UUID - - project_id : str - Project UUID - - policy_set_uuid : str - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - AttachedPolicySetsResponse - OK - - Examples - -------- - import asyncio - - from zep_cloud import AsyncZep - - client = AsyncZep( - api_key="YOUR_API_KEY", - ) - - - async def main() -> None: - await client.user_group.attach_policy_set( - group_uuid="groupUUID", - project_id="projectId", - policy_set_uuid="policy_set_uuid", - ) - - - asyncio.run(main()) - """ - _response = await self._raw_client.attach_policy_set( - group_uuid, project_id=project_id, policy_set_uuid=policy_set_uuid, request_options=request_options - ) - return _response.data - - async def detach_policy_set( - self, - group_uuid: str, - policy_set_uuid: str, - *, - project_id: str, - request_options: typing.Optional[RequestOptions] = None, - ) -> AttachedPolicySetsResponse: - """ - Parameters - ---------- - group_uuid : str - UserGroup UUID - - policy_set_uuid : str - Policy set UUID - - project_id : str - Project UUID - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - AttachedPolicySetsResponse - OK - - Examples - -------- - import asyncio - - from zep_cloud import AsyncZep - - client = AsyncZep( - api_key="YOUR_API_KEY", - ) - - - async def main() -> None: - await client.user_group.detach_policy_set( - group_uuid="groupUUID", - policy_set_uuid="policySetUUID", - project_id="projectId", - ) - - - asyncio.run(main()) - """ - _response = await self._raw_client.detach_policy_set( - group_uuid, policy_set_uuid, project_id=project_id, request_options=request_options - ) - return _response.data - - async def list( - self, - *, - project_id: str, - page_number: int, - page_size: int, - search: typing.Optional[str] = None, - request_options: typing.Optional[RequestOptions] = None, - ) -> UserGroupListResponse: - """ - Parameters - ---------- - project_id : str - Project UUID - - page_number : int - Page number - - page_size : int - Page size - - search : typing.Optional[str] - Name search - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - UserGroupListResponse - OK - - Examples - -------- - import asyncio - - from zep_cloud import AsyncZep - - client = AsyncZep( - api_key="YOUR_API_KEY", - ) - - - async def main() -> None: - await client.user_group.list( - project_id="projectId", - page_number=1, - page_size=1, - search="search", - ) - - - asyncio.run(main()) - """ - _response = await self._raw_client.list( - project_id=project_id, - page_number=page_number, - page_size=page_size, - search=search, - request_options=request_options, - ) - return _response.data - - async def create( - self, - *, - project_id: str, - name: str, - description: typing.Optional[str] = OMIT, - request_options: typing.Optional[RequestOptions] = None, - ) -> UserGroupResponse: - """ - Parameters - ---------- - project_id : str - Project UUID - - name : str - - description : typing.Optional[str] - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - UserGroupResponse - Created - - Examples - -------- - import asyncio - - from zep_cloud import AsyncZep - - client = AsyncZep( - api_key="YOUR_API_KEY", - ) - - - async def main() -> None: - await client.user_group.create( - project_id="projectId", - name="name", - ) - - - asyncio.run(main()) - """ - _response = await self._raw_client.create( - project_id=project_id, name=name, description=description, request_options=request_options - ) - return _response.data - - async def list_for_user( - self, user_uuid: str, *, project_id: str, request_options: typing.Optional[RequestOptions] = None - ) -> UserMembershipGroupsResponse: - """ - Parameters - ---------- - user_uuid : str - User UUID - - project_id : str - Project UUID - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - UserMembershipGroupsResponse - OK - - Examples - -------- - import asyncio - - from zep_cloud import AsyncZep - - client = AsyncZep( - api_key="YOUR_API_KEY", - ) - - - async def main() -> None: - await client.user_group.list_for_user( - user_uuid="userUUID", - project_id="projectId", - ) - - - asyncio.run(main()) - """ - _response = await self._raw_client.list_for_user( - user_uuid, project_id=project_id, request_options=request_options - ) - return _response.data - - async def get( - self, group_uuid: str, *, project_id: str, request_options: typing.Optional[RequestOptions] = None - ) -> UserGroupResponse: - """ - Parameters - ---------- - group_uuid : str - UserGroup UUID - - project_id : str - Project UUID - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - UserGroupResponse - OK - - Examples - -------- - import asyncio - - from zep_cloud import AsyncZep - - client = AsyncZep( - api_key="YOUR_API_KEY", - ) - - - async def main() -> None: - await client.user_group.get( - group_uuid="groupUUID", - project_id="projectId", - ) - - - asyncio.run(main()) - """ - _response = await self._raw_client.get(group_uuid, project_id=project_id, request_options=request_options) - return _response.data - - async def delete( - self, group_uuid: str, *, project_id: str, request_options: typing.Optional[RequestOptions] = None - ) -> None: - """ - Parameters - ---------- - group_uuid : str - UserGroup UUID - - project_id : str - Project UUID - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - None - - Examples - -------- - import asyncio - - from zep_cloud import AsyncZep - - client = AsyncZep( - api_key="YOUR_API_KEY", - ) - - - async def main() -> None: - await client.user_group.delete( - group_uuid="groupUUID", - project_id="projectId", - ) - - - asyncio.run(main()) - """ - _response = await self._raw_client.delete(group_uuid, project_id=project_id, request_options=request_options) - return _response.data - - async def update( - self, - group_uuid: str, - *, - project_id: str, - expected_version: int, - description: typing.Optional[str] = OMIT, - name: typing.Optional[str] = OMIT, - request_options: typing.Optional[RequestOptions] = None, - ) -> UserGroupResponse: - """ - Parameters - ---------- - group_uuid : str - UserGroup UUID - - project_id : str - Project UUID - - expected_version : int - - description : typing.Optional[str] - - name : typing.Optional[str] - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - UserGroupResponse - OK - - Examples - -------- - import asyncio - - from zep_cloud import AsyncZep - - client = AsyncZep( - api_key="YOUR_API_KEY", - ) - - - async def main() -> None: - await client.user_group.update( - group_uuid="groupUUID", - project_id="projectId", - expected_version=1, - ) - - - asyncio.run(main()) - """ - _response = await self._raw_client.update( - group_uuid, - project_id=project_id, - expected_version=expected_version, - description=description, - name=name, - request_options=request_options, - ) - return _response.data - - async def list_members( - self, - group_uuid: str, - *, - project_id: str, - page_number: int, - page_size: int, - search: typing.Optional[str] = None, - request_options: typing.Optional[RequestOptions] = None, - ) -> UserGroupMembersResponse: - """ - Parameters - ---------- - group_uuid : str - UserGroup UUID - - project_id : str - Project UUID - - page_number : int - Page number - - page_size : int - Page size - - search : typing.Optional[str] - User search - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - UserGroupMembersResponse - OK - - Examples - -------- - import asyncio - - from zep_cloud import AsyncZep - - client = AsyncZep( - api_key="YOUR_API_KEY", - ) - - - async def main() -> None: - await client.user_group.list_members( - group_uuid="groupUUID", - project_id="projectId", - page_number=1, - page_size=1, - search="search", - ) - - - asyncio.run(main()) - """ - _response = await self._raw_client.list_members( - group_uuid, - project_id=project_id, - page_number=page_number, - page_size=page_size, - search=search, - request_options=request_options, - ) - return _response.data - - async def add_members( - self, - group_uuid: str, - *, - project_id: str, - user_uuids: typing.Sequence[str], - request_options: typing.Optional[RequestOptions] = None, - ) -> UserGroupMembershipResponse: - """ - Parameters - ---------- - group_uuid : str - UserGroup UUID - - project_id : str - Project UUID - - user_uuids : typing.Sequence[str] - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - UserGroupMembershipResponse - OK - - Examples - -------- - import asyncio - - from zep_cloud import AsyncZep - - client = AsyncZep( - api_key="YOUR_API_KEY", - ) - - - async def main() -> None: - await client.user_group.add_members( - group_uuid="groupUUID", - project_id="projectId", - user_uuids=["user_uuids"], - ) - - - asyncio.run(main()) - """ - _response = await self._raw_client.add_members( - group_uuid, project_id=project_id, user_uuids=user_uuids, request_options=request_options - ) - return _response.data - - async def remove_members( - self, - group_uuid: str, - *, - project_id: str, - user_uuids: typing.Sequence[str], - request_options: typing.Optional[RequestOptions] = None, - ) -> UserGroupMembershipResponse: - """ - Parameters - ---------- - group_uuid : str - UserGroup UUID - - project_id : str - Project UUID - - user_uuids : typing.Sequence[str] - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - UserGroupMembershipResponse - OK - - Examples - -------- - import asyncio - - from zep_cloud import AsyncZep - - client = AsyncZep( - api_key="YOUR_API_KEY", - ) - - - async def main() -> None: - await client.user_group.remove_members( - group_uuid="groupUUID", - project_id="projectId", - user_uuids=["user_uuids"], - ) - - - asyncio.run(main()) - """ - _response = await self._raw_client.remove_members( - group_uuid, project_id=project_id, user_uuids=user_uuids, request_options=request_options - ) - return _response.data - - async def list_member_candidates( - self, - group_uuid: str, - *, - project_id: str, - page_number: int, - page_size: int, - search: typing.Optional[str] = None, - request_options: typing.Optional[RequestOptions] = None, - ) -> UserGroupMembersResponse: - """ - Parameters - ---------- - group_uuid : str - UserGroup UUID - - project_id : str - Project UUID - - page_number : int - Page number - - page_size : int - Page size - - search : typing.Optional[str] - User search - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - UserGroupMembersResponse - OK - - Examples - -------- - import asyncio - - from zep_cloud import AsyncZep - - client = AsyncZep( - api_key="YOUR_API_KEY", - ) - - - async def main() -> None: - await client.user_group.list_member_candidates( - group_uuid="groupUUID", - project_id="projectId", - page_number=1, - page_size=1, - search="search", - ) - - - asyncio.run(main()) - """ - _response = await self._raw_client.list_member_candidates( - group_uuid, - project_id=project_id, - page_number=page_number, - page_size=page_size, - search=search, - request_options=request_options, - ) - return _response.data - - async def remove_member( - self, - group_uuid: str, - user_uuid: str, - *, - project_id: str, - request_options: typing.Optional[RequestOptions] = None, - ) -> UserGroupMembershipResponse: - """ - Parameters - ---------- - group_uuid : str - UserGroup UUID - - user_uuid : str - User UUID - - project_id : str - Project UUID - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - UserGroupMembershipResponse - OK - - Examples - -------- - import asyncio - - from zep_cloud import AsyncZep - - client = AsyncZep( - api_key="YOUR_API_KEY", - ) - - - async def main() -> None: - await client.user_group.remove_member( - group_uuid="groupUUID", - user_uuid="userUUID", - project_id="projectId", - ) - - - asyncio.run(main()) - """ - _response = await self._raw_client.remove_member( - group_uuid, user_uuid, project_id=project_id, request_options=request_options - ) - return _response.data diff --git a/src/zep_cloud/user_group/raw_client.py b/src/zep_cloud/user_group/raw_client.py deleted file mode 100644 index 3253fc42..00000000 --- a/src/zep_cloud/user_group/raw_client.py +++ /dev/null @@ -1,2487 +0,0 @@ -# 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 ..errors.bad_request_error import BadRequestError -from ..errors.conflict_error import ConflictError -from ..errors.forbidden_error import ForbiddenError -from ..errors.not_found_error import NotFoundError -from ..types.api_error import ApiError as types_api_error_ApiError -from ..types.attached_policy_sets_response import AttachedPolicySetsResponse -from ..types.user_group_list_response import UserGroupListResponse -from ..types.user_group_members_response import UserGroupMembersResponse -from ..types.user_group_membership_response import UserGroupMembershipResponse -from ..types.user_group_response import UserGroupResponse -from ..types.user_membership_groups_response import UserMembershipGroupsResponse - -# this is used as the default value for optional parameters -OMIT = typing.cast(typing.Any, ...) - - -class RawUserGroupClient: - def __init__(self, *, client_wrapper: SyncClientWrapper): - self._client_wrapper = client_wrapper - - def list_policy_sets( - self, group_uuid: str, *, project_id: str, request_options: typing.Optional[RequestOptions] = None - ) -> HttpResponse[AttachedPolicySetsResponse]: - """ - Parameters - ---------- - group_uuid : str - UserGroup UUID - - project_id : str - Project UUID - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - HttpResponse[AttachedPolicySetsResponse] - OK - """ - _response = self._client_wrapper.httpx_client.request( - f"abac/user-groups/{jsonable_encoder(group_uuid)}/policy-sets", - method="GET", - params={ - "projectId": project_id, - }, - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - _data = typing.cast( - AttachedPolicySetsResponse, - parse_obj_as( - type_=AttachedPolicySetsResponse, # 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(), - ), - ), - ) - _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 attach_policy_set( - self, - group_uuid: str, - *, - project_id: str, - policy_set_uuid: str, - request_options: typing.Optional[RequestOptions] = None, - ) -> HttpResponse[AttachedPolicySetsResponse]: - """ - Parameters - ---------- - group_uuid : str - UserGroup UUID - - project_id : str - Project UUID - - policy_set_uuid : str - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - HttpResponse[AttachedPolicySetsResponse] - OK - """ - _response = self._client_wrapper.httpx_client.request( - f"abac/user-groups/{jsonable_encoder(group_uuid)}/policy-sets", - method="POST", - params={ - "projectId": project_id, - }, - json={ - "policy_set_uuid": policy_set_uuid, - }, - headers={ - "content-type": "application/json", - }, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - _data = typing.cast( - AttachedPolicySetsResponse, - parse_obj_as( - type_=AttachedPolicySetsResponse, # type: ignore - object_=_response.json(), - ), - ) - return HttpResponse(response=_response, data=_data) - if _response.status_code == 400: - raise BadRequestError( - headers=dict(_response.headers), - body=typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ), - ) - if _response.status_code == 403: - raise ForbiddenError( - headers=dict(_response.headers), - body=typing.cast( - types_api_error_ApiError, - parse_obj_as( - type_=types_api_error_ApiError, # type: ignore - object_=_response.json(), - ), - ), - ) - if _response.status_code == 404: - raise NotFoundError( - headers=dict(_response.headers), - body=typing.cast( - types_api_error_ApiError, - parse_obj_as( - type_=types_api_error_ApiError, # type: ignore - object_=_response.json(), - ), - ), - ) - _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 detach_policy_set( - self, - group_uuid: str, - policy_set_uuid: str, - *, - project_id: str, - request_options: typing.Optional[RequestOptions] = None, - ) -> HttpResponse[AttachedPolicySetsResponse]: - """ - Parameters - ---------- - group_uuid : str - UserGroup UUID - - policy_set_uuid : str - Policy set UUID - - project_id : str - Project UUID - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - HttpResponse[AttachedPolicySetsResponse] - OK - """ - _response = self._client_wrapper.httpx_client.request( - f"abac/user-groups/{jsonable_encoder(group_uuid)}/policy-sets/{jsonable_encoder(policy_set_uuid)}", - method="DELETE", - params={ - "projectId": project_id, - }, - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - _data = typing.cast( - AttachedPolicySetsResponse, - parse_obj_as( - type_=AttachedPolicySetsResponse, # 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(), - ), - ), - ) - _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( - self, - *, - project_id: str, - page_number: int, - page_size: int, - search: typing.Optional[str] = None, - request_options: typing.Optional[RequestOptions] = None, - ) -> HttpResponse[UserGroupListResponse]: - """ - Parameters - ---------- - project_id : str - Project UUID - - page_number : int - Page number - - page_size : int - Page size - - search : typing.Optional[str] - Name search - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - HttpResponse[UserGroupListResponse] - OK - """ - _response = self._client_wrapper.httpx_client.request( - "user-groups", - method="GET", - params={ - "projectId": project_id, - "pageNumber": page_number, - "pageSize": page_size, - "search": search, - }, - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - _data = typing.cast( - UserGroupListResponse, - parse_obj_as( - type_=UserGroupListResponse, # type: ignore - object_=_response.json(), - ), - ) - return HttpResponse(response=_response, data=_data) - if _response.status_code == 400: - raise BadRequestError( - headers=dict(_response.headers), - body=typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ), - ) - if _response.status_code == 403: - raise ForbiddenError( - headers=dict(_response.headers), - body=typing.cast( - types_api_error_ApiError, - parse_obj_as( - type_=types_api_error_ApiError, # type: ignore - object_=_response.json(), - ), - ), - ) - _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 create( - self, - *, - project_id: str, - name: str, - description: typing.Optional[str] = OMIT, - request_options: typing.Optional[RequestOptions] = None, - ) -> HttpResponse[UserGroupResponse]: - """ - Parameters - ---------- - project_id : str - Project UUID - - name : str - - description : typing.Optional[str] - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - HttpResponse[UserGroupResponse] - Created - """ - _response = self._client_wrapper.httpx_client.request( - "user-groups", - method="POST", - params={ - "projectId": project_id, - }, - json={ - "description": description, - "name": name, - }, - headers={ - "content-type": "application/json", - }, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - _data = typing.cast( - UserGroupResponse, - parse_obj_as( - type_=UserGroupResponse, # type: ignore - object_=_response.json(), - ), - ) - return HttpResponse(response=_response, data=_data) - if _response.status_code == 400: - raise BadRequestError( - headers=dict(_response.headers), - body=typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ), - ) - if _response.status_code == 403: - raise ForbiddenError( - headers=dict(_response.headers), - body=typing.cast( - types_api_error_ApiError, - parse_obj_as( - type_=types_api_error_ApiError, # type: ignore - object_=_response.json(), - ), - ), - ) - if _response.status_code == 409: - raise ConflictError( - 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_for_user( - self, user_uuid: str, *, project_id: str, request_options: typing.Optional[RequestOptions] = None - ) -> HttpResponse[UserMembershipGroupsResponse]: - """ - Parameters - ---------- - user_uuid : str - User UUID - - project_id : str - Project UUID - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - HttpResponse[UserMembershipGroupsResponse] - OK - """ - _response = self._client_wrapper.httpx_client.request( - f"user-groups/users/{jsonable_encoder(user_uuid)}", - method="GET", - params={ - "projectId": project_id, - }, - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - _data = typing.cast( - UserMembershipGroupsResponse, - parse_obj_as( - type_=UserMembershipGroupsResponse, # 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(), - ), - ), - ) - _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, group_uuid: str, *, project_id: str, request_options: typing.Optional[RequestOptions] = None - ) -> HttpResponse[UserGroupResponse]: - """ - Parameters - ---------- - group_uuid : str - UserGroup UUID - - project_id : str - Project UUID - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - HttpResponse[UserGroupResponse] - OK - """ - _response = self._client_wrapper.httpx_client.request( - f"user-groups/{jsonable_encoder(group_uuid)}", - method="GET", - params={ - "projectId": project_id, - }, - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - _data = typing.cast( - UserGroupResponse, - parse_obj_as( - type_=UserGroupResponse, # 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(), - ), - ), - ) - _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 delete( - self, group_uuid: str, *, project_id: str, request_options: typing.Optional[RequestOptions] = None - ) -> HttpResponse[None]: - """ - Parameters - ---------- - group_uuid : str - UserGroup UUID - - project_id : str - Project UUID - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - HttpResponse[None] - """ - _response = self._client_wrapper.httpx_client.request( - f"user-groups/{jsonable_encoder(group_uuid)}", - method="DELETE", - params={ - "projectId": project_id, - }, - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return HttpResponse(response=_response, data=None) - 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 == 409: - raise ConflictError( - 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 update( - self, - group_uuid: str, - *, - project_id: str, - expected_version: int, - description: typing.Optional[str] = OMIT, - name: typing.Optional[str] = OMIT, - request_options: typing.Optional[RequestOptions] = None, - ) -> HttpResponse[UserGroupResponse]: - """ - Parameters - ---------- - group_uuid : str - UserGroup UUID - - project_id : str - Project UUID - - expected_version : int - - description : typing.Optional[str] - - name : typing.Optional[str] - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - HttpResponse[UserGroupResponse] - OK - """ - _response = self._client_wrapper.httpx_client.request( - f"user-groups/{jsonable_encoder(group_uuid)}", - method="PATCH", - params={ - "projectId": project_id, - }, - json={ - "description": description, - "expected_version": expected_version, - "name": name, - }, - headers={ - "content-type": "application/json", - }, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - _data = typing.cast( - UserGroupResponse, - parse_obj_as( - type_=UserGroupResponse, # type: ignore - object_=_response.json(), - ), - ) - return HttpResponse(response=_response, data=_data) - if _response.status_code == 400: - raise BadRequestError( - headers=dict(_response.headers), - body=typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ), - ) - if _response.status_code == 403: - raise ForbiddenError( - headers=dict(_response.headers), - body=typing.cast( - types_api_error_ApiError, - parse_obj_as( - type_=types_api_error_ApiError, # type: ignore - object_=_response.json(), - ), - ), - ) - if _response.status_code == 404: - raise NotFoundError( - headers=dict(_response.headers), - body=typing.cast( - types_api_error_ApiError, - parse_obj_as( - type_=types_api_error_ApiError, # type: ignore - object_=_response.json(), - ), - ), - ) - if _response.status_code == 409: - raise ConflictError( - 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_members( - self, - group_uuid: str, - *, - project_id: str, - page_number: int, - page_size: int, - search: typing.Optional[str] = None, - request_options: typing.Optional[RequestOptions] = None, - ) -> HttpResponse[UserGroupMembersResponse]: - """ - Parameters - ---------- - group_uuid : str - UserGroup UUID - - project_id : str - Project UUID - - page_number : int - Page number - - page_size : int - Page size - - search : typing.Optional[str] - User search - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - HttpResponse[UserGroupMembersResponse] - OK - """ - _response = self._client_wrapper.httpx_client.request( - f"user-groups/{jsonable_encoder(group_uuid)}/members", - method="GET", - params={ - "projectId": project_id, - "pageNumber": page_number, - "pageSize": page_size, - "search": search, - }, - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - _data = typing.cast( - UserGroupMembersResponse, - parse_obj_as( - type_=UserGroupMembersResponse, # 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(), - ), - ), - ) - _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 add_members( - self, - group_uuid: str, - *, - project_id: str, - user_uuids: typing.Sequence[str], - request_options: typing.Optional[RequestOptions] = None, - ) -> HttpResponse[UserGroupMembershipResponse]: - """ - Parameters - ---------- - group_uuid : str - UserGroup UUID - - project_id : str - Project UUID - - user_uuids : typing.Sequence[str] - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - HttpResponse[UserGroupMembershipResponse] - OK - """ - _response = self._client_wrapper.httpx_client.request( - f"user-groups/{jsonable_encoder(group_uuid)}/members", - method="POST", - params={ - "projectId": project_id, - }, - json={ - "user_uuids": user_uuids, - }, - headers={ - "content-type": "application/json", - }, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - _data = typing.cast( - UserGroupMembershipResponse, - parse_obj_as( - type_=UserGroupMembershipResponse, # type: ignore - object_=_response.json(), - ), - ) - return HttpResponse(response=_response, data=_data) - if _response.status_code == 400: - raise BadRequestError( - headers=dict(_response.headers), - body=typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ), - ) - if _response.status_code == 403: - raise ForbiddenError( - headers=dict(_response.headers), - body=typing.cast( - types_api_error_ApiError, - parse_obj_as( - type_=types_api_error_ApiError, # type: ignore - object_=_response.json(), - ), - ), - ) - if _response.status_code == 404: - raise NotFoundError( - headers=dict(_response.headers), - body=typing.cast( - types_api_error_ApiError, - parse_obj_as( - type_=types_api_error_ApiError, # type: ignore - object_=_response.json(), - ), - ), - ) - if _response.status_code == 409: - raise ConflictError( - 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 remove_members( - self, - group_uuid: str, - *, - project_id: str, - user_uuids: typing.Sequence[str], - request_options: typing.Optional[RequestOptions] = None, - ) -> HttpResponse[UserGroupMembershipResponse]: - """ - Parameters - ---------- - group_uuid : str - UserGroup UUID - - project_id : str - Project UUID - - user_uuids : typing.Sequence[str] - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - HttpResponse[UserGroupMembershipResponse] - OK - """ - _response = self._client_wrapper.httpx_client.request( - f"user-groups/{jsonable_encoder(group_uuid)}/members/bulk-remove", - method="POST", - params={ - "projectId": project_id, - }, - json={ - "user_uuids": user_uuids, - }, - headers={ - "content-type": "application/json", - }, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - _data = typing.cast( - UserGroupMembershipResponse, - parse_obj_as( - type_=UserGroupMembershipResponse, # type: ignore - object_=_response.json(), - ), - ) - return HttpResponse(response=_response, data=_data) - if _response.status_code == 400: - raise BadRequestError( - headers=dict(_response.headers), - body=typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ), - ) - if _response.status_code == 403: - raise ForbiddenError( - headers=dict(_response.headers), - body=typing.cast( - types_api_error_ApiError, - parse_obj_as( - type_=types_api_error_ApiError, # type: ignore - object_=_response.json(), - ), - ), - ) - if _response.status_code == 404: - raise NotFoundError( - headers=dict(_response.headers), - body=typing.cast( - types_api_error_ApiError, - parse_obj_as( - type_=types_api_error_ApiError, # type: ignore - object_=_response.json(), - ), - ), - ) - if _response.status_code == 409: - raise ConflictError( - 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_member_candidates( - self, - group_uuid: str, - *, - project_id: str, - page_number: int, - page_size: int, - search: typing.Optional[str] = None, - request_options: typing.Optional[RequestOptions] = None, - ) -> HttpResponse[UserGroupMembersResponse]: - """ - Parameters - ---------- - group_uuid : str - UserGroup UUID - - project_id : str - Project UUID - - page_number : int - Page number - - page_size : int - Page size - - search : typing.Optional[str] - User search - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - HttpResponse[UserGroupMembersResponse] - OK - """ - _response = self._client_wrapper.httpx_client.request( - f"user-groups/{jsonable_encoder(group_uuid)}/members/candidates", - method="GET", - params={ - "projectId": project_id, - "pageNumber": page_number, - "pageSize": page_size, - "search": search, - }, - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - _data = typing.cast( - UserGroupMembersResponse, - parse_obj_as( - type_=UserGroupMembersResponse, # 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 == 409: - raise ConflictError( - 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 remove_member( - self, - group_uuid: str, - user_uuid: str, - *, - project_id: str, - request_options: typing.Optional[RequestOptions] = None, - ) -> HttpResponse[UserGroupMembershipResponse]: - """ - Parameters - ---------- - group_uuid : str - UserGroup UUID - - user_uuid : str - User UUID - - project_id : str - Project UUID - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - HttpResponse[UserGroupMembershipResponse] - OK - """ - _response = self._client_wrapper.httpx_client.request( - f"user-groups/{jsonable_encoder(group_uuid)}/members/{jsonable_encoder(user_uuid)}", - method="DELETE", - params={ - "projectId": project_id, - }, - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - _data = typing.cast( - UserGroupMembershipResponse, - parse_obj_as( - type_=UserGroupMembershipResponse, # 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 == 409: - raise ConflictError( - 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 AsyncRawUserGroupClient: - def __init__(self, *, client_wrapper: AsyncClientWrapper): - self._client_wrapper = client_wrapper - - async def list_policy_sets( - self, group_uuid: str, *, project_id: str, request_options: typing.Optional[RequestOptions] = None - ) -> AsyncHttpResponse[AttachedPolicySetsResponse]: - """ - Parameters - ---------- - group_uuid : str - UserGroup UUID - - project_id : str - Project UUID - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - AsyncHttpResponse[AttachedPolicySetsResponse] - OK - """ - _response = await self._client_wrapper.httpx_client.request( - f"abac/user-groups/{jsonable_encoder(group_uuid)}/policy-sets", - method="GET", - params={ - "projectId": project_id, - }, - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - _data = typing.cast( - AttachedPolicySetsResponse, - parse_obj_as( - type_=AttachedPolicySetsResponse, # 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(), - ), - ), - ) - _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 attach_policy_set( - self, - group_uuid: str, - *, - project_id: str, - policy_set_uuid: str, - request_options: typing.Optional[RequestOptions] = None, - ) -> AsyncHttpResponse[AttachedPolicySetsResponse]: - """ - Parameters - ---------- - group_uuid : str - UserGroup UUID - - project_id : str - Project UUID - - policy_set_uuid : str - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - AsyncHttpResponse[AttachedPolicySetsResponse] - OK - """ - _response = await self._client_wrapper.httpx_client.request( - f"abac/user-groups/{jsonable_encoder(group_uuid)}/policy-sets", - method="POST", - params={ - "projectId": project_id, - }, - json={ - "policy_set_uuid": policy_set_uuid, - }, - headers={ - "content-type": "application/json", - }, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - _data = typing.cast( - AttachedPolicySetsResponse, - parse_obj_as( - type_=AttachedPolicySetsResponse, # type: ignore - object_=_response.json(), - ), - ) - return AsyncHttpResponse(response=_response, data=_data) - if _response.status_code == 400: - raise BadRequestError( - headers=dict(_response.headers), - body=typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ), - ) - if _response.status_code == 403: - raise ForbiddenError( - headers=dict(_response.headers), - body=typing.cast( - types_api_error_ApiError, - parse_obj_as( - type_=types_api_error_ApiError, # type: ignore - object_=_response.json(), - ), - ), - ) - if _response.status_code == 404: - raise NotFoundError( - headers=dict(_response.headers), - body=typing.cast( - types_api_error_ApiError, - parse_obj_as( - type_=types_api_error_ApiError, # type: ignore - object_=_response.json(), - ), - ), - ) - _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 detach_policy_set( - self, - group_uuid: str, - policy_set_uuid: str, - *, - project_id: str, - request_options: typing.Optional[RequestOptions] = None, - ) -> AsyncHttpResponse[AttachedPolicySetsResponse]: - """ - Parameters - ---------- - group_uuid : str - UserGroup UUID - - policy_set_uuid : str - Policy set UUID - - project_id : str - Project UUID - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - AsyncHttpResponse[AttachedPolicySetsResponse] - OK - """ - _response = await self._client_wrapper.httpx_client.request( - f"abac/user-groups/{jsonable_encoder(group_uuid)}/policy-sets/{jsonable_encoder(policy_set_uuid)}", - method="DELETE", - params={ - "projectId": project_id, - }, - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - _data = typing.cast( - AttachedPolicySetsResponse, - parse_obj_as( - type_=AttachedPolicySetsResponse, # 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(), - ), - ), - ) - _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( - self, - *, - project_id: str, - page_number: int, - page_size: int, - search: typing.Optional[str] = None, - request_options: typing.Optional[RequestOptions] = None, - ) -> AsyncHttpResponse[UserGroupListResponse]: - """ - Parameters - ---------- - project_id : str - Project UUID - - page_number : int - Page number - - page_size : int - Page size - - search : typing.Optional[str] - Name search - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - AsyncHttpResponse[UserGroupListResponse] - OK - """ - _response = await self._client_wrapper.httpx_client.request( - "user-groups", - method="GET", - params={ - "projectId": project_id, - "pageNumber": page_number, - "pageSize": page_size, - "search": search, - }, - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - _data = typing.cast( - UserGroupListResponse, - parse_obj_as( - type_=UserGroupListResponse, # type: ignore - object_=_response.json(), - ), - ) - return AsyncHttpResponse(response=_response, data=_data) - if _response.status_code == 400: - raise BadRequestError( - headers=dict(_response.headers), - body=typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ), - ) - if _response.status_code == 403: - raise ForbiddenError( - headers=dict(_response.headers), - body=typing.cast( - types_api_error_ApiError, - parse_obj_as( - type_=types_api_error_ApiError, # type: ignore - object_=_response.json(), - ), - ), - ) - _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 create( - self, - *, - project_id: str, - name: str, - description: typing.Optional[str] = OMIT, - request_options: typing.Optional[RequestOptions] = None, - ) -> AsyncHttpResponse[UserGroupResponse]: - """ - Parameters - ---------- - project_id : str - Project UUID - - name : str - - description : typing.Optional[str] - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - AsyncHttpResponse[UserGroupResponse] - Created - """ - _response = await self._client_wrapper.httpx_client.request( - "user-groups", - method="POST", - params={ - "projectId": project_id, - }, - json={ - "description": description, - "name": name, - }, - headers={ - "content-type": "application/json", - }, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - _data = typing.cast( - UserGroupResponse, - parse_obj_as( - type_=UserGroupResponse, # type: ignore - object_=_response.json(), - ), - ) - return AsyncHttpResponse(response=_response, data=_data) - if _response.status_code == 400: - raise BadRequestError( - headers=dict(_response.headers), - body=typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ), - ) - if _response.status_code == 403: - raise ForbiddenError( - headers=dict(_response.headers), - body=typing.cast( - types_api_error_ApiError, - parse_obj_as( - type_=types_api_error_ApiError, # type: ignore - object_=_response.json(), - ), - ), - ) - if _response.status_code == 409: - raise ConflictError( - 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_for_user( - self, user_uuid: str, *, project_id: str, request_options: typing.Optional[RequestOptions] = None - ) -> AsyncHttpResponse[UserMembershipGroupsResponse]: - """ - Parameters - ---------- - user_uuid : str - User UUID - - project_id : str - Project UUID - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - AsyncHttpResponse[UserMembershipGroupsResponse] - OK - """ - _response = await self._client_wrapper.httpx_client.request( - f"user-groups/users/{jsonable_encoder(user_uuid)}", - method="GET", - params={ - "projectId": project_id, - }, - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - _data = typing.cast( - UserMembershipGroupsResponse, - parse_obj_as( - type_=UserMembershipGroupsResponse, # 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(), - ), - ), - ) - _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, group_uuid: str, *, project_id: str, request_options: typing.Optional[RequestOptions] = None - ) -> AsyncHttpResponse[UserGroupResponse]: - """ - Parameters - ---------- - group_uuid : str - UserGroup UUID - - project_id : str - Project UUID - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - AsyncHttpResponse[UserGroupResponse] - OK - """ - _response = await self._client_wrapper.httpx_client.request( - f"user-groups/{jsonable_encoder(group_uuid)}", - method="GET", - params={ - "projectId": project_id, - }, - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - _data = typing.cast( - UserGroupResponse, - parse_obj_as( - type_=UserGroupResponse, # 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(), - ), - ), - ) - _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 delete( - self, group_uuid: str, *, project_id: str, request_options: typing.Optional[RequestOptions] = None - ) -> AsyncHttpResponse[None]: - """ - Parameters - ---------- - group_uuid : str - UserGroup UUID - - project_id : str - Project UUID - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - AsyncHttpResponse[None] - """ - _response = await self._client_wrapper.httpx_client.request( - f"user-groups/{jsonable_encoder(group_uuid)}", - method="DELETE", - params={ - "projectId": project_id, - }, - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return AsyncHttpResponse(response=_response, data=None) - 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 == 409: - raise ConflictError( - 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 update( - self, - group_uuid: str, - *, - project_id: str, - expected_version: int, - description: typing.Optional[str] = OMIT, - name: typing.Optional[str] = OMIT, - request_options: typing.Optional[RequestOptions] = None, - ) -> AsyncHttpResponse[UserGroupResponse]: - """ - Parameters - ---------- - group_uuid : str - UserGroup UUID - - project_id : str - Project UUID - - expected_version : int - - description : typing.Optional[str] - - name : typing.Optional[str] - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - AsyncHttpResponse[UserGroupResponse] - OK - """ - _response = await self._client_wrapper.httpx_client.request( - f"user-groups/{jsonable_encoder(group_uuid)}", - method="PATCH", - params={ - "projectId": project_id, - }, - json={ - "description": description, - "expected_version": expected_version, - "name": name, - }, - headers={ - "content-type": "application/json", - }, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - _data = typing.cast( - UserGroupResponse, - parse_obj_as( - type_=UserGroupResponse, # type: ignore - object_=_response.json(), - ), - ) - return AsyncHttpResponse(response=_response, data=_data) - if _response.status_code == 400: - raise BadRequestError( - headers=dict(_response.headers), - body=typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ), - ) - if _response.status_code == 403: - raise ForbiddenError( - headers=dict(_response.headers), - body=typing.cast( - types_api_error_ApiError, - parse_obj_as( - type_=types_api_error_ApiError, # type: ignore - object_=_response.json(), - ), - ), - ) - if _response.status_code == 404: - raise NotFoundError( - headers=dict(_response.headers), - body=typing.cast( - types_api_error_ApiError, - parse_obj_as( - type_=types_api_error_ApiError, # type: ignore - object_=_response.json(), - ), - ), - ) - if _response.status_code == 409: - raise ConflictError( - 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_members( - self, - group_uuid: str, - *, - project_id: str, - page_number: int, - page_size: int, - search: typing.Optional[str] = None, - request_options: typing.Optional[RequestOptions] = None, - ) -> AsyncHttpResponse[UserGroupMembersResponse]: - """ - Parameters - ---------- - group_uuid : str - UserGroup UUID - - project_id : str - Project UUID - - page_number : int - Page number - - page_size : int - Page size - - search : typing.Optional[str] - User search - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - AsyncHttpResponse[UserGroupMembersResponse] - OK - """ - _response = await self._client_wrapper.httpx_client.request( - f"user-groups/{jsonable_encoder(group_uuid)}/members", - method="GET", - params={ - "projectId": project_id, - "pageNumber": page_number, - "pageSize": page_size, - "search": search, - }, - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - _data = typing.cast( - UserGroupMembersResponse, - parse_obj_as( - type_=UserGroupMembersResponse, # 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(), - ), - ), - ) - _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 add_members( - self, - group_uuid: str, - *, - project_id: str, - user_uuids: typing.Sequence[str], - request_options: typing.Optional[RequestOptions] = None, - ) -> AsyncHttpResponse[UserGroupMembershipResponse]: - """ - Parameters - ---------- - group_uuid : str - UserGroup UUID - - project_id : str - Project UUID - - user_uuids : typing.Sequence[str] - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - AsyncHttpResponse[UserGroupMembershipResponse] - OK - """ - _response = await self._client_wrapper.httpx_client.request( - f"user-groups/{jsonable_encoder(group_uuid)}/members", - method="POST", - params={ - "projectId": project_id, - }, - json={ - "user_uuids": user_uuids, - }, - headers={ - "content-type": "application/json", - }, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - _data = typing.cast( - UserGroupMembershipResponse, - parse_obj_as( - type_=UserGroupMembershipResponse, # type: ignore - object_=_response.json(), - ), - ) - return AsyncHttpResponse(response=_response, data=_data) - if _response.status_code == 400: - raise BadRequestError( - headers=dict(_response.headers), - body=typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ), - ) - if _response.status_code == 403: - raise ForbiddenError( - headers=dict(_response.headers), - body=typing.cast( - types_api_error_ApiError, - parse_obj_as( - type_=types_api_error_ApiError, # type: ignore - object_=_response.json(), - ), - ), - ) - if _response.status_code == 404: - raise NotFoundError( - headers=dict(_response.headers), - body=typing.cast( - types_api_error_ApiError, - parse_obj_as( - type_=types_api_error_ApiError, # type: ignore - object_=_response.json(), - ), - ), - ) - if _response.status_code == 409: - raise ConflictError( - 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 remove_members( - self, - group_uuid: str, - *, - project_id: str, - user_uuids: typing.Sequence[str], - request_options: typing.Optional[RequestOptions] = None, - ) -> AsyncHttpResponse[UserGroupMembershipResponse]: - """ - Parameters - ---------- - group_uuid : str - UserGroup UUID - - project_id : str - Project UUID - - user_uuids : typing.Sequence[str] - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - AsyncHttpResponse[UserGroupMembershipResponse] - OK - """ - _response = await self._client_wrapper.httpx_client.request( - f"user-groups/{jsonable_encoder(group_uuid)}/members/bulk-remove", - method="POST", - params={ - "projectId": project_id, - }, - json={ - "user_uuids": user_uuids, - }, - headers={ - "content-type": "application/json", - }, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - _data = typing.cast( - UserGroupMembershipResponse, - parse_obj_as( - type_=UserGroupMembershipResponse, # type: ignore - object_=_response.json(), - ), - ) - return AsyncHttpResponse(response=_response, data=_data) - if _response.status_code == 400: - raise BadRequestError( - headers=dict(_response.headers), - body=typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ), - ) - if _response.status_code == 403: - raise ForbiddenError( - headers=dict(_response.headers), - body=typing.cast( - types_api_error_ApiError, - parse_obj_as( - type_=types_api_error_ApiError, # type: ignore - object_=_response.json(), - ), - ), - ) - if _response.status_code == 404: - raise NotFoundError( - headers=dict(_response.headers), - body=typing.cast( - types_api_error_ApiError, - parse_obj_as( - type_=types_api_error_ApiError, # type: ignore - object_=_response.json(), - ), - ), - ) - if _response.status_code == 409: - raise ConflictError( - 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_member_candidates( - self, - group_uuid: str, - *, - project_id: str, - page_number: int, - page_size: int, - search: typing.Optional[str] = None, - request_options: typing.Optional[RequestOptions] = None, - ) -> AsyncHttpResponse[UserGroupMembersResponse]: - """ - Parameters - ---------- - group_uuid : str - UserGroup UUID - - project_id : str - Project UUID - - page_number : int - Page number - - page_size : int - Page size - - search : typing.Optional[str] - User search - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - AsyncHttpResponse[UserGroupMembersResponse] - OK - """ - _response = await self._client_wrapper.httpx_client.request( - f"user-groups/{jsonable_encoder(group_uuid)}/members/candidates", - method="GET", - params={ - "projectId": project_id, - "pageNumber": page_number, - "pageSize": page_size, - "search": search, - }, - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - _data = typing.cast( - UserGroupMembersResponse, - parse_obj_as( - type_=UserGroupMembersResponse, # 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 == 409: - raise ConflictError( - 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 remove_member( - self, - group_uuid: str, - user_uuid: str, - *, - project_id: str, - request_options: typing.Optional[RequestOptions] = None, - ) -> AsyncHttpResponse[UserGroupMembershipResponse]: - """ - Parameters - ---------- - group_uuid : str - UserGroup UUID - - user_uuid : str - User UUID - - project_id : str - Project UUID - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - AsyncHttpResponse[UserGroupMembershipResponse] - OK - """ - _response = await self._client_wrapper.httpx_client.request( - f"user-groups/{jsonable_encoder(group_uuid)}/members/{jsonable_encoder(user_uuid)}", - method="DELETE", - params={ - "projectId": project_id, - }, - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - _data = typing.cast( - UserGroupMembershipResponse, - parse_obj_as( - type_=UserGroupMembershipResponse, # 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 == 409: - raise ConflictError( - 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/tests/utils/test_http_client.py b/tests/utils/test_http_client.py index d8c4c778..87b8183d 100644 --- a/tests/utils/test_http_client.py +++ b/tests/utils/test_http_client.py @@ -1,13 +1,57 @@ # This file was auto-generated by Fern from our API Definition. -from zep_cloud.core.http_client import get_request_body +from typing import Any, Dict + +import pytest + +from zep_cloud.core.http_client import ( + AsyncHttpClient, + HttpClient, + _build_url, + get_request_body, + remove_none_from_dict, +) from zep_cloud.core.request_options import RequestOptions +# Stub clients for testing HttpClient and AsyncHttpClient +class _DummySyncClient: + """A minimal stub for httpx.Client that records request arguments.""" + + def __init__(self) -> None: + self.last_request_kwargs: Dict[str, Any] = {} + + def request(self, **kwargs: Any) -> "_DummyResponse": + self.last_request_kwargs = kwargs + return _DummyResponse() + + +class _DummyAsyncClient: + """A minimal stub for httpx.AsyncClient that records request arguments.""" + + def __init__(self) -> None: + self.last_request_kwargs: Dict[str, Any] = {} + + async def request(self, **kwargs: Any) -> "_DummyResponse": + self.last_request_kwargs = kwargs + return _DummyResponse() + + +class _DummyResponse: + """A minimal stub for httpx.Response.""" + + status_code = 200 + headers: Dict[str, str] = {} + + def get_request_options() -> RequestOptions: return {"additional_body_parameters": {"see you": "later"}} +def get_request_options_with_none() -> RequestOptions: + return {"additional_body_parameters": {"see you": "later", "optional": None}} + + def test_get_json_request_body() -> None: json_body, data_body = get_request_body(json={"hello": "world"}, data=None, request_options=None, omit=None) assert json_body == {"hello": "world"} @@ -48,14 +92,209 @@ def test_get_none_request_body() -> None: def test_get_empty_json_request_body() -> None: + """Test that implicit empty bodies (json=None) are collapsed to None.""" unrelated_request_options: RequestOptions = {"max_retries": 3} json_body, data_body = get_request_body(json=None, data=None, request_options=unrelated_request_options, omit=None) assert json_body is None assert data_body is None - json_body_extras, data_body_extras = get_request_body( - json={}, data=None, request_options=unrelated_request_options, omit=None + +def test_explicit_empty_json_body_is_preserved() -> None: + """Test that explicit empty bodies (json={}) are preserved and sent as {}. + + This is important for endpoints where the request body is required but all + fields are optional. The server expects valid JSON ({}) not an empty body. + """ + unrelated_request_options: RequestOptions = {"max_retries": 3} + + # Explicit json={} should be preserved + json_body, data_body = get_request_body(json={}, data=None, request_options=unrelated_request_options, omit=None) + assert json_body == {} + assert data_body is None + + # Explicit data={} should also be preserved + json_body2, data_body2 = get_request_body(json=None, data={}, request_options=unrelated_request_options, omit=None) + assert json_body2 is None + assert data_body2 == {} + + +def test_json_body_preserves_none_values() -> None: + """Test that JSON bodies preserve None values (they become JSON null).""" + json_body, data_body = get_request_body( + json={"hello": "world", "optional": None}, data=None, request_options=None, omit=None ) + # JSON bodies should preserve None values + assert json_body == {"hello": "world", "optional": None} + assert data_body is None - assert json_body_extras is None - assert data_body_extras is None + +def test_data_body_preserves_none_values_without_multipart() -> None: + """Test that data bodies preserve None values when not using multipart. + + The filtering of None values happens in HttpClient.request/stream methods, + not in get_request_body. This test verifies get_request_body doesn't filter None. + """ + json_body, data_body = get_request_body( + json=None, data={"hello": "world", "optional": None}, request_options=None, omit=None + ) + # get_request_body should preserve None values in data body + # The filtering happens later in HttpClient.request when multipart is detected + assert data_body == {"hello": "world", "optional": None} + assert json_body is None + + +def test_remove_none_from_dict_filters_none_values() -> None: + """Test that remove_none_from_dict correctly filters out None values.""" + original = {"hello": "world", "optional": None, "another": "value", "also_none": None} + filtered = remove_none_from_dict(original) + assert filtered == {"hello": "world", "another": "value"} + # Original should not be modified + assert original == {"hello": "world", "optional": None, "another": "value", "also_none": None} + + +def test_remove_none_from_dict_empty_dict() -> None: + """Test that remove_none_from_dict handles empty dict.""" + assert remove_none_from_dict({}) == {} + + +def test_remove_none_from_dict_all_none() -> None: + """Test that remove_none_from_dict handles dict with all None values.""" + assert remove_none_from_dict({"a": None, "b": None}) == {} + + +def test_http_client_does_not_pass_empty_params_list() -> None: + """Test that HttpClient passes params=None when params are empty. + + This prevents httpx from stripping existing query parameters from the URL, + which happens when params=[] or params={} is passed. + """ + dummy_client = _DummySyncClient() + http_client = HttpClient( + httpx_client=dummy_client, # type: ignore[arg-type] + base_timeout=lambda: None, + base_headers=lambda: {}, + base_url=lambda: "https://example.com", + ) + + # Use a path with query params (e.g., pagination cursor URL) + http_client.request( + path="resource?after=123", + method="GET", + params=None, + request_options=None, + ) + + # We care that httpx receives params=None, not [] or {} + assert "params" in dummy_client.last_request_kwargs + assert dummy_client.last_request_kwargs["params"] is None + + # Verify the query string in the URL is preserved + url = str(dummy_client.last_request_kwargs["url"]) + assert "after=123" in url, f"Expected query param 'after=123' in URL, got: {url}" + + +def test_http_client_passes_encoded_params_when_present() -> None: + """Test that HttpClient passes encoded params when params are provided.""" + dummy_client = _DummySyncClient() + http_client = HttpClient( + httpx_client=dummy_client, # type: ignore[arg-type] + base_timeout=lambda: None, + base_headers=lambda: {}, + base_url=lambda: "https://example.com/resource", + ) + + http_client.request( + path="", + method="GET", + params={"after": "456"}, + request_options=None, + ) + + params = dummy_client.last_request_kwargs["params"] + # For a simple dict, encode_query should give a single (key, value) tuple + assert params == [("after", "456")] + + +@pytest.mark.asyncio +async def test_async_http_client_does_not_pass_empty_params_list() -> None: + """Test that AsyncHttpClient passes params=None when params are empty. + + This prevents httpx from stripping existing query parameters from the URL, + which happens when params=[] or params={} is passed. + """ + dummy_client = _DummyAsyncClient() + http_client = AsyncHttpClient( + httpx_client=dummy_client, # type: ignore[arg-type] + base_timeout=lambda: None, + base_headers=lambda: {}, + base_url=lambda: "https://example.com", + async_base_headers=None, + ) + + # Use a path with query params (e.g., pagination cursor URL) + await http_client.request( + path="resource?after=123", + method="GET", + params=None, + request_options=None, + ) + + # We care that httpx receives params=None, not [] or {} + assert "params" in dummy_client.last_request_kwargs + assert dummy_client.last_request_kwargs["params"] is None + + # Verify the query string in the URL is preserved + url = str(dummy_client.last_request_kwargs["url"]) + assert "after=123" in url, f"Expected query param 'after=123' in URL, got: {url}" + + +@pytest.mark.asyncio +async def test_async_http_client_passes_encoded_params_when_present() -> None: + """Test that AsyncHttpClient passes encoded params when params are provided.""" + dummy_client = _DummyAsyncClient() + http_client = AsyncHttpClient( + httpx_client=dummy_client, # type: ignore[arg-type] + base_timeout=lambda: None, + base_headers=lambda: {}, + base_url=lambda: "https://example.com/resource", + async_base_headers=None, + ) + + await http_client.request( + path="", + method="GET", + params={"after": "456"}, + request_options=None, + ) + + params = dummy_client.last_request_kwargs["params"] + # For a simple dict, encode_query should give a single (key, value) tuple + assert params == [("after", "456")] + + +def test_basic_url_joining() -> None: + """Test basic URL joining with a simple base URL and path.""" + result = _build_url("https://api.example.com", "/users") + assert result == "https://api.example.com/users" + + +def test_basic_url_joining_trailing_slash() -> None: + """Test basic URL joining with a simple base URL and path.""" + result = _build_url("https://api.example.com/", "/users") + assert result == "https://api.example.com/users" + + +def test_preserves_base_url_path_prefix() -> None: + """Test that path prefixes in base URL are preserved. + + This is the critical bug fix - urllib.parse.urljoin() would strip + the path prefix when the path starts with '/'. + """ + result = _build_url("https://cloud.example.com/org/tenant/api", "/users") + assert result == "https://cloud.example.com/org/tenant/api/users" + + +def test_preserves_base_url_path_prefix_trailing_slash() -> None: + """Test that path prefixes in base URL are preserved.""" + result = _build_url("https://cloud.example.com/org/tenant/api/", "/users") + assert result == "https://cloud.example.com/org/tenant/api/users" diff --git a/tests/utils/test_query_encoding.py b/tests/utils/test_query_encoding.py index a8b82d03..14af2ca0 100644 --- a/tests/utils/test_query_encoding.py +++ b/tests/utils/test_query_encoding.py @@ -1,6 +1,5 @@ # This file was auto-generated by Fern from our API Definition. - from zep_cloud.core.query_encoder import encode_query