From 2403f1da4d83266ddf49ada0103c8f5d432bf966 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Tue, 29 Apr 2025 19:16:34 +0000
Subject: [PATCH 01/24] feat(api): api update
---
.stats.yml | 4 ++--
src/supermemory/types/memory_list_response.py | 5 -----
2 files changed, 2 insertions(+), 7 deletions(-)
diff --git a/.stats.yml b/.stats.yml
index b07d08ce..8f081055 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
configured_endpoints: 8
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/supermemory--inc%2Fsupermemory-f7a84a68f7d3173627cb589cec436ed7e89c98b2c3e66bbf42549da7346f3560.yml
-openapi_spec_hash: 40877051c2167db483e240b4226d840f
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/supermemory--inc%2Fsupermemory-17320f0488a9b933245c77e962932c0323d8e940123f2571f93e476c5b5c2d18.yml
+openapi_spec_hash: 8c13c404e5eb19f455dc7155c7f93e45
config_hash: eb32087403f958eead829e810f5a71b8
diff --git a/src/supermemory/types/memory_list_response.py b/src/supermemory/types/memory_list_response.py
index b5490f7f..7e5a7ed2 100644
--- a/src/supermemory/types/memory_list_response.py
+++ b/src/supermemory/types/memory_list_response.py
@@ -36,11 +36,6 @@ class Memory(BaseModel):
url: Optional[str] = None
"""Source URL of the memory"""
- workflow_status: Optional[Literal["PENDING", "IN_PROGRESS", "COMPLETED", "FAILED"]] = FieldInfo(
- alias="workflowStatus", default=None
- )
- """Current workflow status"""
-
class Pagination(BaseModel):
current_page: float = FieldInfo(alias="currentPage")
From fda6f9f111dac7db4bba42779e967356b8615e3c Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Wed, 30 Apr 2025 00:16:35 +0000
Subject: [PATCH 02/24] feat(api): api update
---
.stats.yml | 4 ++--
README.md | 27 +++++++++++++++------------
src/supermemory/_client.py | 12 ------------
tests/test_client.py | 22 +---------------------
4 files changed, 18 insertions(+), 47 deletions(-)
diff --git a/.stats.yml b/.stats.yml
index 8f081055..befa4f9e 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
configured_endpoints: 8
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/supermemory--inc%2Fsupermemory-17320f0488a9b933245c77e962932c0323d8e940123f2571f93e476c5b5c2d18.yml
-openapi_spec_hash: 8c13c404e5eb19f455dc7155c7f93e45
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/supermemory--inc%2Fsupermemory-aebc3d012c87df9d5cb4d651a374fceefb5154e74c70f51d927c76b923267a85.yml
+openapi_spec_hash: 98493a823305edac2c711cd052971f3d
config_hash: eb32087403f958eead829e810f5a71b8
diff --git a/README.md b/README.md
index 3dfd7e8c..bc02d4c0 100644
--- a/README.md
+++ b/README.md
@@ -24,11 +24,10 @@ pip install --pre supermemory
The full API of this library can be found in [api.md](api.md).
```python
-import os
from supermemory import Supermemory
client = Supermemory(
- api_key=os.environ.get("SUPERMEMORY_API_KEY"), # This is the default and can be omitted
+ api_key="My API Key",
)
response = client.search.execute(
@@ -37,22 +36,16 @@ response = client.search.execute(
print(response.results)
```
-While you can provide an `api_key` keyword argument,
-we recommend using [python-dotenv](https://pypi.org/project/python-dotenv/)
-to add `SUPERMEMORY_API_KEY="My API Key"` to your `.env` file
-so that your API Key is not stored in source control.
-
## Async usage
Simply import `AsyncSupermemory` instead of `Supermemory` and use `await` with each API call:
```python
-import os
import asyncio
from supermemory import AsyncSupermemory
client = AsyncSupermemory(
- api_key=os.environ.get("SUPERMEMORY_API_KEY"), # This is the default and can be omitted
+ api_key="My API Key",
)
@@ -90,7 +83,9 @@ All errors inherit from `supermemory.APIError`.
import supermemory
from supermemory import Supermemory
-client = Supermemory()
+client = Supermemory(
+ api_key="My API Key",
+)
try:
client.memory.create(
@@ -133,6 +128,7 @@ from supermemory import Supermemory
# Configure the default for all requests:
client = Supermemory(
+ api_key="My API Key",
# default is 2
max_retries=0,
)
@@ -153,12 +149,14 @@ from supermemory import Supermemory
# Configure the default for all requests:
client = Supermemory(
+ api_key="My API Key",
# 20 seconds (default is 1 minute)
timeout=20.0,
)
# More granular control:
client = Supermemory(
+ api_key="My API Key",
timeout=httpx.Timeout(60.0, read=5.0, write=10.0, connect=2.0),
)
@@ -205,7 +203,9 @@ The "raw" Response object can be accessed by prefixing `.with_raw_response.` to
```py
from supermemory import Supermemory
-client = Supermemory()
+client = Supermemory(
+ api_key="My API Key",
+)
response = client.memory.with_raw_response.create(
content="This is a detailed article about machine learning concepts...",
)
@@ -284,6 +284,7 @@ import httpx
from supermemory import Supermemory, DefaultHttpxClient
client = Supermemory(
+ api_key="My API Key",
# Or use the `SUPERMEMORY_BASE_URL` env var
base_url="http://my.test.server.example.com:8083",
http_client=DefaultHttpxClient(
@@ -306,7 +307,9 @@ By default the library closes underlying HTTP connections whenever the client is
```py
from supermemory import Supermemory
-with Supermemory() as client:
+with Supermemory(
+ api_key="My API Key",
+) as client:
# make requests here
...
diff --git a/src/supermemory/_client.py b/src/supermemory/_client.py
index 10d8d620..266329fc 100644
--- a/src/supermemory/_client.py
+++ b/src/supermemory/_client.py
@@ -116,12 +116,6 @@ def __init__(
def qs(self) -> Querystring:
return Querystring(array_format="comma")
- @property
- @override
- def auth_headers(self) -> dict[str, str]:
- api_key = self.api_key
- return {"X-API-Key": api_key}
-
@property
@override
def default_headers(self) -> dict[str, str | Omit]:
@@ -290,12 +284,6 @@ def __init__(
def qs(self) -> Querystring:
return Querystring(array_format="comma")
- @property
- @override
- def auth_headers(self) -> dict[str, str]:
- api_key = self.api_key
- return {"X-API-Key": api_key}
-
@property
@override
def default_headers(self) -> dict[str, str | Omit]:
diff --git a/tests/test_client.py b/tests/test_client.py
index b625c8c7..30dc5897 100644
--- a/tests/test_client.py
+++ b/tests/test_client.py
@@ -26,7 +26,7 @@
from supermemory._utils import maybe_transform
from supermemory._models import BaseModel, FinalRequestOptions
from supermemory._constants import RAW_RESPONSE_HEADER
-from supermemory._exceptions import APIStatusError, APITimeoutError, SupermemoryError, APIResponseValidationError
+from supermemory._exceptions import APIStatusError, APITimeoutError, APIResponseValidationError
from supermemory._base_client import (
DEFAULT_TIMEOUT,
HTTPX_DEFAULT_TIMEOUT,
@@ -336,16 +336,6 @@ def test_default_headers_option(self) -> None:
assert request.headers.get("x-foo") == "stainless"
assert request.headers.get("x-stainless-lang") == "my-overriding-header"
- def test_validate_headers(self) -> None:
- client = Supermemory(base_url=base_url, api_key=api_key, _strict_response_validation=True)
- request = client._build_request(FinalRequestOptions(method="get", url="/foo"))
- assert request.headers.get("X-API-Key") == api_key
-
- with pytest.raises(SupermemoryError):
- with update_env(**{"SUPERMEMORY_API_KEY": Omit()}):
- client2 = Supermemory(base_url=base_url, api_key=None, _strict_response_validation=True)
- _ = client2
-
def test_default_query_option(self) -> None:
client = Supermemory(
base_url=base_url, api_key=api_key, _strict_response_validation=True, default_query={"query_param": "bar"}
@@ -1128,16 +1118,6 @@ def test_default_headers_option(self) -> None:
assert request.headers.get("x-foo") == "stainless"
assert request.headers.get("x-stainless-lang") == "my-overriding-header"
- def test_validate_headers(self) -> None:
- client = AsyncSupermemory(base_url=base_url, api_key=api_key, _strict_response_validation=True)
- request = client._build_request(FinalRequestOptions(method="get", url="/foo"))
- assert request.headers.get("X-API-Key") == api_key
-
- with pytest.raises(SupermemoryError):
- with update_env(**{"SUPERMEMORY_API_KEY": Omit()}):
- client2 = AsyncSupermemory(base_url=base_url, api_key=None, _strict_response_validation=True)
- _ = client2
-
def test_default_query_option(self) -> None:
client = AsyncSupermemory(
base_url=base_url, api_key=api_key, _strict_response_validation=True, default_query={"query_param": "bar"}
From 844d56ecd40cffb441c47050e5e820051d65af7e Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Wed, 30 Apr 2025 02:16:36 +0000
Subject: [PATCH 03/24] feat(api): api update
---
.stats.yml | 4 ++--
src/supermemory/resources/search.py | 10 ++++++++++
src/supermemory/types/memory_list_response.py | 3 +++
src/supermemory/types/search_execute_params.py | 6 ++++++
tests/api_resources/test_search.py | 2 ++
5 files changed, 23 insertions(+), 2 deletions(-)
diff --git a/.stats.yml b/.stats.yml
index befa4f9e..c3fa7868 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
configured_endpoints: 8
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/supermemory--inc%2Fsupermemory-aebc3d012c87df9d5cb4d651a374fceefb5154e74c70f51d927c76b923267a85.yml
-openapi_spec_hash: 98493a823305edac2c711cd052971f3d
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/supermemory--inc%2Fsupermemory-b581efe40ff877fc21a621d2e1b9419bf8126142f14f818416f69f6ffa376ddb.yml
+openapi_spec_hash: 6e730fceb0f977b607e8d08d52f5e252
config_hash: eb32087403f958eead829e810f5a71b8
diff --git a/src/supermemory/resources/search.py b/src/supermemory/resources/search.py
index 6c55ba34..a31c8cad 100644
--- a/src/supermemory/resources/search.py
+++ b/src/supermemory/resources/search.py
@@ -56,6 +56,7 @@ def execute(
include_summary: bool | NotGiven = NOT_GIVEN,
limit: int | NotGiven = NOT_GIVEN,
only_matching_chunks: bool | NotGiven = NOT_GIVEN,
+ rewrite_query: bool | NotGiven = NOT_GIVEN,
user_id: str | NotGiven = NOT_GIVEN,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
# The extra values given here take precedence over values defined on the client or passed to this method.
@@ -87,6 +88,9 @@ def execute(
only_matching_chunks: If true, only return matching chunks without context
+ rewrite_query: If true, rewrites the query to make it easier to find documents. This increases
+ the latency by about 400ms
+
user_id: End user ID this search is associated with
extra_headers: Send extra headers
@@ -110,6 +114,7 @@ def execute(
"include_summary": include_summary,
"limit": limit,
"only_matching_chunks": only_matching_chunks,
+ "rewrite_query": rewrite_query,
"user_id": user_id,
},
search_execute_params.SearchExecuteParams,
@@ -153,6 +158,7 @@ async def execute(
include_summary: bool | NotGiven = NOT_GIVEN,
limit: int | NotGiven = NOT_GIVEN,
only_matching_chunks: bool | NotGiven = NOT_GIVEN,
+ rewrite_query: bool | NotGiven = NOT_GIVEN,
user_id: str | NotGiven = NOT_GIVEN,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
# The extra values given here take precedence over values defined on the client or passed to this method.
@@ -184,6 +190,9 @@ async def execute(
only_matching_chunks: If true, only return matching chunks without context
+ rewrite_query: If true, rewrites the query to make it easier to find documents. This increases
+ the latency by about 400ms
+
user_id: End user ID this search is associated with
extra_headers: Send extra headers
@@ -207,6 +216,7 @@ async def execute(
"include_summary": include_summary,
"limit": limit,
"only_matching_chunks": only_matching_chunks,
+ "rewrite_query": rewrite_query,
"user_id": user_id,
},
search_execute_params.SearchExecuteParams,
diff --git a/src/supermemory/types/memory_list_response.py b/src/supermemory/types/memory_list_response.py
index 7e5a7ed2..936f7675 100644
--- a/src/supermemory/types/memory_list_response.py
+++ b/src/supermemory/types/memory_list_response.py
@@ -15,6 +15,9 @@ class Memory(BaseModel):
id: str
"""Unique identifier of the memory"""
+ content: Optional[str] = None
+ """Content of the memory"""
+
created_at: datetime = FieldInfo(alias="createdAt")
"""Creation timestamp"""
diff --git a/src/supermemory/types/search_execute_params.py b/src/supermemory/types/search_execute_params.py
index 7ad50125..a6ec7301 100644
--- a/src/supermemory/types/search_execute_params.py
+++ b/src/supermemory/types/search_execute_params.py
@@ -43,6 +43,12 @@ class SearchExecuteParams(TypedDict, total=False):
only_matching_chunks: Annotated[bool, PropertyInfo(alias="onlyMatchingChunks")]
"""If true, only return matching chunks without context"""
+ rewrite_query: Annotated[bool, PropertyInfo(alias="rewriteQuery")]
+ """If true, rewrites the query to make it easier to find documents.
+
+ This increases the latency by about 400ms
+ """
+
user_id: Annotated[str, PropertyInfo(alias="userId")]
"""End user ID this search is associated with"""
diff --git a/tests/api_resources/test_search.py b/tests/api_resources/test_search.py
index 5bf10690..f3ed3549 100644
--- a/tests/api_resources/test_search.py
+++ b/tests/api_resources/test_search.py
@@ -54,6 +54,7 @@ def test_method_execute_with_all_params(self, client: Supermemory) -> None:
include_summary=False,
limit=10,
only_matching_chunks=False,
+ rewrite_query=False,
user_id="user_123",
)
assert_matches_type(SearchExecuteResponse, search, path=["response"])
@@ -125,6 +126,7 @@ async def test_method_execute_with_all_params(self, async_client: AsyncSupermemo
include_summary=False,
limit=10,
only_matching_chunks=False,
+ rewrite_query=False,
user_id="user_123",
)
assert_matches_type(SearchExecuteResponse, search, path=["response"])
From 7c0db70ec61ccd64197c333592457b925782f1ce Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Wed, 30 Apr 2025 03:16:37 +0000
Subject: [PATCH 04/24] feat(api): api update
---
.stats.yml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/.stats.yml b/.stats.yml
index c3fa7868..810a2174 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
configured_endpoints: 8
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/supermemory--inc%2Fsupermemory-b581efe40ff877fc21a621d2e1b9419bf8126142f14f818416f69f6ffa376ddb.yml
-openapi_spec_hash: 6e730fceb0f977b607e8d08d52f5e252
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/supermemory--inc%2Fsupermemory-3a9edb70d1db5e4d84c9b36503c833028553baa1687ff9666ce508d044d9cd90.yml
+openapi_spec_hash: 2e9e35933e87a849d9474045c8425731
config_hash: eb32087403f958eead829e810f5a71b8
From ed787b1abd49ebbc4e219f90bf71511306aafb2b Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Wed, 30 Apr 2025 04:16:31 +0000
Subject: [PATCH 05/24] feat(api): api update
---
.stats.yml | 4 ++--
README.md | 10 +++++-----
src/supermemory/resources/memory.py | 6 ++++--
tests/api_resources/test_memory.py | 16 ++++++++--------
tests/test_client.py | 24 ++++++++++--------------
5 files changed, 29 insertions(+), 31 deletions(-)
diff --git a/.stats.yml b/.stats.yml
index 810a2174..d272718d 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
configured_endpoints: 8
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/supermemory--inc%2Fsupermemory-3a9edb70d1db5e4d84c9b36503c833028553baa1687ff9666ce508d044d9cd90.yml
-openapi_spec_hash: 2e9e35933e87a849d9474045c8425731
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/supermemory--inc%2Fsupermemory-9d4f071b79b2524fee219bcfb0eafb1070969bb809e2f3dbee89392bfb3eac53.yml
+openapi_spec_hash: 089ce871ebc7bda9d2974706373a989e
config_hash: eb32087403f958eead829e810f5a71b8
diff --git a/README.md b/README.md
index bc02d4c0..80699ce7 100644
--- a/README.md
+++ b/README.md
@@ -89,7 +89,7 @@ client = Supermemory(
try:
client.memory.create(
- content="This is a detailed article about machine learning concepts...",
+ content="This is a detailed article about machine learning concepts..",
)
except supermemory.APIConnectionError as e:
print("The server could not be reached")
@@ -135,7 +135,7 @@ client = Supermemory(
# Or, configure per-request:
client.with_options(max_retries=5).memory.create(
- content="This is a detailed article about machine learning concepts...",
+ content="This is a detailed article about machine learning concepts..",
)
```
@@ -162,7 +162,7 @@ client = Supermemory(
# Override per-request:
client.with_options(timeout=5.0).memory.create(
- content="This is a detailed article about machine learning concepts...",
+ content="This is a detailed article about machine learning concepts..",
)
```
@@ -207,7 +207,7 @@ client = Supermemory(
api_key="My API Key",
)
response = client.memory.with_raw_response.create(
- content="This is a detailed article about machine learning concepts...",
+ content="This is a detailed article about machine learning concepts..",
)
print(response.headers.get('X-My-Header'))
@@ -227,7 +227,7 @@ To stream the response body, use `.with_streaming_response` instead, which requi
```python
with client.memory.with_streaming_response.create(
- content="This is a detailed article about machine learning concepts...",
+ content="This is a detailed article about machine learning concepts..",
) as response:
print(response.headers.get("X-My-Header"))
diff --git a/src/supermemory/resources/memory.py b/src/supermemory/resources/memory.py
index e0368257..349fdd2b 100644
--- a/src/supermemory/resources/memory.py
+++ b/src/supermemory/resources/memory.py
@@ -62,7 +62,8 @@ def create(
timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
) -> MemoryCreateResponse:
"""
- Add a new memory with content and metadata
+ Add or update a memory with any content type (text, url, file, etc.) with
+ metadata
Args:
content: Content of the memory
@@ -256,7 +257,8 @@ async def create(
timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
) -> MemoryCreateResponse:
"""
- Add a new memory with content and metadata
+ Add or update a memory with any content type (text, url, file, etc.) with
+ metadata
Args:
content: Content of the memory
diff --git a/tests/api_resources/test_memory.py b/tests/api_resources/test_memory.py
index 871f95ce..c41dde7b 100644
--- a/tests/api_resources/test_memory.py
+++ b/tests/api_resources/test_memory.py
@@ -26,7 +26,7 @@ class TestMemory:
@parametrize
def test_method_create(self, client: Supermemory) -> None:
memory = client.memory.create(
- content="This is a detailed article about machine learning concepts...",
+ content="This is a detailed article about machine learning concepts..",
)
assert_matches_type(MemoryCreateResponse, memory, path=["response"])
@@ -34,7 +34,7 @@ def test_method_create(self, client: Supermemory) -> None:
@parametrize
def test_method_create_with_all_params(self, client: Supermemory) -> None:
memory = client.memory.create(
- content="This is a detailed article about machine learning concepts...",
+ content="This is a detailed article about machine learning concepts..",
id="id",
metadata={
"source": "web",
@@ -52,7 +52,7 @@ def test_method_create_with_all_params(self, client: Supermemory) -> None:
@parametrize
def test_raw_response_create(self, client: Supermemory) -> None:
response = client.memory.with_raw_response.create(
- content="This is a detailed article about machine learning concepts...",
+ content="This is a detailed article about machine learning concepts..",
)
assert response.is_closed is True
@@ -64,7 +64,7 @@ def test_raw_response_create(self, client: Supermemory) -> None:
@parametrize
def test_streaming_response_create(self, client: Supermemory) -> None:
with client.memory.with_streaming_response.create(
- content="This is a detailed article about machine learning concepts...",
+ content="This is a detailed article about machine learning concepts..",
) as response:
assert not response.is_closed
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
@@ -206,7 +206,7 @@ class TestAsyncMemory:
@parametrize
async def test_method_create(self, async_client: AsyncSupermemory) -> None:
memory = await async_client.memory.create(
- content="This is a detailed article about machine learning concepts...",
+ content="This is a detailed article about machine learning concepts..",
)
assert_matches_type(MemoryCreateResponse, memory, path=["response"])
@@ -214,7 +214,7 @@ async def test_method_create(self, async_client: AsyncSupermemory) -> None:
@parametrize
async def test_method_create_with_all_params(self, async_client: AsyncSupermemory) -> None:
memory = await async_client.memory.create(
- content="This is a detailed article about machine learning concepts...",
+ content="This is a detailed article about machine learning concepts..",
id="id",
metadata={
"source": "web",
@@ -232,7 +232,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncSupermemor
@parametrize
async def test_raw_response_create(self, async_client: AsyncSupermemory) -> None:
response = await async_client.memory.with_raw_response.create(
- content="This is a detailed article about machine learning concepts...",
+ content="This is a detailed article about machine learning concepts..",
)
assert response.is_closed is True
@@ -244,7 +244,7 @@ async def test_raw_response_create(self, async_client: AsyncSupermemory) -> None
@parametrize
async def test_streaming_response_create(self, async_client: AsyncSupermemory) -> None:
async with async_client.memory.with_streaming_response.create(
- content="This is a detailed article about machine learning concepts...",
+ content="This is a detailed article about machine learning concepts..",
) as response:
assert not response.is_closed
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
diff --git a/tests/test_client.py b/tests/test_client.py
index 30dc5897..d0f97a12 100644
--- a/tests/test_client.py
+++ b/tests/test_client.py
@@ -722,8 +722,7 @@ def test_retrying_timeout_errors_doesnt_leak(self, respx_mock: MockRouter) -> No
body=cast(
object,
maybe_transform(
- dict(content="This is a detailed article about machine learning concepts..."),
- MemoryCreateParams,
+ dict(content="This is a detailed article about machine learning concepts.."), MemoryCreateParams
),
),
cast_to=httpx.Response,
@@ -743,8 +742,7 @@ def test_retrying_status_errors_doesnt_leak(self, respx_mock: MockRouter) -> Non
body=cast(
object,
maybe_transform(
- dict(content="This is a detailed article about machine learning concepts..."),
- MemoryCreateParams,
+ dict(content="This is a detailed article about machine learning concepts.."), MemoryCreateParams
),
),
cast_to=httpx.Response,
@@ -780,7 +778,7 @@ def retry_handler(_request: httpx.Request) -> httpx.Response:
respx_mock.post("/add").mock(side_effect=retry_handler)
response = client.memory.with_raw_response.create(
- content="This is a detailed article about machine learning concepts..."
+ content="This is a detailed article about machine learning concepts.."
)
assert response.retries_taken == failures_before_success
@@ -806,7 +804,7 @@ def retry_handler(_request: httpx.Request) -> httpx.Response:
respx_mock.post("/add").mock(side_effect=retry_handler)
response = client.memory.with_raw_response.create(
- content="This is a detailed article about machine learning concepts...",
+ content="This is a detailed article about machine learning concepts..",
extra_headers={"x-stainless-retry-count": Omit()},
)
@@ -832,7 +830,7 @@ def retry_handler(_request: httpx.Request) -> httpx.Response:
respx_mock.post("/add").mock(side_effect=retry_handler)
response = client.memory.with_raw_response.create(
- content="This is a detailed article about machine learning concepts...",
+ content="This is a detailed article about machine learning concepts..",
extra_headers={"x-stainless-retry-count": "42"},
)
@@ -1508,8 +1506,7 @@ async def test_retrying_timeout_errors_doesnt_leak(self, respx_mock: MockRouter)
body=cast(
object,
maybe_transform(
- dict(content="This is a detailed article about machine learning concepts..."),
- MemoryCreateParams,
+ dict(content="This is a detailed article about machine learning concepts.."), MemoryCreateParams
),
),
cast_to=httpx.Response,
@@ -1529,8 +1526,7 @@ async def test_retrying_status_errors_doesnt_leak(self, respx_mock: MockRouter)
body=cast(
object,
maybe_transform(
- dict(content="This is a detailed article about machine learning concepts..."),
- MemoryCreateParams,
+ dict(content="This is a detailed article about machine learning concepts.."), MemoryCreateParams
),
),
cast_to=httpx.Response,
@@ -1567,7 +1563,7 @@ def retry_handler(_request: httpx.Request) -> httpx.Response:
respx_mock.post("/add").mock(side_effect=retry_handler)
response = await client.memory.with_raw_response.create(
- content="This is a detailed article about machine learning concepts..."
+ content="This is a detailed article about machine learning concepts.."
)
assert response.retries_taken == failures_before_success
@@ -1594,7 +1590,7 @@ def retry_handler(_request: httpx.Request) -> httpx.Response:
respx_mock.post("/add").mock(side_effect=retry_handler)
response = await client.memory.with_raw_response.create(
- content="This is a detailed article about machine learning concepts...",
+ content="This is a detailed article about machine learning concepts..",
extra_headers={"x-stainless-retry-count": Omit()},
)
@@ -1621,7 +1617,7 @@ def retry_handler(_request: httpx.Request) -> httpx.Response:
respx_mock.post("/add").mock(side_effect=retry_handler)
response = await client.memory.with_raw_response.create(
- content="This is a detailed article about machine learning concepts...",
+ content="This is a detailed article about machine learning concepts..",
extra_headers={"x-stainless-retry-count": "42"},
)
From 4052baeca12183552a9bda674e97310e77b93623 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Wed, 30 Apr 2025 05:16:37 +0000
Subject: [PATCH 06/24] feat(api): api update
---
.stats.yml | 4 +-
src/supermemory/resources/memory.py | 38 +++++++++++++---
src/supermemory/resources/search.py | 44 +++++++++++++------
src/supermemory/types/memory_create_params.py | 25 +++++++++--
src/supermemory/types/memory_get_response.py | 15 +++++--
.../types/search_execute_params.py | 30 ++++++++++---
6 files changed, 122 insertions(+), 34 deletions(-)
diff --git a/.stats.yml b/.stats.yml
index d272718d..6cfb1c5a 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
configured_endpoints: 8
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/supermemory--inc%2Fsupermemory-9d4f071b79b2524fee219bcfb0eafb1070969bb809e2f3dbee89392bfb3eac53.yml
-openapi_spec_hash: 089ce871ebc7bda9d2974706373a989e
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/supermemory--inc%2Fsupermemory-783134192ebb9f62b9a25815c143704ccec4466fb4c5ba611d60d854db976970.yml
+openapi_spec_hash: 2d0e081f9844f31ae00f95cff68ec29d
config_hash: eb32087403f958eead829e810f5a71b8
diff --git a/src/supermemory/resources/memory.py b/src/supermemory/resources/memory.py
index 349fdd2b..9bf4e180 100644
--- a/src/supermemory/resources/memory.py
+++ b/src/supermemory/resources/memory.py
@@ -66,11 +66,24 @@ def create(
metadata
Args:
- content: Content of the memory
+ content: The content to extract and process into a memory. This can be a URL to a
+ website, a PDF, an image, or a video.
- metadata: Optional metadata for the memory
+ Plaintext: Any plaintext format
- user_id: Optional end user ID this memory belongs to
+ URL: A URL to a website, PDF, image, or video
+
+ We automatically detect the content type from the url's response format.
+
+ metadata: Optional metadata for the memory. This is used to store additional information
+ about the memory. You can use this to store any additional information you need
+ about the memory. Metadata can be filtered through. Keys must be strings and are
+ case sensitive. Values can be strings, numbers, or booleans. You cannot nest
+ objects.
+
+ user_id: Optional end user ID this memory belongs to. This is used to group memories by
+ user. You should use the same ID stored in your external system where the user
+ is stored
extra_headers: Send extra headers
@@ -261,11 +274,24 @@ async def create(
metadata
Args:
- content: Content of the memory
+ content: The content to extract and process into a memory. This can be a URL to a
+ website, a PDF, an image, or a video.
+
+ Plaintext: Any plaintext format
+
+ URL: A URL to a website, PDF, image, or video
+
+ We automatically detect the content type from the url's response format.
- metadata: Optional metadata for the memory
+ metadata: Optional metadata for the memory. This is used to store additional information
+ about the memory. You can use this to store any additional information you need
+ about the memory. Metadata can be filtered through. Keys must be strings and are
+ case sensitive. Values can be strings, numbers, or booleans. You cannot nest
+ objects.
- user_id: Optional end user ID this memory belongs to
+ user_id: Optional end user ID this memory belongs to. This is used to group memories by
+ user. You should use the same ID stored in your external system where the user
+ is stored
extra_headers: Send extra headers
diff --git a/src/supermemory/resources/search.py b/src/supermemory/resources/search.py
index a31c8cad..d34ef772 100644
--- a/src/supermemory/resources/search.py
+++ b/src/supermemory/resources/search.py
@@ -66,32 +66,40 @@ def execute(
timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
) -> SearchExecuteResponse:
"""
- Search through documents with metadata filtering
+ Search through documents with filtering
Args:
q: Search query string
categories_filter: Optional category filters
- chunk_threshold: Maximum number of chunks to return
+ chunk_threshold: Threshold / sensitivity for chunk selection. 0 is least sensitive (returns most
+ chunks, more results), 1 is most sensitive (returns lesser chunks, accurate
+ results)
- doc_id: Optional document ID to search within
+ doc_id: Optional document ID to search within. You can use this to find chunks in a very
+ large document.
- document_threshold: Maximum number of documents to return
+ document_threshold: Threshold / sensitivity for document selection. 0 is least sensitive (returns
+ most documents, more results), 1 is most sensitive (returns lesser documents,
+ accurate results)
filters: Optional filters to apply to the search
include_summary: If true, include document summary in the response. This is helpful if you want a
- chatbot to know the context of the document.
+ chatbot to know the full context of the document.
limit: Maximum number of results to return
- only_matching_chunks: If true, only return matching chunks without context
+ only_matching_chunks: If true, only return matching chunks without context. Normally, we send the
+ previous and next chunk to provide more context for LLMs. If you only want the
+ matching chunk, set this to true.
rewrite_query: If true, rewrites the query to make it easier to find documents. This increases
the latency by about 400ms
- user_id: End user ID this search is associated with
+ user_id: End user ID this search is associated with. NOTE: This also acts as a filter for
+ the search.
extra_headers: Send extra headers
@@ -168,32 +176,40 @@ async def execute(
timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
) -> SearchExecuteResponse:
"""
- Search through documents with metadata filtering
+ Search through documents with filtering
Args:
q: Search query string
categories_filter: Optional category filters
- chunk_threshold: Maximum number of chunks to return
+ chunk_threshold: Threshold / sensitivity for chunk selection. 0 is least sensitive (returns most
+ chunks, more results), 1 is most sensitive (returns lesser chunks, accurate
+ results)
- doc_id: Optional document ID to search within
+ doc_id: Optional document ID to search within. You can use this to find chunks in a very
+ large document.
- document_threshold: Maximum number of documents to return
+ document_threshold: Threshold / sensitivity for document selection. 0 is least sensitive (returns
+ most documents, more results), 1 is most sensitive (returns lesser documents,
+ accurate results)
filters: Optional filters to apply to the search
include_summary: If true, include document summary in the response. This is helpful if you want a
- chatbot to know the context of the document.
+ chatbot to know the full context of the document.
limit: Maximum number of results to return
- only_matching_chunks: If true, only return matching chunks without context
+ only_matching_chunks: If true, only return matching chunks without context. Normally, we send the
+ previous and next chunk to provide more context for LLMs. If you only want the
+ matching chunk, set this to true.
rewrite_query: If true, rewrites the query to make it easier to find documents. This increases
the latency by about 400ms
- user_id: End user ID this search is associated with
+ user_id: End user ID this search is associated with. NOTE: This also acts as a filter for
+ the search.
extra_headers: Send extra headers
diff --git a/src/supermemory/types/memory_create_params.py b/src/supermemory/types/memory_create_params.py
index dc873287..938ba8e0 100644
--- a/src/supermemory/types/memory_create_params.py
+++ b/src/supermemory/types/memory_create_params.py
@@ -12,12 +12,31 @@
class MemoryCreateParams(TypedDict, total=False):
content: Required[str]
- """Content of the memory"""
+ """The content to extract and process into a memory.
+
+ This can be a URL to a website, a PDF, an image, or a video.
+
+ Plaintext: Any plaintext format
+
+ URL: A URL to a website, PDF, image, or video
+
+ We automatically detect the content type from the url's response format.
+ """
id: str
metadata: Dict[str, Union[str, float, bool]]
- """Optional metadata for the memory"""
+ """Optional metadata for the memory.
+
+ This is used to store additional information about the memory. You can use this
+ to store any additional information you need about the memory. Metadata can be
+ filtered through. Keys must be strings and are case sensitive. Values can be
+ strings, numbers, or booleans. You cannot nest objects.
+ """
user_id: Annotated[str, PropertyInfo(alias="userId")]
- """Optional end user ID this memory belongs to"""
+ """Optional end user ID this memory belongs to.
+
+ This is used to group memories by user. You should use the same ID stored in
+ your external system where the user is stored
+ """
diff --git a/src/supermemory/types/memory_get_response.py b/src/supermemory/types/memory_get_response.py
index d915a18d..a2f008e6 100644
--- a/src/supermemory/types/memory_get_response.py
+++ b/src/supermemory/types/memory_get_response.py
@@ -1,6 +1,8 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from typing import Dict, Optional
+from datetime import datetime
+from typing_extensions import Literal
from pydantic import Field as FieldInfo
@@ -10,18 +12,25 @@
class Doc(BaseModel):
- created_at: str = FieldInfo(alias="createdAt")
+ created_at: datetime = FieldInfo(alias="createdAt")
+ """Timestamp when the memory was created"""
- updated_at: str = FieldInfo(alias="updatedAt")
+ updated_at: datetime = FieldInfo(alias="updatedAt")
+ """Timestamp when the memory was last updated"""
metadata: Optional[Dict[str, object]] = None
+ """Custom metadata associated with the memory"""
summary: Optional[str] = None
+ """Summary of the memory content"""
title: Optional[str] = None
+ """Title of the memory"""
class MemoryGetResponse(BaseModel):
doc: Doc
+ """Memory document details"""
- status: Optional[str] = None
+ status: Optional[Literal["queued", "extracting", "chunking", "embedding", "indexing", "done", "failed"]] = None
+ """Current processing status of the memory"""
diff --git a/src/supermemory/types/search_execute_params.py b/src/supermemory/types/search_execute_params.py
index a6ec7301..2895007a 100644
--- a/src/supermemory/types/search_execute_params.py
+++ b/src/supermemory/types/search_execute_params.py
@@ -20,13 +20,24 @@ class SearchExecuteParams(TypedDict, total=False):
"""Optional category filters"""
chunk_threshold: Annotated[float, PropertyInfo(alias="chunkThreshold")]
- """Maximum number of chunks to return"""
+ """Threshold / sensitivity for chunk selection.
+
+ 0 is least sensitive (returns most chunks, more results), 1 is most sensitive
+ (returns lesser chunks, accurate results)
+ """
doc_id: Annotated[str, PropertyInfo(alias="docId")]
- """Optional document ID to search within"""
+ """Optional document ID to search within.
+
+ You can use this to find chunks in a very large document.
+ """
document_threshold: Annotated[float, PropertyInfo(alias="documentThreshold")]
- """Maximum number of documents to return"""
+ """Threshold / sensitivity for document selection.
+
+ 0 is least sensitive (returns most documents, more results), 1 is most sensitive
+ (returns lesser documents, accurate results)
+ """
filters: Filters
"""Optional filters to apply to the search"""
@@ -34,14 +45,18 @@ class SearchExecuteParams(TypedDict, total=False):
include_summary: Annotated[bool, PropertyInfo(alias="includeSummary")]
"""If true, include document summary in the response.
- This is helpful if you want a chatbot to know the context of the document.
+ This is helpful if you want a chatbot to know the full context of the document.
"""
limit: int
"""Maximum number of results to return"""
only_matching_chunks: Annotated[bool, PropertyInfo(alias="onlyMatchingChunks")]
- """If true, only return matching chunks without context"""
+ """If true, only return matching chunks without context.
+
+ Normally, we send the previous and next chunk to provide more context for LLMs.
+ If you only want the matching chunk, set this to true.
+ """
rewrite_query: Annotated[bool, PropertyInfo(alias="rewriteQuery")]
"""If true, rewrites the query to make it easier to find documents.
@@ -50,7 +65,10 @@ class SearchExecuteParams(TypedDict, total=False):
"""
user_id: Annotated[str, PropertyInfo(alias="userId")]
- """End user ID this search is associated with"""
+ """End user ID this search is associated with.
+
+ NOTE: This also acts as a filter for the search.
+ """
class FiltersUnionMember0(TypedDict, total=False):
From 722df6387d8fc3b38ee892d4382b19339a4b8165 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Wed, 30 Apr 2025 08:16:38 +0000
Subject: [PATCH 07/24] feat(api): api update
---
.stats.yml | 4 ++--
src/supermemory/resources/search.py | 10 ++++++++++
src/supermemory/types/memory_list_response.py | 5 ++++-
src/supermemory/types/search_execute_params.py | 6 ++++++
tests/api_resources/test_search.py | 2 ++
5 files changed, 24 insertions(+), 3 deletions(-)
diff --git a/.stats.yml b/.stats.yml
index 6cfb1c5a..281212b4 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
configured_endpoints: 8
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/supermemory--inc%2Fsupermemory-783134192ebb9f62b9a25815c143704ccec4466fb4c5ba611d60d854db976970.yml
-openapi_spec_hash: 2d0e081f9844f31ae00f95cff68ec29d
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/supermemory--inc%2Fsupermemory-571ecc4d367c9f140a08728c8e3b5c1cc4f5f8ae698e325c5cbe5181c2c87bb0.yml
+openapi_spec_hash: b96a73f50568a58168354cb8690969e9
config_hash: eb32087403f958eead829e810f5a71b8
diff --git a/src/supermemory/resources/search.py b/src/supermemory/resources/search.py
index d34ef772..c6d8395a 100644
--- a/src/supermemory/resources/search.py
+++ b/src/supermemory/resources/search.py
@@ -56,6 +56,7 @@ def execute(
include_summary: bool | NotGiven = NOT_GIVEN,
limit: int | NotGiven = NOT_GIVEN,
only_matching_chunks: bool | NotGiven = NOT_GIVEN,
+ rerank: bool | NotGiven = NOT_GIVEN,
rewrite_query: bool | NotGiven = NOT_GIVEN,
user_id: str | NotGiven = NOT_GIVEN,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
@@ -95,6 +96,9 @@ def execute(
previous and next chunk to provide more context for LLMs. If you only want the
matching chunk, set this to true.
+ rerank: If true, rerank the results based on the query. This is helpful if you want to
+ ensure the most relevant results are returned.
+
rewrite_query: If true, rewrites the query to make it easier to find documents. This increases
the latency by about 400ms
@@ -122,6 +126,7 @@ def execute(
"include_summary": include_summary,
"limit": limit,
"only_matching_chunks": only_matching_chunks,
+ "rerank": rerank,
"rewrite_query": rewrite_query,
"user_id": user_id,
},
@@ -166,6 +171,7 @@ async def execute(
include_summary: bool | NotGiven = NOT_GIVEN,
limit: int | NotGiven = NOT_GIVEN,
only_matching_chunks: bool | NotGiven = NOT_GIVEN,
+ rerank: bool | NotGiven = NOT_GIVEN,
rewrite_query: bool | NotGiven = NOT_GIVEN,
user_id: str | NotGiven = NOT_GIVEN,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
@@ -205,6 +211,9 @@ async def execute(
previous and next chunk to provide more context for LLMs. If you only want the
matching chunk, set this to true.
+ rerank: If true, rerank the results based on the query. This is helpful if you want to
+ ensure the most relevant results are returned.
+
rewrite_query: If true, rewrites the query to make it easier to find documents. This increases
the latency by about 400ms
@@ -232,6 +241,7 @@ async def execute(
"include_summary": include_summary,
"limit": limit,
"only_matching_chunks": only_matching_chunks,
+ "rerank": rerank,
"rewrite_query": rewrite_query,
"user_id": user_id,
},
diff --git a/src/supermemory/types/memory_list_response.py b/src/supermemory/types/memory_list_response.py
index 936f7675..06fff6b5 100644
--- a/src/supermemory/types/memory_list_response.py
+++ b/src/supermemory/types/memory_list_response.py
@@ -13,7 +13,10 @@
class Memory(BaseModel):
id: str
- """Unique identifier of the memory"""
+ """Unique identifier of the memory.
+
+ This is your user's id in your system or database.
+ """
content: Optional[str] = None
"""Content of the memory"""
diff --git a/src/supermemory/types/search_execute_params.py b/src/supermemory/types/search_execute_params.py
index 2895007a..bc3b4756 100644
--- a/src/supermemory/types/search_execute_params.py
+++ b/src/supermemory/types/search_execute_params.py
@@ -58,6 +58,12 @@ class SearchExecuteParams(TypedDict, total=False):
If you only want the matching chunk, set this to true.
"""
+ rerank: bool
+ """If true, rerank the results based on the query.
+
+ This is helpful if you want to ensure the most relevant results are returned.
+ """
+
rewrite_query: Annotated[bool, PropertyInfo(alias="rewriteQuery")]
"""If true, rewrites the query to make it easier to find documents.
diff --git a/tests/api_resources/test_search.py b/tests/api_resources/test_search.py
index f3ed3549..c0557ff5 100644
--- a/tests/api_resources/test_search.py
+++ b/tests/api_resources/test_search.py
@@ -54,6 +54,7 @@ def test_method_execute_with_all_params(self, client: Supermemory) -> None:
include_summary=False,
limit=10,
only_matching_chunks=False,
+ rerank=False,
rewrite_query=False,
user_id="user_123",
)
@@ -126,6 +127,7 @@ async def test_method_execute_with_all_params(self, async_client: AsyncSupermemo
include_summary=False,
limit=10,
only_matching_chunks=False,
+ rerank=False,
rewrite_query=False,
user_id="user_123",
)
From be6c667dbff65c00fc7f3bd22e541b477c19ca08 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Fri, 9 May 2025 02:48:04 +0000
Subject: [PATCH 08/24] chore(internal): avoid errors for isinstance checks on
proxies
---
src/supermemory/_utils/_proxy.py | 5 ++++-
tests/test_utils/test_proxy.py | 11 +++++++++++
2 files changed, 15 insertions(+), 1 deletion(-)
diff --git a/src/supermemory/_utils/_proxy.py b/src/supermemory/_utils/_proxy.py
index ffd883e9..0f239a33 100644
--- a/src/supermemory/_utils/_proxy.py
+++ b/src/supermemory/_utils/_proxy.py
@@ -46,7 +46,10 @@ def __dir__(self) -> Iterable[str]:
@property # type: ignore
@override
def __class__(self) -> type: # pyright: ignore
- proxied = self.__get_proxied__()
+ try:
+ proxied = self.__get_proxied__()
+ except Exception:
+ return type(self)
if issubclass(type(proxied), LazyProxy):
return type(proxied)
return proxied.__class__
diff --git a/tests/test_utils/test_proxy.py b/tests/test_utils/test_proxy.py
index cbb84efb..74440350 100644
--- a/tests/test_utils/test_proxy.py
+++ b/tests/test_utils/test_proxy.py
@@ -21,3 +21,14 @@ def test_recursive_proxy() -> None:
assert dir(proxy) == []
assert type(proxy).__name__ == "RecursiveLazyProxy"
assert type(operator.attrgetter("name.foo.bar.baz")(proxy)).__name__ == "RecursiveLazyProxy"
+
+
+def test_isinstance_does_not_error() -> None:
+ class AlwaysErrorProxy(LazyProxy[Any]):
+ @override
+ def __load__(self) -> Any:
+ raise RuntimeError("Mocking missing dependency")
+
+ proxy = AlwaysErrorProxy()
+ assert not isinstance(proxy, dict)
+ assert isinstance(proxy, LazyProxy)
From aa2984202e3ff68031618847bc5a438e5a42933f Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Sat, 10 May 2025 02:36:38 +0000
Subject: [PATCH 09/24] fix(package): support direct resource imports
---
src/supermemory/__init__.py | 5 +++++
src/supermemory/_utils/_resources_proxy.py | 24 ++++++++++++++++++++++
2 files changed, 29 insertions(+)
create mode 100644 src/supermemory/_utils/_resources_proxy.py
diff --git a/src/supermemory/__init__.py b/src/supermemory/__init__.py
index a46b5100..3cc510e4 100644
--- a/src/supermemory/__init__.py
+++ b/src/supermemory/__init__.py
@@ -1,5 +1,7 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+import typing as _t
+
from . import types
from ._types import NOT_GIVEN, Omit, NoneType, NotGiven, Transport, ProxiesTypes
from ._utils import file_from_path
@@ -78,6 +80,9 @@
"DefaultAsyncHttpxClient",
]
+if not _t.TYPE_CHECKING:
+ from ._utils._resources_proxy import resources as resources
+
_setup_logging()
# Update the __module__ attribute for exported symbols so that
diff --git a/src/supermemory/_utils/_resources_proxy.py b/src/supermemory/_utils/_resources_proxy.py
new file mode 100644
index 00000000..53b457d1
--- /dev/null
+++ b/src/supermemory/_utils/_resources_proxy.py
@@ -0,0 +1,24 @@
+from __future__ import annotations
+
+from typing import Any
+from typing_extensions import override
+
+from ._proxy import LazyProxy
+
+
+class ResourcesProxy(LazyProxy[Any]):
+ """A proxy for the `supermemory.resources` module.
+
+ This is used so that we can lazily import `supermemory.resources` only when
+ needed *and* so that users can just import `supermemory` and reference `supermemory.resources`
+ """
+
+ @override
+ def __load__(self) -> Any:
+ import importlib
+
+ mod = importlib.import_module("supermemory.resources")
+ return mod
+
+
+resources = ResourcesProxy().__as_proxied__()
From 637811c4a31cfc9d258ca8562fee1cd38fb51320 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Sun, 11 May 2025 14:42:31 +0000
Subject: [PATCH 10/24] feat(api): manual updates
---
.stats.yml | 6 +-
README.md | 63 ++--
api.md | 44 +--
src/supermemory/_client.py | 58 +--
src/supermemory/resources/__init__.py | 66 ++--
.../{connection.py => connections.py} | 196 +++++-----
.../resources/{memory.py => memories.py} | 339 +++++++-----------
src/supermemory/resources/search.py | 290 ---------------
src/supermemory/resources/settings.py | 69 +++-
src/supermemory/types/__init__.py | 11 +-
.../types/connection_create_params.py | 15 -
.../types/connection_get_response.py | 21 ++
.../types/connection_list_response.py | 25 ++
src/supermemory/types/memory_add_params.py | 18 +
...ate_response.py => memory_add_response.py} | 4 +-
src/supermemory/types/memory_create_params.py | 42 ---
.../types/memory_delete_response.py | 4 +-
src/supermemory/types/memory_get_response.py | 31 +-
src/supermemory/types/memory_list_params.py | 24 --
src/supermemory/types/memory_list_response.py | 55 +--
.../types/search_execute_params.py | 86 -----
.../types/search_execute_response.py | 52 ---
src/supermemory/types/setting_get_response.py | 11 +
.../types/setting_update_params.py | 16 +-
.../types/setting_update_response.py | 14 +-
tests/api_resources/test_connection.py | 200 -----------
tests/api_resources/test_connections.py | 230 ++++++++++++
.../{test_memory.py => test_memories.py} | 292 +++++++--------
tests/api_resources/test_search.py | 160 ---------
tests/api_resources/test_settings.py | 74 +++-
tests/test_client.py | 120 +++----
31 files changed, 979 insertions(+), 1657 deletions(-)
rename src/supermemory/resources/{connection.py => connections.py} (55%)
rename src/supermemory/resources/{memory.py => memories.py} (62%)
delete mode 100644 src/supermemory/resources/search.py
delete mode 100644 src/supermemory/types/connection_create_params.py
create mode 100644 src/supermemory/types/connection_get_response.py
create mode 100644 src/supermemory/types/connection_list_response.py
create mode 100644 src/supermemory/types/memory_add_params.py
rename src/supermemory/types/{memory_create_response.py => memory_add_response.py} (67%)
delete mode 100644 src/supermemory/types/memory_create_params.py
delete mode 100644 src/supermemory/types/memory_list_params.py
delete mode 100644 src/supermemory/types/search_execute_params.py
delete mode 100644 src/supermemory/types/search_execute_response.py
create mode 100644 src/supermemory/types/setting_get_response.py
delete mode 100644 tests/api_resources/test_connection.py
create mode 100644 tests/api_resources/test_connections.py
rename tests/api_resources/{test_memory.py => test_memories.py} (70%)
delete mode 100644 tests/api_resources/test_search.py
diff --git a/.stats.yml b/.stats.yml
index 281212b4..75349c0b 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
configured_endpoints: 8
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/supermemory--inc%2Fsupermemory-571ecc4d367c9f140a08728c8e3b5c1cc4f5f8ae698e325c5cbe5181c2c87bb0.yml
-openapi_spec_hash: b96a73f50568a58168354cb8690969e9
-config_hash: eb32087403f958eead829e810f5a71b8
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/supermemory--inc%2Fsupermemory-3fa2583744becce1e91ec5ad18f45d2cf17778def3a8f70537a15b08c746c2fb.yml
+openapi_spec_hash: bf3c5827e7ddb8b32435aeb671fe7845
+config_hash: b9c958a39a94966479e516e9061818be
diff --git a/README.md b/README.md
index 80699ce7..9f05e6a6 100644
--- a/README.md
+++ b/README.md
@@ -24,36 +24,43 @@ pip install --pre supermemory
The full API of this library can be found in [api.md](api.md).
```python
+import os
from supermemory import Supermemory
client = Supermemory(
- api_key="My API Key",
+ api_key=os.environ.get("SUPERMEMORY_API_KEY"), # This is the default and can be omitted
)
-response = client.search.execute(
- q="documents related to python",
+memories = client.memories.list(
+ "id",
)
-print(response.results)
+print(memories.success)
```
+While you can provide an `api_key` keyword argument,
+we recommend using [python-dotenv](https://pypi.org/project/python-dotenv/)
+to add `SUPERMEMORY_API_KEY="My API Key"` to your `.env` file
+so that your API Key is not stored in source control.
+
## Async usage
Simply import `AsyncSupermemory` instead of `Supermemory` and use `await` with each API call:
```python
+import os
import asyncio
from supermemory import AsyncSupermemory
client = AsyncSupermemory(
- api_key="My API Key",
+ api_key=os.environ.get("SUPERMEMORY_API_KEY"), # This is the default and can be omitted
)
async def main() -> None:
- response = await client.search.execute(
- q="documents related to python",
+ memories = await client.memories.list(
+ "id",
)
- print(response.results)
+ print(memories.success)
asyncio.run(main())
@@ -83,13 +90,11 @@ All errors inherit from `supermemory.APIError`.
import supermemory
from supermemory import Supermemory
-client = Supermemory(
- api_key="My API Key",
-)
+client = Supermemory()
try:
- client.memory.create(
- content="This is a detailed article about machine learning concepts..",
+ client.memories.list(
+ "id",
)
except supermemory.APIConnectionError as e:
print("The server could not be reached")
@@ -128,14 +133,13 @@ from supermemory import Supermemory
# Configure the default for all requests:
client = Supermemory(
- api_key="My API Key",
# default is 2
max_retries=0,
)
# Or, configure per-request:
-client.with_options(max_retries=5).memory.create(
- content="This is a detailed article about machine learning concepts..",
+client.with_options(max_retries=5).memories.list(
+ "id",
)
```
@@ -149,20 +153,18 @@ from supermemory import Supermemory
# Configure the default for all requests:
client = Supermemory(
- api_key="My API Key",
# 20 seconds (default is 1 minute)
timeout=20.0,
)
# More granular control:
client = Supermemory(
- api_key="My API Key",
timeout=httpx.Timeout(60.0, read=5.0, write=10.0, connect=2.0),
)
# Override per-request:
-client.with_options(timeout=5.0).memory.create(
- content="This is a detailed article about machine learning concepts..",
+client.with_options(timeout=5.0).memories.list(
+ "id",
)
```
@@ -203,16 +205,14 @@ The "raw" Response object can be accessed by prefixing `.with_raw_response.` to
```py
from supermemory import Supermemory
-client = Supermemory(
- api_key="My API Key",
-)
-response = client.memory.with_raw_response.create(
- content="This is a detailed article about machine learning concepts..",
+client = Supermemory()
+response = client.memories.with_raw_response.list(
+ "id",
)
print(response.headers.get('X-My-Header'))
-memory = response.parse() # get the object that `memory.create()` would have returned
-print(memory.id)
+memory = response.parse() # get the object that `memories.list()` would have returned
+print(memory.success)
```
These methods return an [`APIResponse`](https://github.com/supermemoryai/python-sdk/tree/main/src/supermemory/_response.py) object.
@@ -226,8 +226,8 @@ The above interface eagerly reads the full response body when you make the reque
To stream the response body, use `.with_streaming_response` instead, which requires a context manager and only reads the response body once you call `.read()`, `.text()`, `.json()`, `.iter_bytes()`, `.iter_text()`, `.iter_lines()` or `.parse()`. In the async client, these are async methods.
```python
-with client.memory.with_streaming_response.create(
- content="This is a detailed article about machine learning concepts..",
+with client.memories.with_streaming_response.list(
+ "id",
) as response:
print(response.headers.get("X-My-Header"))
@@ -284,7 +284,6 @@ import httpx
from supermemory import Supermemory, DefaultHttpxClient
client = Supermemory(
- api_key="My API Key",
# Or use the `SUPERMEMORY_BASE_URL` env var
base_url="http://my.test.server.example.com:8083",
http_client=DefaultHttpxClient(
@@ -307,9 +306,7 @@ By default the library closes underlying HTTP connections whenever the client is
```py
from supermemory import Supermemory
-with Supermemory(
- api_key="My API Key",
-) as client:
+with Supermemory() as client:
# make requests here
...
diff --git a/api.md b/api.md
index 337614f6..ea51d4ff 100644
--- a/api.md
+++ b/api.md
@@ -1,56 +1,50 @@
-# Settings
-
-Types:
-
-```python
-from supermemory.types import SettingUpdateResponse
-```
-
-Methods:
-
-- client.settings.update(\*\*params) -> SettingUpdateResponse
-
-# Memory
+# Memories
Types:
```python
from supermemory.types import (
- MemoryCreateResponse,
MemoryListResponse,
MemoryDeleteResponse,
+ MemoryAddResponse,
MemoryGetResponse,
)
```
Methods:
-- client.memory.create(\*\*params) -> MemoryCreateResponse
-- client.memory.list(\*\*params) -> MemoryListResponse
-- client.memory.delete(id) -> MemoryDeleteResponse
-- client.memory.get(id) -> MemoryGetResponse
+- client.memories.list(id) -> MemoryListResponse
+- client.memories.delete(id) -> MemoryDeleteResponse
+- client.memories.add(\*\*params) -> MemoryAddResponse
+- client.memories.get(id) -> MemoryGetResponse
-# Search
+# Settings
Types:
```python
-from supermemory.types import SearchExecuteResponse
+from supermemory.types import SettingUpdateResponse, SettingGetResponse
```
Methods:
-- client.search.execute(\*\*params) -> SearchExecuteResponse
+- client.settings.update(\*\*params) -> SettingUpdateResponse
+- client.settings.get() -> SettingGetResponse
-# Connection
+# Connections
Types:
```python
-from supermemory.types import ConnectionCreateResponse
+from supermemory.types import (
+ ConnectionCreateResponse,
+ ConnectionListResponse,
+ ConnectionGetResponse,
+)
```
Methods:
-- client.connection.create(app, \*\*params) -> ConnectionCreateResponse
-- client.connection.retrieve(connection_id) -> None
+- client.connections.create(provider) -> ConnectionCreateResponse
+- client.connections.list() -> ConnectionListResponse
+- client.connections.get(connection_id) -> ConnectionGetResponse
diff --git a/src/supermemory/_client.py b/src/supermemory/_client.py
index 266329fc..0a336bf6 100644
--- a/src/supermemory/_client.py
+++ b/src/supermemory/_client.py
@@ -21,7 +21,7 @@
)
from ._utils import is_given, get_async_library
from ._version import __version__
-from .resources import memory, search, settings, connection
+from .resources import memories, settings, connections
from ._streaming import Stream as Stream, AsyncStream as AsyncStream
from ._exceptions import APIStatusError, SupermemoryError
from ._base_client import (
@@ -43,10 +43,9 @@
class Supermemory(SyncAPIClient):
+ memories: memories.MemoriesResource
settings: settings.SettingsResource
- memory: memory.MemoryResource
- search: search.SearchResource
- connection: connection.ConnectionResource
+ connections: connections.ConnectionsResource
with_raw_response: SupermemoryWithRawResponse
with_streaming_response: SupermemoryWithStreamedResponse
@@ -91,7 +90,7 @@ def __init__(
if base_url is None:
base_url = os.environ.get("SUPERMEMORY_BASE_URL")
if base_url is None:
- base_url = f"https://v2.api.supermemory.ai"
+ base_url = f"https://api.supermemory.ai/"
super().__init__(
version=__version__,
@@ -104,10 +103,9 @@ def __init__(
_strict_response_validation=_strict_response_validation,
)
+ self.memories = memories.MemoriesResource(self)
self.settings = settings.SettingsResource(self)
- self.memory = memory.MemoryResource(self)
- self.search = search.SearchResource(self)
- self.connection = connection.ConnectionResource(self)
+ self.connections = connections.ConnectionsResource(self)
self.with_raw_response = SupermemoryWithRawResponse(self)
self.with_streaming_response = SupermemoryWithStreamedResponse(self)
@@ -116,6 +114,12 @@ def __init__(
def qs(self) -> Querystring:
return Querystring(array_format="comma")
+ @property
+ @override
+ def auth_headers(self) -> dict[str, str]:
+ api_key = self.api_key
+ return {"Authorization": f"Bearer {api_key}"}
+
@property
@override
def default_headers(self) -> dict[str, str | Omit]:
@@ -211,10 +215,9 @@ def _make_status_error(
class AsyncSupermemory(AsyncAPIClient):
+ memories: memories.AsyncMemoriesResource
settings: settings.AsyncSettingsResource
- memory: memory.AsyncMemoryResource
- search: search.AsyncSearchResource
- connection: connection.AsyncConnectionResource
+ connections: connections.AsyncConnectionsResource
with_raw_response: AsyncSupermemoryWithRawResponse
with_streaming_response: AsyncSupermemoryWithStreamedResponse
@@ -259,7 +262,7 @@ def __init__(
if base_url is None:
base_url = os.environ.get("SUPERMEMORY_BASE_URL")
if base_url is None:
- base_url = f"https://v2.api.supermemory.ai"
+ base_url = f"https://api.supermemory.ai/"
super().__init__(
version=__version__,
@@ -272,10 +275,9 @@ def __init__(
_strict_response_validation=_strict_response_validation,
)
+ self.memories = memories.AsyncMemoriesResource(self)
self.settings = settings.AsyncSettingsResource(self)
- self.memory = memory.AsyncMemoryResource(self)
- self.search = search.AsyncSearchResource(self)
- self.connection = connection.AsyncConnectionResource(self)
+ self.connections = connections.AsyncConnectionsResource(self)
self.with_raw_response = AsyncSupermemoryWithRawResponse(self)
self.with_streaming_response = AsyncSupermemoryWithStreamedResponse(self)
@@ -284,6 +286,12 @@ def __init__(
def qs(self) -> Querystring:
return Querystring(array_format="comma")
+ @property
+ @override
+ def auth_headers(self) -> dict[str, str]:
+ api_key = self.api_key
+ return {"Authorization": f"Bearer {api_key}"}
+
@property
@override
def default_headers(self) -> dict[str, str | Omit]:
@@ -380,34 +388,30 @@ def _make_status_error(
class SupermemoryWithRawResponse:
def __init__(self, client: Supermemory) -> None:
+ self.memories = memories.MemoriesResourceWithRawResponse(client.memories)
self.settings = settings.SettingsResourceWithRawResponse(client.settings)
- self.memory = memory.MemoryResourceWithRawResponse(client.memory)
- self.search = search.SearchResourceWithRawResponse(client.search)
- self.connection = connection.ConnectionResourceWithRawResponse(client.connection)
+ self.connections = connections.ConnectionsResourceWithRawResponse(client.connections)
class AsyncSupermemoryWithRawResponse:
def __init__(self, client: AsyncSupermemory) -> None:
+ self.memories = memories.AsyncMemoriesResourceWithRawResponse(client.memories)
self.settings = settings.AsyncSettingsResourceWithRawResponse(client.settings)
- self.memory = memory.AsyncMemoryResourceWithRawResponse(client.memory)
- self.search = search.AsyncSearchResourceWithRawResponse(client.search)
- self.connection = connection.AsyncConnectionResourceWithRawResponse(client.connection)
+ self.connections = connections.AsyncConnectionsResourceWithRawResponse(client.connections)
class SupermemoryWithStreamedResponse:
def __init__(self, client: Supermemory) -> None:
+ self.memories = memories.MemoriesResourceWithStreamingResponse(client.memories)
self.settings = settings.SettingsResourceWithStreamingResponse(client.settings)
- self.memory = memory.MemoryResourceWithStreamingResponse(client.memory)
- self.search = search.SearchResourceWithStreamingResponse(client.search)
- self.connection = connection.ConnectionResourceWithStreamingResponse(client.connection)
+ self.connections = connections.ConnectionsResourceWithStreamingResponse(client.connections)
class AsyncSupermemoryWithStreamedResponse:
def __init__(self, client: AsyncSupermemory) -> None:
+ self.memories = memories.AsyncMemoriesResourceWithStreamingResponse(client.memories)
self.settings = settings.AsyncSettingsResourceWithStreamingResponse(client.settings)
- self.memory = memory.AsyncMemoryResourceWithStreamingResponse(client.memory)
- self.search = search.AsyncSearchResourceWithStreamingResponse(client.search)
- self.connection = connection.AsyncConnectionResourceWithStreamingResponse(client.connection)
+ self.connections = connections.AsyncConnectionsResourceWithStreamingResponse(client.connections)
Client = Supermemory
diff --git a/src/supermemory/resources/__init__.py b/src/supermemory/resources/__init__.py
index b772e05e..5a1fb723 100644
--- a/src/supermemory/resources/__init__.py
+++ b/src/supermemory/resources/__init__.py
@@ -1,20 +1,12 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-from .memory import (
- MemoryResource,
- AsyncMemoryResource,
- MemoryResourceWithRawResponse,
- AsyncMemoryResourceWithRawResponse,
- MemoryResourceWithStreamingResponse,
- AsyncMemoryResourceWithStreamingResponse,
-)
-from .search import (
- SearchResource,
- AsyncSearchResource,
- SearchResourceWithRawResponse,
- AsyncSearchResourceWithRawResponse,
- SearchResourceWithStreamingResponse,
- AsyncSearchResourceWithStreamingResponse,
+from .memories import (
+ MemoriesResource,
+ AsyncMemoriesResource,
+ MemoriesResourceWithRawResponse,
+ AsyncMemoriesResourceWithRawResponse,
+ MemoriesResourceWithStreamingResponse,
+ AsyncMemoriesResourceWithStreamingResponse,
)
from .settings import (
SettingsResource,
@@ -24,38 +16,32 @@
SettingsResourceWithStreamingResponse,
AsyncSettingsResourceWithStreamingResponse,
)
-from .connection import (
- ConnectionResource,
- AsyncConnectionResource,
- ConnectionResourceWithRawResponse,
- AsyncConnectionResourceWithRawResponse,
- ConnectionResourceWithStreamingResponse,
- AsyncConnectionResourceWithStreamingResponse,
+from .connections import (
+ ConnectionsResource,
+ AsyncConnectionsResource,
+ ConnectionsResourceWithRawResponse,
+ AsyncConnectionsResourceWithRawResponse,
+ ConnectionsResourceWithStreamingResponse,
+ AsyncConnectionsResourceWithStreamingResponse,
)
__all__ = [
+ "MemoriesResource",
+ "AsyncMemoriesResource",
+ "MemoriesResourceWithRawResponse",
+ "AsyncMemoriesResourceWithRawResponse",
+ "MemoriesResourceWithStreamingResponse",
+ "AsyncMemoriesResourceWithStreamingResponse",
"SettingsResource",
"AsyncSettingsResource",
"SettingsResourceWithRawResponse",
"AsyncSettingsResourceWithRawResponse",
"SettingsResourceWithStreamingResponse",
"AsyncSettingsResourceWithStreamingResponse",
- "MemoryResource",
- "AsyncMemoryResource",
- "MemoryResourceWithRawResponse",
- "AsyncMemoryResourceWithRawResponse",
- "MemoryResourceWithStreamingResponse",
- "AsyncMemoryResourceWithStreamingResponse",
- "SearchResource",
- "AsyncSearchResource",
- "SearchResourceWithRawResponse",
- "AsyncSearchResourceWithRawResponse",
- "SearchResourceWithStreamingResponse",
- "AsyncSearchResourceWithStreamingResponse",
- "ConnectionResource",
- "AsyncConnectionResource",
- "ConnectionResourceWithRawResponse",
- "AsyncConnectionResourceWithRawResponse",
- "ConnectionResourceWithStreamingResponse",
- "AsyncConnectionResourceWithStreamingResponse",
+ "ConnectionsResource",
+ "AsyncConnectionsResource",
+ "ConnectionsResourceWithRawResponse",
+ "AsyncConnectionsResourceWithRawResponse",
+ "ConnectionsResourceWithStreamingResponse",
+ "AsyncConnectionsResourceWithStreamingResponse",
]
diff --git a/src/supermemory/resources/connection.py b/src/supermemory/resources/connections.py
similarity index 55%
rename from src/supermemory/resources/connection.py
rename to src/supermemory/resources/connections.py
index a55ea8b7..75181a0d 100644
--- a/src/supermemory/resources/connection.py
+++ b/src/supermemory/resources/connections.py
@@ -6,9 +6,7 @@
import httpx
-from ..types import connection_create_params
-from .._types import NOT_GIVEN, Body, Query, Headers, NoneType, NotGiven
-from .._utils import maybe_transform, async_maybe_transform
+from .._types import NOT_GIVEN, Body, Query, Headers, NotGiven
from .._compat import cached_property
from .._resource import SyncAPIResource, AsyncAPIResource
from .._response import (
@@ -18,37 +16,37 @@
async_to_streamed_response_wrapper,
)
from .._base_client import make_request_options
+from ..types.connection_get_response import ConnectionGetResponse
+from ..types.connection_list_response import ConnectionListResponse
from ..types.connection_create_response import ConnectionCreateResponse
-__all__ = ["ConnectionResource", "AsyncConnectionResource"]
+__all__ = ["ConnectionsResource", "AsyncConnectionsResource"]
-class ConnectionResource(SyncAPIResource):
+class ConnectionsResource(SyncAPIResource):
@cached_property
- def with_raw_response(self) -> ConnectionResourceWithRawResponse:
+ def with_raw_response(self) -> ConnectionsResourceWithRawResponse:
"""
This property can be used as a prefix for any HTTP method call to return
the raw response object instead of the parsed content.
For more information, see https://www.github.com/supermemoryai/python-sdk#accessing-raw-response-data-eg-headers
"""
- return ConnectionResourceWithRawResponse(self)
+ return ConnectionsResourceWithRawResponse(self)
@cached_property
- def with_streaming_response(self) -> ConnectionResourceWithStreamingResponse:
+ def with_streaming_response(self) -> ConnectionsResourceWithStreamingResponse:
"""
An alternative to `.with_raw_response` that doesn't eagerly read the response body.
For more information, see https://www.github.com/supermemoryai/python-sdk#with_streaming_response
"""
- return ConnectionResourceWithStreamingResponse(self)
+ return ConnectionsResourceWithStreamingResponse(self)
def create(
self,
- app: Literal["notion", "google-drive"],
+ provider: Literal["notion", "google-drive", "onedrive"],
*,
- id: str,
- redirect_url: str | NotGiven = NOT_GIVEN,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
# The extra values given here take precedence over values defined on the client or passed to this method.
extra_headers: Headers | None = None,
@@ -68,27 +66,36 @@ def create(
timeout: Override the client-level default timeout for this request, in seconds
"""
- if not app:
- raise ValueError(f"Expected a non-empty value for `app` but received {app!r}")
- return self._get(
- f"/connect/{app}",
+ if not provider:
+ raise ValueError(f"Expected a non-empty value for `provider` but received {provider!r}")
+ return self._post(
+ f"/v3/connections/{provider}",
options=make_request_options(
- extra_headers=extra_headers,
- extra_query=extra_query,
- extra_body=extra_body,
- timeout=timeout,
- query=maybe_transform(
- {
- "id": id,
- "redirect_url": redirect_url,
- },
- connection_create_params.ConnectionCreateParams,
- ),
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
cast_to=ConnectionCreateResponse,
)
- def retrieve(
+ def list(
+ self,
+ *,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+ ) -> ConnectionListResponse:
+ """List all connections"""
+ return self._get(
+ "/v3/connections",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=ConnectionListResponse,
+ )
+
+ def get(
self,
connection_id: str,
*,
@@ -98,8 +105,10 @@ def retrieve(
extra_query: Query | None = None,
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
- ) -> None:
+ ) -> ConnectionGetResponse:
"""
+ Get connection details
+
Args:
extra_headers: Send extra headers
@@ -111,42 +120,39 @@ def retrieve(
"""
if not connection_id:
raise ValueError(f"Expected a non-empty value for `connection_id` but received {connection_id!r}")
- extra_headers = {"Accept": "*/*", **(extra_headers or {})}
return self._get(
- f"/connections/{connection_id}",
+ f"/v3/connections/{connection_id}",
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
- cast_to=NoneType,
+ cast_to=ConnectionGetResponse,
)
-class AsyncConnectionResource(AsyncAPIResource):
+class AsyncConnectionsResource(AsyncAPIResource):
@cached_property
- def with_raw_response(self) -> AsyncConnectionResourceWithRawResponse:
+ def with_raw_response(self) -> AsyncConnectionsResourceWithRawResponse:
"""
This property can be used as a prefix for any HTTP method call to return
the raw response object instead of the parsed content.
For more information, see https://www.github.com/supermemoryai/python-sdk#accessing-raw-response-data-eg-headers
"""
- return AsyncConnectionResourceWithRawResponse(self)
+ return AsyncConnectionsResourceWithRawResponse(self)
@cached_property
- def with_streaming_response(self) -> AsyncConnectionResourceWithStreamingResponse:
+ def with_streaming_response(self) -> AsyncConnectionsResourceWithStreamingResponse:
"""
An alternative to `.with_raw_response` that doesn't eagerly read the response body.
For more information, see https://www.github.com/supermemoryai/python-sdk#with_streaming_response
"""
- return AsyncConnectionResourceWithStreamingResponse(self)
+ return AsyncConnectionsResourceWithStreamingResponse(self)
async def create(
self,
- app: Literal["notion", "google-drive"],
+ provider: Literal["notion", "google-drive", "onedrive"],
*,
- id: str,
- redirect_url: str | NotGiven = NOT_GIVEN,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
# The extra values given here take precedence over values defined on the client or passed to this method.
extra_headers: Headers | None = None,
@@ -166,27 +172,36 @@ async def create(
timeout: Override the client-level default timeout for this request, in seconds
"""
- if not app:
- raise ValueError(f"Expected a non-empty value for `app` but received {app!r}")
- return await self._get(
- f"/connect/{app}",
+ if not provider:
+ raise ValueError(f"Expected a non-empty value for `provider` but received {provider!r}")
+ return await self._post(
+ f"/v3/connections/{provider}",
options=make_request_options(
- extra_headers=extra_headers,
- extra_query=extra_query,
- extra_body=extra_body,
- timeout=timeout,
- query=await async_maybe_transform(
- {
- "id": id,
- "redirect_url": redirect_url,
- },
- connection_create_params.ConnectionCreateParams,
- ),
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
cast_to=ConnectionCreateResponse,
)
- async def retrieve(
+ async def list(
+ self,
+ *,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+ ) -> ConnectionListResponse:
+ """List all connections"""
+ return await self._get(
+ "/v3/connections",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=ConnectionListResponse,
+ )
+
+ async def get(
self,
connection_id: str,
*,
@@ -196,8 +211,10 @@ async def retrieve(
extra_query: Query | None = None,
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
- ) -> None:
+ ) -> ConnectionGetResponse:
"""
+ Get connection details
+
Args:
extra_headers: Send extra headers
@@ -209,59 +226,70 @@ async def retrieve(
"""
if not connection_id:
raise ValueError(f"Expected a non-empty value for `connection_id` but received {connection_id!r}")
- extra_headers = {"Accept": "*/*", **(extra_headers or {})}
return await self._get(
- f"/connections/{connection_id}",
+ f"/v3/connections/{connection_id}",
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
- cast_to=NoneType,
+ cast_to=ConnectionGetResponse,
)
-class ConnectionResourceWithRawResponse:
- def __init__(self, connection: ConnectionResource) -> None:
- self._connection = connection
+class ConnectionsResourceWithRawResponse:
+ def __init__(self, connections: ConnectionsResource) -> None:
+ self._connections = connections
self.create = to_raw_response_wrapper(
- connection.create,
+ connections.create,
)
- self.retrieve = to_raw_response_wrapper(
- connection.retrieve,
+ self.list = to_raw_response_wrapper(
+ connections.list,
+ )
+ self.get = to_raw_response_wrapper(
+ connections.get,
)
-class AsyncConnectionResourceWithRawResponse:
- def __init__(self, connection: AsyncConnectionResource) -> None:
- self._connection = connection
+class AsyncConnectionsResourceWithRawResponse:
+ def __init__(self, connections: AsyncConnectionsResource) -> None:
+ self._connections = connections
self.create = async_to_raw_response_wrapper(
- connection.create,
+ connections.create,
+ )
+ self.list = async_to_raw_response_wrapper(
+ connections.list,
)
- self.retrieve = async_to_raw_response_wrapper(
- connection.retrieve,
+ self.get = async_to_raw_response_wrapper(
+ connections.get,
)
-class ConnectionResourceWithStreamingResponse:
- def __init__(self, connection: ConnectionResource) -> None:
- self._connection = connection
+class ConnectionsResourceWithStreamingResponse:
+ def __init__(self, connections: ConnectionsResource) -> None:
+ self._connections = connections
self.create = to_streamed_response_wrapper(
- connection.create,
+ connections.create,
)
- self.retrieve = to_streamed_response_wrapper(
- connection.retrieve,
+ self.list = to_streamed_response_wrapper(
+ connections.list,
+ )
+ self.get = to_streamed_response_wrapper(
+ connections.get,
)
-class AsyncConnectionResourceWithStreamingResponse:
- def __init__(self, connection: AsyncConnectionResource) -> None:
- self._connection = connection
+class AsyncConnectionsResourceWithStreamingResponse:
+ def __init__(self, connections: AsyncConnectionsResource) -> None:
+ self._connections = connections
self.create = async_to_streamed_response_wrapper(
- connection.create,
+ connections.create,
+ )
+ self.list = async_to_streamed_response_wrapper(
+ connections.list,
)
- self.retrieve = async_to_streamed_response_wrapper(
- connection.retrieve,
+ self.get = async_to_streamed_response_wrapper(
+ connections.get,
)
diff --git a/src/supermemory/resources/memory.py b/src/supermemory/resources/memories.py
similarity index 62%
rename from src/supermemory/resources/memory.py
rename to src/supermemory/resources/memories.py
index 9bf4e180..891d1b6a 100644
--- a/src/supermemory/resources/memory.py
+++ b/src/supermemory/resources/memories.py
@@ -2,12 +2,11 @@
from __future__ import annotations
-from typing import Dict, Union
-from typing_extensions import Literal
+from typing import Dict, List, Union
import httpx
-from ..types import memory_list_params, memory_create_params
+from ..types import memory_add_params
from .._types import NOT_GIVEN, Body, Query, Headers, NotGiven
from .._utils import maybe_transform, async_maybe_transform
from .._compat import cached_property
@@ -19,72 +18,49 @@
async_to_streamed_response_wrapper,
)
from .._base_client import make_request_options
+from ..types.memory_add_response import MemoryAddResponse
from ..types.memory_get_response import MemoryGetResponse
from ..types.memory_list_response import MemoryListResponse
-from ..types.memory_create_response import MemoryCreateResponse
from ..types.memory_delete_response import MemoryDeleteResponse
-__all__ = ["MemoryResource", "AsyncMemoryResource"]
+__all__ = ["MemoriesResource", "AsyncMemoriesResource"]
-class MemoryResource(SyncAPIResource):
+class MemoriesResource(SyncAPIResource):
@cached_property
- def with_raw_response(self) -> MemoryResourceWithRawResponse:
+ def with_raw_response(self) -> MemoriesResourceWithRawResponse:
"""
This property can be used as a prefix for any HTTP method call to return
the raw response object instead of the parsed content.
For more information, see https://www.github.com/supermemoryai/python-sdk#accessing-raw-response-data-eg-headers
"""
- return MemoryResourceWithRawResponse(self)
+ return MemoriesResourceWithRawResponse(self)
@cached_property
- def with_streaming_response(self) -> MemoryResourceWithStreamingResponse:
+ def with_streaming_response(self) -> MemoriesResourceWithStreamingResponse:
"""
An alternative to `.with_raw_response` that doesn't eagerly read the response body.
For more information, see https://www.github.com/supermemoryai/python-sdk#with_streaming_response
"""
- return MemoryResourceWithStreamingResponse(self)
+ return MemoriesResourceWithStreamingResponse(self)
- def create(
+ def list(
self,
+ id: str,
*,
- content: str,
- id: str | NotGiven = NOT_GIVEN,
- metadata: Dict[str, Union[str, float, bool]] | NotGiven = NOT_GIVEN,
- user_id: str | NotGiven = NOT_GIVEN,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
# The extra values given here take precedence over values defined on the client or passed to this method.
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
- ) -> MemoryCreateResponse:
+ ) -> MemoryListResponse:
"""
- Add or update a memory with any content type (text, url, file, etc.) with
- metadata
+ Delete a memory
Args:
- content: The content to extract and process into a memory. This can be a URL to a
- website, a PDF, an image, or a video.
-
- Plaintext: Any plaintext format
-
- URL: A URL to a website, PDF, image, or video
-
- We automatically detect the content type from the url's response format.
-
- metadata: Optional metadata for the memory. This is used to store additional information
- about the memory. You can use this to store any additional information you need
- about the memory. Metadata can be filtered through. Keys must be strings and are
- case sensitive. Values can be strings, numbers, or booleans. You cannot nest
- objects.
-
- user_id: Optional end user ID this memory belongs to. This is used to group memories by
- user. You should use the same ID stored in your external system where the user
- is stored
-
extra_headers: Send extra headers
extra_query: Add additional query parameters to the request
@@ -93,52 +69,31 @@ def create(
timeout: Override the client-level default timeout for this request, in seconds
"""
- return self._post(
- "/add",
- body=maybe_transform(
- {
- "content": content,
- "id": id,
- "metadata": metadata,
- "user_id": user_id,
- },
- memory_create_params.MemoryCreateParams,
- ),
+ if not id:
+ raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
+ return self._delete(
+ f"/v3/memories/{id}",
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
- cast_to=MemoryCreateResponse,
+ cast_to=MemoryListResponse,
)
- def list(
+ def delete(
self,
+ id: str,
*,
- filters: str | NotGiven = NOT_GIVEN,
- limit: str | NotGiven = NOT_GIVEN,
- order: Literal["asc", "desc"] | NotGiven = NOT_GIVEN,
- page: str | NotGiven = NOT_GIVEN,
- sort: Literal["createdAt", "updatedAt"] | NotGiven = NOT_GIVEN,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
# The extra values given here take precedence over values defined on the client or passed to this method.
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
- ) -> MemoryListResponse:
+ ) -> MemoryDeleteResponse:
"""
- Retrieves a paginated list of memories with their metadata and workflow status
+ Get a memory by ID
Args:
- filters: Optional filters to apply to the search
-
- limit: Number of items per page
-
- order: Sort order
-
- page: Page number to fetch
-
- sort: Field to sort by
-
extra_headers: Send extra headers
extra_query: Add additional query parameters to the request
@@ -147,40 +102,31 @@ def list(
timeout: Override the client-level default timeout for this request, in seconds
"""
+ if not id:
+ raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return self._get(
- "/memories",
+ f"/v3/memories/{id}",
options=make_request_options(
- extra_headers=extra_headers,
- extra_query=extra_query,
- extra_body=extra_body,
- timeout=timeout,
- query=maybe_transform(
- {
- "filters": filters,
- "limit": limit,
- "order": order,
- "page": page,
- "sort": sort,
- },
- memory_list_params.MemoryListParams,
- ),
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
- cast_to=MemoryListResponse,
+ cast_to=MemoryDeleteResponse,
)
- def delete(
+ def add(
self,
- id: str,
*,
+ content: str,
+ container_tags: List[str] | NotGiven = NOT_GIVEN,
+ metadata: Dict[str, Union[str, float, bool]] | NotGiven = NOT_GIVEN,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
# The extra values given here take precedence over values defined on the client or passed to this method.
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
- ) -> MemoryDeleteResponse:
+ ) -> MemoryAddResponse:
"""
- Delete a memory
+ Add a memory with any content type (text, url, file, etc.) and metadata
Args:
extra_headers: Send extra headers
@@ -191,14 +137,20 @@ def delete(
timeout: Override the client-level default timeout for this request, in seconds
"""
- if not id:
- raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
- return self._delete(
- f"/delete/{id}",
+ return self._post(
+ "/v3/memories",
+ body=maybe_transform(
+ {
+ "content": content,
+ "container_tags": container_tags,
+ "metadata": metadata,
+ },
+ memory_add_params.MemoryAddParams,
+ ),
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
- cast_to=MemoryDeleteResponse,
+ cast_to=MemoryAddResponse,
)
def get(
@@ -227,7 +179,7 @@ def get(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return self._get(
- f"/memory/{id}",
+ f"/v3/memories/{id}",
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
@@ -235,64 +187,41 @@ def get(
)
-class AsyncMemoryResource(AsyncAPIResource):
+class AsyncMemoriesResource(AsyncAPIResource):
@cached_property
- def with_raw_response(self) -> AsyncMemoryResourceWithRawResponse:
+ def with_raw_response(self) -> AsyncMemoriesResourceWithRawResponse:
"""
This property can be used as a prefix for any HTTP method call to return
the raw response object instead of the parsed content.
For more information, see https://www.github.com/supermemoryai/python-sdk#accessing-raw-response-data-eg-headers
"""
- return AsyncMemoryResourceWithRawResponse(self)
+ return AsyncMemoriesResourceWithRawResponse(self)
@cached_property
- def with_streaming_response(self) -> AsyncMemoryResourceWithStreamingResponse:
+ def with_streaming_response(self) -> AsyncMemoriesResourceWithStreamingResponse:
"""
An alternative to `.with_raw_response` that doesn't eagerly read the response body.
For more information, see https://www.github.com/supermemoryai/python-sdk#with_streaming_response
"""
- return AsyncMemoryResourceWithStreamingResponse(self)
+ return AsyncMemoriesResourceWithStreamingResponse(self)
- async def create(
+ async def list(
self,
+ id: str,
*,
- content: str,
- id: str | NotGiven = NOT_GIVEN,
- metadata: Dict[str, Union[str, float, bool]] | NotGiven = NOT_GIVEN,
- user_id: str | NotGiven = NOT_GIVEN,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
# The extra values given here take precedence over values defined on the client or passed to this method.
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
- ) -> MemoryCreateResponse:
+ ) -> MemoryListResponse:
"""
- Add or update a memory with any content type (text, url, file, etc.) with
- metadata
+ Delete a memory
Args:
- content: The content to extract and process into a memory. This can be a URL to a
- website, a PDF, an image, or a video.
-
- Plaintext: Any plaintext format
-
- URL: A URL to a website, PDF, image, or video
-
- We automatically detect the content type from the url's response format.
-
- metadata: Optional metadata for the memory. This is used to store additional information
- about the memory. You can use this to store any additional information you need
- about the memory. Metadata can be filtered through. Keys must be strings and are
- case sensitive. Values can be strings, numbers, or booleans. You cannot nest
- objects.
-
- user_id: Optional end user ID this memory belongs to. This is used to group memories by
- user. You should use the same ID stored in your external system where the user
- is stored
-
extra_headers: Send extra headers
extra_query: Add additional query parameters to the request
@@ -301,52 +230,31 @@ async def create(
timeout: Override the client-level default timeout for this request, in seconds
"""
- return await self._post(
- "/add",
- body=await async_maybe_transform(
- {
- "content": content,
- "id": id,
- "metadata": metadata,
- "user_id": user_id,
- },
- memory_create_params.MemoryCreateParams,
- ),
+ if not id:
+ raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
+ return await self._delete(
+ f"/v3/memories/{id}",
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
- cast_to=MemoryCreateResponse,
+ cast_to=MemoryListResponse,
)
- async def list(
+ async def delete(
self,
+ id: str,
*,
- filters: str | NotGiven = NOT_GIVEN,
- limit: str | NotGiven = NOT_GIVEN,
- order: Literal["asc", "desc"] | NotGiven = NOT_GIVEN,
- page: str | NotGiven = NOT_GIVEN,
- sort: Literal["createdAt", "updatedAt"] | NotGiven = NOT_GIVEN,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
# The extra values given here take precedence over values defined on the client or passed to this method.
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
- ) -> MemoryListResponse:
+ ) -> MemoryDeleteResponse:
"""
- Retrieves a paginated list of memories with their metadata and workflow status
+ Get a memory by ID
Args:
- filters: Optional filters to apply to the search
-
- limit: Number of items per page
-
- order: Sort order
-
- page: Page number to fetch
-
- sort: Field to sort by
-
extra_headers: Send extra headers
extra_query: Add additional query parameters to the request
@@ -355,40 +263,31 @@ async def list(
timeout: Override the client-level default timeout for this request, in seconds
"""
+ if not id:
+ raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return await self._get(
- "/memories",
+ f"/v3/memories/{id}",
options=make_request_options(
- extra_headers=extra_headers,
- extra_query=extra_query,
- extra_body=extra_body,
- timeout=timeout,
- query=await async_maybe_transform(
- {
- "filters": filters,
- "limit": limit,
- "order": order,
- "page": page,
- "sort": sort,
- },
- memory_list_params.MemoryListParams,
- ),
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
- cast_to=MemoryListResponse,
+ cast_to=MemoryDeleteResponse,
)
- async def delete(
+ async def add(
self,
- id: str,
*,
+ content: str,
+ container_tags: List[str] | NotGiven = NOT_GIVEN,
+ metadata: Dict[str, Union[str, float, bool]] | NotGiven = NOT_GIVEN,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
# The extra values given here take precedence over values defined on the client or passed to this method.
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
- ) -> MemoryDeleteResponse:
+ ) -> MemoryAddResponse:
"""
- Delete a memory
+ Add a memory with any content type (text, url, file, etc.) and metadata
Args:
extra_headers: Send extra headers
@@ -399,14 +298,20 @@ async def delete(
timeout: Override the client-level default timeout for this request, in seconds
"""
- if not id:
- raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
- return await self._delete(
- f"/delete/{id}",
+ return await self._post(
+ "/v3/memories",
+ body=await async_maybe_transform(
+ {
+ "content": content,
+ "container_tags": container_tags,
+ "metadata": metadata,
+ },
+ memory_add_params.MemoryAddParams,
+ ),
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
- cast_to=MemoryDeleteResponse,
+ cast_to=MemoryAddResponse,
)
async def get(
@@ -435,7 +340,7 @@ async def get(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return await self._get(
- f"/memory/{id}",
+ f"/v3/memories/{id}",
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
@@ -443,73 +348,73 @@ async def get(
)
-class MemoryResourceWithRawResponse:
- def __init__(self, memory: MemoryResource) -> None:
- self._memory = memory
+class MemoriesResourceWithRawResponse:
+ def __init__(self, memories: MemoriesResource) -> None:
+ self._memories = memories
- self.create = to_raw_response_wrapper(
- memory.create,
- )
self.list = to_raw_response_wrapper(
- memory.list,
+ memories.list,
)
self.delete = to_raw_response_wrapper(
- memory.delete,
+ memories.delete,
+ )
+ self.add = to_raw_response_wrapper(
+ memories.add,
)
self.get = to_raw_response_wrapper(
- memory.get,
+ memories.get,
)
-class AsyncMemoryResourceWithRawResponse:
- def __init__(self, memory: AsyncMemoryResource) -> None:
- self._memory = memory
+class AsyncMemoriesResourceWithRawResponse:
+ def __init__(self, memories: AsyncMemoriesResource) -> None:
+ self._memories = memories
- self.create = async_to_raw_response_wrapper(
- memory.create,
- )
self.list = async_to_raw_response_wrapper(
- memory.list,
+ memories.list,
)
self.delete = async_to_raw_response_wrapper(
- memory.delete,
+ memories.delete,
+ )
+ self.add = async_to_raw_response_wrapper(
+ memories.add,
)
self.get = async_to_raw_response_wrapper(
- memory.get,
+ memories.get,
)
-class MemoryResourceWithStreamingResponse:
- def __init__(self, memory: MemoryResource) -> None:
- self._memory = memory
+class MemoriesResourceWithStreamingResponse:
+ def __init__(self, memories: MemoriesResource) -> None:
+ self._memories = memories
- self.create = to_streamed_response_wrapper(
- memory.create,
- )
self.list = to_streamed_response_wrapper(
- memory.list,
+ memories.list,
)
self.delete = to_streamed_response_wrapper(
- memory.delete,
+ memories.delete,
+ )
+ self.add = to_streamed_response_wrapper(
+ memories.add,
)
self.get = to_streamed_response_wrapper(
- memory.get,
+ memories.get,
)
-class AsyncMemoryResourceWithStreamingResponse:
- def __init__(self, memory: AsyncMemoryResource) -> None:
- self._memory = memory
+class AsyncMemoriesResourceWithStreamingResponse:
+ def __init__(self, memories: AsyncMemoriesResource) -> None:
+ self._memories = memories
- self.create = async_to_streamed_response_wrapper(
- memory.create,
- )
self.list = async_to_streamed_response_wrapper(
- memory.list,
+ memories.list,
)
self.delete = async_to_streamed_response_wrapper(
- memory.delete,
+ memories.delete,
+ )
+ self.add = async_to_streamed_response_wrapper(
+ memories.add,
)
self.get = async_to_streamed_response_wrapper(
- memory.get,
+ memories.get,
)
diff --git a/src/supermemory/resources/search.py b/src/supermemory/resources/search.py
deleted file mode 100644
index c6d8395a..00000000
--- a/src/supermemory/resources/search.py
+++ /dev/null
@@ -1,290 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from __future__ import annotations
-
-from typing import List
-from typing_extensions import Literal
-
-import httpx
-
-from ..types import search_execute_params
-from .._types import NOT_GIVEN, Body, Query, Headers, NotGiven
-from .._utils import maybe_transform, async_maybe_transform
-from .._compat import cached_property
-from .._resource import SyncAPIResource, AsyncAPIResource
-from .._response import (
- to_raw_response_wrapper,
- to_streamed_response_wrapper,
- async_to_raw_response_wrapper,
- async_to_streamed_response_wrapper,
-)
-from .._base_client import make_request_options
-from ..types.search_execute_response import SearchExecuteResponse
-
-__all__ = ["SearchResource", "AsyncSearchResource"]
-
-
-class SearchResource(SyncAPIResource):
- @cached_property
- def with_raw_response(self) -> SearchResourceWithRawResponse:
- """
- This property can be used as a prefix for any HTTP method call to return
- the raw response object instead of the parsed content.
-
- For more information, see https://www.github.com/supermemoryai/python-sdk#accessing-raw-response-data-eg-headers
- """
- return SearchResourceWithRawResponse(self)
-
- @cached_property
- def with_streaming_response(self) -> SearchResourceWithStreamingResponse:
- """
- An alternative to `.with_raw_response` that doesn't eagerly read the response body.
-
- For more information, see https://www.github.com/supermemoryai/python-sdk#with_streaming_response
- """
- return SearchResourceWithStreamingResponse(self)
-
- def execute(
- self,
- *,
- q: str,
- categories_filter: List[Literal["technology", "science", "business", "health"]] | NotGiven = NOT_GIVEN,
- chunk_threshold: float | NotGiven = NOT_GIVEN,
- doc_id: str | NotGiven = NOT_GIVEN,
- document_threshold: float | NotGiven = NOT_GIVEN,
- filters: search_execute_params.Filters | NotGiven = NOT_GIVEN,
- include_summary: bool | NotGiven = NOT_GIVEN,
- limit: int | NotGiven = NOT_GIVEN,
- only_matching_chunks: bool | NotGiven = NOT_GIVEN,
- rerank: bool | NotGiven = NOT_GIVEN,
- rewrite_query: bool | NotGiven = NOT_GIVEN,
- user_id: str | NotGiven = NOT_GIVEN,
- # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
- # The extra values given here take precedence over values defined on the client or passed to this method.
- extra_headers: Headers | None = None,
- extra_query: Query | None = None,
- extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
- ) -> SearchExecuteResponse:
- """
- Search through documents with filtering
-
- Args:
- q: Search query string
-
- categories_filter: Optional category filters
-
- chunk_threshold: Threshold / sensitivity for chunk selection. 0 is least sensitive (returns most
- chunks, more results), 1 is most sensitive (returns lesser chunks, accurate
- results)
-
- doc_id: Optional document ID to search within. You can use this to find chunks in a very
- large document.
-
- document_threshold: Threshold / sensitivity for document selection. 0 is least sensitive (returns
- most documents, more results), 1 is most sensitive (returns lesser documents,
- accurate results)
-
- filters: Optional filters to apply to the search
-
- include_summary: If true, include document summary in the response. This is helpful if you want a
- chatbot to know the full context of the document.
-
- limit: Maximum number of results to return
-
- only_matching_chunks: If true, only return matching chunks without context. Normally, we send the
- previous and next chunk to provide more context for LLMs. If you only want the
- matching chunk, set this to true.
-
- rerank: If true, rerank the results based on the query. This is helpful if you want to
- ensure the most relevant results are returned.
-
- rewrite_query: If true, rewrites the query to make it easier to find documents. This increases
- the latency by about 400ms
-
- user_id: End user ID this search is associated with. NOTE: This also acts as a filter for
- the search.
-
- extra_headers: Send extra headers
-
- extra_query: Add additional query parameters to the request
-
- extra_body: Add additional JSON properties to the request
-
- timeout: Override the client-level default timeout for this request, in seconds
- """
- return self._post(
- "/search",
- body=maybe_transform(
- {
- "q": q,
- "categories_filter": categories_filter,
- "chunk_threshold": chunk_threshold,
- "doc_id": doc_id,
- "document_threshold": document_threshold,
- "filters": filters,
- "include_summary": include_summary,
- "limit": limit,
- "only_matching_chunks": only_matching_chunks,
- "rerank": rerank,
- "rewrite_query": rewrite_query,
- "user_id": user_id,
- },
- search_execute_params.SearchExecuteParams,
- ),
- options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
- ),
- cast_to=SearchExecuteResponse,
- )
-
-
-class AsyncSearchResource(AsyncAPIResource):
- @cached_property
- def with_raw_response(self) -> AsyncSearchResourceWithRawResponse:
- """
- This property can be used as a prefix for any HTTP method call to return
- the raw response object instead of the parsed content.
-
- For more information, see https://www.github.com/supermemoryai/python-sdk#accessing-raw-response-data-eg-headers
- """
- return AsyncSearchResourceWithRawResponse(self)
-
- @cached_property
- def with_streaming_response(self) -> AsyncSearchResourceWithStreamingResponse:
- """
- An alternative to `.with_raw_response` that doesn't eagerly read the response body.
-
- For more information, see https://www.github.com/supermemoryai/python-sdk#with_streaming_response
- """
- return AsyncSearchResourceWithStreamingResponse(self)
-
- async def execute(
- self,
- *,
- q: str,
- categories_filter: List[Literal["technology", "science", "business", "health"]] | NotGiven = NOT_GIVEN,
- chunk_threshold: float | NotGiven = NOT_GIVEN,
- doc_id: str | NotGiven = NOT_GIVEN,
- document_threshold: float | NotGiven = NOT_GIVEN,
- filters: search_execute_params.Filters | NotGiven = NOT_GIVEN,
- include_summary: bool | NotGiven = NOT_GIVEN,
- limit: int | NotGiven = NOT_GIVEN,
- only_matching_chunks: bool | NotGiven = NOT_GIVEN,
- rerank: bool | NotGiven = NOT_GIVEN,
- rewrite_query: bool | NotGiven = NOT_GIVEN,
- user_id: str | NotGiven = NOT_GIVEN,
- # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
- # The extra values given here take precedence over values defined on the client or passed to this method.
- extra_headers: Headers | None = None,
- extra_query: Query | None = None,
- extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
- ) -> SearchExecuteResponse:
- """
- Search through documents with filtering
-
- Args:
- q: Search query string
-
- categories_filter: Optional category filters
-
- chunk_threshold: Threshold / sensitivity for chunk selection. 0 is least sensitive (returns most
- chunks, more results), 1 is most sensitive (returns lesser chunks, accurate
- results)
-
- doc_id: Optional document ID to search within. You can use this to find chunks in a very
- large document.
-
- document_threshold: Threshold / sensitivity for document selection. 0 is least sensitive (returns
- most documents, more results), 1 is most sensitive (returns lesser documents,
- accurate results)
-
- filters: Optional filters to apply to the search
-
- include_summary: If true, include document summary in the response. This is helpful if you want a
- chatbot to know the full context of the document.
-
- limit: Maximum number of results to return
-
- only_matching_chunks: If true, only return matching chunks without context. Normally, we send the
- previous and next chunk to provide more context for LLMs. If you only want the
- matching chunk, set this to true.
-
- rerank: If true, rerank the results based on the query. This is helpful if you want to
- ensure the most relevant results are returned.
-
- rewrite_query: If true, rewrites the query to make it easier to find documents. This increases
- the latency by about 400ms
-
- user_id: End user ID this search is associated with. NOTE: This also acts as a filter for
- the search.
-
- extra_headers: Send extra headers
-
- extra_query: Add additional query parameters to the request
-
- extra_body: Add additional JSON properties to the request
-
- timeout: Override the client-level default timeout for this request, in seconds
- """
- return await self._post(
- "/search",
- body=await async_maybe_transform(
- {
- "q": q,
- "categories_filter": categories_filter,
- "chunk_threshold": chunk_threshold,
- "doc_id": doc_id,
- "document_threshold": document_threshold,
- "filters": filters,
- "include_summary": include_summary,
- "limit": limit,
- "only_matching_chunks": only_matching_chunks,
- "rerank": rerank,
- "rewrite_query": rewrite_query,
- "user_id": user_id,
- },
- search_execute_params.SearchExecuteParams,
- ),
- options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
- ),
- cast_to=SearchExecuteResponse,
- )
-
-
-class SearchResourceWithRawResponse:
- def __init__(self, search: SearchResource) -> None:
- self._search = search
-
- self.execute = to_raw_response_wrapper(
- search.execute,
- )
-
-
-class AsyncSearchResourceWithRawResponse:
- def __init__(self, search: AsyncSearchResource) -> None:
- self._search = search
-
- self.execute = async_to_raw_response_wrapper(
- search.execute,
- )
-
-
-class SearchResourceWithStreamingResponse:
- def __init__(self, search: SearchResource) -> None:
- self._search = search
-
- self.execute = to_streamed_response_wrapper(
- search.execute,
- )
-
-
-class AsyncSearchResourceWithStreamingResponse:
- def __init__(self, search: AsyncSearchResource) -> None:
- self._search = search
-
- self.execute = async_to_streamed_response_wrapper(
- search.execute,
- )
diff --git a/src/supermemory/resources/settings.py b/src/supermemory/resources/settings.py
index 63b3604e..33a331fa 100644
--- a/src/supermemory/resources/settings.py
+++ b/src/supermemory/resources/settings.py
@@ -2,7 +2,7 @@
from __future__ import annotations
-from typing import List, Iterable
+from typing import Dict, List
import httpx
@@ -18,6 +18,7 @@
async_to_streamed_response_wrapper,
)
from .._base_client import make_request_options
+from ..types.setting_get_response import SettingGetResponse
from ..types.setting_update_response import SettingUpdateResponse
__all__ = ["SettingsResource", "AsyncSettingsResource"]
@@ -46,10 +47,9 @@ def with_streaming_response(self) -> SettingsResourceWithStreamingResponse:
def update(
self,
*,
- categories: List[str] | NotGiven = NOT_GIVEN,
exclude_items: List[str] | NotGiven = NOT_GIVEN,
filter_prompt: str | NotGiven = NOT_GIVEN,
- filter_tags: Iterable[setting_update_params.FilterTag] | NotGiven = NOT_GIVEN,
+ filter_tags: Dict[str, List[str]] | NotGiven = NOT_GIVEN,
include_items: List[str] | NotGiven = NOT_GIVEN,
should_llm_filter: bool | NotGiven = NOT_GIVEN,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
@@ -71,11 +71,10 @@ def update(
timeout: Override the client-level default timeout for this request, in seconds
"""
- return self._put(
- "/settings",
+ return self._patch(
+ "/v3/settings",
body=maybe_transform(
{
- "categories": categories,
"exclude_items": exclude_items,
"filter_prompt": filter_prompt,
"filter_tags": filter_tags,
@@ -90,6 +89,25 @@ def update(
cast_to=SettingUpdateResponse,
)
+ def get(
+ self,
+ *,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+ ) -> SettingGetResponse:
+ """Get settings for an organization"""
+ return self._get(
+ "/v3/settings",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=SettingGetResponse,
+ )
+
class AsyncSettingsResource(AsyncAPIResource):
@cached_property
@@ -114,10 +132,9 @@ def with_streaming_response(self) -> AsyncSettingsResourceWithStreamingResponse:
async def update(
self,
*,
- categories: List[str] | NotGiven = NOT_GIVEN,
exclude_items: List[str] | NotGiven = NOT_GIVEN,
filter_prompt: str | NotGiven = NOT_GIVEN,
- filter_tags: Iterable[setting_update_params.FilterTag] | NotGiven = NOT_GIVEN,
+ filter_tags: Dict[str, List[str]] | NotGiven = NOT_GIVEN,
include_items: List[str] | NotGiven = NOT_GIVEN,
should_llm_filter: bool | NotGiven = NOT_GIVEN,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
@@ -139,11 +156,10 @@ async def update(
timeout: Override the client-level default timeout for this request, in seconds
"""
- return await self._put(
- "/settings",
+ return await self._patch(
+ "/v3/settings",
body=await async_maybe_transform(
{
- "categories": categories,
"exclude_items": exclude_items,
"filter_prompt": filter_prompt,
"filter_tags": filter_tags,
@@ -158,6 +174,25 @@ async def update(
cast_to=SettingUpdateResponse,
)
+ async def get(
+ self,
+ *,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+ ) -> SettingGetResponse:
+ """Get settings for an organization"""
+ return await self._get(
+ "/v3/settings",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=SettingGetResponse,
+ )
+
class SettingsResourceWithRawResponse:
def __init__(self, settings: SettingsResource) -> None:
@@ -166,6 +201,9 @@ def __init__(self, settings: SettingsResource) -> None:
self.update = to_raw_response_wrapper(
settings.update,
)
+ self.get = to_raw_response_wrapper(
+ settings.get,
+ )
class AsyncSettingsResourceWithRawResponse:
@@ -175,6 +213,9 @@ def __init__(self, settings: AsyncSettingsResource) -> None:
self.update = async_to_raw_response_wrapper(
settings.update,
)
+ self.get = async_to_raw_response_wrapper(
+ settings.get,
+ )
class SettingsResourceWithStreamingResponse:
@@ -184,6 +225,9 @@ def __init__(self, settings: SettingsResource) -> None:
self.update = to_streamed_response_wrapper(
settings.update,
)
+ self.get = to_streamed_response_wrapper(
+ settings.get,
+ )
class AsyncSettingsResourceWithStreamingResponse:
@@ -193,3 +237,6 @@ def __init__(self, settings: AsyncSettingsResource) -> None:
self.update = async_to_streamed_response_wrapper(
settings.update,
)
+ self.get = async_to_streamed_response_wrapper(
+ settings.get,
+ )
diff --git a/src/supermemory/types/__init__.py b/src/supermemory/types/__init__.py
index 675c5525..c7f47386 100644
--- a/src/supermemory/types/__init__.py
+++ b/src/supermemory/types/__init__.py
@@ -2,15 +2,14 @@
from __future__ import annotations
-from .memory_list_params import MemoryListParams as MemoryListParams
+from .memory_add_params import MemoryAddParams as MemoryAddParams
+from .memory_add_response import MemoryAddResponse as MemoryAddResponse
from .memory_get_response import MemoryGetResponse as MemoryGetResponse
-from .memory_create_params import MemoryCreateParams as MemoryCreateParams
from .memory_list_response import MemoryListResponse as MemoryListResponse
-from .search_execute_params import SearchExecuteParams as SearchExecuteParams
+from .setting_get_response import SettingGetResponse as SettingGetResponse
from .setting_update_params import SettingUpdateParams as SettingUpdateParams
-from .memory_create_response import MemoryCreateResponse as MemoryCreateResponse
from .memory_delete_response import MemoryDeleteResponse as MemoryDeleteResponse
-from .search_execute_response import SearchExecuteResponse as SearchExecuteResponse
+from .connection_get_response import ConnectionGetResponse as ConnectionGetResponse
from .setting_update_response import SettingUpdateResponse as SettingUpdateResponse
-from .connection_create_params import ConnectionCreateParams as ConnectionCreateParams
+from .connection_list_response import ConnectionListResponse as ConnectionListResponse
from .connection_create_response import ConnectionCreateResponse as ConnectionCreateResponse
diff --git a/src/supermemory/types/connection_create_params.py b/src/supermemory/types/connection_create_params.py
deleted file mode 100644
index 4bb84cba..00000000
--- a/src/supermemory/types/connection_create_params.py
+++ /dev/null
@@ -1,15 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from __future__ import annotations
-
-from typing_extensions import Required, Annotated, TypedDict
-
-from .._utils import PropertyInfo
-
-__all__ = ["ConnectionCreateParams"]
-
-
-class ConnectionCreateParams(TypedDict, total=False):
- id: Required[str]
-
- redirect_url: Annotated[str, PropertyInfo(alias="redirectUrl")]
diff --git a/src/supermemory/types/connection_get_response.py b/src/supermemory/types/connection_get_response.py
new file mode 100644
index 00000000..8f3be8de
--- /dev/null
+++ b/src/supermemory/types/connection_get_response.py
@@ -0,0 +1,21 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Dict, Optional
+
+from pydantic import Field as FieldInfo
+
+from .._models import BaseModel
+
+__all__ = ["ConnectionGetResponse"]
+
+
+class ConnectionGetResponse(BaseModel):
+ id: str
+
+ created_at: float = FieldInfo(alias="createdAt")
+
+ provider: str
+
+ expires_at: Optional[float] = FieldInfo(alias="expiresAt", default=None)
+
+ metadata: Optional[Dict[str, object]] = None
diff --git a/src/supermemory/types/connection_list_response.py b/src/supermemory/types/connection_list_response.py
new file mode 100644
index 00000000..f68e38b8
--- /dev/null
+++ b/src/supermemory/types/connection_list_response.py
@@ -0,0 +1,25 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Dict, List, Optional
+from typing_extensions import TypeAlias
+
+from pydantic import Field as FieldInfo
+
+from .._models import BaseModel
+
+__all__ = ["ConnectionListResponse", "ConnectionListResponseItem"]
+
+
+class ConnectionListResponseItem(BaseModel):
+ id: str
+
+ created_at: float = FieldInfo(alias="createdAt")
+
+ provider: str
+
+ expires_at: Optional[float] = FieldInfo(alias="expiresAt", default=None)
+
+ metadata: Optional[Dict[str, object]] = None
+
+
+ConnectionListResponse: TypeAlias = List[ConnectionListResponseItem]
diff --git a/src/supermemory/types/memory_add_params.py b/src/supermemory/types/memory_add_params.py
new file mode 100644
index 00000000..a973e952
--- /dev/null
+++ b/src/supermemory/types/memory_add_params.py
@@ -0,0 +1,18 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Dict, List, Union
+from typing_extensions import Required, Annotated, TypedDict
+
+from .._utils import PropertyInfo
+
+__all__ = ["MemoryAddParams"]
+
+
+class MemoryAddParams(TypedDict, total=False):
+ content: Required[str]
+
+ container_tags: Annotated[List[str], PropertyInfo(alias="containerTags")]
+
+ metadata: Dict[str, Union[str, float, bool]]
diff --git a/src/supermemory/types/memory_create_response.py b/src/supermemory/types/memory_add_response.py
similarity index 67%
rename from src/supermemory/types/memory_create_response.py
rename to src/supermemory/types/memory_add_response.py
index 11751fe3..704918e4 100644
--- a/src/supermemory/types/memory_create_response.py
+++ b/src/supermemory/types/memory_add_response.py
@@ -2,10 +2,10 @@
from .._models import BaseModel
-__all__ = ["MemoryCreateResponse"]
+__all__ = ["MemoryAddResponse"]
-class MemoryCreateResponse(BaseModel):
+class MemoryAddResponse(BaseModel):
id: str
status: str
diff --git a/src/supermemory/types/memory_create_params.py b/src/supermemory/types/memory_create_params.py
deleted file mode 100644
index 938ba8e0..00000000
--- a/src/supermemory/types/memory_create_params.py
+++ /dev/null
@@ -1,42 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from __future__ import annotations
-
-from typing import Dict, Union
-from typing_extensions import Required, Annotated, TypedDict
-
-from .._utils import PropertyInfo
-
-__all__ = ["MemoryCreateParams"]
-
-
-class MemoryCreateParams(TypedDict, total=False):
- content: Required[str]
- """The content to extract and process into a memory.
-
- This can be a URL to a website, a PDF, an image, or a video.
-
- Plaintext: Any plaintext format
-
- URL: A URL to a website, PDF, image, or video
-
- We automatically detect the content type from the url's response format.
- """
-
- id: str
-
- metadata: Dict[str, Union[str, float, bool]]
- """Optional metadata for the memory.
-
- This is used to store additional information about the memory. You can use this
- to store any additional information you need about the memory. Metadata can be
- filtered through. Keys must be strings and are case sensitive. Values can be
- strings, numbers, or booleans. You cannot nest objects.
- """
-
- user_id: Annotated[str, PropertyInfo(alias="userId")]
- """Optional end user ID this memory belongs to.
-
- This is used to group memories by user. You should use the same ID stored in
- your external system where the user is stored
- """
diff --git a/src/supermemory/types/memory_delete_response.py b/src/supermemory/types/memory_delete_response.py
index 0f17a7e1..fe31c22e 100644
--- a/src/supermemory/types/memory_delete_response.py
+++ b/src/supermemory/types/memory_delete_response.py
@@ -6,4 +6,6 @@
class MemoryDeleteResponse(BaseModel):
- success: bool
+ id: str
+
+ status: str
diff --git a/src/supermemory/types/memory_get_response.py b/src/supermemory/types/memory_get_response.py
index a2f008e6..4d115240 100644
--- a/src/supermemory/types/memory_get_response.py
+++ b/src/supermemory/types/memory_get_response.py
@@ -1,36 +1,11 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-from typing import Dict, Optional
-from datetime import datetime
-from typing_extensions import Literal
-
-from pydantic import Field as FieldInfo
-
from .._models import BaseModel
-__all__ = ["MemoryGetResponse", "Doc"]
-
-
-class Doc(BaseModel):
- created_at: datetime = FieldInfo(alias="createdAt")
- """Timestamp when the memory was created"""
-
- updated_at: datetime = FieldInfo(alias="updatedAt")
- """Timestamp when the memory was last updated"""
-
- metadata: Optional[Dict[str, object]] = None
- """Custom metadata associated with the memory"""
-
- summary: Optional[str] = None
- """Summary of the memory content"""
-
- title: Optional[str] = None
- """Title of the memory"""
+__all__ = ["MemoryGetResponse"]
class MemoryGetResponse(BaseModel):
- doc: Doc
- """Memory document details"""
+ id: str
- status: Optional[Literal["queued", "extracting", "chunking", "embedding", "indexing", "done", "failed"]] = None
- """Current processing status of the memory"""
+ status: str
diff --git a/src/supermemory/types/memory_list_params.py b/src/supermemory/types/memory_list_params.py
deleted file mode 100644
index d40690da..00000000
--- a/src/supermemory/types/memory_list_params.py
+++ /dev/null
@@ -1,24 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from __future__ import annotations
-
-from typing_extensions import Literal, TypedDict
-
-__all__ = ["MemoryListParams"]
-
-
-class MemoryListParams(TypedDict, total=False):
- filters: str
- """Optional filters to apply to the search"""
-
- limit: str
- """Number of items per page"""
-
- order: Literal["asc", "desc"]
- """Sort order"""
-
- page: str
- """Page number to fetch"""
-
- sort: Literal["createdAt", "updatedAt"]
- """Field to sort by"""
diff --git a/src/supermemory/types/memory_list_response.py b/src/supermemory/types/memory_list_response.py
index 06fff6b5..0fecfe23 100644
--- a/src/supermemory/types/memory_list_response.py
+++ b/src/supermemory/types/memory_list_response.py
@@ -1,60 +1,9 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-from typing import Dict, List, Optional
-from datetime import datetime
-from typing_extensions import Literal
-
-from pydantic import Field as FieldInfo
-
from .._models import BaseModel
-__all__ = ["MemoryListResponse", "Memory", "Pagination"]
-
-
-class Memory(BaseModel):
- id: str
- """Unique identifier of the memory.
-
- This is your user's id in your system or database.
- """
-
- content: Optional[str] = None
- """Content of the memory"""
-
- created_at: datetime = FieldInfo(alias="createdAt")
- """Creation timestamp"""
-
- metadata: Dict[str, object]
- """Custom metadata associated with the memory"""
-
- status: Optional[Literal["queued", "extracting", "chunking", "embedding", "indexing", "done", "failed"]] = None
- """Processing status of the memory"""
-
- summary: Optional[str] = None
- """Summary of the memory content"""
-
- title: str
- """Title of the memory"""
-
- updated_at: datetime = FieldInfo(alias="updatedAt")
- """Last update timestamp"""
-
- url: Optional[str] = None
- """Source URL of the memory"""
-
-
-class Pagination(BaseModel):
- current_page: float = FieldInfo(alias="currentPage")
-
- limit: float
-
- total_items: float = FieldInfo(alias="totalItems")
-
- total_pages: float = FieldInfo(alias="totalPages")
+__all__ = ["MemoryListResponse"]
class MemoryListResponse(BaseModel):
- memories: List[Memory]
-
- pagination: Pagination
- """Pagination metadata"""
+ success: bool
diff --git a/src/supermemory/types/search_execute_params.py b/src/supermemory/types/search_execute_params.py
deleted file mode 100644
index bc3b4756..00000000
--- a/src/supermemory/types/search_execute_params.py
+++ /dev/null
@@ -1,86 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from __future__ import annotations
-
-from typing import Dict, List, Union, Iterable
-from typing_extensions import Literal, Required, Annotated, TypeAlias, TypedDict
-
-from .._utils import PropertyInfo
-
-__all__ = ["SearchExecuteParams", "Filters", "FiltersUnionMember0"]
-
-
-class SearchExecuteParams(TypedDict, total=False):
- q: Required[str]
- """Search query string"""
-
- categories_filter: Annotated[
- List[Literal["technology", "science", "business", "health"]], PropertyInfo(alias="categoriesFilter")
- ]
- """Optional category filters"""
-
- chunk_threshold: Annotated[float, PropertyInfo(alias="chunkThreshold")]
- """Threshold / sensitivity for chunk selection.
-
- 0 is least sensitive (returns most chunks, more results), 1 is most sensitive
- (returns lesser chunks, accurate results)
- """
-
- doc_id: Annotated[str, PropertyInfo(alias="docId")]
- """Optional document ID to search within.
-
- You can use this to find chunks in a very large document.
- """
-
- document_threshold: Annotated[float, PropertyInfo(alias="documentThreshold")]
- """Threshold / sensitivity for document selection.
-
- 0 is least sensitive (returns most documents, more results), 1 is most sensitive
- (returns lesser documents, accurate results)
- """
-
- filters: Filters
- """Optional filters to apply to the search"""
-
- include_summary: Annotated[bool, PropertyInfo(alias="includeSummary")]
- """If true, include document summary in the response.
-
- This is helpful if you want a chatbot to know the full context of the document.
- """
-
- limit: int
- """Maximum number of results to return"""
-
- only_matching_chunks: Annotated[bool, PropertyInfo(alias="onlyMatchingChunks")]
- """If true, only return matching chunks without context.
-
- Normally, we send the previous and next chunk to provide more context for LLMs.
- If you only want the matching chunk, set this to true.
- """
-
- rerank: bool
- """If true, rerank the results based on the query.
-
- This is helpful if you want to ensure the most relevant results are returned.
- """
-
- rewrite_query: Annotated[bool, PropertyInfo(alias="rewriteQuery")]
- """If true, rewrites the query to make it easier to find documents.
-
- This increases the latency by about 400ms
- """
-
- user_id: Annotated[str, PropertyInfo(alias="userId")]
- """End user ID this search is associated with.
-
- NOTE: This also acts as a filter for the search.
- """
-
-
-class FiltersUnionMember0(TypedDict, total=False):
- and_: Annotated[Iterable[object], PropertyInfo(alias="AND")]
-
- or_: Annotated[Iterable[object], PropertyInfo(alias="OR")]
-
-
-Filters: TypeAlias = Union[FiltersUnionMember0, Dict[str, object]]
diff --git a/src/supermemory/types/search_execute_response.py b/src/supermemory/types/search_execute_response.py
deleted file mode 100644
index 5b2bc4e0..00000000
--- a/src/supermemory/types/search_execute_response.py
+++ /dev/null
@@ -1,52 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from typing import Dict, List, Optional
-from datetime import datetime
-
-from pydantic import Field as FieldInfo
-
-from .._models import BaseModel
-
-__all__ = ["SearchExecuteResponse", "Result", "ResultChunk"]
-
-
-class ResultChunk(BaseModel):
- content: str
- """Content of the matching chunk"""
-
- is_relevant: bool = FieldInfo(alias="isRelevant")
- """Whether this chunk is relevant to the query"""
-
- score: float
- """Similarity score for this chunk"""
-
-
-class Result(BaseModel):
- chunks: List[ResultChunk]
- """Matching content chunks from the document"""
-
- created_at: datetime = FieldInfo(alias="createdAt")
- """Document creation date"""
-
- document_id: str = FieldInfo(alias="documentId")
- """ID of the matching document"""
-
- metadata: Optional[Dict[str, object]] = None
- """Document metadata"""
-
- score: float
- """Relevance score of the match"""
-
- title: str
- """Document title"""
-
- updated_at: datetime = FieldInfo(alias="updatedAt")
- """Document last update date"""
-
-
-class SearchExecuteResponse(BaseModel):
- results: List[Result]
-
- timing: float
-
- total: float
diff --git a/src/supermemory/types/setting_get_response.py b/src/supermemory/types/setting_get_response.py
new file mode 100644
index 00000000..0cf25fd9
--- /dev/null
+++ b/src/supermemory/types/setting_get_response.py
@@ -0,0 +1,11 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Dict
+
+from .._models import BaseModel
+
+__all__ = ["SettingGetResponse"]
+
+
+class SettingGetResponse(BaseModel):
+ settings: Dict[str, object]
diff --git a/src/supermemory/types/setting_update_params.py b/src/supermemory/types/setting_update_params.py
index 16775c4c..8f19a083 100644
--- a/src/supermemory/types/setting_update_params.py
+++ b/src/supermemory/types/setting_update_params.py
@@ -2,29 +2,21 @@
from __future__ import annotations
-from typing import List, Iterable
-from typing_extensions import Required, Annotated, TypedDict
+from typing import Dict, List
+from typing_extensions import Annotated, TypedDict
from .._utils import PropertyInfo
-__all__ = ["SettingUpdateParams", "FilterTag"]
+__all__ = ["SettingUpdateParams"]
class SettingUpdateParams(TypedDict, total=False):
- categories: List[str]
-
exclude_items: Annotated[List[str], PropertyInfo(alias="excludeItems")]
filter_prompt: Annotated[str, PropertyInfo(alias="filterPrompt")]
- filter_tags: Annotated[Iterable[FilterTag], PropertyInfo(alias="filterTags")]
+ filter_tags: Annotated[Dict[str, List[str]], PropertyInfo(alias="filterTags")]
include_items: Annotated[List[str], PropertyInfo(alias="includeItems")]
should_llm_filter: Annotated[bool, PropertyInfo(alias="shouldLLMFilter")]
-
-
-class FilterTag(TypedDict, total=False):
- score: Required[float]
-
- tag: Required[str]
diff --git a/src/supermemory/types/setting_update_response.py b/src/supermemory/types/setting_update_response.py
index 064e3a61..58a717c0 100644
--- a/src/supermemory/types/setting_update_response.py
+++ b/src/supermemory/types/setting_update_response.py
@@ -1,28 +1,20 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-from typing import List, Optional
+from typing import Dict, List, Optional
from pydantic import Field as FieldInfo
from .._models import BaseModel
-__all__ = ["SettingUpdateResponse", "Settings", "SettingsFilterTag"]
-
-
-class SettingsFilterTag(BaseModel):
- score: float
-
- tag: str
+__all__ = ["SettingUpdateResponse", "Settings"]
class Settings(BaseModel):
- categories: Optional[List[str]] = None
-
exclude_items: Optional[List[str]] = FieldInfo(alias="excludeItems", default=None)
filter_prompt: Optional[str] = FieldInfo(alias="filterPrompt", default=None)
- filter_tags: Optional[List[SettingsFilterTag]] = FieldInfo(alias="filterTags", default=None)
+ filter_tags: Optional[Dict[str, List[str]]] = FieldInfo(alias="filterTags", default=None)
include_items: Optional[List[str]] = FieldInfo(alias="includeItems", default=None)
diff --git a/tests/api_resources/test_connection.py b/tests/api_resources/test_connection.py
deleted file mode 100644
index cd9555e8..00000000
--- a/tests/api_resources/test_connection.py
+++ /dev/null
@@ -1,200 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from __future__ import annotations
-
-import os
-from typing import Any, cast
-
-import pytest
-
-from supermemory import Supermemory, AsyncSupermemory
-from tests.utils import assert_matches_type
-from supermemory.types import ConnectionCreateResponse
-
-base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
-
-
-class TestConnection:
- parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"])
-
- @pytest.mark.skip()
- @parametrize
- def test_method_create(self, client: Supermemory) -> None:
- connection = client.connection.create(
- app="notion",
- id="id",
- )
- assert_matches_type(ConnectionCreateResponse, connection, path=["response"])
-
- @pytest.mark.skip()
- @parametrize
- def test_method_create_with_all_params(self, client: Supermemory) -> None:
- connection = client.connection.create(
- app="notion",
- id="id",
- redirect_url="redirectUrl",
- )
- assert_matches_type(ConnectionCreateResponse, connection, path=["response"])
-
- @pytest.mark.skip()
- @parametrize
- def test_raw_response_create(self, client: Supermemory) -> None:
- response = client.connection.with_raw_response.create(
- app="notion",
- id="id",
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- connection = response.parse()
- assert_matches_type(ConnectionCreateResponse, connection, path=["response"])
-
- @pytest.mark.skip()
- @parametrize
- def test_streaming_response_create(self, client: Supermemory) -> None:
- with client.connection.with_streaming_response.create(
- app="notion",
- id="id",
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- connection = response.parse()
- assert_matches_type(ConnectionCreateResponse, connection, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip()
- @parametrize
- def test_method_retrieve(self, client: Supermemory) -> None:
- connection = client.connection.retrieve(
- "connectionId",
- )
- assert connection is None
-
- @pytest.mark.skip()
- @parametrize
- def test_raw_response_retrieve(self, client: Supermemory) -> None:
- response = client.connection.with_raw_response.retrieve(
- "connectionId",
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- connection = response.parse()
- assert connection is None
-
- @pytest.mark.skip()
- @parametrize
- def test_streaming_response_retrieve(self, client: Supermemory) -> None:
- with client.connection.with_streaming_response.retrieve(
- "connectionId",
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- connection = response.parse()
- assert connection is None
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip()
- @parametrize
- def test_path_params_retrieve(self, client: Supermemory) -> None:
- with pytest.raises(ValueError, match=r"Expected a non-empty value for `connection_id` but received ''"):
- client.connection.with_raw_response.retrieve(
- "",
- )
-
-
-class TestAsyncConnection:
- parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"])
-
- @pytest.mark.skip()
- @parametrize
- async def test_method_create(self, async_client: AsyncSupermemory) -> None:
- connection = await async_client.connection.create(
- app="notion",
- id="id",
- )
- assert_matches_type(ConnectionCreateResponse, connection, path=["response"])
-
- @pytest.mark.skip()
- @parametrize
- async def test_method_create_with_all_params(self, async_client: AsyncSupermemory) -> None:
- connection = await async_client.connection.create(
- app="notion",
- id="id",
- redirect_url="redirectUrl",
- )
- assert_matches_type(ConnectionCreateResponse, connection, path=["response"])
-
- @pytest.mark.skip()
- @parametrize
- async def test_raw_response_create(self, async_client: AsyncSupermemory) -> None:
- response = await async_client.connection.with_raw_response.create(
- app="notion",
- id="id",
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- connection = await response.parse()
- assert_matches_type(ConnectionCreateResponse, connection, path=["response"])
-
- @pytest.mark.skip()
- @parametrize
- async def test_streaming_response_create(self, async_client: AsyncSupermemory) -> None:
- async with async_client.connection.with_streaming_response.create(
- app="notion",
- id="id",
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- connection = await response.parse()
- assert_matches_type(ConnectionCreateResponse, connection, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip()
- @parametrize
- async def test_method_retrieve(self, async_client: AsyncSupermemory) -> None:
- connection = await async_client.connection.retrieve(
- "connectionId",
- )
- assert connection is None
-
- @pytest.mark.skip()
- @parametrize
- async def test_raw_response_retrieve(self, async_client: AsyncSupermemory) -> None:
- response = await async_client.connection.with_raw_response.retrieve(
- "connectionId",
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- connection = await response.parse()
- assert connection is None
-
- @pytest.mark.skip()
- @parametrize
- async def test_streaming_response_retrieve(self, async_client: AsyncSupermemory) -> None:
- async with async_client.connection.with_streaming_response.retrieve(
- "connectionId",
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- connection = await response.parse()
- assert connection is None
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip()
- @parametrize
- async def test_path_params_retrieve(self, async_client: AsyncSupermemory) -> None:
- with pytest.raises(ValueError, match=r"Expected a non-empty value for `connection_id` but received ''"):
- await async_client.connection.with_raw_response.retrieve(
- "",
- )
diff --git a/tests/api_resources/test_connections.py b/tests/api_resources/test_connections.py
new file mode 100644
index 00000000..4a34deed
--- /dev/null
+++ b/tests/api_resources/test_connections.py
@@ -0,0 +1,230 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+import os
+from typing import Any, cast
+
+import pytest
+
+from supermemory import Supermemory, AsyncSupermemory
+from tests.utils import assert_matches_type
+from supermemory.types import ConnectionGetResponse, ConnectionListResponse, ConnectionCreateResponse
+
+base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
+
+
+class TestConnections:
+ parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"])
+
+ @pytest.mark.skip()
+ @parametrize
+ def test_method_create(self, client: Supermemory) -> None:
+ connection = client.connections.create(
+ "notion",
+ )
+ assert_matches_type(ConnectionCreateResponse, connection, path=["response"])
+
+ @pytest.mark.skip()
+ @parametrize
+ def test_raw_response_create(self, client: Supermemory) -> None:
+ response = client.connections.with_raw_response.create(
+ "notion",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ connection = response.parse()
+ assert_matches_type(ConnectionCreateResponse, connection, path=["response"])
+
+ @pytest.mark.skip()
+ @parametrize
+ def test_streaming_response_create(self, client: Supermemory) -> None:
+ with client.connections.with_streaming_response.create(
+ "notion",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ connection = response.parse()
+ assert_matches_type(ConnectionCreateResponse, connection, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip()
+ @parametrize
+ def test_method_list(self, client: Supermemory) -> None:
+ connection = client.connections.list()
+ assert_matches_type(ConnectionListResponse, connection, path=["response"])
+
+ @pytest.mark.skip()
+ @parametrize
+ def test_raw_response_list(self, client: Supermemory) -> None:
+ response = client.connections.with_raw_response.list()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ connection = response.parse()
+ assert_matches_type(ConnectionListResponse, connection, path=["response"])
+
+ @pytest.mark.skip()
+ @parametrize
+ def test_streaming_response_list(self, client: Supermemory) -> None:
+ with client.connections.with_streaming_response.list() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ connection = response.parse()
+ assert_matches_type(ConnectionListResponse, connection, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip()
+ @parametrize
+ def test_method_get(self, client: Supermemory) -> None:
+ connection = client.connections.get(
+ "connectionId",
+ )
+ assert_matches_type(ConnectionGetResponse, connection, path=["response"])
+
+ @pytest.mark.skip()
+ @parametrize
+ def test_raw_response_get(self, client: Supermemory) -> None:
+ response = client.connections.with_raw_response.get(
+ "connectionId",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ connection = response.parse()
+ assert_matches_type(ConnectionGetResponse, connection, path=["response"])
+
+ @pytest.mark.skip()
+ @parametrize
+ def test_streaming_response_get(self, client: Supermemory) -> None:
+ with client.connections.with_streaming_response.get(
+ "connectionId",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ connection = response.parse()
+ assert_matches_type(ConnectionGetResponse, connection, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip()
+ @parametrize
+ def test_path_params_get(self, client: Supermemory) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `connection_id` but received ''"):
+ client.connections.with_raw_response.get(
+ "",
+ )
+
+
+class TestAsyncConnections:
+ parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"])
+
+ @pytest.mark.skip()
+ @parametrize
+ async def test_method_create(self, async_client: AsyncSupermemory) -> None:
+ connection = await async_client.connections.create(
+ "notion",
+ )
+ assert_matches_type(ConnectionCreateResponse, connection, path=["response"])
+
+ @pytest.mark.skip()
+ @parametrize
+ async def test_raw_response_create(self, async_client: AsyncSupermemory) -> None:
+ response = await async_client.connections.with_raw_response.create(
+ "notion",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ connection = await response.parse()
+ assert_matches_type(ConnectionCreateResponse, connection, path=["response"])
+
+ @pytest.mark.skip()
+ @parametrize
+ async def test_streaming_response_create(self, async_client: AsyncSupermemory) -> None:
+ async with async_client.connections.with_streaming_response.create(
+ "notion",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ connection = await response.parse()
+ assert_matches_type(ConnectionCreateResponse, connection, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip()
+ @parametrize
+ async def test_method_list(self, async_client: AsyncSupermemory) -> None:
+ connection = await async_client.connections.list()
+ assert_matches_type(ConnectionListResponse, connection, path=["response"])
+
+ @pytest.mark.skip()
+ @parametrize
+ async def test_raw_response_list(self, async_client: AsyncSupermemory) -> None:
+ response = await async_client.connections.with_raw_response.list()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ connection = await response.parse()
+ assert_matches_type(ConnectionListResponse, connection, path=["response"])
+
+ @pytest.mark.skip()
+ @parametrize
+ async def test_streaming_response_list(self, async_client: AsyncSupermemory) -> None:
+ async with async_client.connections.with_streaming_response.list() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ connection = await response.parse()
+ assert_matches_type(ConnectionListResponse, connection, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip()
+ @parametrize
+ async def test_method_get(self, async_client: AsyncSupermemory) -> None:
+ connection = await async_client.connections.get(
+ "connectionId",
+ )
+ assert_matches_type(ConnectionGetResponse, connection, path=["response"])
+
+ @pytest.mark.skip()
+ @parametrize
+ async def test_raw_response_get(self, async_client: AsyncSupermemory) -> None:
+ response = await async_client.connections.with_raw_response.get(
+ "connectionId",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ connection = await response.parse()
+ assert_matches_type(ConnectionGetResponse, connection, path=["response"])
+
+ @pytest.mark.skip()
+ @parametrize
+ async def test_streaming_response_get(self, async_client: AsyncSupermemory) -> None:
+ async with async_client.connections.with_streaming_response.get(
+ "connectionId",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ connection = await response.parse()
+ assert_matches_type(ConnectionGetResponse, connection, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip()
+ @parametrize
+ async def test_path_params_get(self, async_client: AsyncSupermemory) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `connection_id` but received ''"):
+ await async_client.connections.with_raw_response.get(
+ "",
+ )
diff --git a/tests/api_resources/test_memory.py b/tests/api_resources/test_memories.py
similarity index 70%
rename from tests/api_resources/test_memory.py
rename to tests/api_resources/test_memories.py
index c41dde7b..304e16ec 100644
--- a/tests/api_resources/test_memory.py
+++ b/tests/api_resources/test_memories.py
@@ -10,156 +10,157 @@
from supermemory import Supermemory, AsyncSupermemory
from tests.utils import assert_matches_type
from supermemory.types import (
+ MemoryAddResponse,
MemoryGetResponse,
MemoryListResponse,
- MemoryCreateResponse,
MemoryDeleteResponse,
)
base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
-class TestMemory:
+class TestMemories:
parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"])
@pytest.mark.skip()
@parametrize
- def test_method_create(self, client: Supermemory) -> None:
- memory = client.memory.create(
- content="This is a detailed article about machine learning concepts..",
- )
- assert_matches_type(MemoryCreateResponse, memory, path=["response"])
-
- @pytest.mark.skip()
- @parametrize
- def test_method_create_with_all_params(self, client: Supermemory) -> None:
- memory = client.memory.create(
- content="This is a detailed article about machine learning concepts..",
- id="id",
- metadata={
- "source": "web",
- "category": "technology",
- "tag_1": "ai",
- "tag_2": "machine-learning",
- "readingTime": 5,
- "isPublic": True,
- },
- user_id="user_123",
+ def test_method_list(self, client: Supermemory) -> None:
+ memory = client.memories.list(
+ "id",
)
- assert_matches_type(MemoryCreateResponse, memory, path=["response"])
+ assert_matches_type(MemoryListResponse, memory, path=["response"])
@pytest.mark.skip()
@parametrize
- def test_raw_response_create(self, client: Supermemory) -> None:
- response = client.memory.with_raw_response.create(
- content="This is a detailed article about machine learning concepts..",
+ def test_raw_response_list(self, client: Supermemory) -> None:
+ response = client.memories.with_raw_response.list(
+ "id",
)
assert response.is_closed is True
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
memory = response.parse()
- assert_matches_type(MemoryCreateResponse, memory, path=["response"])
+ assert_matches_type(MemoryListResponse, memory, path=["response"])
@pytest.mark.skip()
@parametrize
- def test_streaming_response_create(self, client: Supermemory) -> None:
- with client.memory.with_streaming_response.create(
- content="This is a detailed article about machine learning concepts..",
+ def test_streaming_response_list(self, client: Supermemory) -> None:
+ with client.memories.with_streaming_response.list(
+ "id",
) as response:
assert not response.is_closed
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
memory = response.parse()
- assert_matches_type(MemoryCreateResponse, memory, path=["response"])
+ assert_matches_type(MemoryListResponse, memory, path=["response"])
assert cast(Any, response.is_closed) is True
@pytest.mark.skip()
@parametrize
- def test_method_list(self, client: Supermemory) -> None:
- memory = client.memory.list()
- assert_matches_type(MemoryListResponse, memory, path=["response"])
+ def test_path_params_list(self, client: Supermemory) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"):
+ client.memories.with_raw_response.list(
+ "",
+ )
@pytest.mark.skip()
@parametrize
- def test_method_list_with_all_params(self, client: Supermemory) -> None:
- memory = client.memory.list(
- filters='{"AND":[{"key":"group","value":"jira_users","negate":false},{"filterType":"numeric","key":"timestamp","value":"1742745777","negate":false,"numericOperator":">"}]}',
- limit="10",
- order="desc",
- page="1",
- sort="createdAt",
+ def test_method_delete(self, client: Supermemory) -> None:
+ memory = client.memories.delete(
+ "id",
)
- assert_matches_type(MemoryListResponse, memory, path=["response"])
+ assert_matches_type(MemoryDeleteResponse, memory, path=["response"])
@pytest.mark.skip()
@parametrize
- def test_raw_response_list(self, client: Supermemory) -> None:
- response = client.memory.with_raw_response.list()
+ def test_raw_response_delete(self, client: Supermemory) -> None:
+ response = client.memories.with_raw_response.delete(
+ "id",
+ )
assert response.is_closed is True
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
memory = response.parse()
- assert_matches_type(MemoryListResponse, memory, path=["response"])
+ assert_matches_type(MemoryDeleteResponse, memory, path=["response"])
@pytest.mark.skip()
@parametrize
- def test_streaming_response_list(self, client: Supermemory) -> None:
- with client.memory.with_streaming_response.list() as response:
+ def test_streaming_response_delete(self, client: Supermemory) -> None:
+ with client.memories.with_streaming_response.delete(
+ "id",
+ ) as response:
assert not response.is_closed
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
memory = response.parse()
- assert_matches_type(MemoryListResponse, memory, path=["response"])
+ assert_matches_type(MemoryDeleteResponse, memory, path=["response"])
assert cast(Any, response.is_closed) is True
@pytest.mark.skip()
@parametrize
- def test_method_delete(self, client: Supermemory) -> None:
- memory = client.memory.delete(
- "id",
+ def test_path_params_delete(self, client: Supermemory) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"):
+ client.memories.with_raw_response.delete(
+ "",
+ )
+
+ @pytest.mark.skip()
+ @parametrize
+ def test_method_add(self, client: Supermemory) -> None:
+ memory = client.memories.add(
+ content="This is a detailed article about machine learning concepts...",
)
- assert_matches_type(MemoryDeleteResponse, memory, path=["response"])
+ assert_matches_type(MemoryAddResponse, memory, path=["response"])
@pytest.mark.skip()
@parametrize
- def test_raw_response_delete(self, client: Supermemory) -> None:
- response = client.memory.with_raw_response.delete(
- "id",
+ def test_method_add_with_all_params(self, client: Supermemory) -> None:
+ memory = client.memories.add(
+ content="This is a detailed article about machine learning concepts...",
+ container_tags=["string"],
+ metadata={
+ "source": "web",
+ "category": "technology",
+ "tag_1": "ai",
+ "tag_2": "machine-learning",
+ "readingTime": 5,
+ "isPublic": True,
+ },
+ )
+ assert_matches_type(MemoryAddResponse, memory, path=["response"])
+
+ @pytest.mark.skip()
+ @parametrize
+ def test_raw_response_add(self, client: Supermemory) -> None:
+ response = client.memories.with_raw_response.add(
+ content="This is a detailed article about machine learning concepts...",
)
assert response.is_closed is True
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
memory = response.parse()
- assert_matches_type(MemoryDeleteResponse, memory, path=["response"])
+ assert_matches_type(MemoryAddResponse, memory, path=["response"])
@pytest.mark.skip()
@parametrize
- def test_streaming_response_delete(self, client: Supermemory) -> None:
- with client.memory.with_streaming_response.delete(
- "id",
+ def test_streaming_response_add(self, client: Supermemory) -> None:
+ with client.memories.with_streaming_response.add(
+ content="This is a detailed article about machine learning concepts...",
) as response:
assert not response.is_closed
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
memory = response.parse()
- assert_matches_type(MemoryDeleteResponse, memory, path=["response"])
+ assert_matches_type(MemoryAddResponse, memory, path=["response"])
assert cast(Any, response.is_closed) is True
- @pytest.mark.skip()
- @parametrize
- def test_path_params_delete(self, client: Supermemory) -> None:
- with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"):
- client.memory.with_raw_response.delete(
- "",
- )
-
@pytest.mark.skip()
@parametrize
def test_method_get(self, client: Supermemory) -> None:
- memory = client.memory.get(
+ memory = client.memories.get(
"id",
)
assert_matches_type(MemoryGetResponse, memory, path=["response"])
@@ -167,7 +168,7 @@ def test_method_get(self, client: Supermemory) -> None:
@pytest.mark.skip()
@parametrize
def test_raw_response_get(self, client: Supermemory) -> None:
- response = client.memory.with_raw_response.get(
+ response = client.memories.with_raw_response.get(
"id",
)
@@ -179,7 +180,7 @@ def test_raw_response_get(self, client: Supermemory) -> None:
@pytest.mark.skip()
@parametrize
def test_streaming_response_get(self, client: Supermemory) -> None:
- with client.memory.with_streaming_response.get(
+ with client.memories.with_streaming_response.get(
"id",
) as response:
assert not response.is_closed
@@ -194,152 +195,153 @@ def test_streaming_response_get(self, client: Supermemory) -> None:
@parametrize
def test_path_params_get(self, client: Supermemory) -> None:
with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"):
- client.memory.with_raw_response.get(
+ client.memories.with_raw_response.get(
"",
)
-class TestAsyncMemory:
+class TestAsyncMemories:
parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"])
@pytest.mark.skip()
@parametrize
- async def test_method_create(self, async_client: AsyncSupermemory) -> None:
- memory = await async_client.memory.create(
- content="This is a detailed article about machine learning concepts..",
- )
- assert_matches_type(MemoryCreateResponse, memory, path=["response"])
-
- @pytest.mark.skip()
- @parametrize
- async def test_method_create_with_all_params(self, async_client: AsyncSupermemory) -> None:
- memory = await async_client.memory.create(
- content="This is a detailed article about machine learning concepts..",
- id="id",
- metadata={
- "source": "web",
- "category": "technology",
- "tag_1": "ai",
- "tag_2": "machine-learning",
- "readingTime": 5,
- "isPublic": True,
- },
- user_id="user_123",
+ async def test_method_list(self, async_client: AsyncSupermemory) -> None:
+ memory = await async_client.memories.list(
+ "id",
)
- assert_matches_type(MemoryCreateResponse, memory, path=["response"])
+ assert_matches_type(MemoryListResponse, memory, path=["response"])
@pytest.mark.skip()
@parametrize
- async def test_raw_response_create(self, async_client: AsyncSupermemory) -> None:
- response = await async_client.memory.with_raw_response.create(
- content="This is a detailed article about machine learning concepts..",
+ async def test_raw_response_list(self, async_client: AsyncSupermemory) -> None:
+ response = await async_client.memories.with_raw_response.list(
+ "id",
)
assert response.is_closed is True
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
memory = await response.parse()
- assert_matches_type(MemoryCreateResponse, memory, path=["response"])
+ assert_matches_type(MemoryListResponse, memory, path=["response"])
@pytest.mark.skip()
@parametrize
- async def test_streaming_response_create(self, async_client: AsyncSupermemory) -> None:
- async with async_client.memory.with_streaming_response.create(
- content="This is a detailed article about machine learning concepts..",
+ async def test_streaming_response_list(self, async_client: AsyncSupermemory) -> None:
+ async with async_client.memories.with_streaming_response.list(
+ "id",
) as response:
assert not response.is_closed
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
memory = await response.parse()
- assert_matches_type(MemoryCreateResponse, memory, path=["response"])
+ assert_matches_type(MemoryListResponse, memory, path=["response"])
assert cast(Any, response.is_closed) is True
@pytest.mark.skip()
@parametrize
- async def test_method_list(self, async_client: AsyncSupermemory) -> None:
- memory = await async_client.memory.list()
- assert_matches_type(MemoryListResponse, memory, path=["response"])
+ async def test_path_params_list(self, async_client: AsyncSupermemory) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"):
+ await async_client.memories.with_raw_response.list(
+ "",
+ )
@pytest.mark.skip()
@parametrize
- async def test_method_list_with_all_params(self, async_client: AsyncSupermemory) -> None:
- memory = await async_client.memory.list(
- filters='{"AND":[{"key":"group","value":"jira_users","negate":false},{"filterType":"numeric","key":"timestamp","value":"1742745777","negate":false,"numericOperator":">"}]}',
- limit="10",
- order="desc",
- page="1",
- sort="createdAt",
+ async def test_method_delete(self, async_client: AsyncSupermemory) -> None:
+ memory = await async_client.memories.delete(
+ "id",
)
- assert_matches_type(MemoryListResponse, memory, path=["response"])
+ assert_matches_type(MemoryDeleteResponse, memory, path=["response"])
@pytest.mark.skip()
@parametrize
- async def test_raw_response_list(self, async_client: AsyncSupermemory) -> None:
- response = await async_client.memory.with_raw_response.list()
+ async def test_raw_response_delete(self, async_client: AsyncSupermemory) -> None:
+ response = await async_client.memories.with_raw_response.delete(
+ "id",
+ )
assert response.is_closed is True
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
memory = await response.parse()
- assert_matches_type(MemoryListResponse, memory, path=["response"])
+ assert_matches_type(MemoryDeleteResponse, memory, path=["response"])
@pytest.mark.skip()
@parametrize
- async def test_streaming_response_list(self, async_client: AsyncSupermemory) -> None:
- async with async_client.memory.with_streaming_response.list() as response:
+ async def test_streaming_response_delete(self, async_client: AsyncSupermemory) -> None:
+ async with async_client.memories.with_streaming_response.delete(
+ "id",
+ ) as response:
assert not response.is_closed
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
memory = await response.parse()
- assert_matches_type(MemoryListResponse, memory, path=["response"])
+ assert_matches_type(MemoryDeleteResponse, memory, path=["response"])
assert cast(Any, response.is_closed) is True
@pytest.mark.skip()
@parametrize
- async def test_method_delete(self, async_client: AsyncSupermemory) -> None:
- memory = await async_client.memory.delete(
- "id",
+ async def test_path_params_delete(self, async_client: AsyncSupermemory) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"):
+ await async_client.memories.with_raw_response.delete(
+ "",
+ )
+
+ @pytest.mark.skip()
+ @parametrize
+ async def test_method_add(self, async_client: AsyncSupermemory) -> None:
+ memory = await async_client.memories.add(
+ content="This is a detailed article about machine learning concepts...",
)
- assert_matches_type(MemoryDeleteResponse, memory, path=["response"])
+ assert_matches_type(MemoryAddResponse, memory, path=["response"])
@pytest.mark.skip()
@parametrize
- async def test_raw_response_delete(self, async_client: AsyncSupermemory) -> None:
- response = await async_client.memory.with_raw_response.delete(
- "id",
+ async def test_method_add_with_all_params(self, async_client: AsyncSupermemory) -> None:
+ memory = await async_client.memories.add(
+ content="This is a detailed article about machine learning concepts...",
+ container_tags=["string"],
+ metadata={
+ "source": "web",
+ "category": "technology",
+ "tag_1": "ai",
+ "tag_2": "machine-learning",
+ "readingTime": 5,
+ "isPublic": True,
+ },
+ )
+ assert_matches_type(MemoryAddResponse, memory, path=["response"])
+
+ @pytest.mark.skip()
+ @parametrize
+ async def test_raw_response_add(self, async_client: AsyncSupermemory) -> None:
+ response = await async_client.memories.with_raw_response.add(
+ content="This is a detailed article about machine learning concepts...",
)
assert response.is_closed is True
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
memory = await response.parse()
- assert_matches_type(MemoryDeleteResponse, memory, path=["response"])
+ assert_matches_type(MemoryAddResponse, memory, path=["response"])
@pytest.mark.skip()
@parametrize
- async def test_streaming_response_delete(self, async_client: AsyncSupermemory) -> None:
- async with async_client.memory.with_streaming_response.delete(
- "id",
+ async def test_streaming_response_add(self, async_client: AsyncSupermemory) -> None:
+ async with async_client.memories.with_streaming_response.add(
+ content="This is a detailed article about machine learning concepts...",
) as response:
assert not response.is_closed
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
memory = await response.parse()
- assert_matches_type(MemoryDeleteResponse, memory, path=["response"])
+ assert_matches_type(MemoryAddResponse, memory, path=["response"])
assert cast(Any, response.is_closed) is True
- @pytest.mark.skip()
- @parametrize
- async def test_path_params_delete(self, async_client: AsyncSupermemory) -> None:
- with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"):
- await async_client.memory.with_raw_response.delete(
- "",
- )
-
@pytest.mark.skip()
@parametrize
async def test_method_get(self, async_client: AsyncSupermemory) -> None:
- memory = await async_client.memory.get(
+ memory = await async_client.memories.get(
"id",
)
assert_matches_type(MemoryGetResponse, memory, path=["response"])
@@ -347,7 +349,7 @@ async def test_method_get(self, async_client: AsyncSupermemory) -> None:
@pytest.mark.skip()
@parametrize
async def test_raw_response_get(self, async_client: AsyncSupermemory) -> None:
- response = await async_client.memory.with_raw_response.get(
+ response = await async_client.memories.with_raw_response.get(
"id",
)
@@ -359,7 +361,7 @@ async def test_raw_response_get(self, async_client: AsyncSupermemory) -> None:
@pytest.mark.skip()
@parametrize
async def test_streaming_response_get(self, async_client: AsyncSupermemory) -> None:
- async with async_client.memory.with_streaming_response.get(
+ async with async_client.memories.with_streaming_response.get(
"id",
) as response:
assert not response.is_closed
@@ -374,6 +376,6 @@ async def test_streaming_response_get(self, async_client: AsyncSupermemory) -> N
@parametrize
async def test_path_params_get(self, async_client: AsyncSupermemory) -> None:
with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"):
- await async_client.memory.with_raw_response.get(
+ await async_client.memories.with_raw_response.get(
"",
)
diff --git a/tests/api_resources/test_search.py b/tests/api_resources/test_search.py
deleted file mode 100644
index c0557ff5..00000000
--- a/tests/api_resources/test_search.py
+++ /dev/null
@@ -1,160 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from __future__ import annotations
-
-import os
-from typing import Any, cast
-
-import pytest
-
-from supermemory import Supermemory, AsyncSupermemory
-from tests.utils import assert_matches_type
-from supermemory.types import SearchExecuteResponse
-
-base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
-
-
-class TestSearch:
- parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"])
-
- @pytest.mark.skip()
- @parametrize
- def test_method_execute(self, client: Supermemory) -> None:
- search = client.search.execute(
- q="machine learning concepts",
- )
- assert_matches_type(SearchExecuteResponse, search, path=["response"])
-
- @pytest.mark.skip()
- @parametrize
- def test_method_execute_with_all_params(self, client: Supermemory) -> None:
- search = client.search.execute(
- q="machine learning concepts",
- categories_filter=["technology", "science"],
- chunk_threshold=0.5,
- doc_id="doc_xyz789",
- document_threshold=0.5,
- filters={
- "and_": [
- {
- "key": "group",
- "value": "jira_users",
- "negate": False,
- },
- {
- "filterType": "numeric",
- "key": "timestamp",
- "value": "1742745777",
- "negate": False,
- "numericOperator": ">",
- },
- ],
- "or_": [{}],
- },
- include_summary=False,
- limit=10,
- only_matching_chunks=False,
- rerank=False,
- rewrite_query=False,
- user_id="user_123",
- )
- assert_matches_type(SearchExecuteResponse, search, path=["response"])
-
- @pytest.mark.skip()
- @parametrize
- def test_raw_response_execute(self, client: Supermemory) -> None:
- response = client.search.with_raw_response.execute(
- q="machine learning concepts",
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- search = response.parse()
- assert_matches_type(SearchExecuteResponse, search, path=["response"])
-
- @pytest.mark.skip()
- @parametrize
- def test_streaming_response_execute(self, client: Supermemory) -> None:
- with client.search.with_streaming_response.execute(
- q="machine learning concepts",
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- search = response.parse()
- assert_matches_type(SearchExecuteResponse, search, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
-
-class TestAsyncSearch:
- parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"])
-
- @pytest.mark.skip()
- @parametrize
- async def test_method_execute(self, async_client: AsyncSupermemory) -> None:
- search = await async_client.search.execute(
- q="machine learning concepts",
- )
- assert_matches_type(SearchExecuteResponse, search, path=["response"])
-
- @pytest.mark.skip()
- @parametrize
- async def test_method_execute_with_all_params(self, async_client: AsyncSupermemory) -> None:
- search = await async_client.search.execute(
- q="machine learning concepts",
- categories_filter=["technology", "science"],
- chunk_threshold=0.5,
- doc_id="doc_xyz789",
- document_threshold=0.5,
- filters={
- "and_": [
- {
- "key": "group",
- "value": "jira_users",
- "negate": False,
- },
- {
- "filterType": "numeric",
- "key": "timestamp",
- "value": "1742745777",
- "negate": False,
- "numericOperator": ">",
- },
- ],
- "or_": [{}],
- },
- include_summary=False,
- limit=10,
- only_matching_chunks=False,
- rerank=False,
- rewrite_query=False,
- user_id="user_123",
- )
- assert_matches_type(SearchExecuteResponse, search, path=["response"])
-
- @pytest.mark.skip()
- @parametrize
- async def test_raw_response_execute(self, async_client: AsyncSupermemory) -> None:
- response = await async_client.search.with_raw_response.execute(
- q="machine learning concepts",
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- search = await response.parse()
- assert_matches_type(SearchExecuteResponse, search, path=["response"])
-
- @pytest.mark.skip()
- @parametrize
- async def test_streaming_response_execute(self, async_client: AsyncSupermemory) -> None:
- async with async_client.search.with_streaming_response.execute(
- q="machine learning concepts",
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- search = await response.parse()
- assert_matches_type(SearchExecuteResponse, search, path=["response"])
-
- assert cast(Any, response.is_closed) is True
diff --git a/tests/api_resources/test_settings.py b/tests/api_resources/test_settings.py
index 78bf0968..a7a8a777 100644
--- a/tests/api_resources/test_settings.py
+++ b/tests/api_resources/test_settings.py
@@ -9,7 +9,7 @@
from supermemory import Supermemory, AsyncSupermemory
from tests.utils import assert_matches_type
-from supermemory.types import SettingUpdateResponse
+from supermemory.types import SettingGetResponse, SettingUpdateResponse
base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
@@ -27,15 +27,9 @@ def test_method_update(self, client: Supermemory) -> None:
@parametrize
def test_method_update_with_all_params(self, client: Supermemory) -> None:
setting = client.settings.update(
- categories=["x"],
exclude_items=["x"],
filter_prompt="x",
- filter_tags=[
- {
- "score": 0,
- "tag": "x",
- }
- ],
+ filter_tags={"foo": ["string"]},
include_items=["x"],
should_llm_filter=True,
)
@@ -63,6 +57,34 @@ def test_streaming_response_update(self, client: Supermemory) -> None:
assert cast(Any, response.is_closed) is True
+ @pytest.mark.skip()
+ @parametrize
+ def test_method_get(self, client: Supermemory) -> None:
+ setting = client.settings.get()
+ assert_matches_type(SettingGetResponse, setting, path=["response"])
+
+ @pytest.mark.skip()
+ @parametrize
+ def test_raw_response_get(self, client: Supermemory) -> None:
+ response = client.settings.with_raw_response.get()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ setting = response.parse()
+ assert_matches_type(SettingGetResponse, setting, path=["response"])
+
+ @pytest.mark.skip()
+ @parametrize
+ def test_streaming_response_get(self, client: Supermemory) -> None:
+ with client.settings.with_streaming_response.get() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ setting = response.parse()
+ assert_matches_type(SettingGetResponse, setting, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
class TestAsyncSettings:
parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"])
@@ -77,15 +99,9 @@ async def test_method_update(self, async_client: AsyncSupermemory) -> None:
@parametrize
async def test_method_update_with_all_params(self, async_client: AsyncSupermemory) -> None:
setting = await async_client.settings.update(
- categories=["x"],
exclude_items=["x"],
filter_prompt="x",
- filter_tags=[
- {
- "score": 0,
- "tag": "x",
- }
- ],
+ filter_tags={"foo": ["string"]},
include_items=["x"],
should_llm_filter=True,
)
@@ -112,3 +128,31 @@ async def test_streaming_response_update(self, async_client: AsyncSupermemory) -
assert_matches_type(SettingUpdateResponse, setting, path=["response"])
assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip()
+ @parametrize
+ async def test_method_get(self, async_client: AsyncSupermemory) -> None:
+ setting = await async_client.settings.get()
+ assert_matches_type(SettingGetResponse, setting, path=["response"])
+
+ @pytest.mark.skip()
+ @parametrize
+ async def test_raw_response_get(self, async_client: AsyncSupermemory) -> None:
+ response = await async_client.settings.with_raw_response.get()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ setting = await response.parse()
+ assert_matches_type(SettingGetResponse, setting, path=["response"])
+
+ @pytest.mark.skip()
+ @parametrize
+ async def test_streaming_response_get(self, async_client: AsyncSupermemory) -> None:
+ async with async_client.settings.with_streaming_response.get() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ setting = await response.parse()
+ assert_matches_type(SettingGetResponse, setting, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
diff --git a/tests/test_client.py b/tests/test_client.py
index d0f97a12..977e1f61 100644
--- a/tests/test_client.py
+++ b/tests/test_client.py
@@ -23,17 +23,15 @@
from supermemory import Supermemory, AsyncSupermemory, APIResponseValidationError
from supermemory._types import Omit
-from supermemory._utils import maybe_transform
from supermemory._models import BaseModel, FinalRequestOptions
from supermemory._constants import RAW_RESPONSE_HEADER
-from supermemory._exceptions import APIStatusError, APITimeoutError, APIResponseValidationError
+from supermemory._exceptions import APIStatusError, APITimeoutError, SupermemoryError, APIResponseValidationError
from supermemory._base_client import (
DEFAULT_TIMEOUT,
HTTPX_DEFAULT_TIMEOUT,
BaseClient,
make_request_options,
)
-from supermemory.types.memory_create_params import MemoryCreateParams
from .utils import update_env
@@ -336,6 +334,16 @@ def test_default_headers_option(self) -> None:
assert request.headers.get("x-foo") == "stainless"
assert request.headers.get("x-stainless-lang") == "my-overriding-header"
+ def test_validate_headers(self) -> None:
+ client = Supermemory(base_url=base_url, api_key=api_key, _strict_response_validation=True)
+ request = client._build_request(FinalRequestOptions(method="get", url="/foo"))
+ assert request.headers.get("Authorization") == f"Bearer {api_key}"
+
+ with pytest.raises(SupermemoryError):
+ with update_env(**{"SUPERMEMORY_API_KEY": Omit()}):
+ client2 = Supermemory(base_url=base_url, api_key=None, _strict_response_validation=True)
+ _ = client2
+
def test_default_query_option(self) -> None:
client = Supermemory(
base_url=base_url, api_key=api_key, _strict_response_validation=True, default_query={"query_param": "bar"}
@@ -714,19 +722,11 @@ def test_parse_retry_after_header(self, remaining_retries: int, retry_after: str
@mock.patch("supermemory._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout)
@pytest.mark.respx(base_url=base_url)
def test_retrying_timeout_errors_doesnt_leak(self, respx_mock: MockRouter) -> None:
- respx_mock.post("/add").mock(side_effect=httpx.TimeoutException("Test timeout error"))
+ respx_mock.delete("/v3/memories/id").mock(side_effect=httpx.TimeoutException("Test timeout error"))
with pytest.raises(APITimeoutError):
- self.client.post(
- "/add",
- body=cast(
- object,
- maybe_transform(
- dict(content="This is a detailed article about machine learning concepts.."), MemoryCreateParams
- ),
- ),
- cast_to=httpx.Response,
- options={"headers": {RAW_RESPONSE_HEADER: "stream"}},
+ self.client.delete(
+ "/v3/memories/id", cast_to=httpx.Response, options={"headers": {RAW_RESPONSE_HEADER: "stream"}}
)
assert _get_open_connections(self.client) == 0
@@ -734,19 +734,11 @@ def test_retrying_timeout_errors_doesnt_leak(self, respx_mock: MockRouter) -> No
@mock.patch("supermemory._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout)
@pytest.mark.respx(base_url=base_url)
def test_retrying_status_errors_doesnt_leak(self, respx_mock: MockRouter) -> None:
- respx_mock.post("/add").mock(return_value=httpx.Response(500))
+ respx_mock.delete("/v3/memories/id").mock(return_value=httpx.Response(500))
with pytest.raises(APIStatusError):
- self.client.post(
- "/add",
- body=cast(
- object,
- maybe_transform(
- dict(content="This is a detailed article about machine learning concepts.."), MemoryCreateParams
- ),
- ),
- cast_to=httpx.Response,
- options={"headers": {RAW_RESPONSE_HEADER: "stream"}},
+ self.client.delete(
+ "/v3/memories/id", cast_to=httpx.Response, options={"headers": {RAW_RESPONSE_HEADER: "stream"}}
)
assert _get_open_connections(self.client) == 0
@@ -775,11 +767,9 @@ def retry_handler(_request: httpx.Request) -> httpx.Response:
return httpx.Response(500)
return httpx.Response(200)
- respx_mock.post("/add").mock(side_effect=retry_handler)
+ respx_mock.delete("/v3/memories/id").mock(side_effect=retry_handler)
- response = client.memory.with_raw_response.create(
- content="This is a detailed article about machine learning concepts.."
- )
+ response = client.memories.with_raw_response.list("id")
assert response.retries_taken == failures_before_success
assert int(response.http_request.headers.get("x-stainless-retry-count")) == failures_before_success
@@ -801,12 +791,9 @@ def retry_handler(_request: httpx.Request) -> httpx.Response:
return httpx.Response(500)
return httpx.Response(200)
- respx_mock.post("/add").mock(side_effect=retry_handler)
+ respx_mock.delete("/v3/memories/id").mock(side_effect=retry_handler)
- response = client.memory.with_raw_response.create(
- content="This is a detailed article about machine learning concepts..",
- extra_headers={"x-stainless-retry-count": Omit()},
- )
+ response = client.memories.with_raw_response.list("id", extra_headers={"x-stainless-retry-count": Omit()})
assert len(response.http_request.headers.get_list("x-stainless-retry-count")) == 0
@@ -827,12 +814,9 @@ def retry_handler(_request: httpx.Request) -> httpx.Response:
return httpx.Response(500)
return httpx.Response(200)
- respx_mock.post("/add").mock(side_effect=retry_handler)
+ respx_mock.delete("/v3/memories/id").mock(side_effect=retry_handler)
- response = client.memory.with_raw_response.create(
- content="This is a detailed article about machine learning concepts..",
- extra_headers={"x-stainless-retry-count": "42"},
- )
+ response = client.memories.with_raw_response.list("id", extra_headers={"x-stainless-retry-count": "42"})
assert response.http_request.headers.get("x-stainless-retry-count") == "42"
@@ -1116,6 +1100,16 @@ def test_default_headers_option(self) -> None:
assert request.headers.get("x-foo") == "stainless"
assert request.headers.get("x-stainless-lang") == "my-overriding-header"
+ def test_validate_headers(self) -> None:
+ client = AsyncSupermemory(base_url=base_url, api_key=api_key, _strict_response_validation=True)
+ request = client._build_request(FinalRequestOptions(method="get", url="/foo"))
+ assert request.headers.get("Authorization") == f"Bearer {api_key}"
+
+ with pytest.raises(SupermemoryError):
+ with update_env(**{"SUPERMEMORY_API_KEY": Omit()}):
+ client2 = AsyncSupermemory(base_url=base_url, api_key=None, _strict_response_validation=True)
+ _ = client2
+
def test_default_query_option(self) -> None:
client = AsyncSupermemory(
base_url=base_url, api_key=api_key, _strict_response_validation=True, default_query={"query_param": "bar"}
@@ -1498,19 +1492,11 @@ async def test_parse_retry_after_header(self, remaining_retries: int, retry_afte
@mock.patch("supermemory._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout)
@pytest.mark.respx(base_url=base_url)
async def test_retrying_timeout_errors_doesnt_leak(self, respx_mock: MockRouter) -> None:
- respx_mock.post("/add").mock(side_effect=httpx.TimeoutException("Test timeout error"))
+ respx_mock.delete("/v3/memories/id").mock(side_effect=httpx.TimeoutException("Test timeout error"))
with pytest.raises(APITimeoutError):
- await self.client.post(
- "/add",
- body=cast(
- object,
- maybe_transform(
- dict(content="This is a detailed article about machine learning concepts.."), MemoryCreateParams
- ),
- ),
- cast_to=httpx.Response,
- options={"headers": {RAW_RESPONSE_HEADER: "stream"}},
+ await self.client.delete(
+ "/v3/memories/id", cast_to=httpx.Response, options={"headers": {RAW_RESPONSE_HEADER: "stream"}}
)
assert _get_open_connections(self.client) == 0
@@ -1518,19 +1504,11 @@ async def test_retrying_timeout_errors_doesnt_leak(self, respx_mock: MockRouter)
@mock.patch("supermemory._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout)
@pytest.mark.respx(base_url=base_url)
async def test_retrying_status_errors_doesnt_leak(self, respx_mock: MockRouter) -> None:
- respx_mock.post("/add").mock(return_value=httpx.Response(500))
+ respx_mock.delete("/v3/memories/id").mock(return_value=httpx.Response(500))
with pytest.raises(APIStatusError):
- await self.client.post(
- "/add",
- body=cast(
- object,
- maybe_transform(
- dict(content="This is a detailed article about machine learning concepts.."), MemoryCreateParams
- ),
- ),
- cast_to=httpx.Response,
- options={"headers": {RAW_RESPONSE_HEADER: "stream"}},
+ await self.client.delete(
+ "/v3/memories/id", cast_to=httpx.Response, options={"headers": {RAW_RESPONSE_HEADER: "stream"}}
)
assert _get_open_connections(self.client) == 0
@@ -1560,11 +1538,9 @@ def retry_handler(_request: httpx.Request) -> httpx.Response:
return httpx.Response(500)
return httpx.Response(200)
- respx_mock.post("/add").mock(side_effect=retry_handler)
+ respx_mock.delete("/v3/memories/id").mock(side_effect=retry_handler)
- response = await client.memory.with_raw_response.create(
- content="This is a detailed article about machine learning concepts.."
- )
+ response = await client.memories.with_raw_response.list("id")
assert response.retries_taken == failures_before_success
assert int(response.http_request.headers.get("x-stainless-retry-count")) == failures_before_success
@@ -1587,12 +1563,9 @@ def retry_handler(_request: httpx.Request) -> httpx.Response:
return httpx.Response(500)
return httpx.Response(200)
- respx_mock.post("/add").mock(side_effect=retry_handler)
+ respx_mock.delete("/v3/memories/id").mock(side_effect=retry_handler)
- response = await client.memory.with_raw_response.create(
- content="This is a detailed article about machine learning concepts..",
- extra_headers={"x-stainless-retry-count": Omit()},
- )
+ response = await client.memories.with_raw_response.list("id", extra_headers={"x-stainless-retry-count": Omit()})
assert len(response.http_request.headers.get_list("x-stainless-retry-count")) == 0
@@ -1614,12 +1587,9 @@ def retry_handler(_request: httpx.Request) -> httpx.Response:
return httpx.Response(500)
return httpx.Response(200)
- respx_mock.post("/add").mock(side_effect=retry_handler)
+ respx_mock.delete("/v3/memories/id").mock(side_effect=retry_handler)
- response = await client.memory.with_raw_response.create(
- content="This is a detailed article about machine learning concepts..",
- extra_headers={"x-stainless-retry-count": "42"},
- )
+ response = await client.memories.with_raw_response.list("id", extra_headers={"x-stainless-retry-count": "42"})
assert response.http_request.headers.get("x-stainless-retry-count") == "42"
From af34c01553feba151893eea0f6a905078146424f Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Sun, 11 May 2025 14:49:00 +0000
Subject: [PATCH 11/24] feat(api): manual updates
---
.stats.yml | 6 +-
README.md | 50 ++++---
api.md | 2 +
src/supermemory/resources/memories.py | 107 +++++++++++++-
src/supermemory/types/__init__.py | 2 +
.../types/connection_create_response.py | 6 +-
src/supermemory/types/memory_update_params.py | 20 +++
.../types/memory_update_response.py | 11 ++
tests/api_resources/test_memories.py | 139 ++++++++++++++++++
tests/test_client.py | 126 +++++++++++++---
10 files changed, 421 insertions(+), 48 deletions(-)
create mode 100644 src/supermemory/types/memory_update_params.py
create mode 100644 src/supermemory/types/memory_update_response.py
diff --git a/.stats.yml b/.stats.yml
index 75349c0b..3ae21f36 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
-configured_endpoints: 8
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/supermemory--inc%2Fsupermemory-3fa2583744becce1e91ec5ad18f45d2cf17778def3a8f70537a15b08c746c2fb.yml
-openapi_spec_hash: bf3c5827e7ddb8b32435aeb671fe7845
+configured_endpoints: 9
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/supermemory--inc%2Fsupermemory-a280bf0a406a709c156d5e3fe7c8ae93ebe607d937af8d725d0a2997cab07a7d.yml
+openapi_spec_hash: 15c602571db9cbcce4703c929b994d82
config_hash: b9c958a39a94966479e516e9061818be
diff --git a/README.md b/README.md
index 9f05e6a6..8bdb29a8 100644
--- a/README.md
+++ b/README.md
@@ -31,10 +31,12 @@ client = Supermemory(
api_key=os.environ.get("SUPERMEMORY_API_KEY"), # This is the default and can be omitted
)
-memories = client.memories.list(
- "id",
+memory = client.memories.update(
+ path_id="id",
+ body_id="acxV5LHMEsG2hMSNb4umbn",
+ content="This is a detailed article about machine learning concepts...",
)
-print(memories.success)
+print(memory.id)
```
While you can provide an `api_key` keyword argument,
@@ -57,10 +59,12 @@ client = AsyncSupermemory(
async def main() -> None:
- memories = await client.memories.list(
- "id",
+ memory = await client.memories.update(
+ path_id="id",
+ body_id="acxV5LHMEsG2hMSNb4umbn",
+ content="This is a detailed article about machine learning concepts...",
)
- print(memories.success)
+ print(memory.id)
asyncio.run(main())
@@ -93,8 +97,10 @@ from supermemory import Supermemory
client = Supermemory()
try:
- client.memories.list(
- "id",
+ client.memories.update(
+ path_id="id",
+ body_id="acxV5LHMEsG2hMSNb4umbn",
+ content="This is a detailed article about machine learning concepts...",
)
except supermemory.APIConnectionError as e:
print("The server could not be reached")
@@ -138,8 +144,10 @@ client = Supermemory(
)
# Or, configure per-request:
-client.with_options(max_retries=5).memories.list(
- "id",
+client.with_options(max_retries=5).memories.update(
+ path_id="id",
+ body_id="acxV5LHMEsG2hMSNb4umbn",
+ content="This is a detailed article about machine learning concepts...",
)
```
@@ -163,8 +171,10 @@ client = Supermemory(
)
# Override per-request:
-client.with_options(timeout=5.0).memories.list(
- "id",
+client.with_options(timeout=5.0).memories.update(
+ path_id="id",
+ body_id="acxV5LHMEsG2hMSNb4umbn",
+ content="This is a detailed article about machine learning concepts...",
)
```
@@ -206,13 +216,15 @@ The "raw" Response object can be accessed by prefixing `.with_raw_response.` to
from supermemory import Supermemory
client = Supermemory()
-response = client.memories.with_raw_response.list(
- "id",
+response = client.memories.with_raw_response.update(
+ path_id="id",
+ body_id="acxV5LHMEsG2hMSNb4umbn",
+ content="This is a detailed article about machine learning concepts...",
)
print(response.headers.get('X-My-Header'))
-memory = response.parse() # get the object that `memories.list()` would have returned
-print(memory.success)
+memory = response.parse() # get the object that `memories.update()` would have returned
+print(memory.id)
```
These methods return an [`APIResponse`](https://github.com/supermemoryai/python-sdk/tree/main/src/supermemory/_response.py) object.
@@ -226,8 +238,10 @@ The above interface eagerly reads the full response body when you make the reque
To stream the response body, use `.with_streaming_response` instead, which requires a context manager and only reads the response body once you call `.read()`, `.text()`, `.json()`, `.iter_bytes()`, `.iter_text()`, `.iter_lines()` or `.parse()`. In the async client, these are async methods.
```python
-with client.memories.with_streaming_response.list(
- "id",
+with client.memories.with_streaming_response.update(
+ path_id="id",
+ body_id="acxV5LHMEsG2hMSNb4umbn",
+ content="This is a detailed article about machine learning concepts...",
) as response:
print(response.headers.get("X-My-Header"))
diff --git a/api.md b/api.md
index ea51d4ff..bbc056bf 100644
--- a/api.md
+++ b/api.md
@@ -4,6 +4,7 @@ Types:
```python
from supermemory.types import (
+ MemoryUpdateResponse,
MemoryListResponse,
MemoryDeleteResponse,
MemoryAddResponse,
@@ -13,6 +14,7 @@ from supermemory.types import (
Methods:
+- client.memories.update(path_id, \*\*params) -> MemoryUpdateResponse
- client.memories.list(id) -> MemoryListResponse
- client.memories.delete(id) -> MemoryDeleteResponse
- client.memories.add(\*\*params) -> MemoryAddResponse
diff --git a/src/supermemory/resources/memories.py b/src/supermemory/resources/memories.py
index 891d1b6a..59d5fbc1 100644
--- a/src/supermemory/resources/memories.py
+++ b/src/supermemory/resources/memories.py
@@ -6,7 +6,7 @@
import httpx
-from ..types import memory_add_params
+from ..types import memory_add_params, memory_update_params
from .._types import NOT_GIVEN, Body, Query, Headers, NotGiven
from .._utils import maybe_transform, async_maybe_transform
from .._compat import cached_property
@@ -22,6 +22,7 @@
from ..types.memory_get_response import MemoryGetResponse
from ..types.memory_list_response import MemoryListResponse
from ..types.memory_delete_response import MemoryDeleteResponse
+from ..types.memory_update_response import MemoryUpdateResponse
__all__ = ["MemoriesResource", "AsyncMemoriesResource"]
@@ -46,6 +47,52 @@ def with_streaming_response(self) -> MemoriesResourceWithStreamingResponse:
"""
return MemoriesResourceWithStreamingResponse(self)
+ def update(
+ self,
+ path_id: str,
+ *,
+ body_id: str,
+ content: str,
+ container_tags: List[str] | NotGiven = NOT_GIVEN,
+ metadata: Dict[str, Union[str, float, bool]] | NotGiven = NOT_GIVEN,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+ ) -> MemoryUpdateResponse:
+ """
+ Update a memory with any content type (text, url, file, etc.) and metadata
+
+ Args:
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
+ if not path_id:
+ raise ValueError(f"Expected a non-empty value for `path_id` but received {path_id!r}")
+ return self._patch(
+ f"/v3/memories/{path_id}",
+ body=maybe_transform(
+ {
+ "body_id": body_id,
+ "content": content,
+ "container_tags": container_tags,
+ "metadata": metadata,
+ },
+ memory_update_params.MemoryUpdateParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=MemoryUpdateResponse,
+ )
+
def list(
self,
id: str,
@@ -207,6 +254,52 @@ def with_streaming_response(self) -> AsyncMemoriesResourceWithStreamingResponse:
"""
return AsyncMemoriesResourceWithStreamingResponse(self)
+ async def update(
+ self,
+ path_id: str,
+ *,
+ body_id: str,
+ content: str,
+ container_tags: List[str] | NotGiven = NOT_GIVEN,
+ metadata: Dict[str, Union[str, float, bool]] | NotGiven = NOT_GIVEN,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+ ) -> MemoryUpdateResponse:
+ """
+ Update a memory with any content type (text, url, file, etc.) and metadata
+
+ Args:
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
+ if not path_id:
+ raise ValueError(f"Expected a non-empty value for `path_id` but received {path_id!r}")
+ return await self._patch(
+ f"/v3/memories/{path_id}",
+ body=await async_maybe_transform(
+ {
+ "body_id": body_id,
+ "content": content,
+ "container_tags": container_tags,
+ "metadata": metadata,
+ },
+ memory_update_params.MemoryUpdateParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=MemoryUpdateResponse,
+ )
+
async def list(
self,
id: str,
@@ -352,6 +445,9 @@ class MemoriesResourceWithRawResponse:
def __init__(self, memories: MemoriesResource) -> None:
self._memories = memories
+ self.update = to_raw_response_wrapper(
+ memories.update,
+ )
self.list = to_raw_response_wrapper(
memories.list,
)
@@ -370,6 +466,9 @@ class AsyncMemoriesResourceWithRawResponse:
def __init__(self, memories: AsyncMemoriesResource) -> None:
self._memories = memories
+ self.update = async_to_raw_response_wrapper(
+ memories.update,
+ )
self.list = async_to_raw_response_wrapper(
memories.list,
)
@@ -388,6 +487,9 @@ class MemoriesResourceWithStreamingResponse:
def __init__(self, memories: MemoriesResource) -> None:
self._memories = memories
+ self.update = to_streamed_response_wrapper(
+ memories.update,
+ )
self.list = to_streamed_response_wrapper(
memories.list,
)
@@ -406,6 +508,9 @@ class AsyncMemoriesResourceWithStreamingResponse:
def __init__(self, memories: AsyncMemoriesResource) -> None:
self._memories = memories
+ self.update = async_to_streamed_response_wrapper(
+ memories.update,
+ )
self.list = async_to_streamed_response_wrapper(
memories.list,
)
diff --git a/src/supermemory/types/__init__.py b/src/supermemory/types/__init__.py
index c7f47386..1dc2977e 100644
--- a/src/supermemory/types/__init__.py
+++ b/src/supermemory/types/__init__.py
@@ -6,9 +6,11 @@
from .memory_add_response import MemoryAddResponse as MemoryAddResponse
from .memory_get_response import MemoryGetResponse as MemoryGetResponse
from .memory_list_response import MemoryListResponse as MemoryListResponse
+from .memory_update_params import MemoryUpdateParams as MemoryUpdateParams
from .setting_get_response import SettingGetResponse as SettingGetResponse
from .setting_update_params import SettingUpdateParams as SettingUpdateParams
from .memory_delete_response import MemoryDeleteResponse as MemoryDeleteResponse
+from .memory_update_response import MemoryUpdateResponse as MemoryUpdateResponse
from .connection_get_response import ConnectionGetResponse as ConnectionGetResponse
from .setting_update_response import SettingUpdateResponse as SettingUpdateResponse
from .connection_list_response import ConnectionListResponse as ConnectionListResponse
diff --git a/src/supermemory/types/connection_create_response.py b/src/supermemory/types/connection_create_response.py
index d27a6fab..d8b52e4c 100644
--- a/src/supermemory/types/connection_create_response.py
+++ b/src/supermemory/types/connection_create_response.py
@@ -8,6 +8,8 @@
class ConnectionCreateResponse(BaseModel):
- expires_in: str = FieldInfo(alias="expiresIn")
+ id: str
+
+ auth_link: str = FieldInfo(alias="authLink")
- magic_link: str = FieldInfo(alias="magicLink")
+ expires_in: str = FieldInfo(alias="expiresIn")
diff --git a/src/supermemory/types/memory_update_params.py b/src/supermemory/types/memory_update_params.py
new file mode 100644
index 00000000..adceb6e0
--- /dev/null
+++ b/src/supermemory/types/memory_update_params.py
@@ -0,0 +1,20 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Dict, List, Union
+from typing_extensions import Required, Annotated, TypedDict
+
+from .._utils import PropertyInfo
+
+__all__ = ["MemoryUpdateParams"]
+
+
+class MemoryUpdateParams(TypedDict, total=False):
+ body_id: Required[Annotated[str, PropertyInfo(alias="id")]]
+
+ content: Required[str]
+
+ container_tags: Annotated[List[str], PropertyInfo(alias="containerTags")]
+
+ metadata: Dict[str, Union[str, float, bool]]
diff --git a/src/supermemory/types/memory_update_response.py b/src/supermemory/types/memory_update_response.py
new file mode 100644
index 00000000..132b8cf9
--- /dev/null
+++ b/src/supermemory/types/memory_update_response.py
@@ -0,0 +1,11 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from .._models import BaseModel
+
+__all__ = ["MemoryUpdateResponse"]
+
+
+class MemoryUpdateResponse(BaseModel):
+ id: str
+
+ status: str
diff --git a/tests/api_resources/test_memories.py b/tests/api_resources/test_memories.py
index 304e16ec..cab6854a 100644
--- a/tests/api_resources/test_memories.py
+++ b/tests/api_resources/test_memories.py
@@ -14,6 +14,7 @@
MemoryGetResponse,
MemoryListResponse,
MemoryDeleteResponse,
+ MemoryUpdateResponse,
)
base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
@@ -22,6 +23,75 @@
class TestMemories:
parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"])
+ @pytest.mark.skip()
+ @parametrize
+ def test_method_update(self, client: Supermemory) -> None:
+ memory = client.memories.update(
+ path_id="id",
+ body_id="acxV5LHMEsG2hMSNb4umbn",
+ content="This is a detailed article about machine learning concepts...",
+ )
+ assert_matches_type(MemoryUpdateResponse, memory, path=["response"])
+
+ @pytest.mark.skip()
+ @parametrize
+ def test_method_update_with_all_params(self, client: Supermemory) -> None:
+ memory = client.memories.update(
+ path_id="id",
+ body_id="acxV5LHMEsG2hMSNb4umbn",
+ content="This is a detailed article about machine learning concepts...",
+ container_tags=["string"],
+ metadata={
+ "source": "web",
+ "category": "technology",
+ "tag_1": "ai",
+ "tag_2": "machine-learning",
+ "readingTime": 5,
+ "isPublic": True,
+ },
+ )
+ assert_matches_type(MemoryUpdateResponse, memory, path=["response"])
+
+ @pytest.mark.skip()
+ @parametrize
+ def test_raw_response_update(self, client: Supermemory) -> None:
+ response = client.memories.with_raw_response.update(
+ path_id="id",
+ body_id="acxV5LHMEsG2hMSNb4umbn",
+ content="This is a detailed article about machine learning concepts...",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ memory = response.parse()
+ assert_matches_type(MemoryUpdateResponse, memory, path=["response"])
+
+ @pytest.mark.skip()
+ @parametrize
+ def test_streaming_response_update(self, client: Supermemory) -> None:
+ with client.memories.with_streaming_response.update(
+ path_id="id",
+ body_id="acxV5LHMEsG2hMSNb4umbn",
+ content="This is a detailed article about machine learning concepts...",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ memory = response.parse()
+ assert_matches_type(MemoryUpdateResponse, memory, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip()
+ @parametrize
+ def test_path_params_update(self, client: Supermemory) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `path_id` but received ''"):
+ client.memories.with_raw_response.update(
+ path_id="",
+ body_id="acxV5LHMEsG2hMSNb4umbn",
+ content="This is a detailed article about machine learning concepts...",
+ )
+
@pytest.mark.skip()
@parametrize
def test_method_list(self, client: Supermemory) -> None:
@@ -203,6 +273,75 @@ def test_path_params_get(self, client: Supermemory) -> None:
class TestAsyncMemories:
parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"])
+ @pytest.mark.skip()
+ @parametrize
+ async def test_method_update(self, async_client: AsyncSupermemory) -> None:
+ memory = await async_client.memories.update(
+ path_id="id",
+ body_id="acxV5LHMEsG2hMSNb4umbn",
+ content="This is a detailed article about machine learning concepts...",
+ )
+ assert_matches_type(MemoryUpdateResponse, memory, path=["response"])
+
+ @pytest.mark.skip()
+ @parametrize
+ async def test_method_update_with_all_params(self, async_client: AsyncSupermemory) -> None:
+ memory = await async_client.memories.update(
+ path_id="id",
+ body_id="acxV5LHMEsG2hMSNb4umbn",
+ content="This is a detailed article about machine learning concepts...",
+ container_tags=["string"],
+ metadata={
+ "source": "web",
+ "category": "technology",
+ "tag_1": "ai",
+ "tag_2": "machine-learning",
+ "readingTime": 5,
+ "isPublic": True,
+ },
+ )
+ assert_matches_type(MemoryUpdateResponse, memory, path=["response"])
+
+ @pytest.mark.skip()
+ @parametrize
+ async def test_raw_response_update(self, async_client: AsyncSupermemory) -> None:
+ response = await async_client.memories.with_raw_response.update(
+ path_id="id",
+ body_id="acxV5LHMEsG2hMSNb4umbn",
+ content="This is a detailed article about machine learning concepts...",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ memory = await response.parse()
+ assert_matches_type(MemoryUpdateResponse, memory, path=["response"])
+
+ @pytest.mark.skip()
+ @parametrize
+ async def test_streaming_response_update(self, async_client: AsyncSupermemory) -> None:
+ async with async_client.memories.with_streaming_response.update(
+ path_id="id",
+ body_id="acxV5LHMEsG2hMSNb4umbn",
+ content="This is a detailed article about machine learning concepts...",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ memory = await response.parse()
+ assert_matches_type(MemoryUpdateResponse, memory, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip()
+ @parametrize
+ async def test_path_params_update(self, async_client: AsyncSupermemory) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `path_id` but received ''"):
+ await async_client.memories.with_raw_response.update(
+ path_id="",
+ body_id="acxV5LHMEsG2hMSNb4umbn",
+ content="This is a detailed article about machine learning concepts...",
+ )
+
@pytest.mark.skip()
@parametrize
async def test_method_list(self, async_client: AsyncSupermemory) -> None:
diff --git a/tests/test_client.py b/tests/test_client.py
index 977e1f61..678f7465 100644
--- a/tests/test_client.py
+++ b/tests/test_client.py
@@ -23,6 +23,7 @@
from supermemory import Supermemory, AsyncSupermemory, APIResponseValidationError
from supermemory._types import Omit
+from supermemory._utils import maybe_transform
from supermemory._models import BaseModel, FinalRequestOptions
from supermemory._constants import RAW_RESPONSE_HEADER
from supermemory._exceptions import APIStatusError, APITimeoutError, SupermemoryError, APIResponseValidationError
@@ -32,6 +33,7 @@
BaseClient,
make_request_options,
)
+from supermemory.types.memory_update_params import MemoryUpdateParams
from .utils import update_env
@@ -722,11 +724,23 @@ def test_parse_retry_after_header(self, remaining_retries: int, retry_after: str
@mock.patch("supermemory._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout)
@pytest.mark.respx(base_url=base_url)
def test_retrying_timeout_errors_doesnt_leak(self, respx_mock: MockRouter) -> None:
- respx_mock.delete("/v3/memories/id").mock(side_effect=httpx.TimeoutException("Test timeout error"))
+ respx_mock.patch("/v3/memories/id").mock(side_effect=httpx.TimeoutException("Test timeout error"))
with pytest.raises(APITimeoutError):
- self.client.delete(
- "/v3/memories/id", cast_to=httpx.Response, options={"headers": {RAW_RESPONSE_HEADER: "stream"}}
+ self.client.patch(
+ "/v3/memories/id",
+ body=cast(
+ object,
+ maybe_transform(
+ dict(
+ body_id="acxV5LHMEsG2hMSNb4umbn",
+ content="This is a detailed article about machine learning concepts...",
+ ),
+ MemoryUpdateParams,
+ ),
+ ),
+ cast_to=httpx.Response,
+ options={"headers": {RAW_RESPONSE_HEADER: "stream"}},
)
assert _get_open_connections(self.client) == 0
@@ -734,11 +748,23 @@ def test_retrying_timeout_errors_doesnt_leak(self, respx_mock: MockRouter) -> No
@mock.patch("supermemory._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout)
@pytest.mark.respx(base_url=base_url)
def test_retrying_status_errors_doesnt_leak(self, respx_mock: MockRouter) -> None:
- respx_mock.delete("/v3/memories/id").mock(return_value=httpx.Response(500))
+ respx_mock.patch("/v3/memories/id").mock(return_value=httpx.Response(500))
with pytest.raises(APIStatusError):
- self.client.delete(
- "/v3/memories/id", cast_to=httpx.Response, options={"headers": {RAW_RESPONSE_HEADER: "stream"}}
+ self.client.patch(
+ "/v3/memories/id",
+ body=cast(
+ object,
+ maybe_transform(
+ dict(
+ body_id="acxV5LHMEsG2hMSNb4umbn",
+ content="This is a detailed article about machine learning concepts...",
+ ),
+ MemoryUpdateParams,
+ ),
+ ),
+ cast_to=httpx.Response,
+ options={"headers": {RAW_RESPONSE_HEADER: "stream"}},
)
assert _get_open_connections(self.client) == 0
@@ -767,9 +793,13 @@ def retry_handler(_request: httpx.Request) -> httpx.Response:
return httpx.Response(500)
return httpx.Response(200)
- respx_mock.delete("/v3/memories/id").mock(side_effect=retry_handler)
+ respx_mock.patch("/v3/memories/id").mock(side_effect=retry_handler)
- response = client.memories.with_raw_response.list("id")
+ response = client.memories.with_raw_response.update(
+ path_id="id",
+ body_id="acxV5LHMEsG2hMSNb4umbn",
+ content="This is a detailed article about machine learning concepts...",
+ )
assert response.retries_taken == failures_before_success
assert int(response.http_request.headers.get("x-stainless-retry-count")) == failures_before_success
@@ -791,9 +821,14 @@ def retry_handler(_request: httpx.Request) -> httpx.Response:
return httpx.Response(500)
return httpx.Response(200)
- respx_mock.delete("/v3/memories/id").mock(side_effect=retry_handler)
+ respx_mock.patch("/v3/memories/id").mock(side_effect=retry_handler)
- response = client.memories.with_raw_response.list("id", extra_headers={"x-stainless-retry-count": Omit()})
+ response = client.memories.with_raw_response.update(
+ path_id="id",
+ body_id="acxV5LHMEsG2hMSNb4umbn",
+ content="This is a detailed article about machine learning concepts...",
+ extra_headers={"x-stainless-retry-count": Omit()},
+ )
assert len(response.http_request.headers.get_list("x-stainless-retry-count")) == 0
@@ -814,9 +849,14 @@ def retry_handler(_request: httpx.Request) -> httpx.Response:
return httpx.Response(500)
return httpx.Response(200)
- respx_mock.delete("/v3/memories/id").mock(side_effect=retry_handler)
+ respx_mock.patch("/v3/memories/id").mock(side_effect=retry_handler)
- response = client.memories.with_raw_response.list("id", extra_headers={"x-stainless-retry-count": "42"})
+ response = client.memories.with_raw_response.update(
+ path_id="id",
+ body_id="acxV5LHMEsG2hMSNb4umbn",
+ content="This is a detailed article about machine learning concepts...",
+ extra_headers={"x-stainless-retry-count": "42"},
+ )
assert response.http_request.headers.get("x-stainless-retry-count") == "42"
@@ -1492,11 +1532,23 @@ async def test_parse_retry_after_header(self, remaining_retries: int, retry_afte
@mock.patch("supermemory._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout)
@pytest.mark.respx(base_url=base_url)
async def test_retrying_timeout_errors_doesnt_leak(self, respx_mock: MockRouter) -> None:
- respx_mock.delete("/v3/memories/id").mock(side_effect=httpx.TimeoutException("Test timeout error"))
+ respx_mock.patch("/v3/memories/id").mock(side_effect=httpx.TimeoutException("Test timeout error"))
with pytest.raises(APITimeoutError):
- await self.client.delete(
- "/v3/memories/id", cast_to=httpx.Response, options={"headers": {RAW_RESPONSE_HEADER: "stream"}}
+ await self.client.patch(
+ "/v3/memories/id",
+ body=cast(
+ object,
+ maybe_transform(
+ dict(
+ body_id="acxV5LHMEsG2hMSNb4umbn",
+ content="This is a detailed article about machine learning concepts...",
+ ),
+ MemoryUpdateParams,
+ ),
+ ),
+ cast_to=httpx.Response,
+ options={"headers": {RAW_RESPONSE_HEADER: "stream"}},
)
assert _get_open_connections(self.client) == 0
@@ -1504,11 +1556,23 @@ async def test_retrying_timeout_errors_doesnt_leak(self, respx_mock: MockRouter)
@mock.patch("supermemory._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout)
@pytest.mark.respx(base_url=base_url)
async def test_retrying_status_errors_doesnt_leak(self, respx_mock: MockRouter) -> None:
- respx_mock.delete("/v3/memories/id").mock(return_value=httpx.Response(500))
+ respx_mock.patch("/v3/memories/id").mock(return_value=httpx.Response(500))
with pytest.raises(APIStatusError):
- await self.client.delete(
- "/v3/memories/id", cast_to=httpx.Response, options={"headers": {RAW_RESPONSE_HEADER: "stream"}}
+ await self.client.patch(
+ "/v3/memories/id",
+ body=cast(
+ object,
+ maybe_transform(
+ dict(
+ body_id="acxV5LHMEsG2hMSNb4umbn",
+ content="This is a detailed article about machine learning concepts...",
+ ),
+ MemoryUpdateParams,
+ ),
+ ),
+ cast_to=httpx.Response,
+ options={"headers": {RAW_RESPONSE_HEADER: "stream"}},
)
assert _get_open_connections(self.client) == 0
@@ -1538,9 +1602,13 @@ def retry_handler(_request: httpx.Request) -> httpx.Response:
return httpx.Response(500)
return httpx.Response(200)
- respx_mock.delete("/v3/memories/id").mock(side_effect=retry_handler)
+ respx_mock.patch("/v3/memories/id").mock(side_effect=retry_handler)
- response = await client.memories.with_raw_response.list("id")
+ response = await client.memories.with_raw_response.update(
+ path_id="id",
+ body_id="acxV5LHMEsG2hMSNb4umbn",
+ content="This is a detailed article about machine learning concepts...",
+ )
assert response.retries_taken == failures_before_success
assert int(response.http_request.headers.get("x-stainless-retry-count")) == failures_before_success
@@ -1563,9 +1631,14 @@ def retry_handler(_request: httpx.Request) -> httpx.Response:
return httpx.Response(500)
return httpx.Response(200)
- respx_mock.delete("/v3/memories/id").mock(side_effect=retry_handler)
+ respx_mock.patch("/v3/memories/id").mock(side_effect=retry_handler)
- response = await client.memories.with_raw_response.list("id", extra_headers={"x-stainless-retry-count": Omit()})
+ response = await client.memories.with_raw_response.update(
+ path_id="id",
+ body_id="acxV5LHMEsG2hMSNb4umbn",
+ content="This is a detailed article about machine learning concepts...",
+ extra_headers={"x-stainless-retry-count": Omit()},
+ )
assert len(response.http_request.headers.get_list("x-stainless-retry-count")) == 0
@@ -1587,9 +1660,14 @@ def retry_handler(_request: httpx.Request) -> httpx.Response:
return httpx.Response(500)
return httpx.Response(200)
- respx_mock.delete("/v3/memories/id").mock(side_effect=retry_handler)
+ respx_mock.patch("/v3/memories/id").mock(side_effect=retry_handler)
- response = await client.memories.with_raw_response.list("id", extra_headers={"x-stainless-retry-count": "42"})
+ response = await client.memories.with_raw_response.update(
+ path_id="id",
+ body_id="acxV5LHMEsG2hMSNb4umbn",
+ content="This is a detailed article about machine learning concepts...",
+ extra_headers={"x-stainless-retry-count": "42"},
+ )
assert response.http_request.headers.get("x-stainless-retry-count") == "42"
From 5b0c81086db77a2ea5922d117f4e393475d2bd03 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Sun, 11 May 2025 14:50:23 +0000
Subject: [PATCH 12/24] feat(api): manual updates
---
.stats.yml | 4 +-
README.md | 38 +--
api.md | 12 +
src/supermemory/_client.py | 10 +-
src/supermemory/resources/__init__.py | 14 +
src/supermemory/resources/search.py | 296 ++++++++++++++++++
src/supermemory/types/__init__.py | 2 +
.../types/search_execute_params.py | 86 +++++
.../types/search_execute_response.py | 52 +++
tests/api_resources/test_search.py | 160 ++++++++++
tests/test_client.py | 90 ++----
11 files changed, 676 insertions(+), 88 deletions(-)
create mode 100644 src/supermemory/resources/search.py
create mode 100644 src/supermemory/types/search_execute_params.py
create mode 100644 src/supermemory/types/search_execute_response.py
create mode 100644 tests/api_resources/test_search.py
diff --git a/.stats.yml b/.stats.yml
index 3ae21f36..3b889ac2 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
-configured_endpoints: 9
+configured_endpoints: 10
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/supermemory--inc%2Fsupermemory-a280bf0a406a709c156d5e3fe7c8ae93ebe607d937af8d725d0a2997cab07a7d.yml
openapi_spec_hash: 15c602571db9cbcce4703c929b994d82
-config_hash: b9c958a39a94966479e516e9061818be
+config_hash: 1c771b2d30afc18bf405a425ea1c327a
diff --git a/README.md b/README.md
index 8bdb29a8..43bb97a0 100644
--- a/README.md
+++ b/README.md
@@ -31,12 +31,10 @@ client = Supermemory(
api_key=os.environ.get("SUPERMEMORY_API_KEY"), # This is the default and can be omitted
)
-memory = client.memories.update(
- path_id="id",
- body_id="acxV5LHMEsG2hMSNb4umbn",
- content="This is a detailed article about machine learning concepts...",
+response = client.search.execute(
+ q="documents related to python",
)
-print(memory.id)
+print(response.results)
```
While you can provide an `api_key` keyword argument,
@@ -59,12 +57,10 @@ client = AsyncSupermemory(
async def main() -> None:
- memory = await client.memories.update(
- path_id="id",
- body_id="acxV5LHMEsG2hMSNb4umbn",
- content="This is a detailed article about machine learning concepts...",
+ response = await client.search.execute(
+ q="documents related to python",
)
- print(memory.id)
+ print(response.results)
asyncio.run(main())
@@ -97,9 +93,7 @@ from supermemory import Supermemory
client = Supermemory()
try:
- client.memories.update(
- path_id="id",
- body_id="acxV5LHMEsG2hMSNb4umbn",
+ client.memories.add(
content="This is a detailed article about machine learning concepts...",
)
except supermemory.APIConnectionError as e:
@@ -144,9 +138,7 @@ client = Supermemory(
)
# Or, configure per-request:
-client.with_options(max_retries=5).memories.update(
- path_id="id",
- body_id="acxV5LHMEsG2hMSNb4umbn",
+client.with_options(max_retries=5).memories.add(
content="This is a detailed article about machine learning concepts...",
)
```
@@ -171,9 +163,7 @@ client = Supermemory(
)
# Override per-request:
-client.with_options(timeout=5.0).memories.update(
- path_id="id",
- body_id="acxV5LHMEsG2hMSNb4umbn",
+client.with_options(timeout=5.0).memories.add(
content="This is a detailed article about machine learning concepts...",
)
```
@@ -216,14 +206,12 @@ The "raw" Response object can be accessed by prefixing `.with_raw_response.` to
from supermemory import Supermemory
client = Supermemory()
-response = client.memories.with_raw_response.update(
- path_id="id",
- body_id="acxV5LHMEsG2hMSNb4umbn",
+response = client.memories.with_raw_response.add(
content="This is a detailed article about machine learning concepts...",
)
print(response.headers.get('X-My-Header'))
-memory = response.parse() # get the object that `memories.update()` would have returned
+memory = response.parse() # get the object that `memories.add()` would have returned
print(memory.id)
```
@@ -238,9 +226,7 @@ The above interface eagerly reads the full response body when you make the reque
To stream the response body, use `.with_streaming_response` instead, which requires a context manager and only reads the response body once you call `.read()`, `.text()`, `.json()`, `.iter_bytes()`, `.iter_text()`, `.iter_lines()` or `.parse()`. In the async client, these are async methods.
```python
-with client.memories.with_streaming_response.update(
- path_id="id",
- body_id="acxV5LHMEsG2hMSNb4umbn",
+with client.memories.with_streaming_response.add(
content="This is a detailed article about machine learning concepts...",
) as response:
print(response.headers.get("X-My-Header"))
diff --git a/api.md b/api.md
index bbc056bf..fd254042 100644
--- a/api.md
+++ b/api.md
@@ -20,6 +20,18 @@ Methods:
- client.memories.add(\*\*params) -> MemoryAddResponse
- client.memories.get(id) -> MemoryGetResponse
+# Search
+
+Types:
+
+```python
+from supermemory.types import SearchExecuteResponse
+```
+
+Methods:
+
+- client.search.execute(\*\*params) -> SearchExecuteResponse
+
# Settings
Types:
diff --git a/src/supermemory/_client.py b/src/supermemory/_client.py
index 0a336bf6..e2e99f0b 100644
--- a/src/supermemory/_client.py
+++ b/src/supermemory/_client.py
@@ -21,7 +21,7 @@
)
from ._utils import is_given, get_async_library
from ._version import __version__
-from .resources import memories, settings, connections
+from .resources import search, memories, settings, connections
from ._streaming import Stream as Stream, AsyncStream as AsyncStream
from ._exceptions import APIStatusError, SupermemoryError
from ._base_client import (
@@ -44,6 +44,7 @@
class Supermemory(SyncAPIClient):
memories: memories.MemoriesResource
+ search: search.SearchResource
settings: settings.SettingsResource
connections: connections.ConnectionsResource
with_raw_response: SupermemoryWithRawResponse
@@ -104,6 +105,7 @@ def __init__(
)
self.memories = memories.MemoriesResource(self)
+ self.search = search.SearchResource(self)
self.settings = settings.SettingsResource(self)
self.connections = connections.ConnectionsResource(self)
self.with_raw_response = SupermemoryWithRawResponse(self)
@@ -216,6 +218,7 @@ def _make_status_error(
class AsyncSupermemory(AsyncAPIClient):
memories: memories.AsyncMemoriesResource
+ search: search.AsyncSearchResource
settings: settings.AsyncSettingsResource
connections: connections.AsyncConnectionsResource
with_raw_response: AsyncSupermemoryWithRawResponse
@@ -276,6 +279,7 @@ def __init__(
)
self.memories = memories.AsyncMemoriesResource(self)
+ self.search = search.AsyncSearchResource(self)
self.settings = settings.AsyncSettingsResource(self)
self.connections = connections.AsyncConnectionsResource(self)
self.with_raw_response = AsyncSupermemoryWithRawResponse(self)
@@ -389,6 +393,7 @@ def _make_status_error(
class SupermemoryWithRawResponse:
def __init__(self, client: Supermemory) -> None:
self.memories = memories.MemoriesResourceWithRawResponse(client.memories)
+ self.search = search.SearchResourceWithRawResponse(client.search)
self.settings = settings.SettingsResourceWithRawResponse(client.settings)
self.connections = connections.ConnectionsResourceWithRawResponse(client.connections)
@@ -396,6 +401,7 @@ def __init__(self, client: Supermemory) -> None:
class AsyncSupermemoryWithRawResponse:
def __init__(self, client: AsyncSupermemory) -> None:
self.memories = memories.AsyncMemoriesResourceWithRawResponse(client.memories)
+ self.search = search.AsyncSearchResourceWithRawResponse(client.search)
self.settings = settings.AsyncSettingsResourceWithRawResponse(client.settings)
self.connections = connections.AsyncConnectionsResourceWithRawResponse(client.connections)
@@ -403,6 +409,7 @@ def __init__(self, client: AsyncSupermemory) -> None:
class SupermemoryWithStreamedResponse:
def __init__(self, client: Supermemory) -> None:
self.memories = memories.MemoriesResourceWithStreamingResponse(client.memories)
+ self.search = search.SearchResourceWithStreamingResponse(client.search)
self.settings = settings.SettingsResourceWithStreamingResponse(client.settings)
self.connections = connections.ConnectionsResourceWithStreamingResponse(client.connections)
@@ -410,6 +417,7 @@ def __init__(self, client: Supermemory) -> None:
class AsyncSupermemoryWithStreamedResponse:
def __init__(self, client: AsyncSupermemory) -> None:
self.memories = memories.AsyncMemoriesResourceWithStreamingResponse(client.memories)
+ self.search = search.AsyncSearchResourceWithStreamingResponse(client.search)
self.settings = settings.AsyncSettingsResourceWithStreamingResponse(client.settings)
self.connections = connections.AsyncConnectionsResourceWithStreamingResponse(client.connections)
diff --git a/src/supermemory/resources/__init__.py b/src/supermemory/resources/__init__.py
index 5a1fb723..275ecfbe 100644
--- a/src/supermemory/resources/__init__.py
+++ b/src/supermemory/resources/__init__.py
@@ -1,5 +1,13 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+from .search import (
+ SearchResource,
+ AsyncSearchResource,
+ SearchResourceWithRawResponse,
+ AsyncSearchResourceWithRawResponse,
+ SearchResourceWithStreamingResponse,
+ AsyncSearchResourceWithStreamingResponse,
+)
from .memories import (
MemoriesResource,
AsyncMemoriesResource,
@@ -32,6 +40,12 @@
"AsyncMemoriesResourceWithRawResponse",
"MemoriesResourceWithStreamingResponse",
"AsyncMemoriesResourceWithStreamingResponse",
+ "SearchResource",
+ "AsyncSearchResource",
+ "SearchResourceWithRawResponse",
+ "AsyncSearchResourceWithRawResponse",
+ "SearchResourceWithStreamingResponse",
+ "AsyncSearchResourceWithStreamingResponse",
"SettingsResource",
"AsyncSettingsResource",
"SettingsResourceWithRawResponse",
diff --git a/src/supermemory/resources/search.py b/src/supermemory/resources/search.py
new file mode 100644
index 00000000..4e293996
--- /dev/null
+++ b/src/supermemory/resources/search.py
@@ -0,0 +1,296 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import List
+from typing_extensions import Literal
+
+import httpx
+
+from ..types import search_execute_params
+from .._types import NOT_GIVEN, Body, Query, Headers, NotGiven
+from .._utils import maybe_transform, async_maybe_transform
+from .._compat import cached_property
+from .._resource import SyncAPIResource, AsyncAPIResource
+from .._response import (
+ to_raw_response_wrapper,
+ to_streamed_response_wrapper,
+ async_to_raw_response_wrapper,
+ async_to_streamed_response_wrapper,
+)
+from .._base_client import make_request_options
+from ..types.search_execute_response import SearchExecuteResponse
+
+__all__ = ["SearchResource", "AsyncSearchResource"]
+
+
+class SearchResource(SyncAPIResource):
+ @cached_property
+ def with_raw_response(self) -> SearchResourceWithRawResponse:
+ """
+ This property can be used as a prefix for any HTTP method call to return
+ the raw response object instead of the parsed content.
+
+ For more information, see https://www.github.com/supermemoryai/python-sdk#accessing-raw-response-data-eg-headers
+ """
+ return SearchResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> SearchResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/supermemoryai/python-sdk#with_streaming_response
+ """
+ return SearchResourceWithStreamingResponse(self)
+
+ def execute(
+ self,
+ *,
+ q: str,
+ categories_filter: List[Literal["technology", "science", "business", "health"]] | NotGiven = NOT_GIVEN,
+ chunk_threshold: float | NotGiven = NOT_GIVEN,
+ doc_id: str | NotGiven = NOT_GIVEN,
+ document_threshold: float | NotGiven = NOT_GIVEN,
+ filters: search_execute_params.Filters | NotGiven = NOT_GIVEN,
+ include_summary: bool | NotGiven = NOT_GIVEN,
+ limit: int | NotGiven = NOT_GIVEN,
+ only_matching_chunks: bool | NotGiven = NOT_GIVEN,
+ rerank: bool | NotGiven = NOT_GIVEN,
+ rewrite_query: bool | NotGiven = NOT_GIVEN,
+ user_id: str | NotGiven = NOT_GIVEN,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+ ) -> SearchExecuteResponse:
+ """
+ Search memories with filtering
+
+ Args:
+ q: Search query string
+
+ categories_filter: Optional category filters
+
+ chunk_threshold: Threshold / sensitivity for chunk selection. 0 is least sensitive (returns most
+ chunks, more results), 1 is most sensitive (returns lesser chunks, accurate
+ results)
+
+ doc_id: Optional document ID to search within. You can use this to find chunks in a very
+ large document.
+
+ document_threshold: Threshold / sensitivity for document selection. 0 is least sensitive (returns
+ most documents, more results), 1 is most sensitive (returns lesser documents,
+ accurate results)
+
+ filters: Optional filters to apply to the search
+
+ include_summary: If true, include document summary in the response. This is helpful if you want a
+ chatbot to know the full context of the document.
+
+ limit: Maximum number of results to return
+
+ only_matching_chunks: If true, only return matching chunks without context. Normally, we send the
+ previous and next chunk to provide more context for LLMs. If you only want the
+ matching chunk, set this to true.
+
+ rerank: If true, rerank the results based on the query. This is helpful if you want to
+ ensure the most relevant results are returned.
+
+ rewrite_query: If true, rewrites the query to make it easier to find documents. This increases
+ the latency by about 400ms
+
+ user_id: End user ID this search is associated with. NOTE: This also acts as a filter for
+ the search.
+
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
+ return self._get(
+ "/v3/search",
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform(
+ {
+ "q": q,
+ "categories_filter": categories_filter,
+ "chunk_threshold": chunk_threshold,
+ "doc_id": doc_id,
+ "document_threshold": document_threshold,
+ "filters": filters,
+ "include_summary": include_summary,
+ "limit": limit,
+ "only_matching_chunks": only_matching_chunks,
+ "rerank": rerank,
+ "rewrite_query": rewrite_query,
+ "user_id": user_id,
+ },
+ search_execute_params.SearchExecuteParams,
+ ),
+ ),
+ cast_to=SearchExecuteResponse,
+ )
+
+
+class AsyncSearchResource(AsyncAPIResource):
+ @cached_property
+ def with_raw_response(self) -> AsyncSearchResourceWithRawResponse:
+ """
+ This property can be used as a prefix for any HTTP method call to return
+ the raw response object instead of the parsed content.
+
+ For more information, see https://www.github.com/supermemoryai/python-sdk#accessing-raw-response-data-eg-headers
+ """
+ return AsyncSearchResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> AsyncSearchResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/supermemoryai/python-sdk#with_streaming_response
+ """
+ return AsyncSearchResourceWithStreamingResponse(self)
+
+ async def execute(
+ self,
+ *,
+ q: str,
+ categories_filter: List[Literal["technology", "science", "business", "health"]] | NotGiven = NOT_GIVEN,
+ chunk_threshold: float | NotGiven = NOT_GIVEN,
+ doc_id: str | NotGiven = NOT_GIVEN,
+ document_threshold: float | NotGiven = NOT_GIVEN,
+ filters: search_execute_params.Filters | NotGiven = NOT_GIVEN,
+ include_summary: bool | NotGiven = NOT_GIVEN,
+ limit: int | NotGiven = NOT_GIVEN,
+ only_matching_chunks: bool | NotGiven = NOT_GIVEN,
+ rerank: bool | NotGiven = NOT_GIVEN,
+ rewrite_query: bool | NotGiven = NOT_GIVEN,
+ user_id: str | NotGiven = NOT_GIVEN,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+ ) -> SearchExecuteResponse:
+ """
+ Search memories with filtering
+
+ Args:
+ q: Search query string
+
+ categories_filter: Optional category filters
+
+ chunk_threshold: Threshold / sensitivity for chunk selection. 0 is least sensitive (returns most
+ chunks, more results), 1 is most sensitive (returns lesser chunks, accurate
+ results)
+
+ doc_id: Optional document ID to search within. You can use this to find chunks in a very
+ large document.
+
+ document_threshold: Threshold / sensitivity for document selection. 0 is least sensitive (returns
+ most documents, more results), 1 is most sensitive (returns lesser documents,
+ accurate results)
+
+ filters: Optional filters to apply to the search
+
+ include_summary: If true, include document summary in the response. This is helpful if you want a
+ chatbot to know the full context of the document.
+
+ limit: Maximum number of results to return
+
+ only_matching_chunks: If true, only return matching chunks without context. Normally, we send the
+ previous and next chunk to provide more context for LLMs. If you only want the
+ matching chunk, set this to true.
+
+ rerank: If true, rerank the results based on the query. This is helpful if you want to
+ ensure the most relevant results are returned.
+
+ rewrite_query: If true, rewrites the query to make it easier to find documents. This increases
+ the latency by about 400ms
+
+ user_id: End user ID this search is associated with. NOTE: This also acts as a filter for
+ the search.
+
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
+ return await self._get(
+ "/v3/search",
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=await async_maybe_transform(
+ {
+ "q": q,
+ "categories_filter": categories_filter,
+ "chunk_threshold": chunk_threshold,
+ "doc_id": doc_id,
+ "document_threshold": document_threshold,
+ "filters": filters,
+ "include_summary": include_summary,
+ "limit": limit,
+ "only_matching_chunks": only_matching_chunks,
+ "rerank": rerank,
+ "rewrite_query": rewrite_query,
+ "user_id": user_id,
+ },
+ search_execute_params.SearchExecuteParams,
+ ),
+ ),
+ cast_to=SearchExecuteResponse,
+ )
+
+
+class SearchResourceWithRawResponse:
+ def __init__(self, search: SearchResource) -> None:
+ self._search = search
+
+ self.execute = to_raw_response_wrapper(
+ search.execute,
+ )
+
+
+class AsyncSearchResourceWithRawResponse:
+ def __init__(self, search: AsyncSearchResource) -> None:
+ self._search = search
+
+ self.execute = async_to_raw_response_wrapper(
+ search.execute,
+ )
+
+
+class SearchResourceWithStreamingResponse:
+ def __init__(self, search: SearchResource) -> None:
+ self._search = search
+
+ self.execute = to_streamed_response_wrapper(
+ search.execute,
+ )
+
+
+class AsyncSearchResourceWithStreamingResponse:
+ def __init__(self, search: AsyncSearchResource) -> None:
+ self._search = search
+
+ self.execute = async_to_streamed_response_wrapper(
+ search.execute,
+ )
diff --git a/src/supermemory/types/__init__.py b/src/supermemory/types/__init__.py
index 1dc2977e..9cee290e 100644
--- a/src/supermemory/types/__init__.py
+++ b/src/supermemory/types/__init__.py
@@ -8,10 +8,12 @@
from .memory_list_response import MemoryListResponse as MemoryListResponse
from .memory_update_params import MemoryUpdateParams as MemoryUpdateParams
from .setting_get_response import SettingGetResponse as SettingGetResponse
+from .search_execute_params import SearchExecuteParams as SearchExecuteParams
from .setting_update_params import SettingUpdateParams as SettingUpdateParams
from .memory_delete_response import MemoryDeleteResponse as MemoryDeleteResponse
from .memory_update_response import MemoryUpdateResponse as MemoryUpdateResponse
from .connection_get_response import ConnectionGetResponse as ConnectionGetResponse
+from .search_execute_response import SearchExecuteResponse as SearchExecuteResponse
from .setting_update_response import SettingUpdateResponse as SettingUpdateResponse
from .connection_list_response import ConnectionListResponse as ConnectionListResponse
from .connection_create_response import ConnectionCreateResponse as ConnectionCreateResponse
diff --git a/src/supermemory/types/search_execute_params.py b/src/supermemory/types/search_execute_params.py
new file mode 100644
index 00000000..bc3b4756
--- /dev/null
+++ b/src/supermemory/types/search_execute_params.py
@@ -0,0 +1,86 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Dict, List, Union, Iterable
+from typing_extensions import Literal, Required, Annotated, TypeAlias, TypedDict
+
+from .._utils import PropertyInfo
+
+__all__ = ["SearchExecuteParams", "Filters", "FiltersUnionMember0"]
+
+
+class SearchExecuteParams(TypedDict, total=False):
+ q: Required[str]
+ """Search query string"""
+
+ categories_filter: Annotated[
+ List[Literal["technology", "science", "business", "health"]], PropertyInfo(alias="categoriesFilter")
+ ]
+ """Optional category filters"""
+
+ chunk_threshold: Annotated[float, PropertyInfo(alias="chunkThreshold")]
+ """Threshold / sensitivity for chunk selection.
+
+ 0 is least sensitive (returns most chunks, more results), 1 is most sensitive
+ (returns lesser chunks, accurate results)
+ """
+
+ doc_id: Annotated[str, PropertyInfo(alias="docId")]
+ """Optional document ID to search within.
+
+ You can use this to find chunks in a very large document.
+ """
+
+ document_threshold: Annotated[float, PropertyInfo(alias="documentThreshold")]
+ """Threshold / sensitivity for document selection.
+
+ 0 is least sensitive (returns most documents, more results), 1 is most sensitive
+ (returns lesser documents, accurate results)
+ """
+
+ filters: Filters
+ """Optional filters to apply to the search"""
+
+ include_summary: Annotated[bool, PropertyInfo(alias="includeSummary")]
+ """If true, include document summary in the response.
+
+ This is helpful if you want a chatbot to know the full context of the document.
+ """
+
+ limit: int
+ """Maximum number of results to return"""
+
+ only_matching_chunks: Annotated[bool, PropertyInfo(alias="onlyMatchingChunks")]
+ """If true, only return matching chunks without context.
+
+ Normally, we send the previous and next chunk to provide more context for LLMs.
+ If you only want the matching chunk, set this to true.
+ """
+
+ rerank: bool
+ """If true, rerank the results based on the query.
+
+ This is helpful if you want to ensure the most relevant results are returned.
+ """
+
+ rewrite_query: Annotated[bool, PropertyInfo(alias="rewriteQuery")]
+ """If true, rewrites the query to make it easier to find documents.
+
+ This increases the latency by about 400ms
+ """
+
+ user_id: Annotated[str, PropertyInfo(alias="userId")]
+ """End user ID this search is associated with.
+
+ NOTE: This also acts as a filter for the search.
+ """
+
+
+class FiltersUnionMember0(TypedDict, total=False):
+ and_: Annotated[Iterable[object], PropertyInfo(alias="AND")]
+
+ or_: Annotated[Iterable[object], PropertyInfo(alias="OR")]
+
+
+Filters: TypeAlias = Union[FiltersUnionMember0, Dict[str, object]]
diff --git a/src/supermemory/types/search_execute_response.py b/src/supermemory/types/search_execute_response.py
new file mode 100644
index 00000000..5b2bc4e0
--- /dev/null
+++ b/src/supermemory/types/search_execute_response.py
@@ -0,0 +1,52 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Dict, List, Optional
+from datetime import datetime
+
+from pydantic import Field as FieldInfo
+
+from .._models import BaseModel
+
+__all__ = ["SearchExecuteResponse", "Result", "ResultChunk"]
+
+
+class ResultChunk(BaseModel):
+ content: str
+ """Content of the matching chunk"""
+
+ is_relevant: bool = FieldInfo(alias="isRelevant")
+ """Whether this chunk is relevant to the query"""
+
+ score: float
+ """Similarity score for this chunk"""
+
+
+class Result(BaseModel):
+ chunks: List[ResultChunk]
+ """Matching content chunks from the document"""
+
+ created_at: datetime = FieldInfo(alias="createdAt")
+ """Document creation date"""
+
+ document_id: str = FieldInfo(alias="documentId")
+ """ID of the matching document"""
+
+ metadata: Optional[Dict[str, object]] = None
+ """Document metadata"""
+
+ score: float
+ """Relevance score of the match"""
+
+ title: str
+ """Document title"""
+
+ updated_at: datetime = FieldInfo(alias="updatedAt")
+ """Document last update date"""
+
+
+class SearchExecuteResponse(BaseModel):
+ results: List[Result]
+
+ timing: float
+
+ total: float
diff --git a/tests/api_resources/test_search.py b/tests/api_resources/test_search.py
new file mode 100644
index 00000000..c0557ff5
--- /dev/null
+++ b/tests/api_resources/test_search.py
@@ -0,0 +1,160 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+import os
+from typing import Any, cast
+
+import pytest
+
+from supermemory import Supermemory, AsyncSupermemory
+from tests.utils import assert_matches_type
+from supermemory.types import SearchExecuteResponse
+
+base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
+
+
+class TestSearch:
+ parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"])
+
+ @pytest.mark.skip()
+ @parametrize
+ def test_method_execute(self, client: Supermemory) -> None:
+ search = client.search.execute(
+ q="machine learning concepts",
+ )
+ assert_matches_type(SearchExecuteResponse, search, path=["response"])
+
+ @pytest.mark.skip()
+ @parametrize
+ def test_method_execute_with_all_params(self, client: Supermemory) -> None:
+ search = client.search.execute(
+ q="machine learning concepts",
+ categories_filter=["technology", "science"],
+ chunk_threshold=0.5,
+ doc_id="doc_xyz789",
+ document_threshold=0.5,
+ filters={
+ "and_": [
+ {
+ "key": "group",
+ "value": "jira_users",
+ "negate": False,
+ },
+ {
+ "filterType": "numeric",
+ "key": "timestamp",
+ "value": "1742745777",
+ "negate": False,
+ "numericOperator": ">",
+ },
+ ],
+ "or_": [{}],
+ },
+ include_summary=False,
+ limit=10,
+ only_matching_chunks=False,
+ rerank=False,
+ rewrite_query=False,
+ user_id="user_123",
+ )
+ assert_matches_type(SearchExecuteResponse, search, path=["response"])
+
+ @pytest.mark.skip()
+ @parametrize
+ def test_raw_response_execute(self, client: Supermemory) -> None:
+ response = client.search.with_raw_response.execute(
+ q="machine learning concepts",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ search = response.parse()
+ assert_matches_type(SearchExecuteResponse, search, path=["response"])
+
+ @pytest.mark.skip()
+ @parametrize
+ def test_streaming_response_execute(self, client: Supermemory) -> None:
+ with client.search.with_streaming_response.execute(
+ q="machine learning concepts",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ search = response.parse()
+ assert_matches_type(SearchExecuteResponse, search, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+
+class TestAsyncSearch:
+ parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"])
+
+ @pytest.mark.skip()
+ @parametrize
+ async def test_method_execute(self, async_client: AsyncSupermemory) -> None:
+ search = await async_client.search.execute(
+ q="machine learning concepts",
+ )
+ assert_matches_type(SearchExecuteResponse, search, path=["response"])
+
+ @pytest.mark.skip()
+ @parametrize
+ async def test_method_execute_with_all_params(self, async_client: AsyncSupermemory) -> None:
+ search = await async_client.search.execute(
+ q="machine learning concepts",
+ categories_filter=["technology", "science"],
+ chunk_threshold=0.5,
+ doc_id="doc_xyz789",
+ document_threshold=0.5,
+ filters={
+ "and_": [
+ {
+ "key": "group",
+ "value": "jira_users",
+ "negate": False,
+ },
+ {
+ "filterType": "numeric",
+ "key": "timestamp",
+ "value": "1742745777",
+ "negate": False,
+ "numericOperator": ">",
+ },
+ ],
+ "or_": [{}],
+ },
+ include_summary=False,
+ limit=10,
+ only_matching_chunks=False,
+ rerank=False,
+ rewrite_query=False,
+ user_id="user_123",
+ )
+ assert_matches_type(SearchExecuteResponse, search, path=["response"])
+
+ @pytest.mark.skip()
+ @parametrize
+ async def test_raw_response_execute(self, async_client: AsyncSupermemory) -> None:
+ response = await async_client.search.with_raw_response.execute(
+ q="machine learning concepts",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ search = await response.parse()
+ assert_matches_type(SearchExecuteResponse, search, path=["response"])
+
+ @pytest.mark.skip()
+ @parametrize
+ async def test_streaming_response_execute(self, async_client: AsyncSupermemory) -> None:
+ async with async_client.search.with_streaming_response.execute(
+ q="machine learning concepts",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ search = await response.parse()
+ assert_matches_type(SearchExecuteResponse, search, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
diff --git a/tests/test_client.py b/tests/test_client.py
index 678f7465..3636a001 100644
--- a/tests/test_client.py
+++ b/tests/test_client.py
@@ -33,7 +33,7 @@
BaseClient,
make_request_options,
)
-from supermemory.types.memory_update_params import MemoryUpdateParams
+from supermemory.types.memory_add_params import MemoryAddParams
from .utils import update_env
@@ -724,19 +724,15 @@ def test_parse_retry_after_header(self, remaining_retries: int, retry_after: str
@mock.patch("supermemory._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout)
@pytest.mark.respx(base_url=base_url)
def test_retrying_timeout_errors_doesnt_leak(self, respx_mock: MockRouter) -> None:
- respx_mock.patch("/v3/memories/id").mock(side_effect=httpx.TimeoutException("Test timeout error"))
+ respx_mock.post("/v3/memories").mock(side_effect=httpx.TimeoutException("Test timeout error"))
with pytest.raises(APITimeoutError):
- self.client.patch(
- "/v3/memories/id",
+ self.client.post(
+ "/v3/memories",
body=cast(
object,
maybe_transform(
- dict(
- body_id="acxV5LHMEsG2hMSNb4umbn",
- content="This is a detailed article about machine learning concepts...",
- ),
- MemoryUpdateParams,
+ dict(content="This is a detailed article about machine learning concepts..."), MemoryAddParams
),
),
cast_to=httpx.Response,
@@ -748,19 +744,15 @@ def test_retrying_timeout_errors_doesnt_leak(self, respx_mock: MockRouter) -> No
@mock.patch("supermemory._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout)
@pytest.mark.respx(base_url=base_url)
def test_retrying_status_errors_doesnt_leak(self, respx_mock: MockRouter) -> None:
- respx_mock.patch("/v3/memories/id").mock(return_value=httpx.Response(500))
+ respx_mock.post("/v3/memories").mock(return_value=httpx.Response(500))
with pytest.raises(APIStatusError):
- self.client.patch(
- "/v3/memories/id",
+ self.client.post(
+ "/v3/memories",
body=cast(
object,
maybe_transform(
- dict(
- body_id="acxV5LHMEsG2hMSNb4umbn",
- content="This is a detailed article about machine learning concepts...",
- ),
- MemoryUpdateParams,
+ dict(content="This is a detailed article about machine learning concepts..."), MemoryAddParams
),
),
cast_to=httpx.Response,
@@ -793,12 +785,10 @@ def retry_handler(_request: httpx.Request) -> httpx.Response:
return httpx.Response(500)
return httpx.Response(200)
- respx_mock.patch("/v3/memories/id").mock(side_effect=retry_handler)
+ respx_mock.post("/v3/memories").mock(side_effect=retry_handler)
- response = client.memories.with_raw_response.update(
- path_id="id",
- body_id="acxV5LHMEsG2hMSNb4umbn",
- content="This is a detailed article about machine learning concepts...",
+ response = client.memories.with_raw_response.add(
+ content="This is a detailed article about machine learning concepts..."
)
assert response.retries_taken == failures_before_success
@@ -821,11 +811,9 @@ def retry_handler(_request: httpx.Request) -> httpx.Response:
return httpx.Response(500)
return httpx.Response(200)
- respx_mock.patch("/v3/memories/id").mock(side_effect=retry_handler)
+ respx_mock.post("/v3/memories").mock(side_effect=retry_handler)
- response = client.memories.with_raw_response.update(
- path_id="id",
- body_id="acxV5LHMEsG2hMSNb4umbn",
+ response = client.memories.with_raw_response.add(
content="This is a detailed article about machine learning concepts...",
extra_headers={"x-stainless-retry-count": Omit()},
)
@@ -849,11 +837,9 @@ def retry_handler(_request: httpx.Request) -> httpx.Response:
return httpx.Response(500)
return httpx.Response(200)
- respx_mock.patch("/v3/memories/id").mock(side_effect=retry_handler)
+ respx_mock.post("/v3/memories").mock(side_effect=retry_handler)
- response = client.memories.with_raw_response.update(
- path_id="id",
- body_id="acxV5LHMEsG2hMSNb4umbn",
+ response = client.memories.with_raw_response.add(
content="This is a detailed article about machine learning concepts...",
extra_headers={"x-stainless-retry-count": "42"},
)
@@ -1532,19 +1518,15 @@ async def test_parse_retry_after_header(self, remaining_retries: int, retry_afte
@mock.patch("supermemory._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout)
@pytest.mark.respx(base_url=base_url)
async def test_retrying_timeout_errors_doesnt_leak(self, respx_mock: MockRouter) -> None:
- respx_mock.patch("/v3/memories/id").mock(side_effect=httpx.TimeoutException("Test timeout error"))
+ respx_mock.post("/v3/memories").mock(side_effect=httpx.TimeoutException("Test timeout error"))
with pytest.raises(APITimeoutError):
- await self.client.patch(
- "/v3/memories/id",
+ await self.client.post(
+ "/v3/memories",
body=cast(
object,
maybe_transform(
- dict(
- body_id="acxV5LHMEsG2hMSNb4umbn",
- content="This is a detailed article about machine learning concepts...",
- ),
- MemoryUpdateParams,
+ dict(content="This is a detailed article about machine learning concepts..."), MemoryAddParams
),
),
cast_to=httpx.Response,
@@ -1556,19 +1538,15 @@ async def test_retrying_timeout_errors_doesnt_leak(self, respx_mock: MockRouter)
@mock.patch("supermemory._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout)
@pytest.mark.respx(base_url=base_url)
async def test_retrying_status_errors_doesnt_leak(self, respx_mock: MockRouter) -> None:
- respx_mock.patch("/v3/memories/id").mock(return_value=httpx.Response(500))
+ respx_mock.post("/v3/memories").mock(return_value=httpx.Response(500))
with pytest.raises(APIStatusError):
- await self.client.patch(
- "/v3/memories/id",
+ await self.client.post(
+ "/v3/memories",
body=cast(
object,
maybe_transform(
- dict(
- body_id="acxV5LHMEsG2hMSNb4umbn",
- content="This is a detailed article about machine learning concepts...",
- ),
- MemoryUpdateParams,
+ dict(content="This is a detailed article about machine learning concepts..."), MemoryAddParams
),
),
cast_to=httpx.Response,
@@ -1602,12 +1580,10 @@ def retry_handler(_request: httpx.Request) -> httpx.Response:
return httpx.Response(500)
return httpx.Response(200)
- respx_mock.patch("/v3/memories/id").mock(side_effect=retry_handler)
+ respx_mock.post("/v3/memories").mock(side_effect=retry_handler)
- response = await client.memories.with_raw_response.update(
- path_id="id",
- body_id="acxV5LHMEsG2hMSNb4umbn",
- content="This is a detailed article about machine learning concepts...",
+ response = await client.memories.with_raw_response.add(
+ content="This is a detailed article about machine learning concepts..."
)
assert response.retries_taken == failures_before_success
@@ -1631,11 +1607,9 @@ def retry_handler(_request: httpx.Request) -> httpx.Response:
return httpx.Response(500)
return httpx.Response(200)
- respx_mock.patch("/v3/memories/id").mock(side_effect=retry_handler)
+ respx_mock.post("/v3/memories").mock(side_effect=retry_handler)
- response = await client.memories.with_raw_response.update(
- path_id="id",
- body_id="acxV5LHMEsG2hMSNb4umbn",
+ response = await client.memories.with_raw_response.add(
content="This is a detailed article about machine learning concepts...",
extra_headers={"x-stainless-retry-count": Omit()},
)
@@ -1660,11 +1634,9 @@ def retry_handler(_request: httpx.Request) -> httpx.Response:
return httpx.Response(500)
return httpx.Response(200)
- respx_mock.patch("/v3/memories/id").mock(side_effect=retry_handler)
+ respx_mock.post("/v3/memories").mock(side_effect=retry_handler)
- response = await client.memories.with_raw_response.update(
- path_id="id",
- body_id="acxV5LHMEsG2hMSNb4umbn",
+ response = await client.memories.with_raw_response.add(
content="This is a detailed article about machine learning concepts...",
extra_headers={"x-stainless-retry-count": "42"},
)
From 4a6b77aa6cd55d7135e33cbfb1138d9b2d00d40a Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Sun, 11 May 2025 14:53:35 +0000
Subject: [PATCH 13/24] feat(api): manual updates
---
.stats.yml | 8 +-
api.md | 4 +-
src/supermemory/resources/memories.py | 89 ++++++++++++++----
src/supermemory/types/__init__.py | 1 +
.../types/memory_delete_response.py | 4 +-
src/supermemory/types/memory_list_params.py | 24 +++++
src/supermemory/types/memory_list_response.py | 90 ++++++++++++++++++-
tests/api_resources/test_memories.py | 56 ++++++------
8 files changed, 216 insertions(+), 60 deletions(-)
create mode 100644 src/supermemory/types/memory_list_params.py
diff --git a/.stats.yml b/.stats.yml
index 3b889ac2..45b7a90b 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
-configured_endpoints: 10
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/supermemory--inc%2Fsupermemory-a280bf0a406a709c156d5e3fe7c8ae93ebe607d937af8d725d0a2997cab07a7d.yml
-openapi_spec_hash: 15c602571db9cbcce4703c929b994d82
-config_hash: 1c771b2d30afc18bf405a425ea1c327a
+configured_endpoints: 11
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/supermemory--inc%2Fsupermemory-9f6d4050800c7cde90cbc3d1b59c782955e3cc1f73790c13a1924a000e09ec14.yml
+openapi_spec_hash: 92739eccad02248cc2bf07874e299fec
+config_hash: 3a000ea344f2f52c50cf06452fcf52ca
diff --git a/api.md b/api.md
index fd254042..0c367901 100644
--- a/api.md
+++ b/api.md
@@ -15,8 +15,8 @@ from supermemory.types import (
Methods:
- client.memories.update(path_id, \*\*params) -> MemoryUpdateResponse
-- client.memories.list(id) -> MemoryListResponse
-- client.memories.delete(id) -> MemoryDeleteResponse
+- client.memories.list(\*\*params) -> MemoryListResponse
+- client.memories.delete(id) -> MemoryDeleteResponse
- client.memories.add(\*\*params) -> MemoryAddResponse
- client.memories.get(id) -> MemoryGetResponse
diff --git a/src/supermemory/resources/memories.py b/src/supermemory/resources/memories.py
index 59d5fbc1..5c050e6a 100644
--- a/src/supermemory/resources/memories.py
+++ b/src/supermemory/resources/memories.py
@@ -3,10 +3,11 @@
from __future__ import annotations
from typing import Dict, List, Union
+from typing_extensions import Literal
import httpx
-from ..types import memory_add_params, memory_update_params
+from ..types import memory_add_params, memory_list_params, memory_update_params
from .._types import NOT_GIVEN, Body, Query, Headers, NotGiven
from .._utils import maybe_transform, async_maybe_transform
from .._compat import cached_property
@@ -95,8 +96,12 @@ def update(
def list(
self,
- id: str,
*,
+ filters: str | NotGiven = NOT_GIVEN,
+ limit: str | NotGiven = NOT_GIVEN,
+ order: Literal["asc", "desc"] | NotGiven = NOT_GIVEN,
+ page: str | NotGiven = NOT_GIVEN,
+ sort: Literal["createdAt", "updatedAt"] | NotGiven = NOT_GIVEN,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
# The extra values given here take precedence over values defined on the client or passed to this method.
extra_headers: Headers | None = None,
@@ -105,9 +110,19 @@ def list(
timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
) -> MemoryListResponse:
"""
- Delete a memory
+ Retrieves a paginated list of memories with their metadata and workflow status
Args:
+ filters: Optional filters to apply to the search
+
+ limit: Number of items per page
+
+ order: Sort order
+
+ page: Page number to fetch
+
+ sort: Field to sort by
+
extra_headers: Send extra headers
extra_query: Add additional query parameters to the request
@@ -116,12 +131,23 @@ def list(
timeout: Override the client-level default timeout for this request, in seconds
"""
- if not id:
- raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
- return self._delete(
- f"/v3/memories/{id}",
+ return self._get(
+ "/v3/memories",
options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform(
+ {
+ "filters": filters,
+ "limit": limit,
+ "order": order,
+ "page": page,
+ "sort": sort,
+ },
+ memory_list_params.MemoryListParams,
+ ),
),
cast_to=MemoryListResponse,
)
@@ -138,7 +164,7 @@ def delete(
timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
) -> MemoryDeleteResponse:
"""
- Get a memory by ID
+ Delete a memory
Args:
extra_headers: Send extra headers
@@ -151,7 +177,7 @@ def delete(
"""
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
- return self._get(
+ return self._delete(
f"/v3/memories/{id}",
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
@@ -302,8 +328,12 @@ async def update(
async def list(
self,
- id: str,
*,
+ filters: str | NotGiven = NOT_GIVEN,
+ limit: str | NotGiven = NOT_GIVEN,
+ order: Literal["asc", "desc"] | NotGiven = NOT_GIVEN,
+ page: str | NotGiven = NOT_GIVEN,
+ sort: Literal["createdAt", "updatedAt"] | NotGiven = NOT_GIVEN,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
# The extra values given here take precedence over values defined on the client or passed to this method.
extra_headers: Headers | None = None,
@@ -312,9 +342,19 @@ async def list(
timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
) -> MemoryListResponse:
"""
- Delete a memory
+ Retrieves a paginated list of memories with their metadata and workflow status
Args:
+ filters: Optional filters to apply to the search
+
+ limit: Number of items per page
+
+ order: Sort order
+
+ page: Page number to fetch
+
+ sort: Field to sort by
+
extra_headers: Send extra headers
extra_query: Add additional query parameters to the request
@@ -323,12 +363,23 @@ async def list(
timeout: Override the client-level default timeout for this request, in seconds
"""
- if not id:
- raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
- return await self._delete(
- f"/v3/memories/{id}",
+ return await self._get(
+ "/v3/memories",
options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=await async_maybe_transform(
+ {
+ "filters": filters,
+ "limit": limit,
+ "order": order,
+ "page": page,
+ "sort": sort,
+ },
+ memory_list_params.MemoryListParams,
+ ),
),
cast_to=MemoryListResponse,
)
@@ -345,7 +396,7 @@ async def delete(
timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
) -> MemoryDeleteResponse:
"""
- Get a memory by ID
+ Delete a memory
Args:
extra_headers: Send extra headers
@@ -358,7 +409,7 @@ async def delete(
"""
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
- return await self._get(
+ return await self._delete(
f"/v3/memories/{id}",
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
diff --git a/src/supermemory/types/__init__.py b/src/supermemory/types/__init__.py
index 9cee290e..2545ab27 100644
--- a/src/supermemory/types/__init__.py
+++ b/src/supermemory/types/__init__.py
@@ -3,6 +3,7 @@
from __future__ import annotations
from .memory_add_params import MemoryAddParams as MemoryAddParams
+from .memory_list_params import MemoryListParams as MemoryListParams
from .memory_add_response import MemoryAddResponse as MemoryAddResponse
from .memory_get_response import MemoryGetResponse as MemoryGetResponse
from .memory_list_response import MemoryListResponse as MemoryListResponse
diff --git a/src/supermemory/types/memory_delete_response.py b/src/supermemory/types/memory_delete_response.py
index fe31c22e..0f17a7e1 100644
--- a/src/supermemory/types/memory_delete_response.py
+++ b/src/supermemory/types/memory_delete_response.py
@@ -6,6 +6,4 @@
class MemoryDeleteResponse(BaseModel):
- id: str
-
- status: str
+ success: bool
diff --git a/src/supermemory/types/memory_list_params.py b/src/supermemory/types/memory_list_params.py
new file mode 100644
index 00000000..d40690da
--- /dev/null
+++ b/src/supermemory/types/memory_list_params.py
@@ -0,0 +1,24 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Literal, TypedDict
+
+__all__ = ["MemoryListParams"]
+
+
+class MemoryListParams(TypedDict, total=False):
+ filters: str
+ """Optional filters to apply to the search"""
+
+ limit: str
+ """Number of items per page"""
+
+ order: Literal["asc", "desc"]
+ """Sort order"""
+
+ page: str
+ """Page number to fetch"""
+
+ sort: Literal["createdAt", "updatedAt"]
+ """Field to sort by"""
diff --git a/src/supermemory/types/memory_list_response.py b/src/supermemory/types/memory_list_response.py
index 0fecfe23..5b325c78 100644
--- a/src/supermemory/types/memory_list_response.py
+++ b/src/supermemory/types/memory_list_response.py
@@ -1,9 +1,95 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+from typing import Dict, List, Union, Optional
+from datetime import datetime
+from typing_extensions import Literal
+
+from pydantic import Field as FieldInfo
+
from .._models import BaseModel
-__all__ = ["MemoryListResponse"]
+__all__ = ["MemoryListResponse", "Memory", "Pagination"]
+
+
+class Memory(BaseModel):
+ id: str
+ """Unique identifier of the memory."""
+
+ content: Optional[str] = None
+ """The content to extract and process into a memory.
+
+ This can be a URL to a website, a PDF, an image, or a video.
+
+ Plaintext: Any plaintext format
+
+ URL: A URL to a website, PDF, image, or video
+
+ We automatically detect the content type from the url's response format.
+ """
+
+ created_at: datetime = FieldInfo(alias="createdAt")
+ """Creation timestamp"""
+
+ custom_id: Optional[str] = FieldInfo(alias="customId", default=None)
+ """Optional custom ID of the memory.
+
+ This could be an ID from your database that will uniquely identify this memory.
+ """
+
+ metadata: Union[str, float, bool, Dict[str, object], List[object], None] = None
+ """Optional metadata for the memory.
+
+ This is used to store additional information about the memory. You can use this
+ to store any additional information you need about the memory. Metadata can be
+ filtered through. Keys must be strings and are case sensitive. Values can be
+ strings, numbers, or booleans. You cannot nest objects.
+ """
+
+ og_image: Optional[str] = FieldInfo(alias="ogImage", default=None)
+
+ source: Optional[str] = None
+
+ status: Literal["unknown", "queued", "extracting", "chunking", "embedding", "indexing", "done", "failed"]
+ """Status of the memory"""
+
+ summary: Optional[str] = None
+ """Summary of the memory content"""
+
+ title: Optional[str] = None
+ """Title of the memory"""
+
+ type: Literal["text", "pdf", "tweet", "google_doc", "image", "video", "notion_doc", "webpage"]
+ """Type of the memory"""
+
+ updated_at: datetime = FieldInfo(alias="updatedAt")
+ """Last update timestamp"""
+
+ url: Optional[str] = None
+ """URL of the memory"""
+
+ container_tags: Optional[List[str]] = FieldInfo(alias="containerTags", default=None)
+ """Optional tags this memory should be containerized by.
+
+ This can be an ID for your user, a project ID, or any other identifier you wish
+ to use to group memories.
+ """
+
+ raw: None = None
+ """Raw content of the memory"""
+
+
+class Pagination(BaseModel):
+ current_page: float = FieldInfo(alias="currentPage")
+
+ limit: float
+
+ total_items: float = FieldInfo(alias="totalItems")
+
+ total_pages: float = FieldInfo(alias="totalPages")
class MemoryListResponse(BaseModel):
- success: bool
+ memories: List[Memory]
+
+ pagination: Pagination
+ """Pagination metadata"""
diff --git a/tests/api_resources/test_memories.py b/tests/api_resources/test_memories.py
index cab6854a..228dcf39 100644
--- a/tests/api_resources/test_memories.py
+++ b/tests/api_resources/test_memories.py
@@ -95,17 +95,25 @@ def test_path_params_update(self, client: Supermemory) -> None:
@pytest.mark.skip()
@parametrize
def test_method_list(self, client: Supermemory) -> None:
+ memory = client.memories.list()
+ assert_matches_type(MemoryListResponse, memory, path=["response"])
+
+ @pytest.mark.skip()
+ @parametrize
+ def test_method_list_with_all_params(self, client: Supermemory) -> None:
memory = client.memories.list(
- "id",
+ filters='{"AND":[{"key":"group","value":"jira_users","negate":false},{"filterType":"numeric","key":"timestamp","value":"1742745777","negate":false,"numericOperator":">"}]}',
+ limit="10",
+ order="desc",
+ page="1",
+ sort="createdAt",
)
assert_matches_type(MemoryListResponse, memory, path=["response"])
@pytest.mark.skip()
@parametrize
def test_raw_response_list(self, client: Supermemory) -> None:
- response = client.memories.with_raw_response.list(
- "id",
- )
+ response = client.memories.with_raw_response.list()
assert response.is_closed is True
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
@@ -115,9 +123,7 @@ def test_raw_response_list(self, client: Supermemory) -> None:
@pytest.mark.skip()
@parametrize
def test_streaming_response_list(self, client: Supermemory) -> None:
- with client.memories.with_streaming_response.list(
- "id",
- ) as response:
+ with client.memories.with_streaming_response.list() as response:
assert not response.is_closed
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
@@ -126,14 +132,6 @@ def test_streaming_response_list(self, client: Supermemory) -> None:
assert cast(Any, response.is_closed) is True
- @pytest.mark.skip()
- @parametrize
- def test_path_params_list(self, client: Supermemory) -> None:
- with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"):
- client.memories.with_raw_response.list(
- "",
- )
-
@pytest.mark.skip()
@parametrize
def test_method_delete(self, client: Supermemory) -> None:
@@ -345,17 +343,25 @@ async def test_path_params_update(self, async_client: AsyncSupermemory) -> None:
@pytest.mark.skip()
@parametrize
async def test_method_list(self, async_client: AsyncSupermemory) -> None:
+ memory = await async_client.memories.list()
+ assert_matches_type(MemoryListResponse, memory, path=["response"])
+
+ @pytest.mark.skip()
+ @parametrize
+ async def test_method_list_with_all_params(self, async_client: AsyncSupermemory) -> None:
memory = await async_client.memories.list(
- "id",
+ filters='{"AND":[{"key":"group","value":"jira_users","negate":false},{"filterType":"numeric","key":"timestamp","value":"1742745777","negate":false,"numericOperator":">"}]}',
+ limit="10",
+ order="desc",
+ page="1",
+ sort="createdAt",
)
assert_matches_type(MemoryListResponse, memory, path=["response"])
@pytest.mark.skip()
@parametrize
async def test_raw_response_list(self, async_client: AsyncSupermemory) -> None:
- response = await async_client.memories.with_raw_response.list(
- "id",
- )
+ response = await async_client.memories.with_raw_response.list()
assert response.is_closed is True
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
@@ -365,9 +371,7 @@ async def test_raw_response_list(self, async_client: AsyncSupermemory) -> None:
@pytest.mark.skip()
@parametrize
async def test_streaming_response_list(self, async_client: AsyncSupermemory) -> None:
- async with async_client.memories.with_streaming_response.list(
- "id",
- ) as response:
+ async with async_client.memories.with_streaming_response.list() as response:
assert not response.is_closed
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
@@ -376,14 +380,6 @@ async def test_streaming_response_list(self, async_client: AsyncSupermemory) ->
assert cast(Any, response.is_closed) is True
- @pytest.mark.skip()
- @parametrize
- async def test_path_params_list(self, async_client: AsyncSupermemory) -> None:
- with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"):
- await async_client.memories.with_raw_response.list(
- "",
- )
-
@pytest.mark.skip()
@parametrize
async def test_method_delete(self, async_client: AsyncSupermemory) -> None:
From 3e6314dba381eb65fe644941f2cca25dfcd93d3d Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Sun, 11 May 2025 14:55:19 +0000
Subject: [PATCH 14/24] feat(api): manual updates
---
.stats.yml | 4 +--
api.md | 2 +-
src/supermemory/resources/memories.py | 20 +++++------
src/supermemory/types/memory_update_params.py | 2 --
tests/api_resources/test_memories.py | 34 +++++++------------
5 files changed, 23 insertions(+), 39 deletions(-)
diff --git a/.stats.yml b/.stats.yml
index 45b7a90b..9bf150d2 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
configured_endpoints: 11
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/supermemory--inc%2Fsupermemory-9f6d4050800c7cde90cbc3d1b59c782955e3cc1f73790c13a1924a000e09ec14.yml
-openapi_spec_hash: 92739eccad02248cc2bf07874e299fec
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/supermemory--inc%2Fsupermemory-0293efeddbd48f43b5336c0d87e7862d61de0ad5b5da8c3c17f93da5d8a8edca.yml
+openapi_spec_hash: e94bf330ad1fa4adeea8533abed19be8
config_hash: 3a000ea344f2f52c50cf06452fcf52ca
diff --git a/api.md b/api.md
index 0c367901..5e185be0 100644
--- a/api.md
+++ b/api.md
@@ -14,7 +14,7 @@ from supermemory.types import (
Methods:
-- client.memories.update(path_id, \*\*params) -> MemoryUpdateResponse
+- client.memories.update(id, \*\*params) -> MemoryUpdateResponse
- client.memories.list(\*\*params) -> MemoryListResponse
- client.memories.delete(id) -> MemoryDeleteResponse
- client.memories.add(\*\*params) -> MemoryAddResponse
diff --git a/src/supermemory/resources/memories.py b/src/supermemory/resources/memories.py
index 5c050e6a..e30e6e57 100644
--- a/src/supermemory/resources/memories.py
+++ b/src/supermemory/resources/memories.py
@@ -50,9 +50,8 @@ def with_streaming_response(self) -> MemoriesResourceWithStreamingResponse:
def update(
self,
- path_id: str,
+ id: str,
*,
- body_id: str,
content: str,
container_tags: List[str] | NotGiven = NOT_GIVEN,
metadata: Dict[str, Union[str, float, bool]] | NotGiven = NOT_GIVEN,
@@ -75,13 +74,12 @@ def update(
timeout: Override the client-level default timeout for this request, in seconds
"""
- if not path_id:
- raise ValueError(f"Expected a non-empty value for `path_id` but received {path_id!r}")
+ if not id:
+ raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return self._patch(
- f"/v3/memories/{path_id}",
+ f"/v3/memories/{id}",
body=maybe_transform(
{
- "body_id": body_id,
"content": content,
"container_tags": container_tags,
"metadata": metadata,
@@ -282,9 +280,8 @@ def with_streaming_response(self) -> AsyncMemoriesResourceWithStreamingResponse:
async def update(
self,
- path_id: str,
+ id: str,
*,
- body_id: str,
content: str,
container_tags: List[str] | NotGiven = NOT_GIVEN,
metadata: Dict[str, Union[str, float, bool]] | NotGiven = NOT_GIVEN,
@@ -307,13 +304,12 @@ async def update(
timeout: Override the client-level default timeout for this request, in seconds
"""
- if not path_id:
- raise ValueError(f"Expected a non-empty value for `path_id` but received {path_id!r}")
+ if not id:
+ raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return await self._patch(
- f"/v3/memories/{path_id}",
+ f"/v3/memories/{id}",
body=await async_maybe_transform(
{
- "body_id": body_id,
"content": content,
"container_tags": container_tags,
"metadata": metadata,
diff --git a/src/supermemory/types/memory_update_params.py b/src/supermemory/types/memory_update_params.py
index adceb6e0..2e94bfe3 100644
--- a/src/supermemory/types/memory_update_params.py
+++ b/src/supermemory/types/memory_update_params.py
@@ -11,8 +11,6 @@
class MemoryUpdateParams(TypedDict, total=False):
- body_id: Required[Annotated[str, PropertyInfo(alias="id")]]
-
content: Required[str]
container_tags: Annotated[List[str], PropertyInfo(alias="containerTags")]
diff --git a/tests/api_resources/test_memories.py b/tests/api_resources/test_memories.py
index 228dcf39..239662c5 100644
--- a/tests/api_resources/test_memories.py
+++ b/tests/api_resources/test_memories.py
@@ -27,8 +27,7 @@ class TestMemories:
@parametrize
def test_method_update(self, client: Supermemory) -> None:
memory = client.memories.update(
- path_id="id",
- body_id="acxV5LHMEsG2hMSNb4umbn",
+ id="id",
content="This is a detailed article about machine learning concepts...",
)
assert_matches_type(MemoryUpdateResponse, memory, path=["response"])
@@ -37,8 +36,7 @@ def test_method_update(self, client: Supermemory) -> None:
@parametrize
def test_method_update_with_all_params(self, client: Supermemory) -> None:
memory = client.memories.update(
- path_id="id",
- body_id="acxV5LHMEsG2hMSNb4umbn",
+ id="id",
content="This is a detailed article about machine learning concepts...",
container_tags=["string"],
metadata={
@@ -56,8 +54,7 @@ def test_method_update_with_all_params(self, client: Supermemory) -> None:
@parametrize
def test_raw_response_update(self, client: Supermemory) -> None:
response = client.memories.with_raw_response.update(
- path_id="id",
- body_id="acxV5LHMEsG2hMSNb4umbn",
+ id="id",
content="This is a detailed article about machine learning concepts...",
)
@@ -70,8 +67,7 @@ def test_raw_response_update(self, client: Supermemory) -> None:
@parametrize
def test_streaming_response_update(self, client: Supermemory) -> None:
with client.memories.with_streaming_response.update(
- path_id="id",
- body_id="acxV5LHMEsG2hMSNb4umbn",
+ id="id",
content="This is a detailed article about machine learning concepts...",
) as response:
assert not response.is_closed
@@ -85,10 +81,9 @@ def test_streaming_response_update(self, client: Supermemory) -> None:
@pytest.mark.skip()
@parametrize
def test_path_params_update(self, client: Supermemory) -> None:
- with pytest.raises(ValueError, match=r"Expected a non-empty value for `path_id` but received ''"):
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"):
client.memories.with_raw_response.update(
- path_id="",
- body_id="acxV5LHMEsG2hMSNb4umbn",
+ id="",
content="This is a detailed article about machine learning concepts...",
)
@@ -275,8 +270,7 @@ class TestAsyncMemories:
@parametrize
async def test_method_update(self, async_client: AsyncSupermemory) -> None:
memory = await async_client.memories.update(
- path_id="id",
- body_id="acxV5LHMEsG2hMSNb4umbn",
+ id="id",
content="This is a detailed article about machine learning concepts...",
)
assert_matches_type(MemoryUpdateResponse, memory, path=["response"])
@@ -285,8 +279,7 @@ async def test_method_update(self, async_client: AsyncSupermemory) -> None:
@parametrize
async def test_method_update_with_all_params(self, async_client: AsyncSupermemory) -> None:
memory = await async_client.memories.update(
- path_id="id",
- body_id="acxV5LHMEsG2hMSNb4umbn",
+ id="id",
content="This is a detailed article about machine learning concepts...",
container_tags=["string"],
metadata={
@@ -304,8 +297,7 @@ async def test_method_update_with_all_params(self, async_client: AsyncSupermemor
@parametrize
async def test_raw_response_update(self, async_client: AsyncSupermemory) -> None:
response = await async_client.memories.with_raw_response.update(
- path_id="id",
- body_id="acxV5LHMEsG2hMSNb4umbn",
+ id="id",
content="This is a detailed article about machine learning concepts...",
)
@@ -318,8 +310,7 @@ async def test_raw_response_update(self, async_client: AsyncSupermemory) -> None
@parametrize
async def test_streaming_response_update(self, async_client: AsyncSupermemory) -> None:
async with async_client.memories.with_streaming_response.update(
- path_id="id",
- body_id="acxV5LHMEsG2hMSNb4umbn",
+ id="id",
content="This is a detailed article about machine learning concepts...",
) as response:
assert not response.is_closed
@@ -333,10 +324,9 @@ async def test_streaming_response_update(self, async_client: AsyncSupermemory) -
@pytest.mark.skip()
@parametrize
async def test_path_params_update(self, async_client: AsyncSupermemory) -> None:
- with pytest.raises(ValueError, match=r"Expected a non-empty value for `path_id` but received ''"):
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"):
await async_client.memories.with_raw_response.update(
- path_id="",
- body_id="acxV5LHMEsG2hMSNb4umbn",
+ id="",
content="This is a detailed article about machine learning concepts...",
)
From 820350b366310d13abf48604196592b3e1d5c758 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Sun, 11 May 2025 15:11:52 +0000
Subject: [PATCH 15/24] codegen metadata
---
.stats.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.stats.yml b/.stats.yml
index 9bf150d2..7cbd8a40 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
configured_endpoints: 11
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/supermemory--inc%2Fsupermemory-0293efeddbd48f43b5336c0d87e7862d61de0ad5b5da8c3c17f93da5d8a8edca.yml
openapi_spec_hash: e94bf330ad1fa4adeea8533abed19be8
-config_hash: 3a000ea344f2f52c50cf06452fcf52ca
+config_hash: 26d0d4c1d69982549448a1e030e54663
From 7a81e8027fd0c76041672c71345e18724e71c10f Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Sun, 11 May 2025 15:17:05 +0000
Subject: [PATCH 16/24] feat(api): api update
---
.stats.yml | 8 +-
api.md | 2 -
src/supermemory/resources/memories.py | 103 +-------------
src/supermemory/types/__init__.py | 2 -
.../types/connection_create_response.py | 6 +-
src/supermemory/types/memory_update_params.py | 18 ---
.../types/memory_update_response.py | 11 --
tests/api_resources/test_memories.py | 129 ------------------
8 files changed, 7 insertions(+), 272 deletions(-)
delete mode 100644 src/supermemory/types/memory_update_params.py
delete mode 100644 src/supermemory/types/memory_update_response.py
diff --git a/.stats.yml b/.stats.yml
index 7cbd8a40..a0e7cabb 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
-configured_endpoints: 11
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/supermemory--inc%2Fsupermemory-0293efeddbd48f43b5336c0d87e7862d61de0ad5b5da8c3c17f93da5d8a8edca.yml
-openapi_spec_hash: e94bf330ad1fa4adeea8533abed19be8
-config_hash: 26d0d4c1d69982549448a1e030e54663
+configured_endpoints: 10
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/supermemory--inc%2Fsupermemory-3fa2583744becce1e91ec5ad18f45d2cf17778def3a8f70537a15b08c746c2fb.yml
+openapi_spec_hash: bf3c5827e7ddb8b32435aeb671fe7845
+config_hash: c8c1f2b0d63387d621f0cf066ae3379f
diff --git a/api.md b/api.md
index 5e185be0..8878df76 100644
--- a/api.md
+++ b/api.md
@@ -4,7 +4,6 @@ Types:
```python
from supermemory.types import (
- MemoryUpdateResponse,
MemoryListResponse,
MemoryDeleteResponse,
MemoryAddResponse,
@@ -14,7 +13,6 @@ from supermemory.types import (
Methods:
-- client.memories.update(id, \*\*params) -> MemoryUpdateResponse
- client.memories.list(\*\*params) -> MemoryListResponse
- client.memories.delete(id) -> MemoryDeleteResponse
- client.memories.add(\*\*params) -> MemoryAddResponse
diff --git a/src/supermemory/resources/memories.py b/src/supermemory/resources/memories.py
index e30e6e57..517c98ee 100644
--- a/src/supermemory/resources/memories.py
+++ b/src/supermemory/resources/memories.py
@@ -7,7 +7,7 @@
import httpx
-from ..types import memory_add_params, memory_list_params, memory_update_params
+from ..types import memory_add_params, memory_list_params
from .._types import NOT_GIVEN, Body, Query, Headers, NotGiven
from .._utils import maybe_transform, async_maybe_transform
from .._compat import cached_property
@@ -23,7 +23,6 @@
from ..types.memory_get_response import MemoryGetResponse
from ..types.memory_list_response import MemoryListResponse
from ..types.memory_delete_response import MemoryDeleteResponse
-from ..types.memory_update_response import MemoryUpdateResponse
__all__ = ["MemoriesResource", "AsyncMemoriesResource"]
@@ -48,50 +47,6 @@ def with_streaming_response(self) -> MemoriesResourceWithStreamingResponse:
"""
return MemoriesResourceWithStreamingResponse(self)
- def update(
- self,
- id: str,
- *,
- content: str,
- container_tags: List[str] | NotGiven = NOT_GIVEN,
- metadata: Dict[str, Union[str, float, bool]] | NotGiven = NOT_GIVEN,
- # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
- # The extra values given here take precedence over values defined on the client or passed to this method.
- extra_headers: Headers | None = None,
- extra_query: Query | None = None,
- extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
- ) -> MemoryUpdateResponse:
- """
- Update a memory with any content type (text, url, file, etc.) and metadata
-
- Args:
- extra_headers: Send extra headers
-
- extra_query: Add additional query parameters to the request
-
- extra_body: Add additional JSON properties to the request
-
- timeout: Override the client-level default timeout for this request, in seconds
- """
- if not id:
- raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
- return self._patch(
- f"/v3/memories/{id}",
- body=maybe_transform(
- {
- "content": content,
- "container_tags": container_tags,
- "metadata": metadata,
- },
- memory_update_params.MemoryUpdateParams,
- ),
- options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
- ),
- cast_to=MemoryUpdateResponse,
- )
-
def list(
self,
*,
@@ -278,50 +233,6 @@ def with_streaming_response(self) -> AsyncMemoriesResourceWithStreamingResponse:
"""
return AsyncMemoriesResourceWithStreamingResponse(self)
- async def update(
- self,
- id: str,
- *,
- content: str,
- container_tags: List[str] | NotGiven = NOT_GIVEN,
- metadata: Dict[str, Union[str, float, bool]] | NotGiven = NOT_GIVEN,
- # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
- # The extra values given here take precedence over values defined on the client or passed to this method.
- extra_headers: Headers | None = None,
- extra_query: Query | None = None,
- extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
- ) -> MemoryUpdateResponse:
- """
- Update a memory with any content type (text, url, file, etc.) and metadata
-
- Args:
- extra_headers: Send extra headers
-
- extra_query: Add additional query parameters to the request
-
- extra_body: Add additional JSON properties to the request
-
- timeout: Override the client-level default timeout for this request, in seconds
- """
- if not id:
- raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
- return await self._patch(
- f"/v3/memories/{id}",
- body=await async_maybe_transform(
- {
- "content": content,
- "container_tags": container_tags,
- "metadata": metadata,
- },
- memory_update_params.MemoryUpdateParams,
- ),
- options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
- ),
- cast_to=MemoryUpdateResponse,
- )
-
async def list(
self,
*,
@@ -492,9 +403,6 @@ class MemoriesResourceWithRawResponse:
def __init__(self, memories: MemoriesResource) -> None:
self._memories = memories
- self.update = to_raw_response_wrapper(
- memories.update,
- )
self.list = to_raw_response_wrapper(
memories.list,
)
@@ -513,9 +421,6 @@ class AsyncMemoriesResourceWithRawResponse:
def __init__(self, memories: AsyncMemoriesResource) -> None:
self._memories = memories
- self.update = async_to_raw_response_wrapper(
- memories.update,
- )
self.list = async_to_raw_response_wrapper(
memories.list,
)
@@ -534,9 +439,6 @@ class MemoriesResourceWithStreamingResponse:
def __init__(self, memories: MemoriesResource) -> None:
self._memories = memories
- self.update = to_streamed_response_wrapper(
- memories.update,
- )
self.list = to_streamed_response_wrapper(
memories.list,
)
@@ -555,9 +457,6 @@ class AsyncMemoriesResourceWithStreamingResponse:
def __init__(self, memories: AsyncMemoriesResource) -> None:
self._memories = memories
- self.update = async_to_streamed_response_wrapper(
- memories.update,
- )
self.list = async_to_streamed_response_wrapper(
memories.list,
)
diff --git a/src/supermemory/types/__init__.py b/src/supermemory/types/__init__.py
index 2545ab27..b0199e6a 100644
--- a/src/supermemory/types/__init__.py
+++ b/src/supermemory/types/__init__.py
@@ -7,12 +7,10 @@
from .memory_add_response import MemoryAddResponse as MemoryAddResponse
from .memory_get_response import MemoryGetResponse as MemoryGetResponse
from .memory_list_response import MemoryListResponse as MemoryListResponse
-from .memory_update_params import MemoryUpdateParams as MemoryUpdateParams
from .setting_get_response import SettingGetResponse as SettingGetResponse
from .search_execute_params import SearchExecuteParams as SearchExecuteParams
from .setting_update_params import SettingUpdateParams as SettingUpdateParams
from .memory_delete_response import MemoryDeleteResponse as MemoryDeleteResponse
-from .memory_update_response import MemoryUpdateResponse as MemoryUpdateResponse
from .connection_get_response import ConnectionGetResponse as ConnectionGetResponse
from .search_execute_response import SearchExecuteResponse as SearchExecuteResponse
from .setting_update_response import SettingUpdateResponse as SettingUpdateResponse
diff --git a/src/supermemory/types/connection_create_response.py b/src/supermemory/types/connection_create_response.py
index d8b52e4c..d27a6fab 100644
--- a/src/supermemory/types/connection_create_response.py
+++ b/src/supermemory/types/connection_create_response.py
@@ -8,8 +8,6 @@
class ConnectionCreateResponse(BaseModel):
- id: str
-
- auth_link: str = FieldInfo(alias="authLink")
-
expires_in: str = FieldInfo(alias="expiresIn")
+
+ magic_link: str = FieldInfo(alias="magicLink")
diff --git a/src/supermemory/types/memory_update_params.py b/src/supermemory/types/memory_update_params.py
deleted file mode 100644
index 2e94bfe3..00000000
--- a/src/supermemory/types/memory_update_params.py
+++ /dev/null
@@ -1,18 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from __future__ import annotations
-
-from typing import Dict, List, Union
-from typing_extensions import Required, Annotated, TypedDict
-
-from .._utils import PropertyInfo
-
-__all__ = ["MemoryUpdateParams"]
-
-
-class MemoryUpdateParams(TypedDict, total=False):
- content: Required[str]
-
- container_tags: Annotated[List[str], PropertyInfo(alias="containerTags")]
-
- metadata: Dict[str, Union[str, float, bool]]
diff --git a/src/supermemory/types/memory_update_response.py b/src/supermemory/types/memory_update_response.py
deleted file mode 100644
index 132b8cf9..00000000
--- a/src/supermemory/types/memory_update_response.py
+++ /dev/null
@@ -1,11 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from .._models import BaseModel
-
-__all__ = ["MemoryUpdateResponse"]
-
-
-class MemoryUpdateResponse(BaseModel):
- id: str
-
- status: str
diff --git a/tests/api_resources/test_memories.py b/tests/api_resources/test_memories.py
index 239662c5..7b3105cb 100644
--- a/tests/api_resources/test_memories.py
+++ b/tests/api_resources/test_memories.py
@@ -14,7 +14,6 @@
MemoryGetResponse,
MemoryListResponse,
MemoryDeleteResponse,
- MemoryUpdateResponse,
)
base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
@@ -23,70 +22,6 @@
class TestMemories:
parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"])
- @pytest.mark.skip()
- @parametrize
- def test_method_update(self, client: Supermemory) -> None:
- memory = client.memories.update(
- id="id",
- content="This is a detailed article about machine learning concepts...",
- )
- assert_matches_type(MemoryUpdateResponse, memory, path=["response"])
-
- @pytest.mark.skip()
- @parametrize
- def test_method_update_with_all_params(self, client: Supermemory) -> None:
- memory = client.memories.update(
- id="id",
- content="This is a detailed article about machine learning concepts...",
- container_tags=["string"],
- metadata={
- "source": "web",
- "category": "technology",
- "tag_1": "ai",
- "tag_2": "machine-learning",
- "readingTime": 5,
- "isPublic": True,
- },
- )
- assert_matches_type(MemoryUpdateResponse, memory, path=["response"])
-
- @pytest.mark.skip()
- @parametrize
- def test_raw_response_update(self, client: Supermemory) -> None:
- response = client.memories.with_raw_response.update(
- id="id",
- content="This is a detailed article about machine learning concepts...",
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- memory = response.parse()
- assert_matches_type(MemoryUpdateResponse, memory, path=["response"])
-
- @pytest.mark.skip()
- @parametrize
- def test_streaming_response_update(self, client: Supermemory) -> None:
- with client.memories.with_streaming_response.update(
- id="id",
- content="This is a detailed article about machine learning concepts...",
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- memory = response.parse()
- assert_matches_type(MemoryUpdateResponse, memory, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip()
- @parametrize
- def test_path_params_update(self, client: Supermemory) -> None:
- with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"):
- client.memories.with_raw_response.update(
- id="",
- content="This is a detailed article about machine learning concepts...",
- )
-
@pytest.mark.skip()
@parametrize
def test_method_list(self, client: Supermemory) -> None:
@@ -266,70 +201,6 @@ def test_path_params_get(self, client: Supermemory) -> None:
class TestAsyncMemories:
parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"])
- @pytest.mark.skip()
- @parametrize
- async def test_method_update(self, async_client: AsyncSupermemory) -> None:
- memory = await async_client.memories.update(
- id="id",
- content="This is a detailed article about machine learning concepts...",
- )
- assert_matches_type(MemoryUpdateResponse, memory, path=["response"])
-
- @pytest.mark.skip()
- @parametrize
- async def test_method_update_with_all_params(self, async_client: AsyncSupermemory) -> None:
- memory = await async_client.memories.update(
- id="id",
- content="This is a detailed article about machine learning concepts...",
- container_tags=["string"],
- metadata={
- "source": "web",
- "category": "technology",
- "tag_1": "ai",
- "tag_2": "machine-learning",
- "readingTime": 5,
- "isPublic": True,
- },
- )
- assert_matches_type(MemoryUpdateResponse, memory, path=["response"])
-
- @pytest.mark.skip()
- @parametrize
- async def test_raw_response_update(self, async_client: AsyncSupermemory) -> None:
- response = await async_client.memories.with_raw_response.update(
- id="id",
- content="This is a detailed article about machine learning concepts...",
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- memory = await response.parse()
- assert_matches_type(MemoryUpdateResponse, memory, path=["response"])
-
- @pytest.mark.skip()
- @parametrize
- async def test_streaming_response_update(self, async_client: AsyncSupermemory) -> None:
- async with async_client.memories.with_streaming_response.update(
- id="id",
- content="This is a detailed article about machine learning concepts...",
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- memory = await response.parse()
- assert_matches_type(MemoryUpdateResponse, memory, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip()
- @parametrize
- async def test_path_params_update(self, async_client: AsyncSupermemory) -> None:
- with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"):
- await async_client.memories.with_raw_response.update(
- id="",
- content="This is a detailed article about machine learning concepts...",
- )
-
@pytest.mark.skip()
@parametrize
async def test_method_list(self, async_client: AsyncSupermemory) -> None:
From 063cf45fced039b32de6f00fc4862a873d50451a Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Mon, 12 May 2025 17:17:08 +0000
Subject: [PATCH 17/24] feat(api): api update
---
.stats.yml | 6 +-
api.md | 2 +
src/supermemory/resources/memories.py | 103 +++++++++++++-
src/supermemory/types/__init__.py | 2 +
.../types/connection_create_response.py | 6 +-
src/supermemory/types/memory_update_params.py | 18 +++
.../types/memory_update_response.py | 11 ++
tests/api_resources/test_memories.py | 129 ++++++++++++++++++
8 files changed, 271 insertions(+), 6 deletions(-)
create mode 100644 src/supermemory/types/memory_update_params.py
create mode 100644 src/supermemory/types/memory_update_response.py
diff --git a/.stats.yml b/.stats.yml
index a0e7cabb..213ca130 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
-configured_endpoints: 10
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/supermemory--inc%2Fsupermemory-3fa2583744becce1e91ec5ad18f45d2cf17778def3a8f70537a15b08c746c2fb.yml
-openapi_spec_hash: bf3c5827e7ddb8b32435aeb671fe7845
+configured_endpoints: 11
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/supermemory--inc%2Fsupermemory-7db7d7a82f3e3d16db6481789ab9d65a18481ed036db6fcc1ef993f4a3e0e255.yml
+openapi_spec_hash: 3a969e6bf3d693c02ba142fcd8e64dd8
config_hash: c8c1f2b0d63387d621f0cf066ae3379f
diff --git a/api.md b/api.md
index 8878df76..5e185be0 100644
--- a/api.md
+++ b/api.md
@@ -4,6 +4,7 @@ Types:
```python
from supermemory.types import (
+ MemoryUpdateResponse,
MemoryListResponse,
MemoryDeleteResponse,
MemoryAddResponse,
@@ -13,6 +14,7 @@ from supermemory.types import (
Methods:
+- client.memories.update(id, \*\*params) -> MemoryUpdateResponse
- client.memories.list(\*\*params) -> MemoryListResponse
- client.memories.delete(id) -> MemoryDeleteResponse
- client.memories.add(\*\*params) -> MemoryAddResponse
diff --git a/src/supermemory/resources/memories.py b/src/supermemory/resources/memories.py
index 517c98ee..e30e6e57 100644
--- a/src/supermemory/resources/memories.py
+++ b/src/supermemory/resources/memories.py
@@ -7,7 +7,7 @@
import httpx
-from ..types import memory_add_params, memory_list_params
+from ..types import memory_add_params, memory_list_params, memory_update_params
from .._types import NOT_GIVEN, Body, Query, Headers, NotGiven
from .._utils import maybe_transform, async_maybe_transform
from .._compat import cached_property
@@ -23,6 +23,7 @@
from ..types.memory_get_response import MemoryGetResponse
from ..types.memory_list_response import MemoryListResponse
from ..types.memory_delete_response import MemoryDeleteResponse
+from ..types.memory_update_response import MemoryUpdateResponse
__all__ = ["MemoriesResource", "AsyncMemoriesResource"]
@@ -47,6 +48,50 @@ def with_streaming_response(self) -> MemoriesResourceWithStreamingResponse:
"""
return MemoriesResourceWithStreamingResponse(self)
+ def update(
+ self,
+ id: str,
+ *,
+ content: str,
+ container_tags: List[str] | NotGiven = NOT_GIVEN,
+ metadata: Dict[str, Union[str, float, bool]] | NotGiven = NOT_GIVEN,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+ ) -> MemoryUpdateResponse:
+ """
+ Update a memory with any content type (text, url, file, etc.) and metadata
+
+ Args:
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
+ if not id:
+ raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
+ return self._patch(
+ f"/v3/memories/{id}",
+ body=maybe_transform(
+ {
+ "content": content,
+ "container_tags": container_tags,
+ "metadata": metadata,
+ },
+ memory_update_params.MemoryUpdateParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=MemoryUpdateResponse,
+ )
+
def list(
self,
*,
@@ -233,6 +278,50 @@ def with_streaming_response(self) -> AsyncMemoriesResourceWithStreamingResponse:
"""
return AsyncMemoriesResourceWithStreamingResponse(self)
+ async def update(
+ self,
+ id: str,
+ *,
+ content: str,
+ container_tags: List[str] | NotGiven = NOT_GIVEN,
+ metadata: Dict[str, Union[str, float, bool]] | NotGiven = NOT_GIVEN,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+ ) -> MemoryUpdateResponse:
+ """
+ Update a memory with any content type (text, url, file, etc.) and metadata
+
+ Args:
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
+ if not id:
+ raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
+ return await self._patch(
+ f"/v3/memories/{id}",
+ body=await async_maybe_transform(
+ {
+ "content": content,
+ "container_tags": container_tags,
+ "metadata": metadata,
+ },
+ memory_update_params.MemoryUpdateParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=MemoryUpdateResponse,
+ )
+
async def list(
self,
*,
@@ -403,6 +492,9 @@ class MemoriesResourceWithRawResponse:
def __init__(self, memories: MemoriesResource) -> None:
self._memories = memories
+ self.update = to_raw_response_wrapper(
+ memories.update,
+ )
self.list = to_raw_response_wrapper(
memories.list,
)
@@ -421,6 +513,9 @@ class AsyncMemoriesResourceWithRawResponse:
def __init__(self, memories: AsyncMemoriesResource) -> None:
self._memories = memories
+ self.update = async_to_raw_response_wrapper(
+ memories.update,
+ )
self.list = async_to_raw_response_wrapper(
memories.list,
)
@@ -439,6 +534,9 @@ class MemoriesResourceWithStreamingResponse:
def __init__(self, memories: MemoriesResource) -> None:
self._memories = memories
+ self.update = to_streamed_response_wrapper(
+ memories.update,
+ )
self.list = to_streamed_response_wrapper(
memories.list,
)
@@ -457,6 +555,9 @@ class AsyncMemoriesResourceWithStreamingResponse:
def __init__(self, memories: AsyncMemoriesResource) -> None:
self._memories = memories
+ self.update = async_to_streamed_response_wrapper(
+ memories.update,
+ )
self.list = async_to_streamed_response_wrapper(
memories.list,
)
diff --git a/src/supermemory/types/__init__.py b/src/supermemory/types/__init__.py
index b0199e6a..2545ab27 100644
--- a/src/supermemory/types/__init__.py
+++ b/src/supermemory/types/__init__.py
@@ -7,10 +7,12 @@
from .memory_add_response import MemoryAddResponse as MemoryAddResponse
from .memory_get_response import MemoryGetResponse as MemoryGetResponse
from .memory_list_response import MemoryListResponse as MemoryListResponse
+from .memory_update_params import MemoryUpdateParams as MemoryUpdateParams
from .setting_get_response import SettingGetResponse as SettingGetResponse
from .search_execute_params import SearchExecuteParams as SearchExecuteParams
from .setting_update_params import SettingUpdateParams as SettingUpdateParams
from .memory_delete_response import MemoryDeleteResponse as MemoryDeleteResponse
+from .memory_update_response import MemoryUpdateResponse as MemoryUpdateResponse
from .connection_get_response import ConnectionGetResponse as ConnectionGetResponse
from .search_execute_response import SearchExecuteResponse as SearchExecuteResponse
from .setting_update_response import SettingUpdateResponse as SettingUpdateResponse
diff --git a/src/supermemory/types/connection_create_response.py b/src/supermemory/types/connection_create_response.py
index d27a6fab..d8b52e4c 100644
--- a/src/supermemory/types/connection_create_response.py
+++ b/src/supermemory/types/connection_create_response.py
@@ -8,6 +8,8 @@
class ConnectionCreateResponse(BaseModel):
- expires_in: str = FieldInfo(alias="expiresIn")
+ id: str
+
+ auth_link: str = FieldInfo(alias="authLink")
- magic_link: str = FieldInfo(alias="magicLink")
+ expires_in: str = FieldInfo(alias="expiresIn")
diff --git a/src/supermemory/types/memory_update_params.py b/src/supermemory/types/memory_update_params.py
new file mode 100644
index 00000000..2e94bfe3
--- /dev/null
+++ b/src/supermemory/types/memory_update_params.py
@@ -0,0 +1,18 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Dict, List, Union
+from typing_extensions import Required, Annotated, TypedDict
+
+from .._utils import PropertyInfo
+
+__all__ = ["MemoryUpdateParams"]
+
+
+class MemoryUpdateParams(TypedDict, total=False):
+ content: Required[str]
+
+ container_tags: Annotated[List[str], PropertyInfo(alias="containerTags")]
+
+ metadata: Dict[str, Union[str, float, bool]]
diff --git a/src/supermemory/types/memory_update_response.py b/src/supermemory/types/memory_update_response.py
new file mode 100644
index 00000000..132b8cf9
--- /dev/null
+++ b/src/supermemory/types/memory_update_response.py
@@ -0,0 +1,11 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from .._models import BaseModel
+
+__all__ = ["MemoryUpdateResponse"]
+
+
+class MemoryUpdateResponse(BaseModel):
+ id: str
+
+ status: str
diff --git a/tests/api_resources/test_memories.py b/tests/api_resources/test_memories.py
index 7b3105cb..239662c5 100644
--- a/tests/api_resources/test_memories.py
+++ b/tests/api_resources/test_memories.py
@@ -14,6 +14,7 @@
MemoryGetResponse,
MemoryListResponse,
MemoryDeleteResponse,
+ MemoryUpdateResponse,
)
base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
@@ -22,6 +23,70 @@
class TestMemories:
parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"])
+ @pytest.mark.skip()
+ @parametrize
+ def test_method_update(self, client: Supermemory) -> None:
+ memory = client.memories.update(
+ id="id",
+ content="This is a detailed article about machine learning concepts...",
+ )
+ assert_matches_type(MemoryUpdateResponse, memory, path=["response"])
+
+ @pytest.mark.skip()
+ @parametrize
+ def test_method_update_with_all_params(self, client: Supermemory) -> None:
+ memory = client.memories.update(
+ id="id",
+ content="This is a detailed article about machine learning concepts...",
+ container_tags=["string"],
+ metadata={
+ "source": "web",
+ "category": "technology",
+ "tag_1": "ai",
+ "tag_2": "machine-learning",
+ "readingTime": 5,
+ "isPublic": True,
+ },
+ )
+ assert_matches_type(MemoryUpdateResponse, memory, path=["response"])
+
+ @pytest.mark.skip()
+ @parametrize
+ def test_raw_response_update(self, client: Supermemory) -> None:
+ response = client.memories.with_raw_response.update(
+ id="id",
+ content="This is a detailed article about machine learning concepts...",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ memory = response.parse()
+ assert_matches_type(MemoryUpdateResponse, memory, path=["response"])
+
+ @pytest.mark.skip()
+ @parametrize
+ def test_streaming_response_update(self, client: Supermemory) -> None:
+ with client.memories.with_streaming_response.update(
+ id="id",
+ content="This is a detailed article about machine learning concepts...",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ memory = response.parse()
+ assert_matches_type(MemoryUpdateResponse, memory, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip()
+ @parametrize
+ def test_path_params_update(self, client: Supermemory) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"):
+ client.memories.with_raw_response.update(
+ id="",
+ content="This is a detailed article about machine learning concepts...",
+ )
+
@pytest.mark.skip()
@parametrize
def test_method_list(self, client: Supermemory) -> None:
@@ -201,6 +266,70 @@ def test_path_params_get(self, client: Supermemory) -> None:
class TestAsyncMemories:
parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"])
+ @pytest.mark.skip()
+ @parametrize
+ async def test_method_update(self, async_client: AsyncSupermemory) -> None:
+ memory = await async_client.memories.update(
+ id="id",
+ content="This is a detailed article about machine learning concepts...",
+ )
+ assert_matches_type(MemoryUpdateResponse, memory, path=["response"])
+
+ @pytest.mark.skip()
+ @parametrize
+ async def test_method_update_with_all_params(self, async_client: AsyncSupermemory) -> None:
+ memory = await async_client.memories.update(
+ id="id",
+ content="This is a detailed article about machine learning concepts...",
+ container_tags=["string"],
+ metadata={
+ "source": "web",
+ "category": "technology",
+ "tag_1": "ai",
+ "tag_2": "machine-learning",
+ "readingTime": 5,
+ "isPublic": True,
+ },
+ )
+ assert_matches_type(MemoryUpdateResponse, memory, path=["response"])
+
+ @pytest.mark.skip()
+ @parametrize
+ async def test_raw_response_update(self, async_client: AsyncSupermemory) -> None:
+ response = await async_client.memories.with_raw_response.update(
+ id="id",
+ content="This is a detailed article about machine learning concepts...",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ memory = await response.parse()
+ assert_matches_type(MemoryUpdateResponse, memory, path=["response"])
+
+ @pytest.mark.skip()
+ @parametrize
+ async def test_streaming_response_update(self, async_client: AsyncSupermemory) -> None:
+ async with async_client.memories.with_streaming_response.update(
+ id="id",
+ content="This is a detailed article about machine learning concepts...",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ memory = await response.parse()
+ assert_matches_type(MemoryUpdateResponse, memory, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip()
+ @parametrize
+ async def test_path_params_update(self, async_client: AsyncSupermemory) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"):
+ await async_client.memories.with_raw_response.update(
+ id="",
+ content="This is a detailed article about machine learning concepts...",
+ )
+
@pytest.mark.skip()
@parametrize
async def test_method_list(self, async_client: AsyncSupermemory) -> None:
From c0150acac7ccae7e89707909d9250028fc4d5251 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Tue, 13 May 2025 16:17:09 +0000
Subject: [PATCH 18/24] feat(api): api update
---
.stats.yml | 4 +-
api.md | 4 +-
src/supermemory/resources/connections.py | 77 +++++++++++++++++--
src/supermemory/types/__init__.py | 2 +
.../types/connection_create_params.py | 18 +++++
.../types/connection_create_response.py | 4 +
.../types/connection_list_params.py | 13 ++++
src/supermemory/types/memory_list_response.py | 22 ------
tests/api_resources/test_connections.py | 56 ++++++++++++--
9 files changed, 161 insertions(+), 39 deletions(-)
create mode 100644 src/supermemory/types/connection_create_params.py
create mode 100644 src/supermemory/types/connection_list_params.py
diff --git a/.stats.yml b/.stats.yml
index 213ca130..df736b03 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
configured_endpoints: 11
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/supermemory--inc%2Fsupermemory-7db7d7a82f3e3d16db6481789ab9d65a18481ed036db6fcc1ef993f4a3e0e255.yml
-openapi_spec_hash: 3a969e6bf3d693c02ba142fcd8e64dd8
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/supermemory--inc%2Fsupermemory-17ab2bb871e55eda916736277838e3b8bbd6cec59a3681783bdc454b9c4ab958.yml
+openapi_spec_hash: 4df685b7bc763e16de83eb28da61cdf3
config_hash: c8c1f2b0d63387d621f0cf066ae3379f
diff --git a/api.md b/api.md
index 5e185be0..488b7488 100644
--- a/api.md
+++ b/api.md
@@ -59,6 +59,6 @@ from supermemory.types import (
Methods:
-- client.connections.create(provider) -> ConnectionCreateResponse
-- client.connections.list() -> ConnectionListResponse
+- client.connections.create(provider, \*\*params) -> ConnectionCreateResponse
+- client.connections.list(\*\*params) -> ConnectionListResponse
- client.connections.get(connection_id) -> ConnectionGetResponse
diff --git a/src/supermemory/resources/connections.py b/src/supermemory/resources/connections.py
index 75181a0d..dfc95e77 100644
--- a/src/supermemory/resources/connections.py
+++ b/src/supermemory/resources/connections.py
@@ -2,11 +2,14 @@
from __future__ import annotations
+from typing import Dict, Union, Optional
from typing_extensions import Literal
import httpx
+from ..types import connection_list_params, connection_create_params
from .._types import NOT_GIVEN, Body, Query, Headers, NotGiven
+from .._utils import maybe_transform, async_maybe_transform
from .._compat import cached_property
from .._resource import SyncAPIResource, AsyncAPIResource
from .._response import (
@@ -47,6 +50,9 @@ def create(
self,
provider: Literal["notion", "google-drive", "onedrive"],
*,
+ end_user_id: str | NotGiven = NOT_GIVEN,
+ redirect_url: str | NotGiven = NOT_GIVEN,
+ metadata: Optional[Dict[str, Union[str, float, bool]]] | NotGiven = NOT_GIVEN,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
# The extra values given here take precedence over values defined on the client or passed to this method.
extra_headers: Headers | None = None,
@@ -70,8 +76,19 @@ def create(
raise ValueError(f"Expected a non-empty value for `provider` but received {provider!r}")
return self._post(
f"/v3/connections/{provider}",
+ body=maybe_transform({"metadata": metadata}, connection_create_params.ConnectionCreateParams),
options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform(
+ {
+ "end_user_id": end_user_id,
+ "redirect_url": redirect_url,
+ },
+ connection_create_params.ConnectionCreateParams,
+ ),
),
cast_to=ConnectionCreateResponse,
)
@@ -79,6 +96,7 @@ def create(
def list(
self,
*,
+ end_user_id: str | NotGiven = NOT_GIVEN,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
# The extra values given here take precedence over values defined on the client or passed to this method.
extra_headers: Headers | None = None,
@@ -86,11 +104,26 @@ def list(
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
) -> ConnectionListResponse:
- """List all connections"""
+ """
+ List all connections
+
+ Args:
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
return self._get(
"/v3/connections",
options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform({"end_user_id": end_user_id}, connection_list_params.ConnectionListParams),
),
cast_to=ConnectionListResponse,
)
@@ -153,6 +186,9 @@ async def create(
self,
provider: Literal["notion", "google-drive", "onedrive"],
*,
+ end_user_id: str | NotGiven = NOT_GIVEN,
+ redirect_url: str | NotGiven = NOT_GIVEN,
+ metadata: Optional[Dict[str, Union[str, float, bool]]] | NotGiven = NOT_GIVEN,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
# The extra values given here take precedence over values defined on the client or passed to this method.
extra_headers: Headers | None = None,
@@ -176,8 +212,19 @@ async def create(
raise ValueError(f"Expected a non-empty value for `provider` but received {provider!r}")
return await self._post(
f"/v3/connections/{provider}",
+ body=await async_maybe_transform({"metadata": metadata}, connection_create_params.ConnectionCreateParams),
options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=await async_maybe_transform(
+ {
+ "end_user_id": end_user_id,
+ "redirect_url": redirect_url,
+ },
+ connection_create_params.ConnectionCreateParams,
+ ),
),
cast_to=ConnectionCreateResponse,
)
@@ -185,6 +232,7 @@ async def create(
async def list(
self,
*,
+ end_user_id: str | NotGiven = NOT_GIVEN,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
# The extra values given here take precedence over values defined on the client or passed to this method.
extra_headers: Headers | None = None,
@@ -192,11 +240,28 @@ async def list(
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
) -> ConnectionListResponse:
- """List all connections"""
+ """
+ List all connections
+
+ Args:
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
return await self._get(
"/v3/connections",
options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=await async_maybe_transform(
+ {"end_user_id": end_user_id}, connection_list_params.ConnectionListParams
+ ),
),
cast_to=ConnectionListResponse,
)
diff --git a/src/supermemory/types/__init__.py b/src/supermemory/types/__init__.py
index 2545ab27..311cce3c 100644
--- a/src/supermemory/types/__init__.py
+++ b/src/supermemory/types/__init__.py
@@ -11,10 +11,12 @@
from .setting_get_response import SettingGetResponse as SettingGetResponse
from .search_execute_params import SearchExecuteParams as SearchExecuteParams
from .setting_update_params import SettingUpdateParams as SettingUpdateParams
+from .connection_list_params import ConnectionListParams as ConnectionListParams
from .memory_delete_response import MemoryDeleteResponse as MemoryDeleteResponse
from .memory_update_response import MemoryUpdateResponse as MemoryUpdateResponse
from .connection_get_response import ConnectionGetResponse as ConnectionGetResponse
from .search_execute_response import SearchExecuteResponse as SearchExecuteResponse
from .setting_update_response import SettingUpdateResponse as SettingUpdateResponse
+from .connection_create_params import ConnectionCreateParams as ConnectionCreateParams
from .connection_list_response import ConnectionListResponse as ConnectionListResponse
from .connection_create_response import ConnectionCreateResponse as ConnectionCreateResponse
diff --git a/src/supermemory/types/connection_create_params.py b/src/supermemory/types/connection_create_params.py
new file mode 100644
index 00000000..152cbce3
--- /dev/null
+++ b/src/supermemory/types/connection_create_params.py
@@ -0,0 +1,18 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Dict, Union, Optional
+from typing_extensions import Annotated, TypedDict
+
+from .._utils import PropertyInfo
+
+__all__ = ["ConnectionCreateParams"]
+
+
+class ConnectionCreateParams(TypedDict, total=False):
+ end_user_id: Annotated[str, PropertyInfo(alias="endUserId")]
+
+ redirect_url: Annotated[str, PropertyInfo(alias="redirectUrl")]
+
+ metadata: Optional[Dict[str, Union[str, float, bool]]]
diff --git a/src/supermemory/types/connection_create_response.py b/src/supermemory/types/connection_create_response.py
index d8b52e4c..f0bf02e4 100644
--- a/src/supermemory/types/connection_create_response.py
+++ b/src/supermemory/types/connection_create_response.py
@@ -1,5 +1,7 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+from typing import Optional
+
from pydantic import Field as FieldInfo
from .._models import BaseModel
@@ -13,3 +15,5 @@ class ConnectionCreateResponse(BaseModel):
auth_link: str = FieldInfo(alias="authLink")
expires_in: str = FieldInfo(alias="expiresIn")
+
+ redirects_to: Optional[str] = FieldInfo(alias="redirectsTo", default=None)
diff --git a/src/supermemory/types/connection_list_params.py b/src/supermemory/types/connection_list_params.py
new file mode 100644
index 00000000..e027d5f1
--- /dev/null
+++ b/src/supermemory/types/connection_list_params.py
@@ -0,0 +1,13 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Annotated, TypedDict
+
+from .._utils import PropertyInfo
+
+__all__ = ["ConnectionListParams"]
+
+
+class ConnectionListParams(TypedDict, total=False):
+ end_user_id: Annotated[str, PropertyInfo(alias="endUserId")]
diff --git a/src/supermemory/types/memory_list_response.py b/src/supermemory/types/memory_list_response.py
index 5b325c78..e693ab3f 100644
--- a/src/supermemory/types/memory_list_response.py
+++ b/src/supermemory/types/memory_list_response.py
@@ -1,8 +1,6 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from typing import Dict, List, Union, Optional
-from datetime import datetime
-from typing_extensions import Literal
from pydantic import Field as FieldInfo
@@ -13,7 +11,6 @@
class Memory(BaseModel):
id: str
- """Unique identifier of the memory."""
content: Optional[str] = None
"""The content to extract and process into a memory.
@@ -27,9 +24,6 @@ class Memory(BaseModel):
We automatically detect the content type from the url's response format.
"""
- created_at: datetime = FieldInfo(alias="createdAt")
- """Creation timestamp"""
-
custom_id: Optional[str] = FieldInfo(alias="customId", default=None)
"""Optional custom ID of the memory.
@@ -49,24 +43,11 @@ class Memory(BaseModel):
source: Optional[str] = None
- status: Literal["unknown", "queued", "extracting", "chunking", "embedding", "indexing", "done", "failed"]
- """Status of the memory"""
-
summary: Optional[str] = None
- """Summary of the memory content"""
title: Optional[str] = None
"""Title of the memory"""
- type: Literal["text", "pdf", "tweet", "google_doc", "image", "video", "notion_doc", "webpage"]
- """Type of the memory"""
-
- updated_at: datetime = FieldInfo(alias="updatedAt")
- """Last update timestamp"""
-
- url: Optional[str] = None
- """URL of the memory"""
-
container_tags: Optional[List[str]] = FieldInfo(alias="containerTags", default=None)
"""Optional tags this memory should be containerized by.
@@ -74,9 +55,6 @@ class Memory(BaseModel):
to use to group memories.
"""
- raw: None = None
- """Raw content of the memory"""
-
class Pagination(BaseModel):
current_page: float = FieldInfo(alias="currentPage")
diff --git a/tests/api_resources/test_connections.py b/tests/api_resources/test_connections.py
index 4a34deed..aee15f42 100644
--- a/tests/api_resources/test_connections.py
+++ b/tests/api_resources/test_connections.py
@@ -9,7 +9,11 @@
from supermemory import Supermemory, AsyncSupermemory
from tests.utils import assert_matches_type
-from supermemory.types import ConnectionGetResponse, ConnectionListResponse, ConnectionCreateResponse
+from supermemory.types import (
+ ConnectionGetResponse,
+ ConnectionListResponse,
+ ConnectionCreateResponse,
+)
base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
@@ -21,7 +25,18 @@ class TestConnections:
@parametrize
def test_method_create(self, client: Supermemory) -> None:
connection = client.connections.create(
- "notion",
+ provider="notion",
+ )
+ assert_matches_type(ConnectionCreateResponse, connection, path=["response"])
+
+ @pytest.mark.skip()
+ @parametrize
+ def test_method_create_with_all_params(self, client: Supermemory) -> None:
+ connection = client.connections.create(
+ provider="notion",
+ end_user_id="endUserId",
+ redirect_url="redirectUrl",
+ metadata={"foo": "string"},
)
assert_matches_type(ConnectionCreateResponse, connection, path=["response"])
@@ -29,7 +44,7 @@ def test_method_create(self, client: Supermemory) -> None:
@parametrize
def test_raw_response_create(self, client: Supermemory) -> None:
response = client.connections.with_raw_response.create(
- "notion",
+ provider="notion",
)
assert response.is_closed is True
@@ -41,7 +56,7 @@ def test_raw_response_create(self, client: Supermemory) -> None:
@parametrize
def test_streaming_response_create(self, client: Supermemory) -> None:
with client.connections.with_streaming_response.create(
- "notion",
+ provider="notion",
) as response:
assert not response.is_closed
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
@@ -57,6 +72,14 @@ def test_method_list(self, client: Supermemory) -> None:
connection = client.connections.list()
assert_matches_type(ConnectionListResponse, connection, path=["response"])
+ @pytest.mark.skip()
+ @parametrize
+ def test_method_list_with_all_params(self, client: Supermemory) -> None:
+ connection = client.connections.list(
+ end_user_id="endUserId",
+ )
+ assert_matches_type(ConnectionListResponse, connection, path=["response"])
+
@pytest.mark.skip()
@parametrize
def test_raw_response_list(self, client: Supermemory) -> None:
@@ -129,7 +152,18 @@ class TestAsyncConnections:
@parametrize
async def test_method_create(self, async_client: AsyncSupermemory) -> None:
connection = await async_client.connections.create(
- "notion",
+ provider="notion",
+ )
+ assert_matches_type(ConnectionCreateResponse, connection, path=["response"])
+
+ @pytest.mark.skip()
+ @parametrize
+ async def test_method_create_with_all_params(self, async_client: AsyncSupermemory) -> None:
+ connection = await async_client.connections.create(
+ provider="notion",
+ end_user_id="endUserId",
+ redirect_url="redirectUrl",
+ metadata={"foo": "string"},
)
assert_matches_type(ConnectionCreateResponse, connection, path=["response"])
@@ -137,7 +171,7 @@ async def test_method_create(self, async_client: AsyncSupermemory) -> None:
@parametrize
async def test_raw_response_create(self, async_client: AsyncSupermemory) -> None:
response = await async_client.connections.with_raw_response.create(
- "notion",
+ provider="notion",
)
assert response.is_closed is True
@@ -149,7 +183,7 @@ async def test_raw_response_create(self, async_client: AsyncSupermemory) -> None
@parametrize
async def test_streaming_response_create(self, async_client: AsyncSupermemory) -> None:
async with async_client.connections.with_streaming_response.create(
- "notion",
+ provider="notion",
) as response:
assert not response.is_closed
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
@@ -165,6 +199,14 @@ async def test_method_list(self, async_client: AsyncSupermemory) -> None:
connection = await async_client.connections.list()
assert_matches_type(ConnectionListResponse, connection, path=["response"])
+ @pytest.mark.skip()
+ @parametrize
+ async def test_method_list_with_all_params(self, async_client: AsyncSupermemory) -> None:
+ connection = await async_client.connections.list(
+ end_user_id="endUserId",
+ )
+ assert_matches_type(ConnectionListResponse, connection, path=["response"])
+
@pytest.mark.skip()
@parametrize
async def test_raw_response_list(self, async_client: AsyncSupermemory) -> None:
From aaf354623319d2e3f99031669a615d3af48c9dab Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Wed, 14 May 2025 06:16:58 +0000
Subject: [PATCH 19/24] feat(api): api update
---
.stats.yml | 4 ++--
src/supermemory/types/memory_list_response.py | 22 +++++++++++++++++++
2 files changed, 24 insertions(+), 2 deletions(-)
diff --git a/.stats.yml b/.stats.yml
index df736b03..ce2647c3 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
configured_endpoints: 11
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/supermemory--inc%2Fsupermemory-17ab2bb871e55eda916736277838e3b8bbd6cec59a3681783bdc454b9c4ab958.yml
-openapi_spec_hash: 4df685b7bc763e16de83eb28da61cdf3
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/supermemory--inc%2Fsupermemory-e6735b03c258b382c527550bb78042bdc3aad32a5cf564785dcb9f3fb13a2862.yml
+openapi_spec_hash: 8168fb51314d986893554e1cc935ca7d
config_hash: c8c1f2b0d63387d621f0cf066ae3379f
diff --git a/src/supermemory/types/memory_list_response.py b/src/supermemory/types/memory_list_response.py
index e693ab3f..5b325c78 100644
--- a/src/supermemory/types/memory_list_response.py
+++ b/src/supermemory/types/memory_list_response.py
@@ -1,6 +1,8 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from typing import Dict, List, Union, Optional
+from datetime import datetime
+from typing_extensions import Literal
from pydantic import Field as FieldInfo
@@ -11,6 +13,7 @@
class Memory(BaseModel):
id: str
+ """Unique identifier of the memory."""
content: Optional[str] = None
"""The content to extract and process into a memory.
@@ -24,6 +27,9 @@ class Memory(BaseModel):
We automatically detect the content type from the url's response format.
"""
+ created_at: datetime = FieldInfo(alias="createdAt")
+ """Creation timestamp"""
+
custom_id: Optional[str] = FieldInfo(alias="customId", default=None)
"""Optional custom ID of the memory.
@@ -43,11 +49,24 @@ class Memory(BaseModel):
source: Optional[str] = None
+ status: Literal["unknown", "queued", "extracting", "chunking", "embedding", "indexing", "done", "failed"]
+ """Status of the memory"""
+
summary: Optional[str] = None
+ """Summary of the memory content"""
title: Optional[str] = None
"""Title of the memory"""
+ type: Literal["text", "pdf", "tweet", "google_doc", "image", "video", "notion_doc", "webpage"]
+ """Type of the memory"""
+
+ updated_at: datetime = FieldInfo(alias="updatedAt")
+ """Last update timestamp"""
+
+ url: Optional[str] = None
+ """URL of the memory"""
+
container_tags: Optional[List[str]] = FieldInfo(alias="containerTags", default=None)
"""Optional tags this memory should be containerized by.
@@ -55,6 +74,9 @@ class Memory(BaseModel):
to use to group memories.
"""
+ raw: None = None
+ """Raw content of the memory"""
+
class Pagination(BaseModel):
current_page: float = FieldInfo(alias="currentPage")
From a327d7ddd1836e1a15b30eb5fb33388fe2580229 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Thu, 15 May 2025 03:05:06 +0000
Subject: [PATCH 20/24] chore(ci): upload sdks to package manager
---
.github/workflows/ci.yml | 24 ++++++++++++++++++++++++
scripts/utils/upload-artifact.sh | 25 +++++++++++++++++++++++++
2 files changed, 49 insertions(+)
create mode 100755 scripts/utils/upload-artifact.sh
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 921b479f..71338782 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -30,6 +30,30 @@ jobs:
- name: Run lints
run: ./scripts/lint
+ upload:
+ if: github.repository == 'stainless-sdks/supermemory-python'
+ timeout-minutes: 10
+ name: upload
+ permissions:
+ contents: read
+ id-token: write
+ runs-on: depot-ubuntu-24.04
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Get GitHub OIDC Token
+ id: github-oidc
+ uses: actions/github-script@v6
+ with:
+ script: core.setOutput('github_token', await core.getIDToken());
+
+ - name: Upload tarball
+ env:
+ URL: https://pkg.stainless.com/s
+ AUTH: ${{ steps.github-oidc.outputs.github_token }}
+ SHA: ${{ github.sha }}
+ run: ./scripts/utils/upload-artifact.sh
+
test:
timeout-minutes: 10
name: test
diff --git a/scripts/utils/upload-artifact.sh b/scripts/utils/upload-artifact.sh
new file mode 100755
index 00000000..280352b5
--- /dev/null
+++ b/scripts/utils/upload-artifact.sh
@@ -0,0 +1,25 @@
+#!/usr/bin/env bash
+set -exuo pipefail
+
+RESPONSE=$(curl -X POST "$URL" \
+ -H "Authorization: Bearer $AUTH" \
+ -H "Content-Type: application/json")
+
+SIGNED_URL=$(echo "$RESPONSE" | jq -r '.url')
+
+if [[ "$SIGNED_URL" == "null" ]]; then
+ echo -e "\033[31mFailed to get signed URL.\033[0m"
+ exit 1
+fi
+
+UPLOAD_RESPONSE=$(tar -cz . | curl -v -X PUT \
+ -H "Content-Type: application/gzip" \
+ --data-binary @- "$SIGNED_URL" 2>&1)
+
+if echo "$UPLOAD_RESPONSE" | grep -q "HTTP/[0-9.]* 200"; then
+ echo -e "\033[32mUploaded build to Stainless storage.\033[0m"
+ echo -e "\033[32mInstallation: npm install 'https://pkg.stainless.com/s/supermemory-python/$SHA'\033[0m"
+else
+ echo -e "\033[31mFailed to upload artifact.\033[0m"
+ exit 1
+fi
From 060e32620febdd50931ae4d6e692a527b36b99fe Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Fri, 16 May 2025 02:42:08 +0000
Subject: [PATCH 21/24] chore(ci): fix installation instructions
---
scripts/utils/upload-artifact.sh | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/scripts/utils/upload-artifact.sh b/scripts/utils/upload-artifact.sh
index 280352b5..19843b3c 100755
--- a/scripts/utils/upload-artifact.sh
+++ b/scripts/utils/upload-artifact.sh
@@ -18,7 +18,7 @@ UPLOAD_RESPONSE=$(tar -cz . | curl -v -X PUT \
if echo "$UPLOAD_RESPONSE" | grep -q "HTTP/[0-9.]* 200"; then
echo -e "\033[32mUploaded build to Stainless storage.\033[0m"
- echo -e "\033[32mInstallation: npm install 'https://pkg.stainless.com/s/supermemory-python/$SHA'\033[0m"
+ echo -e "\033[32mInstallation: pip install 'https://pkg.stainless.com/s/supermemory-python/$SHA'\033[0m"
else
echo -e "\033[31mFailed to upload artifact.\033[0m"
exit 1
From c0d13e254d08d459edc35def2c38774ce11fcd0d Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Sat, 17 May 2025 02:50:07 +0000
Subject: [PATCH 22/24] chore(internal): codegen related update
---
scripts/utils/upload-artifact.sh | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/scripts/utils/upload-artifact.sh b/scripts/utils/upload-artifact.sh
index 19843b3c..11632537 100755
--- a/scripts/utils/upload-artifact.sh
+++ b/scripts/utils/upload-artifact.sh
@@ -18,7 +18,7 @@ UPLOAD_RESPONSE=$(tar -cz . | curl -v -X PUT \
if echo "$UPLOAD_RESPONSE" | grep -q "HTTP/[0-9.]* 200"; then
echo -e "\033[32mUploaded build to Stainless storage.\033[0m"
- echo -e "\033[32mInstallation: pip install 'https://pkg.stainless.com/s/supermemory-python/$SHA'\033[0m"
+ echo -e "\033[32mInstallation: pip install --pre 'https://pkg.stainless.com/s/supermemory-python/$SHA'\033[0m"
else
echo -e "\033[31mFailed to upload artifact.\033[0m"
exit 1
From 3fd7de29691be3303c91fd89189371a0ef7845dc Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Sat, 17 May 2025 14:27:38 +0000
Subject: [PATCH 23/24] feat(api): manual updates
---
.stats.yml | 4 +-
README.md | 17 ++++
api.md | 2 +
src/supermemory/_files.py | 2 +-
src/supermemory/resources/memories.py | 99 ++++++++++++++++++-
src/supermemory/types/__init__.py | 2 +
.../types/memory_upload_file_params.py | 13 +++
.../types/memory_upload_file_response.py | 11 +++
tests/api_resources/test_memories.py | 69 +++++++++++++
9 files changed, 212 insertions(+), 7 deletions(-)
create mode 100644 src/supermemory/types/memory_upload_file_params.py
create mode 100644 src/supermemory/types/memory_upload_file_response.py
diff --git a/.stats.yml b/.stats.yml
index ce2647c3..4be06c0d 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
-configured_endpoints: 11
+configured_endpoints: 12
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/supermemory--inc%2Fsupermemory-e6735b03c258b382c527550bb78042bdc3aad32a5cf564785dcb9f3fb13a2862.yml
openapi_spec_hash: 8168fb51314d986893554e1cc935ca7d
-config_hash: c8c1f2b0d63387d621f0cf066ae3379f
+config_hash: 8477e3ee6fd596ab6ac911d052e4de79
diff --git a/README.md b/README.md
index 43bb97a0..55246cf4 100644
--- a/README.md
+++ b/README.md
@@ -77,6 +77,23 @@ Nested request parameters are [TypedDicts](https://docs.python.org/3/library/typ
Typed requests and responses provide autocomplete and documentation within your editor. If you would like to see type errors in VS Code to help catch bugs earlier, set `python.analysis.typeCheckingMode` to `basic`.
+## File uploads
+
+Request parameters that correspond to file uploads can be passed as `bytes`, or a [`PathLike`](https://docs.python.org/3/library/os.html#os.PathLike) instance or a tuple of `(filename, contents, media type)`.
+
+```python
+from pathlib import Path
+from supermemory import Supermemory
+
+client = Supermemory()
+
+client.memories.upload_file(
+ file=Path("/path/to/file"),
+)
+```
+
+The async client uses the exact same interface. If you pass a [`PathLike`](https://docs.python.org/3/library/os.html#os.PathLike) instance, the file contents will be read asynchronously automatically.
+
## Handling errors
When the library is unable to connect to the API (for example, due to network connection problems or a timeout), a subclass of `supermemory.APIConnectionError` is raised.
diff --git a/api.md b/api.md
index 488b7488..66639691 100644
--- a/api.md
+++ b/api.md
@@ -9,6 +9,7 @@ from supermemory.types import (
MemoryDeleteResponse,
MemoryAddResponse,
MemoryGetResponse,
+ MemoryUploadFileResponse,
)
```
@@ -19,6 +20,7 @@ Methods:
- client.memories.delete(id) -> MemoryDeleteResponse
- client.memories.add(\*\*params) -> MemoryAddResponse
- client.memories.get(id) -> MemoryGetResponse
+- client.memories.upload_file(\*\*params) -> MemoryUploadFileResponse
# Search
diff --git a/src/supermemory/_files.py b/src/supermemory/_files.py
index 715cc207..0dcf63d3 100644
--- a/src/supermemory/_files.py
+++ b/src/supermemory/_files.py
@@ -34,7 +34,7 @@ def assert_is_file_content(obj: object, *, key: str | None = None) -> None:
if not is_file_content(obj):
prefix = f"Expected entry at `{key}`" if key is not None else f"Expected file input `{obj!r}`"
raise RuntimeError(
- f"{prefix} to be bytes, an io.IOBase instance, PathLike or a tuple but received {type(obj)} instead."
+ f"{prefix} to be bytes, an io.IOBase instance, PathLike or a tuple but received {type(obj)} instead. See https://github.com/supermemoryai/python-sdk/tree/main#file-uploads"
) from None
diff --git a/src/supermemory/resources/memories.py b/src/supermemory/resources/memories.py
index e30e6e57..180f4cd6 100644
--- a/src/supermemory/resources/memories.py
+++ b/src/supermemory/resources/memories.py
@@ -2,14 +2,14 @@
from __future__ import annotations
-from typing import Dict, List, Union
+from typing import Dict, List, Union, Mapping, cast
from typing_extensions import Literal
import httpx
-from ..types import memory_add_params, memory_list_params, memory_update_params
-from .._types import NOT_GIVEN, Body, Query, Headers, NotGiven
-from .._utils import maybe_transform, async_maybe_transform
+from ..types import memory_add_params, memory_list_params, memory_update_params, memory_upload_file_params
+from .._types import NOT_GIVEN, Body, Query, Headers, NotGiven, FileTypes
+from .._utils import extract_files, maybe_transform, deepcopy_minimal, async_maybe_transform
from .._compat import cached_property
from .._resource import SyncAPIResource, AsyncAPIResource
from .._response import (
@@ -24,6 +24,7 @@
from ..types.memory_list_response import MemoryListResponse
from ..types.memory_delete_response import MemoryDeleteResponse
from ..types.memory_update_response import MemoryUpdateResponse
+from ..types.memory_upload_file_response import MemoryUploadFileResponse
__all__ = ["MemoriesResource", "AsyncMemoriesResource"]
@@ -257,6 +258,45 @@ def get(
cast_to=MemoryGetResponse,
)
+ def upload_file(
+ self,
+ *,
+ file: FileTypes,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+ ) -> MemoryUploadFileResponse:
+ """
+ Upload a file to be processed
+
+ Args:
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
+ body = deepcopy_minimal({"file": file})
+ files = extract_files(cast(Mapping[str, object], body), paths=[["file"]])
+ # It should be noted that the actual Content-Type header that will be
+ # sent to the server will contain a `boundary` parameter, e.g.
+ # multipart/form-data; boundary=---abc--
+ extra_headers = {"Content-Type": "multipart/form-data", **(extra_headers or {})}
+ return self._post(
+ "/v3/memories/file",
+ body=maybe_transform(body, memory_upload_file_params.MemoryUploadFileParams),
+ files=files,
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=MemoryUploadFileResponse,
+ )
+
class AsyncMemoriesResource(AsyncAPIResource):
@cached_property
@@ -487,6 +527,45 @@ async def get(
cast_to=MemoryGetResponse,
)
+ async def upload_file(
+ self,
+ *,
+ file: FileTypes,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+ ) -> MemoryUploadFileResponse:
+ """
+ Upload a file to be processed
+
+ Args:
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
+ body = deepcopy_minimal({"file": file})
+ files = extract_files(cast(Mapping[str, object], body), paths=[["file"]])
+ # It should be noted that the actual Content-Type header that will be
+ # sent to the server will contain a `boundary` parameter, e.g.
+ # multipart/form-data; boundary=---abc--
+ extra_headers = {"Content-Type": "multipart/form-data", **(extra_headers or {})}
+ return await self._post(
+ "/v3/memories/file",
+ body=await async_maybe_transform(body, memory_upload_file_params.MemoryUploadFileParams),
+ files=files,
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=MemoryUploadFileResponse,
+ )
+
class MemoriesResourceWithRawResponse:
def __init__(self, memories: MemoriesResource) -> None:
@@ -507,6 +586,9 @@ def __init__(self, memories: MemoriesResource) -> None:
self.get = to_raw_response_wrapper(
memories.get,
)
+ self.upload_file = to_raw_response_wrapper(
+ memories.upload_file,
+ )
class AsyncMemoriesResourceWithRawResponse:
@@ -528,6 +610,9 @@ def __init__(self, memories: AsyncMemoriesResource) -> None:
self.get = async_to_raw_response_wrapper(
memories.get,
)
+ self.upload_file = async_to_raw_response_wrapper(
+ memories.upload_file,
+ )
class MemoriesResourceWithStreamingResponse:
@@ -549,6 +634,9 @@ def __init__(self, memories: MemoriesResource) -> None:
self.get = to_streamed_response_wrapper(
memories.get,
)
+ self.upload_file = to_streamed_response_wrapper(
+ memories.upload_file,
+ )
class AsyncMemoriesResourceWithStreamingResponse:
@@ -570,3 +658,6 @@ def __init__(self, memories: AsyncMemoriesResource) -> None:
self.get = async_to_streamed_response_wrapper(
memories.get,
)
+ self.upload_file = async_to_streamed_response_wrapper(
+ memories.upload_file,
+ )
diff --git a/src/supermemory/types/__init__.py b/src/supermemory/types/__init__.py
index 311cce3c..2bb705ae 100644
--- a/src/supermemory/types/__init__.py
+++ b/src/supermemory/types/__init__.py
@@ -19,4 +19,6 @@
from .setting_update_response import SettingUpdateResponse as SettingUpdateResponse
from .connection_create_params import ConnectionCreateParams as ConnectionCreateParams
from .connection_list_response import ConnectionListResponse as ConnectionListResponse
+from .memory_upload_file_params import MemoryUploadFileParams as MemoryUploadFileParams
from .connection_create_response import ConnectionCreateResponse as ConnectionCreateResponse
+from .memory_upload_file_response import MemoryUploadFileResponse as MemoryUploadFileResponse
diff --git a/src/supermemory/types/memory_upload_file_params.py b/src/supermemory/types/memory_upload_file_params.py
new file mode 100644
index 00000000..aa6c082a
--- /dev/null
+++ b/src/supermemory/types/memory_upload_file_params.py
@@ -0,0 +1,13 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Required, TypedDict
+
+from .._types import FileTypes
+
+__all__ = ["MemoryUploadFileParams"]
+
+
+class MemoryUploadFileParams(TypedDict, total=False):
+ file: Required[FileTypes]
diff --git a/src/supermemory/types/memory_upload_file_response.py b/src/supermemory/types/memory_upload_file_response.py
new file mode 100644
index 00000000..f67b958f
--- /dev/null
+++ b/src/supermemory/types/memory_upload_file_response.py
@@ -0,0 +1,11 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from .._models import BaseModel
+
+__all__ = ["MemoryUploadFileResponse"]
+
+
+class MemoryUploadFileResponse(BaseModel):
+ id: str
+
+ status: str
diff --git a/tests/api_resources/test_memories.py b/tests/api_resources/test_memories.py
index 239662c5..8e7130f2 100644
--- a/tests/api_resources/test_memories.py
+++ b/tests/api_resources/test_memories.py
@@ -15,6 +15,7 @@
MemoryListResponse,
MemoryDeleteResponse,
MemoryUpdateResponse,
+ MemoryUploadFileResponse,
)
base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
@@ -262,6 +263,40 @@ def test_path_params_get(self, client: Supermemory) -> None:
"",
)
+ @pytest.mark.skip()
+ @parametrize
+ def test_method_upload_file(self, client: Supermemory) -> None:
+ memory = client.memories.upload_file(
+ file=b"raw file contents",
+ )
+ assert_matches_type(MemoryUploadFileResponse, memory, path=["response"])
+
+ @pytest.mark.skip()
+ @parametrize
+ def test_raw_response_upload_file(self, client: Supermemory) -> None:
+ response = client.memories.with_raw_response.upload_file(
+ file=b"raw file contents",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ memory = response.parse()
+ assert_matches_type(MemoryUploadFileResponse, memory, path=["response"])
+
+ @pytest.mark.skip()
+ @parametrize
+ def test_streaming_response_upload_file(self, client: Supermemory) -> None:
+ with client.memories.with_streaming_response.upload_file(
+ file=b"raw file contents",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ memory = response.parse()
+ assert_matches_type(MemoryUploadFileResponse, memory, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
class TestAsyncMemories:
parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"])
@@ -504,3 +539,37 @@ async def test_path_params_get(self, async_client: AsyncSupermemory) -> None:
await async_client.memories.with_raw_response.get(
"",
)
+
+ @pytest.mark.skip()
+ @parametrize
+ async def test_method_upload_file(self, async_client: AsyncSupermemory) -> None:
+ memory = await async_client.memories.upload_file(
+ file=b"raw file contents",
+ )
+ assert_matches_type(MemoryUploadFileResponse, memory, path=["response"])
+
+ @pytest.mark.skip()
+ @parametrize
+ async def test_raw_response_upload_file(self, async_client: AsyncSupermemory) -> None:
+ response = await async_client.memories.with_raw_response.upload_file(
+ file=b"raw file contents",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ memory = await response.parse()
+ assert_matches_type(MemoryUploadFileResponse, memory, path=["response"])
+
+ @pytest.mark.skip()
+ @parametrize
+ async def test_streaming_response_upload_file(self, async_client: AsyncSupermemory) -> None:
+ async with async_client.memories.with_streaming_response.upload_file(
+ file=b"raw file contents",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ memory = await response.parse()
+ assert_matches_type(MemoryUploadFileResponse, memory, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
From b6e9bc2317006d5cbbbcb3c41d280df74d9b7214 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Sat, 17 May 2025 14:28:47 +0000
Subject: [PATCH 24/24] release: 3.0.0-alpha.1
---
.release-please-manifest.json | 2 +-
CHANGELOG.md | 37 +++++++++++++++++++++++++++++++++++
pyproject.toml | 2 +-
src/supermemory/_version.py | 2 +-
4 files changed, 40 insertions(+), 3 deletions(-)
diff --git a/.release-please-manifest.json b/.release-please-manifest.json
index ba6c3483..2f23d818 100644
--- a/.release-please-manifest.json
+++ b/.release-please-manifest.json
@@ -1,3 +1,3 @@
{
- ".": "0.1.0-alpha.1"
+ ".": "3.0.0-alpha.1"
}
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 10dc4129..ecf6170f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,42 @@
# Changelog
+## 3.0.0-alpha.1 (2025-05-17)
+
+Full Changelog: [v0.1.0-alpha.1...v3.0.0-alpha.1](https://github.com/supermemoryai/python-sdk/compare/v0.1.0-alpha.1...v3.0.0-alpha.1)
+
+### Features
+
+* **api:** api update ([aaf3546](https://github.com/supermemoryai/python-sdk/commit/aaf354623319d2e3f99031669a615d3af48c9dab))
+* **api:** api update ([c0150ac](https://github.com/supermemoryai/python-sdk/commit/c0150acac7ccae7e89707909d9250028fc4d5251))
+* **api:** api update ([063cf45](https://github.com/supermemoryai/python-sdk/commit/063cf45fced039b32de6f00fc4862a873d50451a))
+* **api:** api update ([7a81e80](https://github.com/supermemoryai/python-sdk/commit/7a81e8027fd0c76041672c71345e18724e71c10f))
+* **api:** api update ([722df63](https://github.com/supermemoryai/python-sdk/commit/722df6387d8fc3b38ee892d4382b19339a4b8165))
+* **api:** api update ([4052bae](https://github.com/supermemoryai/python-sdk/commit/4052baeca12183552a9bda674e97310e77b93623))
+* **api:** api update ([ed787b1](https://github.com/supermemoryai/python-sdk/commit/ed787b1abd49ebbc4e219f90bf71511306aafb2b))
+* **api:** api update ([7c0db70](https://github.com/supermemoryai/python-sdk/commit/7c0db70ec61ccd64197c333592457b925782f1ce))
+* **api:** api update ([844d56e](https://github.com/supermemoryai/python-sdk/commit/844d56ecd40cffb441c47050e5e820051d65af7e))
+* **api:** api update ([fda6f9f](https://github.com/supermemoryai/python-sdk/commit/fda6f9f111dac7db4bba42779e967356b8615e3c))
+* **api:** api update ([2403f1d](https://github.com/supermemoryai/python-sdk/commit/2403f1da4d83266ddf49ada0103c8f5d432bf966))
+* **api:** manual updates ([3fd7de2](https://github.com/supermemoryai/python-sdk/commit/3fd7de29691be3303c91fd89189371a0ef7845dc))
+* **api:** manual updates ([3e6314d](https://github.com/supermemoryai/python-sdk/commit/3e6314dba381eb65fe644941f2cca25dfcd93d3d))
+* **api:** manual updates ([4a6b77a](https://github.com/supermemoryai/python-sdk/commit/4a6b77aa6cd55d7135e33cbfb1138d9b2d00d40a))
+* **api:** manual updates ([5b0c810](https://github.com/supermemoryai/python-sdk/commit/5b0c81086db77a2ea5922d117f4e393475d2bd03))
+* **api:** manual updates ([af34c01](https://github.com/supermemoryai/python-sdk/commit/af34c01553feba151893eea0f6a905078146424f))
+* **api:** manual updates ([637811c](https://github.com/supermemoryai/python-sdk/commit/637811c4a31cfc9d258ca8562fee1cd38fb51320))
+
+
+### Bug Fixes
+
+* **package:** support direct resource imports ([aa29842](https://github.com/supermemoryai/python-sdk/commit/aa2984202e3ff68031618847bc5a438e5a42933f))
+
+
+### Chores
+
+* **ci:** fix installation instructions ([060e326](https://github.com/supermemoryai/python-sdk/commit/060e32620febdd50931ae4d6e692a527b36b99fe))
+* **ci:** upload sdks to package manager ([a327d7d](https://github.com/supermemoryai/python-sdk/commit/a327d7ddd1836e1a15b30eb5fb33388fe2580229))
+* **internal:** avoid errors for isinstance checks on proxies ([be6c667](https://github.com/supermemoryai/python-sdk/commit/be6c667dbff65c00fc7f3bd22e541b477c19ca08))
+* **internal:** codegen related update ([c0d13e2](https://github.com/supermemoryai/python-sdk/commit/c0d13e254d08d459edc35def2c38774ce11fcd0d))
+
## 0.1.0-alpha.1 (2025-04-29)
Full Changelog: [v0.0.1-alpha.0...v0.1.0-alpha.1](https://github.com/supermemoryai/python-sdk/compare/v0.0.1-alpha.0...v0.1.0-alpha.1)
diff --git a/pyproject.toml b/pyproject.toml
index 8427a405..9ca24d46 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
[project]
name = "supermemory"
-version = "0.1.0-alpha.1"
+version = "3.0.0-alpha.1"
description = "The official Python library for the supermemory API"
dynamic = ["readme"]
license = "Apache-2.0"
diff --git a/src/supermemory/_version.py b/src/supermemory/_version.py
index a40c4ed9..c8cc1993 100644
--- a/src/supermemory/_version.py
+++ b/src/supermemory/_version.py
@@ -1,4 +1,4 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
__title__ = "supermemory"
-__version__ = "0.1.0-alpha.1" # x-release-please-version
+__version__ = "3.0.0-alpha.1" # x-release-please-version