fix(python-sdks): migrate agent-framework, cartesia, and pipecat to v4 APIs

Use client.add and search.memories hybrid mode, improve profile memory
deduplication for string/pydantic items, and add dedupe unit tests.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Dhravya Shah 2026-08-07 19:39:58 -07:00
parent 9c3f84b5cb
commit c449b2fe53
14 changed files with 441 additions and 58 deletions

View file

@ -4,7 +4,7 @@ build-backend = "hatchling.build"
[project]
name = "supermemory-agent-framework"
version = "1.0.0"
version = "1.0.1"
description = "Memory tools and middleware for Microsoft Agent Framework with supermemory"
readme = "README.md"
license = "MIT"

View file

@ -72,19 +72,20 @@ class SupermemoryTools:
] = True,
limit: Annotated[int, "Maximum number of results to return"] = 10,
) -> str:
"""Search (recall) memories/details/information about the user or other facts or entities. Run when explicitly asked or when context about user's past choices would be helpful."""
"""Search stored memories for facts, preferences, history, and context. Use proactively before answering whenever memory could help — not only when explicitly asked."""
try:
response = await self._client.search.execute(
response = await self._client.search.memories(
q=information_to_get,
container_tags=[self._connection.container_tag],
limit=limit,
chunk_threshold=0.6,
include_full_docs=include_full_docs,
threshold=0.6,
search_mode="hybrid",
)
results = response.results or []
result: MemorySearchResult = {
"success": True,
"results": response.results,
"count": len(response.results) if response.results else 0,
"results": results,
"count": len(results),
}
return json.dumps(result, default=str)
except Exception as error:
@ -152,9 +153,9 @@ class SupermemoryTools:
tool(
name="search_memories",
description=(
"Search (recall) memories/details/information about the user or other "
"facts or entities. Run when explicitly asked or when context about "
"user's past choices would be helpful."
"Search (recall) stored memories for facts, preferences, history, and context "
"about the user or any topic. Use proactively before answering whenever memory "
"could help — do not wait for the user to explicitly ask you to search or recall."
),
)(self.search_memories),
tool(

View file

@ -92,14 +92,19 @@ def deduplicate_memories(
def extract_memory_text(item: Any) -> Optional[str]:
if item is None:
return None
if isinstance(item, str):
trimmed = item.strip()
return trimmed if trimmed else None
if isinstance(item, dict):
memory = item.get("memory")
if isinstance(memory, str):
trimmed = memory.strip()
return trimmed if trimmed else None
return None
if isinstance(item, str):
trimmed = item.strip()
# Stainless SDK returns pydantic models (attribute access, snake_case).
memory = getattr(item, "memory", None)
if isinstance(memory, str):
trimmed = memory.strip()
return trimmed if trimmed else None
return None

View file

@ -56,6 +56,20 @@ class TestDeduplicateMemories:
)
assert result.static == ["valid"]
def test_pydantic_like_search_results(self) -> None:
"""SDK search results are pydantic models, not dicts (#1266)."""
from types import SimpleNamespace
result = deduplicate_memories(
static=["User likes Python"],
search_results=[
SimpleNamespace(memory="User prefers async", updated_at="2026-01-01T00:00:00Z"),
SimpleNamespace(memory="User likes Python", updated_at=None),
],
)
assert result.static == ["User likes Python"]
assert result.search_results == ["User prefers async"]
class TestConvertProfileToMarkdown:
def test_empty_profile(self) -> None: