fix(openai-sdk-python): support supermemory 3.50 type and API renames

Fresh pip installs pull supermemory 3.50, which renamed MemoryAddResponse
and MemoryGetResponse and moved document creation to client.add(). The
package failed to import and memory writes used a removed API surface.

Migrate tools and middleware to AddResponse/DocumentGetResponse and
client.add(), pin supermemory>=3.50.0 (Python 3.9+), and add import
compatibility regression tests.

Fixes #1235
This commit is contained in:
Kauhsik Raj 2026-07-14 13:07:15 +05:30
parent 2cebe81512
commit 4dda55c51a
5 changed files with 166 additions and 1314 deletions

View file

@ -4,7 +4,7 @@ build-backend = "hatchling.build"
[project]
name = "supermemory-openai-sdk"
version = "1.0.4"
version = "1.0.5"
description = "Memory tools for OpenAI function calling with supermemory"
readme = "README.md"
license = "MIT"
@ -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",
@ -23,10 +22,13 @@ classifiers = [
"Topic :: Software Development :: Libraries :: Python Modules",
"Topic :: Scientific/Engineering :: Artificial Intelligence",
]
requires-python = ">=3.8.1"
# supermemory>=3.50 requires Python 3.9+
requires-python = ">=3.9"
dependencies = [
"openai>=1.102.0",
"supermemory>=3.1.0",
# 3.50 renamed MemoryAddResponse/MemoryGetResponse and moved add() to the
# top-level client. Older releases break package import and memory writes.
"supermemory>=3.50.0",
"typing-extensions>=4.0.0",
"requests>=2.25.0",
]
@ -62,7 +64,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

View file

@ -229,8 +229,9 @@ async def add_memory_tool(
if custom_id is not None:
add_params["custom_id"] = custom_id
# Handle both sync and async supermemory clients
result = client.memories.add(**add_params)
# supermemory 3.x: document creation lives on the top-level add() API.
# Handle both sync and async clients.
result = client.add(**add_params)
if inspect.isawaitable(result):
response = await result
else:

View file

@ -8,10 +8,11 @@ from openai.types.chat import (
ChatCompletionFunctionToolParam,
ChatCompletionMessageToolCall,
ChatCompletionToolMessageParam,
ChatCompletionToolParam,
)
from supermemory.types import (
MemoryAddResponse,
MemoryGetResponse,
AddResponse,
DocumentGetResponse,
SearchExecuteResponse,
)
from supermemory.types.search_execute_response import Result
@ -34,8 +35,10 @@ class SupermemoryToolsConfig(TypedDict, total=False):
project_id: Optional[str]
# Type aliases using inferred types from supermemory package
MemoryObject = Union[MemoryGetResponse, MemoryAddResponse]
# Type aliases using inferred types from supermemory package.
# supermemory >= 3.50 renamed MemoryAddResponse/MemoryGetResponse to
# AddResponse/DocumentGetResponse.
MemoryObject = Union[DocumentGetResponse, AddResponse]
class MemorySearchResult(TypedDict, total=False):
@ -51,7 +54,7 @@ class MemoryAddResult(TypedDict, total=False):
"""Result type for memory add operations."""
success: bool
memory: Optional[MemoryAddResponse]
memory: Optional[AddResponse]
error: Optional[str]
@ -221,12 +224,12 @@ class SupermemoryTools:
MemoryAddResult
"""
try:
add_params = {
"content": memory,
"container_tags": self.container_tags,
}
response: MemoryAddResponse = await self.client.memories.add(**add_params)
# supermemory 3.x moved document creation to the top-level client.add()
# API (client.memories only exposes forget/update_memory now).
response: AddResponse = await self.client.add(
content=memory,
container_tags=self.container_tags,
)
return MemoryAddResult(
success=True,

View file

@ -0,0 +1,60 @@
"""Regression tests for supermemory SDK compatibility (issue #1235).
These tests must not require SUPERMEMORY_API_KEY — the failure mode was
an ImportError at package import time with supermemory 3.50+.
"""
from __future__ import annotations
import importlib
import inspect
def test_package_imports_cleanly() -> None:
"""Importing supermemory_openai must not raise with current supermemory."""
module = importlib.import_module("supermemory_openai")
assert hasattr(module, "SupermemoryTools")
assert hasattr(module, "with_supermemory")
assert hasattr(module, "MemoryObject")
assert hasattr(module, "MemoryAddResult")
def test_tools_module_uses_current_sdk_types() -> None:
"""Tools module must import renamed supermemory 3.50 types."""
from supermemory.types import AddResponse, DocumentGetResponse
from supermemory_openai.tools import MemoryObject, MemoryAddResult
# MemoryObject is a Union of the current SDK response types
assert AddResponse is not None
assert DocumentGetResponse is not None
# Runtime alias should resolve (typing.Union is fine either way)
assert MemoryObject is not None
assert MemoryAddResult is not None
def test_add_memory_uses_client_add_not_memories_add() -> None:
"""add_memory must call client.add (memories.add was removed in 3.50)."""
import supermemory
from supermemory_openai.tools import SupermemoryTools
client = supermemory.AsyncSupermemory(api_key="sm_test_key_for_signature_check")
assert hasattr(client, "add")
assert callable(client.add)
# memories resource no longer exposes add
assert not hasattr(client.memories, "add")
# Source-level guard: tools.add_memory must reference client.add
source = inspect.getsource(SupermemoryTools.add_memory)
assert "self.client.add(" in source
assert "self.client.memories.add" not in source
def test_middleware_add_memory_tool_uses_client_add() -> None:
"""Middleware save path must use client.add as well."""
from supermemory_openai.middleware import add_memory_tool
source = inspect.getsource(add_memory_tool)
assert "client.add(" in source
# Reject the removed memories resource call site (allow comments that mention it).
assert "result = client.memories.add" not in source
assert "client.memories.add(**" not in source

File diff suppressed because it is too large Load diff