aip-agents-binary 0.6.4__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 (612) hide show
  1. aip_agents/__init__.py +65 -0
  2. aip_agents/__init__.pyi +19 -0
  3. aip_agents/a2a/__init__.py +19 -0
  4. aip_agents/a2a/__init__.pyi +3 -0
  5. aip_agents/a2a/server/__init__.py +10 -0
  6. aip_agents/a2a/server/__init__.pyi +4 -0
  7. aip_agents/a2a/server/base_executor.py +1086 -0
  8. aip_agents/a2a/server/base_executor.pyi +73 -0
  9. aip_agents/a2a/server/google_adk_executor.py +198 -0
  10. aip_agents/a2a/server/google_adk_executor.pyi +51 -0
  11. aip_agents/a2a/server/langflow_executor.py +180 -0
  12. aip_agents/a2a/server/langflow_executor.pyi +43 -0
  13. aip_agents/a2a/server/langgraph_executor.py +270 -0
  14. aip_agents/a2a/server/langgraph_executor.pyi +47 -0
  15. aip_agents/a2a/types.py +232 -0
  16. aip_agents/a2a/types.pyi +132 -0
  17. aip_agents/agent/__init__.py +27 -0
  18. aip_agents/agent/__init__.pyi +9 -0
  19. aip_agents/agent/base_agent.py +970 -0
  20. aip_agents/agent/base_agent.pyi +221 -0
  21. aip_agents/agent/base_langgraph_agent.py +3037 -0
  22. aip_agents/agent/base_langgraph_agent.pyi +233 -0
  23. aip_agents/agent/google_adk_agent.py +926 -0
  24. aip_agents/agent/google_adk_agent.pyi +141 -0
  25. aip_agents/agent/google_adk_constants.py +6 -0
  26. aip_agents/agent/google_adk_constants.pyi +3 -0
  27. aip_agents/agent/hitl/__init__.py +24 -0
  28. aip_agents/agent/hitl/__init__.pyi +6 -0
  29. aip_agents/agent/hitl/config.py +28 -0
  30. aip_agents/agent/hitl/config.pyi +15 -0
  31. aip_agents/agent/hitl/langgraph_hitl_mixin.py +515 -0
  32. aip_agents/agent/hitl/langgraph_hitl_mixin.pyi +42 -0
  33. aip_agents/agent/hitl/manager.py +532 -0
  34. aip_agents/agent/hitl/manager.pyi +200 -0
  35. aip_agents/agent/hitl/models.py +18 -0
  36. aip_agents/agent/hitl/models.pyi +3 -0
  37. aip_agents/agent/hitl/prompt/__init__.py +9 -0
  38. aip_agents/agent/hitl/prompt/__init__.pyi +4 -0
  39. aip_agents/agent/hitl/prompt/base.py +42 -0
  40. aip_agents/agent/hitl/prompt/base.pyi +24 -0
  41. aip_agents/agent/hitl/prompt/deferred.py +73 -0
  42. aip_agents/agent/hitl/prompt/deferred.pyi +30 -0
  43. aip_agents/agent/hitl/registry.py +149 -0
  44. aip_agents/agent/hitl/registry.pyi +101 -0
  45. aip_agents/agent/interface.py +138 -0
  46. aip_agents/agent/interface.pyi +81 -0
  47. aip_agents/agent/interfaces.py +65 -0
  48. aip_agents/agent/interfaces.pyi +44 -0
  49. aip_agents/agent/langflow_agent.py +464 -0
  50. aip_agents/agent/langflow_agent.pyi +133 -0
  51. aip_agents/agent/langgraph_memory_enhancer_agent.py +767 -0
  52. aip_agents/agent/langgraph_memory_enhancer_agent.pyi +50 -0
  53. aip_agents/agent/langgraph_react_agent.py +2856 -0
  54. aip_agents/agent/langgraph_react_agent.pyi +170 -0
  55. aip_agents/agent/system_instruction_context.py +34 -0
  56. aip_agents/agent/system_instruction_context.pyi +13 -0
  57. aip_agents/clients/__init__.py +10 -0
  58. aip_agents/clients/__init__.pyi +4 -0
  59. aip_agents/clients/langflow/__init__.py +10 -0
  60. aip_agents/clients/langflow/__init__.pyi +4 -0
  61. aip_agents/clients/langflow/client.py +477 -0
  62. aip_agents/clients/langflow/client.pyi +140 -0
  63. aip_agents/clients/langflow/types.py +18 -0
  64. aip_agents/clients/langflow/types.pyi +7 -0
  65. aip_agents/constants.py +23 -0
  66. aip_agents/constants.pyi +7 -0
  67. aip_agents/credentials/manager.py +132 -0
  68. aip_agents/examples/__init__.py +5 -0
  69. aip_agents/examples/__init__.pyi +0 -0
  70. aip_agents/examples/compare_streaming_client.py +783 -0
  71. aip_agents/examples/compare_streaming_client.pyi +48 -0
  72. aip_agents/examples/compare_streaming_server.py +142 -0
  73. aip_agents/examples/compare_streaming_server.pyi +18 -0
  74. aip_agents/examples/hello_world_a2a_google_adk_client.py +49 -0
  75. aip_agents/examples/hello_world_a2a_google_adk_client.pyi +9 -0
  76. aip_agents/examples/hello_world_a2a_google_adk_client_agent.py +48 -0
  77. aip_agents/examples/hello_world_a2a_google_adk_client_agent.pyi +9 -0
  78. aip_agents/examples/hello_world_a2a_google_adk_client_streaming.py +60 -0
  79. aip_agents/examples/hello_world_a2a_google_adk_client_streaming.pyi +9 -0
  80. aip_agents/examples/hello_world_a2a_google_adk_server.py +79 -0
  81. aip_agents/examples/hello_world_a2a_google_adk_server.pyi +15 -0
  82. aip_agents/examples/hello_world_a2a_langchain_client.py +39 -0
  83. aip_agents/examples/hello_world_a2a_langchain_client.pyi +5 -0
  84. aip_agents/examples/hello_world_a2a_langchain_client_agent.py +39 -0
  85. aip_agents/examples/hello_world_a2a_langchain_client_agent.pyi +5 -0
  86. aip_agents/examples/hello_world_a2a_langchain_client_lm_invoker.py +37 -0
  87. aip_agents/examples/hello_world_a2a_langchain_client_lm_invoker.pyi +5 -0
  88. aip_agents/examples/hello_world_a2a_langchain_client_streaming.py +41 -0
  89. aip_agents/examples/hello_world_a2a_langchain_client_streaming.pyi +5 -0
  90. aip_agents/examples/hello_world_a2a_langchain_reference_client_streaming.py +60 -0
  91. aip_agents/examples/hello_world_a2a_langchain_reference_client_streaming.pyi +5 -0
  92. aip_agents/examples/hello_world_a2a_langchain_reference_server.py +105 -0
  93. aip_agents/examples/hello_world_a2a_langchain_reference_server.pyi +15 -0
  94. aip_agents/examples/hello_world_a2a_langchain_server.py +79 -0
  95. aip_agents/examples/hello_world_a2a_langchain_server.pyi +15 -0
  96. aip_agents/examples/hello_world_a2a_langchain_server_lm_invoker.py +78 -0
  97. aip_agents/examples/hello_world_a2a_langchain_server_lm_invoker.pyi +15 -0
  98. aip_agents/examples/hello_world_a2a_langflow_client.py +83 -0
  99. aip_agents/examples/hello_world_a2a_langflow_client.pyi +9 -0
  100. aip_agents/examples/hello_world_a2a_langflow_server.py +82 -0
  101. aip_agents/examples/hello_world_a2a_langflow_server.pyi +14 -0
  102. aip_agents/examples/hello_world_a2a_langgraph_artifact_client.py +73 -0
  103. aip_agents/examples/hello_world_a2a_langgraph_artifact_client.pyi +5 -0
  104. aip_agents/examples/hello_world_a2a_langgraph_artifact_client_streaming.py +76 -0
  105. aip_agents/examples/hello_world_a2a_langgraph_artifact_client_streaming.pyi +5 -0
  106. aip_agents/examples/hello_world_a2a_langgraph_artifact_server.py +92 -0
  107. aip_agents/examples/hello_world_a2a_langgraph_artifact_server.pyi +16 -0
  108. aip_agents/examples/hello_world_a2a_langgraph_client.py +54 -0
  109. aip_agents/examples/hello_world_a2a_langgraph_client.pyi +9 -0
  110. aip_agents/examples/hello_world_a2a_langgraph_client_agent.py +54 -0
  111. aip_agents/examples/hello_world_a2a_langgraph_client_agent.pyi +9 -0
  112. aip_agents/examples/hello_world_a2a_langgraph_client_agent_lm_invoker.py +32 -0
  113. aip_agents/examples/hello_world_a2a_langgraph_client_agent_lm_invoker.pyi +2 -0
  114. aip_agents/examples/hello_world_a2a_langgraph_client_streaming.py +50 -0
  115. aip_agents/examples/hello_world_a2a_langgraph_client_streaming.pyi +9 -0
  116. aip_agents/examples/hello_world_a2a_langgraph_client_streaming_lm_invoker.py +44 -0
  117. aip_agents/examples/hello_world_a2a_langgraph_client_streaming_lm_invoker.pyi +5 -0
  118. aip_agents/examples/hello_world_a2a_langgraph_client_streaming_tool_streaming.py +92 -0
  119. aip_agents/examples/hello_world_a2a_langgraph_client_streaming_tool_streaming.pyi +5 -0
  120. aip_agents/examples/hello_world_a2a_langgraph_server.py +84 -0
  121. aip_agents/examples/hello_world_a2a_langgraph_server.pyi +14 -0
  122. aip_agents/examples/hello_world_a2a_langgraph_server_lm_invoker.py +79 -0
  123. aip_agents/examples/hello_world_a2a_langgraph_server_lm_invoker.pyi +15 -0
  124. aip_agents/examples/hello_world_a2a_langgraph_server_tool_streaming.py +132 -0
  125. aip_agents/examples/hello_world_a2a_langgraph_server_tool_streaming.pyi +15 -0
  126. aip_agents/examples/hello_world_a2a_mcp_langgraph.py +196 -0
  127. aip_agents/examples/hello_world_a2a_mcp_langgraph.pyi +48 -0
  128. aip_agents/examples/hello_world_a2a_three_level_agent_hierarchy_client.py +244 -0
  129. aip_agents/examples/hello_world_a2a_three_level_agent_hierarchy_client.pyi +48 -0
  130. aip_agents/examples/hello_world_a2a_three_level_agent_hierarchy_server.py +251 -0
  131. aip_agents/examples/hello_world_a2a_three_level_agent_hierarchy_server.pyi +45 -0
  132. aip_agents/examples/hello_world_a2a_with_metadata_langchain_client.py +57 -0
  133. aip_agents/examples/hello_world_a2a_with_metadata_langchain_client.pyi +5 -0
  134. aip_agents/examples/hello_world_a2a_with_metadata_langchain_server_lm_invoker.py +80 -0
  135. aip_agents/examples/hello_world_a2a_with_metadata_langchain_server_lm_invoker.pyi +15 -0
  136. aip_agents/examples/hello_world_google_adk.py +41 -0
  137. aip_agents/examples/hello_world_google_adk.pyi +5 -0
  138. aip_agents/examples/hello_world_google_adk_mcp_http.py +34 -0
  139. aip_agents/examples/hello_world_google_adk_mcp_http.pyi +5 -0
  140. aip_agents/examples/hello_world_google_adk_mcp_http_stream.py +40 -0
  141. aip_agents/examples/hello_world_google_adk_mcp_http_stream.pyi +5 -0
  142. aip_agents/examples/hello_world_google_adk_mcp_sse.py +44 -0
  143. aip_agents/examples/hello_world_google_adk_mcp_sse.pyi +5 -0
  144. aip_agents/examples/hello_world_google_adk_mcp_sse_stream.py +48 -0
  145. aip_agents/examples/hello_world_google_adk_mcp_sse_stream.pyi +5 -0
  146. aip_agents/examples/hello_world_google_adk_mcp_stdio.py +44 -0
  147. aip_agents/examples/hello_world_google_adk_mcp_stdio.pyi +5 -0
  148. aip_agents/examples/hello_world_google_adk_mcp_stdio_stream.py +48 -0
  149. aip_agents/examples/hello_world_google_adk_mcp_stdio_stream.pyi +5 -0
  150. aip_agents/examples/hello_world_google_adk_stream.py +44 -0
  151. aip_agents/examples/hello_world_google_adk_stream.pyi +5 -0
  152. aip_agents/examples/hello_world_langchain.py +28 -0
  153. aip_agents/examples/hello_world_langchain.pyi +5 -0
  154. aip_agents/examples/hello_world_langchain_lm_invoker.py +15 -0
  155. aip_agents/examples/hello_world_langchain_lm_invoker.pyi +2 -0
  156. aip_agents/examples/hello_world_langchain_mcp_http.py +34 -0
  157. aip_agents/examples/hello_world_langchain_mcp_http.pyi +5 -0
  158. aip_agents/examples/hello_world_langchain_mcp_http_interactive.py +130 -0
  159. aip_agents/examples/hello_world_langchain_mcp_http_interactive.pyi +16 -0
  160. aip_agents/examples/hello_world_langchain_mcp_http_stream.py +42 -0
  161. aip_agents/examples/hello_world_langchain_mcp_http_stream.pyi +5 -0
  162. aip_agents/examples/hello_world_langchain_mcp_multi_server.py +155 -0
  163. aip_agents/examples/hello_world_langchain_mcp_multi_server.pyi +18 -0
  164. aip_agents/examples/hello_world_langchain_mcp_sse.py +34 -0
  165. aip_agents/examples/hello_world_langchain_mcp_sse.pyi +5 -0
  166. aip_agents/examples/hello_world_langchain_mcp_sse_stream.py +40 -0
  167. aip_agents/examples/hello_world_langchain_mcp_sse_stream.pyi +5 -0
  168. aip_agents/examples/hello_world_langchain_mcp_stdio.py +30 -0
  169. aip_agents/examples/hello_world_langchain_mcp_stdio.pyi +5 -0
  170. aip_agents/examples/hello_world_langchain_mcp_stdio_stream.py +41 -0
  171. aip_agents/examples/hello_world_langchain_mcp_stdio_stream.pyi +5 -0
  172. aip_agents/examples/hello_world_langchain_stream.py +36 -0
  173. aip_agents/examples/hello_world_langchain_stream.pyi +5 -0
  174. aip_agents/examples/hello_world_langchain_stream_lm_invoker.py +39 -0
  175. aip_agents/examples/hello_world_langchain_stream_lm_invoker.pyi +5 -0
  176. aip_agents/examples/hello_world_langflow_agent.py +163 -0
  177. aip_agents/examples/hello_world_langflow_agent.pyi +35 -0
  178. aip_agents/examples/hello_world_langgraph.py +39 -0
  179. aip_agents/examples/hello_world_langgraph.pyi +5 -0
  180. aip_agents/examples/hello_world_langgraph_gl_connector_twitter.py +44 -0
  181. aip_agents/examples/hello_world_langgraph_gl_connector_twitter.pyi +5 -0
  182. aip_agents/examples/hello_world_langgraph_mcp_http.py +31 -0
  183. aip_agents/examples/hello_world_langgraph_mcp_http.pyi +5 -0
  184. aip_agents/examples/hello_world_langgraph_mcp_http_stream.py +34 -0
  185. aip_agents/examples/hello_world_langgraph_mcp_http_stream.pyi +5 -0
  186. aip_agents/examples/hello_world_langgraph_mcp_sse.py +35 -0
  187. aip_agents/examples/hello_world_langgraph_mcp_sse.pyi +5 -0
  188. aip_agents/examples/hello_world_langgraph_mcp_sse_stream.py +50 -0
  189. aip_agents/examples/hello_world_langgraph_mcp_sse_stream.pyi +5 -0
  190. aip_agents/examples/hello_world_langgraph_mcp_stdio.py +35 -0
  191. aip_agents/examples/hello_world_langgraph_mcp_stdio.pyi +5 -0
  192. aip_agents/examples/hello_world_langgraph_mcp_stdio_stream.py +50 -0
  193. aip_agents/examples/hello_world_langgraph_mcp_stdio_stream.pyi +5 -0
  194. aip_agents/examples/hello_world_langgraph_stream.py +43 -0
  195. aip_agents/examples/hello_world_langgraph_stream.pyi +5 -0
  196. aip_agents/examples/hello_world_langgraph_stream_lm_invoker.py +37 -0
  197. aip_agents/examples/hello_world_langgraph_stream_lm_invoker.pyi +5 -0
  198. aip_agents/examples/hello_world_model_switch_cli.py +210 -0
  199. aip_agents/examples/hello_world_model_switch_cli.pyi +30 -0
  200. aip_agents/examples/hello_world_multi_agent_adk.py +75 -0
  201. aip_agents/examples/hello_world_multi_agent_adk.pyi +6 -0
  202. aip_agents/examples/hello_world_multi_agent_langchain.py +54 -0
  203. aip_agents/examples/hello_world_multi_agent_langchain.pyi +5 -0
  204. aip_agents/examples/hello_world_multi_agent_langgraph.py +66 -0
  205. aip_agents/examples/hello_world_multi_agent_langgraph.pyi +5 -0
  206. aip_agents/examples/hello_world_multi_agent_langgraph_lm_invoker.py +69 -0
  207. aip_agents/examples/hello_world_multi_agent_langgraph_lm_invoker.pyi +5 -0
  208. aip_agents/examples/hello_world_pii_logger.py +21 -0
  209. aip_agents/examples/hello_world_pii_logger.pyi +5 -0
  210. aip_agents/examples/hello_world_ptc.py +49 -0
  211. aip_agents/examples/hello_world_ptc.pyi +5 -0
  212. aip_agents/examples/hello_world_sentry.py +133 -0
  213. aip_agents/examples/hello_world_sentry.pyi +21 -0
  214. aip_agents/examples/hello_world_step_limits.py +273 -0
  215. aip_agents/examples/hello_world_step_limits.pyi +17 -0
  216. aip_agents/examples/hello_world_stock_a2a_server.py +103 -0
  217. aip_agents/examples/hello_world_stock_a2a_server.pyi +17 -0
  218. aip_agents/examples/hello_world_tool_output_client.py +55 -0
  219. aip_agents/examples/hello_world_tool_output_client.pyi +5 -0
  220. aip_agents/examples/hello_world_tool_output_server.py +114 -0
  221. aip_agents/examples/hello_world_tool_output_server.pyi +19 -0
  222. aip_agents/examples/hitl_demo.py +724 -0
  223. aip_agents/examples/hitl_demo.pyi +67 -0
  224. aip_agents/examples/mcp_configs/configs.py +63 -0
  225. aip_agents/examples/mcp_servers/common.py +76 -0
  226. aip_agents/examples/mcp_servers/mcp_name.py +29 -0
  227. aip_agents/examples/mcp_servers/mcp_server_http.py +19 -0
  228. aip_agents/examples/mcp_servers/mcp_server_sse.py +19 -0
  229. aip_agents/examples/mcp_servers/mcp_server_stdio.py +19 -0
  230. aip_agents/examples/mcp_servers/mcp_time.py +10 -0
  231. aip_agents/examples/pii_demo_langgraph_client.py +69 -0
  232. aip_agents/examples/pii_demo_langgraph_client.pyi +5 -0
  233. aip_agents/examples/pii_demo_langgraph_server.py +126 -0
  234. aip_agents/examples/pii_demo_langgraph_server.pyi +20 -0
  235. aip_agents/examples/pii_demo_multi_agent_client.py +80 -0
  236. aip_agents/examples/pii_demo_multi_agent_client.pyi +5 -0
  237. aip_agents/examples/pii_demo_multi_agent_server.py +247 -0
  238. aip_agents/examples/pii_demo_multi_agent_server.pyi +40 -0
  239. aip_agents/examples/todolist_planning_a2a_langchain_client.py +70 -0
  240. aip_agents/examples/todolist_planning_a2a_langchain_client.pyi +5 -0
  241. aip_agents/examples/todolist_planning_a2a_langgraph_server.py +88 -0
  242. aip_agents/examples/todolist_planning_a2a_langgraph_server.pyi +19 -0
  243. aip_agents/examples/tools/__init__.py +27 -0
  244. aip_agents/examples/tools/__init__.pyi +9 -0
  245. aip_agents/examples/tools/adk_arithmetic_tools.py +36 -0
  246. aip_agents/examples/tools/adk_arithmetic_tools.pyi +24 -0
  247. aip_agents/examples/tools/adk_weather_tool.py +60 -0
  248. aip_agents/examples/tools/adk_weather_tool.pyi +18 -0
  249. aip_agents/examples/tools/data_generator_tool.py +103 -0
  250. aip_agents/examples/tools/data_generator_tool.pyi +15 -0
  251. aip_agents/examples/tools/data_visualization_tool.py +312 -0
  252. aip_agents/examples/tools/data_visualization_tool.pyi +19 -0
  253. aip_agents/examples/tools/image_artifact_tool.py +136 -0
  254. aip_agents/examples/tools/image_artifact_tool.pyi +26 -0
  255. aip_agents/examples/tools/langchain_arithmetic_tools.py +26 -0
  256. aip_agents/examples/tools/langchain_arithmetic_tools.pyi +17 -0
  257. aip_agents/examples/tools/langchain_currency_exchange_tool.py +88 -0
  258. aip_agents/examples/tools/langchain_currency_exchange_tool.pyi +20 -0
  259. aip_agents/examples/tools/langchain_graph_artifact_tool.py +172 -0
  260. aip_agents/examples/tools/langchain_graph_artifact_tool.pyi +25 -0
  261. aip_agents/examples/tools/langchain_weather_tool.py +48 -0
  262. aip_agents/examples/tools/langchain_weather_tool.pyi +19 -0
  263. aip_agents/examples/tools/langgraph_streaming_tool.py +130 -0
  264. aip_agents/examples/tools/langgraph_streaming_tool.pyi +43 -0
  265. aip_agents/examples/tools/mock_retrieval_tool.py +56 -0
  266. aip_agents/examples/tools/mock_retrieval_tool.pyi +13 -0
  267. aip_agents/examples/tools/pii_demo_tools.py +189 -0
  268. aip_agents/examples/tools/pii_demo_tools.pyi +54 -0
  269. aip_agents/examples/tools/random_chart_tool.py +142 -0
  270. aip_agents/examples/tools/random_chart_tool.pyi +20 -0
  271. aip_agents/examples/tools/serper_tool.py +202 -0
  272. aip_agents/examples/tools/serper_tool.pyi +16 -0
  273. aip_agents/examples/tools/stock_tools.py +82 -0
  274. aip_agents/examples/tools/stock_tools.pyi +36 -0
  275. aip_agents/examples/tools/table_generator_tool.py +167 -0
  276. aip_agents/examples/tools/table_generator_tool.pyi +22 -0
  277. aip_agents/examples/tools/time_tool.py +82 -0
  278. aip_agents/examples/tools/time_tool.pyi +15 -0
  279. aip_agents/examples/tools/weather_forecast_tool.py +38 -0
  280. aip_agents/examples/tools/weather_forecast_tool.pyi +14 -0
  281. aip_agents/executor/agent_executor.py +473 -0
  282. aip_agents/executor/base.py +48 -0
  283. aip_agents/guardrails/__init__.py +83 -0
  284. aip_agents/guardrails/__init__.pyi +6 -0
  285. aip_agents/guardrails/engines/__init__.py +69 -0
  286. aip_agents/guardrails/engines/__init__.pyi +4 -0
  287. aip_agents/guardrails/engines/base.py +90 -0
  288. aip_agents/guardrails/engines/base.pyi +61 -0
  289. aip_agents/guardrails/engines/nemo.py +101 -0
  290. aip_agents/guardrails/engines/nemo.pyi +46 -0
  291. aip_agents/guardrails/engines/phrase_matcher.py +113 -0
  292. aip_agents/guardrails/engines/phrase_matcher.pyi +48 -0
  293. aip_agents/guardrails/exceptions.py +39 -0
  294. aip_agents/guardrails/exceptions.pyi +23 -0
  295. aip_agents/guardrails/manager.py +163 -0
  296. aip_agents/guardrails/manager.pyi +42 -0
  297. aip_agents/guardrails/middleware.py +199 -0
  298. aip_agents/guardrails/middleware.pyi +87 -0
  299. aip_agents/guardrails/schemas.py +63 -0
  300. aip_agents/guardrails/schemas.pyi +43 -0
  301. aip_agents/guardrails/utils.py +45 -0
  302. aip_agents/guardrails/utils.pyi +19 -0
  303. aip_agents/mcp/__init__.py +1 -0
  304. aip_agents/mcp/__init__.pyi +0 -0
  305. aip_agents/mcp/client/__init__.py +14 -0
  306. aip_agents/mcp/client/__init__.pyi +5 -0
  307. aip_agents/mcp/client/base_mcp_client.py +369 -0
  308. aip_agents/mcp/client/base_mcp_client.pyi +148 -0
  309. aip_agents/mcp/client/connection_manager.py +228 -0
  310. aip_agents/mcp/client/connection_manager.pyi +51 -0
  311. aip_agents/mcp/client/google_adk/__init__.py +11 -0
  312. aip_agents/mcp/client/google_adk/__init__.pyi +3 -0
  313. aip_agents/mcp/client/google_adk/client.py +381 -0
  314. aip_agents/mcp/client/google_adk/client.pyi +75 -0
  315. aip_agents/mcp/client/langchain/__init__.py +11 -0
  316. aip_agents/mcp/client/langchain/__init__.pyi +3 -0
  317. aip_agents/mcp/client/langchain/client.py +265 -0
  318. aip_agents/mcp/client/langchain/client.pyi +48 -0
  319. aip_agents/mcp/client/persistent_session.py +612 -0
  320. aip_agents/mcp/client/persistent_session.pyi +122 -0
  321. aip_agents/mcp/client/session_pool.py +351 -0
  322. aip_agents/mcp/client/session_pool.pyi +101 -0
  323. aip_agents/mcp/client/transports.py +263 -0
  324. aip_agents/mcp/client/transports.pyi +132 -0
  325. aip_agents/mcp/utils/__init__.py +7 -0
  326. aip_agents/mcp/utils/__init__.pyi +0 -0
  327. aip_agents/mcp/utils/config_validator.py +139 -0
  328. aip_agents/mcp/utils/config_validator.pyi +82 -0
  329. aip_agents/memory/__init__.py +14 -0
  330. aip_agents/memory/__init__.pyi +5 -0
  331. aip_agents/memory/adapters/__init__.py +10 -0
  332. aip_agents/memory/adapters/__init__.pyi +4 -0
  333. aip_agents/memory/adapters/base_adapter.py +811 -0
  334. aip_agents/memory/adapters/base_adapter.pyi +176 -0
  335. aip_agents/memory/adapters/mem0.py +84 -0
  336. aip_agents/memory/adapters/mem0.pyi +22 -0
  337. aip_agents/memory/base.py +84 -0
  338. aip_agents/memory/base.pyi +60 -0
  339. aip_agents/memory/constants.py +49 -0
  340. aip_agents/memory/constants.pyi +25 -0
  341. aip_agents/memory/factory.py +86 -0
  342. aip_agents/memory/factory.pyi +24 -0
  343. aip_agents/memory/guidance.py +20 -0
  344. aip_agents/memory/guidance.pyi +3 -0
  345. aip_agents/memory/simple_memory.py +47 -0
  346. aip_agents/memory/simple_memory.pyi +23 -0
  347. aip_agents/middleware/__init__.py +17 -0
  348. aip_agents/middleware/__init__.pyi +5 -0
  349. aip_agents/middleware/base.py +96 -0
  350. aip_agents/middleware/base.pyi +75 -0
  351. aip_agents/middleware/manager.py +150 -0
  352. aip_agents/middleware/manager.pyi +84 -0
  353. aip_agents/middleware/todolist.py +274 -0
  354. aip_agents/middleware/todolist.pyi +125 -0
  355. aip_agents/ptc/__init__.py +48 -0
  356. aip_agents/ptc/__init__.pyi +10 -0
  357. aip_agents/ptc/doc_gen.py +122 -0
  358. aip_agents/ptc/doc_gen.pyi +40 -0
  359. aip_agents/ptc/exceptions.py +39 -0
  360. aip_agents/ptc/exceptions.pyi +22 -0
  361. aip_agents/ptc/executor.py +143 -0
  362. aip_agents/ptc/executor.pyi +73 -0
  363. aip_agents/ptc/mcp/__init__.py +45 -0
  364. aip_agents/ptc/mcp/__init__.pyi +7 -0
  365. aip_agents/ptc/mcp/sandbox_bridge.py +668 -0
  366. aip_agents/ptc/mcp/sandbox_bridge.pyi +47 -0
  367. aip_agents/ptc/mcp/templates/__init__.py +1 -0
  368. aip_agents/ptc/mcp/templates/__init__.pyi +0 -0
  369. aip_agents/ptc/mcp/templates/mcp_client.py.template +239 -0
  370. aip_agents/ptc/naming.py +184 -0
  371. aip_agents/ptc/naming.pyi +76 -0
  372. aip_agents/ptc/payload.py +26 -0
  373. aip_agents/ptc/payload.pyi +15 -0
  374. aip_agents/ptc/prompt_builder.py +571 -0
  375. aip_agents/ptc/prompt_builder.pyi +55 -0
  376. aip_agents/ptc/ptc_helper.py +16 -0
  377. aip_agents/ptc/ptc_helper.pyi +1 -0
  378. aip_agents/ptc/sandbox_bridge.py +58 -0
  379. aip_agents/ptc/sandbox_bridge.pyi +25 -0
  380. aip_agents/ptc/template_utils.py +33 -0
  381. aip_agents/ptc/template_utils.pyi +13 -0
  382. aip_agents/ptc/templates/__init__.py +1 -0
  383. aip_agents/ptc/templates/__init__.pyi +0 -0
  384. aip_agents/ptc/templates/ptc_helper.py.template +134 -0
  385. aip_agents/sandbox/__init__.py +43 -0
  386. aip_agents/sandbox/__init__.pyi +5 -0
  387. aip_agents/sandbox/defaults.py +9 -0
  388. aip_agents/sandbox/defaults.pyi +2 -0
  389. aip_agents/sandbox/e2b_runtime.py +267 -0
  390. aip_agents/sandbox/e2b_runtime.pyi +51 -0
  391. aip_agents/sandbox/template_builder.py +131 -0
  392. aip_agents/sandbox/template_builder.pyi +36 -0
  393. aip_agents/sandbox/types.py +24 -0
  394. aip_agents/sandbox/types.pyi +14 -0
  395. aip_agents/sandbox/validation.py +50 -0
  396. aip_agents/sandbox/validation.pyi +20 -0
  397. aip_agents/schema/__init__.py +69 -0
  398. aip_agents/schema/__init__.pyi +9 -0
  399. aip_agents/schema/a2a.py +56 -0
  400. aip_agents/schema/a2a.pyi +40 -0
  401. aip_agents/schema/agent.py +111 -0
  402. aip_agents/schema/agent.pyi +65 -0
  403. aip_agents/schema/hitl.py +157 -0
  404. aip_agents/schema/hitl.pyi +89 -0
  405. aip_agents/schema/langgraph.py +37 -0
  406. aip_agents/schema/langgraph.pyi +28 -0
  407. aip_agents/schema/model_id.py +97 -0
  408. aip_agents/schema/model_id.pyi +54 -0
  409. aip_agents/schema/step_limit.py +108 -0
  410. aip_agents/schema/step_limit.pyi +63 -0
  411. aip_agents/schema/storage.py +40 -0
  412. aip_agents/schema/storage.pyi +21 -0
  413. aip_agents/sentry/__init__.py +11 -0
  414. aip_agents/sentry/__init__.pyi +3 -0
  415. aip_agents/sentry/sentry.py +151 -0
  416. aip_agents/sentry/sentry.pyi +48 -0
  417. aip_agents/storage/__init__.py +41 -0
  418. aip_agents/storage/__init__.pyi +8 -0
  419. aip_agents/storage/base.py +85 -0
  420. aip_agents/storage/base.pyi +58 -0
  421. aip_agents/storage/clients/__init__.py +12 -0
  422. aip_agents/storage/clients/__init__.pyi +3 -0
  423. aip_agents/storage/clients/minio_client.py +318 -0
  424. aip_agents/storage/clients/minio_client.pyi +137 -0
  425. aip_agents/storage/config.py +62 -0
  426. aip_agents/storage/config.pyi +29 -0
  427. aip_agents/storage/providers/__init__.py +15 -0
  428. aip_agents/storage/providers/__init__.pyi +5 -0
  429. aip_agents/storage/providers/base.py +106 -0
  430. aip_agents/storage/providers/base.pyi +88 -0
  431. aip_agents/storage/providers/memory.py +114 -0
  432. aip_agents/storage/providers/memory.pyi +79 -0
  433. aip_agents/storage/providers/object_storage.py +214 -0
  434. aip_agents/storage/providers/object_storage.pyi +98 -0
  435. aip_agents/tools/__init__.py +64 -0
  436. aip_agents/tools/__init__.pyi +11 -0
  437. aip_agents/tools/browser_use/__init__.py +82 -0
  438. aip_agents/tools/browser_use/__init__.pyi +14 -0
  439. aip_agents/tools/browser_use/action_parser.py +103 -0
  440. aip_agents/tools/browser_use/action_parser.pyi +18 -0
  441. aip_agents/tools/browser_use/browser_use_tool.py +1120 -0
  442. aip_agents/tools/browser_use/browser_use_tool.pyi +50 -0
  443. aip_agents/tools/browser_use/llm_config.py +120 -0
  444. aip_agents/tools/browser_use/llm_config.pyi +52 -0
  445. aip_agents/tools/browser_use/minio_storage.py +198 -0
  446. aip_agents/tools/browser_use/minio_storage.pyi +109 -0
  447. aip_agents/tools/browser_use/schemas.py +119 -0
  448. aip_agents/tools/browser_use/schemas.pyi +32 -0
  449. aip_agents/tools/browser_use/session.py +76 -0
  450. aip_agents/tools/browser_use/session.pyi +4 -0
  451. aip_agents/tools/browser_use/session_errors.py +132 -0
  452. aip_agents/tools/browser_use/session_errors.pyi +53 -0
  453. aip_agents/tools/browser_use/steel_session_recording.py +317 -0
  454. aip_agents/tools/browser_use/steel_session_recording.pyi +63 -0
  455. aip_agents/tools/browser_use/streaming.py +815 -0
  456. aip_agents/tools/browser_use/streaming.pyi +81 -0
  457. aip_agents/tools/browser_use/structured_data_parser.py +257 -0
  458. aip_agents/tools/browser_use/structured_data_parser.pyi +86 -0
  459. aip_agents/tools/browser_use/structured_data_recovery.py +204 -0
  460. aip_agents/tools/browser_use/structured_data_recovery.pyi +43 -0
  461. aip_agents/tools/browser_use/types.py +78 -0
  462. aip_agents/tools/browser_use/types.pyi +45 -0
  463. aip_agents/tools/code_sandbox/__init__.py +26 -0
  464. aip_agents/tools/code_sandbox/__init__.pyi +3 -0
  465. aip_agents/tools/code_sandbox/constant.py +13 -0
  466. aip_agents/tools/code_sandbox/constant.pyi +4 -0
  467. aip_agents/tools/code_sandbox/e2b_cloud_sandbox_extended.py +306 -0
  468. aip_agents/tools/code_sandbox/e2b_cloud_sandbox_extended.pyi +102 -0
  469. aip_agents/tools/code_sandbox/e2b_sandbox_tool.py +411 -0
  470. aip_agents/tools/code_sandbox/e2b_sandbox_tool.pyi +29 -0
  471. aip_agents/tools/constants.py +177 -0
  472. aip_agents/tools/constants.pyi +138 -0
  473. aip_agents/tools/date_range_tool.py +554 -0
  474. aip_agents/tools/date_range_tool.pyi +21 -0
  475. aip_agents/tools/document_loader/__init__.py +44 -0
  476. aip_agents/tools/document_loader/__init__.pyi +7 -0
  477. aip_agents/tools/document_loader/base_reader.py +302 -0
  478. aip_agents/tools/document_loader/base_reader.pyi +75 -0
  479. aip_agents/tools/document_loader/docx_reader_tool.py +68 -0
  480. aip_agents/tools/document_loader/docx_reader_tool.pyi +10 -0
  481. aip_agents/tools/document_loader/excel_reader_tool.py +171 -0
  482. aip_agents/tools/document_loader/excel_reader_tool.pyi +26 -0
  483. aip_agents/tools/document_loader/pdf_reader_tool.py +79 -0
  484. aip_agents/tools/document_loader/pdf_reader_tool.pyi +11 -0
  485. aip_agents/tools/document_loader/pdf_splitter.py +169 -0
  486. aip_agents/tools/document_loader/pdf_splitter.pyi +18 -0
  487. aip_agents/tools/execute_ptc_code.py +308 -0
  488. aip_agents/tools/execute_ptc_code.pyi +90 -0
  489. aip_agents/tools/gl_connector/__init__.py +5 -0
  490. aip_agents/tools/gl_connector/__init__.pyi +3 -0
  491. aip_agents/tools/gl_connector/tool.py +383 -0
  492. aip_agents/tools/gl_connector/tool.pyi +74 -0
  493. aip_agents/tools/gl_connector_tools.py +119 -0
  494. aip_agents/tools/gl_connector_tools.pyi +39 -0
  495. aip_agents/tools/memory_search/__init__.py +29 -0
  496. aip_agents/tools/memory_search/__init__.pyi +5 -0
  497. aip_agents/tools/memory_search/base.py +200 -0
  498. aip_agents/tools/memory_search/base.pyi +69 -0
  499. aip_agents/tools/memory_search/mem0.py +365 -0
  500. aip_agents/tools/memory_search/mem0.pyi +29 -0
  501. aip_agents/tools/memory_search/schema.py +81 -0
  502. aip_agents/tools/memory_search/schema.pyi +25 -0
  503. aip_agents/tools/memory_search_tool.py +34 -0
  504. aip_agents/tools/memory_search_tool.pyi +3 -0
  505. aip_agents/tools/time_tool.py +117 -0
  506. aip_agents/tools/time_tool.pyi +16 -0
  507. aip_agents/tools/tool_config_injector.py +300 -0
  508. aip_agents/tools/tool_config_injector.pyi +26 -0
  509. aip_agents/tools/web_search/__init__.py +15 -0
  510. aip_agents/tools/web_search/__init__.pyi +3 -0
  511. aip_agents/tools/web_search/serper_tool.py +187 -0
  512. aip_agents/tools/web_search/serper_tool.pyi +19 -0
  513. aip_agents/types/__init__.py +70 -0
  514. aip_agents/types/__init__.pyi +36 -0
  515. aip_agents/types/a2a_events.py +13 -0
  516. aip_agents/types/a2a_events.pyi +3 -0
  517. aip_agents/utils/__init__.py +79 -0
  518. aip_agents/utils/__init__.pyi +11 -0
  519. aip_agents/utils/a2a_connector.py +1757 -0
  520. aip_agents/utils/a2a_connector.pyi +146 -0
  521. aip_agents/utils/artifact_helpers.py +502 -0
  522. aip_agents/utils/artifact_helpers.pyi +203 -0
  523. aip_agents/utils/constants.py +22 -0
  524. aip_agents/utils/constants.pyi +10 -0
  525. aip_agents/utils/datetime/__init__.py +34 -0
  526. aip_agents/utils/datetime/__init__.pyi +4 -0
  527. aip_agents/utils/datetime/normalization.py +231 -0
  528. aip_agents/utils/datetime/normalization.pyi +95 -0
  529. aip_agents/utils/datetime/timezone.py +206 -0
  530. aip_agents/utils/datetime/timezone.pyi +48 -0
  531. aip_agents/utils/env_loader.py +27 -0
  532. aip_agents/utils/env_loader.pyi +10 -0
  533. aip_agents/utils/event_handler_registry.py +58 -0
  534. aip_agents/utils/event_handler_registry.pyi +23 -0
  535. aip_agents/utils/file_prompt_utils.py +176 -0
  536. aip_agents/utils/file_prompt_utils.pyi +21 -0
  537. aip_agents/utils/final_response_builder.py +211 -0
  538. aip_agents/utils/final_response_builder.pyi +34 -0
  539. aip_agents/utils/formatter_llm_client.py +231 -0
  540. aip_agents/utils/formatter_llm_client.pyi +71 -0
  541. aip_agents/utils/langgraph/__init__.py +19 -0
  542. aip_agents/utils/langgraph/__init__.pyi +3 -0
  543. aip_agents/utils/langgraph/converter.py +128 -0
  544. aip_agents/utils/langgraph/converter.pyi +49 -0
  545. aip_agents/utils/langgraph/tool_managers/__init__.py +15 -0
  546. aip_agents/utils/langgraph/tool_managers/__init__.pyi +5 -0
  547. aip_agents/utils/langgraph/tool_managers/a2a_tool_manager.py +99 -0
  548. aip_agents/utils/langgraph/tool_managers/a2a_tool_manager.pyi +35 -0
  549. aip_agents/utils/langgraph/tool_managers/base_tool_manager.py +66 -0
  550. aip_agents/utils/langgraph/tool_managers/base_tool_manager.pyi +48 -0
  551. aip_agents/utils/langgraph/tool_managers/delegation_tool_manager.py +1096 -0
  552. aip_agents/utils/langgraph/tool_managers/delegation_tool_manager.pyi +56 -0
  553. aip_agents/utils/langgraph/tool_output_management.py +1047 -0
  554. aip_agents/utils/langgraph/tool_output_management.pyi +329 -0
  555. aip_agents/utils/logger.py +195 -0
  556. aip_agents/utils/logger.pyi +60 -0
  557. aip_agents/utils/metadata/__init__.py +27 -0
  558. aip_agents/utils/metadata/__init__.pyi +5 -0
  559. aip_agents/utils/metadata/activity_metadata_helper.py +407 -0
  560. aip_agents/utils/metadata/activity_metadata_helper.pyi +25 -0
  561. aip_agents/utils/metadata/activity_narrative/__init__.py +35 -0
  562. aip_agents/utils/metadata/activity_narrative/__init__.pyi +7 -0
  563. aip_agents/utils/metadata/activity_narrative/builder.py +817 -0
  564. aip_agents/utils/metadata/activity_narrative/builder.pyi +35 -0
  565. aip_agents/utils/metadata/activity_narrative/constants.py +51 -0
  566. aip_agents/utils/metadata/activity_narrative/constants.pyi +10 -0
  567. aip_agents/utils/metadata/activity_narrative/context.py +49 -0
  568. aip_agents/utils/metadata/activity_narrative/context.pyi +32 -0
  569. aip_agents/utils/metadata/activity_narrative/formatters.py +230 -0
  570. aip_agents/utils/metadata/activity_narrative/formatters.pyi +48 -0
  571. aip_agents/utils/metadata/activity_narrative/utils.py +35 -0
  572. aip_agents/utils/metadata/activity_narrative/utils.pyi +12 -0
  573. aip_agents/utils/metadata/schemas/__init__.py +16 -0
  574. aip_agents/utils/metadata/schemas/__init__.pyi +4 -0
  575. aip_agents/utils/metadata/schemas/activity_schema.py +29 -0
  576. aip_agents/utils/metadata/schemas/activity_schema.pyi +18 -0
  577. aip_agents/utils/metadata/schemas/thinking_schema.py +31 -0
  578. aip_agents/utils/metadata/schemas/thinking_schema.pyi +20 -0
  579. aip_agents/utils/metadata/thinking_metadata_helper.py +38 -0
  580. aip_agents/utils/metadata/thinking_metadata_helper.pyi +4 -0
  581. aip_agents/utils/metadata_helper.py +358 -0
  582. aip_agents/utils/metadata_helper.pyi +117 -0
  583. aip_agents/utils/name_preprocessor/__init__.py +17 -0
  584. aip_agents/utils/name_preprocessor/__init__.pyi +6 -0
  585. aip_agents/utils/name_preprocessor/base_name_preprocessor.py +73 -0
  586. aip_agents/utils/name_preprocessor/base_name_preprocessor.pyi +52 -0
  587. aip_agents/utils/name_preprocessor/google_name_preprocessor.py +100 -0
  588. aip_agents/utils/name_preprocessor/google_name_preprocessor.pyi +38 -0
  589. aip_agents/utils/name_preprocessor/name_preprocessor.py +87 -0
  590. aip_agents/utils/name_preprocessor/name_preprocessor.pyi +41 -0
  591. aip_agents/utils/name_preprocessor/openai_name_preprocessor.py +48 -0
  592. aip_agents/utils/name_preprocessor/openai_name_preprocessor.pyi +34 -0
  593. aip_agents/utils/pii/__init__.py +25 -0
  594. aip_agents/utils/pii/__init__.pyi +5 -0
  595. aip_agents/utils/pii/pii_handler.py +397 -0
  596. aip_agents/utils/pii/pii_handler.pyi +96 -0
  597. aip_agents/utils/pii/pii_helper.py +207 -0
  598. aip_agents/utils/pii/pii_helper.pyi +78 -0
  599. aip_agents/utils/pii/uuid_deanonymizer_mapping.py +195 -0
  600. aip_agents/utils/pii/uuid_deanonymizer_mapping.pyi +73 -0
  601. aip_agents/utils/reference_helper.py +273 -0
  602. aip_agents/utils/reference_helper.pyi +81 -0
  603. aip_agents/utils/sse_chunk_transformer.py +831 -0
  604. aip_agents/utils/sse_chunk_transformer.pyi +166 -0
  605. aip_agents/utils/step_limit_manager.py +265 -0
  606. aip_agents/utils/step_limit_manager.pyi +112 -0
  607. aip_agents/utils/token_usage_helper.py +156 -0
  608. aip_agents/utils/token_usage_helper.pyi +60 -0
  609. aip_agents_binary-0.6.4.dist-info/METADATA +673 -0
  610. aip_agents_binary-0.6.4.dist-info/RECORD +612 -0
  611. aip_agents_binary-0.6.4.dist-info/WHEEL +5 -0
  612. aip_agents_binary-0.6.4.dist-info/top_level.txt +1 -0
