Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 71 additions & 24 deletions agent-memory-client/agent_memory_client/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import asyncio
import logging # noqa: F401
import re
import warnings
from collections.abc import AsyncIterator, Sequence
from typing import TYPE_CHECKING, Any, Literal, NoReturn, TypedDict

Expand Down Expand Up @@ -50,6 +51,23 @@
)
from .tool_schema import ToolSchema, ToolSchemaCollection

# === Tool Name Constants ===

# Current tool names
TOOL_SEARCH_MEMORY = "search_memory"
TOOL_GET_OR_CREATE_WORKING_MEMORY = "get_or_create_working_memory"
TOOL_LAZILY_CREATE_LONG_TERM_MEMORY = "lazily_create_long_term_memory"
TOOL_UPDATE_WORKING_MEMORY_DATA = "update_working_memory_data"
TOOL_GET_LONG_TERM_MEMORY = "get_long_term_memory"
TOOL_EAGERLY_CREATE_LONG_TERM_MEMORY = "eagerly_create_long_term_memory"
TOOL_EDIT_LONG_TERM_MEMORY = "edit_long_term_memory"
TOOL_DELETE_LONG_TERM_MEMORIES = "delete_long_term_memories"
TOOL_GET_CURRENT_DATETIME = "get_current_datetime"

# Deprecated tool names (aliases for backwards compatibility)
TOOL_ADD_MEMORY_TO_WORKING_MEMORY = "add_memory_to_working_memory" # Deprecated
TOOL_CREATE_LONG_TERM_MEMORY = "create_long_term_memory" # Deprecated

# === Tool Call Type Definitions ===


Expand Down Expand Up @@ -1494,9 +1512,13 @@ def get_working_memory_tool_schema(cls) -> ToolSchema:
)

@classmethod
def get_add_memory_tool_schema(cls) -> ToolSchema:
def get_lazily_create_long_term_memory_tool_schema(cls) -> ToolSchema:
"""
Get OpenAI-compatible tool schema for adding memories to working memory.
Get OpenAI-compatible tool schema for lazily creating long-term memories.

This tool adds memories to working memory, which are then automatically
promoted to long-term storage. This is the "lazy" approach compared to
eagerly_create_long_term_memory which writes directly to long-term storage.

Returns:
ToolSchema object with customizable description and parameters
Expand All @@ -1505,10 +1527,12 @@ def get_add_memory_tool_schema(cls) -> ToolSchema:
{
"type": "function",
"function": {
"name": "add_memory_to_working_memory",
"name": TOOL_LAZILY_CREATE_LONG_TERM_MEMORY,
"description": (
"Store new important information as a structured memory. Use this when users share preferences, facts, or important details that should be remembered for future conversations. "
"Examples: 'User is vegetarian', 'Lives in Seattle', 'Works as a software engineer', 'Prefers morning meetings'. The system automatically promotes important memories to long-term storage. "
"Store new important information as a structured memory that will be promoted to long-term storage. "
"Use this when users share preferences, facts, or important details that should be remembered for future conversations. "
"Examples: 'User is vegetarian', 'Lives in Seattle', 'Works as a software engineer', 'Prefers morning meetings'. "
"The system automatically promotes these memories to long-term storage (lazy creation). "
"For time-bound (episodic) information, include a grounded date phrase in the text (e.g., 'on August 14, 2025') and call get_current_datetime to resolve relative expressions like 'today'/'yesterday'; the backend will set the structured event_date during extraction/promotion. "
"Always check if similar information already exists before creating new memories."
),
Expand Down Expand Up @@ -1676,9 +1700,13 @@ def edit_long_term_memory_tool_schema(cls) -> ToolSchema:
)

@classmethod
def create_long_term_memory_tool_schema(cls) -> ToolSchema:
def get_eagerly_create_long_term_memory_tool_schema(cls) -> ToolSchema:
"""
Get OpenAI-compatible tool schema for creating long-term memories directly.
Get OpenAI-compatible tool schema for eagerly creating long-term memories.

This tool creates memories directly in long-term storage for immediate
retrieval. This is the "eager" approach compared to lazily_create_long_term_memory
which goes through working memory first.

