aip-agents-binary 0.0.0__py3-none-any.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 +66 -0
- aip_agents/a2a/__init__.py +19 -0
- aip_agents/a2a/server/__init__.py +10 -0
- aip_agents/a2a/server/base_executor.py +1125 -0
- aip_agents/a2a/server/google_adk_executor.py +198 -0
- aip_agents/a2a/server/langflow_executor.py +180 -0
- aip_agents/a2a/server/langgraph_executor.py +270 -0
- aip_agents/a2a/types.py +232 -0
- aip_agents/a2ui/__init__.py +26 -0
- aip_agents/a2ui/catalog_provider.py +109 -0
- aip_agents/a2ui/examples/0.8/booking_form.json +1 -0
- aip_agents/a2ui/examples/0.8/confirmation.json +1 -0
- aip_agents/a2ui/examples/0.8/single_column_list.json +1 -0
- aip_agents/a2ui/examples/0.9/booking_form.json +1 -0
- aip_agents/a2ui/examples/0.9/confirmation.json +1 -0
- aip_agents/a2ui/examples/0.9/single_column_list.json +1 -0
- aip_agents/a2ui/middleware.py +754 -0
- aip_agents/a2ui/models.py +153 -0
- aip_agents/a2ui/public_url.py +138 -0
- aip_agents/a2ui/stream_filter.py +67 -0
- aip_agents/agent/__init__.py +72 -0
- aip_agents/agent/base_agent.py +1437 -0
- aip_agents/agent/base_langgraph_agent.py +4048 -0
- aip_agents/agent/google_adk_agent.py +932 -0
- aip_agents/agent/google_adk_constants.py +11 -0
- aip_agents/agent/graph_runtime.py +185 -0
- aip_agents/agent/hitl/__init__.py +24 -0
- aip_agents/agent/hitl/config.py +28 -0
- aip_agents/agent/hitl/langgraph_hitl_mixin.py +515 -0
- aip_agents/agent/hitl/manager.py +532 -0
- aip_agents/agent/hitl/models.py +18 -0
- aip_agents/agent/hitl/prompt/__init__.py +9 -0
- aip_agents/agent/hitl/prompt/base.py +42 -0
- aip_agents/agent/hitl/prompt/deferred.py +73 -0
- aip_agents/agent/hitl/registry.py +149 -0
- aip_agents/agent/interface.py +138 -0
- aip_agents/agent/interfaces.py +65 -0
- aip_agents/agent/langflow_agent.py +464 -0
- aip_agents/agent/langgraph_react_agent.py +3741 -0
- aip_agents/agent/model_invocation_adapter.py +346 -0
- aip_agents/agent/system_instruction_context.py +34 -0
- aip_agents/agent/tool_execution_engine.py +587 -0
- aip_agents/audio_interface/__init__.py +30 -0
- aip_agents/audio_interface/audio_agent_adapter.py +254 -0
- aip_agents/audio_interface/config.py +146 -0
- aip_agents/audio_interface/errors.py +15 -0
- aip_agents/audio_interface/livekit_audio_session.py +504 -0
- aip_agents/audio_interface/livekit_realtime_audio_session.py +142 -0
- aip_agents/audio_interface/session_factory.py +40 -0
- aip_agents/clients/__init__.py +10 -0
- aip_agents/clients/langflow/__init__.py +10 -0
- aip_agents/clients/langflow/client.py +477 -0
- aip_agents/clients/langflow/types.py +18 -0
- aip_agents/common/__init__.py +5 -0
- aip_agents/common/callable_introspection.py +17 -0
- aip_agents/constants.py +23 -0
- aip_agents/context/__init__.py +5 -0
- aip_agents/context/budget.py +237 -0
- aip_agents/context/compaction.py +339 -0
- aip_agents/context/metadata.py +169 -0
- aip_agents/context/offload.py +449 -0
- aip_agents/context/preparation.py +196 -0
- aip_agents/context/prompt.py +61 -0
- aip_agents/context/runtime.py +149 -0
- aip_agents/context/session_recall.py +69 -0
- aip_agents/context/state.py +48 -0
- aip_agents/context/utils.py +44 -0
- aip_agents/credentials/manager.py +132 -0
- aip_agents/examples/__init__.py +5 -0
- aip_agents/examples/audio_livekit_session.py +116 -0
- aip_agents/examples/compare_streaming_client.py +783 -0
- aip_agents/examples/compare_streaming_server.py +141 -0
- aip_agents/examples/gl_connectors_smoke.py +148 -0
- aip_agents/examples/hello_world_a2a_google_adk_client.py +49 -0
- aip_agents/examples/hello_world_a2a_google_adk_client_agent.py +48 -0
- aip_agents/examples/hello_world_a2a_google_adk_client_streaming.py +60 -0
- aip_agents/examples/hello_world_a2a_google_adk_server.py +78 -0
- aip_agents/examples/hello_world_a2a_langchain_client.py +39 -0
- aip_agents/examples/hello_world_a2a_langchain_client_agent.py +39 -0
- aip_agents/examples/hello_world_a2a_langchain_client_lm_invoker.py +37 -0
- aip_agents/examples/hello_world_a2a_langchain_client_streaming.py +41 -0
- aip_agents/examples/hello_world_a2a_langchain_reference_client_streaming.py +60 -0
- aip_agents/examples/hello_world_a2a_langchain_reference_server.py +104 -0
- aip_agents/examples/hello_world_a2a_langchain_server.py +78 -0
- aip_agents/examples/hello_world_a2a_langchain_server_lm_invoker.py +77 -0
- aip_agents/examples/hello_world_a2a_langflow_client.py +83 -0
- aip_agents/examples/hello_world_a2a_langflow_server.py +80 -0
- aip_agents/examples/hello_world_a2a_langgraph_artifact_client.py +73 -0
- aip_agents/examples/hello_world_a2a_langgraph_artifact_client_streaming.py +76 -0
- aip_agents/examples/hello_world_a2a_langgraph_artifact_server.py +91 -0
- aip_agents/examples/hello_world_a2a_langgraph_client.py +54 -0
- aip_agents/examples/hello_world_a2a_langgraph_client_agent.py +54 -0
- aip_agents/examples/hello_world_a2a_langgraph_client_agent_lm_invoker.py +32 -0
- aip_agents/examples/hello_world_a2a_langgraph_client_streaming.py +50 -0
- aip_agents/examples/hello_world_a2a_langgraph_client_streaming_lm_invoker.py +44 -0
- aip_agents/examples/hello_world_a2a_langgraph_client_streaming_tool_streaming.py +92 -0
- aip_agents/examples/hello_world_a2a_langgraph_server.py +83 -0
- aip_agents/examples/hello_world_a2a_langgraph_server_lm_invoker.py +78 -0
- aip_agents/examples/hello_world_a2a_langgraph_server_tool_streaming.py +131 -0
- aip_agents/examples/hello_world_a2a_mcp_langgraph.py +196 -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_server.py +250 -0
- aip_agents/examples/hello_world_a2a_with_metadata_langchain_client.py +57 -0
- aip_agents/examples/hello_world_a2a_with_metadata_langchain_server_lm_invoker.py +79 -0
- aip_agents/examples/hello_world_filesystem.py +162 -0
- aip_agents/examples/hello_world_google_adk.py +41 -0
- aip_agents/examples/hello_world_google_adk_mcp_http.py +34 -0
- aip_agents/examples/hello_world_google_adk_mcp_http_stream.py +40 -0
- aip_agents/examples/hello_world_google_adk_mcp_sse.py +44 -0
- aip_agents/examples/hello_world_google_adk_mcp_sse_stream.py +48 -0
- aip_agents/examples/hello_world_google_adk_mcp_stdio.py +44 -0
- aip_agents/examples/hello_world_google_adk_mcp_stdio_stream.py +48 -0
- aip_agents/examples/hello_world_google_adk_stream.py +44 -0
- aip_agents/examples/hello_world_langchain.py +28 -0
- aip_agents/examples/hello_world_langchain_lm_invoker.py +15 -0
- aip_agents/examples/hello_world_langchain_mcp_http.py +34 -0
- aip_agents/examples/hello_world_langchain_mcp_http_interactive.py +130 -0
- aip_agents/examples/hello_world_langchain_mcp_http_stream.py +42 -0
- aip_agents/examples/hello_world_langchain_mcp_multi_server.py +155 -0
- aip_agents/examples/hello_world_langchain_mcp_sse.py +34 -0
- aip_agents/examples/hello_world_langchain_mcp_sse_stream.py +40 -0
- aip_agents/examples/hello_world_langchain_mcp_stdio.py +30 -0
- aip_agents/examples/hello_world_langchain_mcp_stdio_stream.py +41 -0
- aip_agents/examples/hello_world_langchain_stream.py +36 -0
- aip_agents/examples/hello_world_langchain_stream_lm_invoker.py +39 -0
- aip_agents/examples/hello_world_langflow_agent.py +163 -0
- aip_agents/examples/hello_world_langgraph.py +39 -0
- aip_agents/examples/hello_world_langgraph_gl_connector_twitter.py +44 -0
- aip_agents/examples/hello_world_langgraph_mcp_http.py +31 -0
- aip_agents/examples/hello_world_langgraph_mcp_http_stream.py +34 -0
- aip_agents/examples/hello_world_langgraph_mcp_sse.py +35 -0
- aip_agents/examples/hello_world_langgraph_mcp_sse_stream.py +50 -0
- aip_agents/examples/hello_world_langgraph_mcp_stdio.py +35 -0
- aip_agents/examples/hello_world_langgraph_mcp_stdio_stream.py +50 -0
- aip_agents/examples/hello_world_langgraph_skills.py +62 -0
- aip_agents/examples/hello_world_langgraph_stream.py +43 -0
- aip_agents/examples/hello_world_langgraph_stream_lm_invoker.py +37 -0
- aip_agents/examples/hello_world_model_switch_cli.py +210 -0
- aip_agents/examples/hello_world_multi_agent_adk.py +75 -0
- aip_agents/examples/hello_world_multi_agent_langchain.py +54 -0
- aip_agents/examples/hello_world_multi_agent_langgraph.py +66 -0
- aip_agents/examples/hello_world_multi_agent_langgraph_lm_invoker.py +69 -0
- aip_agents/examples/hello_world_multi_agent_tool_output_client.py +57 -0
- aip_agents/examples/hello_world_multi_agent_tool_output_server.py +131 -0
- aip_agents/examples/hello_world_pii_logger.py +21 -0
- aip_agents/examples/hello_world_ptc.py +49 -0
- aip_agents/examples/hello_world_ptc_custom_tools.py +83 -0
- aip_agents/examples/hello_world_sentry.py +133 -0
- aip_agents/examples/hello_world_step_limits.py +273 -0
- aip_agents/examples/hello_world_stock_a2a_server.py +100 -0
- aip_agents/examples/hello_world_tool_output_client.py +55 -0
- aip_agents/examples/hello_world_tool_output_server.py +113 -0
- aip_agents/examples/hitl_demo.py +724 -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_server.py +125 -0
- aip_agents/examples/pii_demo_multi_agent_client.py +80 -0
- aip_agents/examples/pii_demo_multi_agent_server.py +246 -0
- aip_agents/examples/todolist_planning_a2a_langchain_client.py +70 -0
- aip_agents/examples/todolist_planning_a2a_langgraph_server.py +87 -0
- aip_agents/examples/tools/__init__.py +27 -0
- aip_agents/examples/tools/adk_arithmetic_tools.py +36 -0
- aip_agents/examples/tools/adk_weather_tool.py +60 -0
- aip_agents/examples/tools/data_generator_tool.py +103 -0
- aip_agents/examples/tools/data_visualization_tool.py +312 -0
- aip_agents/examples/tools/image_artifact_tool.py +136 -0
- aip_agents/examples/tools/langchain_arithmetic_tools.py +26 -0
- aip_agents/examples/tools/langchain_currency_exchange_tool.py +88 -0
- aip_agents/examples/tools/langchain_graph_artifact_tool.py +172 -0
- aip_agents/examples/tools/langchain_weather_tool.py +48 -0
- aip_agents/examples/tools/langgraph_streaming_tool.py +130 -0
- aip_agents/examples/tools/mock_retrieval_tool.py +56 -0
- aip_agents/examples/tools/multiply_tool.py +43 -0
- aip_agents/examples/tools/pii_demo_tools.py +189 -0
- aip_agents/examples/tools/random_chart_tool.py +142 -0
- aip_agents/examples/tools/serper_tool.py +202 -0
- aip_agents/examples/tools/stock_tools.py +82 -0
- aip_agents/examples/tools/table_generator_tool.py +167 -0
- aip_agents/examples/tools/time_tool.py +82 -0
- aip_agents/examples/tools/weather_forecast_tool.py +38 -0
- aip_agents/guardrails/__init__.py +83 -0
- aip_agents/guardrails/engines/__init__.py +69 -0
- aip_agents/guardrails/engines/base.py +90 -0
- aip_agents/guardrails/engines/nemo.py +101 -0
- aip_agents/guardrails/engines/phrase_matcher.py +113 -0
- aip_agents/guardrails/exceptions.py +39 -0
- aip_agents/guardrails/manager.py +163 -0
- aip_agents/guardrails/middleware.py +199 -0
- aip_agents/guardrails/schemas.py +63 -0
- aip_agents/guardrails/utils.py +45 -0
- aip_agents/integration/__init__.py +43 -0
- aip_agents/integration/agent.py +58 -0
- aip_agents/integration/guardrails.py +52 -0
- aip_agents/integration/hitl.py +71 -0
- aip_agents/integration/ptc.py +95 -0
- aip_agents/integration/skills.py +37 -0
- aip_agents/integration/storage.py +81 -0
- aip_agents/integration/version.py +103 -0
- aip_agents/mcp/__init__.py +1 -0
- aip_agents/mcp/client/__init__.py +60 -0
- aip_agents/mcp/client/base_mcp_client.py +377 -0
- aip_agents/mcp/client/connection_manager.py +231 -0
- aip_agents/mcp/client/errors.py +119 -0
- aip_agents/mcp/client/google_adk/__init__.py +45 -0
- aip_agents/mcp/client/google_adk/client.py +383 -0
- aip_agents/mcp/client/langchain/__init__.py +11 -0
- aip_agents/mcp/client/langchain/client.py +265 -0
- aip_agents/mcp/client/persistent_session.py +704 -0
- aip_agents/mcp/client/session_pool.py +358 -0
- aip_agents/mcp/client/transports.py +288 -0
- aip_agents/mcp/utils/__init__.py +7 -0
- aip_agents/mcp/utils/config_validator.py +139 -0
- aip_agents/memory/__init__.py +14 -0
- aip_agents/memory/adapters/__init__.py +10 -0
- aip_agents/memory/adapters/base_adapter.py +815 -0
- aip_agents/memory/adapters/mem0.py +286 -0
- aip_agents/memory/base.py +84 -0
- aip_agents/memory/constants.py +49 -0
- aip_agents/memory/factory.py +86 -0
- aip_agents/memory/guidance.py +20 -0
- aip_agents/memory/simple_memory.py +47 -0
- aip_agents/middleware/__init__.py +65 -0
- aip_agents/middleware/backends/__init__.py +72 -0
- aip_agents/middleware/backends/in_memory.py +578 -0
- aip_agents/middleware/backends/local_disk.py +1203 -0
- aip_agents/middleware/backends/protocol.py +353 -0
- aip_agents/middleware/backends/sandbox.py +1431 -0
- aip_agents/middleware/backends/sandbox_files.py +113 -0
- aip_agents/middleware/backends/utils.py +293 -0
- aip_agents/middleware/base.py +239 -0
- aip_agents/middleware/filesystem.py +690 -0
- aip_agents/middleware/manager.py +291 -0
- aip_agents/middleware/memory.py +532 -0
- aip_agents/middleware/pii_middleware.py +192 -0
- aip_agents/middleware/schema.py +19 -0
- aip_agents/middleware/skills.py +872 -0
- aip_agents/middleware/task_delegation.py +1656 -0
- aip_agents/middleware/todolist.py +276 -0
- aip_agents/middleware/tools/__init__.py +23 -0
- aip_agents/middleware/tools/edit_file.py +70 -0
- aip_agents/middleware/tools/execute.py +428 -0
- aip_agents/middleware/tools/grep_file.py +79 -0
- aip_agents/middleware/tools/ls.py +71 -0
- aip_agents/middleware/tools/read_file.py +239 -0
- aip_agents/middleware/tools/skill_load.py +193 -0
- aip_agents/middleware/tools/skill_resource.py +338 -0
- aip_agents/middleware/tools/write_file.py +114 -0
- aip_agents/middleware/vision.py +322 -0
- aip_agents/ptc/__init__.py +87 -0
- aip_agents/ptc/custom_tools.py +511 -0
- aip_agents/ptc/custom_tools_payload.py +499 -0
- aip_agents/ptc/custom_tools_templates/__init__.py +1 -0
- aip_agents/ptc/custom_tools_templates/custom_build_function.py.template +24 -0
- aip_agents/ptc/custom_tools_templates/custom_init.py.template +26 -0
- aip_agents/ptc/custom_tools_templates/custom_invoke.py.template +149 -0
- aip_agents/ptc/custom_tools_templates/custom_registry.py.template +112 -0
- aip_agents/ptc/custom_tools_templates/custom_sources_init.py.template +7 -0
- aip_agents/ptc/custom_tools_templates/custom_wrapper.py.template +87 -0
- aip_agents/ptc/doc_gen.py +122 -0
- aip_agents/ptc/exceptions.py +57 -0
- aip_agents/ptc/executor.py +627 -0
- aip_agents/ptc/mcp/__init__.py +45 -0
- aip_agents/ptc/mcp/sandbox_bridge.py +679 -0
- aip_agents/ptc/mcp/templates/__init__.py +1 -0
- aip_agents/ptc/mcp/templates/mcp_client.py.template +240 -0
- aip_agents/ptc/naming.py +430 -0
- aip_agents/ptc/payload.py +26 -0
- aip_agents/ptc/prompt_builder.py +674 -0
- aip_agents/ptc/ptc_helper.py +16 -0
- aip_agents/ptc/sandbox_bridge.py +297 -0
- aip_agents/ptc/template_utils.py +33 -0
- aip_agents/ptc/templates/__init__.py +1 -0
- aip_agents/ptc/templates/ptc_helper.py.template +134 -0
- aip_agents/ptc/tool_def_helpers.py +101 -0
- aip_agents/ptc/tool_enrichment.py +163 -0
- aip_agents/resilience/__init__.py +10 -0
- aip_agents/resilience/base.py +46 -0
- aip_agents/resilience/tool.py +1661 -0
- aip_agents/sandbox/__init__.py +62 -0
- aip_agents/sandbox/defaults.py +220 -0
- aip_agents/sandbox/dockerfiles/aip-agents-sandbox-v2-1-datasaur.Dockerfile +120 -0
- aip_agents/sandbox/dockerfiles/aip-agents-sandbox-v2-1.Dockerfile +100 -0
- aip_agents/sandbox/dockerfiles/aip-agents-sandbox-v2-2-datasaur.Dockerfile +143 -0
- aip_agents/sandbox/dockerfiles/aip-agents-sandbox-v2-2.Dockerfile +119 -0
- aip_agents/sandbox/dockerfiles/aip-agents-sandbox-v2-3-datasaur.Dockerfile +173 -0
- aip_agents/sandbox/dockerfiles/aip-agents-sandbox-v2-3.Dockerfile +130 -0
- aip_agents/sandbox/dockerfiles/aip-agents-sandbox-v2-4-runner-managed.Dockerfile +164 -0
- aip_agents/sandbox/dockerfiles/aip-agents-sandbox-v2-4-runner-managed.patch_js_context.py +41 -0
- aip_agents/sandbox/dockerfiles/aip-agents-sandbox-v2-4-runner-managed.requirements.txt +29 -0
- aip_agents/sandbox/dockerfiles/aip-agents-sandbox-v2.Dockerfile +87 -0
- aip_agents/sandbox/e2b_runtime.py +27 -0
- aip_agents/sandbox/image_registry.py +98 -0
- aip_agents/sandbox/providers/__init__.py +76 -0
- aip_agents/sandbox/providers/base.py +392 -0
- aip_agents/sandbox/providers/bedrock.py +28 -0
- aip_agents/sandbox/providers/e2b.py +230 -0
- aip_agents/sandbox/providers/opensandbox.py +163 -0
- aip_agents/sandbox/sandbox_runtime.py +967 -0
- aip_agents/sandbox/template_builder.py +240 -0
- aip_agents/sandbox/types.py +141 -0
- aip_agents/sandbox/validation.py +50 -0
- aip_agents/schema/__init__.py +106 -0
- aip_agents/schema/a2a.py +58 -0
- aip_agents/schema/agent.py +117 -0
- aip_agents/schema/artifacts.py +75 -0
- aip_agents/schema/attachments.py +425 -0
- aip_agents/schema/hitl.py +157 -0
- aip_agents/schema/langgraph.py +47 -0
- aip_agents/schema/model_id.py +103 -0
- aip_agents/schema/model_usage.py +50 -0
- aip_agents/schema/runtime_metadata.py +78 -0
- aip_agents/schema/step_limit.py +108 -0
- aip_agents/schema/storage.py +40 -0
- aip_agents/schema/tool_payloads.py +68 -0
- aip_agents/sentry/__init__.py +11 -0
- aip_agents/sentry/sentry.py +267 -0
- aip_agents/skills/__init__.py +30 -0
- aip_agents/skills/errors.py +110 -0
- aip_agents/skills/installer.py +479 -0
- aip_agents/skills/models.py +769 -0
- aip_agents/skills/stager.py +224 -0
- aip_agents/skills/validation.py +53 -0
- aip_agents/storage/__init__.py +41 -0
- aip_agents/storage/base.py +85 -0
- aip_agents/storage/clients/__init__.py +12 -0
- aip_agents/storage/clients/minio_client.py +318 -0
- aip_agents/storage/config.py +62 -0
- aip_agents/storage/providers/__init__.py +15 -0
- aip_agents/storage/providers/base.py +106 -0
- aip_agents/storage/providers/memory.py +114 -0
- aip_agents/storage/providers/object_storage.py +214 -0
- aip_agents/tools/__init__.py +65 -0
- aip_agents/tools/agent_schedule_tool.py +392 -0
- aip_agents/tools/browser_use/__init__.py +83 -0
- aip_agents/tools/browser_use/action_parser.py +104 -0
- aip_agents/tools/browser_use/browser_use_tool.py +1118 -0
- aip_agents/tools/browser_use/llm_config.py +120 -0
- aip_agents/tools/browser_use/minio_storage.py +203 -0
- aip_agents/tools/browser_use/schemas.py +121 -0
- aip_agents/tools/browser_use/session.py +13 -0
- aip_agents/tools/browser_use/session_errors.py +132 -0
- aip_agents/tools/browser_use/steel_session_recording.py +321 -0
- aip_agents/tools/browser_use/streaming.py +263 -0
- aip_agents/tools/browser_use/structured_data_parser.py +257 -0
- aip_agents/tools/browser_use/structured_data_recovery.py +204 -0
- aip_agents/tools/browser_use/types.py +37 -0
- aip_agents/tools/code_sandbox/__init__.py +48 -0
- aip_agents/tools/code_sandbox/code_sandbox_tool.py +350 -0
- aip_agents/tools/code_sandbox/constant.py +13 -0
- aip_agents/tools/code_sandbox/e2b_cloud_sandbox_extended.py +346 -0
- aip_agents/tools/code_sandbox/e2b_sandbox_tool.py +65 -0
- aip_agents/tools/computer_use/__init__.py +75 -0
- aip_agents/tools/computer_use/computer_use_tool.py +910 -0
- aip_agents/tools/computer_use/schemas.py +78 -0
- aip_agents/tools/computer_use/streaming.py +198 -0
- aip_agents/tools/computer_use/types.py +32 -0
- aip_agents/tools/constants.py +177 -0
- aip_agents/tools/date_range_tool.py +554 -0
- aip_agents/tools/document_loader/__init__.py +44 -0
- aip_agents/tools/document_loader/base_reader.py +302 -0
- aip_agents/tools/document_loader/docx_reader_tool.py +68 -0
- aip_agents/tools/document_loader/excel_reader_tool.py +171 -0
- aip_agents/tools/document_loader/pdf_reader_tool.py +79 -0
- aip_agents/tools/document_loader/pdf_splitter.py +169 -0
- aip_agents/tools/execute_ptc_code.py +582 -0
- aip_agents/tools/gl_connector/__init__.py +5 -0
- aip_agents/tools/gl_connector/tool.py +518 -0
- aip_agents/tools/gl_connector_tools.py +170 -0
- aip_agents/tools/memory_search/__init__.py +29 -0
- aip_agents/tools/memory_search/base.py +213 -0
- aip_agents/tools/memory_search/mem0.py +424 -0
- aip_agents/tools/memory_search/schema.py +81 -0
- aip_agents/tools/memory_search_tool.py +34 -0
- aip_agents/tools/streaming_common.py +577 -0
- aip_agents/tools/time_tool.py +117 -0
- aip_agents/tools/tool_config_injector.py +300 -0
- aip_agents/tools/web_search/__init__.py +15 -0
- aip_agents/tools/web_search/serper_tool.py +187 -0
- aip_agents/types/__init__.py +73 -0
- aip_agents/types/a2a_events.py +13 -0
- aip_agents/utils/__init__.py +91 -0
- aip_agents/utils/a2a_connector.py +1758 -0
- aip_agents/utils/artifact_helpers.py +542 -0
- aip_agents/utils/artifacts/__init__.py +20 -0
- aip_agents/utils/artifacts/tracker.py +367 -0
- aip_agents/utils/attachment_helpers.py +178 -0
- aip_agents/utils/constants.py +22 -0
- aip_agents/utils/datetime/__init__.py +34 -0
- aip_agents/utils/datetime/normalization.py +231 -0
- aip_agents/utils/datetime/timezone.py +206 -0
- aip_agents/utils/env_loader.py +27 -0
- aip_agents/utils/event_handler_registry.py +58 -0
- aip_agents/utils/file_prompt_utils.py +276 -0
- aip_agents/utils/file_watchers/__init__.py +33 -0
- aip_agents/utils/file_watchers/base.py +46 -0
- aip_agents/utils/file_watchers/e2b.py +128 -0
- aip_agents/utils/file_watchers/factory.py +39 -0
- aip_agents/utils/file_watchers/ls_diff.py +88 -0
- aip_agents/utils/file_watchers/sandbox.py +66 -0
- aip_agents/utils/file_watchers/watchdog.py +97 -0
- aip_agents/utils/final_response_builder.py +211 -0
- aip_agents/utils/formatter_llm_client.py +258 -0
- aip_agents/utils/langgraph/__init__.py +19 -0
- aip_agents/utils/langgraph/converter.py +399 -0
- aip_agents/utils/langgraph/delegation_context.py +22 -0
- aip_agents/utils/langgraph/tool_managers/__init__.py +15 -0
- aip_agents/utils/langgraph/tool_managers/a2a_tool_manager.py +99 -0
- aip_agents/utils/langgraph/tool_managers/base_tool_manager.py +66 -0
- aip_agents/utils/langgraph/tool_managers/delegation_tool_manager.py +1329 -0
- aip_agents/utils/langgraph/tool_output_management.py +1047 -0
- aip_agents/utils/logger.py +195 -0
- aip_agents/utils/metadata/__init__.py +27 -0
- aip_agents/utils/metadata/activity_metadata_helper.py +407 -0
- aip_agents/utils/metadata/activity_narrative/__init__.py +35 -0
- aip_agents/utils/metadata/activity_narrative/builder.py +822 -0
- aip_agents/utils/metadata/activity_narrative/constants.py +51 -0
- aip_agents/utils/metadata/activity_narrative/context.py +49 -0
- aip_agents/utils/metadata/activity_narrative/formatters.py +230 -0
- aip_agents/utils/metadata/activity_narrative/utils.py +35 -0
- aip_agents/utils/metadata/schemas/__init__.py +16 -0
- aip_agents/utils/metadata/schemas/activity_schema.py +29 -0
- aip_agents/utils/metadata/schemas/thinking_schema.py +31 -0
- aip_agents/utils/metadata/thinking_metadata_helper.py +38 -0
- aip_agents/utils/metadata_helper.py +363 -0
- aip_agents/utils/name_preprocessor/__init__.py +17 -0
- aip_agents/utils/name_preprocessor/base_name_preprocessor.py +73 -0
- aip_agents/utils/name_preprocessor/google_name_preprocessor.py +100 -0
- aip_agents/utils/name_preprocessor/name_preprocessor.py +87 -0
- aip_agents/utils/name_preprocessor/openai_name_preprocessor.py +48 -0
- aip_agents/utils/pii/__init__.py +29 -0
- aip_agents/utils/pii/pii_handler.py +555 -0
- aip_agents/utils/pii/pii_helper.py +225 -0
- aip_agents/utils/pii/uuid_deanonymizer_mapping.py +195 -0
- aip_agents/utils/reference_helper.py +273 -0
- aip_agents/utils/sse_chunk_transformer.py +836 -0
- aip_agents/utils/step_limit_manager.py +265 -0
- aip_agents/utils/token_usage_helper.py +531 -0
- aip_agents_binary-0.0.0.dist-info/METADATA +825 -0
- aip_agents_binary-0.0.0.dist-info/RECORD +447 -0
- aip_agents_binary-0.0.0.dist-info/WHEEL +5 -0
- aip_agents_binary-0.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
"""Steel session recording helper built on Steel's HLS exports.
|
|
2
|
+
|
|
3
|
+
This module downloads Steel session HLS manifests, merges the associated
|
|
4
|
+
segments into a single MP4 file, and uploads the result to MinIO storage.
|
|
5
|
+
It replaces the earlier rrweb + Playwright conversion pipeline.
|
|
6
|
+
|
|
7
|
+
Authors:
|
|
8
|
+
Reinhart Linanda (reinhart.linanda@gdplabs.id)
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
import asyncio
|
|
12
|
+
import re
|
|
13
|
+
import shutil
|
|
14
|
+
import tempfile
|
|
15
|
+
import time
|
|
16
|
+
from io import BufferedWriter
|
|
17
|
+
from pathlib import Path
|
|
18
|
+
from urllib.parse import quote, urljoin
|
|
19
|
+
|
|
20
|
+
import requests
|
|
21
|
+
from dotenv import load_dotenv
|
|
22
|
+
|
|
23
|
+
from aip_agents.tools.browser_use.minio_storage import MinIOStorage
|
|
24
|
+
from aip_agents.utils.logger import get_logger
|
|
25
|
+
|
|
26
|
+
load_dotenv()
|
|
27
|
+
|
|
28
|
+
logger = get_logger(__name__)
|
|
29
|
+
|
|
30
|
+
VIDEO_FILE_NAME_PREFIX = "session_"
|
|
31
|
+
MANIFEST_TEMP_SUFFIX = ".m3u8"
|
|
32
|
+
STEEL_SESSION_ID_PATTERN = re.compile(r"^[A-Za-z0-9_-]+$")
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class SteelSessionRecorder:
|
|
36
|
+
"""High-level helper to export Steel sessions via their HLS manifests.
|
|
37
|
+
|
|
38
|
+
This class provides a high-level interface for exporting Steel sessions via their HLS manifests.
|
|
39
|
+
It provides methods for sanitizing session IDs, building safe filenames, and generating video filenames.
|
|
40
|
+
It also provides methods for downloading and merging HLS manifests, and uploading videos to MinIO.
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
@staticmethod
|
|
44
|
+
def safe_session_id(session_id: str) -> str:
|
|
45
|
+
"""Sanitize a session ID for filename usage.
|
|
46
|
+
|
|
47
|
+
Args:
|
|
48
|
+
session_id: The session ID to sanitize.
|
|
49
|
+
|
|
50
|
+
Returns:
|
|
51
|
+
str: The sanitized session ID.
|
|
52
|
+
"""
|
|
53
|
+
return "".join(c for c in session_id if c.isalnum() or c in ("-", "_"))
|
|
54
|
+
|
|
55
|
+
@staticmethod
|
|
56
|
+
def safe_session_filename(session_id: str, extension: str) -> str:
|
|
57
|
+
"""Build a safe filename for a session recording.
|
|
58
|
+
|
|
59
|
+
Args:
|
|
60
|
+
session_id: The session ID to build a filename for.
|
|
61
|
+
extension: The extension of the filename.
|
|
62
|
+
|
|
63
|
+
Returns:
|
|
64
|
+
str: The safe filename.
|
|
65
|
+
"""
|
|
66
|
+
safe_id = SteelSessionRecorder.safe_session_id(session_id)
|
|
67
|
+
return f"{VIDEO_FILE_NAME_PREFIX}{safe_id}{extension}"
|
|
68
|
+
|
|
69
|
+
@staticmethod
|
|
70
|
+
def generate_video_filename(session_id: str, extension: str = ".mp4") -> str:
|
|
71
|
+
"""Generate a filename for a session recording.
|
|
72
|
+
|
|
73
|
+
Args:
|
|
74
|
+
session_id: The session ID to generate a filename for.
|
|
75
|
+
extension: The extension of the filename.
|
|
76
|
+
|
|
77
|
+
Returns:
|
|
78
|
+
str: The generated filename.
|
|
79
|
+
"""
|
|
80
|
+
normalized_extension = extension if extension.startswith(".") else f".{extension}"
|
|
81
|
+
return SteelSessionRecorder.safe_session_filename(session_id, normalized_extension)
|
|
82
|
+
|
|
83
|
+
@staticmethod
|
|
84
|
+
def _parse_manifest_entries(manifest_text: str, manifest_url: str) -> tuple[str | None, list[str]]:
|
|
85
|
+
"""Parse manifest lines into init segment and media segment URLs.
|
|
86
|
+
|
|
87
|
+
Args:
|
|
88
|
+
manifest_text: The text of the manifest.
|
|
89
|
+
manifest_url: The URL of the manifest.
|
|
90
|
+
|
|
91
|
+
Returns:
|
|
92
|
+
tuple[str | None, list[str]]: The init segment URL and the list of media segment URLs.
|
|
93
|
+
"""
|
|
94
|
+
init_url = None
|
|
95
|
+
segments: list[str] = []
|
|
96
|
+
|
|
97
|
+
for line in manifest_text.splitlines():
|
|
98
|
+
line = line.strip()
|
|
99
|
+
if not line:
|
|
100
|
+
continue
|
|
101
|
+
|
|
102
|
+
if not line.startswith("#"):
|
|
103
|
+
segments.append(urljoin(manifest_url, line))
|
|
104
|
+
continue
|
|
105
|
+
|
|
106
|
+
if line.startswith("#EXT-X-MAP"):
|
|
107
|
+
match = re.search(r'URI="([^"]+)"', line)
|
|
108
|
+
if match:
|
|
109
|
+
init_url = match.group(1)
|
|
110
|
+
|
|
111
|
+
if init_url:
|
|
112
|
+
init_url = urljoin(manifest_url, init_url)
|
|
113
|
+
|
|
114
|
+
return init_url, segments
|
|
115
|
+
|
|
116
|
+
@staticmethod
|
|
117
|
+
def _stream_url(session: requests.Session, url: str, headers: dict[str, str], output_file: BufferedWriter) -> None:
|
|
118
|
+
"""Stream data from a URL into a buffered writer.
|
|
119
|
+
|
|
120
|
+
Args:
|
|
121
|
+
session: The requests session to use.
|
|
122
|
+
url: The URL to stream from.
|
|
123
|
+
headers: The headers to use.
|
|
124
|
+
output_file: The buffered writer to write the data to.
|
|
125
|
+
"""
|
|
126
|
+
with session.get(url, headers=headers, stream=True, timeout=120) as resp:
|
|
127
|
+
resp.raise_for_status()
|
|
128
|
+
|
|
129
|
+
# Validate content type
|
|
130
|
+
content_type = resp.headers.get("content-type", "")
|
|
131
|
+
if not content_type.startswith(("video/", "application/octet-stream")):
|
|
132
|
+
logger.warning("Unexpected content type: %s", content_type)
|
|
133
|
+
return
|
|
134
|
+
|
|
135
|
+
for chunk in resp.iter_content(chunk_size=64 * 1024):
|
|
136
|
+
if chunk:
|
|
137
|
+
output_file.write(chunk)
|
|
138
|
+
|
|
139
|
+
@staticmethod
|
|
140
|
+
def _cleanup_temp_directory(video_dir: str) -> None:
|
|
141
|
+
"""Clean up the temporary directory.
|
|
142
|
+
|
|
143
|
+
Args:
|
|
144
|
+
video_dir: The directory to clean up.
|
|
145
|
+
"""
|
|
146
|
+
try:
|
|
147
|
+
shutil.rmtree(video_dir)
|
|
148
|
+
except OSError:
|
|
149
|
+
pass
|
|
150
|
+
|
|
151
|
+
def __init__(self, base_url: str, api_key: str):
|
|
152
|
+
"""Initialize the recorder.
|
|
153
|
+
|
|
154
|
+
Args:
|
|
155
|
+
base_url: Steel API base URL.
|
|
156
|
+
api_key: Steel API key for authentication.
|
|
157
|
+
"""
|
|
158
|
+
self.base_url = base_url
|
|
159
|
+
self.api_key = api_key
|
|
160
|
+
|
|
161
|
+
self._manifest_poll_timeout_minutes = 1
|
|
162
|
+
self._manifest_poll_interval_seconds = 2
|
|
163
|
+
|
|
164
|
+
try:
|
|
165
|
+
self.minio_storage = MinIOStorage()
|
|
166
|
+
except Exception as exc:
|
|
167
|
+
logger.warning("Failed to initialize MinIO storage: %s", exc)
|
|
168
|
+
self.minio_storage = None
|
|
169
|
+
|
|
170
|
+
def _download_manifest(self, session_id: str, dest: Path) -> str | None:
|
|
171
|
+
"""Download the Steel HLS manifest for a session.
|
|
172
|
+
|
|
173
|
+
Args:
|
|
174
|
+
session_id: The session ID to download the manifest for.
|
|
175
|
+
dest: The destination path to save the manifest to.
|
|
176
|
+
|
|
177
|
+
Returns:
|
|
178
|
+
str | None: The URL of the manifest, or None if the base URL or API key is not set.
|
|
179
|
+
|
|
180
|
+
Raises:
|
|
181
|
+
requests.exceptions.RequestException: If the manifest is not ready after the timeout.
|
|
182
|
+
"""
|
|
183
|
+
if not self.base_url or not self.api_key:
|
|
184
|
+
logger.warning("Base URL or API key not set, skipping download for session %s", session_id)
|
|
185
|
+
return None
|
|
186
|
+
if not STEEL_SESSION_ID_PATTERN.fullmatch(session_id):
|
|
187
|
+
raise ValueError("Steel session ID contains unsupported characters")
|
|
188
|
+
|
|
189
|
+
session_path_segment = quote(session_id, safe="")
|
|
190
|
+
url = f"{self.base_url.rstrip('/')}/v1/sessions/{session_path_segment}/hls"
|
|
191
|
+
headers = {"steel-api-key": self.api_key}
|
|
192
|
+
|
|
193
|
+
deadline = time.monotonic() + (self._manifest_poll_timeout_minutes * 60)
|
|
194
|
+
attempt = 0
|
|
195
|
+
while True:
|
|
196
|
+
response = requests.get(url, headers=headers, timeout=60)
|
|
197
|
+
if response.ok:
|
|
198
|
+
dest.write_text(response.text)
|
|
199
|
+
return response.url
|
|
200
|
+
|
|
201
|
+
pollable = response.status_code in {404, 408, 429, 503}
|
|
202
|
+
attempt += 1
|
|
203
|
+
if not pollable or time.monotonic() >= deadline:
|
|
204
|
+
logger.warning(
|
|
205
|
+
"Manifest not ready for session %s after %.1f minutes, last status %d",
|
|
206
|
+
session_id,
|
|
207
|
+
self._manifest_poll_timeout_minutes,
|
|
208
|
+
response.status_code,
|
|
209
|
+
)
|
|
210
|
+
response.raise_for_status()
|
|
211
|
+
|
|
212
|
+
logger.debug(
|
|
213
|
+
"Manifest not ready for session %s (attempt %d, status %d); waiting %.1f seconds",
|
|
214
|
+
session_id,
|
|
215
|
+
attempt,
|
|
216
|
+
response.status_code,
|
|
217
|
+
self._manifest_poll_interval_seconds,
|
|
218
|
+
)
|
|
219
|
+
time.sleep(self._manifest_poll_interval_seconds)
|
|
220
|
+
|
|
221
|
+
def _merge_segments(self, manifest_path: Path, manifest_url: str, output_path: Path) -> bool:
|
|
222
|
+
"""Merge HLS segments defined in a manifest into a single video file.
|
|
223
|
+
|
|
224
|
+
Args:
|
|
225
|
+
manifest_path: The path to the manifest.
|
|
226
|
+
manifest_url: The URL of the manifest.
|
|
227
|
+
output_path: The path to save the merged video to.
|
|
228
|
+
|
|
229
|
+
Returns:
|
|
230
|
+
bool: True if the segments were merged successfully, False otherwise.
|
|
231
|
+
"""
|
|
232
|
+
if not self.api_key:
|
|
233
|
+
logger.warning("API key not set, skipping merge for session %s", manifest_url)
|
|
234
|
+
return False
|
|
235
|
+
|
|
236
|
+
headers = {"steel-api-key": self.api_key}
|
|
237
|
+
manifest_text = manifest_path.read_text()
|
|
238
|
+
init_url, segments = SteelSessionRecorder._parse_manifest_entries(manifest_text, manifest_url)
|
|
239
|
+
|
|
240
|
+
if not init_url or not segments:
|
|
241
|
+
logger.warning("No media segments found in manifest.")
|
|
242
|
+
return False
|
|
243
|
+
|
|
244
|
+
output_path.parent.mkdir(parents=True, exist_ok=True)
|
|
245
|
+
|
|
246
|
+
with requests.Session() as session, open(output_path, "wb") as output_file:
|
|
247
|
+
if init_url:
|
|
248
|
+
SteelSessionRecorder._stream_url(session, init_url, headers, output_file)
|
|
249
|
+
|
|
250
|
+
for segment_url in segments:
|
|
251
|
+
SteelSessionRecorder._stream_url(session, segment_url, headers, output_file)
|
|
252
|
+
|
|
253
|
+
return True
|
|
254
|
+
|
|
255
|
+
async def _download_and_merge_manifest(self, session_id: str, output_path: Path) -> bool:
|
|
256
|
+
"""Download and merge the Steel HLS manifest into a single file.
|
|
257
|
+
|
|
258
|
+
Args:
|
|
259
|
+
session_id: The session ID to download the manifest for.
|
|
260
|
+
output_path: The path to save the merged video to.
|
|
261
|
+
|
|
262
|
+
Returns:
|
|
263
|
+
bool: True if the manifest was downloaded and merged successfully, False otherwise.
|
|
264
|
+
"""
|
|
265
|
+
manifest_path = Path(tempfile.NamedTemporaryFile(suffix=MANIFEST_TEMP_SUFFIX, delete=False).name)
|
|
266
|
+
|
|
267
|
+
try:
|
|
268
|
+
manifest_url = await asyncio.to_thread(self._download_manifest, session_id, manifest_path)
|
|
269
|
+
if not manifest_url:
|
|
270
|
+
logger.warning("Failed to download manifest for session %s", session_id)
|
|
271
|
+
return False
|
|
272
|
+
|
|
273
|
+
merged = await asyncio.to_thread(self._merge_segments, manifest_path, manifest_url, output_path)
|
|
274
|
+
if not merged:
|
|
275
|
+
logger.warning("Failed to merge segments for session %s", session_id)
|
|
276
|
+
return False
|
|
277
|
+
|
|
278
|
+
return True
|
|
279
|
+
except Exception as exc:
|
|
280
|
+
logger.warning(
|
|
281
|
+
"Failed to generate video from HLS manifest for session %s: %s", session_id, exc, exc_info=True
|
|
282
|
+
)
|
|
283
|
+
return False
|
|
284
|
+
finally:
|
|
285
|
+
manifest_path.unlink(missing_ok=True)
|
|
286
|
+
|
|
287
|
+
async def _upload_video_to_minio(self, video_path: Path, video_filename: str) -> None:
|
|
288
|
+
"""Upload a video file to MinIO storage.
|
|
289
|
+
|
|
290
|
+
Args:
|
|
291
|
+
video_path: The path to the video file to upload.
|
|
292
|
+
video_filename: The filename of the video to upload.
|
|
293
|
+
"""
|
|
294
|
+
if not video_path.exists():
|
|
295
|
+
logger.warning("Video file not found: %s", video_path)
|
|
296
|
+
return
|
|
297
|
+
|
|
298
|
+
await asyncio.to_thread(self.minio_storage.upload_file, str(video_path), video_filename)
|
|
299
|
+
|
|
300
|
+
async def record_session_to_video(self, session_id: str) -> None:
|
|
301
|
+
"""Download the HLS manifest and upload the merged video to MinIO.
|
|
302
|
+
|
|
303
|
+
Args:
|
|
304
|
+
session_id: The session ID to record.
|
|
305
|
+
"""
|
|
306
|
+
if not self.minio_storage:
|
|
307
|
+
logger.warning("MinIO storage not available, skipping recording for %s", session_id)
|
|
308
|
+
return
|
|
309
|
+
|
|
310
|
+
video_dir = tempfile.mkdtemp()
|
|
311
|
+
try:
|
|
312
|
+
video_filename = SteelSessionRecorder.generate_video_filename(session_id, extension=".mp4")
|
|
313
|
+
output_path = Path(video_dir) / video_filename
|
|
314
|
+
merged = await self._download_and_merge_manifest(session_id, output_path)
|
|
315
|
+
if not merged:
|
|
316
|
+
logger.warning("Skipping upload because manifest merge failed for session %s", session_id)
|
|
317
|
+
return
|
|
318
|
+
|
|
319
|
+
await self._upload_video_to_minio(output_path, video_filename)
|
|
320
|
+
finally:
|
|
321
|
+
SteelSessionRecorder._cleanup_temp_directory(video_dir)
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
"""Helpers for assembling streaming responses emitted by the browser-use tool.
|
|
2
|
+
|
|
3
|
+
Tool-agnostic helpers are imported from ``aip_agents.tools.streaming_common`` and
|
|
4
|
+
re-exported here for backward compatibility; only browser-use-specific logic lives
|
|
5
|
+
in this module.
|
|
6
|
+
|
|
7
|
+
Authors:
|
|
8
|
+
Raymond Christopher (raymond.christopher@gdplabs.id)
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
from collections.abc import Callable, Iterable
|
|
14
|
+
from typing import Any
|
|
15
|
+
|
|
16
|
+
from browser_use import Agent
|
|
17
|
+
from browser_use.agent.views import ActionResult
|
|
18
|
+
|
|
19
|
+
from aip_agents.tools.browser_use.types import StreamingResponse, ToolCallInfo
|
|
20
|
+
from aip_agents.tools.streaming_common import (
|
|
21
|
+
PROCESSING_MESSAGE,
|
|
22
|
+
TASK_COMPLETED_MESSAGE,
|
|
23
|
+
THINKING_SUMMARY_SYSTEM_PROMPT,
|
|
24
|
+
_build_completion_activity_message,
|
|
25
|
+
_build_fallback_thinking_message,
|
|
26
|
+
_coerce_response_text,
|
|
27
|
+
_first_sentence,
|
|
28
|
+
_format_tool_context,
|
|
29
|
+
_format_tool_display_name,
|
|
30
|
+
_formatter_llm_client,
|
|
31
|
+
_summarize_final_detail,
|
|
32
|
+
_summarize_final_headline,
|
|
33
|
+
_summarize_tool_details,
|
|
34
|
+
_summarize_with_llm,
|
|
35
|
+
_tool_display_and_output,
|
|
36
|
+
build_running_step_response,
|
|
37
|
+
create_error_response,
|
|
38
|
+
generate_thinking_message,
|
|
39
|
+
yield_iframe_activity,
|
|
40
|
+
yield_status_message,
|
|
41
|
+
yield_thinking_marker,
|
|
42
|
+
)
|
|
43
|
+
from aip_agents.tools.streaming_common import _resolve_tool_name as _resolve_tool_name_shared
|
|
44
|
+
from aip_agents.types import A2AStreamEventType
|
|
45
|
+
from aip_agents.utils.logger import get_logger
|
|
46
|
+
from aip_agents.utils.metadata.activity_metadata_helper import _create_activity_info
|
|
47
|
+
from aip_agents.utils.metadata_helper import Kind, MetadataFieldKeys, Status
|
|
48
|
+
|
|
49
|
+
PRIMARY_TOOL_NAME = "browser_use_tool"
|
|
50
|
+
|
|
51
|
+
logger = get_logger(__name__)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def _resolve_tool_name(tool_info: dict[str, Any]) -> str:
|
|
55
|
+
"""Return the most specific tool name in ``tool_info``, defaulting to the browser-use tool.
|
|
56
|
+
|
|
57
|
+
Args:
|
|
58
|
+
tool_info: Metadata dictionary emitted by browser-use steps.
|
|
59
|
+
|
|
60
|
+
Returns:
|
|
61
|
+
str: Tool name suitable for display.
|
|
62
|
+
"""
|
|
63
|
+
return _resolve_tool_name_shared(tool_info, PRIMARY_TOOL_NAME)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def create_step_response(
|
|
67
|
+
agent: Agent,
|
|
68
|
+
tool_calls: list[ToolCallInfo],
|
|
69
|
+
is_done: bool,
|
|
70
|
+
content: str,
|
|
71
|
+
thinking_message: str | None,
|
|
72
|
+
) -> StreamingResponse:
|
|
73
|
+
"""Compose the per-step payload emitted during browser-use streaming.
|
|
74
|
+
|
|
75
|
+
Args:
|
|
76
|
+
agent: Browser-use agent producing the step output.
|
|
77
|
+
tool_calls: Tool call descriptors extracted from the step.
|
|
78
|
+
is_done: Flag indicating whether this is the final step in the run.
|
|
79
|
+
content: High-level status text describing the step progress.
|
|
80
|
+
thinking_message: Optional preformatted thinking summary to attach.
|
|
81
|
+
|
|
82
|
+
Returns:
|
|
83
|
+
StreamingResponse: Serialized payload for the current streaming step.
|
|
84
|
+
"""
|
|
85
|
+
tool_calls_dict = [{"name": tc.name, "args": tc.args, "output": tc.output} for tc in tool_calls]
|
|
86
|
+
|
|
87
|
+
if is_done:
|
|
88
|
+
final_tool = _get_done_tool_for_final_response(agent, tool_calls_dict)
|
|
89
|
+
final_output = final_tool.get("output") or TASK_COMPLETED_MESSAGE
|
|
90
|
+
if not any(call.get("name") == "done" for call in tool_calls_dict):
|
|
91
|
+
tool_calls_dict.append(final_tool)
|
|
92
|
+
tool_info = {
|
|
93
|
+
"name": PRIMARY_TOOL_NAME,
|
|
94
|
+
"args": final_tool.get("args", {}),
|
|
95
|
+
"output": final_output,
|
|
96
|
+
"execution_time": final_tool.get("execution_time"),
|
|
97
|
+
"tool_calls": tool_calls_dict,
|
|
98
|
+
}
|
|
99
|
+
completion_message = _build_completion_activity_message(tool_info, final_output, PRIMARY_TOOL_NAME)
|
|
100
|
+
logger.info(
|
|
101
|
+
"Browser-use completion message generated: headline=%r detail=%r",
|
|
102
|
+
completion_message.split("\n\n", 1)[0].strip("*"),
|
|
103
|
+
completion_message.split("\n\n", 1)[1] if "\n\n" in completion_message else "",
|
|
104
|
+
)
|
|
105
|
+
activity_info = _create_activity_info({"message": completion_message})
|
|
106
|
+
logger.debug("Browser-use completion activity info payload: %s", activity_info)
|
|
107
|
+
metadata = {
|
|
108
|
+
MetadataFieldKeys.KIND: Kind.FINAL_THINKING_STEP,
|
|
109
|
+
MetadataFieldKeys.STATUS: Status.FINISHED,
|
|
110
|
+
MetadataFieldKeys.TOOL_INFO: tool_info,
|
|
111
|
+
}
|
|
112
|
+
return StreamingResponse(
|
|
113
|
+
event_type=A2AStreamEventType.STATUS_UPDATE,
|
|
114
|
+
content=final_output,
|
|
115
|
+
thinking_and_activity_info=activity_info,
|
|
116
|
+
is_final=False,
|
|
117
|
+
tool_info=tool_info,
|
|
118
|
+
metadata=metadata,
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
return build_running_step_response(content, tool_calls_dict, thinking_message)
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def generate_step_content(tool_calls: list[ToolCallInfo], is_done: bool) -> str:
|
|
125
|
+
"""Return user-friendly status text derived from tool call outputs.
|
|
126
|
+
|
|
127
|
+
Args:
|
|
128
|
+
tool_calls: Tool call descriptors extracted from the step.
|
|
129
|
+
is_done: Flag indicating whether this is the final step in the run.
|
|
130
|
+
|
|
131
|
+
Returns:
|
|
132
|
+
User-friendly status text string.
|
|
133
|
+
"""
|
|
134
|
+
if not tool_calls:
|
|
135
|
+
return TASK_COMPLETED_MESSAGE if is_done else PROCESSING_MESSAGE
|
|
136
|
+
|
|
137
|
+
if is_done:
|
|
138
|
+
return TASK_COMPLETED_MESSAGE
|
|
139
|
+
|
|
140
|
+
return _get_progress_message_from_tool_calls(tool_calls)
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def _get_progress_message_from_tool_calls(tool_calls: list[ToolCallInfo]) -> str:
|
|
144
|
+
"""Generate progress message from tool calls.
|
|
145
|
+
|
|
146
|
+
Args:
|
|
147
|
+
tool_calls: List of tool calls to generate progress message from.
|
|
148
|
+
|
|
149
|
+
Returns:
|
|
150
|
+
str: Progress message string.
|
|
151
|
+
"""
|
|
152
|
+
tool_names = [tc.name for tc in tool_calls if tc.name]
|
|
153
|
+
if tool_names:
|
|
154
|
+
return f"Completed {', '.join(tool_names)}"
|
|
155
|
+
return PROCESSING_MESSAGE
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
def _get_done_tool_for_final_response(agent: Agent, tool_calls_dict: list[dict]) -> dict[str, Any]:
|
|
159
|
+
"""Find or create the 'done' tool for final response.
|
|
160
|
+
|
|
161
|
+
Args:
|
|
162
|
+
agent: The browser-use agent.
|
|
163
|
+
tool_calls_dict: List of tool call dictionaries.
|
|
164
|
+
|
|
165
|
+
Returns:
|
|
166
|
+
dict[str, Any]: The 'done' tool dictionary for final response.
|
|
167
|
+
"""
|
|
168
|
+
for tool_call in tool_calls_dict:
|
|
169
|
+
if tool_call.get("name") == "done":
|
|
170
|
+
return tool_call
|
|
171
|
+
|
|
172
|
+
final_response = _extract_final_response(agent.state.last_result)
|
|
173
|
+
extracted_content = ""
|
|
174
|
+
|
|
175
|
+
if final_response and final_response.get("extracted_content"):
|
|
176
|
+
extracted_content = final_response["extracted_content"]
|
|
177
|
+
elif tool_calls_dict:
|
|
178
|
+
extracted_content = tool_calls_dict[-1]["output"]
|
|
179
|
+
|
|
180
|
+
return {"name": "done", "args": {}, "output": extracted_content or TASK_COMPLETED_MESSAGE}
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
def _extract_final_response(last_result: Iterable[ActionResult] | None) -> dict[str, Any] | None:
|
|
184
|
+
"""Extract final response data from ActionResult when is_done=True.
|
|
185
|
+
|
|
186
|
+
Args:
|
|
187
|
+
last_result: Iterable of ActionResult objects from the agent's last operation.
|
|
188
|
+
|
|
189
|
+
Returns:
|
|
190
|
+
Dictionary containing serialized final response data, or ``None`` if no result found.
|
|
191
|
+
"""
|
|
192
|
+
results = list(last_result or [])
|
|
193
|
+
done_result = _first_matching_result(results, lambda item: getattr(item, "is_done", False))
|
|
194
|
+
if done_result:
|
|
195
|
+
return _serialize_action_result(done_result, bool(done_result.success))
|
|
196
|
+
|
|
197
|
+
extracted_result = _first_matching_result(reversed(results), lambda item: getattr(item, "extracted_content", ""))
|
|
198
|
+
if extracted_result:
|
|
199
|
+
return _serialize_action_result(extracted_result, True)
|
|
200
|
+
return None
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
def _first_matching_result(iterable: Iterable[Any], predicate: Callable[[Any], bool]) -> Any | None:
|
|
204
|
+
"""Return the first item in ``iterable`` that satisfies ``predicate``.
|
|
205
|
+
|
|
206
|
+
Args:
|
|
207
|
+
iterable: Sequence or generator of results.
|
|
208
|
+
predicate: Callable returning True for the desired item.
|
|
209
|
+
|
|
210
|
+
Returns:
|
|
211
|
+
Any | None: Matching item or None when not found.
|
|
212
|
+
"""
|
|
213
|
+
for item in iterable:
|
|
214
|
+
if predicate(item):
|
|
215
|
+
return item
|
|
216
|
+
return None
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
def _serialize_action_result(result: ActionResult, success: bool) -> dict[str, Any]:
|
|
220
|
+
"""Normalize an ``ActionResult`` to a dict for streaming responses.
|
|
221
|
+
|
|
222
|
+
Args:
|
|
223
|
+
result: ActionResult emitted by browser-use.
|
|
224
|
+
success: Whether the action is considered successful.
|
|
225
|
+
|
|
226
|
+
Returns:
|
|
227
|
+
dict[str, Any]: Structured payload capturing success/error information.
|
|
228
|
+
"""
|
|
229
|
+
return {
|
|
230
|
+
"success": success,
|
|
231
|
+
"extracted_content": getattr(result, "extracted_content", "") or "",
|
|
232
|
+
"error": getattr(result, "error", None),
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
__all__ = [
|
|
237
|
+
"PROCESSING_MESSAGE",
|
|
238
|
+
"TASK_COMPLETED_MESSAGE",
|
|
239
|
+
"THINKING_SUMMARY_SYSTEM_PROMPT",
|
|
240
|
+
"_build_completion_activity_message",
|
|
241
|
+
"_build_fallback_thinking_message",
|
|
242
|
+
"_coerce_response_text",
|
|
243
|
+
"_extract_final_response",
|
|
244
|
+
"_first_sentence",
|
|
245
|
+
"_formatter_llm_client",
|
|
246
|
+
"_format_tool_context",
|
|
247
|
+
"_format_tool_display_name",
|
|
248
|
+
"_get_done_tool_for_final_response",
|
|
249
|
+
"_get_progress_message_from_tool_calls",
|
|
250
|
+
"_resolve_tool_name",
|
|
251
|
+
"_summarize_final_detail",
|
|
252
|
+
"_summarize_final_headline",
|
|
253
|
+
"_summarize_tool_details",
|
|
254
|
+
"_summarize_with_llm",
|
|
255
|
+
"_tool_display_and_output",
|
|
256
|
+
"create_error_response",
|
|
257
|
+
"create_step_response",
|
|
258
|
+
"generate_step_content",
|
|
259
|
+
"generate_thinking_message",
|
|
260
|
+
"yield_iframe_activity",
|
|
261
|
+
"yield_status_message",
|
|
262
|
+
"yield_thinking_marker",
|
|
263
|
+
]
|