From 58d3aeaf9283fbae821ce92fa781fb136831b88d Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sat, 8 Aug 2026 02:45:20 +0000 Subject: [PATCH 1/3] fix(openai-sdk-python): use singular container_tag and forward include.documents Breaking: SupermemoryToolsConfig now takes container_tag (str) instead of container_tags (list). search_memories maps include_full_docs to include={"documents": ...} on client.search.memories. Co-authored-by: Dhravya Shah --- packages/openai-sdk-python/README.md | 20 +++++++++-- packages/openai-sdk-python/pyproject.toml | 2 +- .../src/supermemory_openai/tools.py | 22 +++++++----- .../openai-sdk-python/tests/test_tools.py | 36 ++++++++++++++----- 4 files changed, 59 insertions(+), 21 deletions(-) diff --git a/packages/openai-sdk-python/README.md b/packages/openai-sdk-python/README.md index 7e5b68aa..3405dc2f 100644 --- a/packages/openai-sdk-python/README.md +++ b/packages/openai-sdk-python/README.md @@ -4,6 +4,22 @@ Memory tools and middleware for OpenAI with Supermemory integration. This package provides both **automatic memory injection middleware** and **manual memory tools** for the official [OpenAI Python SDK](https://github.com/openai/openai-python) using [Supermemory](https://supermemory.ai) capabilities. +## Breaking changes (v2.0) + +Aligned with Supermemory v4 APIs: + +- `SupermemoryToolsConfig.container_tags` (list) is **removed**. Use a single `container_tag` string instead. +- Search/add tool calls send `container_tag` (singular) to the API. +- `search_memories(..., include_full_docs=True)` maps to `include={"documents": True}` on `client.search.memories`. + +```python +# Before (v1) +config = {"container_tags": ["user-123"]} + +# After (v2) +config = {"container_tag": "user-123"} +``` + ## Installation Install using uv (recommended): @@ -237,7 +253,7 @@ from supermemory_openai import SupermemoryTools tools = SupermemoryTools( api_key="your-supermemory-api-key", config={ - "project_id": "my-project", # or use container_tags + "project_id": "my-project", # or use container_tag="user-123" "base_url": "https://custom-endpoint.com", # optional } ) @@ -408,7 +424,7 @@ Optional for testing: ### Required - `openai>=1.102.0` - Official OpenAI Python SDK -- `supermemory>=3.1.0` - Supermemory client +- `supermemory>=3.50.0` - Supermemory client - `requests>=2.25.0` - HTTP requests (fallback) ### Optional diff --git a/packages/openai-sdk-python/pyproject.toml b/packages/openai-sdk-python/pyproject.toml index 18b5f4da..f6d78545 100644 --- a/packages/openai-sdk-python/pyproject.toml +++ b/packages/openai-sdk-python/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "hatchling.build" [project] name = "supermemory-openai-sdk" -version = "1.0.4" +version = "2.0.0" description = "Memory tools for OpenAI function calling with supermemory" readme = "README.md" license = "MIT" diff --git a/packages/openai-sdk-python/src/supermemory_openai/tools.py b/packages/openai-sdk-python/src/supermemory_openai/tools.py index 60274615..25dfb837 100644 --- a/packages/openai-sdk-python/src/supermemory_openai/tools.py +++ b/packages/openai-sdk-python/src/supermemory_openai/tools.py @@ -22,11 +22,14 @@ from .exceptions import ( class SupermemoryToolsConfig(TypedDict, total=False): """Configuration for Supermemory tools. - Only one of `project_id` or `container_tags` can be provided. + Only one of `project_id` or `container_tag` can be provided. + + Breaking change: `container_tags` (list) was removed in favor of a single + `container_tag` string, matching the Supermemory v4 API. """ base_url: Optional[str] - container_tags: Optional[List[str]] + container_tag: Optional[str] project_id: Optional[str] @@ -123,13 +126,13 @@ class SupermemoryTools: self.client = supermemory.AsyncSupermemory(**client_kwargs) - # Set container tags + # Set container tag (singular — v4 API) if config.get("project_id"): - self.container_tags = [f"sm_project_{config['project_id']}"] - elif config.get("container_tags"): - self.container_tags = config["container_tags"] + self.container_tag = f"sm_project_{config['project_id']}" + elif config.get("container_tag"): + self.container_tag = config["container_tag"] else: - self.container_tags = ["sm_project_default"] + self.container_tag = "sm_project_default" def get_tool_definitions(self) -> List[ChatCompletionFunctionToolParam]: """Get OpenAI function definitions for all memory tools. @@ -185,10 +188,11 @@ class SupermemoryTools: try: response: SearchMemoriesResponse = await self.client.search.memories( q=information_to_get, - container_tags=self.container_tags, + container_tag=self.container_tag, limit=limit, threshold=0.6, search_mode="hybrid", + include={"documents": include_full_docs}, ) results = response.results or [] @@ -220,7 +224,7 @@ class SupermemoryTools: try: response: AddResponse = await self.client.add( content=memory, - container_tags=self.container_tags, + container_tag=self.container_tag, ) return MemoryAddResult( diff --git a/packages/openai-sdk-python/tests/test_tools.py b/packages/openai-sdk-python/tests/test_tools.py index 5bc95920..2ff3fa72 100644 --- a/packages/openai-sdk-python/tests/test_tools.py +++ b/packages/openai-sdk-python/tests/test_tools.py @@ -129,14 +129,15 @@ class TestToolInitialization: len(tools.get_tool_definitions()) == 2 ) # Currently has search_memories and add_memory - def test_create_tools_with_custom_container_tags(self, test_api_key: str): - """Test creating tools with custom container tags.""" + def test_create_tools_with_custom_container_tag(self, test_api_key: str): + """Test creating tools with a custom container tag.""" config: SupermemoryToolsConfig = { - "container_tags": ["custom-tag-1", "custom-tag-2"], + "container_tag": "custom-tag-1", } tools = SupermemoryTools(test_api_key, config) assert tools is not None + assert tools.container_tag == "custom-tag-1" assert ( len(tools.get_tool_definitions()) == 2 ) # Currently has search_memories and add_memory @@ -186,7 +187,7 @@ class TestMemoryOperationsUnit: from types import SimpleNamespace from unittest.mock import AsyncMock - tools = SupermemoryTools("test-key", {"container_tags": ["unit-tag"]}) + tools = SupermemoryTools("test-key", {"container_tag": "unit-tag"}) tools.client.add = AsyncMock( return_value=SimpleNamespace( id="doc_123", @@ -201,7 +202,7 @@ class TestMemoryOperationsUnit: assert result["memory"]["id"] == "doc_123" tools.client.add.assert_awaited_once_with( content="User likes tea", - container_tags=["unit-tag"], + container_tag="unit-tag", ) @pytest.mark.asyncio @@ -210,7 +211,7 @@ class TestMemoryOperationsUnit: from types import SimpleNamespace from unittest.mock import AsyncMock - tools = SupermemoryTools("test-key", {"container_tags": ["unit-tag"]}) + tools = SupermemoryTools("test-key", {"container_tag": "unit-tag"}) tools.client.search.memories = AsyncMock( return_value=SimpleNamespace( results=[SimpleNamespace(model_dump=lambda: {"memory": "likes tea"})] @@ -224,9 +225,26 @@ class TestMemoryOperationsUnit: tools.client.search.memories.assert_awaited_once() kwargs = tools.client.search.memories.await_args.kwargs assert kwargs["q"] == "tea" - assert kwargs["container_tags"] == ["unit-tag"] + assert kwargs["container_tag"] == "unit-tag" assert kwargs["limit"] == 3 assert kwargs["search_mode"] == "hybrid" + assert kwargs["include"] == {"documents": True} + + @pytest.mark.asyncio + async def test_search_memories_forwards_include_full_docs_false(self): + """include_full_docs=False must set include.documents to False.""" + from types import SimpleNamespace + from unittest.mock import AsyncMock + + tools = SupermemoryTools("test-key", {"container_tag": "unit-tag"}) + tools.client.search.memories = AsyncMock( + return_value=SimpleNamespace(results=[]) + ) + + await tools.search_memories("tea", include_full_docs=False) + + kwargs = tools.client.search.memories.await_args.kwargs + assert kwargs["include"] == {"documents": False} class TestMemoryOperations: @@ -263,7 +281,7 @@ class TestMemoryOperations: async def test_add_memory(self, test_api_key: str, test_base_url: str): """Test adding memory.""" config: SupermemoryToolsConfig = { - "container_tags": ["test-add-memory"], + "container_tag": "test-add-memory", } if test_base_url: config["base_url"] = test_base_url @@ -399,7 +417,7 @@ class TestOpenAIIntegration: ): """Test handling multiple tool calls.""" tools_config: SupermemoryToolsConfig = { - "container_tags": ["test-multi-tools"], + "container_tag": "test-multi-tools", } if test_base_url: tools_config["base_url"] = test_base_url From 321e07b0541fbbe0b6737bce1c0b28dac1ca0c52 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sat, 8 Aug 2026 02:58:39 +0000 Subject: [PATCH 2/3] chore(openai-sdk-python): sync 2.0.0 lockfile and drop Python 3.8 classifiers Align uv.lock package version, Trove classifiers, and mypy python_version with requires-python >=3.9 for the breaking v2 release. Co-authored-by: Dhravya Shah --- packages/openai-sdk-python/uv.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/openai-sdk-python/uv.lock b/packages/openai-sdk-python/uv.lock index 6c457622..401b6a5c 100644 --- a/packages/openai-sdk-python/uv.lock +++ b/packages/openai-sdk-python/uv.lock @@ -377,7 +377,7 @@ resolution-markers = [ "python_full_version < '3.10'", ] dependencies = [ - { name = "colorama", marker = "python_full_version < '3.10' and sys_platform == 'win32'" }, + { name = "colorama", marker = "sys_platform == 'win32'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/b9/2e/0090cbf739cee7d23781ad4b89a9894a41538e4fcf4c31dcdd705b78eb8b/click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a", size = 226593, upload-time = "2024-12-21T18:38:44.339Z" } wheels = [ @@ -392,7 +392,7 @@ resolution-markers = [ "python_full_version >= '3.10'", ] dependencies = [ - { name = "colorama", marker = "python_full_version >= '3.10' and sys_platform == 'win32'" }, + { name = "colorama", marker = "sys_platform == 'win32'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/60/6c/8ca2efa64cf75a977a0d7fac081354553ebe483345c734fb6b6515d96bbc/click-8.2.1.tar.gz", hash = "sha256:27c491cc05d968d271d5a1db13e3b5a184636d9d930f148c50b038f0d0646202", size = 286342, upload-time = "2025-05-20T23:19:49.832Z" } wheels = [ @@ -422,7 +422,7 @@ name = "exceptiongroup" version = "1.3.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "typing-extensions", marker = "python_full_version < '3.13'" }, + { name = "typing-extensions" }, ] sdist = { url = "https://files.pythonhosted.org/packages/0b/9f/a65090624ecf468cdca03533906e7c69ed7588582240cfe7cc9e770b50eb/exceptiongroup-1.3.0.tar.gz", hash = "sha256:b241f5885f560bc56a59ee63ca4c6a8bfa46ae4ad651af316d4e81817bb9fd88", size = 29749, upload-time = "2025-05-10T17:42:51.123Z" } wheels = [ @@ -1372,7 +1372,7 @@ wheels = [ [[package]] name = "supermemory-openai-sdk" -version = "1.0.4" +version = "2.0.0" source = { editable = "." } dependencies = [ { name = "openai" }, From d34809072b0f8bfbe2d199c697e4b82c2bdfe714 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sat, 8 Aug 2026 02:58:48 +0000 Subject: [PATCH 3/3] chore(openai-sdk-python): align classifiers and mypy with requires-python>=3.9 Co-authored-by: Dhravya Shah --- packages/openai-sdk-python/pyproject.toml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/openai-sdk-python/pyproject.toml b/packages/openai-sdk-python/pyproject.toml index f6d78545..d4f9ba17 100644 --- a/packages/openai-sdk-python/pyproject.toml +++ b/packages/openai-sdk-python/pyproject.toml @@ -15,7 +15,6 @@ classifiers = [ "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", @@ -62,7 +61,7 @@ multi_line_output = 3 line_length = 88 [tool.mypy] -python_version = "3.8" +python_version = "3.9" warn_return_any = true warn_unused_configs = true disallow_untyped_defs = true