@@ -0,0 +1,1096 @@
1
+ """Delegation tool manager for LangGraph agents.
2
+
3
+ This module provides the DelegationToolManager class that converts internal
4
+ agent instances into LangChain tools for delegation within LangGraph agents.
5
+ """
6
+
7
+ import uuid
8
+ from contextvars import ContextVar
9
+ from typing import Any
10
+
11
+ from langchain_core.runnables import RunnableConfig
12
+ from langchain_core.tools import BaseTool, tool
13
+ from langgraph.config import get_stream_writer
14
+ from langgraph.types import Command, StreamWriter
15
+
16
+ import aip_agents.agent.base_langgraph_agent as bla
17
+ from aip_agents.agent.base_agent import BaseAgent
18
+ from aip_agents.schema.step_limit import MaxDelegationDepthExceededError
19
+ from aip_agents.types import A2AEvent, A2AStreamEventType
20
+ from aip_agents.utils.artifact_helpers import extract_artifacts_from_agent_response
21
+ from aip_agents.utils.langgraph.tool_managers.base_tool_manager import BaseLangGraphToolManager
22
+ from aip_agents.utils.logger import get_logger
23
+ from aip_agents.utils.metadata_helper import MetadataFieldKeys, get_next_step_number
24
+ from aip_agents.utils.pii.pii_helper import (
25
+ anonymize_final_response_content,
26
+ extract_pii_mapping_from_agent_response,
27
+ )
28
+ from aip_agents.utils.reference_helper import extract_references_from_agent_response
29
+ from aip_agents.utils.step_limit_manager import (
30
+ _DELEGATION_CHAIN_CVAR,
31
+ _DELEGATION_DEPTH_CVAR,
32
+ _REMAINING_STEP_BUDGET_CVAR,
33
+ _STEP_LIMIT_CONFIG_CVAR,
34
+ StepLimitManager,
35
+ )
36
+ from aip_agents.utils.token_usage_helper import (
37
+ STEP_USAGE_KEY,
38
+ TOTAL_USAGE_KEY,
39
+ USAGE_METADATA_KEY,
40
+ extract_token_usage_from_agent_response,
41
+ )
42
+
43
+ # Context variable to carry parent step id from coordinator to sub-agent as a fallback
44
+ _DELEGATION_PARENT_STEP_ID_CVAR: ContextVar[str | None] = ContextVar("delegation_parent_step_id", default=None)
45
+ # Track the last sub-agent TOOL_CALL step_id so sub-agent TOOL_RESULT can link to it
46
+ _DELEGATION_SUB_START_STEP_CVAR: ContextVar[dict[str, str] | None] = ContextVar(
47
+ "delegation_sub_start_step", default=None
48
+ )
49
+
50
+ logger = get_logger(__name__)
51
+
52
+ # Constants for response keys
53
+ OUTPUT_KEY = "output"
54
+ RESULT_KEY = "result"
55
+ ARTIFACTS_KEY = "artifacts"
56
+ METADATA_KEY = "metadata"
57
+
58
+ # Internal metadata keys to filter out
59
+ METADATA_INTERNAL_PREFIXES = ["__", "langgraph_", "langchain_"]
60
+ METADATA_INTERNAL_KEYS = {"step_id", "previous_step_ids", "agent_name"}
61
+ AGENT_RUN_A2A_STREAMING_METHOD = "arun_a2a_stream"
62
+
63
+
64
+ class DelegationToolManager(BaseLangGraphToolManager):
65
+ """Manages internal agent delegation tools for LangGraph agents.
66
+
67
+ This tool manager converts internal agent instances into LangChain tools
68
+ that can be used for task delegation within a unified ToolNode. Each
69
+ delegated agent becomes a tool that the coordinator can call.
70
+
71
+ Simplified version following legacy BaseLangChainAgent patterns.
72
+ """
73
+
74
+ def __init__(self, parent_agent: BaseAgent | None = None):
75
+ """Initialize the delegation tool manager.
76
+
77
+ Args:
78
+ parent_agent: The parent agent that creates delegation tools, used for parent step lookup.
79
+ """
80
+ super().__init__()
81
+ self.registered_agents: list[BaseAgent] = []
82
+ self.parent_agent = parent_agent
83
+
84
+ def register_resources(self, agents: list[BaseAgent]) -> list[BaseTool]:
85
+ """Register internal agents for delegation and convert them to tools.
86
+
87
+ Args:
88
+ agents: List of BaseAgent instances for internal task delegation.
89
+
90
+ Returns:
91
+ List of created delegation tools.
92
+ """
93
+ self.registered_agents = list(agents)
94
+ self.created_tools = []
95
+
96
+ for agent in agents:
97
+ delegation_tool = self._create_delegation_tool_streaming(agent)
98
+ self.created_tools.append(delegation_tool)
99
+
100
+ logger.info(
101
+ f"DelegationToolManager: Created {len(self.created_tools)} streaming delegation tools "
102
+ f"for {len(agents)} agents"
103
+ )
104
+ return self.created_tools
105
+
106
+ def get_resource_names(self) -> list[str]:
107
+ """Get names of all registered delegation agents.
108
+
109
+ Returns:
110
+ list[str]: A list of names of all registered delegation agents.
111
+ """
112
+ return [agent.name for agent in self.registered_agents]
113
+
114
+ def _create_delegation_tool_streaming(self, agent: BaseAgent) -> BaseTool:
115
+ """Create a LangChain tool for agent delegation with real-time streaming support.
116
+
117
+ This version uses async streaming to provide real-time tool call and artifact visibility.
118
+
119
+ Args:
120
+ agent: The agent to create a delegation tool for.
121
+
122
+ Returns:
123
+ BaseTool: An async LangChain tool for agent delegation with streaming.
124
+ """
125
+
126
+ @tool
127
+ async def delegate_to_agent(query: str, config: RunnableConfig) -> str | dict[str, Any]:
128
+ """Delegate task to internal agent with real-time streaming.
129
+
130
+ Args:
131
+ query: The task to delegate to the internal agent.
132
+ config: The runtime configuration for the agent.
133
+
134
+ Returns:
135
+ The result from the delegated agent, including artifacts if any.
136
+ """
137
+ try:
138
+ writer: StreamWriter = get_stream_writer()
139
+ except Exception as exc:
140
+ logger.warning(
141
+ "DelegationToolManager: Stream writer unavailable; delegation streaming disabled.",
142
+ extra={"error": str(exc), "error_type": type(exc).__name__},
143
+ )
144
+
145
+ def _noop_writer(_: Any) -> None:
146
+ """No-op writer for non-graph execution contexts."""
147
+ return None
148
+
149
+ writer = _noop_writer
150
+
151
+ try:
152
+ # Check delegation depth limit before executing
153
+ try:
154
+ current_depth = _DELEGATION_DEPTH_CVAR.get() or 0
155
+ parent_config = _STEP_LIMIT_CONFIG_CVAR.get()
156
+
157
+ temp_state = {
158
+ "delegation_depth": current_depth,
159
+ "delegation_chain": list(_DELEGATION_CHAIN_CVAR.get() or []),
160
+ }
161
+ manager = StepLimitManager.from_state(temp_state, config=parent_config)
162
+ manager.check_delegation_depth(target_agent_name=agent.name)
163
+
164
+ except MaxDelegationDepthExceededError as depth_error:
165
+ logger.warning(
166
+ f"DelegationToolManager: Delegation depth check failed for '{agent.name}': {depth_error}"
167
+ )
168
+ self._notify_error_via_writer(writer, agent.name, depth_error)
169
+ return self._handle_delegation_error(agent.name, depth_error)
170
+
171
+ logger.debug(f"DelegationToolManager: Delegating to '{agent.name}'")
172
+ configurable_kwargs = self._get_configurable_kwargs(agent, config)
173
+ result = await self._execute_delegated_agent(agent, query, configurable_kwargs, config, writer)
174
+ return self._handle_delegation_response_with_extras(agent.name, result)
175
+
176
+ except Exception as e:
177
+ self._notify_error_via_writer(writer, agent.name, e)
178
+ return self._handle_delegation_error(agent.name, e)
179
+
180
+ delegate_to_agent.name = f"delegate_to_{agent.name}"
181
+ delegate_to_agent.description = (
182
+ f"Delegate tasks to internal agent '{agent.name}'. "
183
+ f"Use this when you need to: {agent.description or 'coordinate with this agent'}"
184
+ )
185
+
186
+ delegate_to_agent.metadata = self._build_delegation_tool_metadata(agent)
187
+
188
+ return delegate_to_agent
189
+
190
+ @staticmethod
191
+ def _build_delegation_tool_metadata(agent: BaseAgent) -> dict[str, Any]:
192
+ """Create metadata payload used to mark tools as delegation-capable.
193
+
194
+ Args:
195
+ agent (BaseAgent): The agent to create metadata for.
196
+
197
+ Returns:
198
+ dict[str, Any]: The metadata payload for the delegation tool.
199
+ """
200
+ return {
201
+ "is_delegation_tool": True,
202
+ "delegated_agent_name": agent.name,
203
+ "tool_type": "delegation",
204
+ "delegation_manager": DelegationToolManager.__name__,
205
+ }
206
+
207
+ async def _execute_delegated_agent(
208
+ self,
209
+ agent: BaseAgent,
210
+ query: str,
211
+ configurable_kwargs: dict[str, Any],
212
+ config: RunnableConfig | None,
213
+ writer: StreamWriter,
214
+ ) -> Any:
215
+ """Execute delegated agent call with streaming or synchronous fallback.
216
+
217
+ Args:
218
+ agent: The delegated agent to execute.
219
+ query: The query string to pass to the agent.
220
+ configurable_kwargs: Additional configuration arguments for the agent.
221
+ config: Runnable configuration for the execution context.
222
+ writer: Stream writer to emit events during execution.
223
+
224
+ Returns:
225
+ The result of the agent execution.
226
+ """
227
+ # T021: Propagate delegation depth and step budget to sub-agent
228
+ # Import here to avoid circular dependencies if any
229
+ from aip_agents.utils.step_limit_manager import (
230
+ _DELEGATION_DEPTH_CVAR,
231
+ _STEP_LIMIT_CONFIG_CVAR,
232
+ StepLimitManager,
233
+ )
234
+
235
+ # Context tokens for reset
236
+ depth_token = None
237
+ chain_token = None
238
+ budget_token = None
239
+
240
+ try:
241
+ # Get current delegation context from ContextVars
242
+ current_depth = _DELEGATION_DEPTH_CVAR.get() or 0
243
+ current_chain = _DELEGATION_CHAIN_CVAR.get() or []
244
+ remaining_budget = _REMAINING_STEP_BUDGET_CVAR.get()
245
+ parent_config = _STEP_LIMIT_CONFIG_CVAR.get()
246
+
247
+ # Increment depth for sub-agent
248
+ new_depth = current_depth + 1
249
+ new_chain = list(current_chain) + [agent.name]
250
+
251
+ # Calculate child budget using parent logic
252
+ # Use transient manager to apply calculation rules
253
+ manager = StepLimitManager(
254
+ config=parent_config,
255
+ initial_delegation_depth=current_depth,
256
+ parent_step_budget=remaining_budget,
257
+ )
258
+ child_max_steps = None
259
+ child_config = getattr(agent, "step_limit_config", None)
260
+ if child_config is not None and hasattr(child_config, "max_steps"):
261
+ child_max_steps = child_config.max_steps
262
+ child_budget = manager.get_child_budget(child_max_steps=child_max_steps)
263
+
264
+ # Set context for sub-agent
265
+ depth_token = _DELEGATION_DEPTH_CVAR.set(new_depth)
266
+ chain_token = _DELEGATION_CHAIN_CVAR.set(tuple(new_chain))
267
+ budget_token = _REMAINING_STEP_BUDGET_CVAR.set(child_budget)
268
+
269
+ logger.debug(
270
+ f"DelegationToolManager: Delegating to '{agent.name}' at depth {new_depth}, "
271
+ f"chain: {new_chain}, child_budget: {child_budget} (from parent: {remaining_budget})"
272
+ )
273
+
274
+ # Execute
275
+ if not hasattr(agent, AGENT_RUN_A2A_STREAMING_METHOD):
276
+ return agent.run(query, **configurable_kwargs)
277
+
278
+ self._set_parent_step_context(config)
279
+ final_chunk = await self._handle_delegation_streaming(agent, query, configurable_kwargs, writer)
280
+ return self._format_final_chunk_sub_agent_output(final_chunk)
281
+
282
+ except Exception as e:
283
+ logger.warning(f"DelegationToolManager: Error in delegation execution: {e}")
284
+ raise e
285
+ finally:
286
+ # Restore context and propagate child usage back to parent (Spec-1)
287
+ # Parent context is restored by reset, then we set it to the final child budget
288
+ if budget_token:
289
+ final_child_budget = _REMAINING_STEP_BUDGET_CVAR.get()
290
+ _REMAINING_STEP_BUDGET_CVAR.reset(budget_token)
291
+ _REMAINING_STEP_BUDGET_CVAR.set(final_child_budget)
292
+
293
+ if depth_token:
294
+ _DELEGATION_DEPTH_CVAR.reset(depth_token)
295
+ if chain_token:
296
+ _DELEGATION_CHAIN_CVAR.reset(chain_token)
297
+
298
+ def _set_parent_step_context(self, config: RunnableConfig | None) -> None:
299
+ """Bridge parent step ID from tool configuration into context variables.
300
+
301
+ Args:
302
+ config: Runnable configuration containing parent step ID information.
303
+ """
304
+ try:
305
+ parent_step_id = None
306
+ cfg = config or {}
307
+ cfg_conf = cfg.get("configurable") if isinstance(cfg, dict) else None
308
+ if isinstance(cfg_conf, dict):
309
+ parent_step_id = cfg_conf.get("parent_step_id")
310
+ if not parent_step_id:
311
+ metadata = cfg.get("metadata") or {}
312
+ tool_call_id = (
313
+ cfg_conf.get("tool_call_id")
314
+ or metadata.get("tool_call_id")
315
+ or metadata.get("id")
316
+ or (metadata.get("tool_call") or {}).get("id")
317
+ )
318
+ if tool_call_id and self.parent_agent is not None:
319
+ thread_key = getattr(self.parent_agent, "thread_id_key", "thread_id")
320
+ thread_id = cfg_conf.get(thread_key)
321
+ parent_map = self.parent_agent._tool_parent_map_by_thread.get(str(thread_id), {})
322
+ parent_step_id = parent_map.get(str(tool_call_id))
323
+ _DELEGATION_PARENT_STEP_ID_CVAR.set(parent_step_id)
324
+ except Exception:
325
+ _DELEGATION_PARENT_STEP_ID_CVAR.set(None)
326
+
327
+ def _notify_error_via_writer(self, writer: StreamWriter, agent_name: str, exception: Exception) -> None:
328
+ """Safely notify error via writer using A2AEvent structure.
329
+
330
+ Args:
331
+ writer: Stream writer for sending updates
332
+ agent_name: Name of the agent that encountered the error
333
+ exception: The exception that occurred
334
+ """
335
+ try:
336
+ a2a_event: A2AEvent = {
337
+ "event_type": A2AStreamEventType.ERROR,
338
+ "content": f"Error in {agent_name}: {str(exception)}",
339
+ "metadata": {},
340
+ "is_final": False,
341
+ }
342
+ writer(a2a_event)
343
+ except Exception:
344
+ pass
345
+
346
+ def _create_delegation_tool(self, agent: BaseAgent) -> BaseTool:
347
+ """Create a LangChain tool for agent delegation (non-streaming version).
348
+
349
+ Simplified version following legacy BaseLangChainAgent._create_delegation_func pattern.
350
+ This is the original non-streaming version for backward compatibility.
351
+
352
+ Args:
353
+ agent: The agent to create a delegation tool for.
354
+
355
+ Returns:
356
+ BaseTool: A LangChain tool for agent delegation.
357
+ """
358
+
359
+ @tool
360
+ def delegate_to_agent(query: str, config: RunnableConfig) -> str | dict[str, Any] | Command:
361
+ """Delegate task to internal agent.
362
+
363
+ Args:
364
+ query: The task to delegate to the internal agent.
365
+ config: The runtime configuration for the agent.
366
+
367
+ Returns:
368
+ The result from the delegated agent, including artifacts and metadata if any.
369
+ """
370
+ try:
371
+ logger.debug(f"DelegationToolManager: Delegating to '{agent.name}'")
372
+
373
+ # Use simple delegation kwargs (following legacy pattern)
374
+ configurable_kwargs = self._get_configurable_kwargs(agent, config)
375
+ result = agent.run(query, **configurable_kwargs)
376
+
377
+ # Handle response with artifact, metadata, references and token usage support
378
+ return self._handle_delegation_response_with_extras(agent.name, result)
379
+
380
+ except Exception as e:
381
+ return self._handle_delegation_error(agent.name, e)
382
+
383
+ # Set tool metadata
384
+ delegate_to_agent.name = f"delegate_to_{agent.name}"
385
+ delegate_to_agent.description = (
386
+ f"Delegate tasks to internal agent '{agent.name}'. "
387
+ f"Use this when you need to: {agent.description or 'coordinate with this agent'}"
388
+ )
389
+
390
+ delegate_to_agent.metadata = self._build_delegation_tool_metadata(agent)
391
+
392
+ return delegate_to_agent
393
+
394
+ def _get_configurable_kwargs(self, agent: BaseAgent, config: RunnableConfig | None = None) -> dict[str, Any]:
395
+ """Get configurable kwargs for agent delegation.
396
+
397
+ Args:
398
+ agent: The agent to get configurable kwargs for.
399
+ config: The parent agent's config containing thread_id to inherit.
400
+
401
+ Returns:
402
+ dict[str, Any]: A dictionary with 'configurable' key if the agent
403
+ has 'thread_id_key', otherwise an empty dictionary.
404
+ """
405
+ if hasattr(agent, "thread_id_key"):
406
+ # Try to use parent thread ID from config first
407
+ parent_thread_id = None
408
+ if config and config.get("configurable"):
409
+ parent_thread_id = config["configurable"].get("thread_id")
410
+
411
+ if parent_thread_id:
412
+ # Use parent's thread ID to maintain conversation continuity
413
+ return {"configurable": {agent.thread_id_key: parent_thread_id}}
414
+ else:
415
+ delegation_thread_id = f"delegation_to_{agent.name}_{uuid.uuid4().hex[:8]}"
416
+ return {"configurable": {agent.thread_id_key: delegation_thread_id}}
417
+ return {}
418
+
419
+ def _handle_delegation_response(self, agent_name: str, result: Any) -> str:
420
+ """Handle delegation response (following legacy pattern).
421
+
422
+ Args:
423
+ agent_name (str): The name of the agent that was delegated to.
424
+ result (Any): The result from the delegated agent.
425
+
426
+ Returns:
427
+ str: The formatted response string.
428
+ """
429
+ try:
430
+ if isinstance(result, dict):
431
+ response_content = result.get(
432
+ OUTPUT_KEY, f"No '{OUTPUT_KEY}' key found in response from agent {agent_name}."
433
+ )
434
+ logger.info(f"DelegationToolManager: Agent '{agent_name}' responded: {response_content}")
435
+ return str(response_content)
436
+ else:
437
+ return str(result)
438
+ except Exception as e:
439
+ logger.warning(f"DelegationToolManager: Error formatting delegation response from '{agent_name}': {e}")
440
+ return str(result)
441
+
442
+ async def _handle_delegation_streaming(
443
+ self, agent: BaseAgent, query: str, configurable_kwargs: dict, writer: StreamWriter
444
+ ) -> dict | None:
445
+ """Handle streaming communication with a delegated agent.
446
+
447
+ Args:
448
+ agent: The agent to stream from
449
+ query: The query to send to the agent
450
+ configurable_kwargs: Configuration parameters for the agent
451
+ writer: Stream writer for sending updates
452
+
453
+ Returns:
454
+ The final result chunk from the agent
455
+ """
456
+ final_result = None
457
+
458
+ async for chunk in agent.arun_a2a_stream(query, **configurable_kwargs):
459
+ if isinstance(chunk, dict):
460
+ self._anonymize_final_chunk(chunk)
461
+ self._forward_sub_agent_chunk(chunk, writer)
462
+
463
+ if self._is_delegation_chunk_final(chunk):
464
+ final_result = chunk
465
+ return final_result
466
+
467
+ def _is_delegation_chunk_final(self, chunk: dict) -> bool:
468
+ """Check if a delegation chunk represents the final result.
469
+
470
+ Args:
471
+ chunk: The chunk to check
472
+
473
+ Returns:
474
+ True if this is the final chunk
475
+ """
476
+ return chunk.get("is_final") or chunk.get("status") == "completed"
477
+
478
+ def _anonymize_final_chunk(self, chunk: dict) -> None:
479
+ """Mask sub-agent final responses using available PII mapping.
480
+
481
+ Args:
482
+ chunk: Streamed response chunk from the delegated agent.
483
+
484
+ Returns:
485
+ None: This method mutates the provided chunk in place when masking is applied.
486
+ """
487
+ if not self._is_delegation_chunk_final(chunk):
488
+ return
489
+
490
+ content = chunk.get("content")
491
+ if not isinstance(content, str) or not content:
492
+ return
493
+
494
+ chunk["content"] = anonymize_final_response_content(content, chunk)
495
+
496
+ def _handle_delegation_response_with_extras(self, agent_name: str, result: Any) -> str | dict[str, Any] | Command:
497
+ """Handle delegation response with full support for artifacts, metadata, references, and token usage.
498
+
499
+ Args:
500
+ agent_name: The name of the agent that provided the response.
501
+ result: The result from the delegated agent.
502
+
503
+ Returns:
504
+ Either a string (when no additional data), dict with 'result' and other keys,
505
+ or Command with comprehensive updates.
506
+ """
507
+ try:
508
+ text_response, artifacts = extract_artifacts_from_agent_response(result)
509
+ metadata_update = self._extract_metadata_from_agent_response(result)
510
+ token_usage = extract_token_usage_from_agent_response(result)
511
+ references = extract_references_from_agent_response(result)
512
+ pii_mapping = extract_pii_mapping_from_agent_response(result)
513
+
514
+ if artifacts:
515
+ logger.info(f"DelegationToolManager: Agent '{agent_name}' responded with {len(artifacts)} artifacts")
516
+ if metadata_update:
517
+ logger.info(
518
+ f"DelegationToolManager: Agent '{agent_name}' responded with metadata updates: {metadata_update}"
519
+ )
520
+ if token_usage:
521
+ logger.info(f"DelegationToolManager: Agent '{agent_name}' responded with token usage: {token_usage}")
522
+ if references:
523
+ logger.info(f"DelegationToolManager: Agent '{agent_name}' responded with {len(references)} references")
524
+ if pii_mapping:
525
+ logger.info(
526
+ f"DelegationToolManager: Agent '{agent_name}' responded with PII mapping: {len(pii_mapping)} entries"
527
+ )
528
+
529
+ # Prepare response with any additional data
530
+ has_extras = self._has_response_extras(artifacts, metadata_update, token_usage, references, pii_mapping)
531
+
532
+ if has_extras:
533
+ update_dict = self._build_response_update_dict(
534
+ agent_name, text_response, artifacts, metadata_update, token_usage, references, pii_mapping
535
+ )
536
+ return Command(update=update_dict)
537
+ else:
538
+ return f"[{agent_name}] {text_response}"
539
+
540
+ except Exception as e:
541
+ logger.warning(f"DelegationToolManager: Error formatting delegation response from '{agent_name}': {e}")
542
+ return str(result)
543
+
544
+ def _has_response_extras(
545
+ self,
546
+ artifacts: list,
547
+ metadata_update: dict | None,
548
+ token_usage: dict | None,
549
+ references: list,
550
+ pii_mapping: dict[str, str] | None = None,
551
+ ) -> bool:
552
+ """Check if the response has any extra data beyond the text response.
553
+
554
+ Args:
555
+ artifacts (list): List of artifacts from the response.
556
+ metadata_update (dict | None): Optional metadata update.
557
+ token_usage (dict | None): Optional token usage information.
558
+ references (list): List of references from the response.
559
+ pii_mapping (dict[str, str] | None): Optional PII mapping from the response.
560
+
561
+ Returns:
562
+ bool: True if any extra data is present, False otherwise.
563
+ """
564
+ return any([artifacts, metadata_update, token_usage, references, pii_mapping])
565
+
566
+ def _build_response_update_dict( # noqa: PLR0913
567
+ self,
568
+ agent_name: str,
569
+ text_response: str,
570
+ artifacts: list,
571
+ metadata_update: dict | None,
572
+ token_usage: dict | None,
573
+ references: list,
574
+ pii_mapping: dict[str, str] | None = None,
575
+ ) -> dict[str, Any]: # noqa: PLR0913
576
+ """Build the update dictionary for responses with extra data.
577
+
578
+ Args:
579
+ agent_name: Name of the agent that generated the response.
580
+ text_response: The main text response from the agent.
581
+ artifacts: List of artifacts associated with the response.
582
+ metadata_update: Optional metadata update dictionary.
583
+ token_usage: Optional token usage information.
584
+ references: List of references associated with the response.
585
+ pii_mapping: Optional PII mapping from the response.
586
+
587
+ Returns:
588
+ Dictionary containing the formatted response with all extra data included.
589
+ """
590
+ update_dict = {RESULT_KEY: f"[{agent_name}] {text_response}"}
591
+
592
+ # Add each type of extra data if available
593
+ if artifacts:
594
+ update_dict[ARTIFACTS_KEY] = artifacts
595
+ if metadata_update:
596
+ update_dict[METADATA_KEY] = metadata_update
597
+ if token_usage:
598
+ update_dict[USAGE_METADATA_KEY] = token_usage
599
+ if references:
600
+ update_dict[MetadataFieldKeys.REFERENCES] = references
601
+ if pii_mapping:
602
+ update_dict[MetadataFieldKeys.PII_MAPPING] = pii_mapping
603
+
604
+ return update_dict
605
+
606
+ def _extract_metadata_from_agent_response(self, result: Any) -> dict[str, Any] | None:
607
+ """Extract metadata from agent response for delegation tools.
608
+
609
+ Args:
610
+ result: The result returned by the delegated agent.
611
+
612
+ Returns:
613
+ Metadata dict if found, None otherwise.
614
+ """
615
+ if not isinstance(result, dict):
616
+ return None
617
+
618
+ full_state = result.get("full_final_state", {})
619
+ if not isinstance(full_state, dict):
620
+ return None
621
+
622
+ metadata = full_state.get("metadata")
623
+ if not isinstance(metadata, dict):
624
+ return None
625
+
626
+ # Keep filtered metadata but also preserve linkage fields
627
+ filtered = self._filter_metadata(metadata)
628
+ prev_ids = metadata.get("previous_step_ids")
629
+ if isinstance(prev_ids, list) and prev_ids:
630
+ # Do not drop linkage information
631
+ filtered["previous_step_ids"] = list(prev_ids)
632
+ # Optionally keep step_id if present (useful for advanced tracing)
633
+ if "step_id" in metadata and metadata["step_id"]:
634
+ filtered.setdefault("step_id", metadata["step_id"]) # don't overwrite if user explicitly set
635
+
636
+ return filtered
637
+
638
+ def _filter_metadata(self, metadata: dict[str, Any]) -> dict[str, Any]:
639
+ """Filter out internal LangGraph keys to avoid pollution.
640
+
641
+ Args:
642
+ metadata: Raw metadata dict
643
+
644
+ Returns:
645
+ Filtered metadata dict
646
+ """
647
+ filtered_metadata = {
648
+ k: v
649
+ for k, v in metadata.items()
650
+ if not any(k.startswith(prefix) for prefix in METADATA_INTERNAL_PREFIXES)
651
+ and k not in METADATA_INTERNAL_KEYS
652
+ }
653
+ return filtered_metadata if filtered_metadata else {}
654
+
655
+ def _handle_delegation_error(self, agent_name: str, exception: Exception) -> str:
656
+ """Handle delegation errors (following legacy pattern).
657
+
658
+ Args:
659
+ agent_name: The name of the agent that caused the error.
660
+ exception: The exception that occurred.
661
+
662
+ Returns:
663
+ str: A string containing the error message.
664
+ """
665
+ error_msg = f"Error calling agent {agent_name}: {str(exception)}"
666
+ logger.error(f"DelegationToolManager: Error delegating to '{agent_name}': {exception}", exc_info=True)
667
+ return error_msg
668
+
669
+ def _forward_sub_agent_chunk(self, chunk: dict, writer: StreamWriter) -> None:
670
+ """Forward sub-agent streaming chunks in real-time.
671
+
672
+ Args:
673
+ chunk: Streaming chunk from the sub-agent
674
+ writer: Stream writer to emit events
675
+ """
676
+ event_type = self._extract_event_type(chunk)
677
+
678
+ if event_type == A2AStreamEventType.TOOL_CALL:
679
+ self._forward_tool_call_event(chunk, writer)
680
+ elif event_type == A2AStreamEventType.TOOL_RESULT:
681
+ self._forward_tool_result_event(chunk, writer)
682
+
683
+ def _extract_event_type(self, chunk: dict) -> A2AStreamEventType | None:
684
+ """Extract event type from chunk, converting to A2AStreamEventType enum.
685
+
686
+ Args:
687
+ chunk: Streaming chunk from the sub-agent
688
+
689
+ Returns:
690
+ Event type as A2AStreamEventType enum, or None if not found/invalid
691
+ """
692
+ event_type = chunk.get("event_type")
693
+
694
+ if isinstance(event_type, A2AStreamEventType):
695
+ return event_type
696
+
697
+ if isinstance(event_type, str):
698
+ try:
699
+ return A2AStreamEventType(event_type)
700
+ except ValueError:
701
+ return None
702
+
703
+ return None
704
+
705
+ def _extract_delegation_tool_name_prefix(self, tool_name: str) -> str:
706
+ """Extract meaningful prefix from delegation tool name.
707
+
708
+ Args:
709
+ tool_name: The delegation tool name (e.g., "delegate_to_TableAgent")
710
+
711
+ Returns:
712
+ The extracted prefix (e.g., "table" from "delegate_to_TableAgent")
713
+ """
714
+ if tool_name.startswith("delegate_to_"):
715
+ # Extract the agent name after "delegate_to_"
716
+ agent_name = tool_name[12:] # Remove "delegate_to_"
717
+ # Remove "Agent" suffix if present
718
+ if agent_name.endswith("Agent"):
719
+ agent_name = agent_name[:-5] # Remove "Agent"
720
+ # Convert to lowercase and take first 4 characters
721
+ return agent_name.lower()[:4]
722
+ else:
723
+ # Fallback to first 4 characters
724
+ return tool_name[:4]
725
+
726
+ def _generate_delegation_tool_call_step_id(self, tool_info: dict[str, Any], counter: int) -> str:
727
+ """Generate step_id for delegation tool call events.
728
+
729
+ Args:
730
+ tool_info: Tool information
731
+ counter: Step counter
732
+
733
+ Returns:
734
+ Generated step_id
735
+ """
736
+ if not tool_info or not tool_info.get("tool_calls"):
737
+ return f"delegate_call_{counter:03d}"
738
+
739
+ tool_calls = tool_info["tool_calls"]
740
+ if len(tool_calls) == 1:
741
+ # Single tool call
742
+ tool_name = tool_calls[0].get("name", "unknown")
743
+ prefix = self._extract_delegation_tool_name_prefix(tool_name)
744
+ return f"{prefix}_call_{counter:03d}"
745
+ else:
746
+ # Multiple tool calls (parallel execution)
747
+ tool_names = [self._extract_delegation_tool_name_prefix(tc.get("name", "unknown")) for tc in tool_calls]
748
+ combined_name = "".join(tool_names)[:6] # Limit length
749
+ return f"{combined_name}_parent_{counter:03d}"
750
+
751
+ def _generate_delegation_tool_result_step_id(self, tool_info: dict[str, Any] | None, counter: int) -> str:
752
+ """Generate step_id for delegation tool result events.
753
+
754
+ Args:
755
+ tool_info: Tool information
756
+ counter: Step counter
757
+
758
+ Returns:
759
+ Generated step_id
760
+ """
761
+ if not tool_info:
762
+ return f"delegate_done_{counter:03d}"
763
+
764
+ tool_name = tool_info.get("name", "unknown")
765
+ prefix = self._extract_delegation_tool_name_prefix(tool_name)
766
+ return f"{prefix}_done_{counter:03d}"
767
+
768
+ def _generate_delegation_step_id(
769
+ self, event_type: A2AStreamEventType, agent_name: str, tool_info: dict[str, Any] | None = None
770
+ ) -> str:
771
+ """Generate a meaningful step_id for delegation events.
772
+
773
+ Args:
774
+ event_type: The type of event (tool_call, tool_result, etc.)
775
+ agent_name: The name of the delegated agent
776
+ tool_info: Tool information containing tool names and IDs
777
+
778
+ Returns:
779
+ A meaningful step_id string
780
+ """
781
+ try:
782
+ counter = get_next_step_number()
783
+
784
+ # Use mapping to reduce branches
785
+ step_id_generators = {
786
+ A2AStreamEventType.TOOL_CALL: lambda: self._generate_delegation_tool_call_step_id(tool_info, counter),
787
+ A2AStreamEventType.TOOL_RESULT: lambda: self._generate_delegation_tool_result_step_id(
788
+ tool_info, counter
789
+ ),
790
+ }
791
+
792
+ generator = step_id_generators.get(event_type)
793
+ if generator:
794
+ return generator()
795
+
796
+ # Handle both enum and string event types
797
+ event_type_value = event_type.value if hasattr(event_type, "value") else str(event_type)
798
+ fallback_prefix = self._build_fallback_prefix(agent_name)
799
+ return f"{fallback_prefix}_{event_type_value}_{counter:03d}"
800
+
801
+ except Exception:
802
+ # Fallback to random generation if anything goes wrong
803
+ return f"delegate_{uuid.uuid4().hex[:8]}"
804
+
805
+ @staticmethod
806
+ def _build_fallback_prefix(agent_name: str) -> str:
807
+ """Create a fallback prefix that incorporates the agent name when available.
808
+
809
+ Args:
810
+ agent_name: The name of the agent to create a prefix for.
811
+
812
+ Returns:
813
+ A fallback prefix string incorporating the agent name.
814
+ """
815
+ if not agent_name:
816
+ return "delegate"
817
+
818
+ sanitized = "".join(ch for ch in agent_name.lower() if ch.isalnum())[:8]
819
+ return f"delegate_{sanitized}" if sanitized else "delegate"
820
+
821
+ def _forward_tool_call_event(self, chunk: dict, writer: StreamWriter) -> None:
822
+ """Forward tool call events with coordinator-style format using A2AEvent structure.
823
+
824
+ Args:
825
+ chunk: Streaming chunk containing tool call info
826
+ writer: Stream writer to emit events
827
+ """
828
+ tool_info = chunk.get("tool_info", {})
829
+ message = self._create_tool_call_message(tool_info)
830
+ metadata = self._prepare_tool_call_metadata(chunk, tool_info)
831
+
832
+ a2a_event: A2AEvent = {
833
+ "event_type": A2AStreamEventType.TOOL_CALL,
834
+ "content": message,
835
+ "metadata": metadata,
836
+ "tool_info": tool_info,
837
+ "is_final": False,
838
+ "artifacts": chunk.get("artifacts"),
839
+ MetadataFieldKeys.REFERENCES: chunk.get(MetadataFieldKeys.REFERENCES),
840
+ STEP_USAGE_KEY: chunk.get(STEP_USAGE_KEY),
841
+ TOTAL_USAGE_KEY: chunk.get(TOTAL_USAGE_KEY),
842
+ }
843
+ writer(a2a_event)
844
+
845
+ def _prepare_tool_call_metadata(self, chunk: dict, tool_info: dict) -> dict:
846
+ """Prepare metadata for tool call events with step ID generation and linkage.
847
+
848
+ Args:
849
+ chunk: Streaming chunk containing metadata
850
+ tool_info: Tool information for step ID generation
851
+
852
+ Returns:
853
+ Prepared metadata dictionary
854
+ """
855
+ metadata = chunk.get("metadata") or {}
856
+ self._ensure_step_id_in_metadata(metadata, tool_info)
857
+
858
+ agent_name = metadata.get("agent_name")
859
+ if agent_name:
860
+ self._setup_agent_linkage(metadata, agent_name, tool_info)
861
+ else:
862
+ self._handle_missing_agent_name(metadata)
863
+
864
+ return metadata
865
+
866
+ def _ensure_step_id_in_metadata(self, metadata: dict, tool_info: dict) -> None:
867
+ """Ensure step_id is present in metadata, generating one if missing.
868
+
869
+ Args:
870
+ metadata: Metadata dictionary to update
871
+ tool_info: Tool information for step ID generation
872
+ """
873
+ if "step_id" not in metadata:
874
+ agent_name_for_id = metadata.get("agent_name") or "anon_agent"
875
+ metadata["step_id"] = self._generate_delegation_step_id(
876
+ A2AStreamEventType.TOOL_CALL, agent_name_for_id, tool_info
877
+ )
878
+
879
+ def _setup_agent_linkage(self, metadata: dict, agent_name: str, tool_info: dict) -> None:
880
+ """Setup linkage between parent and sub-agent for tool call events.
881
+
882
+ Args:
883
+ metadata: Metadata dictionary to update
884
+ agent_name: Name of the agent
885
+ tool_info: Tool information for parent lookup
886
+ """
887
+ parent_step_id = self._get_parent_step_id(tool_info)
888
+ metadata["previous_step_ids"] = [parent_step_id] if parent_step_id else []
889
+
890
+ # Record this sub-agent start step_id so its result can link back to it
891
+ sub_start_map = _DELEGATION_SUB_START_STEP_CVAR.get() or {}
892
+ sub_start_map[agent_name] = metadata["step_id"]
893
+ _DELEGATION_SUB_START_STEP_CVAR.set(sub_start_map)
894
+
895
+ def _get_parent_step_id(self, tool_info: dict) -> str | None:
896
+ """Get parent step ID from context or parent agent lookup.
897
+
898
+ Args:
899
+ tool_info: Tool information for parent lookup
900
+
901
+ Returns:
902
+ Parent step ID if found, None otherwise
903
+ """
904
+ parent_step_id = _DELEGATION_PARENT_STEP_ID_CVAR.get()
905
+
906
+ if not parent_step_id and self._can_lookup_parent_step():
907
+ parent_step_id = self._lookup_parent_step_from_agent(tool_info)
908
+
909
+ return parent_step_id
910
+
911
+ def _can_lookup_parent_step(self) -> bool:
912
+ """Check if parent step lookup is possible.
913
+
914
+ Returns:
915
+ True if parent agent has the required mapping
916
+ """
917
+ return self.parent_agent is not None and hasattr(self.parent_agent, "_tool_parent_map_by_thread")
918
+
919
+ def _lookup_parent_step_from_agent(self, tool_info: dict) -> str | None:
920
+ """Lookup parent step ID from parent agent's mapping.
921
+
922
+ Args:
923
+ tool_info: Tool information containing tool call ID
924
+
925
+ Returns:
926
+ Parent step ID if found, None otherwise
927
+ """
928
+ try:
929
+ thread_id = bla._THREAD_ID_CVAR.get()
930
+ if not thread_id:
931
+ return None
932
+
933
+ parent_map = self.parent_agent._tool_parent_map_by_thread.get(thread_id, {})
934
+ tool_call_id = tool_info.get("id") if tool_info else None
935
+
936
+ if tool_call_id:
937
+ return parent_map.get(str(tool_call_id))
938
+
939
+ except Exception as e:
940
+ logger.debug(f"Failed to look up parent step ID from parent agent: {e}")
941
+
942
+ return None
943
+
944
+ def _handle_missing_agent_name(self, metadata: dict) -> None:
945
+ """Handle case where agent_name is missing from metadata.
946
+
947
+ Args:
948
+ metadata: Metadata dictionary to update
949
+ """
950
+ logger.warning("Delegation tool call missing 'agent_name'; skipping linkage")
951
+ metadata["previous_step_ids"] = []
952
+ metadata["agent_name_missing"] = True
953
+
954
+ def _forward_tool_result_event(self, chunk: dict, writer: StreamWriter) -> None:
955
+ """Forward tool result events with coordinator-style format using A2AEvent structure.
956
+
957
+ Args:
958
+ chunk: Streaming chunk containing tool result info
959
+ writer: Stream writer to emit events
960
+ """
961
+ tool_info = chunk.get("tool_info", {})
962
+ tool_names: list[str] = []
963
+
964
+ primary_name = tool_info.get("name")
965
+ if isinstance(primary_name, str) and primary_name:
966
+ tool_names.append(primary_name)
967
+ elif isinstance(tool_info.get("tool_calls"), list):
968
+ tool_names.extend(
969
+ call.get("name")
970
+ for call in tool_info["tool_calls"]
971
+ if isinstance(call, dict) and isinstance(call.get("name"), str)
972
+ )
973
+
974
+ tool_names = [name for name in tool_names if name] or ["unknown_tool"]
975
+
976
+ # Preserve sub-agent metadata
977
+ metadata = chunk.get("metadata") or {}
978
+
979
+ # Link result to sub-agent start step_id only if agent_name present
980
+ agent_name = metadata.get("agent_name")
981
+ if agent_name:
982
+ sub_start_map = _DELEGATION_SUB_START_STEP_CVAR.get() or {}
983
+ start_step_id = sub_start_map.get(agent_name)
984
+ metadata["previous_step_ids"] = [start_step_id] if start_step_id else []
985
+ else:
986
+ logger.warning("Delegation tool result missing 'agent_name'; skipping linkage")
987
+ metadata["previous_step_ids"] = []
988
+ metadata["agent_name_missing"] = True
989
+
990
+ content = self._build_completion_content(tool_names)
991
+
992
+ a2a_event: A2AEvent = {
993
+ "event_type": A2AStreamEventType.TOOL_RESULT,
994
+ "content": content,
995
+ "metadata": metadata,
996
+ "tool_info": tool_info,
997
+ "is_final": False,
998
+ "artifacts": chunk.get("artifacts"),
999
+ MetadataFieldKeys.REFERENCES: chunk.get(MetadataFieldKeys.REFERENCES),
1000
+ STEP_USAGE_KEY: chunk.get(STEP_USAGE_KEY),
1001
+ TOTAL_USAGE_KEY: chunk.get(TOTAL_USAGE_KEY),
1002
+ }
1003
+ writer(a2a_event)
1004
+
1005
+ def _build_completion_content(self, tool_names: list[str]) -> str:
1006
+ """Create completion message consistent with coordinator formatting.
1007
+
1008
+ Args:
1009
+ tool_names: List of tool names that were executed.
1010
+
1011
+ Returns:
1012
+ Formatted completion message string.
1013
+ """
1014
+ deduped_names = list(dict.fromkeys(name for name in tool_names if name))
1015
+ if not deduped_names:
1016
+ deduped_names = ["unknown_tool"]
1017
+
1018
+ if self.parent_agent and hasattr(self.parent_agent, "_get_tool_completion_content"):
1019
+ try:
1020
+ return self.parent_agent._get_tool_completion_content(deduped_names)
1021
+ except Exception: # pragma: no cover - defensive fallback
1022
+ logger.debug("DelegationToolManager: parent agent completion formatting failed", exc_info=True)
1023
+
1024
+ has_delegation = any(name.startswith("delegate_to") for name in deduped_names)
1025
+ prefix = "Completed sub-agents:" if has_delegation else "Completed tools:"
1026
+ return f"{prefix} {', '.join(deduped_names)}"
1027
+
1028
+ def _create_tool_call_message(self, tool_info: dict) -> str:
1029
+ """Create a consistent message for tool call events.
1030
+
1031
+ Args:
1032
+ tool_info: Tool information from the chunk
1033
+
1034
+ Returns:
1035
+ Formatted message string
1036
+ """
1037
+ tool_calls = tool_info.get("tool_calls", [])
1038
+ tool_names = [tc.get("name", "unknown") for tc in tool_calls]
1039
+ return f"Processing with tools: {', '.join(tool_names)}"
1040
+
1041
+ def _format_final_chunk_sub_agent_output(self, final_result: dict | str | Any) -> dict[str, Any]:
1042
+ """Format the final chunk from a sub-agent result to match the .arun() output.
1043
+
1044
+ Args:
1045
+ final_result: The result from agent execution
1046
+
1047
+ Returns:
1048
+ A dictionary with keys:
1049
+ {
1050
+ "output": <output string>,
1051
+ "full_final_state": {
1052
+ "artifacts": <artifacts>,
1053
+ "references": <references>,
1054
+ "metadata": <metadata>,
1055
+ "total_usage": <total_usage>,
1056
+ }
1057
+ }
1058
+
1059
+ Note:
1060
+ - To preserve pattern of .arun():
1061
+ - the output will be stored in "output" key and extras will be stored in "full_final_state" key
1062
+ - Those extras being: "artifacts", "references", "metadata", and "total_usage"
1063
+ """
1064
+ result: dict[str, Any] = {
1065
+ "output": "",
1066
+ "full_final_state": {
1067
+ "artifacts": [],
1068
+ MetadataFieldKeys.REFERENCES: [],
1069
+ "metadata": {},
1070
+ TOTAL_USAGE_KEY: {},
1071
+ },
1072
+ }
1073
+
1074
+ if not isinstance(final_result, dict):
1075
+ result["output"] = str(final_result)
1076
+ else:
1077
+ result["output"] = final_result.get("content", str(final_result))
1078
+ result["full_final_state"] = {
1079
+ "artifacts": final_result.get("artifacts", []),
1080
+ MetadataFieldKeys.REFERENCES: final_result.get(MetadataFieldKeys.REFERENCES, []),
1081
+ "metadata": final_result.get("metadata", {}),
1082
+ TOTAL_USAGE_KEY: final_result.get(TOTAL_USAGE_KEY, {}),
1083
+ }
1084
+
1085
+ # Propagate sub-agent final step id to coordinator via metadata.previous_step_ids
1086
+ try:
1087
+ metadata = final_result.get("metadata") or {}
1088
+ final_step_id = metadata.get("step_id")
1089
+ if final_step_id:
1090
+ result["metadata"] = {"previous_step_ids": [final_step_id]}
1091
+ except Exception:
1092
+ # If metadata access fails, ensure we have a metadata key
1093
+ result["metadata"] = {}
1094
+
1095
+ # Single return point
1096
+ return result