fix(openai-sdk-python): harden v4 migration

This commit is contained in:
ved015 2026-08-21 21:24:38 +05:30
parent f68bd30262
commit 183e9fba93
6 changed files with 52 additions and 36 deletions

View file

@ -245,8 +245,7 @@ tools = SupermemoryTools(
# Search memories
result = await tools.search_memories(
information_to_get="user preferences",
limit=10,
include_full_docs=True
limit=10
)
# Add memory
@ -260,6 +259,10 @@ result = await tools.fetch_memory(
)
```
`include_full_docs` is retained as a deprecated Python argument for compatibility,
but v4 search returns relevant memories and chunks instead of full source documents.
It is no longer exposed in the OpenAI tool schema.
### Individual Tools
```python

View file

@ -4,7 +4,7 @@ build-backend = "hatchling.build"
[project]
name = "supermemory-openai-sdk"
version = "1.0.5"
version = "1.0.6"
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",
@ -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

View file

@ -222,15 +222,15 @@ async def add_memory_tool(
) -> None:
"""Add a new memory to the SuperMemory system."""
try:
add_params = {
"content": content,
"container_tag": container_tag,
}
if custom_id is not None:
add_params["custom_id"] = custom_id
# Handle both sync and async supermemory clients
result = client.add(**add_params)
if custom_id is None:
result = client.add(content=content, container_tag=container_tag)
else:
result = client.add(
content=content,
container_tag=container_tag,
custom_id=custom_id,
)
if inspect.isawaitable(result):
response = await result
else:

View file

@ -1,7 +1,8 @@
"""Supermemory tools for OpenAI function calling."""
import json
from typing import Dict, List, Optional, TypedDict, Union
import warnings
from typing import Dict, List, Optional, TypedDict
import supermemory
from openai.types.chat import (
@ -10,7 +11,6 @@ from openai.types.chat import (
ChatCompletionToolMessageParam,
)
from supermemory.types import AddResponse, SearchMemoriesResponse
from supermemory.types.search_memories_response import Result
from .exceptions import (
SupermemoryConfigurationError,
@ -23,6 +23,8 @@ class SupermemoryToolsConfig(TypedDict, total=False):
"""Configuration for Supermemory tools.
Only one of `project_id` or `container_tags` can be provided.
The first container tag is the primary v4 search scope; all configured tags
are applied when adding a memory.
"""
base_url: Optional[str]
@ -38,7 +40,7 @@ class MemorySearchResult(TypedDict, total=False):
"""Result type for memory search operations."""
success: bool
results: Optional[List[Result]]
results: Optional[List[Dict[str, object]]]
count: Optional[int]
error: Optional[str]
@ -65,14 +67,6 @@ MEMORY_TOOL_SCHEMAS: Dict[str, ChatCompletionFunctionToolParam] = {
"type": "string",
"description": "Terms to search for in the user's memories",
},
"include_full_docs": {
"type": "boolean",
"description": (
"Whether to include the full document content in the response. "
"Defaults to true for better AI context."
),
"default": True,
},
"limit": {
"type": "number",
"description": "Maximum number of results to return",
@ -169,23 +163,32 @@ class SupermemoryTools:
async def search_memories(
self,
information_to_get: str,
include_full_docs: bool = True,
include_full_docs: Optional[bool] = None,
limit: int = 10,
) -> MemorySearchResult:
"""Search memories.
Args:
information_to_get: Terms to search for
include_full_docs: Whether to include full document content
include_full_docs: Deprecated compatibility argument. V4 search
returns relevant memories and chunks, not full source documents.
limit: Maximum number of results
Returns:
MemorySearchResult
"""
if include_full_docs is not None:
warnings.warn(
"include_full_docs is deprecated and ignored because v4 search "
"does not return full source documents",
DeprecationWarning,
stacklevel=2,
)
try:
response: SearchMemoriesResponse = await self.client.search.memories(
q=information_to_get,
container_tags=self.container_tags,
container_tag=self.container_tags[0],
limit=limit,
threshold=0.6,
search_mode="hybrid",
@ -317,7 +320,7 @@ class SearchMemoriesTool:
async def execute(
self,
information_to_get: str,
include_full_docs: bool = True,
include_full_docs: Optional[bool] = None,
limit: int = 10,
) -> MemorySearchResult:
"""Execute search memories."""

View file

@ -159,6 +159,10 @@ class TestToolDefinitions:
assert search_tool is not None
assert search_tool["type"] == "function"
assert "information_to_get" in search_tool["function"]["parameters"]["required"]
assert (
"include_full_docs"
not in search_tool["function"]["parameters"]["properties"]
)
# Check addMemory
add_tool = next(
@ -206,25 +210,32 @@ class TestMemoryOperationsUnit:
@pytest.mark.asyncio
async def test_search_memories_uses_search_memories_hybrid(self):
"""search_memories must call client.search.memories with hybrid mode."""
"""V4 search must use the primary singular tag and hybrid mode."""
from types import SimpleNamespace
from unittest.mock import AsyncMock
tools = SupermemoryTools("test-key", {"container_tags": ["unit-tag"]})
tools = SupermemoryTools(
"test-key", {"container_tags": ["primary-tag", "secondary-tag"]}
)
tools.client.search.memories = AsyncMock(
return_value=SimpleNamespace(
results=[SimpleNamespace(model_dump=lambda: {"memory": "likes tea"})]
)
)
result = await tools.search_memories("tea", limit=3)
with pytest.warns(DeprecationWarning, match="include_full_docs"):
result = await tools.search_memories(
"tea", include_full_docs=False, limit=3
)
assert result["success"] is True
assert result["count"] == 1
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"] == "primary-tag"
assert "container_tags" not in kwargs
assert "include_full_docs" not in kwargs
assert kwargs["limit"] == 3
assert kwargs["search_mode"] == "hybrid"

View file

@ -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 = "1.0.6"
source = { editable = "." }
dependencies = [
{ name = "openai" },