Returns:
ToolSchema object with customizable description and parameters
Expand All @@ -1687,12 +1715,11 @@ def create_long_term_memory_tool_schema(cls) -> ToolSchema:
{
"type": "function",
"function": {
"name": "create_long_term_memory",
"name": TOOL_EAGERLY_CREATE_LONG_TERM_MEMORY,
"description": (
"Create long-term memories directly for immediate storage and retrieval. "
"Use this for important information that should be permanently stored without going through working memory. "
"This is the 'eager' approach - memories are created immediately in long-term storage. "
"Examples: User preferences, important facts, key events that need to be searchable right away. "
"Create long-term memories directly for immediate storage and retrieval (eager creation). "
"Use this for important information that should be permanently stored and searchable right away. "
"Examples: User preferences, important facts, key events that need to be immediately retrievable. "
"For episodic memories, include event_date in ISO format."
),
"parameters": {
Expand Down Expand Up @@ -1797,10 +1824,10 @@ def get_all_memory_tool_schemas(cls) -> ToolSchemaCollection:
[
cls.get_memory_search_tool_schema(),
cls.get_working_memory_tool_schema(),
cls.get_add_memory_tool_schema(),
cls.get_lazily_create_long_term_memory_tool_schema(),
cls.get_update_memory_data_tool_schema(),
cls.get_long_term_memory_tool_schema(),
cls.create_long_term_memory_tool_schema(),
cls.get_eagerly_create_long_term_memory_tool_schema(),
cls.edit_long_term_memory_tool_schema(),
cls.delete_long_term_memories_tool_schema(),
cls.get_current_datetime_tool_schema(),
Expand Down Expand Up @@ -1835,10 +1862,10 @@ def get_all_memory_tool_schemas_anthropic(cls) -> ToolSchemaCollection:
[
cls.get_memory_search_tool_schema_anthropic(),
cls.get_working_memory_tool_schema_anthropic(),
cls.get_add_memory_tool_schema_anthropic(),
cls.get_lazily_create_long_term_memory_tool_schema_anthropic(),
cls.get_update_memory_data_tool_schema_anthropic(),
cls.get_long_term_memory_tool_schema_anthropic(),
cls.create_long_term_memory_tool_schema_anthropic(),
cls.get_eagerly_create_long_term_memory_tool_schema_anthropic(),
cls.edit_long_term_memory_tool_schema_anthropic(),
cls.delete_long_term_memories_tool_schema_anthropic(),
cls.get_current_datetime_tool_schema_anthropic(),
Expand Down Expand Up @@ -1884,9 +1911,9 @@ def get_working_memory_tool_schema_anthropic(cls) -> ToolSchema:
return cls._convert_openai_to_anthropic_schema(openai_schema)

@classmethod
def get_add_memory_tool_schema_anthropic(cls) -> ToolSchema:
"""Get add memory tool schema in Anthropic format."""
openai_schema = cls.get_add_memory_tool_schema()
def get_lazily_create_long_term_memory_tool_schema_anthropic(cls) -> ToolSchema:
"""Get lazily create long-term memory tool schema in Anthropic format."""
openai_schema = cls.get_lazily_create_long_term_memory_tool_schema()
return cls._convert_openai_to_anthropic_schema(openai_schema)

@classmethod
Expand All @@ -1902,9 +1929,9 @@ def get_long_term_memory_tool_schema_anthropic(cls) -> ToolSchema:
return cls._convert_openai_to_anthropic_schema(openai_schema)

@classmethod
def create_long_term_memory_tool_schema_anthropic(cls) -> ToolSchema:
"""Get create long-term memory tool schema in Anthropic format."""
openai_schema = cls.create_long_term_memory_tool_schema()
def get_eagerly_create_long_term_memory_tool_schema_anthropic(cls) -> ToolSchema:
"""Get eagerly create long-term memory tool schema in Anthropic format."""
openai_schema = cls.get_eagerly_create_long_term_memory_tool_schema()
return cls._convert_openai_to_anthropic_schema(openai_schema)

@classmethod
Expand Down Expand Up @@ -2282,7 +2309,17 @@ async def resolve_function_call(
session_id, effective_namespace, user_id
)

elif function_name == "add_memory_to_working_memory":
elif function_name in (
TOOL_LAZILY_CREATE_LONG_TERM_MEMORY,
TOOL_ADD_MEMORY_TO_WORKING_MEMORY, # Deprecated alias
):
if function_name == TOOL_ADD_MEMORY_TO_WORKING_MEMORY:
warnings.warn(
f"Tool name '{TOOL_ADD_MEMORY_TO_WORKING_MEMORY}' is deprecated. "
f"Use '{TOOL_LAZILY_CREATE_LONG_TERM_MEMORY}' instead.",
DeprecationWarning,
stacklevel=2,
)
result = await self._resolve_add_memory(
args, session_id, effective_namespace, user_id
)
Expand All @@ -2295,7 +2332,17 @@ async def resolve_function_call(
elif function_name == "get_long_term_memory":
result = await self._resolve_get_long_term_memory(args)

elif function_name == "create_long_term_memory":
elif function_name in (
TOOL_EAGERLY_CREATE_LONG_TERM_MEMORY,
TOOL_CREATE_LONG_TERM_MEMORY, # Deprecated alias
):
if function_name == TOOL_CREATE_LONG_TERM_MEMORY:
warnings.warn(
f"Tool name '{TOOL_CREATE_LONG_TERM_MEMORY}' is deprecated. "
f"Use '{TOOL_EAGERLY_CREATE_LONG_TERM_MEMORY}' instead.",
DeprecationWarning,
stacklevel=2,
)
result = await self._resolve_create_long_term_memory(
args, effective_namespace, user_id
)
Expand Down
32 changes: 16 additions & 16 deletions agent-memory-client/agent_memory_client/integrations/langchain.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,10 +89,10 @@ def get_memory_tools(
Available tools:
- "search_memory"
- "get_or_create_working_memory"
- "add_memory_to_working_memory"
- "lazily_create_long_term_memory"
- "update_working_memory_data"
- "get_long_term_memory"
- "create_long_term_memory"
- "eagerly_create_long_term_memory"
- "edit_long_term_memory"
- "delete_long_term_memories"
- "get_current_datetime"
Expand All @@ -117,7 +117,7 @@ def get_memory_tools(
memory_client=client,
session_id="chat_session",
user_id="alice",
tools=["search_memory", "create_long_term_memory"]
tools=["search_memory", "eagerly_create_long_term_memory"]
)
```
"""
Expand All @@ -137,9 +137,9 @@ def get_memory_tools(
memory_client, session_id, namespace, user_id
),
},
"add_memory_to_working_memory": {
"name": "add_memory_to_working_memory",
"description": "Store new important information as a structured memory. Use this when users share preferences, facts, or important details that should be remembered for future conversations. The system automatically promotes important memories to long-term storage.",
"lazily_create_long_term_memory": {
"name": "lazily_create_long_term_memory",
"description": "Store new important information as a structured memory that will be promoted to long-term storage. Use this when users share preferences, facts, or important details that should be remembered for future conversations. The system automatically promotes important memories to long-term storage (lazy creation).",
"func": _create_add_memory_func(
memory_client, session_id, namespace, user_id
),
Expand All @@ -156,9 +156,9 @@ def get_memory_tools(
"description": "Retrieve a specific long-term memory by its unique ID to see full details. Use this when you have a memory ID from search_memory results and need complete information.",
"func": _create_get_long_term_memory_func(memory_client),
},
"create_long_term_memory": {
"name": "create_long_term_memory",
"description": "Create long-term memories directly for immediate storage and retrieval. Use this for important information that should be permanently stored without going through working memory. You can pass a single memory object or a list of memory objects. Each memory needs: text (string), memory_type ('episodic' or 'semantic'), and optionally topics (list), entities (list), event_date (ISO string).",
"eagerly_create_long_term_memory": {
"name": "eagerly_create_long_term_memory",
"description": "Create long-term memories directly for immediate storage and retrieval (eager creation). Use this for important information that should be permanently stored and searchable right away. You can pass a single memory object or a list of memory objects. Each memory needs: text (string), memory_type ('episodic' or 'semantic'), and optionally topics (list), entities (list), event_date (ISO string).",
"func": _create_create_long_term_memory_func(
memory_client, namespace, user_id
),
Expand Down Expand Up @@ -272,9 +272,9 @@ def _create_add_memory_func(
namespace: str | None,
user_id: str | None,
) -> Any:
"""Create add_memory_to_working_memory function."""
"""Create lazily_create_long_term_memory function."""

async def add_memory_to_working_memory(
async def lazily_create_long_term_memory(
text: str,
memory_type: Literal["episodic", "semantic"],
topics: list[str] | None = None,
Expand All @@ -292,7 +292,7 @@ async def add_memory_to_working_memory(
)
return str(result.get("summary", str(result)))

return add_memory_to_working_memory
return lazily_create_long_term_memory


def _create_update_memory_data_func(
Expand Down Expand Up @@ -343,9 +343,9 @@ def _create_create_long_term_memory_func(
namespace: str | None,
user_id: str | None,
) -> Any:
"""Create create_long_term_memory function."""
"""Create eagerly_create_long_term_memory function."""

async def create_long_term_memory(
async def eagerly_create_long_term_memory(
memories: list[dict[str, Any]] | dict[str, Any],
) -> str:
"""Create long-term memories directly for immediate storage.
Expand All @@ -358,7 +358,7 @@ async def create_long_term_memory(
memories = [memories]

result = await client.resolve_function_call(
function_name="create_long_term_memory",
function_name="eagerly_create_long_term_memory",
function_arguments={"memories": memories},
session_id="", # Not needed for direct long-term memory creation
namespace=namespace,
Expand All @@ -369,7 +369,7 @@ async def create_long_term_memory(
else:
return f"Error: {result.get('error', 'Unknown error')}"

return create_long_term_memory
return eagerly_create_long_term_memory


def _create_edit_long_term_memory_func(client: MemoryAPIClient) -> Any:
Expand Down
22 changes: 11 additions & 11 deletions agent-memory-client/tests/test_langchain_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,10 +78,10 @@ def test_get_memory_tools_all(self):
expected_names = {
"search_memory",
"get_or_create_working_memory",
"add_memory_to_working_memory",
"lazily_create_long_term_memory",
"update_working_memory_data",
"get_long_term_memory",
"create_long_term_memory",
"eagerly_create_long_term_memory",
"edit_long_term_memory",
"delete_long_term_memories",
"get_current_datetime",
Expand All @@ -100,14 +100,14 @@ def test_get_memory_tools_selective(self):
memory_client=client,
session_id="test_session",
user_id="test_user",
tools=["search_memory", "create_long_term_memory"],
tools=["search_memory", "eagerly_create_long_term_memory"],
)

# Should return only 2 tools
assert len(tools) == 2

tool_names = {tool.name for tool in tools}
assert tool_names == {"search_memory", "create_long_term_memory"}
assert tool_names == {"search_memory", "eagerly_create_long_term_memory"}

@pytest.mark.skipif(not _langchain_available(), reason="LangChain not installed")
def test_get_memory_tools_invalid_tool_name(self):
Expand Down Expand Up @@ -168,7 +168,7 @@ async def test_search_memory_tool_execution(self):
@pytest.mark.skipif(not _langchain_available(), reason="LangChain not installed")
@pytest.mark.asyncio
async def test_add_memory_tool_execution(self):
"""Test that add_memory_to_working_memory tool executes correctly."""
"""Test that lazily_create_long_term_memory tool executes correctly."""
from agent_memory_client.integrations.langchain import get_memory_tools

client = _create_mock_client()
Expand All @@ -183,7 +183,7 @@ async def test_add_memory_tool_execution(self):
memory_client=client,
session_id="test_session",
user_id="test_user",
tools=["add_memory_to_working_memory"],
tools=["lazily_create_long_term_memory"],
)

add_tool = tools[0]
Expand All @@ -209,7 +209,7 @@ async def test_add_memory_tool_execution(self):
@pytest.mark.skipif(not _langchain_available(), reason="LangChain not installed")
@pytest.mark.asyncio
async def test_create_long_term_memory_tool_execution(self):
"""Test that create_long_term_memory tool executes correctly."""
"""Test that eagerly_create_long_term_memory tool executes correctly."""
from agent_memory_client.integrations.langchain import get_memory_tools

client = _create_mock_client()
Expand All @@ -224,7 +224,7 @@ async def test_create_long_term_memory_tool_execution(self):
memory_client=client,
session_id="test_session",
user_id="test_user",
tools=["create_long_term_memory"],
tools=["eagerly_create_long_term_memory"],
)

create_tool = tools[0]
Expand All @@ -242,13 +242,13 @@ async def test_create_long_term_memory_tool_execution(self):
# Verify resolve_function_call was called correctly
client.resolve_function_call.assert_called_once()
call_kwargs = client.resolve_function_call.call_args.kwargs
assert call_kwargs["function_name"] == "create_long_term_memory"
assert call_kwargs["function_name"] == "eagerly_create_long_term_memory"
assert len(call_kwargs["function_arguments"]["memories"]) == 2

@pytest.mark.skipif(not _langchain_available(), reason="LangChain not installed")
@pytest.mark.asyncio
async def test_create_long_term_memory_accepts_single_object(self):
"""Test that create_long_term_memory accepts a single memory object (not just array)."""
"""Test that eagerly_create_long_term_memory accepts a single memory object (not just array)."""
from agent_memory_client.integrations.langchain import get_memory_tools

client = _create_mock_client()
Expand All @@ -263,7 +263,7 @@ async def test_create_long_term_memory_accepts_single_object(self):
memory_client=client,
session_id="test_session",
user_id="test_user",
tools=["create_long_term_memory"],
tools=["eagerly_create_long_term_memory"],
)

create_tool = tools[0]
Expand Down
Loading