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,214 @@
|
|
|
1
|
+
"""Object storage provider implementation.
|
|
2
|
+
|
|
3
|
+
Authors:
|
|
4
|
+
Christian Trisno Sen Long Chen (christian.t.s.l.chen@gdplabs.id)
|
|
5
|
+
Fachriza Adhiatma (fachriza.d.adhiatma@gdplabs.id)
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import json
|
|
9
|
+
import pickle
|
|
10
|
+
from typing import Any
|
|
11
|
+
|
|
12
|
+
from aip_agents.storage.base import BaseObjectStorageClient
|
|
13
|
+
from aip_agents.storage.providers.base import BaseStorageProvider, StorageError
|
|
14
|
+
from aip_agents.utils.logger import get_logger
|
|
15
|
+
|
|
16
|
+
logger = get_logger(__name__)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class ObjectStorageProvider(BaseStorageProvider):
|
|
20
|
+
"""Object storage provider for S3-compatible storage.
|
|
21
|
+
|
|
22
|
+
Works with any S3-compatible storage including AWS S3, MinIO,
|
|
23
|
+
Google Cloud Storage (with S3 compatibility), etc.
|
|
24
|
+
|
|
25
|
+
Best for:
|
|
26
|
+
- Very large datasets
|
|
27
|
+
- Distributed systems
|
|
28
|
+
- Cloud deployments
|
|
29
|
+
- Long-term storage
|
|
30
|
+
- Multi-region access
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
def __init__(self, client: BaseObjectStorageClient, prefix: str = "", use_json: bool = False):
|
|
34
|
+
"""Initialize object storage provider.
|
|
35
|
+
|
|
36
|
+
Args:
|
|
37
|
+
client: Object storage client instance
|
|
38
|
+
prefix: Prefix for all keys (like a directory)
|
|
39
|
+
use_json: Use JSON format (True) or pickle (False)
|
|
40
|
+
"""
|
|
41
|
+
self.client = client
|
|
42
|
+
self.prefix = prefix.rstrip("/") + "/" if prefix else ""
|
|
43
|
+
self.use_json = use_json
|
|
44
|
+
|
|
45
|
+
def _get_object_key(self, key: str) -> str:
|
|
46
|
+
"""Get full object key with prefix.
|
|
47
|
+
|
|
48
|
+
Args:
|
|
49
|
+
key: Storage key
|
|
50
|
+
|
|
51
|
+
Returns:
|
|
52
|
+
Full object key with prefix
|
|
53
|
+
"""
|
|
54
|
+
return f"{self.prefix}{key}"
|
|
55
|
+
|
|
56
|
+
def _serialize_data(self, data: Any) -> bytes:
|
|
57
|
+
"""Serialize data to bytes.
|
|
58
|
+
|
|
59
|
+
Args:
|
|
60
|
+
data: Data to serialize
|
|
61
|
+
|
|
62
|
+
Returns:
|
|
63
|
+
Serialized data as bytes
|
|
64
|
+
|
|
65
|
+
Raises:
|
|
66
|
+
StorageError: If serialization fails
|
|
67
|
+
"""
|
|
68
|
+
try:
|
|
69
|
+
if self.use_json:
|
|
70
|
+
return json.dumps(data, default=str).encode("utf-8")
|
|
71
|
+
return pickle.dumps(data)
|
|
72
|
+
except Exception as e:
|
|
73
|
+
raise StorageError(f"Failed to serialize data: {e}") from e
|
|
74
|
+
|
|
75
|
+
def _deserialize_data(self, data_bytes: bytes) -> Any:
|
|
76
|
+
"""Deserialize data from bytes.
|
|
77
|
+
|
|
78
|
+
Args:
|
|
79
|
+
data_bytes: Serialized data
|
|
80
|
+
|
|
81
|
+
Returns:
|
|
82
|
+
Deserialized data
|
|
83
|
+
|
|
84
|
+
Raises:
|
|
85
|
+
StorageError: If deserialization fails
|
|
86
|
+
"""
|
|
87
|
+
try:
|
|
88
|
+
if self.use_json:
|
|
89
|
+
return json.loads(data_bytes.decode("utf-8"))
|
|
90
|
+
return pickle.loads(data_bytes)
|
|
91
|
+
except Exception as e:
|
|
92
|
+
raise StorageError(f"Failed to deserialize data: {e}") from e
|
|
93
|
+
|
|
94
|
+
def store(self, key: str, data: Any) -> None:
|
|
95
|
+
"""Store data in object storage.
|
|
96
|
+
|
|
97
|
+
Args:
|
|
98
|
+
key: Unique identifier for the data
|
|
99
|
+
data: Data to store
|
|
100
|
+
|
|
101
|
+
Raises:
|
|
102
|
+
StorageError: If storage operation fails
|
|
103
|
+
"""
|
|
104
|
+
object_key = self._get_object_key(key)
|
|
105
|
+
|
|
106
|
+
try:
|
|
107
|
+
data_bytes = self._serialize_data(data)
|
|
108
|
+
|
|
109
|
+
self.client.upload(
|
|
110
|
+
object_key=object_key,
|
|
111
|
+
file_stream=data_bytes,
|
|
112
|
+
content_type="application/json" if self.use_json else "application/octet-stream",
|
|
113
|
+
metadata={"storage_key": key, "format": "json" if self.use_json else "pickle"},
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
logger.debug(f"Stored data to object storage: {object_key}")
|
|
117
|
+
|
|
118
|
+
except Exception as e:
|
|
119
|
+
raise StorageError(f"Failed to store data in object storage: {e}") from e
|
|
120
|
+
|
|
121
|
+
def retrieve(self, key: str) -> Any:
|
|
122
|
+
"""Retrieve data from object storage.
|
|
123
|
+
|
|
124
|
+
Args:
|
|
125
|
+
key: Unique identifier for the data
|
|
126
|
+
|
|
127
|
+
Returns:
|
|
128
|
+
The stored data
|
|
129
|
+
|
|
130
|
+
Raises:
|
|
131
|
+
KeyError: If key not found
|
|
132
|
+
StorageError: If retrieval operation fails
|
|
133
|
+
"""
|
|
134
|
+
object_key = self._get_object_key(key)
|
|
135
|
+
|
|
136
|
+
try:
|
|
137
|
+
data_bytes = self.client.get(object_key)
|
|
138
|
+
return self._deserialize_data(data_bytes)
|
|
139
|
+
|
|
140
|
+
except KeyError as e:
|
|
141
|
+
raise KeyError(f"Key '{key}' not found in object storage: {e}") from e
|
|
142
|
+
except Exception as e:
|
|
143
|
+
raise StorageError(f"Failed to retrieve data from object storage: {e}") from e
|
|
144
|
+
|
|
145
|
+
def exists(self, key: str) -> bool:
|
|
146
|
+
"""Check if object exists.
|
|
147
|
+
|
|
148
|
+
Args:
|
|
149
|
+
key: Unique identifier to check
|
|
150
|
+
|
|
151
|
+
Returns:
|
|
152
|
+
True if key exists, False otherwise
|
|
153
|
+
"""
|
|
154
|
+
object_key = self._get_object_key(key)
|
|
155
|
+
|
|
156
|
+
try:
|
|
157
|
+
return self.client.object_exists(object_key)
|
|
158
|
+
except Exception as e:
|
|
159
|
+
logger.warning(f"Failed to check object existence: {e}")
|
|
160
|
+
return False
|
|
161
|
+
|
|
162
|
+
def delete(self, key: str) -> None:
|
|
163
|
+
"""Delete object.
|
|
164
|
+
|
|
165
|
+
Args:
|
|
166
|
+
key: Unique identifier for the data
|
|
167
|
+
"""
|
|
168
|
+
object_key = self._get_object_key(key)
|
|
169
|
+
|
|
170
|
+
try:
|
|
171
|
+
self.client.delete(object_key)
|
|
172
|
+
logger.debug(f"Deleted object: {object_key}")
|
|
173
|
+
except Exception as e:
|
|
174
|
+
logger.warning(f"Failed to delete object {object_key}: {e}")
|
|
175
|
+
|
|
176
|
+
def list_keys(self, prefix: str = "") -> list[str]:
|
|
177
|
+
"""List all keys with optional prefix.
|
|
178
|
+
|
|
179
|
+
Args:
|
|
180
|
+
prefix: Optional prefix to filter keys
|
|
181
|
+
|
|
182
|
+
Raises:
|
|
183
|
+
NotImplementedError: list_keys is not implemented
|
|
184
|
+
"""
|
|
185
|
+
raise NotImplementedError("list_keys not yet implemented for object storage")
|
|
186
|
+
|
|
187
|
+
def clear(self) -> None:
|
|
188
|
+
"""Clear all objects with the configured prefix.
|
|
189
|
+
|
|
190
|
+
Warning:
|
|
191
|
+
This is a dangerous operation!
|
|
192
|
+
"""
|
|
193
|
+
logger.warning("clear() not implemented for object storage - too dangerous")
|
|
194
|
+
raise NotImplementedError("Batch clear not implemented for safety reasons")
|
|
195
|
+
|
|
196
|
+
def get_presigned_url(self, key: str, expires_hours: int = 24) -> str | None:
|
|
197
|
+
"""Generate presigned URL for direct access.
|
|
198
|
+
|
|
199
|
+
Args:
|
|
200
|
+
key: Storage key
|
|
201
|
+
expires_hours: URL expiration in hours
|
|
202
|
+
|
|
203
|
+
Returns:
|
|
204
|
+
Presigned URL for direct access
|
|
205
|
+
|
|
206
|
+
Raises:
|
|
207
|
+
StorageError: If URL generation fails
|
|
208
|
+
"""
|
|
209
|
+
object_key = self._get_object_key(key)
|
|
210
|
+
|
|
211
|
+
try:
|
|
212
|
+
return self.client.generate_presigned_url(object_key=object_key, expires=expires_hours)
|
|
213
|
+
except Exception as e:
|
|
214
|
+
raise StorageError(f"Failed to generate presigned URL: {e}") from e
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"""Initialize Tools Module for AIP Agents."""
|
|
2
|
+
|
|
3
|
+
from importlib import import_module
|
|
4
|
+
from typing import TYPE_CHECKING
|
|
5
|
+
|
|
6
|
+
from aip_agents.tools.date_range_tool import DateRangeTool
|
|
7
|
+
from aip_agents.tools.gl_connector import GLConnectorTool
|
|
8
|
+
from aip_agents.tools.gl_connector_tools import (
|
|
9
|
+
BOSA_AUTOMATED_TOOLS,
|
|
10
|
+
GL_CONNECTORS_AUTOMATED_TOOLS,
|
|
11
|
+
)
|
|
12
|
+
from aip_agents.tools.time_tool import TimeTool
|
|
13
|
+
from aip_agents.tools.web_search import GoogleSerperTool
|
|
14
|
+
from aip_agents.utils.logger import get_logger
|
|
15
|
+
|
|
16
|
+
logger = get_logger(__name__)
|
|
17
|
+
|
|
18
|
+
__all__ = [
|
|
19
|
+
"BOSA_AUTOMATED_TOOLS",
|
|
20
|
+
"GL_CONNECTORS_AUTOMATED_TOOLS",
|
|
21
|
+
"GLConnectorTool",
|
|
22
|
+
"GoogleSerperTool",
|
|
23
|
+
"TimeTool",
|
|
24
|
+
"DateRangeTool",
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def _register_optional(module_path: str, export_name: str) -> None:
|
|
29
|
+
"""Try to import optional tool module and expose it in __all__.
|
|
30
|
+
|
|
31
|
+
Args:
|
|
32
|
+
module_path: The module path to import.
|
|
33
|
+
export_name: The name to export in __all__.
|
|
34
|
+
"""
|
|
35
|
+
try:
|
|
36
|
+
module = import_module(module_path)
|
|
37
|
+
tool = getattr(module, export_name)
|
|
38
|
+
__all__.append(export_name)
|
|
39
|
+
globals()[export_name] = tool
|
|
40
|
+
|
|
41
|
+
except ImportError as e:
|
|
42
|
+
logger.debug(f"Module {module_path} not found: {e}")
|
|
43
|
+
except AttributeError as e:
|
|
44
|
+
logger.debug(f"Tool {export_name} not found in module {module_path}: {e}")
|
|
45
|
+
except Exception as e:
|
|
46
|
+
logger.debug(f"Unexpected error loading {export_name}: {e}")
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
_register_optional("aip_agents.tools.browser_use", "BrowserUseTool")
|
|
50
|
+
_register_optional("aip_agents.tools.code_sandbox", "CodeSandboxTool")
|
|
51
|
+
_register_optional("aip_agents.tools.code_sandbox", "E2BCodeSandboxTool")
|
|
52
|
+
_register_optional("aip_agents.tools.document_loader", "DocxReaderTool")
|
|
53
|
+
_register_optional("aip_agents.tools.document_loader", "ExcelReaderTool")
|
|
54
|
+
_register_optional("aip_agents.tools.document_loader", "PDFReaderTool")
|
|
55
|
+
_register_optional("aip_agents.tools.execute_ptc_code", "create_execute_ptc_code_tool")
|
|
56
|
+
|
|
57
|
+
if TYPE_CHECKING:
|
|
58
|
+
from aip_agents.tools.browser_use import BrowserUseTool
|
|
59
|
+
from aip_agents.tools.code_sandbox import CodeSandboxTool, E2BCodeSandboxTool
|
|
60
|
+
from aip_agents.tools.document_loader import (
|
|
61
|
+
DocxReaderTool,
|
|
62
|
+
ExcelReaderTool,
|
|
63
|
+
PDFReaderTool,
|
|
64
|
+
)
|
|
65
|
+
from aip_agents.tools.execute_ptc_code import create_execute_ptc_code_tool
|
|
@@ -0,0 +1,392 @@
|
|
|
1
|
+
"""Agent-bound schedule CRUD native tool.
|
|
2
|
+
|
|
3
|
+
Authors:
|
|
4
|
+
Saul Sayers (saul.sayers@gdplabs.id)
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import asyncio
|
|
10
|
+
import re
|
|
11
|
+
from typing import Any, Literal
|
|
12
|
+
|
|
13
|
+
import httpx
|
|
14
|
+
from langchain_core.runnables import RunnableConfig
|
|
15
|
+
from langchain_core.tools import BaseTool
|
|
16
|
+
from pydantic import BaseModel, Field, SecretStr
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class AgentScheduleToolConfig(BaseModel):
|
|
20
|
+
"""Runtime configuration for AgentScheduleNativeTool."""
|
|
21
|
+
|
|
22
|
+
api_base_url: str = Field(description="Base URL for AIP backend API")
|
|
23
|
+
api_key: SecretStr = Field(description="API key used for schedule endpoint calls")
|
|
24
|
+
request_timeout_seconds: int = Field(default=30, ge=1, le=120)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class AgentScheduleToolInput(BaseModel):
|
|
28
|
+
"""Action-based input for schedule CRUD operations."""
|
|
29
|
+
|
|
30
|
+
action: Literal["create", "list", "update", "delete"] = Field(description="CRUD action to perform")
|
|
31
|
+
schedule_id: str | None = Field(default=None)
|
|
32
|
+
input: str | None = Field(default=None)
|
|
33
|
+
schedule: dict[str, Any] | None = Field(default=None)
|
|
34
|
+
page: int | None = Field(default=None)
|
|
35
|
+
limit: int | None = Field(default=None)
|
|
36
|
+
|
|
37
|
+
class Config:
|
|
38
|
+
"""Reject unknown fields like agent_id/account_id in payload."""
|
|
39
|
+
|
|
40
|
+
extra = "forbid"
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class AgentScheduleNativeTool(BaseTool):
|
|
44
|
+
"""Native tool for schedule CRUD scoped to trusted bound agent."""
|
|
45
|
+
|
|
46
|
+
name: str = "agent_schedule_native_tool"
|
|
47
|
+
description: str = (
|
|
48
|
+
"Create, list, update, or delete schedules for the current bound agent only. "
|
|
49
|
+
"Identity is resolved from trusted runtime metadata."
|
|
50
|
+
)
|
|
51
|
+
args_schema: type[BaseModel] = AgentScheduleToolInput
|
|
52
|
+
tool_config_schema: type[BaseModel] = AgentScheduleToolConfig
|
|
53
|
+
|
|
54
|
+
def _run(
|
|
55
|
+
self,
|
|
56
|
+
action: str,
|
|
57
|
+
schedule_id: str | None = None,
|
|
58
|
+
input: str | None = None,
|
|
59
|
+
schedule: dict[str, Any] | None = None,
|
|
60
|
+
page: int | None = None,
|
|
61
|
+
limit: int | None = None,
|
|
62
|
+
metadata: dict[str, Any] | None = None,
|
|
63
|
+
config: RunnableConfig | None = None,
|
|
64
|
+
) -> dict[str, Any]:
|
|
65
|
+
"""Execute schedule CRUD action with bound-agent safeguards."""
|
|
66
|
+
effective_metadata = self._resolve_effective_metadata(config, metadata)
|
|
67
|
+
validation_error = self._validate_action_inputs(action, schedule_id, input, schedule, page, limit)
|
|
68
|
+
if validation_error:
|
|
69
|
+
return self._error(action, validation_error)
|
|
70
|
+
|
|
71
|
+
runtime = self._resolve_runtime_config(config, effective_metadata)
|
|
72
|
+
if isinstance(runtime, dict) and runtime.get("error"):
|
|
73
|
+
return self._error(action, runtime["error"])
|
|
74
|
+
|
|
75
|
+
bound_agent_id = self._resolve_bound_agent_id(effective_metadata)
|
|
76
|
+
if not bound_agent_id:
|
|
77
|
+
return self._error(action, "bound_agent_id not found in runtime metadata")
|
|
78
|
+
|
|
79
|
+
action_handlers: dict[str, tuple[str, Any]] = {
|
|
80
|
+
"create": ("Schedule created", lambda: self._handle_create(bound_agent_id, input, schedule, runtime)),
|
|
81
|
+
"list": ("Schedules listed", lambda: self._handle_list(bound_agent_id, page, limit, runtime)),
|
|
82
|
+
"update": (
|
|
83
|
+
"Schedule updated",
|
|
84
|
+
lambda: self._handle_update(bound_agent_id, schedule_id, input, schedule, runtime),
|
|
85
|
+
),
|
|
86
|
+
"delete": ("Schedule deleted", lambda: self._handle_delete(bound_agent_id, schedule_id, runtime)),
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
handler_entry = action_handlers.get(action)
|
|
90
|
+
if handler_entry is None:
|
|
91
|
+
return self._error(action, "Unsupported action") # pragma: no cover
|
|
92
|
+
|
|
93
|
+
success_message, handler = handler_entry
|
|
94
|
+
try:
|
|
95
|
+
data = handler()
|
|
96
|
+
if isinstance(data, dict) and data.get("_error"):
|
|
97
|
+
return self._error(action, data["_error"])
|
|
98
|
+
return self._success(action, success_message, data)
|
|
99
|
+
except RuntimeError as exc:
|
|
100
|
+
# Sanitize: extract only the part after the first ": " to avoid leaking raw API bodies
|
|
101
|
+
# into tool responses consumed by the LLM.
|
|
102
|
+
msg = str(exc)
|
|
103
|
+
safe_msg = msg.split(": ", 1)[-1] if ": " in msg else "Schedule action failed"
|
|
104
|
+
if " {" in safe_msg:
|
|
105
|
+
safe_msg = safe_msg.split(" {", 1)[0]
|
|
106
|
+
return self._error(action, safe_msg)
|
|
107
|
+
except Exception:
|
|
108
|
+
return self._error(action, "Schedule action failed")
|
|
109
|
+
|
|
110
|
+
async def _arun(
|
|
111
|
+
self,
|
|
112
|
+
action: str,
|
|
113
|
+
schedule_id: str | None = None,
|
|
114
|
+
input: str | None = None,
|
|
115
|
+
schedule: dict[str, Any] | None = None,
|
|
116
|
+
page: int | None = None,
|
|
117
|
+
limit: int | None = None,
|
|
118
|
+
metadata: dict[str, Any] | None = None,
|
|
119
|
+
config: RunnableConfig | None = None,
|
|
120
|
+
) -> dict[str, Any]:
|
|
121
|
+
return await asyncio.to_thread(
|
|
122
|
+
self._run,
|
|
123
|
+
action,
|
|
124
|
+
schedule_id,
|
|
125
|
+
input,
|
|
126
|
+
schedule,
|
|
127
|
+
page,
|
|
128
|
+
limit,
|
|
129
|
+
metadata,
|
|
130
|
+
config,
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
def _handle_create(
|
|
134
|
+
self,
|
|
135
|
+
bound_agent_id: str,
|
|
136
|
+
input_value: str | None,
|
|
137
|
+
schedule: dict[str, Any] | None,
|
|
138
|
+
runtime: dict[str, Any],
|
|
139
|
+
) -> dict[str, Any]:
|
|
140
|
+
path = f"/agents/{bound_agent_id}/schedule"
|
|
141
|
+
payload = {"input": input_value, "schedule": schedule}
|
|
142
|
+
return self._call_api("POST", path, runtime, payload)
|
|
143
|
+
|
|
144
|
+
def _handle_list(
|
|
145
|
+
self,
|
|
146
|
+
bound_agent_id: str,
|
|
147
|
+
page: int | None,
|
|
148
|
+
limit: int | None,
|
|
149
|
+
runtime: dict[str, Any],
|
|
150
|
+
) -> dict[str, Any]:
|
|
151
|
+
query_params: dict[str, Any] = {"agent_id": bound_agent_id}
|
|
152
|
+
if page is not None:
|
|
153
|
+
query_params["page"] = page
|
|
154
|
+
if limit is not None:
|
|
155
|
+
query_params["limit"] = limit
|
|
156
|
+
return self._call_api("GET", "/agents/schedules", runtime, query_params=query_params)
|
|
157
|
+
|
|
158
|
+
def _check_schedule_ownership(
|
|
159
|
+
self,
|
|
160
|
+
bound_agent_id: str,
|
|
161
|
+
schedule_id: str | None,
|
|
162
|
+
runtime: dict[str, Any],
|
|
163
|
+
) -> str | None:
|
|
164
|
+
detail = self._call_api("GET", f"/agents/schedules/{schedule_id}", runtime)
|
|
165
|
+
owner_id = self._extract_owner_id(detail)
|
|
166
|
+
if owner_id != bound_agent_id:
|
|
167
|
+
return "Forbidden: schedule does not belong to bound agent"
|
|
168
|
+
return None
|
|
169
|
+
|
|
170
|
+
def _handle_update(
|
|
171
|
+
self,
|
|
172
|
+
bound_agent_id: str,
|
|
173
|
+
schedule_id: str | None,
|
|
174
|
+
input_value: str | None,
|
|
175
|
+
schedule: dict[str, Any] | None,
|
|
176
|
+
runtime: dict[str, Any],
|
|
177
|
+
) -> dict[str, Any]:
|
|
178
|
+
ownership_error = self._check_schedule_ownership(bound_agent_id, schedule_id, runtime)
|
|
179
|
+
if ownership_error:
|
|
180
|
+
return {"_error": ownership_error}
|
|
181
|
+
payload = {"input": input_value, "schedule": schedule}
|
|
182
|
+
return self._call_api("PUT", f"/agents/schedules/{schedule_id}", runtime, payload)
|
|
183
|
+
|
|
184
|
+
def _handle_delete(
|
|
185
|
+
self,
|
|
186
|
+
bound_agent_id: str,
|
|
187
|
+
schedule_id: str | None,
|
|
188
|
+
runtime: dict[str, Any],
|
|
189
|
+
) -> dict[str, Any]:
|
|
190
|
+
ownership_error = self._check_schedule_ownership(bound_agent_id, schedule_id, runtime)
|
|
191
|
+
if ownership_error:
|
|
192
|
+
return {"_error": ownership_error}
|
|
193
|
+
return self._call_api("DELETE", f"/agents/schedules/{schedule_id}", runtime)
|
|
194
|
+
|
|
195
|
+
@staticmethod
|
|
196
|
+
def _resolve_effective_metadata(
|
|
197
|
+
config: RunnableConfig | None,
|
|
198
|
+
metadata: dict[str, Any] | None,
|
|
199
|
+
) -> dict[str, Any]:
|
|
200
|
+
effective_metadata: dict[str, Any] = {}
|
|
201
|
+
if isinstance(config, dict):
|
|
202
|
+
config_metadata = config.get("metadata")
|
|
203
|
+
if isinstance(config_metadata, dict):
|
|
204
|
+
effective_metadata.update(config_metadata)
|
|
205
|
+
if isinstance(metadata, dict):
|
|
206
|
+
# These keys carry trusted runtime config values (from agent runner) and must not be overridden by untrusted metadata.
|
|
207
|
+
PROTECTED_KEYS = {
|
|
208
|
+
"bound_agent_id",
|
|
209
|
+
"api_base_url",
|
|
210
|
+
"api_key",
|
|
211
|
+
"aip_base_url",
|
|
212
|
+
"aip_api_key",
|
|
213
|
+
"request_timeout_seconds",
|
|
214
|
+
}
|
|
215
|
+
for key, value in metadata.items():
|
|
216
|
+
key_str = str(key)
|
|
217
|
+
if key_str in PROTECTED_KEYS and key_str in effective_metadata:
|
|
218
|
+
continue
|
|
219
|
+
effective_metadata[key_str] = value
|
|
220
|
+
return effective_metadata
|
|
221
|
+
|
|
222
|
+
@staticmethod
|
|
223
|
+
def _validate_action_inputs(
|
|
224
|
+
action: str,
|
|
225
|
+
schedule_id: str | None,
|
|
226
|
+
input_value: str | None,
|
|
227
|
+
schedule: dict[str, Any] | None,
|
|
228
|
+
page: int | None,
|
|
229
|
+
limit: int | None,
|
|
230
|
+
) -> str | None:
|
|
231
|
+
valid_actions = {"create", "list", "update", "delete"}
|
|
232
|
+
if action not in valid_actions:
|
|
233
|
+
return f"Invalid action '{action}'"
|
|
234
|
+
return (
|
|
235
|
+
AgentScheduleNativeTool._validate_schedule_payload(action, input_value, schedule)
|
|
236
|
+
or AgentScheduleNativeTool._validate_schedule_id(action, schedule_id)
|
|
237
|
+
or AgentScheduleNativeTool._validate_pagination(action, page, limit)
|
|
238
|
+
)
|
|
239
|
+
|
|
240
|
+
@staticmethod
|
|
241
|
+
def _validate_schedule_payload(action: str, input_value: str | None, schedule: dict[str, Any] | None) -> str | None:
|
|
242
|
+
if action not in {"create", "update"}:
|
|
243
|
+
return None
|
|
244
|
+
if not input_value or not schedule:
|
|
245
|
+
return "'input' and 'schedule' are required for create/update" # pragma: no cover
|
|
246
|
+
required_schedule_fields = {"minute", "hour", "day_of_month", "month", "day_of_week"}
|
|
247
|
+
missing_fields = sorted(
|
|
248
|
+
field
|
|
249
|
+
for field in required_schedule_fields
|
|
250
|
+
if not isinstance(schedule.get(field), str) or not schedule.get(field)
|
|
251
|
+
)
|
|
252
|
+
if missing_fields:
|
|
253
|
+
return f"Incomplete schedule payload, missing fields: {', '.join(missing_fields)}"
|
|
254
|
+
return None
|
|
255
|
+
|
|
256
|
+
@staticmethod
|
|
257
|
+
def _validate_schedule_id(action: str, schedule_id: str | None) -> str | None:
|
|
258
|
+
if action not in {"update", "delete"}:
|
|
259
|
+
return None
|
|
260
|
+
if not schedule_id:
|
|
261
|
+
return "'schedule_id' is required for update/delete"
|
|
262
|
+
if not re.match(r"^[a-zA-Z0-9\-_]+$", schedule_id):
|
|
263
|
+
return "'schedule_id' contains invalid characters"
|
|
264
|
+
return None
|
|
265
|
+
|
|
266
|
+
@staticmethod
|
|
267
|
+
def _validate_pagination(action: str, page: int | None, limit: int | None) -> str | None:
|
|
268
|
+
if action != "list":
|
|
269
|
+
return None
|
|
270
|
+
if page is not None and page < 1:
|
|
271
|
+
return "'page' must be a positive integer"
|
|
272
|
+
if limit is not None and limit < 1:
|
|
273
|
+
return "'limit' must be a positive integer"
|
|
274
|
+
return None
|
|
275
|
+
|
|
276
|
+
def _resolve_runtime_config(
|
|
277
|
+
self,
|
|
278
|
+
config: RunnableConfig | None,
|
|
279
|
+
metadata: dict[str, Any] | None,
|
|
280
|
+
) -> dict[str, Any]:
|
|
281
|
+
tool_cfg = None
|
|
282
|
+
get_tool_config = getattr(self, "get_tool_config", None)
|
|
283
|
+
if callable(get_tool_config):
|
|
284
|
+
tool_cfg = get_tool_config(config)
|
|
285
|
+
|
|
286
|
+
if tool_cfg is not None:
|
|
287
|
+
if hasattr(tool_cfg, "model_dump"):
|
|
288
|
+
dumped = tool_cfg.model_dump(exclude_none=True)
|
|
289
|
+
api_key = dumped.get("api_key")
|
|
290
|
+
if isinstance(api_key, SecretStr):
|
|
291
|
+
dumped["api_key"] = api_key.get_secret_value()
|
|
292
|
+
return self._normalize_runtime_config(
|
|
293
|
+
dumped.get("api_base_url"),
|
|
294
|
+
dumped.get("api_key"),
|
|
295
|
+
dumped.get("request_timeout_seconds", 30),
|
|
296
|
+
)
|
|
297
|
+
if isinstance(tool_cfg, dict):
|
|
298
|
+
api_key = tool_cfg.get("api_key")
|
|
299
|
+
if isinstance(api_key, SecretStr):
|
|
300
|
+
tool_cfg = {**tool_cfg, "api_key": api_key.get_secret_value()}
|
|
301
|
+
return self._normalize_runtime_config(
|
|
302
|
+
tool_cfg.get("api_base_url"),
|
|
303
|
+
tool_cfg.get("api_key"),
|
|
304
|
+
tool_cfg.get("request_timeout_seconds", 30),
|
|
305
|
+
)
|
|
306
|
+
|
|
307
|
+
flat = metadata or {}
|
|
308
|
+
api_base_url = flat.get("api_base_url") or flat.get("aip_base_url")
|
|
309
|
+
api_key = flat.get("api_key") or flat.get("aip_api_key")
|
|
310
|
+
timeout = flat.get("request_timeout_seconds", 30)
|
|
311
|
+
return self._normalize_runtime_config(api_base_url, api_key, timeout)
|
|
312
|
+
|
|
313
|
+
@staticmethod
|
|
314
|
+
def _normalize_runtime_config(
|
|
315
|
+
api_base_url: Any,
|
|
316
|
+
api_key: Any,
|
|
317
|
+
timeout: Any,
|
|
318
|
+
) -> dict[str, Any]:
|
|
319
|
+
if not api_base_url or not api_key:
|
|
320
|
+
return {"error": "Missing tool runtime config: api_base_url/api_key"}
|
|
321
|
+
|
|
322
|
+
try:
|
|
323
|
+
timeout_seconds = int(timeout)
|
|
324
|
+
except (TypeError, ValueError):
|
|
325
|
+
return {"error": "Invalid tool runtime config: request_timeout_seconds must be an integer"}
|
|
326
|
+
|
|
327
|
+
if timeout_seconds < 1 or timeout_seconds > 120:
|
|
328
|
+
return {"error": "Invalid tool runtime config: request_timeout_seconds must be between 1 and 120"}
|
|
329
|
+
|
|
330
|
+
return {
|
|
331
|
+
"api_base_url": str(api_base_url),
|
|
332
|
+
"api_key": str(api_key),
|
|
333
|
+
"request_timeout_seconds": timeout_seconds,
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
@staticmethod
|
|
337
|
+
def _resolve_bound_agent_id(metadata: dict[str, Any] | None) -> str | None:
|
|
338
|
+
if not isinstance(metadata, dict):
|
|
339
|
+
return None # pragma: no cover
|
|
340
|
+
value = metadata.get("bound_agent_id")
|
|
341
|
+
return str(value) if value else None
|
|
342
|
+
|
|
343
|
+
@staticmethod
|
|
344
|
+
def _extract_owner_id(schedule_detail: dict[str, Any]) -> str | None:
|
|
345
|
+
metadata = schedule_detail.get("metadata") if isinstance(schedule_detail, dict) else None
|
|
346
|
+
if not isinstance(metadata, dict):
|
|
347
|
+
wrapped = schedule_detail.get("data") if isinstance(schedule_detail, dict) else None
|
|
348
|
+
metadata = wrapped.get("metadata") if isinstance(wrapped, dict) else None
|
|
349
|
+
if isinstance(metadata, dict):
|
|
350
|
+
raw = metadata.get("bound_agent_id")
|
|
351
|
+
if raw:
|
|
352
|
+
return str(raw)
|
|
353
|
+
return None
|
|
354
|
+
|
|
355
|
+
def _call_api(
|
|
356
|
+
self,
|
|
357
|
+
method: str,
|
|
358
|
+
path: str,
|
|
359
|
+
runtime: dict[str, Any],
|
|
360
|
+
payload: dict[str, Any] | None = None,
|
|
361
|
+
query_params: dict[str, Any] | None = None,
|
|
362
|
+
) -> dict[str, Any]:
|
|
363
|
+
base_url = runtime["api_base_url"].rstrip("/")
|
|
364
|
+
url = f"{base_url}{path}"
|
|
365
|
+
headers = {
|
|
366
|
+
"X-API-Key": runtime["api_key"],
|
|
367
|
+
}
|
|
368
|
+
try:
|
|
369
|
+
with httpx.Client(timeout=runtime["request_timeout_seconds"]) as client:
|
|
370
|
+
resp = client.request(method, url, json=payload, params=query_params, headers=headers)
|
|
371
|
+
resp.raise_for_status()
|
|
372
|
+
if not resp.content:
|
|
373
|
+
return {}
|
|
374
|
+
try:
|
|
375
|
+
decoded = resp.json()
|
|
376
|
+
except ValueError as exc:
|
|
377
|
+
raise RuntimeError(f"Schedule API {method} {path} returned invalid JSON") from exc
|
|
378
|
+
if isinstance(decoded, dict):
|
|
379
|
+
return decoded
|
|
380
|
+
return {"items": decoded}
|
|
381
|
+
except httpx.HTTPStatusError as exc:
|
|
382
|
+
raise RuntimeError(f"Schedule API {method} {path} failed: {exc.response.status_code}") from exc
|
|
383
|
+
except httpx.RequestError as exc:
|
|
384
|
+
raise RuntimeError(f"Schedule API {method} {path} unreachable: {exc}") from exc
|
|
385
|
+
|
|
386
|
+
@staticmethod
|
|
387
|
+
def _success(action: str, message: str, data: dict[str, Any]) -> dict[str, Any]:
|
|
388
|
+
return {"success": True, "action": action, "message": message, "data": data}
|
|
389
|
+
|
|
390
|
+
@staticmethod
|
|
391
|
+
def _error(action: str, message: str) -> dict[str, Any]:
|
|
392
|
+
return {"success": False, "action": action, "message": message, "data": {}}
|