diff --git a/agentrun/memory_collection/__memory_collection_async_template.py b/agentrun/memory_collection/__memory_collection_async_template.py index b2f574d..c53a078 100644 --- a/agentrun/memory_collection/__memory_collection_async_template.py +++ b/agentrun/memory_collection/__memory_collection_async_template.py @@ -228,7 +228,7 @@ async def to_mem0_memory_async( config: Optional[Config] = None, history_db_path: Optional[str] = None, ): - """将 MemoryCollection 转换为 agentrun-mem0ai Memory 客户端(异步) + """将 MemoryCollection 转换为 agentrun-mem0ai AsyncMemory 客户端(异步) Args: memory_collection_name: 记忆集合名称 @@ -236,7 +236,7 @@ async def to_mem0_memory_async( history_db_path: mem0 历史数据库路径(可选) Returns: - Memory: agentrun-mem0ai Memory 客户端实例 + AsyncMemory: agentrun-mem0ai AsyncMemory 客户端实例 Raises: ImportError: 如果未安装 agentrun-mem0ai 包 @@ -247,10 +247,10 @@ async def to_mem0_memory_async( ... "memoryCollection010901", ... config=config ... ) - >>> memory.add("用户喜欢吃苹果", user_id="user123") + >>> await memory.add("用户喜欢吃苹果", user_id="user123") """ try: - from agentrun_mem0 import Memory + from agentrun_mem0 import AsyncMemory except ImportError as e: raise ImportError( "agentrun-mem0ai package is required. Install it with: pip" @@ -267,8 +267,8 @@ async def to_mem0_memory_async( memory_collection, config, history_db_path ) - # 创建并返回 Memory 实例 - return Memory.from_config(mem0_config) + # 创建并返回 AsyncMemory 实例 + return await AsyncMemory.from_config(mem0_config) @staticmethod def _convert_vpc_endpoint_to_public(endpoint: str) -> str: @@ -392,13 +392,25 @@ async def _build_mem0_config_async( ) ) + embedder_config_dict = { + "model": embedder_config.config.model, + "openai_base_url": base_url, + "api_key": api_key, + } + + # 从 vector_store_config 中获取向量维度 + if ( + memory_collection.vector_store_config + and memory_collection.vector_store_config.config + and memory_collection.vector_store_config.config.vector_dimension + ): + embedder_config_dict["embedding_dims"] = ( + memory_collection.vector_store_config.config.vector_dimension + ) + mem0_config["embedder"] = { "provider": "openai", # mem0 使用 openai 兼容接口 - "config": { - "model": embedder_config.config.model, - "openai_base_url": base_url, - "api_key": api_key, - }, + "config": embedder_config_dict, } # 添加历史数据库路径 diff --git a/agentrun/memory_collection/memory_collection.py b/agentrun/memory_collection/memory_collection.py index 94e613b..3ff6f5f 100644 --- a/agentrun/memory_collection/memory_collection.py +++ b/agentrun/memory_collection/memory_collection.py @@ -407,7 +407,7 @@ async def to_mem0_memory_async( config: Optional[Config] = None, history_db_path: Optional[str] = None, ): - """将 MemoryCollection 转换为 agentrun-mem0ai Memory 客户端(异步) + """将 MemoryCollection 转换为 agentrun-mem0ai AsyncMemory 客户端(异步) Args: memory_collection_name: 记忆集合名称 @@ -415,7 +415,7 @@ async def to_mem0_memory_async( history_db_path: mem0 历史数据库路径(可选) Returns: - Memory: agentrun-mem0ai Memory 客户端实例 + AsyncMemory: agentrun-mem0ai AsyncMemory 客户端实例 Raises: ImportError: 如果未安装 agentrun-mem0ai 包 @@ -426,10 +426,10 @@ async def to_mem0_memory_async( ... "memoryCollection010901", ... config=config ... ) - >>> memory.add("用户喜欢吃苹果", user_id="user123") + >>> await memory.add("用户喜欢吃苹果", user_id="user123") """ try: - from agentrun_mem0 import Memory + from agentrun_mem0 import AsyncMemory except ImportError as e: raise ImportError( "agentrun-mem0ai package is required. Install it with: pip" @@ -446,8 +446,8 @@ async def to_mem0_memory_async( memory_collection, config, history_db_path ) - # 创建并返回 Memory 实例 - return Memory.from_config(mem0_config) + # 创建并返回 AsyncMemory 实例 + return await AsyncMemory.from_config(mem0_config) @classmethod def to_mem0_memory( @@ -620,13 +620,25 @@ async def _build_mem0_config_async( ) ) + embedder_config_dict = { + "model": embedder_config.config.model, + "openai_base_url": base_url, + "api_key": api_key, + } + + # 从 vector_store_config 中获取向量维度 + if ( + memory_collection.vector_store_config + and memory_collection.vector_store_config.config + and memory_collection.vector_store_config.config.vector_dimension + ): + embedder_config_dict["embedding_dims"] = ( + memory_collection.vector_store_config.config.vector_dimension + ) + mem0_config["embedder"] = { "provider": "openai", # mem0 使用 openai 兼容接口 - "config": { - "model": embedder_config.config.model, - "openai_base_url": base_url, - "api_key": api_key, - }, + "config": embedder_config_dict, } # 添加历史数据库路径 @@ -732,13 +744,25 @@ def _build_mem0_config( model_service_name, config ) + embedder_config_dict = { + "model": embedder_config.config.model, + "openai_base_url": base_url, + "api_key": api_key, + } + + # 从 vector_store_config 中获取向量维度 + if ( + memory_collection.vector_store_config + and memory_collection.vector_store_config.config + and memory_collection.vector_store_config.config.vector_dimension + ): + embedder_config_dict["embedding_dims"] = ( + memory_collection.vector_store_config.config.vector_dimension + ) + mem0_config["embedder"] = { "provider": "openai", # mem0 使用 openai 兼容接口 - "config": { - "model": embedder_config.config.model, - "openai_base_url": base_url, - "api_key": api_key, - }, + "config": embedder_config_dict, } # 添加历史数据库路径 diff --git a/codegen/codegen.py b/codegen/codegen.py index 315b98b..cf4ad29 100644 --- a/codegen/codegen.py +++ b/codegen/codegen.py @@ -206,6 +206,7 @@ def _generate_sync_code_for_file(async_file): content = ( line.replace("AsyncClient", "Client") .replace("AsyncOpenAI", "OpenAI") + .replace("AsyncMemory", "Memory") .replace("async_playwright", "sync_playwright") .replace("asyncio.gather(*", "(") .replace("_async", "") diff --git a/examples/memory_collection_example.py b/examples/memory_collection_example.py index 4ccb0b9..afd561f 100644 --- a/examples/memory_collection_example.py +++ b/examples/memory_collection_example.py @@ -23,8 +23,8 @@ from agentrun.utils.config import Config -async def main(): - """主函数 / Main function""" +async def memory_collection_basic_example(): + """MemoryCollection 基础操作示例 / MemoryCollection Basic Operations Example""" # 创建配置 # Create configuration @@ -155,8 +155,73 @@ async def main(): traceback.print_exc() - print("\n✅ 示例完成") + +async def async_mem0_memory_example(): + """异步 AsyncMemory 转换方法使用示例""" + print("\n=== 异步转换为 mem0ai AsyncMemory 客户端 ===") + + try: + # 使用高层 API 的 to_mem0_memory_async 方法 + # Use high-level API's to_mem0_memory_async method + memory = await MemoryCollection.to_mem0_memory_async( + "memoryCollection010901" + ) + print(f"✅ 成功创建 mem0ai AsyncMemory 客户端") + print(f" 类型: {type(memory)}") + + # 使用 mem0ai AsyncMemory 客户端进行操作 + # Use mem0ai AsyncMemory client for operations + user_id = "user456" + + # 添加记忆 + # Add memory + result = await memory.add( + "我喜欢喝咖啡和茶", + user_id=user_id, + metadata={"category": "beverage"}, + ) + print(f"\n✅ 添加记忆成功:") + for idx, res in enumerate(result.get("results", []), 1): + print(f" {idx}. ID: {res.get('id')}, 事件: {res.get('event')}") + + # 搜索记忆 + # Search memory + search_results = await memory.search( + "用户喜欢喝什么?", user_id=user_id + ) + print(f"\n✅ 搜索记忆结果:") + for idx, result in enumerate(search_results.get("results", []), 1): + print( + f" {idx}. 内容: {result.get('memory')}, 相似度:" + f" {result.get('score', 0):.4f}" + ) + + # 获取所有记忆 + # Get all memories + all_memories = await memory.get_all(user_id=user_id) + print(f"\n✅ 获取所有记忆:") + for idx, mem in enumerate(all_memories.get("results", []), 1): + print(f" {idx}. {mem.get('memory')}") + + except ImportError as e: + print(f"⚠️ mem0ai 未安装: {e}") + print(" 安装方法: pip install agentrun-sdk[mem0]") + except Exception as e: + print(f"❌ AsyncMemory 操作失败: {e}") + import traceback + + traceback.print_exc() if __name__ == "__main__": - asyncio.run(main()) + import asyncio + + # 运行基础操作示例 + # Run basic operations example + asyncio.run(memory_collection_basic_example()) + + # 运行异步 AsyncMemory 示例 + # Run async AsyncMemory example + asyncio.run(async_mem0_memory_example()) + + print("\n✅ 示例完成") diff --git a/pyproject.toml b/pyproject.toml index a1633d7..4107cd4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -16,7 +16,7 @@ dependencies = [ "alibabacloud-agentrun20250910>=5.2.0", "alibabacloud_tea_openapi>=0.4.2", "alibabacloud_bailian20231229>=2.6.2", - "agentrun-mem0ai>=0.0.6", + "agentrun-mem0ai>=0.0.10", ] [project.optional-dependencies] diff --git a/tests/unittests/memory_collection/test_memory_collection.py b/tests/unittests/memory_collection/test_memory_collection.py index d5c465c..1032240 100644 --- a/tests/unittests/memory_collection/test_memory_collection.py +++ b/tests/unittests/memory_collection/test_memory_collection.py @@ -364,3 +364,106 @@ def test_from_inner_object_with_extra(self): assert ( memory_collection.memory_collection_name == "test-memory-collection" ) + + +class TestMemoryCollectionToMem0Memory: + """测试 MemoryCollection.to_mem0_memory 和 to_mem0_memory_async 方法""" + + @patch("agentrun.memory_collection.client.MemoryCollectionControlAPI") + def test_to_mem0_memory_sync(self, mock_control_api_class): + """测试同步转换为 mem0 Memory 客户端""" + # Mock MemoryCollection 数据 + mock_control_api = MagicMock() + mock_data = MockMemoryCollectionData() + mock_control_api.get_memory_collection.return_value = mock_data + mock_control_api_class.return_value = mock_control_api + + # Mock Memory.from_config + with patch("agentrun_mem0.Memory") as mock_memory_class: + mock_memory_instance = MagicMock() + mock_memory_class.from_config.return_value = mock_memory_instance + + # 调用 to_mem0_memory + result = MemoryCollection.to_mem0_memory( + "test-memory-collection", + config=Config( + access_key_id="test-key", + access_key_secret="test-secret", + region_id="cn-hangzhou", + ), + ) + + # 验证返回的是 Memory 实例 + assert result == mock_memory_instance + mock_memory_class.from_config.assert_called_once() + + @patch("agentrun.memory_collection.client.MemoryCollectionControlAPI") + @pytest.mark.asyncio + async def test_to_mem0_memory_async(self, mock_control_api_class): + """测试异步转换为 mem0 AsyncMemory 客户端""" + # Mock MemoryCollection 数据 + mock_control_api = MagicMock() + mock_data = MockMemoryCollectionData() + mock_control_api.get_memory_collection_async = AsyncMock( + return_value=mock_data + ) + mock_control_api_class.return_value = mock_control_api + + # Mock AsyncMemory.from_config + with patch("agentrun_mem0.AsyncMemory") as mock_async_memory_class: + mock_async_memory_instance = MagicMock() + # from_config 是异步方法,需要返回 AsyncMock + mock_async_memory_class.from_config = AsyncMock( + return_value=mock_async_memory_instance + ) + + # 调用 to_mem0_memory_async + result = await MemoryCollection.to_mem0_memory_async( + "test-memory-collection", + config=Config( + access_key_id="test-key", + access_key_secret="test-secret", + region_id="cn-hangzhou", + ), + ) + + # 验证返回的是 AsyncMemory 实例 + assert result == mock_async_memory_instance + mock_async_memory_class.from_config.assert_called_once() + + @patch("agentrun.memory_collection.client.MemoryCollectionControlAPI") + def test_to_mem0_memory_import_error(self, mock_control_api_class): + """测试 mem0 包未安装时的错误处理""" + mock_control_api = MagicMock() + mock_control_api.get_memory_collection.return_value = ( + MockMemoryCollectionData() + ) + mock_control_api_class.return_value = mock_control_api + + # Mock import 失败 + with patch("builtins.__import__", side_effect=ImportError("No module")): + with pytest.raises(ImportError) as exc_info: + MemoryCollection.to_mem0_memory("test-memory-collection") + + assert "agentrun-mem0ai package is required" in str(exc_info.value) + + @patch("agentrun.memory_collection.client.MemoryCollectionControlAPI") + @pytest.mark.asyncio + async def test_to_mem0_memory_async_import_error( + self, mock_control_api_class + ): + """测试异步方法 mem0 包未安装时的错误处理""" + mock_control_api = MagicMock() + mock_control_api.get_memory_collection_async = AsyncMock( + return_value=MockMemoryCollectionData() + ) + mock_control_api_class.return_value = mock_control_api + + # Mock import 失败 + with patch("builtins.__import__", side_effect=ImportError("No module")): + with pytest.raises(ImportError) as exc_info: + await MemoryCollection.to_mem0_memory_async( + "test-memory-collection" + ) + + assert "agentrun-mem0ai package is required" in str(exc_info.value)