aip-agents-binary 0.5.25b1__py3-none-macosx_13_0_arm64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- aip_agents/__init__.py +65 -0
- aip_agents/__init__.pyi +19 -0
- aip_agents/a2a/__init__.py +19 -0
- aip_agents/a2a/__init__.pyi +3 -0
- aip_agents/a2a/server/__init__.py +10 -0
- aip_agents/a2a/server/__init__.pyi +4 -0
- aip_agents/a2a/server/base_executor.py +1086 -0
- aip_agents/a2a/server/base_executor.pyi +73 -0
- aip_agents/a2a/server/google_adk_executor.py +198 -0
- aip_agents/a2a/server/google_adk_executor.pyi +51 -0
- aip_agents/a2a/server/langflow_executor.py +180 -0
- aip_agents/a2a/server/langflow_executor.pyi +43 -0
- aip_agents/a2a/server/langgraph_executor.py +270 -0
- aip_agents/a2a/server/langgraph_executor.pyi +47 -0
- aip_agents/a2a/types.py +232 -0
- aip_agents/a2a/types.pyi +132 -0
- aip_agents/agent/__init__.py +27 -0
- aip_agents/agent/__init__.pyi +9 -0
- aip_agents/agent/base_agent.py +970 -0
- aip_agents/agent/base_agent.pyi +221 -0
- aip_agents/agent/base_langgraph_agent.py +2948 -0
- aip_agents/agent/base_langgraph_agent.pyi +232 -0
- aip_agents/agent/google_adk_agent.py +926 -0
- aip_agents/agent/google_adk_agent.pyi +141 -0
- aip_agents/agent/google_adk_constants.py +6 -0
- aip_agents/agent/google_adk_constants.pyi +3 -0
- aip_agents/agent/hitl/__init__.py +24 -0
- aip_agents/agent/hitl/__init__.pyi +6 -0
- aip_agents/agent/hitl/config.py +28 -0
- aip_agents/agent/hitl/config.pyi +15 -0
- aip_agents/agent/hitl/langgraph_hitl_mixin.py +515 -0
- aip_agents/agent/hitl/langgraph_hitl_mixin.pyi +42 -0
- aip_agents/agent/hitl/manager.py +532 -0
- aip_agents/agent/hitl/manager.pyi +200 -0
- aip_agents/agent/hitl/models.py +18 -0
- aip_agents/agent/hitl/models.pyi +3 -0
- aip_agents/agent/hitl/prompt/__init__.py +9 -0
- aip_agents/agent/hitl/prompt/__init__.pyi +4 -0
- aip_agents/agent/hitl/prompt/base.py +42 -0
- aip_agents/agent/hitl/prompt/base.pyi +24 -0
- aip_agents/agent/hitl/prompt/deferred.py +73 -0
- aip_agents/agent/hitl/prompt/deferred.pyi +30 -0
- aip_agents/agent/hitl/registry.py +149 -0
- aip_agents/agent/hitl/registry.pyi +101 -0
- aip_agents/agent/interface.py +138 -0
- aip_agents/agent/interface.pyi +81 -0
- aip_agents/agent/interfaces.py +65 -0
- aip_agents/agent/interfaces.pyi +44 -0
- aip_agents/agent/langflow_agent.py +464 -0
- aip_agents/agent/langflow_agent.pyi +133 -0
- aip_agents/agent/langgraph_memory_enhancer_agent.py +433 -0
- aip_agents/agent/langgraph_memory_enhancer_agent.pyi +49 -0
- aip_agents/agent/langgraph_react_agent.py +2596 -0
- aip_agents/agent/langgraph_react_agent.pyi +131 -0
- aip_agents/agent/system_instruction_context.py +34 -0
- aip_agents/agent/system_instruction_context.pyi +13 -0
- aip_agents/clients/__init__.py +10 -0
- aip_agents/clients/__init__.pyi +4 -0
- aip_agents/clients/langflow/__init__.py +10 -0
- aip_agents/clients/langflow/__init__.pyi +4 -0
- aip_agents/clients/langflow/client.py +477 -0
- aip_agents/clients/langflow/client.pyi +140 -0
- aip_agents/clients/langflow/types.py +18 -0
- aip_agents/clients/langflow/types.pyi +7 -0
- aip_agents/constants.py +23 -0
- aip_agents/constants.pyi +7 -0
- aip_agents/credentials/manager.py +132 -0
- aip_agents/examples/__init__.py +5 -0
- aip_agents/examples/__init__.pyi +0 -0
- aip_agents/examples/compare_streaming_client.py +783 -0
- aip_agents/examples/compare_streaming_client.pyi +48 -0
- aip_agents/examples/compare_streaming_server.py +142 -0
- aip_agents/examples/compare_streaming_server.pyi +18 -0
- aip_agents/examples/demo_memory_recall.py +401 -0
- aip_agents/examples/demo_memory_recall.pyi +58 -0
- aip_agents/examples/hello_world_a2a_google_adk_client.py +49 -0
- aip_agents/examples/hello_world_a2a_google_adk_client.pyi +9 -0
- aip_agents/examples/hello_world_a2a_google_adk_client_agent.py +48 -0
- aip_agents/examples/hello_world_a2a_google_adk_client_agent.pyi +9 -0
- aip_agents/examples/hello_world_a2a_google_adk_client_streaming.py +60 -0
- aip_agents/examples/hello_world_a2a_google_adk_client_streaming.pyi +9 -0
- aip_agents/examples/hello_world_a2a_google_adk_server.py +79 -0
- aip_agents/examples/hello_world_a2a_google_adk_server.pyi +15 -0
- aip_agents/examples/hello_world_a2a_langchain_client.py +39 -0
- aip_agents/examples/hello_world_a2a_langchain_client.pyi +5 -0
- aip_agents/examples/hello_world_a2a_langchain_client_agent.py +39 -0
- aip_agents/examples/hello_world_a2a_langchain_client_agent.pyi +5 -0
- aip_agents/examples/hello_world_a2a_langchain_client_lm_invoker.py +37 -0
- aip_agents/examples/hello_world_a2a_langchain_client_lm_invoker.pyi +5 -0
- aip_agents/examples/hello_world_a2a_langchain_client_streaming.py +41 -0
- aip_agents/examples/hello_world_a2a_langchain_client_streaming.pyi +5 -0
- aip_agents/examples/hello_world_a2a_langchain_reference_client_streaming.py +60 -0
- aip_agents/examples/hello_world_a2a_langchain_reference_client_streaming.pyi +5 -0
- aip_agents/examples/hello_world_a2a_langchain_reference_server.py +105 -0
- aip_agents/examples/hello_world_a2a_langchain_reference_server.pyi +15 -0
- aip_agents/examples/hello_world_a2a_langchain_server.py +79 -0
- aip_agents/examples/hello_world_a2a_langchain_server.pyi +15 -0
- aip_agents/examples/hello_world_a2a_langchain_server_lm_invoker.py +78 -0
- aip_agents/examples/hello_world_a2a_langchain_server_lm_invoker.pyi +15 -0
- aip_agents/examples/hello_world_a2a_langflow_client.py +83 -0
- aip_agents/examples/hello_world_a2a_langflow_client.pyi +9 -0
- aip_agents/examples/hello_world_a2a_langflow_server.py +82 -0
- aip_agents/examples/hello_world_a2a_langflow_server.pyi +14 -0
- aip_agents/examples/hello_world_a2a_langgraph_artifact_client.py +73 -0
- aip_agents/examples/hello_world_a2a_langgraph_artifact_client.pyi +5 -0
- aip_agents/examples/hello_world_a2a_langgraph_artifact_client_streaming.py +76 -0
- aip_agents/examples/hello_world_a2a_langgraph_artifact_client_streaming.pyi +5 -0
- aip_agents/examples/hello_world_a2a_langgraph_artifact_server.py +92 -0
- aip_agents/examples/hello_world_a2a_langgraph_artifact_server.pyi +16 -0
- aip_agents/examples/hello_world_a2a_langgraph_client.py +54 -0
- aip_agents/examples/hello_world_a2a_langgraph_client.pyi +9 -0
- aip_agents/examples/hello_world_a2a_langgraph_client_agent.py +54 -0
- aip_agents/examples/hello_world_a2a_langgraph_client_agent.pyi +9 -0
- aip_agents/examples/hello_world_a2a_langgraph_client_agent_lm_invoker.py +32 -0
- aip_agents/examples/hello_world_a2a_langgraph_client_agent_lm_invoker.pyi +2 -0
- aip_agents/examples/hello_world_a2a_langgraph_client_streaming.py +50 -0
- aip_agents/examples/hello_world_a2a_langgraph_client_streaming.pyi +9 -0
- aip_agents/examples/hello_world_a2a_langgraph_client_streaming_lm_invoker.py +44 -0
- aip_agents/examples/hello_world_a2a_langgraph_client_streaming_lm_invoker.pyi +5 -0
- aip_agents/examples/hello_world_a2a_langgraph_client_streaming_tool_streaming.py +92 -0
- aip_agents/examples/hello_world_a2a_langgraph_client_streaming_tool_streaming.pyi +5 -0
- aip_agents/examples/hello_world_a2a_langgraph_server.py +84 -0
- aip_agents/examples/hello_world_a2a_langgraph_server.pyi +14 -0
- aip_agents/examples/hello_world_a2a_langgraph_server_lm_invoker.py +79 -0
- aip_agents/examples/hello_world_a2a_langgraph_server_lm_invoker.pyi +15 -0
- aip_agents/examples/hello_world_a2a_langgraph_server_tool_streaming.py +132 -0
- aip_agents/examples/hello_world_a2a_langgraph_server_tool_streaming.pyi +15 -0
- aip_agents/examples/hello_world_a2a_mcp_langgraph.py +196 -0
- aip_agents/examples/hello_world_a2a_mcp_langgraph.pyi +48 -0
- aip_agents/examples/hello_world_a2a_three_level_agent_hierarchy_client.py +244 -0
- aip_agents/examples/hello_world_a2a_three_level_agent_hierarchy_client.pyi +48 -0
- aip_agents/examples/hello_world_a2a_three_level_agent_hierarchy_server.py +251 -0
- aip_agents/examples/hello_world_a2a_three_level_agent_hierarchy_server.pyi +45 -0
- aip_agents/examples/hello_world_a2a_with_metadata_langchain_client.py +57 -0
- aip_agents/examples/hello_world_a2a_with_metadata_langchain_client.pyi +5 -0
- aip_agents/examples/hello_world_a2a_with_metadata_langchain_server_lm_invoker.py +80 -0
- aip_agents/examples/hello_world_a2a_with_metadata_langchain_server_lm_invoker.pyi +15 -0
- aip_agents/examples/hello_world_google_adk.py +41 -0
- aip_agents/examples/hello_world_google_adk.pyi +5 -0
- aip_agents/examples/hello_world_google_adk_mcp_http.py +34 -0
- aip_agents/examples/hello_world_google_adk_mcp_http.pyi +5 -0
- aip_agents/examples/hello_world_google_adk_mcp_http_stream.py +40 -0
- aip_agents/examples/hello_world_google_adk_mcp_http_stream.pyi +5 -0
- aip_agents/examples/hello_world_google_adk_mcp_sse.py +44 -0
- aip_agents/examples/hello_world_google_adk_mcp_sse.pyi +5 -0
- aip_agents/examples/hello_world_google_adk_mcp_sse_stream.py +48 -0
- aip_agents/examples/hello_world_google_adk_mcp_sse_stream.pyi +5 -0
- aip_agents/examples/hello_world_google_adk_mcp_stdio.py +44 -0
- aip_agents/examples/hello_world_google_adk_mcp_stdio.pyi +5 -0
- aip_agents/examples/hello_world_google_adk_mcp_stdio_stream.py +48 -0
- aip_agents/examples/hello_world_google_adk_mcp_stdio_stream.pyi +5 -0
- aip_agents/examples/hello_world_google_adk_stream.py +44 -0
- aip_agents/examples/hello_world_google_adk_stream.pyi +5 -0
- aip_agents/examples/hello_world_langchain.py +28 -0
- aip_agents/examples/hello_world_langchain.pyi +5 -0
- aip_agents/examples/hello_world_langchain_lm_invoker.py +15 -0
- aip_agents/examples/hello_world_langchain_lm_invoker.pyi +2 -0
- aip_agents/examples/hello_world_langchain_mcp_http.py +34 -0
- aip_agents/examples/hello_world_langchain_mcp_http.pyi +5 -0
- aip_agents/examples/hello_world_langchain_mcp_http_interactive.py +130 -0
- aip_agents/examples/hello_world_langchain_mcp_http_interactive.pyi +16 -0
- aip_agents/examples/hello_world_langchain_mcp_http_stream.py +42 -0
- aip_agents/examples/hello_world_langchain_mcp_http_stream.pyi +5 -0
- aip_agents/examples/hello_world_langchain_mcp_multi_server.py +155 -0
- aip_agents/examples/hello_world_langchain_mcp_multi_server.pyi +18 -0
- aip_agents/examples/hello_world_langchain_mcp_sse.py +34 -0
- aip_agents/examples/hello_world_langchain_mcp_sse.pyi +5 -0
- aip_agents/examples/hello_world_langchain_mcp_sse_stream.py +40 -0
- aip_agents/examples/hello_world_langchain_mcp_sse_stream.pyi +5 -0
- aip_agents/examples/hello_world_langchain_mcp_stdio.py +30 -0
- aip_agents/examples/hello_world_langchain_mcp_stdio.pyi +5 -0
- aip_agents/examples/hello_world_langchain_mcp_stdio_stream.py +41 -0
- aip_agents/examples/hello_world_langchain_mcp_stdio_stream.pyi +5 -0
- aip_agents/examples/hello_world_langchain_stream.py +36 -0
- aip_agents/examples/hello_world_langchain_stream.pyi +5 -0
- aip_agents/examples/hello_world_langchain_stream_lm_invoker.py +39 -0
- aip_agents/examples/hello_world_langchain_stream_lm_invoker.pyi +5 -0
- aip_agents/examples/hello_world_langflow_agent.py +163 -0
- aip_agents/examples/hello_world_langflow_agent.pyi +35 -0
- aip_agents/examples/hello_world_langgraph.py +39 -0
- aip_agents/examples/hello_world_langgraph.pyi +5 -0
- aip_agents/examples/hello_world_langgraph_gl_connector_twitter.py +44 -0
- aip_agents/examples/hello_world_langgraph_gl_connector_twitter.pyi +5 -0
- aip_agents/examples/hello_world_langgraph_mcp_http.py +31 -0
- aip_agents/examples/hello_world_langgraph_mcp_http.pyi +5 -0
- aip_agents/examples/hello_world_langgraph_mcp_http_stream.py +34 -0
- aip_agents/examples/hello_world_langgraph_mcp_http_stream.pyi +5 -0
- aip_agents/examples/hello_world_langgraph_mcp_sse.py +35 -0
- aip_agents/examples/hello_world_langgraph_mcp_sse.pyi +5 -0
- aip_agents/examples/hello_world_langgraph_mcp_sse_stream.py +50 -0
- aip_agents/examples/hello_world_langgraph_mcp_sse_stream.pyi +5 -0
- aip_agents/examples/hello_world_langgraph_mcp_stdio.py +35 -0
- aip_agents/examples/hello_world_langgraph_mcp_stdio.pyi +5 -0
- aip_agents/examples/hello_world_langgraph_mcp_stdio_stream.py +50 -0
- aip_agents/examples/hello_world_langgraph_mcp_stdio_stream.pyi +5 -0
- aip_agents/examples/hello_world_langgraph_stream.py +43 -0
- aip_agents/examples/hello_world_langgraph_stream.pyi +5 -0
- aip_agents/examples/hello_world_langgraph_stream_lm_invoker.py +37 -0
- aip_agents/examples/hello_world_langgraph_stream_lm_invoker.pyi +5 -0
- aip_agents/examples/hello_world_model_switch_cli.py +210 -0
- aip_agents/examples/hello_world_model_switch_cli.pyi +30 -0
- aip_agents/examples/hello_world_multi_agent_adk.py +75 -0
- aip_agents/examples/hello_world_multi_agent_adk.pyi +6 -0
- aip_agents/examples/hello_world_multi_agent_langchain.py +54 -0
- aip_agents/examples/hello_world_multi_agent_langchain.pyi +5 -0
- aip_agents/examples/hello_world_multi_agent_langgraph.py +66 -0
- aip_agents/examples/hello_world_multi_agent_langgraph.pyi +5 -0
- aip_agents/examples/hello_world_multi_agent_langgraph_lm_invoker.py +69 -0
- aip_agents/examples/hello_world_multi_agent_langgraph_lm_invoker.pyi +5 -0
- aip_agents/examples/hello_world_pii_logger.py +21 -0
- aip_agents/examples/hello_world_pii_logger.pyi +5 -0
- aip_agents/examples/hello_world_sentry.py +133 -0
- aip_agents/examples/hello_world_sentry.pyi +21 -0
- aip_agents/examples/hello_world_step_limits.py +273 -0
- aip_agents/examples/hello_world_step_limits.pyi +17 -0
- aip_agents/examples/hello_world_stock_a2a_server.py +103 -0
- aip_agents/examples/hello_world_stock_a2a_server.pyi +17 -0
- aip_agents/examples/hello_world_tool_output_client.py +46 -0
- aip_agents/examples/hello_world_tool_output_client.pyi +5 -0
- aip_agents/examples/hello_world_tool_output_server.py +114 -0
- aip_agents/examples/hello_world_tool_output_server.pyi +19 -0
- aip_agents/examples/hitl_demo.py +724 -0
- aip_agents/examples/hitl_demo.pyi +67 -0
- aip_agents/examples/mcp_configs/configs.py +63 -0
- aip_agents/examples/mcp_servers/common.py +76 -0
- aip_agents/examples/mcp_servers/mcp_name.py +29 -0
- aip_agents/examples/mcp_servers/mcp_server_http.py +19 -0
- aip_agents/examples/mcp_servers/mcp_server_sse.py +19 -0
- aip_agents/examples/mcp_servers/mcp_server_stdio.py +19 -0
- aip_agents/examples/mcp_servers/mcp_time.py +10 -0
- aip_agents/examples/pii_demo_langgraph_client.py +69 -0
- aip_agents/examples/pii_demo_langgraph_client.pyi +5 -0
- aip_agents/examples/pii_demo_langgraph_server.py +126 -0
- aip_agents/examples/pii_demo_langgraph_server.pyi +20 -0
- aip_agents/examples/pii_demo_multi_agent_client.py +80 -0
- aip_agents/examples/pii_demo_multi_agent_client.pyi +5 -0
- aip_agents/examples/pii_demo_multi_agent_server.py +247 -0
- aip_agents/examples/pii_demo_multi_agent_server.pyi +40 -0
- aip_agents/examples/todolist_planning_a2a_langchain_client.py +70 -0
- aip_agents/examples/todolist_planning_a2a_langchain_client.pyi +5 -0
- aip_agents/examples/todolist_planning_a2a_langgraph_server.py +88 -0
- aip_agents/examples/todolist_planning_a2a_langgraph_server.pyi +19 -0
- aip_agents/examples/tools/__init__.py +27 -0
- aip_agents/examples/tools/__init__.pyi +9 -0
- aip_agents/examples/tools/adk_arithmetic_tools.py +36 -0
- aip_agents/examples/tools/adk_arithmetic_tools.pyi +24 -0
- aip_agents/examples/tools/adk_weather_tool.py +60 -0
- aip_agents/examples/tools/adk_weather_tool.pyi +18 -0
- aip_agents/examples/tools/data_generator_tool.py +103 -0
- aip_agents/examples/tools/data_generator_tool.pyi +15 -0
- aip_agents/examples/tools/data_visualization_tool.py +312 -0
- aip_agents/examples/tools/data_visualization_tool.pyi +19 -0
- aip_agents/examples/tools/image_artifact_tool.py +136 -0
- aip_agents/examples/tools/image_artifact_tool.pyi +26 -0
- aip_agents/examples/tools/langchain_arithmetic_tools.py +26 -0
- aip_agents/examples/tools/langchain_arithmetic_tools.pyi +17 -0
- aip_agents/examples/tools/langchain_currency_exchange_tool.py +88 -0
- aip_agents/examples/tools/langchain_currency_exchange_tool.pyi +20 -0
- aip_agents/examples/tools/langchain_graph_artifact_tool.py +172 -0
- aip_agents/examples/tools/langchain_graph_artifact_tool.pyi +25 -0
- aip_agents/examples/tools/langchain_weather_tool.py +48 -0
- aip_agents/examples/tools/langchain_weather_tool.pyi +19 -0
- aip_agents/examples/tools/langgraph_streaming_tool.py +130 -0
- aip_agents/examples/tools/langgraph_streaming_tool.pyi +43 -0
- aip_agents/examples/tools/mock_retrieval_tool.py +56 -0
- aip_agents/examples/tools/mock_retrieval_tool.pyi +13 -0
- aip_agents/examples/tools/pii_demo_tools.py +189 -0
- aip_agents/examples/tools/pii_demo_tools.pyi +54 -0
- aip_agents/examples/tools/random_chart_tool.py +142 -0
- aip_agents/examples/tools/random_chart_tool.pyi +20 -0
- aip_agents/examples/tools/serper_tool.py +202 -0
- aip_agents/examples/tools/serper_tool.pyi +16 -0
- aip_agents/examples/tools/stock_tools.py +82 -0
- aip_agents/examples/tools/stock_tools.pyi +36 -0
- aip_agents/examples/tools/table_generator_tool.py +167 -0
- aip_agents/examples/tools/table_generator_tool.pyi +22 -0
- aip_agents/examples/tools/time_tool.py +82 -0
- aip_agents/examples/tools/time_tool.pyi +15 -0
- aip_agents/examples/tools/weather_forecast_tool.py +38 -0
- aip_agents/examples/tools/weather_forecast_tool.pyi +14 -0
- aip_agents/executor/agent_executor.py +473 -0
- aip_agents/executor/base.py +48 -0
- aip_agents/guardrails/__init__.py +83 -0
- aip_agents/guardrails/__init__.pyi +6 -0
- aip_agents/guardrails/engines/__init__.py +69 -0
- aip_agents/guardrails/engines/__init__.pyi +4 -0
- aip_agents/guardrails/engines/base.py +90 -0
- aip_agents/guardrails/engines/base.pyi +61 -0
- aip_agents/guardrails/engines/nemo.py +101 -0
- aip_agents/guardrails/engines/nemo.pyi +46 -0
- aip_agents/guardrails/engines/phrase_matcher.py +113 -0
- aip_agents/guardrails/engines/phrase_matcher.pyi +48 -0
- aip_agents/guardrails/exceptions.py +39 -0
- aip_agents/guardrails/exceptions.pyi +23 -0
- aip_agents/guardrails/manager.py +163 -0
- aip_agents/guardrails/manager.pyi +42 -0
- aip_agents/guardrails/middleware.py +199 -0
- aip_agents/guardrails/middleware.pyi +87 -0
- aip_agents/guardrails/schemas.py +63 -0
- aip_agents/guardrails/schemas.pyi +43 -0
- aip_agents/guardrails/utils.py +45 -0
- aip_agents/guardrails/utils.pyi +19 -0
- aip_agents/mcp/__init__.py +1 -0
- aip_agents/mcp/__init__.pyi +0 -0
- aip_agents/mcp/client/__init__.py +14 -0
- aip_agents/mcp/client/__init__.pyi +5 -0
- aip_agents/mcp/client/base_mcp_client.py +369 -0
- aip_agents/mcp/client/base_mcp_client.pyi +148 -0
- aip_agents/mcp/client/connection_manager.py +193 -0
- aip_agents/mcp/client/connection_manager.pyi +48 -0
- aip_agents/mcp/client/google_adk/__init__.py +11 -0
- aip_agents/mcp/client/google_adk/__init__.pyi +3 -0
- aip_agents/mcp/client/google_adk/client.py +381 -0
- aip_agents/mcp/client/google_adk/client.pyi +75 -0
- aip_agents/mcp/client/langchain/__init__.py +11 -0
- aip_agents/mcp/client/langchain/__init__.pyi +3 -0
- aip_agents/mcp/client/langchain/client.py +265 -0
- aip_agents/mcp/client/langchain/client.pyi +48 -0
- aip_agents/mcp/client/persistent_session.py +362 -0
- aip_agents/mcp/client/persistent_session.pyi +113 -0
- aip_agents/mcp/client/session_pool.py +351 -0
- aip_agents/mcp/client/session_pool.pyi +101 -0
- aip_agents/mcp/client/transports.py +228 -0
- aip_agents/mcp/client/transports.pyi +123 -0
- aip_agents/mcp/utils/__init__.py +7 -0
- aip_agents/mcp/utils/__init__.pyi +0 -0
- aip_agents/mcp/utils/config_validator.py +139 -0
- aip_agents/mcp/utils/config_validator.pyi +82 -0
- aip_agents/memory/__init__.py +14 -0
- aip_agents/memory/__init__.pyi +5 -0
- aip_agents/memory/adapters/__init__.py +10 -0
- aip_agents/memory/adapters/__init__.pyi +4 -0
- aip_agents/memory/adapters/base_adapter.py +717 -0
- aip_agents/memory/adapters/base_adapter.pyi +150 -0
- aip_agents/memory/adapters/mem0.py +84 -0
- aip_agents/memory/adapters/mem0.pyi +22 -0
- aip_agents/memory/base.py +84 -0
- aip_agents/memory/base.pyi +60 -0
- aip_agents/memory/constants.py +49 -0
- aip_agents/memory/constants.pyi +25 -0
- aip_agents/memory/factory.py +86 -0
- aip_agents/memory/factory.pyi +24 -0
- aip_agents/memory/guidance.py +20 -0
- aip_agents/memory/guidance.pyi +3 -0
- aip_agents/memory/simple_memory.py +47 -0
- aip_agents/memory/simple_memory.pyi +23 -0
- aip_agents/middleware/__init__.py +17 -0
- aip_agents/middleware/__init__.pyi +5 -0
- aip_agents/middleware/base.py +96 -0
- aip_agents/middleware/base.pyi +75 -0
- aip_agents/middleware/manager.py +150 -0
- aip_agents/middleware/manager.pyi +84 -0
- aip_agents/middleware/todolist.py +274 -0
- aip_agents/middleware/todolist.pyi +125 -0
- aip_agents/schema/__init__.py +69 -0
- aip_agents/schema/__init__.pyi +9 -0
- aip_agents/schema/a2a.py +56 -0
- aip_agents/schema/a2a.pyi +40 -0
- aip_agents/schema/agent.py +111 -0
- aip_agents/schema/agent.pyi +65 -0
- aip_agents/schema/hitl.py +157 -0
- aip_agents/schema/hitl.pyi +89 -0
- aip_agents/schema/langgraph.py +37 -0
- aip_agents/schema/langgraph.pyi +28 -0
- aip_agents/schema/model_id.py +97 -0
- aip_agents/schema/model_id.pyi +54 -0
- aip_agents/schema/step_limit.py +108 -0
- aip_agents/schema/step_limit.pyi +63 -0
- aip_agents/schema/storage.py +40 -0
- aip_agents/schema/storage.pyi +21 -0
- aip_agents/sentry/__init__.py +11 -0
- aip_agents/sentry/__init__.pyi +3 -0
- aip_agents/sentry/sentry.py +151 -0
- aip_agents/sentry/sentry.pyi +48 -0
- aip_agents/storage/__init__.py +41 -0
- aip_agents/storage/__init__.pyi +8 -0
- aip_agents/storage/base.py +85 -0
- aip_agents/storage/base.pyi +58 -0
- aip_agents/storage/clients/__init__.py +12 -0
- aip_agents/storage/clients/__init__.pyi +3 -0
- aip_agents/storage/clients/minio_client.py +318 -0
- aip_agents/storage/clients/minio_client.pyi +137 -0
- aip_agents/storage/config.py +62 -0
- aip_agents/storage/config.pyi +29 -0
- aip_agents/storage/providers/__init__.py +15 -0
- aip_agents/storage/providers/__init__.pyi +5 -0
- aip_agents/storage/providers/base.py +106 -0
- aip_agents/storage/providers/base.pyi +88 -0
- aip_agents/storage/providers/memory.py +114 -0
- aip_agents/storage/providers/memory.pyi +79 -0
- aip_agents/storage/providers/object_storage.py +214 -0
- aip_agents/storage/providers/object_storage.pyi +98 -0
- aip_agents/tools/__init__.py +53 -0
- aip_agents/tools/__init__.pyi +9 -0
- aip_agents/tools/browser_use/__init__.py +82 -0
- aip_agents/tools/browser_use/__init__.pyi +14 -0
- aip_agents/tools/browser_use/action_parser.py +103 -0
- aip_agents/tools/browser_use/action_parser.pyi +18 -0
- aip_agents/tools/browser_use/browser_use_tool.py +1112 -0
- aip_agents/tools/browser_use/browser_use_tool.pyi +50 -0
- aip_agents/tools/browser_use/llm_config.py +120 -0
- aip_agents/tools/browser_use/llm_config.pyi +52 -0
- aip_agents/tools/browser_use/minio_storage.py +198 -0
- aip_agents/tools/browser_use/minio_storage.pyi +109 -0
- aip_agents/tools/browser_use/schemas.py +119 -0
- aip_agents/tools/browser_use/schemas.pyi +32 -0
- aip_agents/tools/browser_use/session.py +76 -0
- aip_agents/tools/browser_use/session.pyi +4 -0
- aip_agents/tools/browser_use/session_errors.py +132 -0
- aip_agents/tools/browser_use/session_errors.pyi +53 -0
- aip_agents/tools/browser_use/steel_session_recording.py +317 -0
- aip_agents/tools/browser_use/steel_session_recording.pyi +63 -0
- aip_agents/tools/browser_use/streaming.py +813 -0
- aip_agents/tools/browser_use/streaming.pyi +81 -0
- aip_agents/tools/browser_use/structured_data_parser.py +257 -0
- aip_agents/tools/browser_use/structured_data_parser.pyi +86 -0
- aip_agents/tools/browser_use/structured_data_recovery.py +204 -0
- aip_agents/tools/browser_use/structured_data_recovery.pyi +43 -0
- aip_agents/tools/browser_use/types.py +78 -0
- aip_agents/tools/browser_use/types.pyi +45 -0
- aip_agents/tools/code_sandbox/__init__.py +26 -0
- aip_agents/tools/code_sandbox/__init__.pyi +3 -0
- aip_agents/tools/code_sandbox/constant.py +13 -0
- aip_agents/tools/code_sandbox/constant.pyi +4 -0
- aip_agents/tools/code_sandbox/e2b_cloud_sandbox_extended.py +306 -0
- aip_agents/tools/code_sandbox/e2b_cloud_sandbox_extended.pyi +102 -0
- aip_agents/tools/code_sandbox/e2b_sandbox_tool.py +411 -0
- aip_agents/tools/code_sandbox/e2b_sandbox_tool.pyi +29 -0
- aip_agents/tools/constants.py +177 -0
- aip_agents/tools/constants.pyi +138 -0
- aip_agents/tools/document_loader/__init__.py +44 -0
- aip_agents/tools/document_loader/__init__.pyi +7 -0
- aip_agents/tools/document_loader/base_reader.py +302 -0
- aip_agents/tools/document_loader/base_reader.pyi +75 -0
- aip_agents/tools/document_loader/docx_reader_tool.py +68 -0
- aip_agents/tools/document_loader/docx_reader_tool.pyi +10 -0
- aip_agents/tools/document_loader/excel_reader_tool.py +171 -0
- aip_agents/tools/document_loader/excel_reader_tool.pyi +26 -0
- aip_agents/tools/document_loader/pdf_reader_tool.py +79 -0
- aip_agents/tools/document_loader/pdf_reader_tool.pyi +11 -0
- aip_agents/tools/document_loader/pdf_splitter.py +169 -0
- aip_agents/tools/document_loader/pdf_splitter.pyi +18 -0
- aip_agents/tools/gl_connector/__init__.py +5 -0
- aip_agents/tools/gl_connector/__init__.pyi +3 -0
- aip_agents/tools/gl_connector/tool.py +383 -0
- aip_agents/tools/gl_connector/tool.pyi +74 -0
- aip_agents/tools/gl_connector_tools.py +119 -0
- aip_agents/tools/gl_connector_tools.pyi +39 -0
- aip_agents/tools/memory_search/__init__.py +22 -0
- aip_agents/tools/memory_search/__init__.pyi +5 -0
- aip_agents/tools/memory_search/base.py +200 -0
- aip_agents/tools/memory_search/base.pyi +69 -0
- aip_agents/tools/memory_search/mem0.py +258 -0
- aip_agents/tools/memory_search/mem0.pyi +19 -0
- aip_agents/tools/memory_search/schema.py +48 -0
- aip_agents/tools/memory_search/schema.pyi +15 -0
- aip_agents/tools/memory_search_tool.py +26 -0
- aip_agents/tools/memory_search_tool.pyi +3 -0
- aip_agents/tools/time_tool.py +117 -0
- aip_agents/tools/time_tool.pyi +16 -0
- aip_agents/tools/tool_config_injector.py +300 -0
- aip_agents/tools/tool_config_injector.pyi +26 -0
- aip_agents/tools/web_search/__init__.py +15 -0
- aip_agents/tools/web_search/__init__.pyi +3 -0
- aip_agents/tools/web_search/serper_tool.py +187 -0
- aip_agents/tools/web_search/serper_tool.pyi +19 -0
- aip_agents/types/__init__.py +70 -0
- aip_agents/types/__init__.pyi +36 -0
- aip_agents/types/a2a_events.py +13 -0
- aip_agents/types/a2a_events.pyi +3 -0
- aip_agents/utils/__init__.py +79 -0
- aip_agents/utils/__init__.pyi +11 -0
- aip_agents/utils/a2a_connector.py +1757 -0
- aip_agents/utils/a2a_connector.pyi +146 -0
- aip_agents/utils/artifact_helpers.py +502 -0
- aip_agents/utils/artifact_helpers.pyi +203 -0
- aip_agents/utils/constants.py +22 -0
- aip_agents/utils/constants.pyi +10 -0
- aip_agents/utils/datetime/__init__.py +34 -0
- aip_agents/utils/datetime/__init__.pyi +4 -0
- aip_agents/utils/datetime/normalization.py +231 -0
- aip_agents/utils/datetime/normalization.pyi +95 -0
- aip_agents/utils/datetime/timezone.py +206 -0
- aip_agents/utils/datetime/timezone.pyi +48 -0
- aip_agents/utils/env_loader.py +27 -0
- aip_agents/utils/env_loader.pyi +10 -0
- aip_agents/utils/event_handler_registry.py +58 -0
- aip_agents/utils/event_handler_registry.pyi +23 -0
- aip_agents/utils/file_prompt_utils.py +176 -0
- aip_agents/utils/file_prompt_utils.pyi +21 -0
- aip_agents/utils/final_response_builder.py +211 -0
- aip_agents/utils/final_response_builder.pyi +34 -0
- aip_agents/utils/formatter_llm_client.py +231 -0
- aip_agents/utils/formatter_llm_client.pyi +71 -0
- aip_agents/utils/langgraph/__init__.py +19 -0
- aip_agents/utils/langgraph/__init__.pyi +3 -0
- aip_agents/utils/langgraph/converter.py +128 -0
- aip_agents/utils/langgraph/converter.pyi +49 -0
- aip_agents/utils/langgraph/tool_managers/__init__.py +15 -0
- aip_agents/utils/langgraph/tool_managers/__init__.pyi +5 -0
- aip_agents/utils/langgraph/tool_managers/a2a_tool_manager.py +99 -0
- aip_agents/utils/langgraph/tool_managers/a2a_tool_manager.pyi +35 -0
- aip_agents/utils/langgraph/tool_managers/base_tool_manager.py +66 -0
- aip_agents/utils/langgraph/tool_managers/base_tool_manager.pyi +48 -0
- aip_agents/utils/langgraph/tool_managers/delegation_tool_manager.py +1071 -0
- aip_agents/utils/langgraph/tool_managers/delegation_tool_manager.pyi +56 -0
- aip_agents/utils/langgraph/tool_output_management.py +967 -0
- aip_agents/utils/langgraph/tool_output_management.pyi +292 -0
- aip_agents/utils/logger.py +195 -0
- aip_agents/utils/logger.pyi +60 -0
- aip_agents/utils/metadata/__init__.py +27 -0
- aip_agents/utils/metadata/__init__.pyi +5 -0
- aip_agents/utils/metadata/activity_metadata_helper.py +407 -0
- aip_agents/utils/metadata/activity_metadata_helper.pyi +25 -0
- aip_agents/utils/metadata/activity_narrative/__init__.py +35 -0
- aip_agents/utils/metadata/activity_narrative/__init__.pyi +7 -0
- aip_agents/utils/metadata/activity_narrative/builder.py +817 -0
- aip_agents/utils/metadata/activity_narrative/builder.pyi +35 -0
- aip_agents/utils/metadata/activity_narrative/constants.py +51 -0
- aip_agents/utils/metadata/activity_narrative/constants.pyi +10 -0
- aip_agents/utils/metadata/activity_narrative/context.py +49 -0
- aip_agents/utils/metadata/activity_narrative/context.pyi +32 -0
- aip_agents/utils/metadata/activity_narrative/formatters.py +230 -0
- aip_agents/utils/metadata/activity_narrative/formatters.pyi +48 -0
- aip_agents/utils/metadata/activity_narrative/utils.py +35 -0
- aip_agents/utils/metadata/activity_narrative/utils.pyi +12 -0
- aip_agents/utils/metadata/schemas/__init__.py +16 -0
- aip_agents/utils/metadata/schemas/__init__.pyi +4 -0
- aip_agents/utils/metadata/schemas/activity_schema.py +29 -0
- aip_agents/utils/metadata/schemas/activity_schema.pyi +18 -0
- aip_agents/utils/metadata/schemas/thinking_schema.py +31 -0
- aip_agents/utils/metadata/schemas/thinking_schema.pyi +20 -0
- aip_agents/utils/metadata/thinking_metadata_helper.py +38 -0
- aip_agents/utils/metadata/thinking_metadata_helper.pyi +4 -0
- aip_agents/utils/metadata_helper.py +358 -0
- aip_agents/utils/metadata_helper.pyi +117 -0
- aip_agents/utils/name_preprocessor/__init__.py +17 -0
- aip_agents/utils/name_preprocessor/__init__.pyi +6 -0
- aip_agents/utils/name_preprocessor/base_name_preprocessor.py +73 -0
- aip_agents/utils/name_preprocessor/base_name_preprocessor.pyi +52 -0
- aip_agents/utils/name_preprocessor/google_name_preprocessor.py +100 -0
- aip_agents/utils/name_preprocessor/google_name_preprocessor.pyi +38 -0
- aip_agents/utils/name_preprocessor/name_preprocessor.py +87 -0
- aip_agents/utils/name_preprocessor/name_preprocessor.pyi +41 -0
- aip_agents/utils/name_preprocessor/openai_name_preprocessor.py +48 -0
- aip_agents/utils/name_preprocessor/openai_name_preprocessor.pyi +34 -0
- aip_agents/utils/pii/__init__.py +25 -0
- aip_agents/utils/pii/__init__.pyi +5 -0
- aip_agents/utils/pii/pii_handler.py +397 -0
- aip_agents/utils/pii/pii_handler.pyi +96 -0
- aip_agents/utils/pii/pii_helper.py +207 -0
- aip_agents/utils/pii/pii_helper.pyi +78 -0
- aip_agents/utils/pii/uuid_deanonymizer_mapping.py +195 -0
- aip_agents/utils/pii/uuid_deanonymizer_mapping.pyi +73 -0
- aip_agents/utils/reference_helper.py +273 -0
- aip_agents/utils/reference_helper.pyi +81 -0
- aip_agents/utils/sse_chunk_transformer.py +831 -0
- aip_agents/utils/sse_chunk_transformer.pyi +166 -0
- aip_agents/utils/step_limit_manager.py +265 -0
- aip_agents/utils/step_limit_manager.pyi +112 -0
- aip_agents/utils/token_usage_helper.py +156 -0
- aip_agents/utils/token_usage_helper.pyi +60 -0
- aip_agents_binary-0.5.25b1.dist-info/METADATA +681 -0
- aip_agents_binary-0.5.25b1.dist-info/RECORD +566 -0
- aip_agents_binary-0.5.25b1.dist-info/WHEEL +5 -0
- aip_agents_binary-0.5.25b1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,717 @@
|
|
|
1
|
+
"""Base adapter that bridges aip-agents BaseMemory to async memory managers.
|
|
2
|
+
|
|
3
|
+
This adapter hides the async nature of gllm_memory.MemoryManager (or any future
|
|
4
|
+
async provider) behind the existing synchronous BaseMemory contract so downstream
|
|
5
|
+
LangGraph/LangChain components can continue using blocking calls.
|
|
6
|
+
|
|
7
|
+
Authors:
|
|
8
|
+
Raymond Christopher (raymond.christopher@gdplabs.id)
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
import asyncio
|
|
14
|
+
import threading
|
|
15
|
+
from concurrent.futures import Future, ThreadPoolExecutor
|
|
16
|
+
from contextlib import suppress
|
|
17
|
+
from dataclasses import dataclass
|
|
18
|
+
from datetime import datetime, timedelta
|
|
19
|
+
from time import perf_counter
|
|
20
|
+
from typing import Any, ClassVar
|
|
21
|
+
|
|
22
|
+
from gllm_core.schema import Chunk
|
|
23
|
+
from gllm_inference.schema.message import Message
|
|
24
|
+
|
|
25
|
+
try:
|
|
26
|
+
from gllm_memory import MemoryManager
|
|
27
|
+
from gllm_memory.enums import MemoryScope
|
|
28
|
+
|
|
29
|
+
_HAS_GLLM_MEMORY = True
|
|
30
|
+
except ImportError: # pragma: no cover
|
|
31
|
+
MemoryManager = Any # type: ignore[assignment]
|
|
32
|
+
MemoryScope = Any # type: ignore[assignment]
|
|
33
|
+
_HAS_GLLM_MEMORY = False
|
|
34
|
+
|
|
35
|
+
from aip_agents.memory.base import BaseMemory
|
|
36
|
+
from aip_agents.memory.constants import MemoryDefaults
|
|
37
|
+
from aip_agents.types import ChatMessage
|
|
38
|
+
from aip_agents.utils.datetime import format_created_updated_label
|
|
39
|
+
from aip_agents.utils.logger import get_logger
|
|
40
|
+
|
|
41
|
+
logger = get_logger(__name__)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def _require_gllm_memory() -> None:
|
|
45
|
+
if not _HAS_GLLM_MEMORY:
|
|
46
|
+
raise ImportError("optional dependency 'gllm-memory' is required for memory adapters")
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
if _HAS_GLLM_MEMORY:
|
|
50
|
+
DEFAULT_SCOPE: ClassVar[set[MemoryScope]] = {MemoryScope.USER}
|
|
51
|
+
else:
|
|
52
|
+
DEFAULT_SCOPE: ClassVar[set[Any]] = set()
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
@dataclass(frozen=True)
|
|
56
|
+
class _RetrieveOptions:
|
|
57
|
+
user_id: str
|
|
58
|
+
top_k: int
|
|
59
|
+
metadata: dict[str, str] | None
|
|
60
|
+
keywords: Any
|
|
61
|
+
page: int
|
|
62
|
+
categories: list[str] | None
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
class _AsyncRunner:
|
|
66
|
+
"""Runs async coroutines on a dedicated background event loop."""
|
|
67
|
+
|
|
68
|
+
def __init__(self) -> None:
|
|
69
|
+
self._loop = asyncio.new_event_loop()
|
|
70
|
+
self._thread = threading.Thread(target=self._loop.run_forever, daemon=True)
|
|
71
|
+
self._thread.start()
|
|
72
|
+
self._shutdown = False
|
|
73
|
+
|
|
74
|
+
def run(self, awaitable: Any) -> Any:
|
|
75
|
+
"""Execute an awaitable on the background loop and block for the result.
|
|
76
|
+
|
|
77
|
+
Args:
|
|
78
|
+
awaitable: The coroutine to execute.
|
|
79
|
+
|
|
80
|
+
Returns:
|
|
81
|
+
The result of the coroutine execution.
|
|
82
|
+
"""
|
|
83
|
+
if self._shutdown:
|
|
84
|
+
raise RuntimeError("AsyncRunner has been shut down")
|
|
85
|
+
future = asyncio.run_coroutine_threadsafe(awaitable, self._loop)
|
|
86
|
+
return future.result()
|
|
87
|
+
|
|
88
|
+
def shutdown(self, timeout: float | None = 5.0) -> None:
|
|
89
|
+
"""Gracefully stop the event loop thread.
|
|
90
|
+
|
|
91
|
+
Args:
|
|
92
|
+
timeout: Maximum time to wait for the thread to stop.
|
|
93
|
+
"""
|
|
94
|
+
if self._shutdown:
|
|
95
|
+
return
|
|
96
|
+
self._shutdown = True
|
|
97
|
+
self._loop.call_soon_threadsafe(self._loop.stop)
|
|
98
|
+
self._thread.join(timeout)
|
|
99
|
+
with suppress(Exception):
|
|
100
|
+
self._loop.close()
|
|
101
|
+
|
|
102
|
+
def __del__(self) -> None: # pragma: no cover - best effort cleanup
|
|
103
|
+
with suppress(Exception):
|
|
104
|
+
self.shutdown(timeout=0)
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
class BaseMemoryAdapter(BaseMemory):
|
|
108
|
+
"""Provider-agnostic long-term memory adapter backed by gllm_memory."""
|
|
109
|
+
|
|
110
|
+
def __init__(
|
|
111
|
+
self,
|
|
112
|
+
*,
|
|
113
|
+
agent_id: str,
|
|
114
|
+
manager: MemoryManager,
|
|
115
|
+
namespace: str | None = None,
|
|
116
|
+
limit: int = MemoryDefaults.RETRIEVAL_LIMIT,
|
|
117
|
+
max_chars: int = MemoryDefaults.MAX_CHARS,
|
|
118
|
+
) -> None:
|
|
119
|
+
"""Initialize the GLLM memory adapter.
|
|
120
|
+
|
|
121
|
+
Args:
|
|
122
|
+
agent_id: Unique identifier for the agent using this memory.
|
|
123
|
+
manager: Configured gllm_memory MemoryManager instance.
|
|
124
|
+
namespace: Optional namespace for organizing memories.
|
|
125
|
+
limit: Maximum number of memories to retrieve in search operations.
|
|
126
|
+
max_chars: Maximum character length for text content.
|
|
127
|
+
"""
|
|
128
|
+
_require_gllm_memory()
|
|
129
|
+
|
|
130
|
+
self.agent_id = agent_id or MemoryDefaults.DEFAULT_USER_ID
|
|
131
|
+
self.namespace = namespace
|
|
132
|
+
self.limit = int(limit)
|
|
133
|
+
self.max_chars = int(max_chars)
|
|
134
|
+
|
|
135
|
+
self._manager = manager
|
|
136
|
+
self._runner = _AsyncRunner()
|
|
137
|
+
self._executor = ThreadPoolExecutor(max_workers=2, thread_name_prefix="memory-save")
|
|
138
|
+
self._pending_futures: set[Future[Any]] = set()
|
|
139
|
+
self._futures_lock = threading.Lock()
|
|
140
|
+
self._closed = False
|
|
141
|
+
|
|
142
|
+
@classmethod
|
|
143
|
+
def validate_env(
|
|
144
|
+
cls,
|
|
145
|
+
) -> None: # pragma: no cover - base adapter has no env requirements
|
|
146
|
+
"""Base adapter does not enforce environment validation."""
|
|
147
|
+
return None
|
|
148
|
+
|
|
149
|
+
# ------------------------------------------------------------------ #
|
|
150
|
+
# BaseMemory interface
|
|
151
|
+
# ------------------------------------------------------------------ #
|
|
152
|
+
|
|
153
|
+
def get_messages(self) -> list[ChatMessage]:
|
|
154
|
+
"""Retrieve all stored chat messages.
|
|
155
|
+
|
|
156
|
+
Returns:
|
|
157
|
+
An empty list as GLLM adapter doesn't support message retrieval.
|
|
158
|
+
"""
|
|
159
|
+
return []
|
|
160
|
+
|
|
161
|
+
def add_message(self, message: ChatMessage) -> None:
|
|
162
|
+
"""Best-effort single-message persistence for API parity.
|
|
163
|
+
|
|
164
|
+
Args:
|
|
165
|
+
message: The chat message to add to memory.
|
|
166
|
+
"""
|
|
167
|
+
try:
|
|
168
|
+
self._runner.run(
|
|
169
|
+
self._manager.add(
|
|
170
|
+
user_id=self.agent_id,
|
|
171
|
+
agent_id=self.agent_id,
|
|
172
|
+
messages=[self._to_message(message)],
|
|
173
|
+
scopes=DEFAULT_SCOPE,
|
|
174
|
+
infer=False,
|
|
175
|
+
)
|
|
176
|
+
)
|
|
177
|
+
except Exception as exc: # noqa: BLE001
|
|
178
|
+
logger.debug("BaseMemoryAdapter.add_message ignored error: %s", exc)
|
|
179
|
+
|
|
180
|
+
def clear(self) -> None:
|
|
181
|
+
"""Clear all stored memories.
|
|
182
|
+
|
|
183
|
+
Raises:
|
|
184
|
+
NotImplementedError: This method is not implemented for GLLM adapter.
|
|
185
|
+
"""
|
|
186
|
+
raise NotImplementedError("clear() is not implemented for BaseMemoryAdapter.")
|
|
187
|
+
|
|
188
|
+
# ------------------------------------------------------------------ #
|
|
189
|
+
# Legacy Mem0Memory-compatible surface area
|
|
190
|
+
# ------------------------------------------------------------------ #
|
|
191
|
+
|
|
192
|
+
def search(
|
|
193
|
+
self,
|
|
194
|
+
query: str,
|
|
195
|
+
*,
|
|
196
|
+
user_id: str,
|
|
197
|
+
limit: int | None = None,
|
|
198
|
+
filters: dict[str, Any] | None = None,
|
|
199
|
+
) -> list[dict[str, Any]]:
|
|
200
|
+
"""Search for memories using a text query.
|
|
201
|
+
|
|
202
|
+
Args:
|
|
203
|
+
query: The search query string.
|
|
204
|
+
user_id: User identifier for the search scope.
|
|
205
|
+
limit: Maximum number of results to return.
|
|
206
|
+
filters: Optional filters to apply to the search.
|
|
207
|
+
|
|
208
|
+
Returns:
|
|
209
|
+
List of memory hits matching the search criteria.
|
|
210
|
+
"""
|
|
211
|
+
return self.retrieve(query=query, user_id=user_id, limit=limit, filters=filters)
|
|
212
|
+
|
|
213
|
+
def retrieve(
|
|
214
|
+
self,
|
|
215
|
+
*,
|
|
216
|
+
query: str | None,
|
|
217
|
+
user_id: str,
|
|
218
|
+
limit: int | None = None,
|
|
219
|
+
filters: dict[str, Any] | None = None,
|
|
220
|
+
page: int | None = None,
|
|
221
|
+
) -> list[dict[str, Any]]:
|
|
222
|
+
"""Retrieve memories with optional search query and filters.
|
|
223
|
+
|
|
224
|
+
Args:
|
|
225
|
+
query: Optional search query string. If None, retrieves all memories.
|
|
226
|
+
user_id: User identifier for the retrieval scope.
|
|
227
|
+
limit: Maximum number of results to return.
|
|
228
|
+
filters: Optional filters to apply to the retrieval.
|
|
229
|
+
page: Page number for pagination.
|
|
230
|
+
|
|
231
|
+
Returns:
|
|
232
|
+
List of memory hits matching the criteria.
|
|
233
|
+
"""
|
|
234
|
+
options = self._build_retrieve_options(
|
|
235
|
+
user_id=user_id,
|
|
236
|
+
limit=limit,
|
|
237
|
+
filters=filters,
|
|
238
|
+
page=page,
|
|
239
|
+
)
|
|
240
|
+
try:
|
|
241
|
+
start = perf_counter()
|
|
242
|
+
chunks = self._runner.run(self._create_retrieve_task(query, options))
|
|
243
|
+
duration = perf_counter() - start
|
|
244
|
+
logger.info(
|
|
245
|
+
"BaseMemoryAdapter: retrieve user_id='%s' query='%s' limit=%s returned %d hits in %.2fs (filters=%s)",
|
|
246
|
+
user_id,
|
|
247
|
+
query,
|
|
248
|
+
options.top_k,
|
|
249
|
+
len(chunks),
|
|
250
|
+
duration,
|
|
251
|
+
options.metadata,
|
|
252
|
+
)
|
|
253
|
+
except Exception as exc: # noqa: BLE001
|
|
254
|
+
logger.debug("BaseMemoryAdapter.retrieve ignored error: %s", exc)
|
|
255
|
+
return []
|
|
256
|
+
|
|
257
|
+
return [self._chunk_to_hit(chunk) for chunk in chunks]
|
|
258
|
+
|
|
259
|
+
def save_interaction(self, *, user_text: str, ai_text: str, user_id: str) -> None:
|
|
260
|
+
"""Save a user-AI interaction as memories.
|
|
261
|
+
|
|
262
|
+
Args:
|
|
263
|
+
user_text: The user's input text.
|
|
264
|
+
ai_text: The AI's response text.
|
|
265
|
+
user_id: User identifier for the memory storage.
|
|
266
|
+
"""
|
|
267
|
+
truncated_user = str(user_text)[: self.max_chars]
|
|
268
|
+
truncated_ai = str(ai_text)[: self.max_chars]
|
|
269
|
+
messages = [
|
|
270
|
+
Message.user(contents=truncated_user),
|
|
271
|
+
Message.assistant(contents=truncated_ai),
|
|
272
|
+
]
|
|
273
|
+
preview_user = truncated_user[: MemoryDefaults.LOG_PREVIEW_LENGTH]
|
|
274
|
+
preview_ai = truncated_ai[: MemoryDefaults.LOG_PREVIEW_LENGTH]
|
|
275
|
+
logger.info(
|
|
276
|
+
"BaseMemoryAdapter: saving interaction user_id='%s' user_preview='%s%s' ai_preview='%s%s'",
|
|
277
|
+
user_id,
|
|
278
|
+
preview_user,
|
|
279
|
+
"..." if len(truncated_user) > len(preview_user) else "",
|
|
280
|
+
preview_ai,
|
|
281
|
+
"..." if len(truncated_ai) > len(preview_ai) else "",
|
|
282
|
+
)
|
|
283
|
+
try:
|
|
284
|
+
start = perf_counter()
|
|
285
|
+
self._runner.run(
|
|
286
|
+
self._manager.add(
|
|
287
|
+
user_id=user_id or self.agent_id,
|
|
288
|
+
agent_id=self.agent_id,
|
|
289
|
+
messages=messages,
|
|
290
|
+
scopes=DEFAULT_SCOPE,
|
|
291
|
+
)
|
|
292
|
+
)
|
|
293
|
+
duration = perf_counter() - start
|
|
294
|
+
logger.info(
|
|
295
|
+
"BaseMemoryAdapter: save_interaction completed for user_id='%s' in %.2fs",
|
|
296
|
+
user_id,
|
|
297
|
+
duration,
|
|
298
|
+
)
|
|
299
|
+
except Exception as exc: # noqa: BLE001
|
|
300
|
+
logger.debug("BaseMemoryAdapter.save_interaction ignored error: %s", exc)
|
|
301
|
+
|
|
302
|
+
def save_interaction_async(self, *, user_text: str, ai_text: str, user_id: str) -> Future[Any]:
|
|
303
|
+
"""Schedule save_interaction without blocking the caller.
|
|
304
|
+
|
|
305
|
+
Args:
|
|
306
|
+
user_text: The user's input text to save.
|
|
307
|
+
ai_text: The AI's response text to save.
|
|
308
|
+
user_id: User identifier for the memory storage.
|
|
309
|
+
"""
|
|
310
|
+
future = self._executor.submit(
|
|
311
|
+
self.save_interaction,
|
|
312
|
+
user_text=user_text,
|
|
313
|
+
ai_text=ai_text,
|
|
314
|
+
user_id=user_id,
|
|
315
|
+
)
|
|
316
|
+
with self._futures_lock:
|
|
317
|
+
self._pending_futures.add(future)
|
|
318
|
+
|
|
319
|
+
def _on_complete(done: Future[Any]) -> None:
|
|
320
|
+
"""Discard a completed future from the pending set and log failures.
|
|
321
|
+
|
|
322
|
+
Args:
|
|
323
|
+
done: Future returned by the executor for save_interaction.
|
|
324
|
+
"""
|
|
325
|
+
with self._futures_lock:
|
|
326
|
+
self._pending_futures.discard(done)
|
|
327
|
+
exc = done.exception()
|
|
328
|
+
if exc:
|
|
329
|
+
logger.warning(
|
|
330
|
+
"BaseMemoryAdapter: async save failed for user_id='%s': %s",
|
|
331
|
+
user_id,
|
|
332
|
+
exc,
|
|
333
|
+
)
|
|
334
|
+
|
|
335
|
+
future.add_done_callback(_on_complete)
|
|
336
|
+
return future
|
|
337
|
+
|
|
338
|
+
def format_hits(
|
|
339
|
+
self,
|
|
340
|
+
hits: list[dict[str, Any]],
|
|
341
|
+
max_items: int = MemoryDefaults.MAX_ITEMS,
|
|
342
|
+
with_tag: bool = True,
|
|
343
|
+
) -> str:
|
|
344
|
+
"""Format memory hits into a readable string.
|
|
345
|
+
|
|
346
|
+
Args:
|
|
347
|
+
hits: List of memory hit dictionaries to format.
|
|
348
|
+
max_items: Maximum number of hits to include in the output.
|
|
349
|
+
with_tag: Whether to wrap the output with memory tags.
|
|
350
|
+
|
|
351
|
+
Returns:
|
|
352
|
+
Formatted string representation of the memory hits.
|
|
353
|
+
"""
|
|
354
|
+
lines: list[str] = []
|
|
355
|
+
for hit in hits[:max_items]:
|
|
356
|
+
if not isinstance(hit, dict):
|
|
357
|
+
lines.append(f"- {hit}")
|
|
358
|
+
continue
|
|
359
|
+
text = hit.get("memory") or hit.get("text") or hit.get("content")
|
|
360
|
+
if not text:
|
|
361
|
+
text = str(hit)
|
|
362
|
+
label = format_created_updated_label(hit.get("created_at"), hit.get("updated_at"))
|
|
363
|
+
prefix = f"- [{label}] " if label else "- "
|
|
364
|
+
lines.append(f"{prefix}{text}")
|
|
365
|
+
|
|
366
|
+
if not lines:
|
|
367
|
+
logger.info("BaseMemoryAdapter: No memories to format for prompt")
|
|
368
|
+
return ""
|
|
369
|
+
|
|
370
|
+
formatted_memory = (
|
|
371
|
+
f"{MemoryDefaults.MEMORY_TAG_OPEN}\n" + "\n".join(lines) + f"\n{MemoryDefaults.MEMORY_TAG_CLOSE}\n\n"
|
|
372
|
+
if with_tag
|
|
373
|
+
else "\n".join(lines)
|
|
374
|
+
)
|
|
375
|
+
logger.info("BaseMemoryAdapter: Formatted %s memories for prompt", len(lines))
|
|
376
|
+
logger.info(
|
|
377
|
+
"BaseMemoryAdapter: Prompt memory block:%s%s",
|
|
378
|
+
"\n" if lines else " ",
|
|
379
|
+
formatted_memory.strip(),
|
|
380
|
+
)
|
|
381
|
+
return formatted_memory
|
|
382
|
+
|
|
383
|
+
def flush_pending_writes(self, timeout: float | None = None) -> None:
|
|
384
|
+
"""Block until current async writes complete.
|
|
385
|
+
|
|
386
|
+
Args:
|
|
387
|
+
timeout: Maximum time to wait for pending writes to complete.
|
|
388
|
+
"""
|
|
389
|
+
futures = self._snapshot_pending_futures()
|
|
390
|
+
for future in futures:
|
|
391
|
+
try:
|
|
392
|
+
future.result(timeout=timeout)
|
|
393
|
+
except Exception as exc: # noqa: BLE001
|
|
394
|
+
logger.warning("BaseMemoryAdapter: Pending async save raised: %s", exc)
|
|
395
|
+
|
|
396
|
+
def close(self, *, wait: bool = True, timeout: float | None = None) -> None:
|
|
397
|
+
"""Release background resources and optionally wait for pending saves.
|
|
398
|
+
|
|
399
|
+
Args:
|
|
400
|
+
wait: Whether to wait for pending async operations to complete.
|
|
401
|
+
timeout: Maximum time to wait when wait=True.
|
|
402
|
+
"""
|
|
403
|
+
if self._closed:
|
|
404
|
+
return
|
|
405
|
+
self._closed = True
|
|
406
|
+
if wait:
|
|
407
|
+
self.flush_pending_writes(timeout=timeout)
|
|
408
|
+
self._executor.shutdown(wait=wait, cancel_futures=not wait)
|
|
409
|
+
self._runner.shutdown()
|
|
410
|
+
|
|
411
|
+
def __del__(self) -> None: # pragma: no cover - best effort cleanup
|
|
412
|
+
"""Clean up resources when the adapter is garbage collected."""
|
|
413
|
+
with suppress(Exception):
|
|
414
|
+
self.close(wait=False)
|
|
415
|
+
|
|
416
|
+
def _snapshot_pending_futures(self) -> list[Future[Any]]:
|
|
417
|
+
with self._futures_lock:
|
|
418
|
+
return list(self._pending_futures)
|
|
419
|
+
|
|
420
|
+
def _call_manager_with_optional_categories(
|
|
421
|
+
self,
|
|
422
|
+
func: Any,
|
|
423
|
+
*,
|
|
424
|
+
categories: list[str] | None,
|
|
425
|
+
**kwargs: Any,
|
|
426
|
+
) -> Any:
|
|
427
|
+
"""Invoke a MemoryManager coroutine, retrying without categories if unsupported.
|
|
428
|
+
|
|
429
|
+
Args:
|
|
430
|
+
func: The MemoryManager method to call.
|
|
431
|
+
categories: Optional categories to pass to the method.
|
|
432
|
+
**kwargs: Additional keyword arguments to pass to the method.
|
|
433
|
+
|
|
434
|
+
Returns:
|
|
435
|
+
The result of calling the MemoryManager method.
|
|
436
|
+
"""
|
|
437
|
+
if categories:
|
|
438
|
+
try:
|
|
439
|
+
return func(categories=categories, **kwargs)
|
|
440
|
+
except TypeError:
|
|
441
|
+
logger.debug(
|
|
442
|
+
"BaseMemoryAdapter: '%s' does not accept categories, retrying without it",
|
|
443
|
+
getattr(func, "__name__", func),
|
|
444
|
+
)
|
|
445
|
+
return func(**kwargs)
|
|
446
|
+
|
|
447
|
+
# ------------------------------------------------------------------ #
|
|
448
|
+
# Helper utilities
|
|
449
|
+
# ------------------------------------------------------------------ #
|
|
450
|
+
|
|
451
|
+
def _build_retrieve_options(
|
|
452
|
+
self,
|
|
453
|
+
*,
|
|
454
|
+
user_id: str,
|
|
455
|
+
limit: int | None,
|
|
456
|
+
filters: dict[str, Any] | None,
|
|
457
|
+
page: int | None,
|
|
458
|
+
) -> _RetrieveOptions:
|
|
459
|
+
"""Assemble normalized retrieval options for the MemoryManager.
|
|
460
|
+
|
|
461
|
+
Args:
|
|
462
|
+
user_id: Optional user identifier requesting the memory retrieval.
|
|
463
|
+
limit: Maximum number of items to return.
|
|
464
|
+
filters: Raw filter payload supplied by the caller.
|
|
465
|
+
page: Page number for paginated listing operations.
|
|
466
|
+
|
|
467
|
+
Returns:
|
|
468
|
+
_RetrieveOptions instance consumed by downstream search/list calls.
|
|
469
|
+
"""
|
|
470
|
+
effective_user = user_id or self.agent_id or MemoryDefaults.DEFAULT_USER_ID
|
|
471
|
+
top_k = int(limit) if limit is not None else self.limit
|
|
472
|
+
normalized_filters = self._normalize_filters(filters or {})
|
|
473
|
+
metadata_payload = self._build_metadata_payload(normalized_filters)
|
|
474
|
+
keywords = normalized_filters.get("keywords")
|
|
475
|
+
categories = normalized_filters.get("categories")
|
|
476
|
+
return _RetrieveOptions(
|
|
477
|
+
user_id=effective_user,
|
|
478
|
+
top_k=top_k,
|
|
479
|
+
metadata=metadata_payload,
|
|
480
|
+
keywords=keywords,
|
|
481
|
+
page=page or 1,
|
|
482
|
+
categories=list(categories) if isinstance(categories, list) else categories,
|
|
483
|
+
)
|
|
484
|
+
|
|
485
|
+
def _create_retrieve_task(self, query: str | None, options: _RetrieveOptions) -> Any:
|
|
486
|
+
"""Build the manager coroutine to execute for search/list requests.
|
|
487
|
+
|
|
488
|
+
Args:
|
|
489
|
+
query: Optional search query to execute against the memories.
|
|
490
|
+
options: Prepared retrieval options containing metadata and pagination.
|
|
491
|
+
|
|
492
|
+
Returns:
|
|
493
|
+
Awaitable returned by the MemoryManager search or list method.
|
|
494
|
+
"""
|
|
495
|
+
if query:
|
|
496
|
+
return self._call_manager_with_optional_categories(
|
|
497
|
+
self._manager.search,
|
|
498
|
+
categories=options.categories,
|
|
499
|
+
query=query,
|
|
500
|
+
user_id=options.user_id,
|
|
501
|
+
agent_id=self.agent_id,
|
|
502
|
+
scopes=DEFAULT_SCOPE,
|
|
503
|
+
metadata=options.metadata,
|
|
504
|
+
top_k=options.top_k,
|
|
505
|
+
)
|
|
506
|
+
return self._call_manager_with_optional_categories(
|
|
507
|
+
self._manager.list_memories,
|
|
508
|
+
categories=options.categories,
|
|
509
|
+
user_id=options.user_id,
|
|
510
|
+
agent_id=self.agent_id,
|
|
511
|
+
scopes=DEFAULT_SCOPE,
|
|
512
|
+
metadata=options.metadata,
|
|
513
|
+
keywords=options.keywords,
|
|
514
|
+
page=options.page,
|
|
515
|
+
page_size=options.top_k,
|
|
516
|
+
)
|
|
517
|
+
|
|
518
|
+
def _normalize_filters(self, filters: dict[str, Any]) -> dict[str, Any]:
|
|
519
|
+
"""Normalize filters from legacy AND/OR format to the expected structure.
|
|
520
|
+
|
|
521
|
+
Args:
|
|
522
|
+
filters: Raw filter dictionary that may use legacy format.
|
|
523
|
+
|
|
524
|
+
Returns:
|
|
525
|
+
Normalized filter dictionary.
|
|
526
|
+
"""
|
|
527
|
+
if self._is_legacy_filter_format(filters):
|
|
528
|
+
return self._convert_legacy_filters(filters)
|
|
529
|
+
return filters
|
|
530
|
+
|
|
531
|
+
@staticmethod
|
|
532
|
+
def _is_legacy_filter_format(filters: dict[str, Any]) -> bool:
|
|
533
|
+
"""Return True when the filters dict uses legacy AND/OR syntax.
|
|
534
|
+
|
|
535
|
+
Args:
|
|
536
|
+
filters: Filter dictionary to check.
|
|
537
|
+
|
|
538
|
+
Returns:
|
|
539
|
+
True if the filters use legacy AND/OR syntax.
|
|
540
|
+
"""
|
|
541
|
+
if not isinstance(filters, dict):
|
|
542
|
+
return False
|
|
543
|
+
return "AND" in filters or "OR" in filters
|
|
544
|
+
|
|
545
|
+
@staticmethod
|
|
546
|
+
def _convert_legacy_filters(filters: dict[str, Any]) -> dict[str, Any]:
|
|
547
|
+
"""Convert AND/OR style legacy filters into the normalized structure.
|
|
548
|
+
|
|
549
|
+
Args:
|
|
550
|
+
filters: Legacy filter payload coming from older clients.
|
|
551
|
+
|
|
552
|
+
Returns:
|
|
553
|
+
Dictionary with metadata, categories, and date range keys.
|
|
554
|
+
"""
|
|
555
|
+
normalized: dict[str, Any] = {
|
|
556
|
+
"metadata": {},
|
|
557
|
+
"categories": None,
|
|
558
|
+
"start_time": None,
|
|
559
|
+
"end_time": None,
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
clauses = filters.get("AND", [])
|
|
563
|
+
for clause in clauses:
|
|
564
|
+
if not isinstance(clause, dict):
|
|
565
|
+
continue
|
|
566
|
+
BaseMemoryAdapter._process_clause(clause, normalized)
|
|
567
|
+
|
|
568
|
+
return normalized
|
|
569
|
+
|
|
570
|
+
@staticmethod
|
|
571
|
+
def _process_clause(clause: dict[str, Any], normalized: dict[str, Any]) -> None:
|
|
572
|
+
"""Process a single clause and update the normalized filters.
|
|
573
|
+
|
|
574
|
+
Args:
|
|
575
|
+
clause: Single filter clause to process.
|
|
576
|
+
normalized: Dictionary to update with normalized filter values.
|
|
577
|
+
"""
|
|
578
|
+
if "created_at" in clause and isinstance(clause["created_at"], dict):
|
|
579
|
+
BaseMemoryAdapter._process_created_at_clause(clause["created_at"], normalized)
|
|
580
|
+
elif "categories" in clause and isinstance(clause["categories"], dict):
|
|
581
|
+
BaseMemoryAdapter._process_categories_clause(clause["categories"], normalized)
|
|
582
|
+
elif "metadata" in clause and isinstance(clause["metadata"], dict):
|
|
583
|
+
normalized["metadata"].update(clause["metadata"])
|
|
584
|
+
|
|
585
|
+
@staticmethod
|
|
586
|
+
def _process_created_at_clause(created_filter: dict[str, Any], normalized: dict[str, Any]) -> None:
|
|
587
|
+
"""Process created_at clause for date filtering.
|
|
588
|
+
|
|
589
|
+
Args:
|
|
590
|
+
created_filter: Created date filter criteria.
|
|
591
|
+
normalized: Dictionary to update with normalized date values.
|
|
592
|
+
"""
|
|
593
|
+
start_candidate = created_filter.get("gte") or created_filter.get("gt")
|
|
594
|
+
end_candidate = created_filter.get("lte") or created_filter.get("lt")
|
|
595
|
+
if start_candidate:
|
|
596
|
+
normalized["start_time"] = start_candidate
|
|
597
|
+
if end_candidate:
|
|
598
|
+
normalized["end_time"] = BaseMemoryAdapter._restore_end_date(created_filter)
|
|
599
|
+
|
|
600
|
+
@staticmethod
|
|
601
|
+
def _process_categories_clause(categories_filter: dict[str, Any], normalized: dict[str, Any]) -> None:
|
|
602
|
+
"""Process categories clause for category filtering.
|
|
603
|
+
|
|
604
|
+
Args:
|
|
605
|
+
categories_filter: Categories filter criteria.
|
|
606
|
+
normalized: Dictionary to update with normalized category values.
|
|
607
|
+
"""
|
|
608
|
+
cats = categories_filter.get("in")
|
|
609
|
+
if cats:
|
|
610
|
+
normalized["categories"] = list(cats)
|
|
611
|
+
|
|
612
|
+
@staticmethod
|
|
613
|
+
def _restore_end_date(created_filter: dict[str, Any]) -> str | None:
|
|
614
|
+
"""Convert exclusive lt filters back to the user's original end date.
|
|
615
|
+
|
|
616
|
+
Args:
|
|
617
|
+
created_filter: Dictionary containing date filter criteria.
|
|
618
|
+
|
|
619
|
+
Returns:
|
|
620
|
+
The restored end date string, or None if not applicable.
|
|
621
|
+
"""
|
|
622
|
+
end_candidate = created_filter.get("lte") or created_filter.get("lt")
|
|
623
|
+
if end_candidate is None:
|
|
624
|
+
return None
|
|
625
|
+
if "lt" in created_filter and "lte" not in created_filter:
|
|
626
|
+
try:
|
|
627
|
+
dt = datetime.strptime(end_candidate, "%Y-%m-%d") - timedelta(days=1)
|
|
628
|
+
return dt.date().isoformat()
|
|
629
|
+
except ValueError:
|
|
630
|
+
return end_candidate
|
|
631
|
+
return end_candidate
|
|
632
|
+
|
|
633
|
+
@staticmethod
|
|
634
|
+
def _build_metadata_payload(
|
|
635
|
+
filters: dict[str, Any] | None,
|
|
636
|
+
) -> dict[str, str] | None:
|
|
637
|
+
"""Create the metadata payload expected by the MemoryManager APIs.
|
|
638
|
+
|
|
639
|
+
Args:
|
|
640
|
+
filters: Normalized filter dictionary built from user input.
|
|
641
|
+
|
|
642
|
+
Returns:
|
|
643
|
+
Dictionary of metadata strings or None when no metadata was provided.
|
|
644
|
+
"""
|
|
645
|
+
if not filters:
|
|
646
|
+
return None
|
|
647
|
+
|
|
648
|
+
metadata: dict[str, str] = {}
|
|
649
|
+
|
|
650
|
+
raw_metadata = filters.get("metadata") or {}
|
|
651
|
+
for key, value in raw_metadata.items():
|
|
652
|
+
if value is None:
|
|
653
|
+
continue
|
|
654
|
+
metadata[key] = str(value)
|
|
655
|
+
|
|
656
|
+
start_time = filters.get("start_time")
|
|
657
|
+
end_time = filters.get("end_time")
|
|
658
|
+
if start_time:
|
|
659
|
+
metadata["start_time"] = str(start_time)
|
|
660
|
+
if end_time:
|
|
661
|
+
metadata["end_time"] = str(end_time)
|
|
662
|
+
|
|
663
|
+
categories = filters.get("categories")
|
|
664
|
+
if categories:
|
|
665
|
+
metadata["category"] = ",".join(str(cat) for cat in categories)
|
|
666
|
+
|
|
667
|
+
return metadata or None
|
|
668
|
+
|
|
669
|
+
@staticmethod
|
|
670
|
+
def _to_message(message: ChatMessage) -> Message:
|
|
671
|
+
"""Convert a MemoryManager ChatMessage into the shared Message schema.
|
|
672
|
+
|
|
673
|
+
Args:
|
|
674
|
+
message: ChatMessage returned from the memory service.
|
|
675
|
+
|
|
676
|
+
Returns:
|
|
677
|
+
Message: Structured message with normalized role and content.
|
|
678
|
+
"""
|
|
679
|
+
role = (message.role or "user").lower()
|
|
680
|
+
content = str(message.content) if message.content is not None else ""
|
|
681
|
+
if role == "assistant":
|
|
682
|
+
return Message.assistant(contents=content)
|
|
683
|
+
if role == "system":
|
|
684
|
+
return Message.system(contents=content)
|
|
685
|
+
return Message.user(contents=content)
|
|
686
|
+
|
|
687
|
+
@staticmethod
|
|
688
|
+
def _chunk_to_hit(chunk: Chunk) -> dict[str, Any]:
|
|
689
|
+
"""Transform a Chunk record into the hit dict consumed by callers.
|
|
690
|
+
|
|
691
|
+
Args:
|
|
692
|
+
chunk: Chunk object returned by the retriever.
|
|
693
|
+
|
|
694
|
+
Returns:
|
|
695
|
+
dict[str, Any]: Serializable hit payload.
|
|
696
|
+
"""
|
|
697
|
+
metadata = dict(chunk.metadata or {})
|
|
698
|
+
content = chunk.content
|
|
699
|
+
if isinstance(content, bytes):
|
|
700
|
+
try:
|
|
701
|
+
content = content.decode("utf-8")
|
|
702
|
+
except Exception: # noqa: BLE001
|
|
703
|
+
content = content.decode("utf-8", "ignore")
|
|
704
|
+
if content is None:
|
|
705
|
+
content = ""
|
|
706
|
+
|
|
707
|
+
hit = {
|
|
708
|
+
"id": chunk.id,
|
|
709
|
+
"memory": content,
|
|
710
|
+
"score": chunk.score,
|
|
711
|
+
"metadata": metadata,
|
|
712
|
+
"created_at": metadata.get("created_at"),
|
|
713
|
+
"updated_at": metadata.get("updated_at"),
|
|
714
|
+
"user_id": metadata.get("user_id"),
|
|
715
|
+
"agent_id": metadata.get("agent_id"),
|
|
716
|
+
}
|
|
717
|
+
return hit
|