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/.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/.stats.yml b/.stats.yml
index b07d08ce..4be06c0d 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
-config_hash: eb32087403f958eead829e810f5a71b8
+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: 8477e3ee6fd596ab6ac911d052e4de79
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/README.md b/README.md
index 3dfd7e8c..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.
@@ -93,7 +110,7 @@ from supermemory import Supermemory
client = Supermemory()
try:
- client.memory.create(
+ client.memories.add(
content="This is a detailed article about machine learning concepts...",
)
except supermemory.APIConnectionError as e:
@@ -138,7 +155,7 @@ client = Supermemory(
)
# Or, configure per-request:
-client.with_options(max_retries=5).memory.create(
+client.with_options(max_retries=5).memories.add(
content="This is a detailed article about machine learning concepts...",
)
```
@@ -163,7 +180,7 @@ client = Supermemory(
)
# Override per-request:
-client.with_options(timeout=5.0).memory.create(
+client.with_options(timeout=5.0).memories.add(
content="This is a detailed article about machine learning concepts...",
)
```
@@ -206,12 +223,12 @@ The "raw" Response object can be accessed by prefixing `.with_raw_response.` to
from supermemory import Supermemory
client = Supermemory()
-response = client.memory.with_raw_response.create(
+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 `memory.create()` would have returned
+memory = response.parse() # get the object that `memories.add()` would have returned
print(memory.id)
```
@@ -226,7 +243,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.memory.with_streaming_response.create(
+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 337614f6..66639691 100644
--- a/api.md
+++ b/api.md
@@ -1,56 +1,66 @@
-# Settings
+# Memories
Types:
```python
-from supermemory.types import SettingUpdateResponse
+from supermemory.types import (
+ MemoryUpdateResponse,
+ MemoryListResponse,
+ MemoryDeleteResponse,
+ MemoryAddResponse,
+ MemoryGetResponse,
+ MemoryUploadFileResponse,
+)
```
Methods:
-- client.settings.update(\*\*params) -> SettingUpdateResponse
+- client.memories.update(id, \*\*params) -> MemoryUpdateResponse
+- client.memories.list(\*\*params) -> MemoryListResponse
+- client.memories.delete(id) -> MemoryDeleteResponse
+- client.memories.add(\*\*params) -> MemoryAddResponse
+- client.memories.get(id) -> MemoryGetResponse
+- client.memories.upload_file(\*\*params) -> MemoryUploadFileResponse
-# Memory
+# Search
Types:
```python
-from supermemory.types import (
- MemoryCreateResponse,
- MemoryListResponse,
- MemoryDeleteResponse,
- MemoryGetResponse,
-)
+from supermemory.types import SearchExecuteResponse
```
Methods:
-- client.memory.create(\*\*params) -> MemoryCreateResponse
-- client.memory.list(\*\*params) -> MemoryListResponse
-- client.memory.delete(id) -> MemoryDeleteResponse
-- client.memory.get(id) -> MemoryGetResponse
+- client.search.execute(\*\*params) -> SearchExecuteResponse
-# 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, \*\*params) -> ConnectionCreateResponse
+- client.connections.list(\*\*params) -> ConnectionListResponse
+- client.connections.get(connection_id) -> ConnectionGetResponse
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/scripts/utils/upload-artifact.sh b/scripts/utils/upload-artifact.sh
new file mode 100755
index 00000000..11632537
--- /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: 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
+fi
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/_client.py b/src/supermemory/_client.py
index 10d8d620..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 memory, search, settings, connection
+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 (
@@ -43,10 +43,10 @@
class Supermemory(SyncAPIClient):
- settings: settings.SettingsResource
- memory: memory.MemoryResource
+ memories: memories.MemoriesResource
search: search.SearchResource
- connection: connection.ConnectionResource
+ settings: settings.SettingsResource
+ connections: connections.ConnectionsResource
with_raw_response: SupermemoryWithRawResponse
with_streaming_response: SupermemoryWithStreamedResponse
@@ -91,7 +91,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 +104,10 @@ def __init__(
_strict_response_validation=_strict_response_validation,
)
- self.settings = settings.SettingsResource(self)
- self.memory = memory.MemoryResource(self)
+ self.memories = memories.MemoriesResource(self)
self.search = search.SearchResource(self)
- self.connection = connection.ConnectionResource(self)
+ self.settings = settings.SettingsResource(self)
+ self.connections = connections.ConnectionsResource(self)
self.with_raw_response = SupermemoryWithRawResponse(self)
self.with_streaming_response = SupermemoryWithStreamedResponse(self)
@@ -120,7 +120,7 @@ def qs(self) -> Querystring:
@override
def auth_headers(self) -> dict[str, str]:
api_key = self.api_key
- return {"X-API-Key": api_key}
+ return {"Authorization": f"Bearer {api_key}"}
@property
@override
@@ -217,10 +217,10 @@ def _make_status_error(
class AsyncSupermemory(AsyncAPIClient):
- settings: settings.AsyncSettingsResource
- memory: memory.AsyncMemoryResource
+ memories: memories.AsyncMemoriesResource
search: search.AsyncSearchResource
- connection: connection.AsyncConnectionResource
+ settings: settings.AsyncSettingsResource
+ connections: connections.AsyncConnectionsResource
with_raw_response: AsyncSupermemoryWithRawResponse
with_streaming_response: AsyncSupermemoryWithStreamedResponse
@@ -265,7 +265,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__,
@@ -278,10 +278,10 @@ def __init__(
_strict_response_validation=_strict_response_validation,
)
- self.settings = settings.AsyncSettingsResource(self)
- self.memory = memory.AsyncMemoryResource(self)
+ self.memories = memories.AsyncMemoriesResource(self)
self.search = search.AsyncSearchResource(self)
- self.connection = connection.AsyncConnectionResource(self)
+ self.settings = settings.AsyncSettingsResource(self)
+ self.connections = connections.AsyncConnectionsResource(self)
self.with_raw_response = AsyncSupermemoryWithRawResponse(self)
self.with_streaming_response = AsyncSupermemoryWithStreamedResponse(self)
@@ -294,7 +294,7 @@ def qs(self) -> Querystring:
@override
def auth_headers(self) -> dict[str, str]:
api_key = self.api_key
- return {"X-API-Key": api_key}
+ return {"Authorization": f"Bearer {api_key}"}
@property
@override
@@ -392,34 +392,34 @@ def _make_status_error(
class SupermemoryWithRawResponse:
def __init__(self, client: Supermemory) -> None:
- self.settings = settings.SettingsResourceWithRawResponse(client.settings)
- self.memory = memory.MemoryResourceWithRawResponse(client.memory)
+ self.memories = memories.MemoriesResourceWithRawResponse(client.memories)
self.search = search.SearchResourceWithRawResponse(client.search)
- self.connection = connection.ConnectionResourceWithRawResponse(client.connection)
+ self.settings = settings.SettingsResourceWithRawResponse(client.settings)
+ self.connections = connections.ConnectionsResourceWithRawResponse(client.connections)
class AsyncSupermemoryWithRawResponse:
def __init__(self, client: AsyncSupermemory) -> None:
- self.settings = settings.AsyncSettingsResourceWithRawResponse(client.settings)
- self.memory = memory.AsyncMemoryResourceWithRawResponse(client.memory)
+ self.memories = memories.AsyncMemoriesResourceWithRawResponse(client.memories)
self.search = search.AsyncSearchResourceWithRawResponse(client.search)
- self.connection = connection.AsyncConnectionResourceWithRawResponse(client.connection)
+ self.settings = settings.AsyncSettingsResourceWithRawResponse(client.settings)
+ self.connections = connections.AsyncConnectionsResourceWithRawResponse(client.connections)
class SupermemoryWithStreamedResponse:
def __init__(self, client: Supermemory) -> None:
- self.settings = settings.SettingsResourceWithStreamingResponse(client.settings)
- self.memory = memory.MemoryResourceWithStreamingResponse(client.memory)
+ self.memories = memories.MemoriesResourceWithStreamingResponse(client.memories)
self.search = search.SearchResourceWithStreamingResponse(client.search)
- self.connection = connection.ConnectionResourceWithStreamingResponse(client.connection)
+ self.settings = settings.SettingsResourceWithStreamingResponse(client.settings)
+ self.connections = connections.ConnectionsResourceWithStreamingResponse(client.connections)
class AsyncSupermemoryWithStreamedResponse:
def __init__(self, client: AsyncSupermemory) -> None:
- self.settings = settings.AsyncSettingsResourceWithStreamingResponse(client.settings)
- self.memory = memory.AsyncMemoryResourceWithStreamingResponse(client.memory)
+ self.memories = memories.AsyncMemoriesResourceWithStreamingResponse(client.memories)
self.search = search.AsyncSearchResourceWithStreamingResponse(client.search)
- self.connection = connection.AsyncConnectionResourceWithStreamingResponse(client.connection)
+ self.settings = settings.AsyncSettingsResourceWithStreamingResponse(client.settings)
+ self.connections = connections.AsyncConnectionsResourceWithStreamingResponse(client.connections)
Client = Supermemory
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/_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/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__()
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
diff --git a/src/supermemory/resources/__init__.py b/src/supermemory/resources/__init__.py
index b772e05e..275ecfbe 100644
--- a/src/supermemory/resources/__init__.py
+++ b/src/supermemory/resources/__init__.py
@@ -1,13 +1,5 @@
# 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,
@@ -16,6 +8,14 @@
SearchResourceWithStreamingResponse,
AsyncSearchResourceWithStreamingResponse,
)
+from .memories import (
+ MemoriesResource,
+ AsyncMemoriesResource,
+ MemoriesResourceWithRawResponse,
+ AsyncMemoriesResourceWithRawResponse,
+ MemoriesResourceWithStreamingResponse,
+ AsyncMemoriesResourceWithStreamingResponse,
+)
from .settings import (
SettingsResource,
AsyncSettingsResource,
@@ -24,38 +24,38 @@
SettingsResourceWithStreamingResponse,
AsyncSettingsResourceWithStreamingResponse,
)
-from .connection import (
- ConnectionResource,
- AsyncConnectionResource,
- ConnectionResourceWithRawResponse,
- AsyncConnectionResourceWithRawResponse,
- ConnectionResourceWithStreamingResponse,
- AsyncConnectionResourceWithStreamingResponse,
+from .connections import (
+ ConnectionsResource,
+ AsyncConnectionsResource,
+ ConnectionsResourceWithRawResponse,
+ AsyncConnectionsResourceWithRawResponse,
+ ConnectionsResourceWithStreamingResponse,
+ AsyncConnectionsResourceWithStreamingResponse,
)
__all__ = [
- "SettingsResource",
- "AsyncSettingsResource",
- "SettingsResourceWithRawResponse",
- "AsyncSettingsResourceWithRawResponse",
- "SettingsResourceWithStreamingResponse",
- "AsyncSettingsResourceWithStreamingResponse",
- "MemoryResource",
- "AsyncMemoryResource",
- "MemoryResourceWithRawResponse",
- "AsyncMemoryResourceWithRawResponse",
- "MemoryResourceWithStreamingResponse",
- "AsyncMemoryResourceWithStreamingResponse",
+ "MemoriesResource",
+ "AsyncMemoriesResource",
+ "MemoriesResourceWithRawResponse",
+ "AsyncMemoriesResourceWithRawResponse",
+ "MemoriesResourceWithStreamingResponse",
+ "AsyncMemoriesResourceWithStreamingResponse",
"SearchResource",
"AsyncSearchResource",
"SearchResourceWithRawResponse",
"AsyncSearchResourceWithRawResponse",
"SearchResourceWithStreamingResponse",
"AsyncSearchResourceWithStreamingResponse",
- "ConnectionResource",
- "AsyncConnectionResource",
- "ConnectionResourceWithRawResponse",
- "AsyncConnectionResourceWithRawResponse",
- "ConnectionResourceWithStreamingResponse",
- "AsyncConnectionResourceWithStreamingResponse",
+ "SettingsResource",
+ "AsyncSettingsResource",
+ "SettingsResourceWithRawResponse",
+ "AsyncSettingsResourceWithRawResponse",
+ "SettingsResourceWithStreamingResponse",
+ "AsyncSettingsResourceWithStreamingResponse",
+ "ConnectionsResource",
+ "AsyncConnectionsResource",
+ "ConnectionsResourceWithRawResponse",
+ "AsyncConnectionsResourceWithRawResponse",
+ "ConnectionsResourceWithStreamingResponse",
+ "AsyncConnectionsResourceWithStreamingResponse",
]
diff --git a/src/supermemory/resources/connection.py b/src/supermemory/resources/connections.py
similarity index 52%
rename from src/supermemory/resources/connection.py
rename to src/supermemory/resources/connections.py
index a55ea8b7..dfc95e77 100644
--- a/src/supermemory/resources/connection.py
+++ b/src/supermemory/resources/connections.py
@@ -2,12 +2,13 @@
from __future__ import annotations
+from typing import Dict, Union, Optional
from typing_extensions import Literal
import httpx
-from ..types import connection_create_params
-from .._types import NOT_GIVEN, Body, Query, Headers, NoneType, NotGiven
+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
@@ -18,37 +19,40 @@
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,
+ 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,
@@ -68,10 +72,11 @@ 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}",
+ body=maybe_transform({"metadata": metadata}, connection_create_params.ConnectionCreateParams),
options=make_request_options(
extra_headers=extra_headers,
extra_query=extra_query,
@@ -79,7 +84,7 @@ def create(
timeout=timeout,
query=maybe_transform(
{
- "id": id,
+ "end_user_id": end_user_id,
"redirect_url": redirect_url,
},
connection_create_params.ConnectionCreateParams,
@@ -88,7 +93,42 @@ def create(
cast_to=ConnectionCreateResponse,
)
- def retrieve(
+ 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,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+ ) -> ConnectionListResponse:
+ """
+ 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,
+ query=maybe_transform({"end_user_id": end_user_id}, connection_list_params.ConnectionListParams),
+ ),
+ cast_to=ConnectionListResponse,
+ )
+
+ def get(
self,
connection_id: str,
*,
@@ -98,8 +138,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 +153,42 @@ 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,
+ 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,
@@ -166,10 +208,11 @@ 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}",
+ body=await async_maybe_transform({"metadata": metadata}, connection_create_params.ConnectionCreateParams),
options=make_request_options(
extra_headers=extra_headers,
extra_query=extra_query,
@@ -177,7 +220,7 @@ async def create(
timeout=timeout,
query=await async_maybe_transform(
{
- "id": id,
+ "end_user_id": end_user_id,
"redirect_url": redirect_url,
},
connection_create_params.ConnectionCreateParams,
@@ -186,7 +229,44 @@ async def create(
cast_to=ConnectionCreateResponse,
)
- async def retrieve(
+ 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,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+ ) -> ConnectionListResponse:
+ """
+ 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,
+ query=await async_maybe_transform(
+ {"end_user_id": end_user_id}, connection_list_params.ConnectionListParams
+ ),
+ ),
+ cast_to=ConnectionListResponse,
+ )
+
+ async def get(
self,
connection_id: str,
*,
@@ -196,8 +276,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 +291,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 56%
rename from src/supermemory/resources/memory.py
rename to src/supermemory/resources/memories.py
index e0368257..180f4cd6 100644
--- a/src/supermemory/resources/memory.py
+++ b/src/supermemory/resources/memories.py
@@ -2,14 +2,14 @@
from __future__ import annotations
-from typing import Dict, Union
+from typing import Dict, List, Union, Mapping, cast
from typing_extensions import Literal
import httpx
-from ..types import memory_list_params, memory_create_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 (
@@ -19,58 +19,54 @@
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
+from ..types.memory_update_response import MemoryUpdateResponse
+from ..types.memory_upload_file_response import MemoryUploadFileResponse
-__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 update(
self,
+ id: str,
*,
content: str,
- id: str | NotGiven = NOT_GIVEN,
+ container_tags: List[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:
+ ) -> MemoryUpdateResponse:
"""
- Add a new memory with content and metadata
+ Update a memory with any content type (text, url, file, etc.) and metadata
Args:
- content: Content of the memory
-
- metadata: Optional metadata for the memory
-
- user_id: Optional end user ID this memory belongs to
-
extra_headers: Send extra headers
extra_query: Add additional query parameters to the request
@@ -79,21 +75,22 @@ def create(
timeout: Override the client-level default timeout for this request, in seconds
"""
- return self._post(
- "/add",
+ 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,
- "id": id,
+ "container_tags": container_tags,
"metadata": metadata,
- "user_id": user_id,
},
- memory_create_params.MemoryCreateParams,
+ memory_update_params.MemoryUpdateParams,
),
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
- cast_to=MemoryCreateResponse,
+ cast_to=MemoryUpdateResponse,
)
def list(
@@ -134,7 +131,7 @@ def list(
timeout: Override the client-level default timeout for this request, in seconds
"""
return self._get(
- "/memories",
+ "/v3/memories",
options=make_request_options(
extra_headers=extra_headers,
extra_query=extra_query,
@@ -180,13 +177,54 @@ def delete(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return self._delete(
- f"/delete/{id}",
+ f"/v3/memories/{id}",
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
cast_to=MemoryDeleteResponse,
)
+ def add(
+ self,
+ *,
+ 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,
+ ) -> MemoryAddResponse:
+ """
+ Add 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
+ """
+ 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=MemoryAddResponse,
+ )
+
def get(
self,
id: str,
@@ -213,58 +251,91 @@ 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
),
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 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 update(
self,
+ id: str,
*,
content: str,
- id: str | NotGiven = NOT_GIVEN,
+ container_tags: List[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:
+ ) -> MemoryUpdateResponse:
"""
- Add a new memory with content and metadata
+ Update a memory with any content type (text, url, file, etc.) and metadata
Args:
- content: Content of the memory
-
- metadata: Optional metadata for the memory
-
- user_id: Optional end user ID this memory belongs to
-
extra_headers: Send extra headers
extra_query: Add additional query parameters to the request
@@ -273,21 +344,22 @@ async def create(
timeout: Override the client-level default timeout for this request, in seconds
"""
- return await self._post(
- "/add",
+ 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,
- "id": id,
+ "container_tags": container_tags,
"metadata": metadata,
- "user_id": user_id,
},
- memory_create_params.MemoryCreateParams,
+ memory_update_params.MemoryUpdateParams,
),
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
- cast_to=MemoryCreateResponse,
+ cast_to=MemoryUpdateResponse,
)
async def list(
@@ -328,7 +400,7 @@ async def list(
timeout: Override the client-level default timeout for this request, in seconds
"""
return await self._get(
- "/memories",
+ "/v3/memories",
options=make_request_options(
extra_headers=extra_headers,
extra_query=extra_query,
@@ -374,13 +446,54 @@ async def delete(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return await self._delete(
- f"/delete/{id}",
+ f"/v3/memories/{id}",
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
cast_to=MemoryDeleteResponse,
)
+ async def add(
+ self,
+ *,
+ 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,
+ ) -> MemoryAddResponse:
+ """
+ Add 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
+ """
+ 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=MemoryAddResponse,
+ )
+
async def get(
self,
id: str,
@@ -407,81 +520,144 @@ 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
),
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 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.update = to_raw_response_wrapper(
+ memories.update,
)
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,
+ )
+ self.upload_file = to_raw_response_wrapper(
+ memories.upload_file,
)
-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.update = async_to_raw_response_wrapper(
+ memories.update,
)
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,
+ )
+ self.upload_file = async_to_raw_response_wrapper(
+ memories.upload_file,
)
-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.update = to_streamed_response_wrapper(
+ memories.update,
)
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,
+ )
+ self.upload_file = to_streamed_response_wrapper(
+ memories.upload_file,
)
-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.update = async_to_streamed_response_wrapper(
+ memories.update,
)
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,
+ )
+ self.upload_file = async_to_streamed_response_wrapper(
+ memories.upload_file,
)
diff --git a/src/supermemory/resources/search.py b/src/supermemory/resources/search.py
index 6c55ba34..4e293996 100644
--- a/src/supermemory/resources/search.py
+++ b/src/supermemory/resources/search.py
@@ -56,6 +56,8 @@ 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.
# The extra values given here take precedence over values defined on the client or passed to this method.
@@ -65,29 +67,43 @@ def execute(
timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
) -> SearchExecuteResponse:
"""
- Search through documents with metadata filtering
+ Search memories 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.
- user_id: End user ID this search is associated with
+ 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
@@ -97,25 +113,30 @@ def execute(
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,
- "user_id": user_id,
- },
- search_execute_params.SearchExecuteParams,
- ),
+ return self._get(
+ "/v3/search",
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(
+ {
+ "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,
)
@@ -153,6 +174,8 @@ 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.
# The extra values given here take precedence over values defined on the client or passed to this method.
@@ -162,29 +185,43 @@ async def execute(
timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
) -> SearchExecuteResponse:
"""
- Search through documents with metadata filtering
+ Search memories 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.
- user_id: End user ID this search is associated with
+ 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
@@ -194,25 +231,30 @@ async def execute(
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,
- "user_id": user_id,
- },
- search_execute_params.SearchExecuteParams,
- ),
+ return await self._get(
+ "/v3/search",
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(
+ {
+ "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,
)
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..2bb705ae 100644
--- a/src/supermemory/types/__init__.py
+++ b/src/supermemory/types/__init__.py
@@ -2,15 +2,23 @@
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_create_params import MemoryCreateParams as MemoryCreateParams
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_create_response import MemoryCreateResponse as MemoryCreateResponse
+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 .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/connection_create_params.py b/src/supermemory/types/connection_create_params.py
index 4bb84cba..152cbce3 100644
--- a/src/supermemory/types/connection_create_params.py
+++ b/src/supermemory/types/connection_create_params.py
@@ -2,7 +2,8 @@
from __future__ import annotations
-from typing_extensions import Required, Annotated, TypedDict
+from typing import Dict, Union, Optional
+from typing_extensions import Annotated, TypedDict
from .._utils import PropertyInfo
@@ -10,6 +11,8 @@
class ConnectionCreateParams(TypedDict, total=False):
- id: Required[str]
+ 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 d27a6fab..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
@@ -8,6 +10,10 @@
class ConnectionCreateResponse(BaseModel):
+ id: str
+
+ auth_link: str = FieldInfo(alias="authLink")
+
expires_in: str = FieldInfo(alias="expiresIn")
- magic_link: str = FieldInfo(alias="magicLink")
+ redirects_to: Optional[str] = FieldInfo(alias="redirectsTo", default=None)
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_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/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 dc873287..00000000
--- a/src/supermemory/types/memory_create_params.py
+++ /dev/null
@@ -1,23 +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]
- """Content of the memory"""
-
- id: str
-
- metadata: Dict[str, Union[str, float, bool]]
- """Optional metadata for the memory"""
-
- user_id: Annotated[str, PropertyInfo(alias="userId")]
- """Optional end user ID this memory belongs to"""
diff --git a/src/supermemory/types/memory_get_response.py b/src/supermemory/types/memory_get_response.py
index d915a18d..4d115240 100644
--- a/src/supermemory/types/memory_get_response.py
+++ b/src/supermemory/types/memory_get_response.py
@@ -1,27 +1,11 @@
# 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__ = ["MemoryGetResponse", "Doc"]
-
-
-class Doc(BaseModel):
- created_at: str = FieldInfo(alias="createdAt")
-
- updated_at: str = FieldInfo(alias="updatedAt")
-
- metadata: Optional[Dict[str, object]] = None
-
- summary: Optional[str] = None
-
- title: Optional[str] = None
+__all__ = ["MemoryGetResponse"]
class MemoryGetResponse(BaseModel):
- doc: Doc
+ id: str
- status: Optional[str] = None
+ status: str
diff --git a/src/supermemory/types/memory_list_response.py b/src/supermemory/types/memory_list_response.py
index b5490f7f..5b325c78 100644
--- a/src/supermemory/types/memory_list_response.py
+++ b/src/supermemory/types/memory_list_response.py
@@ -1,6 +1,6 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-from typing import Dict, List, Optional
+from typing import Dict, List, Union, Optional
from datetime import datetime
from typing_extensions import Literal
@@ -13,33 +13,69 @@
class Memory(BaseModel):
id: str
- """Unique identifier of the memory"""
+ """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"""
- metadata: Dict[str, object]
- """Custom metadata associated with the memory"""
+ 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.
- status: Optional[Literal["queued", "extracting", "chunking", "embedding", "indexing", "done", "failed"]] = None
- """Processing status of 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: str
+ 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
- """Source URL of the memory"""
+ """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.
+ """
- workflow_status: Optional[Literal["PENDING", "IN_PROGRESS", "COMPLETED", "FAILED"]] = FieldInfo(
- alias="workflowStatus", default=None
- )
- """Current workflow status"""
+ raw: None = None
+ """Raw content of the memory"""
class Pagination(BaseModel):
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/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/src/supermemory/types/search_execute_params.py b/src/supermemory/types/search_execute_params.py
index 7ad50125..bc3b4756 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,17 +45,36 @@ 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.
+ """
+
+ 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"""
+ """End user ID this search is associated with.
+
+ NOTE: This also acts as a filter for the search.
+ """
class FiltersUnionMember0(TypedDict, total=False):
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..aee15f42
--- /dev/null
+++ b/tests/api_resources/test_connections.py
@@ -0,0 +1,272 @@
+# 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(
+ 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"])
+
+ @pytest.mark.skip()
+ @parametrize
+ def test_raw_response_create(self, client: Supermemory) -> None:
+ response = client.connections.with_raw_response.create(
+ provider="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(
+ provider="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_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:
+ 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(
+ 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"])
+
+ @pytest.mark.skip()
+ @parametrize
+ async def test_raw_response_create(self, async_client: AsyncSupermemory) -> None:
+ response = await async_client.connections.with_raw_response.create(
+ provider="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(
+ provider="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_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:
+ 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 51%
rename from tests/api_resources/test_memory.py
rename to tests/api_resources/test_memories.py
index 871f95ce..8e7130f2 100644
--- a/tests/api_resources/test_memory.py
+++ b/tests/api_resources/test_memories.py
@@ -10,32 +10,36 @@
from supermemory import Supermemory, AsyncSupermemory
from tests.utils import assert_matches_type
from supermemory.types import (
+ MemoryAddResponse,
MemoryGetResponse,
MemoryListResponse,
- MemoryCreateResponse,
MemoryDeleteResponse,
+ MemoryUpdateResponse,
+ MemoryUploadFileResponse,
)
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(
+ 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(MemoryCreateResponse, memory, path=["response"])
+ assert_matches_type(MemoryUpdateResponse, 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...",
+ 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",
@@ -44,46 +48,56 @@ def test_method_create_with_all_params(self, client: Supermemory) -> None:
"readingTime": 5,
"isPublic": True,
},
- user_id="user_123",
)
- assert_matches_type(MemoryCreateResponse, memory, path=["response"])
+ assert_matches_type(MemoryUpdateResponse, memory, path=["response"])
@pytest.mark.skip()
@parametrize
- def test_raw_response_create(self, client: Supermemory) -> None:
- response = client.memory.with_raw_response.create(
+ 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(MemoryCreateResponse, memory, path=["response"])
+ assert_matches_type(MemoryUpdateResponse, memory, path=["response"])
@pytest.mark.skip()
@parametrize
- def test_streaming_response_create(self, client: Supermemory) -> None:
- with client.memory.with_streaming_response.create(
+ 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(MemoryCreateResponse, memory, path=["response"])
+ 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:
- memory = client.memory.list()
+ 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.memory.list(
+ memory = client.memories.list(
filters='{"AND":[{"key":"group","value":"jira_users","negate":false},{"filterType":"numeric","key":"timestamp","value":"1742745777","negate":false,"numericOperator":">"}]}',
limit="10",
order="desc",
@@ -95,7 +109,7 @@ def test_method_list_with_all_params(self, client: Supermemory) -> None:
@pytest.mark.skip()
@parametrize
def test_raw_response_list(self, client: Supermemory) -> None:
- response = client.memory.with_raw_response.list()
+ response = client.memories.with_raw_response.list()
assert response.is_closed is True
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
@@ -105,7 +119,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.memory.with_streaming_response.list() 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"
@@ -117,7 +131,7 @@ def test_streaming_response_list(self, client: Supermemory) -> None:
@pytest.mark.skip()
@parametrize
def test_method_delete(self, client: Supermemory) -> None:
- memory = client.memory.delete(
+ memory = client.memories.delete(
"id",
)
assert_matches_type(MemoryDeleteResponse, memory, path=["response"])
@@ -125,7 +139,7 @@ def test_method_delete(self, client: Supermemory) -> None:
@pytest.mark.skip()
@parametrize
def test_raw_response_delete(self, client: Supermemory) -> None:
- response = client.memory.with_raw_response.delete(
+ response = client.memories.with_raw_response.delete(
"id",
)
@@ -137,7 +151,7 @@ def test_raw_response_delete(self, client: Supermemory) -> None:
@pytest.mark.skip()
@parametrize
def test_streaming_response_delete(self, client: Supermemory) -> None:
- with client.memory.with_streaming_response.delete(
+ with client.memories.with_streaming_response.delete(
"id",
) as response:
assert not response.is_closed
@@ -152,14 +166,65 @@ def test_streaming_response_delete(self, client: Supermemory) -> None:
@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(
+ 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(MemoryAddResponse, memory, path=["response"])
+
+ @pytest.mark.skip()
+ @parametrize
+ 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(MemoryAddResponse, memory, path=["response"])
+
+ @pytest.mark.skip()
+ @parametrize
+ 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(MemoryAddResponse, memory, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
@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 +232,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 +244,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,28 +259,64 @@ 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(
"",
)
+ @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 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(
+ 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(MemoryCreateResponse, memory, path=["response"])
+ assert_matches_type(MemoryUpdateResponse, 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...",
+ 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",
@@ -224,46 +325,56 @@ async def test_method_create_with_all_params(self, async_client: AsyncSupermemor
"readingTime": 5,
"isPublic": True,
},
- user_id="user_123",
)
- assert_matches_type(MemoryCreateResponse, memory, path=["response"])
+ assert_matches_type(MemoryUpdateResponse, 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(
+ 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(MemoryCreateResponse, memory, path=["response"])
+ assert_matches_type(MemoryUpdateResponse, 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(
+ 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(MemoryCreateResponse, memory, path=["response"])
+ 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:
- memory = await async_client.memory.list()
+ 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.memory.list(
+ memory = await async_client.memories.list(
filters='{"AND":[{"key":"group","value":"jira_users","negate":false},{"filterType":"numeric","key":"timestamp","value":"1742745777","negate":false,"numericOperator":">"}]}',
limit="10",
order="desc",
@@ -275,7 +386,7 @@ async def test_method_list_with_all_params(self, async_client: AsyncSupermemory)
@pytest.mark.skip()
@parametrize
async def test_raw_response_list(self, async_client: AsyncSupermemory) -> None:
- response = await async_client.memory.with_raw_response.list()
+ 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"
@@ -285,7 +396,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.memory.with_streaming_response.list() 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"
@@ -297,7 +408,7 @@ async def test_streaming_response_list(self, async_client: AsyncSupermemory) ->
@pytest.mark.skip()
@parametrize
async def test_method_delete(self, async_client: AsyncSupermemory) -> None:
- memory = await async_client.memory.delete(
+ memory = await async_client.memories.delete(
"id",
)
assert_matches_type(MemoryDeleteResponse, memory, path=["response"])
@@ -305,7 +416,7 @@ async def test_method_delete(self, async_client: AsyncSupermemory) -> None:
@pytest.mark.skip()
@parametrize
async def test_raw_response_delete(self, async_client: AsyncSupermemory) -> None:
- response = await async_client.memory.with_raw_response.delete(
+ response = await async_client.memories.with_raw_response.delete(
"id",
)
@@ -317,7 +428,7 @@ async def test_raw_response_delete(self, async_client: AsyncSupermemory) -> None
@pytest.mark.skip()
@parametrize
async def test_streaming_response_delete(self, async_client: AsyncSupermemory) -> None:
- async with async_client.memory.with_streaming_response.delete(
+ async with async_client.memories.with_streaming_response.delete(
"id",
) as response:
assert not response.is_closed
@@ -332,14 +443,65 @@ async def test_streaming_response_delete(self, async_client: AsyncSupermemory) -
@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(
+ 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(MemoryAddResponse, memory, path=["response"])
+
+ @pytest.mark.skip()
+ @parametrize
+ 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(MemoryAddResponse, memory, path=["response"])
+
+ @pytest.mark.skip()
+ @parametrize
+ 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(MemoryAddResponse, memory, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
@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 +509,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 +521,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 +536,40 @@ 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(
"",
)
+
+ @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
diff --git a/tests/api_resources/test_search.py b/tests/api_resources/test_search.py
index 5bf10690..c0557ff5 100644
--- a/tests/api_resources/test_search.py
+++ b/tests/api_resources/test_search.py
@@ -54,6 +54,8 @@ 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",
)
assert_matches_type(SearchExecuteResponse, search, path=["response"])
@@ -125,6 +127,8 @@ 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",
)
assert_matches_type(SearchExecuteResponse, search, path=["response"])
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 b625c8c7..3636a001 100644
--- a/tests/test_client.py
+++ b/tests/test_client.py
@@ -33,7 +33,7 @@
BaseClient,
make_request_options,
)
-from supermemory.types.memory_create_params import MemoryCreateParams
+from supermemory.types.memory_add_params import MemoryAddParams
from .utils import update_env
@@ -339,7 +339,7 @@ def test_default_headers_option(self) -> None:
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
+ assert request.headers.get("Authorization") == f"Bearer {api_key}"
with pytest.raises(SupermemoryError):
with update_env(**{"SUPERMEMORY_API_KEY": Omit()}):
@@ -724,16 +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.post("/add").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.post(
- "/add",
+ "/v3/memories",
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..."), MemoryAddParams
),
),
cast_to=httpx.Response,
@@ -745,16 +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.post("/add").mock(return_value=httpx.Response(500))
+ respx_mock.post("/v3/memories").mock(return_value=httpx.Response(500))
with pytest.raises(APIStatusError):
self.client.post(
- "/add",
+ "/v3/memories",
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..."), MemoryAddParams
),
),
cast_to=httpx.Response,
@@ -787,9 +785,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.post("/v3/memories").mock(side_effect=retry_handler)
- response = client.memory.with_raw_response.create(
+ response = client.memories.with_raw_response.add(
content="This is a detailed article about machine learning concepts..."
)
@@ -813,9 +811,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.post("/v3/memories").mock(side_effect=retry_handler)
- response = client.memory.with_raw_response.create(
+ response = client.memories.with_raw_response.add(
content="This is a detailed article about machine learning concepts...",
extra_headers={"x-stainless-retry-count": Omit()},
)
@@ -839,9 +837,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.post("/v3/memories").mock(side_effect=retry_handler)
- response = client.memory.with_raw_response.create(
+ response = client.memories.with_raw_response.add(
content="This is a detailed article about machine learning concepts...",
extra_headers={"x-stainless-retry-count": "42"},
)
@@ -1131,7 +1129,7 @@ def test_default_headers_option(self) -> None:
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
+ assert request.headers.get("Authorization") == f"Bearer {api_key}"
with pytest.raises(SupermemoryError):
with update_env(**{"SUPERMEMORY_API_KEY": Omit()}):
@@ -1520,16 +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.post("/add").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.post(
- "/add",
+ "/v3/memories",
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..."), MemoryAddParams
),
),
cast_to=httpx.Response,
@@ -1541,16 +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.post("/add").mock(return_value=httpx.Response(500))
+ respx_mock.post("/v3/memories").mock(return_value=httpx.Response(500))
with pytest.raises(APIStatusError):
await self.client.post(
- "/add",
+ "/v3/memories",
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..."), MemoryAddParams
),
),
cast_to=httpx.Response,
@@ -1584,9 +1580,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.post("/v3/memories").mock(side_effect=retry_handler)
- response = await client.memory.with_raw_response.create(
+ response = await client.memories.with_raw_response.add(
content="This is a detailed article about machine learning concepts..."
)
@@ -1611,9 +1607,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.post("/v3/memories").mock(side_effect=retry_handler)
- response = await client.memory.with_raw_response.create(
+ 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()},
)
@@ -1638,9 +1634,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.post("/v3/memories").mock(side_effect=retry_handler)
- response = await client.memory.with_raw_response.create(
+ 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"},
)
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)