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,362 @@
|
|
|
1
|
+
"""Persistent MCP Session wrapper for connection reuse.
|
|
2
|
+
|
|
3
|
+
This module implements persistent MCP sessions that reuse connections across
|
|
4
|
+
multiple tool calls, avoiding the session recreation overhead.
|
|
5
|
+
|
|
6
|
+
Authors:
|
|
7
|
+
Putu Ravindra Wiguna (putu.r.wiguna@gdplabs.id)
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import asyncio
|
|
11
|
+
from typing import Any
|
|
12
|
+
|
|
13
|
+
from gllm_tools.mcp.client.config import MCPConfiguration
|
|
14
|
+
from mcp import ClientSession
|
|
15
|
+
from mcp.types import CallToolResult, Tool
|
|
16
|
+
|
|
17
|
+
from aip_agents.mcp.client.connection_manager import MCPConnectionManager
|
|
18
|
+
from aip_agents.mcp.utils.config_validator import validate_allowed_tools_list
|
|
19
|
+
from aip_agents.utils.logger import get_logger
|
|
20
|
+
|
|
21
|
+
logger = get_logger(__name__)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class PersistentMCPSession:
|
|
25
|
+
"""Persistent MCP session that reuses connections.
|
|
26
|
+
|
|
27
|
+
This session wrapper manages the connection lifecycle and caches tools
|
|
28
|
+
to avoid repeated initialization overhead. It provides automatic reconnection
|
|
29
|
+
and thread-safe operations.
|
|
30
|
+
|
|
31
|
+
Tool Filtering:
|
|
32
|
+
When allowed_tools is configured, tools are filtered inline during list_tools()
|
|
33
|
+
and permission checked in call_tool() using set lookup.
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
def __init__(
|
|
37
|
+
self,
|
|
38
|
+
server_name: str,
|
|
39
|
+
config: MCPConfiguration,
|
|
40
|
+
allowed_tools: list[str] | None = None,
|
|
41
|
+
):
|
|
42
|
+
"""Initialize persistent session.
|
|
43
|
+
|
|
44
|
+
Args:
|
|
45
|
+
server_name: Name of the MCP server
|
|
46
|
+
config: MCP server configuration
|
|
47
|
+
allowed_tools: Optional list of tool names to allow. None or empty means all tools allowed.
|
|
48
|
+
"""
|
|
49
|
+
self.server_name = server_name
|
|
50
|
+
self.config = config
|
|
51
|
+
self.connection_manager = MCPConnectionManager(server_name, config)
|
|
52
|
+
self.client_session: ClientSession | None = None
|
|
53
|
+
self.tools: list[Tool] = []
|
|
54
|
+
|
|
55
|
+
# Keep only the set for fast permission checks
|
|
56
|
+
validated_allowed = validate_allowed_tools_list(allowed_tools, "'allowed_tools' parameter")
|
|
57
|
+
self._allowed_tools_set: set[str] | None = set(validated_allowed) if validated_allowed else None
|
|
58
|
+
self._warned_unknown_tools: set[str] = set()
|
|
59
|
+
self._filtered_tools_cache: list[Tool] | None = None # Cache for filtered tools
|
|
60
|
+
|
|
61
|
+
# Log allowed tools configuration
|
|
62
|
+
if self._allowed_tools_set:
|
|
63
|
+
logger.info(
|
|
64
|
+
f"Session for '{server_name}' configured with {len(self._allowed_tools_set)} allowed tool(s): "
|
|
65
|
+
f"{', '.join(sorted(self._allowed_tools_set))}"
|
|
66
|
+
)
|
|
67
|
+
else:
|
|
68
|
+
logger.debug(f"Session for '{server_name}' allows all tools (no restriction)")
|
|
69
|
+
|
|
70
|
+
self._initialized = False
|
|
71
|
+
self._lock = asyncio.Lock()
|
|
72
|
+
|
|
73
|
+
async def initialize(self) -> None:
|
|
74
|
+
"""Initialize session once and cache tools.
|
|
75
|
+
|
|
76
|
+
This method is idempotent and can be called multiple times safely.
|
|
77
|
+
|
|
78
|
+
Raises:
|
|
79
|
+
Exception: If session initialization fails
|
|
80
|
+
"""
|
|
81
|
+
if self._initialized:
|
|
82
|
+
return
|
|
83
|
+
|
|
84
|
+
async with self._lock:
|
|
85
|
+
# Double-check pattern
|
|
86
|
+
if self._initialized:
|
|
87
|
+
return
|
|
88
|
+
|
|
89
|
+
try:
|
|
90
|
+
logger.info(f"Initializing persistent session for {self.server_name}")
|
|
91
|
+
|
|
92
|
+
# Start connection manager
|
|
93
|
+
read_stream, write_stream = await self.connection_manager.start()
|
|
94
|
+
|
|
95
|
+
# Create client session
|
|
96
|
+
self.client_session = ClientSession(read_stream, write_stream)
|
|
97
|
+
await self.client_session.__aenter__()
|
|
98
|
+
|
|
99
|
+
# MCP handshake
|
|
100
|
+
result = await self.client_session.initialize()
|
|
101
|
+
logger.debug(f"MCP handshake complete for {self.server_name}: {result.capabilities}")
|
|
102
|
+
|
|
103
|
+
# Discover and cache tools
|
|
104
|
+
if result.capabilities.tools:
|
|
105
|
+
tools_result = await self.client_session.list_tools()
|
|
106
|
+
self.tools = tools_result.tools if tools_result else []
|
|
107
|
+
self._filtered_tools_cache = None # Invalidate cache when tools change
|
|
108
|
+
logger.info(f"Cached {len(self.tools)} tools for {self.server_name}")
|
|
109
|
+
else:
|
|
110
|
+
logger.info(f"No tools available for {self.server_name}")
|
|
111
|
+
|
|
112
|
+
# Warn once per initialization if allowed_tools references unknown names
|
|
113
|
+
if self._allowed_tools_set:
|
|
114
|
+
self._warn_on_unknown_allowed_tools(list(self._allowed_tools_set), self.tools)
|
|
115
|
+
|
|
116
|
+
# Discover resources (for future use)
|
|
117
|
+
if result.capabilities.resources:
|
|
118
|
+
try:
|
|
119
|
+
resources_result = await self.client_session.list_resources()
|
|
120
|
+
if resources_result and resources_result.resources:
|
|
121
|
+
logger.debug(f"Found {len(resources_result.resources)} resources for {self.server_name}")
|
|
122
|
+
except Exception:
|
|
123
|
+
logger.debug(f"Could not list resources for {self.server_name}, skipping")
|
|
124
|
+
|
|
125
|
+
self._initialized = True
|
|
126
|
+
logger.info(f"Session initialization complete for {self.server_name}")
|
|
127
|
+
|
|
128
|
+
except Exception as e:
|
|
129
|
+
logger.error(f"Failed to initialize session for {self.server_name}: {e}", exc_info=True)
|
|
130
|
+
await self._cleanup_on_error()
|
|
131
|
+
raise ConnectionError(f"Failed to initialize MCP session for {self.server_name}: {str(e)}") from e
|
|
132
|
+
|
|
133
|
+
async def call_tool(self, name: str, arguments: dict[str, Any]) -> CallToolResult:
|
|
134
|
+
"""Call MCP tool using persistent session.
|
|
135
|
+
|
|
136
|
+
Args:
|
|
137
|
+
name (str): Tool name
|
|
138
|
+
arguments (dict[str, Any]): Tool arguments
|
|
139
|
+
|
|
140
|
+
Returns:
|
|
141
|
+
CallToolResult: Tool call result
|
|
142
|
+
|
|
143
|
+
Raises:
|
|
144
|
+
Exception: If tool call fails
|
|
145
|
+
"""
|
|
146
|
+
await self.ensure_connected()
|
|
147
|
+
|
|
148
|
+
if self._allowed_tools_set and name not in self._allowed_tools_set:
|
|
149
|
+
allowed_display = ", ".join(sorted(self._allowed_tools_set))
|
|
150
|
+
error_msg = (
|
|
151
|
+
f"Tool '{name}' is not allowed on server '{self.server_name}' (allowed tools: {allowed_display})"
|
|
152
|
+
)
|
|
153
|
+
logger.warning(f"[{self.server_name}] Tool '{name}' blocked: not in allowed_tools ({allowed_display})")
|
|
154
|
+
raise PermissionError(error_msg)
|
|
155
|
+
|
|
156
|
+
try:
|
|
157
|
+
logger.debug(f"Calling tool '{name}' on {self.server_name} with args: {arguments}")
|
|
158
|
+
result = await self.client_session.call_tool(name, arguments)
|
|
159
|
+
logger.debug(f"Tool '{name}' completed successfully")
|
|
160
|
+
return result
|
|
161
|
+
except Exception as e:
|
|
162
|
+
self._handle_connection_error(e, f"Tool call '{name}'")
|
|
163
|
+
|
|
164
|
+
async def read_resource(self, uri: str) -> Any:
|
|
165
|
+
"""Read an MCP resource using persistent session.
|
|
166
|
+
|
|
167
|
+
Args:
|
|
168
|
+
uri (str): The URI of the resource to read
|
|
169
|
+
|
|
170
|
+
Returns:
|
|
171
|
+
Any: The resource content
|
|
172
|
+
|
|
173
|
+
Raises:
|
|
174
|
+
Exception: If resource reading fails
|
|
175
|
+
"""
|
|
176
|
+
await self.ensure_connected()
|
|
177
|
+
return await self._execute_read_resource(uri)
|
|
178
|
+
|
|
179
|
+
async def _execute_read_resource(self, uri: str) -> Any:
|
|
180
|
+
"""Execute the reading of an MCP resource.
|
|
181
|
+
|
|
182
|
+
Args:
|
|
183
|
+
uri (str): The URI of the resource to read
|
|
184
|
+
|
|
185
|
+
Returns:
|
|
186
|
+
Any: The resource content
|
|
187
|
+
|
|
188
|
+
Raises:
|
|
189
|
+
Exception: If resource reading fails
|
|
190
|
+
"""
|
|
191
|
+
try:
|
|
192
|
+
logger.debug(f"Reading resource '{uri}' on {self.server_name}")
|
|
193
|
+
result = await self.client_session.read_resource(uri)
|
|
194
|
+
logger.debug(f"Resource '{uri}' read successfully")
|
|
195
|
+
return result
|
|
196
|
+
except Exception as e:
|
|
197
|
+
self._handle_connection_error(e, f"Reading resource '{uri}'")
|
|
198
|
+
|
|
199
|
+
async def list_tools(self) -> list[Tool]:
|
|
200
|
+
"""Get cached tools list with allowed tools filtering applied.
|
|
201
|
+
|
|
202
|
+
Returns:
|
|
203
|
+
list[Tool]: a copy of list of available tools, filtered to only allowed tools if configured
|
|
204
|
+
"""
|
|
205
|
+
await self.ensure_connected()
|
|
206
|
+
|
|
207
|
+
if not self._allowed_tools_set:
|
|
208
|
+
return list(self.tools)
|
|
209
|
+
|
|
210
|
+
if self._filtered_tools_cache is None:
|
|
211
|
+
self._filtered_tools_cache = [tool for tool in self.tools if tool.name in self._allowed_tools_set]
|
|
212
|
+
|
|
213
|
+
return list(self._filtered_tools_cache)
|
|
214
|
+
|
|
215
|
+
def get_tools_count(self) -> int:
|
|
216
|
+
"""Get count of allowed tools.
|
|
217
|
+
|
|
218
|
+
Returns:
|
|
219
|
+
Count of allowed tools
|
|
220
|
+
"""
|
|
221
|
+
if not self._allowed_tools_set:
|
|
222
|
+
return len(self.tools)
|
|
223
|
+
|
|
224
|
+
if self._filtered_tools_cache is not None:
|
|
225
|
+
return len(self._filtered_tools_cache)
|
|
226
|
+
|
|
227
|
+
return sum(1 for tool in self.tools if tool.name in self._allowed_tools_set)
|
|
228
|
+
|
|
229
|
+
async def ensure_connected(self) -> None:
|
|
230
|
+
"""Ensure connection is healthy, reconnect if needed.
|
|
231
|
+
|
|
232
|
+
This method provides automatic reconnection capability.
|
|
233
|
+
|
|
234
|
+
Raises:
|
|
235
|
+
Exception: If reconnection fails
|
|
236
|
+
"""
|
|
237
|
+
if not self._initialized or not self.connection_manager.is_connected:
|
|
238
|
+
logger.info(f"Reconnecting session for {self.server_name}")
|
|
239
|
+
await self.initialize()
|
|
240
|
+
|
|
241
|
+
def _handle_connection_error(self, e: Exception, operation: str) -> None:
|
|
242
|
+
"""Handle connection-related errors with logging and reconnection marking.
|
|
243
|
+
|
|
244
|
+
Args:
|
|
245
|
+
e (Exception): The exception that occurred
|
|
246
|
+
operation (str): The operation that failed
|
|
247
|
+
"""
|
|
248
|
+
logger.error(f"{operation} failed on {self.server_name}: {e}")
|
|
249
|
+
if not self.connection_manager.is_connected:
|
|
250
|
+
logger.info(f"Connection lost for {self.server_name}, marking for reconnection")
|
|
251
|
+
self._initialized = False
|
|
252
|
+
raise ConnectionError(f"{operation} failed on {self.server_name}: {str(e)}") from e
|
|
253
|
+
|
|
254
|
+
async def disconnect(self) -> None:
|
|
255
|
+
"""Disconnect session gracefully.
|
|
256
|
+
|
|
257
|
+
This method cleans up all resources and connections.
|
|
258
|
+
"""
|
|
259
|
+
logger.info(f"Disconnecting session for {self.server_name}")
|
|
260
|
+
|
|
261
|
+
async with self._lock:
|
|
262
|
+
try:
|
|
263
|
+
# Close client session
|
|
264
|
+
if self.client_session:
|
|
265
|
+
try:
|
|
266
|
+
await self.client_session.__aexit__(None, None, None)
|
|
267
|
+
except Exception as e:
|
|
268
|
+
logger.warning(f"Error closing client session for {self.server_name}: {e}")
|
|
269
|
+
self.client_session = None
|
|
270
|
+
|
|
271
|
+
# Stop connection manager
|
|
272
|
+
await self.connection_manager.stop()
|
|
273
|
+
|
|
274
|
+
except Exception as e:
|
|
275
|
+
logger.error(f"Error during disconnect for {self.server_name}: {e}")
|
|
276
|
+
finally:
|
|
277
|
+
self._initialized = False
|
|
278
|
+
self.tools.clear()
|
|
279
|
+
self._filtered_tools_cache = None # Clear cache on disconnect
|
|
280
|
+
logger.info(f"Session disconnected for {self.server_name}")
|
|
281
|
+
|
|
282
|
+
async def _cleanup_on_error(self) -> None:
|
|
283
|
+
"""Internal cleanup method for error scenarios."""
|
|
284
|
+
try:
|
|
285
|
+
if self.client_session:
|
|
286
|
+
await self.client_session.__aexit__(None, None, None)
|
|
287
|
+
self.client_session = None
|
|
288
|
+
except Exception as e:
|
|
289
|
+
logger.debug(f"Ignored cleanup error for client_session: {e}")
|
|
290
|
+
|
|
291
|
+
try:
|
|
292
|
+
await self.connection_manager.stop()
|
|
293
|
+
except Exception as e:
|
|
294
|
+
logger.debug(f"Ignored cleanup error for connection_manager: {e}")
|
|
295
|
+
|
|
296
|
+
self._initialized = False
|
|
297
|
+
self.tools.clear()
|
|
298
|
+
self._filtered_tools_cache = None # Clear cache on error cleanup
|
|
299
|
+
|
|
300
|
+
@property
|
|
301
|
+
def is_initialized(self) -> bool:
|
|
302
|
+
"""Check if session is initialized.
|
|
303
|
+
|
|
304
|
+
Returns:
|
|
305
|
+
bool: True if initialized and connected, False otherwise
|
|
306
|
+
"""
|
|
307
|
+
return self._initialized and self.connection_manager.is_connected
|
|
308
|
+
|
|
309
|
+
def update_allowed_tools(self, allowed_tools: list[str] | None) -> bool:
|
|
310
|
+
"""Update the list of allowed tools for this session.
|
|
311
|
+
|
|
312
|
+
Args:
|
|
313
|
+
allowed_tools: New list of allowed tool names or None for no restriction.
|
|
314
|
+
None and empty list both mean 'no restrictions, allow all tools'.
|
|
315
|
+
|
|
316
|
+
Returns:
|
|
317
|
+
bool: True if the configuration changed, False otherwise.
|
|
318
|
+
|
|
319
|
+
Raises:
|
|
320
|
+
ValueError: If allowed_tools contains invalid entries.
|
|
321
|
+
"""
|
|
322
|
+
# Validate first - ensures consistent error handling regardless of current state
|
|
323
|
+
validated = validate_allowed_tools_list(allowed_tools, f"Server '{self.server_name}'")
|
|
324
|
+
new_set = set(validated) if validated else None
|
|
325
|
+
|
|
326
|
+
# Check if actually changed
|
|
327
|
+
if self._allowed_tools_set == new_set:
|
|
328
|
+
logger.debug(f"Allowed tools unchanged for {self.server_name}")
|
|
329
|
+
return False
|
|
330
|
+
|
|
331
|
+
# Log and update
|
|
332
|
+
old_display = sorted(self._allowed_tools_set) if self._allowed_tools_set else None
|
|
333
|
+
self._allowed_tools_set = new_set
|
|
334
|
+
self._filtered_tools_cache = None # Invalidate cache when allowed_tools changes
|
|
335
|
+
logger.debug(f"Updated allowed_tools for {self.server_name}: {old_display} -> {validated}")
|
|
336
|
+
|
|
337
|
+
# Warn immediately if we already have cached tools
|
|
338
|
+
if self.tools:
|
|
339
|
+
self._warn_on_unknown_allowed_tools(validated, self.tools)
|
|
340
|
+
return True
|
|
341
|
+
|
|
342
|
+
def _warn_on_unknown_allowed_tools(self, allowed_tools: list[str] | None, available_tools: list[Tool]) -> None:
|
|
343
|
+
"""Emit warnings for allowed tool names that are not exposed by the server.
|
|
344
|
+
|
|
345
|
+
Warnings are deduplicated - each unknown tool is only warned about once per session.
|
|
346
|
+
|
|
347
|
+
Args:
|
|
348
|
+
allowed_tools: Configured whitelist of tool names, or None for no restriction.
|
|
349
|
+
available_tools: Tools currently exposed by the server.
|
|
350
|
+
"""
|
|
351
|
+
if not allowed_tools or not available_tools:
|
|
352
|
+
return
|
|
353
|
+
|
|
354
|
+
available_names = {tool.name for tool in available_tools}
|
|
355
|
+
unknown = [tool_name for tool_name in allowed_tools if tool_name not in available_names]
|
|
356
|
+
for tool_name in unknown:
|
|
357
|
+
# Only warn once per tool name
|
|
358
|
+
if tool_name not in self._warned_unknown_tools:
|
|
359
|
+
self._warned_unknown_tools.add(tool_name)
|
|
360
|
+
logger.warning(
|
|
361
|
+
f"[{self.server_name}] Tool '{tool_name}' not found in available tools but specified in allowed_tools"
|
|
362
|
+
)
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
from _typeshed import Incomplete
|
|
2
|
+
from aip_agents.mcp.client.connection_manager import MCPConnectionManager as MCPConnectionManager
|
|
3
|
+
from aip_agents.mcp.utils.config_validator import validate_allowed_tools_list as validate_allowed_tools_list
|
|
4
|
+
from aip_agents.utils.logger import get_logger as get_logger
|
|
5
|
+
from gllm_tools.mcp.client.config import MCPConfiguration
|
|
6
|
+
from mcp import ClientSession
|
|
7
|
+
from mcp.types import CallToolResult, Tool as Tool
|
|
8
|
+
from typing import Any
|
|
9
|
+
|
|
10
|
+
logger: Incomplete
|
|
11
|
+
|
|
12
|
+
class PersistentMCPSession:
|
|
13
|
+
"""Persistent MCP session that reuses connections.
|
|
14
|
+
|
|
15
|
+
This session wrapper manages the connection lifecycle and caches tools
|
|
16
|
+
to avoid repeated initialization overhead. It provides automatic reconnection
|
|
17
|
+
and thread-safe operations.
|
|
18
|
+
|
|
19
|
+
Tool Filtering:
|
|
20
|
+
When allowed_tools is configured, tools are filtered inline during list_tools()
|
|
21
|
+
and permission checked in call_tool() using set lookup.
|
|
22
|
+
"""
|
|
23
|
+
server_name: Incomplete
|
|
24
|
+
config: Incomplete
|
|
25
|
+
connection_manager: Incomplete
|
|
26
|
+
client_session: ClientSession | None
|
|
27
|
+
tools: list[Tool]
|
|
28
|
+
def __init__(self, server_name: str, config: MCPConfiguration, allowed_tools: list[str] | None = None) -> None:
|
|
29
|
+
"""Initialize persistent session.
|
|
30
|
+
|
|
31
|
+
Args:
|
|
32
|
+
server_name: Name of the MCP server
|
|
33
|
+
config: MCP server configuration
|
|
34
|
+
allowed_tools: Optional list of tool names to allow. None or empty means all tools allowed.
|
|
35
|
+
"""
|
|
36
|
+
async def initialize(self) -> None:
|
|
37
|
+
"""Initialize session once and cache tools.
|
|
38
|
+
|
|
39
|
+
This method is idempotent and can be called multiple times safely.
|
|
40
|
+
|
|
41
|
+
Raises:
|
|
42
|
+
Exception: If session initialization fails
|
|
43
|
+
"""
|
|
44
|
+
async def call_tool(self, name: str, arguments: dict[str, Any]) -> CallToolResult:
|
|
45
|
+
"""Call MCP tool using persistent session.
|
|
46
|
+
|
|
47
|
+
Args:
|
|
48
|
+
name (str): Tool name
|
|
49
|
+
arguments (dict[str, Any]): Tool arguments
|
|
50
|
+
|
|
51
|
+
Returns:
|
|
52
|
+
CallToolResult: Tool call result
|
|
53
|
+
|
|
54
|
+
Raises:
|
|
55
|
+
Exception: If tool call fails
|
|
56
|
+
"""
|
|
57
|
+
async def read_resource(self, uri: str) -> Any:
|
|
58
|
+
"""Read an MCP resource using persistent session.
|
|
59
|
+
|
|
60
|
+
Args:
|
|
61
|
+
uri (str): The URI of the resource to read
|
|
62
|
+
|
|
63
|
+
Returns:
|
|
64
|
+
Any: The resource content
|
|
65
|
+
|
|
66
|
+
Raises:
|
|
67
|
+
Exception: If resource reading fails
|
|
68
|
+
"""
|
|
69
|
+
async def list_tools(self) -> list[Tool]:
|
|
70
|
+
"""Get cached tools list with allowed tools filtering applied.
|
|
71
|
+
|
|
72
|
+
Returns:
|
|
73
|
+
list[Tool]: a copy of list of available tools, filtered to only allowed tools if configured
|
|
74
|
+
"""
|
|
75
|
+
def get_tools_count(self) -> int:
|
|
76
|
+
"""Get count of allowed tools.
|
|
77
|
+
|
|
78
|
+
Returns:
|
|
79
|
+
Count of allowed tools
|
|
80
|
+
"""
|
|
81
|
+
async def ensure_connected(self) -> None:
|
|
82
|
+
"""Ensure connection is healthy, reconnect if needed.
|
|
83
|
+
|
|
84
|
+
This method provides automatic reconnection capability.
|
|
85
|
+
|
|
86
|
+
Raises:
|
|
87
|
+
Exception: If reconnection fails
|
|
88
|
+
"""
|
|
89
|
+
async def disconnect(self) -> None:
|
|
90
|
+
"""Disconnect session gracefully.
|
|
91
|
+
|
|
92
|
+
This method cleans up all resources and connections.
|
|
93
|
+
"""
|
|
94
|
+
@property
|
|
95
|
+
def is_initialized(self) -> bool:
|
|
96
|
+
"""Check if session is initialized.
|
|
97
|
+
|
|
98
|
+
Returns:
|
|
99
|
+
bool: True if initialized and connected, False otherwise
|
|
100
|
+
"""
|
|
101
|
+
def update_allowed_tools(self, allowed_tools: list[str] | None) -> bool:
|
|
102
|
+
"""Update the list of allowed tools for this session.
|
|
103
|
+
|
|
104
|
+
Args:
|
|
105
|
+
allowed_tools: New list of allowed tool names or None for no restriction.
|
|
106
|
+
None and empty list both mean 'no restrictions, allow all tools'.
|
|
107
|
+
|
|
108
|
+
Returns:
|
|
109
|
+
bool: True if the configuration changed, False otherwise.
|
|
110
|
+
|
|
111
|
+
Raises:
|
|
112
|
+
ValueError: If allowed_tools contains invalid entries.
|
|
113
|
+
"""
|