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.
Files changed (447) hide show
  1. aip_agents/__init__.py +66 -0
  2. aip_agents/a2a/__init__.py +19 -0
  3. aip_agents/a2a/server/__init__.py +10 -0
  4. aip_agents/a2a/server/base_executor.py +1125 -0
  5. aip_agents/a2a/server/google_adk_executor.py +198 -0
  6. aip_agents/a2a/server/langflow_executor.py +180 -0
  7. aip_agents/a2a/server/langgraph_executor.py +270 -0
  8. aip_agents/a2a/types.py +232 -0
  9. aip_agents/a2ui/__init__.py +26 -0
  10. aip_agents/a2ui/catalog_provider.py +109 -0
  11. aip_agents/a2ui/examples/0.8/booking_form.json +1 -0
  12. aip_agents/a2ui/examples/0.8/confirmation.json +1 -0
  13. aip_agents/a2ui/examples/0.8/single_column_list.json +1 -0
  14. aip_agents/a2ui/examples/0.9/booking_form.json +1 -0
  15. aip_agents/a2ui/examples/0.9/confirmation.json +1 -0
  16. aip_agents/a2ui/examples/0.9/single_column_list.json +1 -0
  17. aip_agents/a2ui/middleware.py +754 -0
  18. aip_agents/a2ui/models.py +153 -0
  19. aip_agents/a2ui/public_url.py +138 -0
  20. aip_agents/a2ui/stream_filter.py +67 -0
  21. aip_agents/agent/__init__.py +72 -0
  22. aip_agents/agent/base_agent.py +1437 -0
  23. aip_agents/agent/base_langgraph_agent.py +4048 -0
  24. aip_agents/agent/google_adk_agent.py +932 -0
  25. aip_agents/agent/google_adk_constants.py +11 -0
  26. aip_agents/agent/graph_runtime.py +185 -0
  27. aip_agents/agent/hitl/__init__.py +24 -0
  28. aip_agents/agent/hitl/config.py +28 -0
  29. aip_agents/agent/hitl/langgraph_hitl_mixin.py +515 -0
  30. aip_agents/agent/hitl/manager.py +532 -0
  31. aip_agents/agent/hitl/models.py +18 -0
  32. aip_agents/agent/hitl/prompt/__init__.py +9 -0
  33. aip_agents/agent/hitl/prompt/base.py +42 -0
  34. aip_agents/agent/hitl/prompt/deferred.py +73 -0
  35. aip_agents/agent/hitl/registry.py +149 -0
  36. aip_agents/agent/interface.py +138 -0
  37. aip_agents/agent/interfaces.py +65 -0
  38. aip_agents/agent/langflow_agent.py +464 -0
  39. aip_agents/agent/langgraph_react_agent.py +3741 -0
  40. aip_agents/agent/model_invocation_adapter.py +346 -0
  41. aip_agents/agent/system_instruction_context.py +34 -0
  42. aip_agents/agent/tool_execution_engine.py +587 -0
  43. aip_agents/audio_interface/__init__.py +30 -0
  44. aip_agents/audio_interface/audio_agent_adapter.py +254 -0
  45. aip_agents/audio_interface/config.py +146 -0
  46. aip_agents/audio_interface/errors.py +15 -0
  47. aip_agents/audio_interface/livekit_audio_session.py +504 -0
  48. aip_agents/audio_interface/livekit_realtime_audio_session.py +142 -0
  49. aip_agents/audio_interface/session_factory.py +40 -0
  50. aip_agents/clients/__init__.py +10 -0
  51. aip_agents/clients/langflow/__init__.py +10 -0
  52. aip_agents/clients/langflow/client.py +477 -0
  53. aip_agents/clients/langflow/types.py +18 -0
  54. aip_agents/common/__init__.py +5 -0
  55. aip_agents/common/callable_introspection.py +17 -0
  56. aip_agents/constants.py +23 -0
  57. aip_agents/context/__init__.py +5 -0
  58. aip_agents/context/budget.py +237 -0
  59. aip_agents/context/compaction.py +339 -0
  60. aip_agents/context/metadata.py +169 -0
  61. aip_agents/context/offload.py +449 -0
  62. aip_agents/context/preparation.py +196 -0
  63. aip_agents/context/prompt.py +61 -0
  64. aip_agents/context/runtime.py +149 -0
  65. aip_agents/context/session_recall.py +69 -0
  66. aip_agents/context/state.py +48 -0
  67. aip_agents/context/utils.py +44 -0
  68. aip_agents/credentials/manager.py +132 -0
  69. aip_agents/examples/__init__.py +5 -0
  70. aip_agents/examples/audio_livekit_session.py +116 -0
  71. aip_agents/examples/compare_streaming_client.py +783 -0
  72. aip_agents/examples/compare_streaming_server.py +141 -0
  73. aip_agents/examples/gl_connectors_smoke.py +148 -0
  74. aip_agents/examples/hello_world_a2a_google_adk_client.py +49 -0
  75. aip_agents/examples/hello_world_a2a_google_adk_client_agent.py +48 -0
  76. aip_agents/examples/hello_world_a2a_google_adk_client_streaming.py +60 -0
  77. aip_agents/examples/hello_world_a2a_google_adk_server.py +78 -0
  78. aip_agents/examples/hello_world_a2a_langchain_client.py +39 -0
  79. aip_agents/examples/hello_world_a2a_langchain_client_agent.py +39 -0
  80. aip_agents/examples/hello_world_a2a_langchain_client_lm_invoker.py +37 -0
  81. aip_agents/examples/hello_world_a2a_langchain_client_streaming.py +41 -0
  82. aip_agents/examples/hello_world_a2a_langchain_reference_client_streaming.py +60 -0
  83. aip_agents/examples/hello_world_a2a_langchain_reference_server.py +104 -0
  84. aip_agents/examples/hello_world_a2a_langchain_server.py +78 -0
  85. aip_agents/examples/hello_world_a2a_langchain_server_lm_invoker.py +77 -0
  86. aip_agents/examples/hello_world_a2a_langflow_client.py +83 -0
  87. aip_agents/examples/hello_world_a2a_langflow_server.py +80 -0
  88. aip_agents/examples/hello_world_a2a_langgraph_artifact_client.py +73 -0
  89. aip_agents/examples/hello_world_a2a_langgraph_artifact_client_streaming.py +76 -0
  90. aip_agents/examples/hello_world_a2a_langgraph_artifact_server.py +91 -0
  91. aip_agents/examples/hello_world_a2a_langgraph_client.py +54 -0
  92. aip_agents/examples/hello_world_a2a_langgraph_client_agent.py +54 -0
  93. aip_agents/examples/hello_world_a2a_langgraph_client_agent_lm_invoker.py +32 -0
  94. aip_agents/examples/hello_world_a2a_langgraph_client_streaming.py +50 -0
  95. aip_agents/examples/hello_world_a2a_langgraph_client_streaming_lm_invoker.py +44 -0
  96. aip_agents/examples/hello_world_a2a_langgraph_client_streaming_tool_streaming.py +92 -0
  97. aip_agents/examples/hello_world_a2a_langgraph_server.py +83 -0
  98. aip_agents/examples/hello_world_a2a_langgraph_server_lm_invoker.py +78 -0
  99. aip_agents/examples/hello_world_a2a_langgraph_server_tool_streaming.py +131 -0
  100. aip_agents/examples/hello_world_a2a_mcp_langgraph.py +196 -0
  101. aip_agents/examples/hello_world_a2a_three_level_agent_hierarchy_client.py +244 -0
  102. aip_agents/examples/hello_world_a2a_three_level_agent_hierarchy_server.py +250 -0
  103. aip_agents/examples/hello_world_a2a_with_metadata_langchain_client.py +57 -0
  104. aip_agents/examples/hello_world_a2a_with_metadata_langchain_server_lm_invoker.py +79 -0
  105. aip_agents/examples/hello_world_filesystem.py +162 -0
  106. aip_agents/examples/hello_world_google_adk.py +41 -0
  107. aip_agents/examples/hello_world_google_adk_mcp_http.py +34 -0
  108. aip_agents/examples/hello_world_google_adk_mcp_http_stream.py +40 -0
  109. aip_agents/examples/hello_world_google_adk_mcp_sse.py +44 -0
  110. aip_agents/examples/hello_world_google_adk_mcp_sse_stream.py +48 -0
  111. aip_agents/examples/hello_world_google_adk_mcp_stdio.py +44 -0
  112. aip_agents/examples/hello_world_google_adk_mcp_stdio_stream.py +48 -0
  113. aip_agents/examples/hello_world_google_adk_stream.py +44 -0
  114. aip_agents/examples/hello_world_langchain.py +28 -0
  115. aip_agents/examples/hello_world_langchain_lm_invoker.py +15 -0
  116. aip_agents/examples/hello_world_langchain_mcp_http.py +34 -0
  117. aip_agents/examples/hello_world_langchain_mcp_http_interactive.py +130 -0
  118. aip_agents/examples/hello_world_langchain_mcp_http_stream.py +42 -0
  119. aip_agents/examples/hello_world_langchain_mcp_multi_server.py +155 -0
  120. aip_agents/examples/hello_world_langchain_mcp_sse.py +34 -0
  121. aip_agents/examples/hello_world_langchain_mcp_sse_stream.py +40 -0
  122. aip_agents/examples/hello_world_langchain_mcp_stdio.py +30 -0
  123. aip_agents/examples/hello_world_langchain_mcp_stdio_stream.py +41 -0
  124. aip_agents/examples/hello_world_langchain_stream.py +36 -0
  125. aip_agents/examples/hello_world_langchain_stream_lm_invoker.py +39 -0
  126. aip_agents/examples/hello_world_langflow_agent.py +163 -0
  127. aip_agents/examples/hello_world_langgraph.py +39 -0
  128. aip_agents/examples/hello_world_langgraph_gl_connector_twitter.py +44 -0
  129. aip_agents/examples/hello_world_langgraph_mcp_http.py +31 -0
  130. aip_agents/examples/hello_world_langgraph_mcp_http_stream.py +34 -0
  131. aip_agents/examples/hello_world_langgraph_mcp_sse.py +35 -0
  132. aip_agents/examples/hello_world_langgraph_mcp_sse_stream.py +50 -0
  133. aip_agents/examples/hello_world_langgraph_mcp_stdio.py +35 -0
  134. aip_agents/examples/hello_world_langgraph_mcp_stdio_stream.py +50 -0
  135. aip_agents/examples/hello_world_langgraph_skills.py +62 -0
  136. aip_agents/examples/hello_world_langgraph_stream.py +43 -0
  137. aip_agents/examples/hello_world_langgraph_stream_lm_invoker.py +37 -0
  138. aip_agents/examples/hello_world_model_switch_cli.py +210 -0
  139. aip_agents/examples/hello_world_multi_agent_adk.py +75 -0
  140. aip_agents/examples/hello_world_multi_agent_langchain.py +54 -0
  141. aip_agents/examples/hello_world_multi_agent_langgraph.py +66 -0
  142. aip_agents/examples/hello_world_multi_agent_langgraph_lm_invoker.py +69 -0
  143. aip_agents/examples/hello_world_multi_agent_tool_output_client.py +57 -0
  144. aip_agents/examples/hello_world_multi_agent_tool_output_server.py +131 -0
  145. aip_agents/examples/hello_world_pii_logger.py +21 -0
  146. aip_agents/examples/hello_world_ptc.py +49 -0
  147. aip_agents/examples/hello_world_ptc_custom_tools.py +83 -0
  148. aip_agents/examples/hello_world_sentry.py +133 -0
  149. aip_agents/examples/hello_world_step_limits.py +273 -0
  150. aip_agents/examples/hello_world_stock_a2a_server.py +100 -0
  151. aip_agents/examples/hello_world_tool_output_client.py +55 -0
  152. aip_agents/examples/hello_world_tool_output_server.py +113 -0
  153. aip_agents/examples/hitl_demo.py +724 -0
  154. aip_agents/examples/mcp_configs/configs.py +63 -0
  155. aip_agents/examples/mcp_servers/common.py +76 -0
  156. aip_agents/examples/mcp_servers/mcp_name.py +29 -0
  157. aip_agents/examples/mcp_servers/mcp_server_http.py +19 -0
  158. aip_agents/examples/mcp_servers/mcp_server_sse.py +19 -0
  159. aip_agents/examples/mcp_servers/mcp_server_stdio.py +19 -0
  160. aip_agents/examples/mcp_servers/mcp_time.py +10 -0
  161. aip_agents/examples/pii_demo_langgraph_client.py +69 -0
  162. aip_agents/examples/pii_demo_langgraph_server.py +125 -0
  163. aip_agents/examples/pii_demo_multi_agent_client.py +80 -0
  164. aip_agents/examples/pii_demo_multi_agent_server.py +246 -0
  165. aip_agents/examples/todolist_planning_a2a_langchain_client.py +70 -0
  166. aip_agents/examples/todolist_planning_a2a_langgraph_server.py +87 -0
  167. aip_agents/examples/tools/__init__.py +27 -0
  168. aip_agents/examples/tools/adk_arithmetic_tools.py +36 -0
  169. aip_agents/examples/tools/adk_weather_tool.py +60 -0
  170. aip_agents/examples/tools/data_generator_tool.py +103 -0
  171. aip_agents/examples/tools/data_visualization_tool.py +312 -0
  172. aip_agents/examples/tools/image_artifact_tool.py +136 -0
  173. aip_agents/examples/tools/langchain_arithmetic_tools.py +26 -0
  174. aip_agents/examples/tools/langchain_currency_exchange_tool.py +88 -0
  175. aip_agents/examples/tools/langchain_graph_artifact_tool.py +172 -0
  176. aip_agents/examples/tools/langchain_weather_tool.py +48 -0
  177. aip_agents/examples/tools/langgraph_streaming_tool.py +130 -0
  178. aip_agents/examples/tools/mock_retrieval_tool.py +56 -0
  179. aip_agents/examples/tools/multiply_tool.py +43 -0
  180. aip_agents/examples/tools/pii_demo_tools.py +189 -0
  181. aip_agents/examples/tools/random_chart_tool.py +142 -0
  182. aip_agents/examples/tools/serper_tool.py +202 -0
  183. aip_agents/examples/tools/stock_tools.py +82 -0
  184. aip_agents/examples/tools/table_generator_tool.py +167 -0
  185. aip_agents/examples/tools/time_tool.py +82 -0
  186. aip_agents/examples/tools/weather_forecast_tool.py +38 -0
  187. aip_agents/guardrails/__init__.py +83 -0
  188. aip_agents/guardrails/engines/__init__.py +69 -0
  189. aip_agents/guardrails/engines/base.py +90 -0
  190. aip_agents/guardrails/engines/nemo.py +101 -0
  191. aip_agents/guardrails/engines/phrase_matcher.py +113 -0
  192. aip_agents/guardrails/exceptions.py +39 -0
  193. aip_agents/guardrails/manager.py +163 -0
  194. aip_agents/guardrails/middleware.py +199 -0
  195. aip_agents/guardrails/schemas.py +63 -0
  196. aip_agents/guardrails/utils.py +45 -0
  197. aip_agents/integration/__init__.py +43 -0
  198. aip_agents/integration/agent.py +58 -0
  199. aip_agents/integration/guardrails.py +52 -0
  200. aip_agents/integration/hitl.py +71 -0
  201. aip_agents/integration/ptc.py +95 -0
  202. aip_agents/integration/skills.py +37 -0
  203. aip_agents/integration/storage.py +81 -0
  204. aip_agents/integration/version.py +103 -0
  205. aip_agents/mcp/__init__.py +1 -0
  206. aip_agents/mcp/client/__init__.py +60 -0
  207. aip_agents/mcp/client/base_mcp_client.py +377 -0
  208. aip_agents/mcp/client/connection_manager.py +231 -0
  209. aip_agents/mcp/client/errors.py +119 -0
  210. aip_agents/mcp/client/google_adk/__init__.py +45 -0
  211. aip_agents/mcp/client/google_adk/client.py +383 -0
  212. aip_agents/mcp/client/langchain/__init__.py +11 -0
  213. aip_agents/mcp/client/langchain/client.py +265 -0
  214. aip_agents/mcp/client/persistent_session.py +704 -0
  215. aip_agents/mcp/client/session_pool.py +358 -0
  216. aip_agents/mcp/client/transports.py +288 -0
  217. aip_agents/mcp/utils/__init__.py +7 -0
  218. aip_agents/mcp/utils/config_validator.py +139 -0
  219. aip_agents/memory/__init__.py +14 -0
  220. aip_agents/memory/adapters/__init__.py +10 -0
  221. aip_agents/memory/adapters/base_adapter.py +815 -0
  222. aip_agents/memory/adapters/mem0.py +286 -0
  223. aip_agents/memory/base.py +84 -0
  224. aip_agents/memory/constants.py +49 -0
  225. aip_agents/memory/factory.py +86 -0
  226. aip_agents/memory/guidance.py +20 -0
  227. aip_agents/memory/simple_memory.py +47 -0
  228. aip_agents/middleware/__init__.py +65 -0
  229. aip_agents/middleware/backends/__init__.py +72 -0
  230. aip_agents/middleware/backends/in_memory.py +578 -0
  231. aip_agents/middleware/backends/local_disk.py +1203 -0
  232. aip_agents/middleware/backends/protocol.py +353 -0
  233. aip_agents/middleware/backends/sandbox.py +1431 -0
  234. aip_agents/middleware/backends/sandbox_files.py +113 -0
  235. aip_agents/middleware/backends/utils.py +293 -0
  236. aip_agents/middleware/base.py +239 -0
  237. aip_agents/middleware/filesystem.py +690 -0
  238. aip_agents/middleware/manager.py +291 -0
  239. aip_agents/middleware/memory.py +532 -0
  240. aip_agents/middleware/pii_middleware.py +192 -0
  241. aip_agents/middleware/schema.py +19 -0
  242. aip_agents/middleware/skills.py +872 -0
  243. aip_agents/middleware/task_delegation.py +1656 -0
  244. aip_agents/middleware/todolist.py +276 -0
  245. aip_agents/middleware/tools/__init__.py +23 -0
  246. aip_agents/middleware/tools/edit_file.py +70 -0
  247. aip_agents/middleware/tools/execute.py +428 -0
  248. aip_agents/middleware/tools/grep_file.py +79 -0
  249. aip_agents/middleware/tools/ls.py +71 -0
  250. aip_agents/middleware/tools/read_file.py +239 -0
  251. aip_agents/middleware/tools/skill_load.py +193 -0
  252. aip_agents/middleware/tools/skill_resource.py +338 -0
  253. aip_agents/middleware/tools/write_file.py +114 -0
  254. aip_agents/middleware/vision.py +322 -0
  255. aip_agents/ptc/__init__.py +87 -0
  256. aip_agents/ptc/custom_tools.py +511 -0
  257. aip_agents/ptc/custom_tools_payload.py +499 -0
  258. aip_agents/ptc/custom_tools_templates/__init__.py +1 -0
  259. aip_agents/ptc/custom_tools_templates/custom_build_function.py.template +24 -0
  260. aip_agents/ptc/custom_tools_templates/custom_init.py.template +26 -0
  261. aip_agents/ptc/custom_tools_templates/custom_invoke.py.template +149 -0
  262. aip_agents/ptc/custom_tools_templates/custom_registry.py.template +112 -0
  263. aip_agents/ptc/custom_tools_templates/custom_sources_init.py.template +7 -0
  264. aip_agents/ptc/custom_tools_templates/custom_wrapper.py.template +87 -0
  265. aip_agents/ptc/doc_gen.py +122 -0
  266. aip_agents/ptc/exceptions.py +57 -0
  267. aip_agents/ptc/executor.py +627 -0
  268. aip_agents/ptc/mcp/__init__.py +45 -0
  269. aip_agents/ptc/mcp/sandbox_bridge.py +679 -0
  270. aip_agents/ptc/mcp/templates/__init__.py +1 -0
  271. aip_agents/ptc/mcp/templates/mcp_client.py.template +240 -0
  272. aip_agents/ptc/naming.py +430 -0
  273. aip_agents/ptc/payload.py +26 -0
  274. aip_agents/ptc/prompt_builder.py +674 -0
  275. aip_agents/ptc/ptc_helper.py +16 -0
  276. aip_agents/ptc/sandbox_bridge.py +297 -0
  277. aip_agents/ptc/template_utils.py +33 -0
  278. aip_agents/ptc/templates/__init__.py +1 -0
  279. aip_agents/ptc/templates/ptc_helper.py.template +134 -0
  280. aip_agents/ptc/tool_def_helpers.py +101 -0
  281. aip_agents/ptc/tool_enrichment.py +163 -0
  282. aip_agents/resilience/__init__.py +10 -0
  283. aip_agents/resilience/base.py +46 -0
  284. aip_agents/resilience/tool.py +1661 -0
  285. aip_agents/sandbox/__init__.py +62 -0
  286. aip_agents/sandbox/defaults.py +220 -0
  287. aip_agents/sandbox/dockerfiles/aip-agents-sandbox-v2-1-datasaur.Dockerfile +120 -0
  288. aip_agents/sandbox/dockerfiles/aip-agents-sandbox-v2-1.Dockerfile +100 -0
  289. aip_agents/sandbox/dockerfiles/aip-agents-sandbox-v2-2-datasaur.Dockerfile +143 -0
  290. aip_agents/sandbox/dockerfiles/aip-agents-sandbox-v2-2.Dockerfile +119 -0
  291. aip_agents/sandbox/dockerfiles/aip-agents-sandbox-v2-3-datasaur.Dockerfile +173 -0
  292. aip_agents/sandbox/dockerfiles/aip-agents-sandbox-v2-3.Dockerfile +130 -0
  293. aip_agents/sandbox/dockerfiles/aip-agents-sandbox-v2-4-runner-managed.Dockerfile +164 -0
  294. aip_agents/sandbox/dockerfiles/aip-agents-sandbox-v2-4-runner-managed.patch_js_context.py +41 -0
  295. aip_agents/sandbox/dockerfiles/aip-agents-sandbox-v2-4-runner-managed.requirements.txt +29 -0
  296. aip_agents/sandbox/dockerfiles/aip-agents-sandbox-v2.Dockerfile +87 -0
  297. aip_agents/sandbox/e2b_runtime.py +27 -0
  298. aip_agents/sandbox/image_registry.py +98 -0
  299. aip_agents/sandbox/providers/__init__.py +76 -0
  300. aip_agents/sandbox/providers/base.py +392 -0
  301. aip_agents/sandbox/providers/bedrock.py +28 -0
  302. aip_agents/sandbox/providers/e2b.py +230 -0
  303. aip_agents/sandbox/providers/opensandbox.py +163 -0
  304. aip_agents/sandbox/sandbox_runtime.py +967 -0
  305. aip_agents/sandbox/template_builder.py +240 -0
  306. aip_agents/sandbox/types.py +141 -0
  307. aip_agents/sandbox/validation.py +50 -0
  308. aip_agents/schema/__init__.py +106 -0
  309. aip_agents/schema/a2a.py +58 -0
  310. aip_agents/schema/agent.py +117 -0
  311. aip_agents/schema/artifacts.py +75 -0
  312. aip_agents/schema/attachments.py +425 -0
  313. aip_agents/schema/hitl.py +157 -0
  314. aip_agents/schema/langgraph.py +47 -0
  315. aip_agents/schema/model_id.py +103 -0
  316. aip_agents/schema/model_usage.py +50 -0
  317. aip_agents/schema/runtime_metadata.py +78 -0
  318. aip_agents/schema/step_limit.py +108 -0
  319. aip_agents/schema/storage.py +40 -0
  320. aip_agents/schema/tool_payloads.py +68 -0
  321. aip_agents/sentry/__init__.py +11 -0
  322. aip_agents/sentry/sentry.py +267 -0
  323. aip_agents/skills/__init__.py +30 -0
  324. aip_agents/skills/errors.py +110 -0
  325. aip_agents/skills/installer.py +479 -0
  326. aip_agents/skills/models.py +769 -0
  327. aip_agents/skills/stager.py +224 -0
  328. aip_agents/skills/validation.py +53 -0
  329. aip_agents/storage/__init__.py +41 -0
  330. aip_agents/storage/base.py +85 -0
  331. aip_agents/storage/clients/__init__.py +12 -0
  332. aip_agents/storage/clients/minio_client.py +318 -0
  333. aip_agents/storage/config.py +62 -0
  334. aip_agents/storage/providers/__init__.py +15 -0
  335. aip_agents/storage/providers/base.py +106 -0
  336. aip_agents/storage/providers/memory.py +114 -0
  337. aip_agents/storage/providers/object_storage.py +214 -0
  338. aip_agents/tools/__init__.py +65 -0
  339. aip_agents/tools/agent_schedule_tool.py +392 -0
  340. aip_agents/tools/browser_use/__init__.py +83 -0
  341. aip_agents/tools/browser_use/action_parser.py +104 -0
  342. aip_agents/tools/browser_use/browser_use_tool.py +1118 -0
  343. aip_agents/tools/browser_use/llm_config.py +120 -0
  344. aip_agents/tools/browser_use/minio_storage.py +203 -0
  345. aip_agents/tools/browser_use/schemas.py +121 -0
  346. aip_agents/tools/browser_use/session.py +13 -0
  347. aip_agents/tools/browser_use/session_errors.py +132 -0
  348. aip_agents/tools/browser_use/steel_session_recording.py +321 -0
  349. aip_agents/tools/browser_use/streaming.py +263 -0
  350. aip_agents/tools/browser_use/structured_data_parser.py +257 -0
  351. aip_agents/tools/browser_use/structured_data_recovery.py +204 -0
  352. aip_agents/tools/browser_use/types.py +37 -0
  353. aip_agents/tools/code_sandbox/__init__.py +48 -0
  354. aip_agents/tools/code_sandbox/code_sandbox_tool.py +350 -0
  355. aip_agents/tools/code_sandbox/constant.py +13 -0
  356. aip_agents/tools/code_sandbox/e2b_cloud_sandbox_extended.py +346 -0
  357. aip_agents/tools/code_sandbox/e2b_sandbox_tool.py +65 -0
  358. aip_agents/tools/computer_use/__init__.py +75 -0
  359. aip_agents/tools/computer_use/computer_use_tool.py +910 -0
  360. aip_agents/tools/computer_use/schemas.py +78 -0
  361. aip_agents/tools/computer_use/streaming.py +198 -0
  362. aip_agents/tools/computer_use/types.py +32 -0
  363. aip_agents/tools/constants.py +177 -0
  364. aip_agents/tools/date_range_tool.py +554 -0
  365. aip_agents/tools/document_loader/__init__.py +44 -0
  366. aip_agents/tools/document_loader/base_reader.py +302 -0
  367. aip_agents/tools/document_loader/docx_reader_tool.py +68 -0
  368. aip_agents/tools/document_loader/excel_reader_tool.py +171 -0
  369. aip_agents/tools/document_loader/pdf_reader_tool.py +79 -0
  370. aip_agents/tools/document_loader/pdf_splitter.py +169 -0
  371. aip_agents/tools/execute_ptc_code.py +582 -0
  372. aip_agents/tools/gl_connector/__init__.py +5 -0
  373. aip_agents/tools/gl_connector/tool.py +518 -0
  374. aip_agents/tools/gl_connector_tools.py +170 -0
  375. aip_agents/tools/memory_search/__init__.py +29 -0
  376. aip_agents/tools/memory_search/base.py +213 -0
  377. aip_agents/tools/memory_search/mem0.py +424 -0
  378. aip_agents/tools/memory_search/schema.py +81 -0
  379. aip_agents/tools/memory_search_tool.py +34 -0
  380. aip_agents/tools/streaming_common.py +577 -0
  381. aip_agents/tools/time_tool.py +117 -0
  382. aip_agents/tools/tool_config_injector.py +300 -0
  383. aip_agents/tools/web_search/__init__.py +15 -0
  384. aip_agents/tools/web_search/serper_tool.py +187 -0
  385. aip_agents/types/__init__.py +73 -0
  386. aip_agents/types/a2a_events.py +13 -0
  387. aip_agents/utils/__init__.py +91 -0
  388. aip_agents/utils/a2a_connector.py +1758 -0
  389. aip_agents/utils/artifact_helpers.py +542 -0
  390. aip_agents/utils/artifacts/__init__.py +20 -0
  391. aip_agents/utils/artifacts/tracker.py +367 -0
  392. aip_agents/utils/attachment_helpers.py +178 -0
  393. aip_agents/utils/constants.py +22 -0
  394. aip_agents/utils/datetime/__init__.py +34 -0
  395. aip_agents/utils/datetime/normalization.py +231 -0
  396. aip_agents/utils/datetime/timezone.py +206 -0
  397. aip_agents/utils/env_loader.py +27 -0
  398. aip_agents/utils/event_handler_registry.py +58 -0
  399. aip_agents/utils/file_prompt_utils.py +276 -0
  400. aip_agents/utils/file_watchers/__init__.py +33 -0
  401. aip_agents/utils/file_watchers/base.py +46 -0
  402. aip_agents/utils/file_watchers/e2b.py +128 -0
  403. aip_agents/utils/file_watchers/factory.py +39 -0
  404. aip_agents/utils/file_watchers/ls_diff.py +88 -0
  405. aip_agents/utils/file_watchers/sandbox.py +66 -0
  406. aip_agents/utils/file_watchers/watchdog.py +97 -0
  407. aip_agents/utils/final_response_builder.py +211 -0
  408. aip_agents/utils/formatter_llm_client.py +258 -0
  409. aip_agents/utils/langgraph/__init__.py +19 -0
  410. aip_agents/utils/langgraph/converter.py +399 -0
  411. aip_agents/utils/langgraph/delegation_context.py +22 -0
  412. aip_agents/utils/langgraph/tool_managers/__init__.py +15 -0
  413. aip_agents/utils/langgraph/tool_managers/a2a_tool_manager.py +99 -0
  414. aip_agents/utils/langgraph/tool_managers/base_tool_manager.py +66 -0
  415. aip_agents/utils/langgraph/tool_managers/delegation_tool_manager.py +1329 -0
  416. aip_agents/utils/langgraph/tool_output_management.py +1047 -0
  417. aip_agents/utils/logger.py +195 -0
  418. aip_agents/utils/metadata/__init__.py +27 -0
  419. aip_agents/utils/metadata/activity_metadata_helper.py +407 -0
  420. aip_agents/utils/metadata/activity_narrative/__init__.py +35 -0
  421. aip_agents/utils/metadata/activity_narrative/builder.py +822 -0
  422. aip_agents/utils/metadata/activity_narrative/constants.py +51 -0
  423. aip_agents/utils/metadata/activity_narrative/context.py +49 -0
  424. aip_agents/utils/metadata/activity_narrative/formatters.py +230 -0
  425. aip_agents/utils/metadata/activity_narrative/utils.py +35 -0
  426. aip_agents/utils/metadata/schemas/__init__.py +16 -0
  427. aip_agents/utils/metadata/schemas/activity_schema.py +29 -0
  428. aip_agents/utils/metadata/schemas/thinking_schema.py +31 -0
  429. aip_agents/utils/metadata/thinking_metadata_helper.py +38 -0
  430. aip_agents/utils/metadata_helper.py +363 -0
  431. aip_agents/utils/name_preprocessor/__init__.py +17 -0
  432. aip_agents/utils/name_preprocessor/base_name_preprocessor.py +73 -0
  433. aip_agents/utils/name_preprocessor/google_name_preprocessor.py +100 -0
  434. aip_agents/utils/name_preprocessor/name_preprocessor.py +87 -0
  435. aip_agents/utils/name_preprocessor/openai_name_preprocessor.py +48 -0
  436. aip_agents/utils/pii/__init__.py +29 -0
  437. aip_agents/utils/pii/pii_handler.py +555 -0
  438. aip_agents/utils/pii/pii_helper.py +225 -0
  439. aip_agents/utils/pii/uuid_deanonymizer_mapping.py +195 -0
  440. aip_agents/utils/reference_helper.py +273 -0
  441. aip_agents/utils/sse_chunk_transformer.py +836 -0
  442. aip_agents/utils/step_limit_manager.py +265 -0
  443. aip_agents/utils/token_usage_helper.py +531 -0
  444. aip_agents_binary-0.0.0.dist-info/METADATA +825 -0
  445. aip_agents_binary-0.0.0.dist-info/RECORD +447 -0
  446. aip_agents_binary-0.0.0.dist-info/WHEEL +5 -0
  447. aip_agents_binary-0.0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,428 @@
