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,131 @@
1
+ """Example A2A server demonstrating multi-agent tool output management.
2
+
3
+ This server provides a multi-agent system for data generation and visualization,
4
+ demonstrating how tool outputs can be shared across agent boundaries using
5
+ a shared ToolOutputManager.
6
+
7
+ Workflow:
8
+ 1. CoordinatorAgent: Receives user request and delegates tasks.
9
+ 2. GeneratorAgent: Generates sample data and stores it.
10
+ 3. VisualizerAgent: Retrieves stored data via reference and creates visualizations.
11
+
12
+ Authors:
13
+ Christian Trisno Sen Long Chen (christian.t.s.l.chen@gdplabs.id)
14
+ """
15
+
16
+ import click
17
+ import uvicorn
18
+ from a2a.types import AgentCapabilities, AgentCard, AgentSkill
19
+ from dotenv import load_dotenv
20
+
21
+ from aip_agents.agent import LangGraphReactAgent
22
+ from aip_agents.examples.tools.data_generator_tool import DataGeneratorTool
23
+ from aip_agents.examples.tools.data_visualization_tool import DataVisualizerTool
24
+ from aip_agents.storage.clients.minio_client import MinioConfig, MinioObjectStorage
25
+ from aip_agents.storage.providers.object_storage import ObjectStorageProvider
26
+ from aip_agents.utils.langgraph.tool_output_management import ToolOutputConfig, ToolOutputManager
27
+ from aip_agents.utils.logger import get_logger
28
+
29
+ load_dotenv()
30
+ logger = get_logger(__name__)
31
+
32
+ SERVER_AGENT_NAME = "MultiAgentDataVisualizationAgent"
33
+
34
+
35
+ @click.command()
36
+ @click.option("--host", default="localhost", help="Host to bind the server to")
37
+ @click.option("--port", default=8886, help="Port to bind the server to")
38
+ def main(host: str, port: int):
39
+ """Run the Multi-Agent Data Visualization A2A server.
40
+
41
+ Args:
42
+ host (str): Host to bind the server to.
43
+ port (int): Port to bind the server to.
44
+ """
45
+ logger.info(f"Starting {SERVER_AGENT_NAME} on http://{host}:{port}")
46
+
47
+ # 1. Setup Shared Tool Output Management
48
+ minio_config = MinioConfig.from_env()
49
+ minio_client = MinioObjectStorage(minio_config)
50
+ object_storage_provider = ObjectStorageProvider(
51
+ client=minio_client,
52
+ prefix="multi_agent_test", # Unique prefix for this example
53
+ )
54
+ tool_output_config = ToolOutputConfig(
55
+ storage_provider=object_storage_provider,
56
+ )
57
+ tool_output_manager = ToolOutputManager(tool_output_config)
58
+
59
+ # 2. Create Specialized Agents
60
+ model_name = "openai/gpt-4.1"
61
+
62
+ # Generator Agent: Specializes in data generation
63
+ generator_agent = LangGraphReactAgent(
64
+ name="GeneratorAgent",
65
+ instruction="""You are a data generation specialist.
66
+ Generate sample datasets (sales, scores, growth data) when requested.
67
+ Always ensure your tool outputs are stored for other agents to use.""",
68
+ model=model_name,
69
+ tools=[DataGeneratorTool()],
70
+ tool_output_manager=tool_output_manager,
71
+ )
72
+
73
+ # Visualizer Agent: Specializes in data visualization
74
+ visualizer_agent = LangGraphReactAgent(
75
+ name="VisualizerAgent",
76
+ instruction="""You are a data visualization specialist.
77
+ Create charts and visualizations from data references ($tool_output.call_id).
78
+ Do not try to generate data yourself; use the data provided by the GeneratorAgent.""",
79
+ model=model_name,
80
+ tools=[DataVisualizerTool()],
81
+ tool_output_manager=tool_output_manager,
82
+ )
83
+
84
+ # 3. Create Coordinator Agent (The Main Entry Point)
85
+ coordinator_agent = LangGraphReactAgent(
86
+ name=SERVER_AGENT_NAME,
87
+ instruction="""You are a coordinator that manages data workflows.
88
+ Delegate data generation tasks to the GeneratorAgent and visualization tasks to the VisualizerAgent.
89
+
90
+ When you receive a request:
91
+ 1. Ask GeneratorAgent to generate the data.
92
+ 2. Pass the resulting tool output reference ($tool_output.call_id) to the VisualizerAgent to create the chart.
93
+
94
+ Always use tool output references to avoid passing large amounts of data between agents.""",
95
+ model=model_name,
96
+ agents=[generator_agent, visualizer_agent],
97
+ tool_output_manager=tool_output_manager,
98
+ )
99
+
100
+ # 4. Define Agent Card for A2A
101
+ agent_card = AgentCard(
102
+ name=SERVER_AGENT_NAME,
103
+ description="Multi-agent system that generates and visualizes data using shared tool outputs",
104
+ url=f"http://{host}:{port}",
105
+ version="1.0.0",
106
+ default_input_modes=["text"],
107
+ default_output_modes=["text"],
108
+ capabilities=AgentCapabilities(streaming=True),
109
+ skills=[
110
+ AgentSkill(
111
+ id="coordinated_analysis",
112
+ name="Coordinated Data Analysis",
113
+ description="End-to-end data generation and visualization via multiple specialized agents",
114
+ examples=[
115
+ "Generate sales data and create a bar chart",
116
+ "Analyze student scores with a line chart",
117
+ ],
118
+ tags=["multi-agent", "data", "visualization"],
119
+ ),
120
+ ],
121
+ )
122
+
123
+ # 5. Create and Run A2A App
124
+ app = coordinator_agent.to_a2a(agent_card=agent_card)
125
+
126
+ logger.info("A2A application configured. Starting Uvicorn server...")
127
+ uvicorn.run(app, host=host, port=port)
128
+
129
+
130
+ if __name__ == "__main__":
131
+ main()
@@ -0,0 +1,21 @@
1
+ """This example shows how to use the get_logger function to initialize a logger with PII logging enabled.
2
+
3
+ Authors:
4
+ Saul Sayers (saul.sayers@gdplabs.id)
5
+ """
6
+
7
+ import logging
8
+
9
+ from aip_agents.utils.logger import get_logger
10
+
11
+ logger = get_logger(__name__, logging.DEBUG)
12
+
13
+ # Set up logging format
14
+ sensitive_info = (
15
+ "contoh nomor ktp 3525011212941001\n"
16
+ "contoh email john.doe@example.com\n"
17
+ "contoh nomor telepon +628121729819 dan 0812898029384.\n"
18
+ "contoh npwp 01.123.456.7-891.234"
19
+ )
20
+
21
+ logger.info(f"Logging sensitive information for processing: \n{sensitive_info}")
@@ -0,0 +1,49 @@
1
+ """Minimal PTC hello world example.
2
+
3
+ Required environment variables:
4
+ - OPENAI_API_KEY
5
+ - E2B_API_KEY
6
+ """
7
+
8
+ import asyncio
9
+
10
+ from aip_agents.agent import LangGraphReactAgent
11
+ from aip_agents.ptc import PromptConfig, PTCSandboxConfig
12
+
13
+
14
+ async def main() -> None:
15
+ """Run a hello-world PTC flow."""
16
+ instruction = (
17
+ "You are a helpful assistant with access to execute_ptc_code. "
18
+ "Use execute_ptc_code to run Python and print output. "
19
+ "The tool returns JSON with ok/stdout/stderr/exit_code."
20
+ )
21
+
22
+ agent = LangGraphReactAgent(
23
+ name="ptc_hello_world",
24
+ instruction=instruction,
25
+ model="openai/gpt-5.2",
26
+ ptc_config=PTCSandboxConfig(enabled=True, sandbox_timeout=180.0, prompt=PromptConfig(mode="index")),
27
+ )
28
+ agent.add_mcp_server(
29
+ {
30
+ "deepwiki": {
31
+ "transport": "streamable-http",
32
+ "url": "https://mcp.deepwiki.com/mcp",
33
+ "headers": {},
34
+ "timeout": 60.0,
35
+ }
36
+ }
37
+ )
38
+
39
+ try:
40
+ response = await agent.arun(
41
+ query="Use execute_ptc_code to print 'Hello, world!' and count the number of words in the output of deepwiki.read_wiki_structure('anthropics/claude-code')."
42
+ )
43
+ print("execute_ptc_code output:", response["output"])
44
+ finally:
45
+ await agent.cleanup()
46
+
47
+
48
+ if __name__ == "__main__":
49
+ asyncio.run(main())
@@ -0,0 +1,83 @@
1
+ """Minimal PTC hello world example with custom tools.
2
+
3
+ Author: Putu Ravindra Wiguna (putu.r.wiguna@gdplabs.id)
4
+
5
+ Required environment variables:
6
+ - OPENAI_API_KEY
7
+ - E2B_API_KEY
8
+ """
9
+
10
+ import asyncio
11
+ import json
12
+ from pathlib import Path
13
+
14
+ from langchain_openai import ChatOpenAI
15
+
16
+ from aip_agents.agent import LangGraphReactAgent
17
+ from aip_agents.examples.tools.multiply_tool import MultiplyTool
18
+ from aip_agents.ptc import PromptConfig, PTCCustomToolConfig, PTCSandboxConfig, file_tool, package_tool
19
+ from aip_agents.tools.time_tool import TimeTool
20
+
21
+
22
+ async def main() -> None:
23
+ """Run a hello-world PTC flow with custom tools."""
24
+ repo_root = Path.cwd()
25
+ multiply_tool_path = repo_root / "aip_agents/examples/tools/multiply_tool.py"
26
+
27
+ instruction = (
28
+ "You are a helpful assistant with access to execute_ptc_code. "
29
+ "Use execute_ptc_code to run Python and print output. "
30
+ "Custom tools are available under tools.custom (import with "
31
+ "'from tools.custom import <tool_name>')."
32
+ )
33
+
34
+ agent = LangGraphReactAgent(
35
+ name="ptc_custom_tools_hello_world",
36
+ instruction=instruction,
37
+ model=ChatOpenAI(model="gpt-5.2"),
38
+ tools=[TimeTool(), MultiplyTool()],
39
+ tool_configs={"multiply": {"offset": 20}},
40
+ ptc_config=PTCSandboxConfig(
41
+ enabled=True,
42
+ sandbox_timeout=180.0,
43
+ prompt=PromptConfig(mode="auto"),
44
+ custom_tools=PTCCustomToolConfig(
45
+ enabled=True,
46
+ bundle_roots=[str(repo_root)],
47
+ requirements=[],
48
+ tools=[
49
+ package_tool(
50
+ "time_tool",
51
+ import_path="aip_agents.tools.time_tool",
52
+ class_name="TimeTool",
53
+ ),
54
+ file_tool(
55
+ "multiply",
56
+ file_path=str(multiply_tool_path),
57
+ class_name="MultiplyTool",
58
+ ),
59
+ ],
60
+ ),
61
+ ),
62
+ )
63
+
64
+ try:
65
+ # Pass tool config at runtime via metadata
66
+ # The multiply tool will use offset=10, so multiply(a=6, b=7) returns 6*7+10=52
67
+ print("execute_ptc_code output: ", end="")
68
+ last_chunk = None
69
+ async for chunk in agent.arun_sse_stream(
70
+ query=("Use execute_ptc_code to import from tools.custom. Print time_tool() and multiply(a=6, b=7)."),
71
+ metadata={"tool_configs": {"multiply": {"offset": 10}}},
72
+ ):
73
+ last_chunk = chunk
74
+ print(json.dumps(chunk))
75
+ print("-" * 20)
76
+ finally:
77
+ await agent.cleanup()
78
+
79
+ print("execute_ptc_code output: ", last_chunk["content"])
80
+
81
+
82
+ if __name__ == "__main__":
83
+ asyncio.run(main())
@@ -0,0 +1,133 @@
1
+ """This is a simple FastAPI app to test Sentry with Open Telemetry from GL Connectors SDK.
2
+
3
+ To run this example, make sure to set the following environment variables:
4
+ SENTRY_DSN
5
+ SENTRY_ENVIRONMENT
6
+ SENTRY_PROJECT
7
+ VERSION_NUMBER
8
+ BUILD_NUMBER
9
+ USE_OPENTELEMETRY
10
+
11
+ Authors:
12
+ Saul Sayers (saul.sayers@gdplabs.id)
13
+ """
14
+
15
+ import io
16
+ import os
17
+ import subprocess
18
+ import sys
19
+ import threading
20
+ import time
21
+
22
+ import uvicorn
23
+ from fastapi import FastAPI
24
+ from fastapi.responses import JSONResponse
25
+ from fastapi.staticfiles import StaticFiles
26
+
27
+ from aip_agents.examples.hello_world_langgraph import langgraph_example
28
+ from aip_agents.sentry import setup_telemetry
29
+ from aip_agents.utils.logger import get_logger
30
+
31
+ logger = get_logger(__name__)
32
+
33
+ BASE_URL = "http://localhost:8585"
34
+ SENTRY_ENVIRONMENT = os.getenv("SENTRY_ENVIRONMENT", "development")
35
+ USE_OPENTELEMETRY = os.getenv("USE_OPENTELEMETRY", "true").lower() == "true"
36
+
37
+
38
+ def fetch_endpoints():
39
+ """Fetch all endpoints from the server."""
40
+ BASE_URL = "http://127.0.0.1:8585"
41
+ endpoints = [
42
+ "/",
43
+ "/langgraph-hello-world",
44
+ "/test-telemetry",
45
+ "/raise-error",
46
+ ]
47
+ for ep in endpoints:
48
+ url = BASE_URL + ep
49
+ try:
50
+ # Because using request.get() will trigger sentry, but the ep name is not saved.
51
+ # Instead of GET /langgraph-hello-world, sentry will save it as GET
52
+ url = f"http://127.0.0.1:8585{ep}"
53
+ result = subprocess.run(["curl", "-i", url], capture_output=True, text=True, check=False)
54
+ logger.info(result.stdout)
55
+ except Exception as e:
56
+ logger.error(f"Error fetching {ep}: {e}")
57
+
58
+
59
+ def create_app() -> FastAPI:
60
+ """Create and configure the FastAPI application.
61
+
62
+ Returns:
63
+ FastAPI: The configured FastAPI application.
64
+ """
65
+ app = FastAPI(
66
+ title="GL Connectors SDK - Sentry with Open Telemetry",
67
+ description="This is a simple FastAPI app to test Sentry with Open Telemetry.",
68
+ version="0.0.1",
69
+ docs_url=None,
70
+ redoc_url="/docs",
71
+ )
72
+
73
+ if os.path.isdir("static"):
74
+ app.mount("/static", StaticFiles(directory="static"), name="static")
75
+ setup_telemetry(app)
76
+
77
+ @app.get("/", tags=["Root"])
78
+ async def index():
79
+ if USE_OPENTELEMETRY:
80
+ return {
81
+ "message": "Application running with Sentry + OpenTelemetry.",
82
+ "telemetry_mode": "Sentry with OpenTelemetry",
83
+ "environment": SENTRY_ENVIRONMENT,
84
+ }
85
+ else:
86
+ return {
87
+ "message": "Application running with Sentry only (no OpenTelemetry).",
88
+ "telemetry_mode": "Sentry only",
89
+ "environment": SENTRY_ENVIRONMENT,
90
+ }
91
+
92
+ @app.get("/langgraph-hello-world", tags=["LangGraph"])
93
+ async def langgraph_hello_world():
94
+ old_stdout = sys.stdout
95
+ sys.stdout = mystdout = io.StringIO()
96
+ try:
97
+ await langgraph_example()
98
+ output = mystdout.getvalue()
99
+ finally:
100
+ sys.stdout = old_stdout
101
+ return JSONResponse(content={"output": output})
102
+
103
+ @app.get("/test-telemetry", tags=["Root"])
104
+ async def test_telemetry():
105
+ return {
106
+ "message": "Telemetry test endpoint called.",
107
+ "using_opentelemetry": USE_OPENTELEMETRY,
108
+ "check": "Check your Sentry dashboard for traces.",
109
+ }
110
+
111
+ @app.get("/raise-error", tags=["Root"])
112
+ async def raise_error():
113
+ raise RuntimeError("This is a test error for Sentry!")
114
+
115
+ return app
116
+
117
+
118
+ def run_server():
119
+ """Run the FastAPI server."""
120
+ uvicorn.run(
121
+ "aip_agents.examples.hello_world_sentry:create_app",
122
+ host="127.0.0.1",
123
+ port=8585,
124
+ factory=True,
125
+ log_level="info",
126
+ )
127
+
128
+
129
+ if __name__ == "__main__":
130
+ server_thread = threading.Thread(target=run_server, daemon=True)
131
+ server_thread.start()
132
+ time.sleep(2)
133
+ fetch_endpoints()
@@ -0,0 +1,273 @@
1
+ """Example demonstrating configurable step limits and delegation depth tracking.
2
+
3
+ This example shows how to:
4
+ 1. Configure maximum steps for an agent
5
+ 2. Configure maximum delegation depth
6
+ 3. Handle step limit exceeded errors gracefully
7
+ 4. Track delegation chains across multi-agent hierarchies
8
+
9
+ Authors:
10
+ Saul Sayers (saul.sayers@gdplabs.id)
11
+ """
12
+
13
+ import asyncio
14
+ import os
15
+
16
+ from langchain_openai import ChatOpenAI
17
+
18
+ from aip_agents.agent import LangGraphReactAgent
19
+ from aip_agents.examples.tools.langchain_arithmetic_tools import add_numbers
20
+ from aip_agents.schema.step_limit import MaxStepsExceededError, StepLimitConfig
21
+ from aip_agents.utils.step_limit_manager import StepLimitManager
22
+
23
+
24
+ def print_config_validation(config: StepLimitConfig | None, context: str):
25
+ """Print step limit configuration validation."""
26
+ print(f"\n{'=' * 60}")
27
+ print(f"Configuration Validation - {context}")
28
+ print(f"{'=' * 60}")
29
+ if config is None:
30
+ print("✓ Config: None (will use platform defaults)")
31
+ print(" Expected: max_steps=25, max_delegation_depth=5")
32
+ else:
33
+ print(f"✓ max_steps: {config.max_steps}")
34
+ print(f"✓ max_delegation_depth: {config.max_delegation_depth}")
35
+
36
+ # Validate ranges
37
+ if 1 <= config.max_steps <= 1000:
38
+ print(" ✓ max_steps is valid (1-1000)")
39
+ else:
40
+ print(" ✗ max_steps is INVALID (should be 1-1000)")
41
+
42
+ if 0 <= config.max_delegation_depth <= 10:
43
+ print(" ✓ max_delegation_depth is valid (0-10)")
44
+ else:
45
+ print(" ✗ max_delegation_depth is INVALID (should be 0-10)")
46
+ print(f"{'=' * 60}\n")
47
+
48
+
49
+ async def test_case_1_success_no_limits():
50
+ """Test Case 1: Success - High limits, no warnings."""
51
+ print("\n" + "=" * 60)
52
+ print("TEST CASE 1: Success - High Limits (No Warnings)")
53
+ print("=" * 60)
54
+
55
+ model = ChatOpenAI(model="gpt-4o-mini", temperature=0)
56
+ tools = [add_numbers]
57
+
58
+ # Very high limits - should complete successfully
59
+ step_limit_config = StepLimitConfig(
60
+ max_steps=100, # High limit
61
+ max_delegation_depth=5, # High depth
62
+ )
63
+
64
+ print_config_validation(step_limit_config, "High Limits")
65
+
66
+ agent = LangGraphReactAgent(
67
+ name="SuccessAgent",
68
+ instruction="You are a helpful math assistant.",
69
+ model=model,
70
+ tools=tools,
71
+ )
72
+
73
+ query = "What is 5 + 3?"
74
+ print(f"Query: {query}")
75
+ print("Expected: Should complete successfully without warnings\n")
76
+
77
+ try:
78
+ response = await agent.arun(
79
+ query=query,
80
+ step_limit_config=step_limit_config,
81
+ configurable={"thread_id": "test_case_1"},
82
+ )
83
+ print(f"✅ SUCCESS: {response['output']}")
84
+ print("✅ Test passed: Agent completed without hitting limits\n")
85
+ except Exception as e:
86
+ print(f"❌ FAILED: {e}\n")
87
+
88
+
89
+ async def test_case_2_parallel_tool_batch_accounting():
90
+ """Test Case 2: Demonstrate that parallel tool batches consume multiple steps."""
91
+ manager = StepLimitManager(StepLimitConfig(max_steps=6))
92
+ print("\n" + "=" * 60)
93
+ print("TEST CASE 2: Parallel Tool Batch Accounting")
94
+ print("=" * 60)
95
+ print("Simulating one agent reasoning step plus 5 parallel tool calls.\n")
96
+
97
+ print(f"Initial steps: {manager.context.current_step}, remaining budget: {manager.context.remaining_step_budget}")
98
+ manager.increment_step() # Agent LLM call
99
+ print(
100
+ f"After agent turn -> steps: {manager.context.current_step}, remaining: {manager.context.remaining_step_budget}"
101
+ )
102
+
103
+ # Simulate a batch of 5 tool calls executed in parallel
104
+ manager.increment_step(count=5)
105
+ print("After 5 parallel tool calls (count=5):")
106
+ print(f"Steps used: {manager.context.current_step}, remaining: {manager.context.remaining_step_budget}")
107
+
108
+ # Ensure limit is enforced now
109
+ try:
110
+ manager.check_step_limit()
111
+ except MaxStepsExceededError as exc:
112
+ print(f"✅ Limit enforcement triggered immediately: {exc}")
113
+ return
114
+
115
+ print("❌ Expected the limit to be hit after consuming 6 steps, but it was not.")
116
+
117
+
118
+ async def test_case_3_step_limit_exceeded():
119
+ """Test Case 3: Step Limit Exceeded - Only 2 steps allowed."""
120
+ print("\n" + "=" * 60)
121
+ print("TEST CASE 3: Step Limit Exceeded (max_steps=2)")
122
+ print("=" * 60)
123
+
124
+ model = ChatOpenAI(model="gpt-4o-mini", temperature=0)
125
+ tools = [add_numbers]
126
+
127
+ # Very low step limit - will hit limit
128
+ step_limit_config = StepLimitConfig(
129
+ max_steps=2, # Only 2 steps: 1 for thinking, 1 for tool call
130
+ max_delegation_depth=0,
131
+ )
132
+
133
+ print_config_validation(step_limit_config, "Very Low Step Limit")
134
+
135
+ agent = LangGraphReactAgent(
136
+ name="LimitedAgent",
137
+ instruction="You are a helpful math assistant. Always use the add_numbers tool.",
138
+ model=model,
139
+ tools=tools,
140
+ )
141
+
142
+ query = "Use the add_numbers tool to calculate 7 + 8, then add 10 to the result"
143
+ print(f"Query: {query}")
144
+ print("Expected: Should hit step limit after 2 steps\n")
145
+ print("Step 0: Initial LLM call")
146
+ print("Step 1: Tool call (add_numbers)")
147
+ print("Step 2: Would be final response, but LIMIT HIT!\n")
148
+
149
+ try:
150
+ response = await agent.arun(
151
+ query=query,
152
+ step_limit_config=step_limit_config,
153
+ configurable={"thread_id": "test_case_3"},
154
+ )
155
+ output = response["output"]
156
+ print(f"Response: {output}\n")
157
+
158
+ # Check if the response indicates limit was hit
159
+ if "exceeded" in output.lower() or "limit" in output.lower():
160
+ print("✅ SUCCESS: Step limit was enforced!")
161
+ print("✅ Test passed: Agent terminated at limit\n")
162
+ else:
163
+ print("⚠️ Agent completed without hitting limit")
164
+ print(" (This might happen if task was very simple)\n")
165
+ except Exception as e:
166
+ print(f"Exception raised: {type(e).__name__}: {e}")
167
+ print("✅ Test passed: Step limit enforced via exception\n")
168
+
169
+
170
+ async def test_case_4_delegation_depth_exceeded():
171
+ """Test Case 4: Delegation Depth Exceeded - Zero depth."""
172
+ print("\n" + "=" * 60)
173
+ print("TEST CASE 4: Delegation Depth Exceeded (depth=0)")
174
+ print("=" * 60)
175
+
176
+ model = ChatOpenAI(model="gpt-4o-mini", temperature=0)
177
+
178
+ # Create sub-agent
179
+ math_agent = LangGraphReactAgent(
180
+ name="MathAgent",
181
+ instruction="You are a math specialist. Use add_numbers tool for calculations.",
182
+ model=model,
183
+ tools=[add_numbers],
184
+ )
185
+
186
+ # Create coordinator
187
+ coordinator = LangGraphReactAgent(
188
+ name="Coordinator",
189
+ instruction="You coordinate tasks. You MUST delegate all math to MathAgent using the delegate_to_agent tool.",
190
+ model=model,
191
+ tools=[],
192
+ )
193
+ coordinator.register_delegation_agents([math_agent])
194
+
195
+ # Zero delegation depth - should block delegation
196
+ step_limit_config = StepLimitConfig(
197
+ max_steps=50, # High steps
198
+ max_delegation_depth=0, # NO delegation allowed!
199
+ )
200
+
201
+ print_config_validation(step_limit_config, "Zero Delegation Depth")
202
+
203
+ query = "Delegate to MathAgent to calculate 20 + 30"
204
+ print(f"Query: {query}")
205
+ print("Expected: Delegation should be BLOCKED (depth=0)\n")
206
+ print("The coordinator will try to delegate but should get an error\n")
207
+
208
+ try:
209
+ response = await coordinator.arun(
210
+ query=query,
211
+ step_limit_config=step_limit_config,
212
+ configurable={"thread_id": "test_case_4"},
213
+ )
214
+ output = response["output"]
215
+ print(f"Response: {output}\n")
216
+
217
+ # Check if delegation was blocked
218
+ if (
219
+ "cannot" in output.lower()
220
+ or "depth" in output.lower()
221
+ or "exceeded" in output.lower()
222
+ or "error" in output.lower()
223
+ ):
224
+ print("✅ SUCCESS: Delegation depth limit enforced!")
225
+ print("✅ Test passed: Delegation was blocked\n")
226
+ else:
227
+ print("⚠️ Agent responded without delegating")
228
+ print(" (Coordinator may have answered directly instead)\n")
229
+ except Exception as e:
230
+ print(f"Exception raised: {type(e).__name__}: {e}")
231
+ if "delegation" in str(e).lower() or "depth" in str(e).lower():
232
+ print("✅ Test passed: Delegation depth enforced via exception\n")
233
+ else:
234
+ print("⚠️ Different error occurred\n")
235
+
236
+
237
+ async def main():
238
+ """Run all test cases."""
239
+ print("=" * 60)
240
+ print("Step Limit Configuration - Test Suite")
241
+ print("=" * 60)
242
+ print("\nRunning 4 test cases:")
243
+ print("1. Success with high limits")
244
+ print("2. Parallel tool batch accounting demo")
245
+ print("3. Step limit exceeded")
246
+ print("4. Delegation depth exceeded")
247
+ print("\nNOTE: Some limits are enforced silently via the agent's")
248
+ print(" internal logic. Check for error messages in responses.")
249
+
250
+ await test_case_1_success_no_limits()
251
+ await test_case_2_parallel_tool_batch_accounting()
252
+ await test_case_3_step_limit_exceeded()
253
+ await test_case_4_delegation_depth_exceeded()
254
+
255
+ print("\n" + "=" * 60)
256
+ print("All test cases completed!")
257
+ print("=" * 60)
258
+ print("\n📝 Summary:")
259
+ print("- Test 1: Should show successful completion")
260
+ print("- Test 2: Shows that parallel tool batches consume multiple steps at once")
261
+ print("- Test 3: Should show step limit enforcement")
262
+ print("- Test 4: Should show delegation blocking")
263
+
264
+
265
+ if __name__ == "__main__":
266
+ # Check for API key
267
+ if not os.getenv("OPENAI_API_KEY"):
268
+ print("ERROR: OPENAI_API_KEY environment variable not set!")
269
+ print("Please set it before running:")
270
+ print('export OPENAI_API_KEY="your-key-here"')
271
+ exit(1)
272
+
273
+ asyncio.run(main())