aip-agents-binary 0.5.20__py3-none-manylinux_2_31_x86_64.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 +2942 -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 +2514 -0
- aip_agents/agent/langgraph_react_agent.pyi +126 -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_bosa_twitter.py +41 -0
- aip_agents/examples/hello_world_langgraph_bosa_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/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 +359 -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 +215 -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 +88 -0
- aip_agents/middleware/base.pyi +71 -0
- aip_agents/middleware/manager.py +128 -0
- aip_agents/middleware/manager.pyi +80 -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 +33 -0
- aip_agents/tools/__init__.pyi +13 -0
- aip_agents/tools/bosa_tools.py +105 -0
- aip_agents/tools/bosa_tools.pyi +37 -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 +257 -0
- aip_agents/tools/code_sandbox/e2b_cloud_sandbox_extended.pyi +86 -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 +165 -0
- aip_agents/tools/constants.pyi +135 -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 +351 -0
- aip_agents/tools/gl_connector/tool.pyi +74 -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.20.dist-info/METADATA +681 -0
- aip_agents_binary-0.5.20.dist-info/RECORD +546 -0
- aip_agents_binary-0.5.20.dist-info/WHEEL +5 -0
- aip_agents_binary-0.5.20.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,515 @@
|
|
|
1
|
+
"""Mixin that encapsulates HITL helper logic for LangGraph agents."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from collections.abc import Callable
|
|
6
|
+
from datetime import datetime
|
|
7
|
+
from typing import Any
|
|
8
|
+
|
|
9
|
+
from langchain_core.messages import ToolMessage
|
|
10
|
+
from langgraph.config import get_stream_writer
|
|
11
|
+
from langgraph.types import StreamWriter
|
|
12
|
+
|
|
13
|
+
from aip_agents.agent.hitl.config import ToolApprovalConfig
|
|
14
|
+
from aip_agents.agent.hitl.manager import ApprovalManager
|
|
15
|
+
from aip_agents.schema.hitl import ApprovalDecision, ApprovalDecisionType, ApprovalRequest, HitlMetadata
|
|
16
|
+
from aip_agents.schema.langgraph import ToolCallResult
|
|
17
|
+
from aip_agents.tools.tool_config_injector import TOOL_CONFIGS_KEY
|
|
18
|
+
from aip_agents.utils.datetime import ensure_utc_datetime
|
|
19
|
+
from aip_agents.utils.logger import get_logger
|
|
20
|
+
|
|
21
|
+
logger = get_logger(__name__)
|
|
22
|
+
|
|
23
|
+
MAX_CONTEXT_MESSAGE_LENGTH = 200
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class LangGraphHitLMixin:
|
|
27
|
+
"""Provide Human-in-the-Loop helpers for LangGraph agents."""
|
|
28
|
+
|
|
29
|
+
_hitl_manager: ApprovalManager | None
|
|
30
|
+
tool_configs: dict[str, Any] | None
|
|
31
|
+
name: str
|
|
32
|
+
|
|
33
|
+
@property
|
|
34
|
+
def hitl_manager(self) -> ApprovalManager | None:
|
|
35
|
+
"""Return the active ``ApprovalManager``, creating one if needed."""
|
|
36
|
+
manager = getattr(self, "_hitl_manager", None)
|
|
37
|
+
if manager is not None:
|
|
38
|
+
return manager
|
|
39
|
+
return self._initialize_hitl_manager_if_needed()
|
|
40
|
+
|
|
41
|
+
@hitl_manager.setter
|
|
42
|
+
def hitl_manager(self, manager: ApprovalManager | None) -> None:
|
|
43
|
+
"""Set the HITL approval manager instance.
|
|
44
|
+
|
|
45
|
+
Args:
|
|
46
|
+
manager: ApprovalManager instance or None.
|
|
47
|
+
"""
|
|
48
|
+
self._hitl_manager = manager
|
|
49
|
+
|
|
50
|
+
async def _check_hitl_approval(
|
|
51
|
+
self,
|
|
52
|
+
tool_call: dict[str, Any],
|
|
53
|
+
tool_name: str,
|
|
54
|
+
state: dict[str, Any],
|
|
55
|
+
) -> ApprovalDecision | None:
|
|
56
|
+
"""Resolve approval gating for a tool call if HITL is configured.
|
|
57
|
+
|
|
58
|
+
Args:
|
|
59
|
+
tool_call: The tool call information containing id, name, and args.
|
|
60
|
+
tool_name: Name of the tool being executed.
|
|
61
|
+
state: Current agent state containing conversation context.
|
|
62
|
+
|
|
63
|
+
Returns:
|
|
64
|
+
ApprovalDecision if HITL is configured and decision is made, None otherwise.
|
|
65
|
+
"""
|
|
66
|
+
hitl_config = self._get_hitl_config(tool_name)
|
|
67
|
+
manager = self.hitl_manager
|
|
68
|
+
if manager is None and hitl_config is not None:
|
|
69
|
+
manager = self._initialize_hitl_manager_for_tool(tool_name)
|
|
70
|
+
|
|
71
|
+
if manager is None or hitl_config is None:
|
|
72
|
+
return None
|
|
73
|
+
|
|
74
|
+
request = manager.create_approval_request(
|
|
75
|
+
tool_name=tool_name,
|
|
76
|
+
arguments=tool_call.get("args", {}),
|
|
77
|
+
config=hitl_config,
|
|
78
|
+
context=self._extract_hitl_context(state),
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
try:
|
|
82
|
+
decision = await manager.prompt_for_decision(
|
|
83
|
+
request=request,
|
|
84
|
+
timeout_seconds=hitl_config.timeout_seconds,
|
|
85
|
+
)
|
|
86
|
+
except Exception as exc: # noqa: BLE001
|
|
87
|
+
logger.warning(
|
|
88
|
+
"HITL approval check failed, proceeding with tool execution",
|
|
89
|
+
extra={"tool_name": tool_name, "error": str(exc), "error_type": type(exc).__name__},
|
|
90
|
+
)
|
|
91
|
+
return None
|
|
92
|
+
|
|
93
|
+
if decision.decision == ApprovalDecisionType.PENDING:
|
|
94
|
+
return await self._handle_pending_hitl_decision(
|
|
95
|
+
tool_call=tool_call,
|
|
96
|
+
pending_decision=decision,
|
|
97
|
+
request=request,
|
|
98
|
+
hitl_config=hitl_config,
|
|
99
|
+
state=state,
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
finalized_decision = self._finalize_hitl_decision(request, decision)
|
|
103
|
+
self._log_hitl_decision(tool_name, finalized_decision, state)
|
|
104
|
+
return finalized_decision
|
|
105
|
+
|
|
106
|
+
def _finalize_hitl_decision(
|
|
107
|
+
self,
|
|
108
|
+
request: ApprovalRequest,
|
|
109
|
+
decision: ApprovalDecision,
|
|
110
|
+
) -> ApprovalDecision:
|
|
111
|
+
"""Convert prompt handler output into a manager-recorded decision.
|
|
112
|
+
|
|
113
|
+
Args:
|
|
114
|
+
request: The approval request that was made.
|
|
115
|
+
decision: The decision returned by the prompt handler.
|
|
116
|
+
|
|
117
|
+
Returns:
|
|
118
|
+
Finalized ApprovalDecision recorded with the manager.
|
|
119
|
+
"""
|
|
120
|
+
manager = self.hitl_manager
|
|
121
|
+
if manager is None:
|
|
122
|
+
return decision
|
|
123
|
+
|
|
124
|
+
operator_input = decision.operator_input or ""
|
|
125
|
+
|
|
126
|
+
if decision.decision == ApprovalDecisionType.PENDING:
|
|
127
|
+
return decision
|
|
128
|
+
|
|
129
|
+
if decision.decision == ApprovalDecisionType.TIMEOUT_SKIP:
|
|
130
|
+
return manager.timeout_request(
|
|
131
|
+
request,
|
|
132
|
+
operator_input=operator_input or "TIMEOUT",
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
decision_handlers = {
|
|
136
|
+
ApprovalDecisionType.APPROVED: manager.approve_request,
|
|
137
|
+
ApprovalDecisionType.REJECTED: manager.reject_request,
|
|
138
|
+
ApprovalDecisionType.SKIPPED: manager.skip_request,
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
handler = decision_handlers.get(decision.decision)
|
|
142
|
+
if handler:
|
|
143
|
+
return handler(request, operator_input)
|
|
144
|
+
|
|
145
|
+
return manager.skip_request(request, operator_input)
|
|
146
|
+
|
|
147
|
+
async def _handle_pending_hitl_decision(
|
|
148
|
+
self,
|
|
149
|
+
tool_call: dict[str, Any],
|
|
150
|
+
pending_decision: ApprovalDecision,
|
|
151
|
+
request: ApprovalRequest | None,
|
|
152
|
+
hitl_config: ToolApprovalConfig | None,
|
|
153
|
+
state: dict[str, Any],
|
|
154
|
+
) -> ApprovalDecision:
|
|
155
|
+
"""Emit a pending sentinel and wait for resolution from the manager.
|
|
156
|
+
|
|
157
|
+
Args:
|
|
158
|
+
tool_call: The tool call information that requires approval.
|
|
159
|
+
pending_decision: The initial pending decision from the prompt handler.
|
|
160
|
+
request: The approval request that was created.
|
|
161
|
+
hitl_config: Configuration for the HITL approval process.
|
|
162
|
+
state: Current agent state containing conversation context.
|
|
163
|
+
|
|
164
|
+
Returns:
|
|
165
|
+
Final approval decision after waiting for external resolution.
|
|
166
|
+
"""
|
|
167
|
+
manager = self.hitl_manager
|
|
168
|
+
if manager is None or request is None or hitl_config is None:
|
|
169
|
+
return pending_decision
|
|
170
|
+
|
|
171
|
+
self._emit_hitl_pending_event(
|
|
172
|
+
tool_call=tool_call,
|
|
173
|
+
decision=pending_decision,
|
|
174
|
+
request=request,
|
|
175
|
+
hitl_config=hitl_config,
|
|
176
|
+
)
|
|
177
|
+
|
|
178
|
+
final_decision = await manager.wait_for_pending_decision(
|
|
179
|
+
request=request,
|
|
180
|
+
timeout_seconds=hitl_config.timeout_seconds,
|
|
181
|
+
)
|
|
182
|
+
|
|
183
|
+
self._log_hitl_decision(tool_call["name"], final_decision, state)
|
|
184
|
+
return final_decision
|
|
185
|
+
|
|
186
|
+
def _log_hitl_decision(self, tool_name: str, decision: ApprovalDecision, state: dict[str, Any]) -> None:
|
|
187
|
+
"""Emit a structured log entry for a resolved HITL decision.
|
|
188
|
+
|
|
189
|
+
Args:
|
|
190
|
+
tool_name: Name of the tool that required approval.
|
|
191
|
+
decision: The final approval decision that was made.
|
|
192
|
+
state: Current agent state containing thread_id and other context.
|
|
193
|
+
"""
|
|
194
|
+
manager = self.hitl_manager
|
|
195
|
+
if manager is None:
|
|
196
|
+
return
|
|
197
|
+
|
|
198
|
+
log_entry = manager.create_log_entry(
|
|
199
|
+
decision=decision,
|
|
200
|
+
tool_name=tool_name,
|
|
201
|
+
agent_id=getattr(self, "name", None),
|
|
202
|
+
thread_id=state.get("thread_id"),
|
|
203
|
+
)
|
|
204
|
+
logger.info("HITL decision recorded", extra=log_entry.__dict__)
|
|
205
|
+
|
|
206
|
+
def _emit_hitl_pending_event(
|
|
207
|
+
self,
|
|
208
|
+
tool_call: dict[str, Any],
|
|
209
|
+
decision: ApprovalDecision,
|
|
210
|
+
request: ApprovalRequest | None = None,
|
|
211
|
+
hitl_config: ToolApprovalConfig | None = None,
|
|
212
|
+
) -> None:
|
|
213
|
+
"""Send a streaming sentinel describing a pending HITL request.
|
|
214
|
+
|
|
215
|
+
Args:
|
|
216
|
+
tool_call: The tool call information that requires approval.
|
|
217
|
+
decision: The pending approval decision.
|
|
218
|
+
request: The approval request that was created.
|
|
219
|
+
hitl_config: Configuration for the HITL approval process.
|
|
220
|
+
"""
|
|
221
|
+
# Pending uses the same sentinel builder as other blocking decisions so streaming stays consistent.
|
|
222
|
+
sentinel_result = self._create_hitl_blocking_result(
|
|
223
|
+
tool_call=tool_call,
|
|
224
|
+
decision=decision,
|
|
225
|
+
pending_request=request,
|
|
226
|
+
hitl_config=hitl_config,
|
|
227
|
+
)
|
|
228
|
+
if not sentinel_result.messages:
|
|
229
|
+
return
|
|
230
|
+
|
|
231
|
+
try:
|
|
232
|
+
writer: StreamWriter | None = get_stream_writer()
|
|
233
|
+
except Exception: # noqa: BLE001
|
|
234
|
+
writer = None
|
|
235
|
+
|
|
236
|
+
if writer is None:
|
|
237
|
+
return
|
|
238
|
+
|
|
239
|
+
event = self._create_tool_result_event(sentinel_result.messages[0])
|
|
240
|
+
try:
|
|
241
|
+
writer(event)
|
|
242
|
+
except Exception: # noqa: BLE001
|
|
243
|
+
logger.warning(f"Failed to emit HITL pending event: {tool_call['name']}")
|
|
244
|
+
|
|
245
|
+
def _get_hitl_config(self, tool_name: str) -> ToolApprovalConfig | None:
|
|
246
|
+
"""Extract the HITL configuration for a tool from agent-level settings.
|
|
247
|
+
|
|
248
|
+
Args:
|
|
249
|
+
tool_name: Name of the tool to get HITL configuration for.
|
|
250
|
+
|
|
251
|
+
Returns:
|
|
252
|
+
ToolApprovalConfig if HITL is configured for the tool, None otherwise.
|
|
253
|
+
"""
|
|
254
|
+
tool_configs = self.tool_configs
|
|
255
|
+
if not isinstance(tool_configs, dict):
|
|
256
|
+
return None
|
|
257
|
+
|
|
258
|
+
direct_config = self._get_direct_tool_hitl_config(tool_name)
|
|
259
|
+
if direct_config:
|
|
260
|
+
return direct_config
|
|
261
|
+
|
|
262
|
+
nested_config = self._get_nested_tool_hitl_config(tool_name)
|
|
263
|
+
if nested_config:
|
|
264
|
+
return nested_config
|
|
265
|
+
|
|
266
|
+
return None
|
|
267
|
+
|
|
268
|
+
def _get_direct_tool_hitl_config(self, tool_name: str) -> ToolApprovalConfig | None:
|
|
269
|
+
"""Resolve HITL configuration using a direct tool name lookup.
|
|
270
|
+
|
|
271
|
+
Args:
|
|
272
|
+
tool_name: Name of the tool to get HITL configuration for.
|
|
273
|
+
|
|
274
|
+
Returns:
|
|
275
|
+
ToolApprovalConfig if found using direct lookup, None otherwise.
|
|
276
|
+
"""
|
|
277
|
+
tool_configs = self.tool_configs or {}
|
|
278
|
+
tool_config = tool_configs.get(tool_name)
|
|
279
|
+
return self._parse_hitl_config_value(tool_config, tool_name)
|
|
280
|
+
|
|
281
|
+
def _get_nested_tool_hitl_config(self, tool_name: str) -> ToolApprovalConfig | None:
|
|
282
|
+
"""Resolve HITL configuration from a nested ``tool_configs`` map.
|
|
283
|
+
|
|
284
|
+
Args:
|
|
285
|
+
tool_name: Name of the tool to get HITL configuration for.
|
|
286
|
+
|
|
287
|
+
Returns:
|
|
288
|
+
ToolApprovalConfig if found in nested configuration, None otherwise.
|
|
289
|
+
"""
|
|
290
|
+
tool_configs = self.tool_configs or {}
|
|
291
|
+
nested_configs = tool_configs.get(TOOL_CONFIGS_KEY)
|
|
292
|
+
if not isinstance(nested_configs, dict):
|
|
293
|
+
return None
|
|
294
|
+
|
|
295
|
+
tool_config = nested_configs.get(tool_name)
|
|
296
|
+
return self._parse_hitl_config_value(tool_config, tool_name)
|
|
297
|
+
|
|
298
|
+
def _parse_hitl_config_value(self, value: Any, tool_name: str) -> ToolApprovalConfig | None:
|
|
299
|
+
"""Convert a configuration value into ``ToolApprovalConfig`` if possible.
|
|
300
|
+
|
|
301
|
+
Args:
|
|
302
|
+
value: The configuration value to parse (can be ToolApprovalConfig, dict, or other).
|
|
303
|
+
tool_name: Name of the tool this configuration is for.
|
|
304
|
+
|
|
305
|
+
Returns:
|
|
306
|
+
ToolApprovalConfig if parsing succeeds, None otherwise.
|
|
307
|
+
"""
|
|
308
|
+
if isinstance(value, ToolApprovalConfig):
|
|
309
|
+
return value
|
|
310
|
+
|
|
311
|
+
if isinstance(value, dict):
|
|
312
|
+
return self._parse_hitl_config_dict(value, tool_name)
|
|
313
|
+
|
|
314
|
+
return None
|
|
315
|
+
|
|
316
|
+
def _parse_hitl_config_dict(self, value: dict[str, Any], tool_name: str) -> ToolApprovalConfig | None:
|
|
317
|
+
"""Construct ``ToolApprovalConfig`` from a dictionary of values.
|
|
318
|
+
|
|
319
|
+
Args:
|
|
320
|
+
value: Dictionary containing HITL configuration parameters.
|
|
321
|
+
tool_name: Name of the tool this configuration is for.
|
|
322
|
+
|
|
323
|
+
Returns:
|
|
324
|
+
ToolApprovalConfig if construction succeeds, None otherwise.
|
|
325
|
+
"""
|
|
326
|
+
if "hitl" in value:
|
|
327
|
+
return self._parse_hitl_config_value(value["hitl"], tool_name)
|
|
328
|
+
|
|
329
|
+
allowed_keys = {"timeout_seconds", "requires_approval"}
|
|
330
|
+
if not set(value.keys()).issubset(allowed_keys):
|
|
331
|
+
return None
|
|
332
|
+
|
|
333
|
+
config_kwargs = dict(value)
|
|
334
|
+
config_kwargs.pop("requires_approval", None)
|
|
335
|
+
try:
|
|
336
|
+
return ToolApprovalConfig(**config_kwargs)
|
|
337
|
+
except (TypeError, ValueError):
|
|
338
|
+
return None
|
|
339
|
+
|
|
340
|
+
def ensure_hitl_manager(self) -> ApprovalManager | None:
|
|
341
|
+
"""Ensure an ``ApprovalManager`` exists when HITL configs are present."""
|
|
342
|
+
return self._initialize_hitl_manager_if_needed()
|
|
343
|
+
|
|
344
|
+
def use_hitl_manager(self, manager: ApprovalManager) -> None:
|
|
345
|
+
"""Replace the current ``ApprovalManager`` with the supplied instance.
|
|
346
|
+
|
|
347
|
+
Args:
|
|
348
|
+
manager: The ApprovalManager instance to use for HITL approvals.
|
|
349
|
+
"""
|
|
350
|
+
self.hitl_manager = manager
|
|
351
|
+
|
|
352
|
+
def register_hitl_notifier(self, notifier: Callable[[ApprovalRequest], None]) -> None:
|
|
353
|
+
"""Register a notifier callback to receive HITL approval requests.
|
|
354
|
+
|
|
355
|
+
Args:
|
|
356
|
+
notifier: Callback function that will be called with approval requests.
|
|
357
|
+
"""
|
|
358
|
+
manager = self.ensure_hitl_manager()
|
|
359
|
+
if manager is None:
|
|
360
|
+
manager = self._create_default_hitl_manager()
|
|
361
|
+
self.hitl_manager = manager
|
|
362
|
+
|
|
363
|
+
handler = getattr(manager, "_prompt_handler", None)
|
|
364
|
+
if handler is None:
|
|
365
|
+
return
|
|
366
|
+
|
|
367
|
+
if hasattr(handler, "attach_manager"):
|
|
368
|
+
try:
|
|
369
|
+
handler.attach_manager(manager) # type: ignore[call-arg]
|
|
370
|
+
except Exception:
|
|
371
|
+
pass
|
|
372
|
+
|
|
373
|
+
try:
|
|
374
|
+
handler._notify = notifier
|
|
375
|
+
except Exception:
|
|
376
|
+
logger.warning("Failed to attach HITL notifier callback", extra={"agent": getattr(self, "name", None)})
|
|
377
|
+
|
|
378
|
+
def _initialize_hitl_manager_for_tool(self, tool_name: str) -> ApprovalManager | None:
|
|
379
|
+
"""Create a default ``ApprovalManager`` for a specific tool if required.
|
|
380
|
+
|
|
381
|
+
Args:
|
|
382
|
+
tool_name: Name of the tool that requires HITL approval.
|
|
383
|
+
|
|
384
|
+
Returns:
|
|
385
|
+
ApprovalManager instance if HITL is needed, None otherwise.
|
|
386
|
+
"""
|
|
387
|
+
return self._initialize_hitl_manager_if_needed(tool_name)
|
|
388
|
+
|
|
389
|
+
def _initialize_hitl_manager_if_needed(self, tool_name: str | None = None) -> ApprovalManager | None:
|
|
390
|
+
"""Create a default ``ApprovalManager`` when HITL configs require it.
|
|
391
|
+
|
|
392
|
+
Args:
|
|
393
|
+
tool_name: Optional name of the tool that triggered the initialization.
|
|
394
|
+
|
|
395
|
+
Returns:
|
|
396
|
+
ApprovalManager instance if HITL is needed, None otherwise.
|
|
397
|
+
"""
|
|
398
|
+
manager = getattr(self, "_hitl_manager", None)
|
|
399
|
+
if manager is not None:
|
|
400
|
+
return manager
|
|
401
|
+
|
|
402
|
+
candidate_names = {tool_name} if tool_name else self._collect_hitl_tool_names()
|
|
403
|
+
if candidate_names and any(self._get_hitl_config(name) for name in candidate_names):
|
|
404
|
+
self._hitl_manager = self._create_default_hitl_manager()
|
|
405
|
+
logger.debug("Agent '%s': HITL manager auto-initialized", self.name)
|
|
406
|
+
|
|
407
|
+
return getattr(self, "_hitl_manager", None)
|
|
408
|
+
|
|
409
|
+
def _collect_hitl_tool_names(self) -> set[str]:
|
|
410
|
+
"""Gather candidate tool names that may have HITL configuration."""
|
|
411
|
+
names: set[str] = set()
|
|
412
|
+
|
|
413
|
+
try:
|
|
414
|
+
names.update(tool.name for tool in getattr(self, "resolved_tools", []) if getattr(tool, "name", None))
|
|
415
|
+
except Exception:
|
|
416
|
+
pass
|
|
417
|
+
|
|
418
|
+
tool_configs = getattr(self, "tool_configs", {})
|
|
419
|
+
if isinstance(tool_configs, dict):
|
|
420
|
+
for key, value in tool_configs.items():
|
|
421
|
+
if key != TOOL_CONFIGS_KEY and isinstance(value, dict):
|
|
422
|
+
names.add(str(key))
|
|
423
|
+
|
|
424
|
+
nested = tool_configs.get(TOOL_CONFIGS_KEY)
|
|
425
|
+
if isinstance(nested, dict):
|
|
426
|
+
names.update(str(k) for k in nested.keys())
|
|
427
|
+
|
|
428
|
+
return names
|
|
429
|
+
|
|
430
|
+
def _create_default_hitl_manager(self) -> ApprovalManager:
|
|
431
|
+
"""Create the default ``ApprovalManager`` used for auto HITL handling."""
|
|
432
|
+
return ApprovalManager()
|
|
433
|
+
|
|
434
|
+
def _extract_hitl_context(self, state: dict[str, Any]) -> dict[str, str] | None:
|
|
435
|
+
"""Collect human-readable context for approval prompts.
|
|
436
|
+
|
|
437
|
+
Args:
|
|
438
|
+
state: Current agent state containing messages and thread information.
|
|
439
|
+
|
|
440
|
+
Returns:
|
|
441
|
+
Dictionary containing context information like last user message and thread_id,
|
|
442
|
+
or None if no context is available.
|
|
443
|
+
"""
|
|
444
|
+
context: dict[str, str] = {}
|
|
445
|
+
|
|
446
|
+
messages = state.get("messages", [])
|
|
447
|
+
for msg in reversed(messages):
|
|
448
|
+
if hasattr(msg, "type") and msg.type == "human":
|
|
449
|
+
content = getattr(msg, "content", "")
|
|
450
|
+
if content:
|
|
451
|
+
truncated_content = content[:MAX_CONTEXT_MESSAGE_LENGTH]
|
|
452
|
+
context["last_user_message"] = truncated_content
|
|
453
|
+
break
|
|
454
|
+
|
|
455
|
+
thread_id = state.get("thread_id")
|
|
456
|
+
if thread_id:
|
|
457
|
+
context["thread_id"] = str(thread_id)
|
|
458
|
+
|
|
459
|
+
return context or None
|
|
460
|
+
|
|
461
|
+
def _create_hitl_blocking_result(
|
|
462
|
+
self,
|
|
463
|
+
tool_call: dict[str, Any],
|
|
464
|
+
decision: ApprovalDecision,
|
|
465
|
+
pending_request: ApprovalRequest | None = None,
|
|
466
|
+
hitl_config: ToolApprovalConfig | None = None,
|
|
467
|
+
) -> ToolCallResult:
|
|
468
|
+
"""Build a sentinel ``ToolCallResult`` for any tool-execution-blocking HITL decision.
|
|
469
|
+
|
|
470
|
+
Covers ``REJECTED``, ``SKIPPED``, ``TIMEOUT_SKIP`` and ``PENDING`` decisions, providing a
|
|
471
|
+
consistent message payload for streaming and logging when execution does not proceed.
|
|
472
|
+
|
|
473
|
+
Args:
|
|
474
|
+
tool_call: The tool call information that was blocked.
|
|
475
|
+
decision: The approval decision that blocked execution.
|
|
476
|
+
pending_request: The approval request if decision is pending.
|
|
477
|
+
hitl_config: Configuration for the HITL approval process.
|
|
478
|
+
|
|
479
|
+
Returns:
|
|
480
|
+
ToolCallResult with sentinel messages and metadata for the blocking decision.
|
|
481
|
+
"""
|
|
482
|
+
manager = self.hitl_manager
|
|
483
|
+
if manager is None:
|
|
484
|
+
return ToolCallResult(messages=[], artifacts=[], metadata_delta={}, references=[], step_usage=None)
|
|
485
|
+
|
|
486
|
+
tool_call_id = tool_call["id"]
|
|
487
|
+
message_content = manager.get_decision_message(decision)
|
|
488
|
+
|
|
489
|
+
timeout_seconds = None
|
|
490
|
+
if hitl_config and getattr(hitl_config, "timeout_seconds", None) is not None:
|
|
491
|
+
timeout_seconds = hitl_config.timeout_seconds
|
|
492
|
+
|
|
493
|
+
timeout_at = getattr(pending_request, "timeout_at", None)
|
|
494
|
+
timeout_at_utc = ensure_utc_datetime(timeout_at) if isinstance(timeout_at, datetime) else None
|
|
495
|
+
|
|
496
|
+
hitl_meta = HitlMetadata.from_decision(
|
|
497
|
+
decision,
|
|
498
|
+
timeout_seconds=timeout_seconds,
|
|
499
|
+
timeout_at=timeout_at_utc,
|
|
500
|
+
).as_payload()
|
|
501
|
+
|
|
502
|
+
sentinel_message = ToolMessage(
|
|
503
|
+
content=message_content,
|
|
504
|
+
tool_call_id=tool_call_id,
|
|
505
|
+
name=tool_call["name"],
|
|
506
|
+
response_metadata={"hitl": hitl_meta},
|
|
507
|
+
)
|
|
508
|
+
|
|
509
|
+
return ToolCallResult(
|
|
510
|
+
messages=[sentinel_message],
|
|
511
|
+
artifacts=[],
|
|
512
|
+
metadata_delta={},
|
|
513
|
+
references=[],
|
|
514
|
+
step_usage=None,
|
|
515
|
+
)
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
from _typeshed import Incomplete
|
|
2
|
+
from aip_agents.agent.hitl.config import ToolApprovalConfig as ToolApprovalConfig
|
|
3
|
+
from aip_agents.agent.hitl.manager import ApprovalManager as ApprovalManager
|
|
4
|
+
from aip_agents.schema.hitl import ApprovalDecision as ApprovalDecision, ApprovalDecisionType as ApprovalDecisionType, ApprovalRequest as ApprovalRequest, HitlMetadata as HitlMetadata
|
|
5
|
+
from aip_agents.schema.langgraph import ToolCallResult as ToolCallResult
|
|
6
|
+
from aip_agents.tools.tool_config_injector import TOOL_CONFIGS_KEY as TOOL_CONFIGS_KEY
|
|
7
|
+
from aip_agents.utils.datetime import ensure_utc_datetime as ensure_utc_datetime
|
|
8
|
+
from aip_agents.utils.logger import get_logger as get_logger
|
|
9
|
+
from collections.abc import Callable
|
|
10
|
+
from typing import Any
|
|
11
|
+
|
|
12
|
+
logger: Incomplete
|
|
13
|
+
MAX_CONTEXT_MESSAGE_LENGTH: int
|
|
14
|
+
|
|
15
|
+
class LangGraphHitLMixin:
|
|
16
|
+
"""Provide Human-in-the-Loop helpers for LangGraph agents."""
|
|
17
|
+
tool_configs: dict[str, Any] | None
|
|
18
|
+
name: str
|
|
19
|
+
@property
|
|
20
|
+
def hitl_manager(self) -> ApprovalManager | None:
|
|
21
|
+
"""Return the active ``ApprovalManager``, creating one if needed."""
|
|
22
|
+
@hitl_manager.setter
|
|
23
|
+
def hitl_manager(self, manager: ApprovalManager | None) -> None:
|
|
24
|
+
"""Set the HITL approval manager instance.
|
|
25
|
+
|
|
26
|
+
Args:
|
|
27
|
+
manager: ApprovalManager instance or None.
|
|
28
|
+
"""
|
|
29
|
+
def ensure_hitl_manager(self) -> ApprovalManager | None:
|
|
30
|
+
"""Ensure an ``ApprovalManager`` exists when HITL configs are present."""
|
|
31
|
+
def use_hitl_manager(self, manager: ApprovalManager) -> None:
|
|
32
|
+
"""Replace the current ``ApprovalManager`` with the supplied instance.
|
|
33
|
+
|
|
34
|
+
Args:
|
|
35
|
+
manager: The ApprovalManager instance to use for HITL approvals.
|
|
36
|
+
"""
|
|
37
|
+
def register_hitl_notifier(self, notifier: Callable[[ApprovalRequest], None]) -> None:
|
|
38
|
+
"""Register a notifier callback to receive HITL approval requests.
|
|
39
|
+
|
|
40
|
+
Args:
|
|
41
|
+
notifier: Callback function that will be called with approval requests.
|
|
42
|
+
"""
|