1
+ """Execute tool for running shell commands with artifact tracking.
2
+
3
+ This module provides the ExecuteTool class that wraps backend command execution
4
+ with a LangChain tool interface, including timeout handling, output formatting,
5
+ and artifact tracking for files created during execution.
6
+
7
+ Authors:
8
+ Christian Trisno Sen Long Chen (christian.t.s.l.chen@gdplabs.id)
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ import asyncio
14
+ from collections.abc import AsyncIterator
15
+ from contextlib import AsyncExitStack, asynccontextmanager
16
+ from functools import lru_cache
17
+ from pathlib import Path
18
+ from typing import Annotated, Any, cast
19
+
20
+ from langchain_core.tools import BaseTool
21
+ from langgraph.types import Command
22
+ from pydantic import BaseModel, Field, SkipValidation
23
+
24
+ from aip_agents.common.callable_introspection import callable_accepts_keyword
25
+ from aip_agents.middleware.backends.protocol import BackendProtocol, ExecuteResult
26
+ from aip_agents.middleware.schema import MiddlewareToolConfig
27
+ from aip_agents.utils.artifacts import ArtifactTracker
28
+ from aip_agents.utils.file_watchers import FileWatcherStrategy, SandboxArtifactWatcher, create_local_strategy
29
+ from aip_agents.utils.logger import get_logger
30
+
31
+ logger = get_logger(__name__)
32
+
33
+
34
+ class ExecuteInput(BaseModel):
35
+ """Input schema for the execute tool.
36
+
37
+ Attributes:
38
+ command: The shell command to execute.
39
+ timeout: Timeout in seconds (optional, defaults to 30).
40
+ """
41
+
42
+ command: str = Field(description="Shell command to execute")
43
+ timeout: int = Field(default=30, description="Timeout in seconds", ge=1)
44
+
45
+
46
+ class ExecuteTool(BaseTool):
47
+ """Tool for executing shell commands via backend with artifact tracking.
48
+
49
+ This tool wraps backend command execution with proper timeout handling,
50
+ output formatting, and artifact tracking for files created during execution.
51
+
52
+ Attributes:
53
+ name: Tool name ('execute').
54
+ description: Tool description for LLM.
55
+ args_schema: Input schema class.
56
+ backend: BackendProtocol instance for execution.
57
+ max_execute_timeout: Maximum allowed timeout in seconds.
58
+ """
59
+
60
+ name: str = "execute"
61
+ description: str = (
62
+ "Execute a shell command. Returns stdout/stderr with exit code. "
63
+ "Use timeout parameter for long-running commands. "
64
+ "Creates artifacts for any files generated during execution."
65
+ )
66
+ args_schema: type[BaseModel] = ExecuteInput # type: ignore[assignment]
67
+ tool_config_schema: type[BaseModel] = MiddlewareToolConfig
68
+ backend: Annotated[BackendProtocol, SkipValidation()] # BackendProtocol type with validation skipped for Protocol
69
+ max_execute_timeout: int = 300
70
+
71
+ async def _arun(self, command: str, timeout: int = 30) -> Command | str:
72
+ """Execute a command with artifact tracking (async).
73
+
74
+ Args:
75
+ command: Shell command to execute.
76
+ timeout: Timeout in seconds.
77
+
78
+ Returns:
79
+ Command with artifacts if files created,
80
+ otherwise formatted result string.
81
+ """
82
+ timeout = self._clamp_timeout(timeout)
83
+
84
+ if not self._backend_supports_execution():
85
+ return (
86
+ "Error: Execution not available. This agent's backend "
87
+ "does not support command execution. "
88
+ "To use the execute tool, provide a backend that implements "
89
+ "the execute() method."
90
+ )
91
+
92
+ backend_class = type(self.backend)
93
+ execute_fn = getattr(self.backend, "execute", None)
94
+ supports_timeout = ExecuteTool._execute_accepts_timeout(backend_class) or callable_accepts_keyword(
95
+ execute_fn, "timeout"
96
+ )
97
+ if not supports_timeout:
98
+ return (
99
+ "Error: This backend does not support per-command timeout "
100
+ "overrides. Update your backend package or omit the timeout parameter."
101
+ )
102
+
103
+ try:
104
+ return await self._arun_with_tracking(command, timeout)
105
+ except NotImplementedError as e:
106
+ return f"Error: Execution not available. {e}"
107
+ except ValueError as e:
108
+ return f"Error: Invalid parameter. {e}"
109
+ except Exception as e:
110
+ return f"Error: Execution failed. {str(e)}"
111
+
112
+ def _run(self, command: str, timeout: int = 30) -> Command | str:
113
+ """Execute a command synchronously with artifact tracking.
114
+
115
+ Args:
116
+ command: Shell command to execute.
117
+ timeout: Timeout in seconds.
118
+
119
+ Returns:
120
+ Command with artifacts (if files created) or error message string.
121
+ """
122
+ backend = cast(Any, self.backend)
123
+ run_sync = getattr(backend, "_run_sync", None)
124
+ if callable(run_sync):
125
+ return run_sync(self._arun(command, timeout=timeout))
126
+ return asyncio.run(self._arun(command, timeout=timeout))
127
+
128
+ def _clamp_timeout(self, timeout: int) -> int:
129
+ """Clamp timeout to valid range.
130
+
131
+ Args:
132
+ timeout: Requested timeout in seconds.
133
+
134
+ Returns:
135
+ Timeout clamped between 1 and max_execute_timeout.
136
+ """
137
+ return max(1, min(timeout, self.max_execute_timeout))
138
+
139
+ def _backend_supports_execution(self) -> bool:
140
+ """Check if backend supports execution.
141
+
142
+ Returns:
143
+ True if backend has callable execute method.
144
+ """
145
+ return hasattr(self.backend, "execute") and callable(getattr(self.backend, "execute"))
146
+
147
+ @staticmethod
148
+ @lru_cache(maxsize=128)
149
+ def _execute_accepts_timeout(backend_class: type) -> bool:
150
+ """Check if backend class execute accepts timeout parameter."""
151
+ execute_fn = getattr(backend_class, "execute", None)
152
+ return callable_accepts_keyword(execute_fn, "timeout")
153
+
154
+ async def _arun_with_tracking(self, command: str, timeout: int) -> Command:
155
+ """Execute with artifact tracking using context manager.
156
+
157
+ Args:
158
+ command: Shell command to execute.
159
+ timeout: Timeout in seconds.
160
+
161
+ Returns:
162
+ Command with execution result and artifacts.
163
+ """
164
+ # Initialize the runtime first so a lazily-resolved base_dir (e.g. the
165
+ # sandbox backend's $HOME/workspace resolution) is settled before we read
166
+ # it; otherwise the tracker would watch the stale default directory.
167
+ if hasattr(self.backend, "ensure_runtime"):
168
+ await self.backend.ensure_runtime()
169
+
170
+ # Get base directory from backend
171
+ base_dir = self._get_backend_base_dir()
172
+ if not base_dir:
173
+ # Fallback to execute without tracking
174
+ result = await self._aexecute_backend(command, timeout)
175
+ return self._format_result_as_command(result, [])
176
+
177
+ # Create watcher strategy
178
+ strategy = await self._create_watcher_strategy()
179
+
180
+ async with self._tracker_with_fallback(base_dir, strategy) as tracker:
181
+ return await self._execute_with_tracker(command, timeout, tracker)
182
+
183
+ @asynccontextmanager
184
+ async def _tracker_with_fallback(
185
+ self, base_dir: str, strategy: FileWatcherStrategy
186
+ ) -> AsyncIterator[ArtifactTracker]:
187
+ """Context manager that yields an ArtifactTracker using the given strategy.
188
+
189
+ Falls back to a non-watchdog strategy if the given strategy fails to initialize
190
+ (e.g. due to missing dependencies or OS limitations).
191
+
192
+ Args:
193
+ base_dir: Base directory to watch for artifacts.
194
+ strategy: Primary file watcher strategy to use.
195
+
196
+ Yields:
197
+ An initialized ArtifactTracker instance.
198
+ """
199
+ stack = AsyncExitStack()
200
+ tracker = self._make_tracker(base_dir, strategy)
201
+ try:
202
+ active_tracker = await stack.enter_async_context(tracker)
203
+ except (ImportError, OSError) as exc:
204
+ await stack.aclose()
205
+ logger.warning(
206
+ "Watchdog watcher unavailable (%s), falling back to LsDiffWatcher",
207
+ exc,
208
+ )
209
+ file_lister = self._get_file_lister()
210
+ fallback = create_local_strategy(file_lister, use_watchdog=False)
211
+ fallback_tracker = self._make_tracker(base_dir, fallback)
212
+ stack = AsyncExitStack()
213
+ active_tracker = await stack.enter_async_context(fallback_tracker)
214
+
215
+ try:
216
+ yield active_tracker
217
+ finally:
218
+ await stack.aclose()
219
+
220
+ def _make_tracker(self, base_dir: str, strategy: FileWatcherStrategy) -> ArtifactTracker:
221
+ """Helper to create an ArtifactTracker with the given strategy."""
222
+ return ArtifactTracker(
223
+ base_dir=base_dir,
224
+ file_reader=self._read_file_bytes,
225
+ watcher_strategy=strategy,
226
+ )
227
+
228
+ async def _execute_with_tracker(self, command: str, timeout: int, tracker: ArtifactTracker) -> Command:
229
+ """Execute command and track artifacts using the given tracker.
230
+
231
+ Args:
232
+ command: Shell command to execute.
233
+ timeout: Timeout in seconds.
234
+ tracker: Initialized ArtifactTracker instance.
235
+
236
+ Returns:
237
+ Command with execution result and artifacts.
238
+ """
239
+ result = await self._aexecute_backend(command, timeout)
240
+ created_files = await tracker.collect()
241
+
242
+ if created_files:
243
+ file_cache = await self._aread_file_cache(created_files)
244
+ tracker._file_reader = lambda p, _c=file_cache: _c[p] # type: ignore[method-assign]
245
+
246
+ artifacts, errors = tracker.build_artifacts(created_files)
247
+ return self._format_result_as_command(result, artifacts, errors)
248
+
249
+ def _read_file_bytes(self, path: str) -> bytes:
250
+ """Read file as bytes using backend (synchronous fallback).
251
+
252
+ Used as the initial ``file_reader`` passed to ``ArtifactTracker``. For
253
+ backends that only expose an async API (e.g. ``SandboxBackend``), the
254
+ caller should replace ``tracker._file_reader`` with a cache-backed
255
+ synchronous lambda after pre-reading the files asynchronously via
256
+ :meth:`_aread_file_cache`. That avoids running async E2B client calls
257
+ from a sync callback that runs in a different event loop.
258
+
259
+ Args:
260
+ path: File path to read.
261
+
262
+ Returns:
263
+ File content as bytes.
264
+
265
+ Raises:
266
+ FileNotFoundError: If file not found.
267
+ PermissionError: If file not readable.
268
+ IsADirectoryError: If path is a directory.
269
+ """
270
+ backend = cast(Any, self.backend)
271
+
272
+ if hasattr(backend, "read_bytes") and callable(getattr(backend, "read_bytes")):
273
+ return backend.read_bytes(path)
274
+
275
+ content = backend.read(path)
276
+ return content.encode("utf-8")
277
+
278
+ async def _aread_file_bytes(self, path: str) -> bytes:
279
+ """Read file as bytes using the async backend API.
280
+
281
+ Args:
282
+ path: File path to read.
283
+
284
+ Returns:
285
+ File content as bytes.
286
+ """
287
+ backend = cast(Any, self.backend)
288
+
289
+ if hasattr(backend, "aread_bytes") and callable(getattr(backend, "aread_bytes")):
290
+ return await backend.aread_bytes(path)
291
+
292
+ if hasattr(backend, "read_bytes") and callable(getattr(backend, "read_bytes")):
293
+ return await asyncio.to_thread(backend.read_bytes, path)
294
+
295
+ content = await asyncio.to_thread(backend.read, path)
296
+ return content.encode("utf-8")
297
+
298
+ async def _aread_file_cache(self, paths: list[str]) -> dict[str, bytes]:
299
+ """Pre-read multiple files asynchronously into an in-memory cache.
300
+
301
+ Files that cannot be read are omitted from the returned dict; the
302
+ caller's ``file_reader`` lambda will raise ``KeyError`` for those paths
303
+ which ``ArtifactTracker.build_artifacts`` catches and converts to error
304
+ entries.
305
+
306
+ Args:
307
+ paths: Absolute file paths to read.
308
+
309
+ Returns:
310
+ Mapping of path → raw bytes for every file that was read
311
+ successfully.
312
+ """
313
+ cache: dict[str, bytes] = {}
314
+ for path in paths:
315
+ try:
316
+ cache[path] = await self._aread_file_bytes(path)
317
+ except Exception as exc:
318
+ logger.warning("Failed to read file %s: %s: %s", path, type(exc).__name__, exc)
319
+ return cache
320
+
321
+ async def _aexecute_backend(self, command: str, timeout: int) -> ExecuteResult:
322
+ """Execute command using the backend's async API if available, otherwise run sync execute in a thread."""
323
+ backend = cast(Any, self.backend)
324
+ if hasattr(backend, "aexecute") and callable(getattr(backend, "aexecute")):
325
+ return await backend.aexecute(command, timeout=timeout)
326
+
327
+ execute_fn = getattr(backend, "execute")
328
+ return await asyncio.to_thread(execute_fn, command, timeout=timeout)
329
+
330
+ async def _create_watcher_strategy(self) -> FileWatcherStrategy:
331
+ """Create and return the appropriate file watcher strategy based on the backend."""
332
+ try:
333
+ from aip_agents.middleware.backends.sandbox import SandboxBackend as sandbox_backend_type
334
+ except ImportError:
335
+ sandbox_backend_type = None
336
+
337
+ backend = cast(Any, self.backend)
338
+ if sandbox_backend_type is not None and isinstance(backend, sandbox_backend_type):
339
+ # Provider-neutral: watch via the runtime's execute_command (find -newer),
340
+ # so this works on any sandbox backend, not just E2B. _create_watcher_strategy
341
+ # runs before _aexecute_backend, so initialize the runtime first.
342
+ runtime = await backend._ensure_runtime()
343
+ return SandboxArtifactWatcher(runtime)
344
+
345
+ file_lister = self._get_file_lister()
346
+ return create_local_strategy(file_lister, use_watchdog=True)
347
+
348
+ def _format_result_as_command(
349
+ self,
350
+ result: ExecuteResult,
351
+ artifacts: list[dict[str, Any]],
352
+ errors: list[dict[str, str]] | None = None,
353
+ ) -> Command:
354
+ """Format execution result as Command with artifacts.
355
+
356
+ Args:
357
+ result: ExecuteResult from backend.
358
+ artifacts: List of artifact dicts.
359
+ errors: List of artifact error dicts.
360
+
361
+ Returns:
362
+ Command with result and artifacts.
363
+ """
364
+ execution_summary = self._format_result(result)
365
+
366
+ # Build response
367
+ response_data: dict[str, Any] = {
368
+ "result": execution_summary,
369
+ "artifacts": artifacts,
370
+ }
371
+
372
+ if errors:
373
+ response_data["artifact_errors"] = errors
374
+
375
+ # Return Command directly (not via helper to support empty artifacts)
376
+ return Command(update=response_data)
377
+
378
+ def _get_backend_base_dir(self) -> str | None:
379
+ """Get base directory from backend for artifact tracking.
380
+
381
+ Returns:
382
+ Base directory path or None if not available.
383
+ """
384
+ # Try common attribute names
385
+ for attr in ["base_path", "base_directory", "base_dir", "working_dir"]:
386
+ if hasattr(self.backend, attr):
387
+ val = getattr(self.backend, attr)
388
+ if isinstance(val, str | Path):
389
+ return str(val)
390
+ return None
391
+
392
+ def _get_file_lister(self) -> Any:
393
+ """Get file lister callable from backend.
394
+
395
+ Returns:
396
+ Callable that lists files in a directory.
397
+
398
+ Raises:
399
+ AttributeError: If backend does not have ls_info method.
400
+ """
401
+ if hasattr(self.backend, "ls_info"):
402
+ return self.backend.ls_info
403
+
404
+ raise AttributeError("Backend does not support file listing. Please provide a backend with ls_info method.")
405
+
406
+ def _format_result(self, result: ExecuteResult) -> str:
407
+ """Format execution result for LLM consumption.
408
+
409
+ Args:
410
+ result: ExecuteResult from backend.
411
+
412
+ Returns:
413
+ Formatted output string with stdout, stderr, exit code.
414
+ """
415
+ parts: list[str] = []
416
+
417
+ if result.stdout:
418
+ parts.append(f"STDOUT:\n{result.stdout}")
419
+ if result.stderr:
420
+ parts.append(f"STDERR:\n{result.stderr}")
421
+
422
+ status = "succeeded" if result.exit_code == 0 else "failed"
423
+ parts.append(f"\n[Command {status} with exit code {result.exit_code}]")
424
+
425
+ if result.truncated:
426
+ parts.append("\n[Output was truncated due to size limits]")
427
+
428
+ return "\n".join(parts)
@@ -0,0 +1,79 @@
1
+ """Grep tool for agents.
2
+
3
+ Authors:
4
+ Christian Trisno Sen Long Chen (christian.t.s.l.chen@gdplabs.id)
5
+
6
+ Notes:
7
+ TODO: After migrating to deepagents:
8
+ - Reuse from deepagents: BackendProtocol, GrepMatch, format_grep_matches()
9
+ """
10
+
11
+ from typing import Annotated, Any
12
+
13
+ from langchain_core.tools import BaseTool
14
+ from pydantic import BaseModel, Field, SkipValidation
15
+
16
+ from aip_agents.middleware.backends.protocol import GrepMatch
17
+ from aip_agents.middleware.backends.utils import ensure_absolute_path, format_grep_matches
18
+ from aip_agents.middleware.schema import MiddlewareToolConfig
19
+
20
+ GREP_TOOL_DESCRIPTION = """Search for a text pattern across files.
21
+
22
+ Searches for literal text (not regex) and returns matching files or content based on output_mode.
23
+ Special characters like parentheses, brackets, pipes, etc. are treated as literal characters, not regex operators.
24
+
25
+ Examples:
26
+ - Search all files: `grep(pattern="TODO")`
27
+ - Search Python files only: `grep(pattern="import", glob="*.py")`
28
+ - Show matching lines: `grep(pattern="error", output_mode="content")`
29
+ - Search for code with special chars: `grep(pattern="def __init__(self):")`"""
30
+
31
+
32
+ class GrepInput(BaseModel):
33
+ """Input schema for grep tool."""
34
+
35
+ path: str = Field(description="Directory path to search")
36
+ pattern: str = Field(description="Text pattern to search for (literal string)")
37
+ max_matches: int = Field(default=50, description="Maximum number of matches to return")
38
+
39
+
40
+ class GrepTool(BaseTool):
41
+ """Tool for searching file contents across directories."""
42
+
43
+ name: str = "grep"
44
+ description: str = GREP_TOOL_DESCRIPTION
45
+ args_schema: type[BaseModel] = GrepInput
46
+ tool_config_schema: type[BaseModel] = MiddlewareToolConfig
47
+ backend: Annotated[Any, SkipValidation()]
48
+
49
+ def _run(self, path: str, pattern: str, max_matches: int = 50) -> str:
50
+ """Execute the grep operation.
51
+
52
+ Args:
53
+ path (str): Directory path to search.
54
+ pattern (str): Text pattern to search for.
55
+ max_matches (int, optional): Maximum matches to return. Defaults to 50.
56
+
57
+ Returns:
58
+ str: Search results or error message.
59
+ """
60
+ try:
61
+ matches = self.backend.grep(pattern=pattern, path=path)
62
+ if len(matches) > max_matches:
63
+ matches = matches[:max_matches]
64
+ # Normalize paths to absolute so read_file receives consistent input
65
+ normalized = [
66
+ GrepMatch(
67
+ path=ensure_absolute_path(m.path),
68
+ line_number=m.line_number,
69
+ content=m.content,
70
+ )
71
+ for m in matches
72
+ ]
73
+ return format_grep_matches(normalized, output_mode="content")
74
+ except FileNotFoundError:
75
+ return f"Error: Path not found: {path}"
76
+ except ValueError as e:
77
+ return f"Error: {str(e)}"
78
+ except Exception as e:
79
+ return f"Error searching: {str(e)}"
@@ -0,0 +1,71 @@
1
+ """List files tool for agents.
2
+
3
+ Authors:
4
+ Christian Trisno Sen Long Chen (christian.t.s.l.chen@gdplabs.id)
5
+
6
+ TODO: When migrating to deepagents, replace this entire file with:
7
+ from deepagents.middleware.tools.ls import LsTool, LsInput, truncate_if_too_long
8
+
9
+ Note: deepagents LsTool uses ToolRuntime pattern instead of BaseTool.
10
+ We'll need to adapt our middleware to use deepagents' tool registration.
11
+ """
12
+
13
+ from typing import Annotated, Any
14
+
15
+ from langchain_core.tools import BaseTool
16
+ from pydantic import BaseModel, Field, SkipValidation
17
+
18
+ from aip_agents.middleware.backends.utils import (
19
+ ensure_absolute_path,
20
+ truncate_if_too_long,
21
+ )
22
+ from aip_agents.middleware.schema import MiddlewareToolConfig
23
+
24
+ LIST_FILES_TOOL_DESCRIPTION = """Lists all files in a directory.
25
+
26
+ This is useful for exploring the filesystem and finding the right file to read or edit.
27
+ You should almost ALWAYS use this tool before using the read_file tool."""
28
+
29
+
30
+ class LsInput(BaseModel):
31
+ """Input schema for ls tool."""
32
+
33
+ path: str = Field(description="Absolute path to the directory to list. Must be absolute, not relative.")
34
+
35
+
36
+ class LsTool(BaseTool):
37
+ """Tool for listing directory contents.
38
+
39
+ Returns a Python list representation (as string) of absolute paths for files and directories.
40
+ Large results are automatically truncated with guidance.
41
+ """
42
+
43
+ name: str = "ls"
44
+ description: str = LIST_FILES_TOOL_DESCRIPTION
45
+ args_schema: type[BaseModel] = LsInput
46
+ tool_config_schema: type[BaseModel] = MiddlewareToolConfig
47
+ backend: Annotated[Any, SkipValidation()]
48
+
49
+ def _run(self, path: str) -> str:
50
+ """Execute the ls operation.
51
+
52
+ Args:
53
+ path (str): Directory path to list.
54
+
55
+ Returns:
56
+ str: Python list representation (as string) of absolute paths,
57
+ or an error message if directory not found or path is not a directory.
58
+ Example: "['/workspace/file1.txt', '/workspace/file2.txt']"
59
+ """
60
+ try:
61
+ entries = self.backend.ls_info(path)
62
+ # Extract full paths like deepagents does
63
+ paths = [ensure_absolute_path(str(entry["path"])) for entry in entries]
64
+ truncated = truncate_if_too_long(paths)
65
+ return str(truncated)
66
+ except FileNotFoundError:
67
+ return f"No directory found: {path}"
68
+ except NotADirectoryError:
69
+ return f"Not a directory: {path}"
70
+ except Exception as e:
71
+ return f"Error: {str(e)}"