aip-agents-binary 0.0.0b2__py3-none-any.whl → 0.5.11__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 (506) 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 +1 -1
  5. aip_agents/a2a/server/__init__.py +10 -0
  6. aip_agents/a2a/server/base_executor.py +1086 -0
  7. aip_agents/a2a/server/base_executor.pyi +16 -6
  8. aip_agents/a2a/server/google_adk_executor.py +198 -0
  9. aip_agents/a2a/server/google_adk_executor.pyi +11 -11
  10. aip_agents/a2a/server/langflow_executor.py +180 -0
  11. aip_agents/a2a/server/langflow_executor.pyi +43 -0
  12. aip_agents/a2a/server/langgraph_executor.py +267 -0
  13. aip_agents/a2a/server/langgraph_executor.pyi +11 -12
  14. aip_agents/a2a/types.py +232 -0
  15. aip_agents/a2a/types.pyi +54 -47
  16. aip_agents/agent/__init__.py +27 -0
  17. aip_agents/agent/__init__.pyi +3 -1
  18. aip_agents/agent/base_agent.py +970 -0
  19. aip_agents/agent/base_agent.pyi +24 -8
  20. aip_agents/agent/base_langgraph_agent.py +2942 -0
  21. aip_agents/agent/base_langgraph_agent.pyi +93 -25
  22. aip_agents/agent/google_adk_agent.py +926 -0
  23. aip_agents/agent/google_adk_agent.pyi +34 -21
  24. aip_agents/agent/google_adk_constants.py +6 -0
  25. aip_agents/agent/google_adk_constants.pyi +3 -0
  26. aip_agents/agent/hitl/__init__.py +24 -0
  27. aip_agents/agent/hitl/__init__.pyi +6 -0
  28. aip_agents/agent/hitl/config.py +28 -0
  29. aip_agents/agent/hitl/config.pyi +15 -0
  30. aip_agents/agent/hitl/langgraph_hitl_mixin.py +515 -0
  31. aip_agents/agent/hitl/langgraph_hitl_mixin.pyi +42 -0
  32. aip_agents/agent/hitl/manager.py +522 -0
  33. aip_agents/agent/hitl/manager.pyi +199 -0
  34. aip_agents/agent/hitl/models.py +18 -0
  35. aip_agents/agent/hitl/models.pyi +3 -0
  36. aip_agents/agent/hitl/prompt/__init__.py +9 -0
  37. aip_agents/agent/hitl/prompt/__init__.pyi +4 -0
  38. aip_agents/agent/hitl/prompt/base.py +42 -0
  39. aip_agents/agent/hitl/prompt/base.pyi +24 -0
  40. aip_agents/agent/hitl/prompt/deferred.py +73 -0
  41. aip_agents/agent/hitl/prompt/deferred.pyi +30 -0
  42. aip_agents/agent/interface.py +138 -0
  43. aip_agents/agent/interface.pyi +5 -5
  44. aip_agents/agent/interfaces.py +65 -0
  45. aip_agents/agent/interfaces.pyi +44 -0
  46. aip_agents/agent/langflow_agent.py +464 -0
  47. aip_agents/agent/langflow_agent.pyi +133 -0
  48. aip_agents/agent/langgraph_memory_enhancer_agent.py +433 -0
  49. aip_agents/agent/langgraph_memory_enhancer_agent.pyi +49 -0
  50. aip_agents/agent/langgraph_react_agent.py +2514 -0
  51. aip_agents/agent/langgraph_react_agent.pyi +51 -56
  52. aip_agents/agent/system_instruction_context.py +34 -0
  53. aip_agents/agent/system_instruction_context.pyi +13 -0
  54. aip_agents/clients/__init__.py +10 -0
  55. aip_agents/clients/__init__.pyi +4 -0
  56. aip_agents/clients/langflow/__init__.py +10 -0
  57. aip_agents/clients/langflow/__init__.pyi +4 -0
  58. aip_agents/clients/langflow/client.py +477 -0
  59. aip_agents/clients/langflow/client.pyi +140 -0
  60. aip_agents/clients/langflow/types.py +18 -0
  61. aip_agents/clients/langflow/types.pyi +7 -0
  62. aip_agents/constants.py +23 -0
  63. aip_agents/constants.pyi +1 -0
  64. aip_agents/credentials/manager.py +132 -0
  65. aip_agents/examples/__init__.py +5 -0
  66. aip_agents/examples/compare_streaming_client.py +783 -0
  67. aip_agents/examples/compare_streaming_client.pyi +48 -0
  68. aip_agents/examples/compare_streaming_server.py +142 -0
  69. aip_agents/examples/compare_streaming_server.pyi +18 -0
  70. aip_agents/examples/demo_memory_recall.py +401 -0
  71. aip_agents/examples/demo_memory_recall.pyi +58 -0
  72. aip_agents/examples/hello_world_a2a_google_adk_client.py +49 -0
  73. aip_agents/examples/hello_world_a2a_google_adk_client.pyi +2 -2
  74. aip_agents/examples/hello_world_a2a_google_adk_client_agent.py +48 -0
  75. aip_agents/examples/hello_world_a2a_google_adk_client_agent.pyi +2 -2
  76. aip_agents/examples/hello_world_a2a_google_adk_client_streaming.py +60 -0
  77. aip_agents/examples/hello_world_a2a_google_adk_client_streaming.pyi +2 -2
  78. aip_agents/examples/hello_world_a2a_google_adk_server.py +79 -0
  79. aip_agents/examples/hello_world_a2a_google_adk_server.pyi +7 -2
  80. aip_agents/examples/hello_world_a2a_langchain_client.py +39 -0
  81. aip_agents/examples/hello_world_a2a_langchain_client.pyi +1 -1
  82. aip_agents/examples/hello_world_a2a_langchain_client_agent.py +39 -0
  83. aip_agents/examples/hello_world_a2a_langchain_client_agent.pyi +1 -1
  84. aip_agents/examples/hello_world_a2a_langchain_client_lm_invoker.py +37 -0
  85. aip_agents/examples/hello_world_a2a_langchain_client_lm_invoker.pyi +1 -1
  86. aip_agents/examples/hello_world_a2a_langchain_client_streaming.py +41 -0
  87. aip_agents/examples/hello_world_a2a_langchain_client_streaming.pyi +1 -1
  88. aip_agents/examples/hello_world_a2a_langchain_reference_client_streaming.py +60 -0
  89. aip_agents/examples/hello_world_a2a_langchain_reference_client_streaming.pyi +1 -1
  90. aip_agents/examples/hello_world_a2a_langchain_reference_server.py +105 -0
  91. aip_agents/examples/hello_world_a2a_langchain_reference_server.pyi +8 -3
  92. aip_agents/examples/hello_world_a2a_langchain_server.py +79 -0
  93. aip_agents/examples/hello_world_a2a_langchain_server.pyi +7 -2
  94. aip_agents/examples/hello_world_a2a_langchain_server_lm_invoker.py +78 -0
  95. aip_agents/examples/hello_world_a2a_langchain_server_lm_invoker.pyi +7 -2
  96. aip_agents/examples/hello_world_a2a_langflow_client.py +83 -0
  97. aip_agents/examples/hello_world_a2a_langflow_client.pyi +9 -0
  98. aip_agents/examples/hello_world_a2a_langflow_server.py +82 -0
  99. aip_agents/examples/hello_world_a2a_langflow_server.pyi +14 -0
  100. aip_agents/examples/hello_world_a2a_langgraph_artifact_client.py +73 -0
  101. aip_agents/examples/hello_world_a2a_langgraph_artifact_client.pyi +1 -1
  102. aip_agents/examples/hello_world_a2a_langgraph_artifact_client_streaming.py +76 -0
  103. aip_agents/examples/hello_world_a2a_langgraph_artifact_client_streaming.pyi +1 -1
  104. aip_agents/examples/hello_world_a2a_langgraph_artifact_server.py +92 -0
  105. aip_agents/examples/hello_world_a2a_langgraph_artifact_server.pyi +7 -2
  106. aip_agents/examples/hello_world_a2a_langgraph_client.py +54 -0
  107. aip_agents/examples/hello_world_a2a_langgraph_client.pyi +2 -2
  108. aip_agents/examples/hello_world_a2a_langgraph_client_agent.py +54 -0
  109. aip_agents/examples/hello_world_a2a_langgraph_client_agent.pyi +2 -2
  110. aip_agents/examples/hello_world_a2a_langgraph_client_agent_lm_invoker.py +32 -0
  111. aip_agents/examples/hello_world_a2a_langgraph_client_agent_lm_invoker.pyi +1 -1
  112. aip_agents/examples/hello_world_a2a_langgraph_client_streaming.py +50 -0
  113. aip_agents/examples/hello_world_a2a_langgraph_client_streaming.pyi +3 -3
  114. aip_agents/examples/hello_world_a2a_langgraph_client_streaming_lm_invoker.py +44 -0
  115. aip_agents/examples/hello_world_a2a_langgraph_client_streaming_lm_invoker.pyi +1 -1
  116. aip_agents/examples/hello_world_a2a_langgraph_client_streaming_tool_streaming.py +92 -0
  117. aip_agents/examples/hello_world_a2a_langgraph_client_streaming_tool_streaming.pyi +1 -1
  118. aip_agents/examples/hello_world_a2a_langgraph_server.py +84 -0
  119. aip_agents/examples/hello_world_a2a_langgraph_server.pyi +7 -2
  120. aip_agents/examples/hello_world_a2a_langgraph_server_lm_invoker.py +79 -0
  121. aip_agents/examples/hello_world_a2a_langgraph_server_lm_invoker.pyi +7 -2
  122. aip_agents/examples/hello_world_a2a_langgraph_server_tool_streaming.py +132 -0
  123. aip_agents/examples/hello_world_a2a_langgraph_server_tool_streaming.pyi +7 -2
  124. aip_agents/examples/hello_world_a2a_mcp_langgraph.py +196 -0
  125. aip_agents/examples/hello_world_a2a_mcp_langgraph.pyi +1 -1
  126. aip_agents/examples/hello_world_a2a_three_level_agent_hierarchy_client.py +244 -0
  127. aip_agents/examples/hello_world_a2a_three_level_agent_hierarchy_client.pyi +31 -6
  128. aip_agents/examples/hello_world_a2a_three_level_agent_hierarchy_server.py +251 -0
  129. aip_agents/examples/hello_world_a2a_three_level_agent_hierarchy_server.pyi +33 -5
  130. aip_agents/examples/hello_world_a2a_with_metadata_langchain_client.py +57 -0
  131. aip_agents/examples/hello_world_a2a_with_metadata_langchain_client.pyi +1 -1
  132. aip_agents/examples/hello_world_a2a_with_metadata_langchain_server_lm_invoker.py +80 -0
  133. aip_agents/examples/hello_world_a2a_with_metadata_langchain_server_lm_invoker.pyi +7 -2
  134. aip_agents/examples/hello_world_google_adk.py +41 -0
  135. aip_agents/examples/hello_world_google_adk_mcp_http.py +34 -0
  136. aip_agents/examples/hello_world_google_adk_mcp_http_stream.py +40 -0
  137. aip_agents/examples/hello_world_google_adk_mcp_sse.py +44 -0
  138. aip_agents/examples/hello_world_google_adk_mcp_sse_stream.py +48 -0
  139. aip_agents/examples/hello_world_google_adk_mcp_stdio.py +44 -0
  140. aip_agents/examples/hello_world_google_adk_mcp_stdio_stream.py +48 -0
  141. aip_agents/examples/hello_world_google_adk_stream.py +44 -0
  142. aip_agents/examples/hello_world_langchain.py +28 -0
  143. aip_agents/examples/hello_world_langchain_lm_invoker.py +15 -0
  144. aip_agents/examples/hello_world_langchain_mcp_http.py +34 -0
  145. aip_agents/examples/hello_world_langchain_mcp_http_interactive.py +130 -0
  146. aip_agents/examples/hello_world_langchain_mcp_http_interactive.pyi +16 -0
  147. aip_agents/examples/hello_world_langchain_mcp_http_stream.py +42 -0
  148. aip_agents/examples/hello_world_langchain_mcp_multi_server.py +155 -0
  149. aip_agents/examples/hello_world_langchain_mcp_multi_server.pyi +18 -0
  150. aip_agents/examples/hello_world_langchain_mcp_sse.py +34 -0
  151. aip_agents/examples/hello_world_langchain_mcp_sse_stream.py +40 -0
  152. aip_agents/examples/hello_world_langchain_mcp_stdio.py +30 -0
  153. aip_agents/examples/hello_world_langchain_mcp_stdio_stream.py +41 -0
  154. aip_agents/examples/hello_world_langchain_stream.py +36 -0
  155. aip_agents/examples/hello_world_langchain_stream_lm_invoker.py +39 -0
  156. aip_agents/examples/hello_world_langflow_agent.py +163 -0
  157. aip_agents/examples/hello_world_langflow_agent.pyi +35 -0
  158. aip_agents/examples/hello_world_langgraph.py +39 -0
  159. aip_agents/examples/hello_world_langgraph_bosa_twitter.py +41 -0
  160. aip_agents/examples/hello_world_langgraph_mcp_http.py +31 -0
  161. aip_agents/examples/hello_world_langgraph_mcp_http_stream.py +34 -0
  162. aip_agents/examples/hello_world_langgraph_mcp_sse.py +35 -0
  163. aip_agents/examples/hello_world_langgraph_mcp_sse_stream.py +50 -0
  164. aip_agents/examples/hello_world_langgraph_mcp_stdio.py +35 -0
  165. aip_agents/examples/hello_world_langgraph_mcp_stdio_stream.py +50 -0
  166. aip_agents/examples/hello_world_langgraph_stream.py +43 -0
  167. aip_agents/examples/hello_world_langgraph_stream_lm_invoker.py +37 -0
  168. aip_agents/examples/hello_world_model_switch_cli.py +210 -0
  169. aip_agents/examples/hello_world_model_switch_cli.pyi +18 -3
  170. aip_agents/examples/hello_world_multi_agent_adk.py +75 -0
  171. aip_agents/examples/hello_world_multi_agent_langchain.py +54 -0
  172. aip_agents/examples/hello_world_multi_agent_langgraph.py +66 -0
  173. aip_agents/examples/hello_world_multi_agent_langgraph_lm_invoker.py +69 -0
  174. aip_agents/examples/hello_world_pii_logger.py +21 -0
  175. aip_agents/examples/hello_world_pii_logger.pyi +1 -1
  176. aip_agents/examples/hello_world_sentry.py +133 -0
  177. aip_agents/examples/hello_world_sentry.pyi +1 -1
  178. aip_agents/examples/hello_world_step_limits.py +273 -0
  179. aip_agents/examples/hello_world_step_limits.pyi +17 -0
  180. aip_agents/examples/hello_world_stock_a2a_server.py +103 -0
  181. aip_agents/examples/hello_world_stock_a2a_server.pyi +7 -2
  182. aip_agents/examples/hello_world_tool_output_client.py +46 -0
  183. aip_agents/examples/hello_world_tool_output_client.pyi +1 -1
  184. aip_agents/examples/hello_world_tool_output_server.py +114 -0
  185. aip_agents/examples/hello_world_tool_output_server.pyi +7 -2
  186. aip_agents/examples/hitl_demo.py +724 -0
  187. aip_agents/examples/hitl_demo.pyi +67 -0
  188. aip_agents/examples/mcp_configs/configs.py +63 -0
  189. aip_agents/examples/mcp_servers/common.py +76 -0
  190. aip_agents/examples/mcp_servers/mcp_name.py +29 -0
  191. aip_agents/examples/mcp_servers/mcp_server_http.py +19 -0
  192. aip_agents/examples/mcp_servers/mcp_server_sse.py +19 -0
  193. aip_agents/examples/mcp_servers/mcp_server_stdio.py +19 -0
  194. aip_agents/examples/mcp_servers/mcp_time.py +10 -0
  195. aip_agents/examples/pii_demo_langgraph_client.py +69 -0
  196. aip_agents/examples/pii_demo_langgraph_client.pyi +5 -0
  197. aip_agents/examples/pii_demo_langgraph_server.py +126 -0
  198. aip_agents/examples/pii_demo_langgraph_server.pyi +20 -0
  199. aip_agents/examples/pii_demo_multi_agent_client.py +80 -0
  200. aip_agents/examples/pii_demo_multi_agent_client.pyi +5 -0
  201. aip_agents/examples/pii_demo_multi_agent_server.py +247 -0
  202. aip_agents/examples/pii_demo_multi_agent_server.pyi +40 -0
  203. aip_agents/examples/todolist_planning_a2a_langchain_client.py +70 -0
  204. aip_agents/examples/todolist_planning_a2a_langchain_client.pyi +5 -0
  205. aip_agents/examples/todolist_planning_a2a_langgraph_server.py +88 -0
  206. aip_agents/examples/todolist_planning_a2a_langgraph_server.pyi +19 -0
  207. aip_agents/examples/tools/__init__.py +27 -0
  208. aip_agents/examples/tools/__init__.pyi +3 -1
  209. aip_agents/examples/tools/adk_arithmetic_tools.py +36 -0
  210. aip_agents/examples/tools/adk_weather_tool.py +60 -0
  211. aip_agents/examples/tools/adk_weather_tool.pyi +1 -1
  212. aip_agents/examples/tools/data_generator_tool.py +103 -0
  213. aip_agents/examples/tools/data_visualization_tool.py +312 -0
  214. aip_agents/examples/tools/data_visualization_tool.pyi +2 -0
  215. aip_agents/examples/tools/image_artifact_tool.py +136 -0
  216. aip_agents/examples/tools/image_artifact_tool.pyi +2 -0
  217. aip_agents/examples/tools/langchain_arithmetic_tools.py +26 -0
  218. aip_agents/examples/tools/langchain_arithmetic_tools.pyi +7 -0
  219. aip_agents/examples/tools/langchain_currency_exchange_tool.py +88 -0
  220. aip_agents/examples/tools/langchain_currency_exchange_tool.pyi +0 -1
  221. aip_agents/examples/tools/langchain_graph_artifact_tool.py +172 -0
  222. aip_agents/examples/tools/langchain_graph_artifact_tool.pyi +2 -0
  223. aip_agents/examples/tools/langchain_weather_tool.py +48 -0
  224. aip_agents/examples/tools/langchain_weather_tool.pyi +1 -1
  225. aip_agents/examples/tools/langgraph_streaming_tool.py +130 -0
  226. aip_agents/examples/tools/langgraph_streaming_tool.pyi +1 -1
  227. aip_agents/examples/tools/mock_retrieval_tool.py +56 -0
  228. aip_agents/examples/tools/mock_retrieval_tool.pyi +13 -0
  229. aip_agents/examples/tools/pii_demo_tools.py +189 -0
  230. aip_agents/examples/tools/pii_demo_tools.pyi +54 -0
  231. aip_agents/examples/tools/random_chart_tool.py +142 -0
  232. aip_agents/examples/tools/random_chart_tool.pyi +20 -0
  233. aip_agents/examples/tools/serper_tool.py +202 -0
  234. aip_agents/examples/tools/stock_tools.py +82 -0
  235. aip_agents/examples/tools/stock_tools.pyi +18 -3
  236. aip_agents/examples/tools/table_generator_tool.py +167 -0
  237. aip_agents/examples/tools/time_tool.py +82 -0
  238. aip_agents/examples/tools/weather_forecast_tool.py +38 -0
  239. aip_agents/executor/agent_executor.py +473 -0
  240. aip_agents/executor/base.py +48 -0
  241. aip_agents/mcp/__init__.py +1 -0
  242. aip_agents/mcp/client/__init__.py +14 -0
  243. aip_agents/mcp/client/__init__.pyi +4 -3
  244. aip_agents/mcp/client/base_mcp_client.py +369 -0
  245. aip_agents/mcp/client/base_mcp_client.pyi +148 -0
  246. aip_agents/mcp/client/connection_manager.py +193 -0
  247. aip_agents/mcp/client/connection_manager.pyi +48 -0
  248. aip_agents/mcp/client/google_adk/__init__.py +11 -0
  249. aip_agents/mcp/client/google_adk/__init__.pyi +1 -1
  250. aip_agents/mcp/client/google_adk/client.py +381 -0
  251. aip_agents/mcp/client/google_adk/client.pyi +50 -13
  252. aip_agents/mcp/client/langchain/__init__.py +11 -0
  253. aip_agents/mcp/client/langchain/__init__.pyi +1 -1
  254. aip_agents/mcp/client/langchain/client.py +265 -0
  255. aip_agents/mcp/client/langchain/client.pyi +47 -2
  256. aip_agents/mcp/client/persistent_session.py +359 -0
  257. aip_agents/mcp/client/persistent_session.pyi +113 -0
  258. aip_agents/mcp/client/session_pool.py +351 -0
  259. aip_agents/mcp/client/session_pool.pyi +101 -0
  260. aip_agents/mcp/client/transports.py +215 -0
  261. aip_agents/mcp/client/transports.pyi +123 -0
  262. aip_agents/mcp/utils/__init__.py +7 -0
  263. aip_agents/mcp/utils/__init__.pyi +0 -0
  264. aip_agents/mcp/utils/config_validator.py +139 -0
  265. aip_agents/mcp/utils/config_validator.pyi +82 -0
  266. aip_agents/memory/__init__.py +14 -0
  267. aip_agents/memory/__init__.pyi +5 -0
  268. aip_agents/memory/adapters/__init__.py +10 -0
  269. aip_agents/memory/adapters/__init__.pyi +4 -0
  270. aip_agents/memory/adapters/base_adapter.py +717 -0
  271. aip_agents/memory/adapters/base_adapter.pyi +150 -0
  272. aip_agents/memory/adapters/mem0.py +84 -0
  273. aip_agents/memory/adapters/mem0.pyi +22 -0
  274. aip_agents/memory/base.py +84 -0
  275. aip_agents/memory/base.pyi +15 -4
  276. aip_agents/memory/constants.py +49 -0
  277. aip_agents/memory/constants.pyi +25 -0
  278. aip_agents/memory/factory.py +86 -0
  279. aip_agents/memory/factory.pyi +24 -0
  280. aip_agents/memory/guidance.py +20 -0
  281. aip_agents/memory/guidance.pyi +3 -0
  282. aip_agents/memory/simple_memory.py +47 -0
  283. aip_agents/memory/simple_memory.pyi +6 -5
  284. aip_agents/middleware/__init__.py +17 -0
  285. aip_agents/middleware/__init__.pyi +5 -0
  286. aip_agents/middleware/base.py +88 -0
  287. aip_agents/middleware/base.pyi +71 -0
  288. aip_agents/middleware/manager.py +128 -0
  289. aip_agents/middleware/manager.pyi +80 -0
  290. aip_agents/middleware/todolist.py +274 -0
  291. aip_agents/middleware/todolist.pyi +125 -0
  292. aip_agents/schema/__init__.py +69 -0
  293. aip_agents/schema/__init__.pyi +9 -0
  294. aip_agents/schema/a2a.py +56 -0
  295. aip_agents/schema/a2a.pyi +40 -0
  296. aip_agents/schema/agent.py +111 -0
  297. aip_agents/schema/agent.pyi +65 -0
  298. aip_agents/schema/hitl.py +157 -0
  299. aip_agents/schema/hitl.pyi +89 -0
  300. aip_agents/schema/langgraph.py +37 -0
  301. aip_agents/schema/langgraph.pyi +28 -0
  302. aip_agents/schema/model_id.py +97 -0
  303. aip_agents/schema/model_id.pyi +54 -0
  304. aip_agents/schema/step_limit.py +108 -0
  305. aip_agents/schema/step_limit.pyi +63 -0
  306. aip_agents/schema/storage.py +40 -0
  307. aip_agents/schema/storage.pyi +21 -0
  308. aip_agents/sentry/__init__.py +11 -0
  309. aip_agents/sentry/__init__.pyi +1 -1
  310. aip_agents/sentry/sentry.py +151 -0
  311. aip_agents/sentry/sentry.pyi +2 -2
  312. aip_agents/storage/__init__.py +41 -0
  313. aip_agents/storage/base.py +85 -0
  314. aip_agents/storage/base.pyi +1 -2
  315. aip_agents/storage/clients/__init__.py +12 -0
  316. aip_agents/storage/clients/minio_client.py +318 -0
  317. aip_agents/storage/config.py +62 -0
  318. aip_agents/storage/config.pyi +9 -46
  319. aip_agents/storage/providers/__init__.py +15 -0
  320. aip_agents/storage/providers/base.py +106 -0
  321. aip_agents/storage/providers/base.pyi +2 -3
  322. aip_agents/storage/providers/memory.py +114 -0
  323. aip_agents/storage/providers/object_storage.py +214 -0
  324. aip_agents/storage/providers/object_storage.pyi +1 -1
  325. aip_agents/tools/__init__.py +6 -0
  326. aip_agents/tools/__init__.pyi +3 -2
  327. aip_agents/tools/bosa_tools.py +105 -0
  328. aip_agents/tools/bosa_tools.pyi +2 -2
  329. aip_agents/tools/browser_use/__init__.py +82 -0
  330. aip_agents/tools/browser_use/__init__.pyi +14 -0
  331. aip_agents/tools/browser_use/action_parser.py +103 -0
  332. aip_agents/tools/browser_use/action_parser.pyi +18 -0
  333. aip_agents/tools/browser_use/browser_use_tool.py +1112 -0
  334. aip_agents/tools/browser_use/browser_use_tool.pyi +50 -0
  335. aip_agents/tools/browser_use/llm_config.py +120 -0
  336. aip_agents/tools/browser_use/llm_config.pyi +52 -0
  337. aip_agents/tools/browser_use/minio_storage.py +198 -0
  338. aip_agents/tools/browser_use/minio_storage.pyi +109 -0
  339. aip_agents/tools/browser_use/schemas.py +119 -0
  340. aip_agents/tools/browser_use/schemas.pyi +32 -0
  341. aip_agents/tools/browser_use/session.py +76 -0
  342. aip_agents/tools/browser_use/session.pyi +4 -0
  343. aip_agents/tools/browser_use/session_errors.py +132 -0
  344. aip_agents/tools/browser_use/session_errors.pyi +53 -0
  345. aip_agents/tools/browser_use/steel_session_recording.py +317 -0
  346. aip_agents/tools/browser_use/steel_session_recording.pyi +63 -0
  347. aip_agents/tools/browser_use/streaming.py +813 -0
  348. aip_agents/tools/browser_use/streaming.pyi +81 -0
  349. aip_agents/tools/browser_use/structured_data_parser.py +257 -0
  350. aip_agents/tools/browser_use/structured_data_parser.pyi +86 -0
  351. aip_agents/tools/browser_use/structured_data_recovery.py +204 -0
  352. aip_agents/tools/browser_use/structured_data_recovery.pyi +43 -0
  353. aip_agents/tools/browser_use/types.py +78 -0
  354. aip_agents/tools/browser_use/types.pyi +45 -0
  355. aip_agents/tools/code_sandbox/__init__.py +26 -0
  356. aip_agents/tools/code_sandbox/__init__.pyi +3 -0
  357. aip_agents/tools/code_sandbox/constant.py +13 -0
  358. aip_agents/tools/code_sandbox/constant.pyi +4 -0
  359. aip_agents/tools/code_sandbox/e2b_cloud_sandbox_extended.py +257 -0
  360. aip_agents/tools/code_sandbox/e2b_cloud_sandbox_extended.pyi +86 -0
  361. aip_agents/tools/code_sandbox/e2b_sandbox_tool.py +411 -0
  362. aip_agents/tools/code_sandbox/e2b_sandbox_tool.pyi +29 -0
  363. aip_agents/tools/constants.py +165 -0
  364. aip_agents/tools/constants.pyi +105 -100
  365. aip_agents/tools/document_loader/__init__.py +37 -0
  366. aip_agents/tools/document_loader/__init__.pyi +7 -0
  367. aip_agents/tools/document_loader/base_reader.py +262 -0
  368. aip_agents/tools/document_loader/base_reader.pyi +62 -0
  369. aip_agents/tools/document_loader/docx_reader_tool.py +53 -0
  370. aip_agents/tools/document_loader/docx_reader_tool.pyi +6 -0
  371. aip_agents/tools/document_loader/excel_reader_tool.py +160 -0
  372. aip_agents/tools/document_loader/excel_reader_tool.pyi +26 -0
  373. aip_agents/tools/document_loader/pdf_reader_tool.py +67 -0
  374. aip_agents/tools/document_loader/pdf_reader_tool.pyi +11 -0
  375. aip_agents/tools/document_loader/pdf_splitter.py +169 -0
  376. aip_agents/tools/document_loader/pdf_splitter.pyi +18 -0
  377. aip_agents/tools/gl_connector/__init__.py +5 -0
  378. aip_agents/tools/gl_connector/__init__.pyi +3 -0
  379. aip_agents/tools/gl_connector/tool.py +351 -0
  380. aip_agents/tools/gl_connector/tool.pyi +74 -0
  381. aip_agents/tools/memory_search/__init__.py +22 -0
  382. aip_agents/tools/memory_search/__init__.pyi +5 -0
  383. aip_agents/tools/memory_search/base.py +200 -0
  384. aip_agents/tools/memory_search/base.pyi +69 -0
  385. aip_agents/tools/memory_search/mem0.py +258 -0
  386. aip_agents/tools/memory_search/mem0.pyi +19 -0
  387. aip_agents/tools/memory_search/schema.py +48 -0
  388. aip_agents/tools/memory_search/schema.pyi +15 -0
  389. aip_agents/tools/memory_search_tool.py +26 -0
  390. aip_agents/tools/memory_search_tool.pyi +3 -0
  391. aip_agents/tools/tool_config_injector.py +300 -0
  392. aip_agents/tools/web_search/__init__.py +15 -0
  393. aip_agents/tools/web_search/__init__.pyi +3 -0
  394. aip_agents/tools/web_search/serper_tool.py +187 -0
  395. aip_agents/tools/web_search/serper_tool.pyi +19 -0
  396. aip_agents/types/__init__.py +70 -0
  397. aip_agents/types/__init__.pyi +35 -2
  398. aip_agents/types/a2a_events.py +13 -0
  399. aip_agents/types/a2a_events.pyi +2 -73
  400. aip_agents/utils/__init__.py +79 -0
  401. aip_agents/utils/__init__.pyi +8 -2
  402. aip_agents/utils/a2a_connector.py +1757 -0
  403. aip_agents/utils/a2a_connector.pyi +15 -4
  404. aip_agents/utils/artifact_helpers.py +502 -0
  405. aip_agents/utils/artifact_helpers.pyi +26 -2
  406. aip_agents/utils/constants.py +22 -0
  407. aip_agents/utils/constants.pyi +10 -0
  408. aip_agents/utils/datetime/__init__.py +34 -0
  409. aip_agents/utils/datetime/__init__.pyi +4 -0
  410. aip_agents/utils/datetime/normalization.py +231 -0
  411. aip_agents/utils/datetime/normalization.pyi +95 -0
  412. aip_agents/utils/datetime/timezone.py +206 -0
  413. aip_agents/utils/datetime/timezone.pyi +48 -0
  414. aip_agents/utils/env_loader.py +27 -0
  415. aip_agents/utils/env_loader.pyi +10 -0
  416. aip_agents/utils/event_handler_registry.py +58 -0
  417. aip_agents/utils/event_handler_registry.pyi +23 -0
  418. aip_agents/utils/file_prompt_utils.py +176 -0
  419. aip_agents/utils/file_prompt_utils.pyi +21 -0
  420. aip_agents/utils/final_response_builder.py +211 -0
  421. aip_agents/utils/final_response_builder.pyi +34 -0
  422. aip_agents/utils/formatter_llm_client.py +231 -0
  423. aip_agents/utils/formatter_llm_client.pyi +71 -0
  424. aip_agents/utils/langgraph/__init__.py +19 -0
  425. aip_agents/utils/langgraph/converter.py +128 -0
  426. aip_agents/utils/langgraph/converter.pyi +1 -1
  427. aip_agents/utils/langgraph/tool_managers/__init__.py +15 -0
  428. aip_agents/utils/langgraph/tool_managers/a2a_tool_manager.py +99 -0
  429. aip_agents/utils/langgraph/tool_managers/a2a_tool_manager.pyi +2 -2
  430. aip_agents/utils/langgraph/tool_managers/base_tool_manager.py +66 -0
  431. aip_agents/utils/langgraph/tool_managers/base_tool_manager.pyi +2 -3
  432. aip_agents/utils/langgraph/tool_managers/delegation_tool_manager.py +1071 -0
  433. aip_agents/utils/langgraph/tool_managers/delegation_tool_manager.pyi +17 -11
  434. aip_agents/utils/langgraph/tool_output_management.py +967 -0
  435. aip_agents/utils/langgraph/tool_output_management.pyi +15 -33
  436. aip_agents/utils/logger.py +195 -0
  437. aip_agents/utils/logger.pyi +60 -0
  438. aip_agents/utils/metadata/__init__.py +27 -0
  439. aip_agents/utils/metadata/__init__.pyi +5 -0
  440. aip_agents/utils/metadata/activity_metadata_helper.py +407 -0
  441. aip_agents/utils/metadata/activity_metadata_helper.pyi +25 -0
  442. aip_agents/utils/metadata/activity_narrative/__init__.py +35 -0
  443. aip_agents/utils/metadata/activity_narrative/__init__.pyi +7 -0
  444. aip_agents/utils/metadata/activity_narrative/builder.py +817 -0
  445. aip_agents/utils/metadata/activity_narrative/builder.pyi +35 -0
  446. aip_agents/utils/metadata/activity_narrative/constants.py +51 -0
  447. aip_agents/utils/metadata/activity_narrative/constants.pyi +10 -0
  448. aip_agents/utils/metadata/activity_narrative/context.py +49 -0
  449. aip_agents/utils/metadata/activity_narrative/context.pyi +32 -0
  450. aip_agents/utils/metadata/activity_narrative/formatters.py +230 -0
  451. aip_agents/utils/metadata/activity_narrative/formatters.pyi +48 -0
  452. aip_agents/utils/metadata/activity_narrative/utils.py +35 -0
  453. aip_agents/utils/metadata/activity_narrative/utils.pyi +12 -0
  454. aip_agents/utils/metadata/schemas/__init__.py +16 -0
  455. aip_agents/utils/metadata/schemas/__init__.pyi +4 -0
  456. aip_agents/utils/metadata/schemas/activity_schema.py +29 -0
  457. aip_agents/utils/metadata/schemas/activity_schema.pyi +18 -0
  458. aip_agents/utils/metadata/schemas/thinking_schema.py +31 -0
  459. aip_agents/utils/metadata/schemas/thinking_schema.pyi +20 -0
  460. aip_agents/utils/metadata/thinking_metadata_helper.py +38 -0
  461. aip_agents/utils/metadata/thinking_metadata_helper.pyi +4 -0
  462. aip_agents/utils/metadata_helper.py +358 -0
  463. aip_agents/utils/metadata_helper.pyi +55 -48
  464. aip_agents/utils/name_preprocessor/__init__.py +17 -0
  465. aip_agents/utils/name_preprocessor/base_name_preprocessor.py +73 -0
  466. aip_agents/utils/name_preprocessor/base_name_preprocessor.pyi +1 -2
  467. aip_agents/utils/name_preprocessor/google_name_preprocessor.py +100 -0
  468. aip_agents/utils/name_preprocessor/google_name_preprocessor.pyi +1 -1
  469. aip_agents/utils/name_preprocessor/name_preprocessor.py +87 -0
  470. aip_agents/utils/name_preprocessor/name_preprocessor.pyi +4 -4
  471. aip_agents/utils/name_preprocessor/openai_name_preprocessor.py +48 -0
  472. aip_agents/utils/name_preprocessor/openai_name_preprocessor.pyi +1 -1
  473. aip_agents/utils/pii/__init__.py +25 -0
  474. aip_agents/utils/pii/__init__.pyi +5 -0
  475. aip_agents/utils/pii/pii_handler.py +397 -0
  476. aip_agents/utils/pii/pii_handler.pyi +96 -0
  477. aip_agents/utils/pii/pii_helper.py +207 -0
  478. aip_agents/utils/pii/pii_helper.pyi +78 -0
  479. aip_agents/utils/pii/uuid_deanonymizer_mapping.py +195 -0
  480. aip_agents/utils/pii/uuid_deanonymizer_mapping.pyi +73 -0
  481. aip_agents/utils/reference_helper.py +273 -0
  482. aip_agents/utils/reference_helper.pyi +38 -6
  483. aip_agents/utils/sse_chunk_transformer.py +831 -0
  484. aip_agents/utils/sse_chunk_transformer.pyi +166 -0
  485. aip_agents/utils/step_limit_manager.py +265 -0
  486. aip_agents/utils/step_limit_manager.pyi +112 -0
  487. aip_agents/utils/token_usage_helper.py +156 -0
  488. aip_agents/utils/token_usage_helper.pyi +1 -1
  489. aip_agents_binary-0.5.11.dist-info/METADATA +689 -0
  490. aip_agents_binary-0.5.11.dist-info/RECORD +542 -0
  491. {aip_agents_binary-0.0.0b2.dist-info → aip_agents_binary-0.5.11.dist-info}/WHEEL +2 -1
  492. aip_agents_binary-0.5.11.dist-info/top_level.txt +1 -0
  493. aip_agents/agent/types.pyi +0 -106
  494. aip_agents/examples/hello_world_a2a_multi_agent_coordinator_client.pyi +0 -15
  495. aip_agents/examples/hello_world_a2a_multi_agent_coordinator_client_streaming.pyi +0 -5
  496. aip_agents/examples/hello_world_a2a_multi_agent_coordinator_server.pyi +0 -11
  497. aip_agents/examples/hello_world_langgraph_bosa.pyi +0 -5
  498. aip_agents/examples/tools/pr_details_bosa_tool.pyi +0 -26
  499. aip_agents/tools/base.pyi +0 -44
  500. aip_agents/tools/base_bosa_tools.pyi +0 -12
  501. aip_agents/tools/bosa_connector.pyi +0 -30
  502. aip_agents/tools/bosa_tools_interface.pyi +0 -26
  503. aip_agents/tools/nested_agent_tool.pyi +0 -45
  504. aip_agents/utils/logger_manager.pyi +0 -151
  505. aip_agents_binary-0.0.0b2.dist-info/METADATA +0 -277
  506. aip_agents_binary-0.0.0b2.dist-info/RECORD +0 -157
@@ -0,0 +1,23 @@
1
+ from _typeshed import Incomplete
2
+ from aip_agents.schema.a2a import A2AStreamEventType as A2AStreamEventType
3
+ from aip_agents.utils.logger import get_logger as get_logger
4
+ from typing import Any
5
+
6
+ logger: Incomplete
7
+
8
+ class EventHandlerRegistry:
9
+ """Registry for tracking known streaming events with pass-through behaviour."""
10
+ def __init__(self) -> None:
11
+ """Initialize the event handler registry with known event types."""
12
+ def handle(self, event_type: A2AStreamEventType | str | None, payload: dict[str, Any]) -> dict[str, Any]:
13
+ """Return the payload unchanged while logging unknown events.
14
+
15
+ Args:
16
+ event_type (A2AStreamEventType | str | None): The type of the streaming event.
17
+ payload (dict[str, Any]): The event payload data.
18
+
19
+ Returns:
20
+ dict[str, Any]: The payload unchanged (pass-through).
21
+ """
22
+
23
+ DEFAULT_EVENT_HANDLER_REGISTRY: Incomplete
@@ -0,0 +1,176 @@
1
+ """Utilities for augmenting prompts with local file path notes.
2
+
3
+ This module adds file path metadata to queries but does not read file contents.
4
+
5
+ Authors:
6
+ Fachriza Adhiatma (fachriza.d.adhiatma@gdplabs.id)
7
+ """
8
+
9
+ import os
10
+
11
+ from aip_agents.utils.logger import get_logger
12
+
13
+ logger = get_logger(__name__)
14
+
15
+ FILE_PATH_SYSTEM_NOTE = (
16
+ "\n\n[System Note: The user has provided a file named '{filename}'. "
17
+ "It is available at the following local path: {path}]"
18
+ )
19
+ FILE_PATH_INACCESSIBLE_NOTE = (
20
+ "\n\n[System Note: A file path was provided ({path}), but the file is not accessible. "
21
+ "Please inform the user about this issue.]"
22
+ )
23
+ FILE_URL_SYSTEM_NOTE = (
24
+ "\n\n[System Note: The file is also available at the following URL: {url} (expires in {expires_in} {hour_unit}).]"
25
+ )
26
+
27
+
28
+ def _normalize_file_entry(entry: str | dict[str, object]) -> dict[str, object] | None:
29
+ """Normalize a single file entry into a dict.
30
+
31
+ Args:
32
+ entry: A string file path or a metadata dict.
33
+
34
+ Returns:
35
+ A normalized metadata dict or None if the entry is falsy.
36
+
37
+ Raises:
38
+ ValueError: If metadata dicts do not include a valid path.
39
+ """
40
+ if not entry:
41
+ return None
42
+
43
+ if isinstance(entry, str):
44
+ return {"path": entry}
45
+
46
+ if isinstance(entry, dict):
47
+ path = entry.get("path") or entry.get("local_path")
48
+ if not isinstance(path, str) or not path:
49
+ raise ValueError("file metadata dicts must include a non-empty 'path'")
50
+ return {
51
+ "path": path,
52
+ "filename": entry.get("filename"),
53
+ "s3_url": entry.get("s3_url") or entry.get("url") or entry.get("file_uri"),
54
+ "expires_in_hours": entry.get("expires_in_hours"),
55
+ }
56
+
57
+ raise ValueError("files must be a list of strings or dicts")
58
+
59
+
60
+ def _dedupe_file_entries(files: list[str | dict[str, object]]) -> list[dict[str, object]]:
61
+ """Normalize and deduplicate file entries by their resolved path.
62
+
63
+ Args:
64
+ files: List of local filesystem paths or file metadata dicts.
65
+
66
+ Returns:
67
+ Deduplicated list of normalized dict entries.
68
+ """
69
+ seen: set[str] = set()
70
+ deduped_entries: list[dict[str, object]] = []
71
+
72
+ for raw_entry in files:
73
+ try:
74
+ normalized = _normalize_file_entry(raw_entry)
75
+ except ValueError as exc:
76
+ logger.warning(f"Skipping invalid file entry: {exc}")
77
+ continue
78
+ if not normalized:
79
+ continue
80
+ path_value = normalized.get("path")
81
+ path = path_value if isinstance(path_value, str) else str(path_value)
82
+ if path in seen:
83
+ continue
84
+ seen.add(path)
85
+ deduped_entries.append(normalized)
86
+
87
+ return deduped_entries
88
+
89
+
90
+ def _format_expiration_hours(expires_in_hours: object) -> tuple[object, str]:
91
+ """Format expiration hours for display.
92
+
93
+ Args:
94
+ expires_in_hours: Expiration hours value.
95
+
96
+ Returns:
97
+ Tuple of (expires_value, hour_unit).
98
+ """
99
+ if isinstance(expires_in_hours, int):
100
+ return expires_in_hours, "hour" if expires_in_hours == 1 else "hours"
101
+
102
+ if isinstance(expires_in_hours, str) and expires_in_hours.isdigit():
103
+ expires_value = int(expires_in_hours)
104
+ return expires_value, "hour" if expires_value == 1 else "hours"
105
+
106
+ return "unknown", "hours"
107
+
108
+
109
+ def _build_file_path_note(entry: dict[str, object]) -> str:
110
+ """Build the system note for a file path entry.
111
+
112
+ Args:
113
+ entry: Normalized file metadata dict.
114
+
115
+ Returns:
116
+ System note string describing the file path accessibility.
117
+ """
118
+ path = str(entry["path"])
119
+ is_accessible = os.path.isfile(path) and os.access(path, os.R_OK)
120
+ if is_accessible:
121
+ filename_value = entry.get("filename")
122
+ filename = filename_value if isinstance(filename_value, str) and filename_value else os.path.basename(path)
123
+ return FILE_PATH_SYSTEM_NOTE.format(filename=filename, path=path)
124
+
125
+ logger.warning(f"File path is not accessible: {path}")
126
+ return FILE_PATH_INACCESSIBLE_NOTE.format(path=path)
127
+
128
+
129
+ def _build_file_url_note(entry: dict[str, object]) -> str:
130
+ """Build the system note for a file URL entry.
131
+
132
+ Args:
133
+ entry: Normalized file metadata dict.
134
+
135
+ Returns:
136
+ System note string describing the URL, or an empty string if no URL exists.
137
+ """
138
+ url = entry.get("s3_url")
139
+ if not isinstance(url, str) or not url:
140
+ return ""
141
+
142
+ expires_value, hour_unit = _format_expiration_hours(entry.get("expires_in_hours"))
143
+ return FILE_URL_SYSTEM_NOTE.format(
144
+ url=url,
145
+ expires_in=expires_value,
146
+ hour_unit=hour_unit,
147
+ )
148
+
149
+
150
+ def augment_query_with_file_paths(query: str, files: list[str | dict[str, object]]) -> str:
151
+ """Augment query with file path system notes.
152
+
153
+ Args:
154
+ query: The original user query string.
155
+ files: List of local filesystem paths or file metadata dicts to include.
156
+
157
+ Returns:
158
+ The query with system notes appended for each file path.
159
+
160
+ Raises:
161
+ ValueError: If files is not a list of strings or metadata dicts.
162
+ """
163
+ if not isinstance(files, list):
164
+ raise ValueError("files must be a list of strings or dicts")
165
+
166
+ deduped_entries = _dedupe_file_entries(files)
167
+
168
+ if not deduped_entries:
169
+ return query
170
+
171
+ augmented_query = query
172
+ for entry in deduped_entries:
173
+ augmented_query += _build_file_path_note(entry)
174
+ augmented_query += _build_file_url_note(entry)
175
+
176
+ return augmented_query
@@ -0,0 +1,21 @@
1
+ from _typeshed import Incomplete
2
+ from aip_agents.utils.logger import get_logger as get_logger
3
+
4
+ logger: Incomplete
5
+ FILE_PATH_SYSTEM_NOTE: str
6
+ FILE_PATH_INACCESSIBLE_NOTE: str
7
+ FILE_URL_SYSTEM_NOTE: str
8
+
9
+ def augment_query_with_file_paths(query: str, files: list[str | dict[str, object]]) -> str:
10
+ """Augment query with file path system notes.
11
+
12
+ Args:
13
+ query: The original user query string.
14
+ files: List of local filesystem paths or file metadata dicts to include.
15
+
16
+ Returns:
17
+ The query with system notes appended for each file path.
18
+
19
+ Raises:
20
+ ValueError: If files is not a list of strings or metadata dicts.
21
+ """
@@ -0,0 +1,211 @@
1
+ """Utilities for assembling final response events with consistent structure.
2
+
3
+ This module wraps the lower-level ``_build_final_response_event`` helper and
4
+ provides a single entry point for producing final response payloads that may
5
+ include accumulated artifacts, custom metadata overrides, and additional
6
+ top-level fields.
7
+
8
+ Authors:
9
+ Raymond Christopher (raymond.christopher@gdplabs.id)
10
+ """
11
+
12
+ from __future__ import annotations
13
+
14
+ from dataclasses import dataclass
15
+ from datetime import UTC, datetime
16
+ from typing import Any
17
+
18
+ from aip_agents.utils.metadata_helper import Kind, MetadataFieldKeys, Status
19
+
20
+ _FINAL_METADATA_RESERVED_KEYS = {
21
+ MetadataFieldKeys.KIND.value,
22
+ MetadataFieldKeys.STATUS.value,
23
+ "timestamp",
24
+ }
25
+
26
+
27
+ @dataclass(slots=True)
28
+ class FinalResponseMetadataOptions:
29
+ """Container for optional metadata fields on final response events."""
30
+
31
+ step_id: str | None = None
32
+ previous_step_ids: list[str] | None = None
33
+ tool_info: dict[str, Any] | None = None
34
+ thinking_and_activity_info: dict[str, Any] | None = None
35
+ completion_reason: str | None = None
36
+ timeout_seconds: float | None = None
37
+ message: dict[str, Any] | None = None
38
+ partial_result: str | None = None
39
+ metadata_extra: dict[str, Any] | None = None
40
+
41
+
42
+ def _metadata_overrides_from_options(options: FinalResponseMetadataOptions) -> dict[str, Any]:
43
+ """Build a dictionary of metadata overrides from the provided options.
44
+
45
+ Args:
46
+ options: The metadata options to extract overrides from.
47
+ """
48
+ potential_overrides = {
49
+ "step_id": options.step_id,
50
+ "previous_step_ids": options.previous_step_ids,
51
+ MetadataFieldKeys.TOOL_INFO: options.tool_info,
52
+ MetadataFieldKeys.THINKING_AND_ACTIVITY_INFO: options.thinking_and_activity_info,
53
+ "completion_reason": options.completion_reason,
54
+ "timeout_seconds": options.timeout_seconds,
55
+ MetadataFieldKeys.MESSAGE: options.message,
56
+ "partial_result": options.partial_result,
57
+ }
58
+ return {key: value for key, value in potential_overrides.items() if value is not None}
59
+
60
+
61
+ def _normalized_metadata_extras(metadata_extra: dict[str, Any] | None) -> dict[str, Any]:
62
+ """Return metadata extras filtered for reserved keys and normalized to strings.
63
+
64
+ Args:
65
+ metadata_extra: Additional metadata to normalize, or None.
66
+ """
67
+ if not metadata_extra:
68
+ return {}
69
+ normalized: dict[str, Any] = {}
70
+ for key, value in metadata_extra.items():
71
+ normalized_key = str(key)
72
+ if normalized_key in _FINAL_METADATA_RESERVED_KEYS:
73
+ continue
74
+ normalized[normalized_key] = value
75
+ return normalized
76
+
77
+
78
+ def _update_optional_top_level_fields(
79
+ event: dict[str, Any],
80
+ status: str,
81
+ task_state: str,
82
+ artifacts: list[dict[str, Any]] | None,
83
+ ) -> None:
84
+ """Apply optional top-level fields when they are provided.
85
+
86
+ Args:
87
+ event: The event dictionary to update.
88
+ status: The status value to set.
89
+ task_state: The task state value to set.
90
+ artifacts: List of artifacts to include, or None.
91
+ """
92
+ for key, value in (("status", status), ("task_state", task_state)):
93
+ if value:
94
+ event[key] = value
95
+ if artifacts:
96
+ event["artifacts"] = artifacts
97
+
98
+
99
+ def _ensure_timestamp_alignment(
100
+ event: dict[str, Any],
101
+ metadata: dict[str, Any],
102
+ timestamp: datetime | None,
103
+ ) -> None:
104
+ """Keep event-level and metadata timestamps synchronized.
105
+
106
+ Args:
107
+ event: The event dictionary containing timestamp information.
108
+ metadata: The metadata dictionary to update.
109
+ timestamp: The timestamp to align, or None.
110
+ """
111
+ event_timestamp = event.get("timestamp")
112
+ if event_timestamp is not None:
113
+ metadata["timestamp"] = event_timestamp
114
+ return
115
+
116
+ metadata_timestamp = metadata.get("timestamp")
117
+ if metadata_timestamp is not None:
118
+ event["timestamp"] = metadata_timestamp
119
+ return
120
+
121
+ resolved_timestamp = (timestamp or datetime.now(UTC)).isoformat()
122
+ metadata["timestamp"] = resolved_timestamp
123
+ event["timestamp"] = resolved_timestamp
124
+
125
+
126
+ def _build_final_response_event(
127
+ *,
128
+ content: str,
129
+ metadata_options: FinalResponseMetadataOptions | None = None,
130
+ event_extra: dict[str, Any] | None = None,
131
+ timestamp: datetime | None = None,
132
+ ) -> dict[str, Any]:
133
+ """Build a standardized final_response event payload.
134
+
135
+ Args:
136
+ content: The human-readable message to include in the event.
137
+ metadata_options: Optional container for per-event metadata overrides such as
138
+ identifiers, tool info, localized messages, and completion details.
139
+ event_extra: Additional top-level event fields to merge (e.g., task_id).
140
+ timestamp: Explicit timestamp for the event; defaults to current UTC time.
141
+
142
+ Returns:
143
+ dict[str, Any]: Final response payload ready for SSE serialization.
144
+ """
145
+ timestamp_value = (timestamp or datetime.now(UTC)).isoformat()
146
+ metadata: dict[str, Any] = {
147
+ MetadataFieldKeys.KIND: Kind.FINAL_RESPONSE,
148
+ MetadataFieldKeys.STATUS: Status.FINISHED,
149
+ MetadataFieldKeys.TIME: 0.0,
150
+ "timestamp": timestamp_value,
151
+ }
152
+
153
+ if metadata_options is not None:
154
+ metadata.update(_metadata_overrides_from_options(metadata_options))
155
+ metadata.update(_normalized_metadata_extras(metadata_options.metadata_extra))
156
+
157
+ event: dict[str, Any] = {
158
+ "status": "success",
159
+ "task_state": "completed",
160
+ "content": content,
161
+ "event_type": "final_response",
162
+ "final": True,
163
+ "metadata": metadata,
164
+ }
165
+
166
+ if event_extra:
167
+ event.update(event_extra)
168
+
169
+ return event
170
+
171
+
172
+ def assemble_final_response(
173
+ *,
174
+ content: str,
175
+ artifacts: list[dict[str, Any]] | None = None,
176
+ metadata_options: FinalResponseMetadataOptions | None = None,
177
+ status: str = "success",
178
+ task_state: str = "completed",
179
+ extra_fields: dict[str, Any] | None = None,
180
+ timestamp: datetime | None = None,
181
+ ) -> dict[str, Any]:
182
+ """Create a final response event with optional artifacts and overrides.
183
+
184
+ Args:
185
+ content: Human readable message for the final response.
186
+ artifacts: Optional list of artifact dictionaries to attach.
187
+ metadata_options: Metadata overrides passed through to the underlying builder.
188
+ status: Top-level status string; defaults to ``"success"``.
189
+ task_state: State string describing the task; defaults to ``"completed"``.
190
+ extra_fields: Additional top-level fields to merge onto the event.
191
+ timestamp: Explicit timestamp for the event. Defaults to ``datetime.now(UTC)``.
192
+
193
+ Returns:
194
+ dict[str, Any]: Final response event payload ready for downstream streaming.
195
+ """
196
+ event = _build_final_response_event(
197
+ content=content,
198
+ metadata_options=metadata_options,
199
+ event_extra=extra_fields,
200
+ timestamp=timestamp,
201
+ )
202
+
203
+ _update_optional_top_level_fields(event, status, task_state, artifacts)
204
+
205
+ metadata = event.setdefault("metadata", {})
206
+ _ensure_timestamp_alignment(event, metadata, timestamp)
207
+
208
+ return event
209
+
210
+
211
+ __all__ = ["FinalResponseMetadataOptions", "assemble_final_response"]
@@ -0,0 +1,34 @@
1
+ from dataclasses import dataclass
2
+ from datetime import datetime
3
+ from typing import Any
4
+
5
+ __all__ = ['FinalResponseMetadataOptions', 'assemble_final_response']
6
+
7
+ @dataclass(slots=True)
8
+ class FinalResponseMetadataOptions:
9
+ """Container for optional metadata fields on final response events."""
10
+ step_id: str | None = ...
11
+ previous_step_ids: list[str] | None = ...
12
+ tool_info: dict[str, Any] | None = ...
13
+ thinking_and_activity_info: dict[str, Any] | None = ...
14
+ completion_reason: str | None = ...
15
+ timeout_seconds: float | None = ...
16
+ message: dict[str, Any] | None = ...
17
+ partial_result: str | None = ...
18
+ metadata_extra: dict[str, Any] | None = ...
19
+
20
+ def assemble_final_response(*, content: str, artifacts: list[dict[str, Any]] | None = None, metadata_options: FinalResponseMetadataOptions | None = None, status: str = 'success', task_state: str = 'completed', extra_fields: dict[str, Any] | None = None, timestamp: datetime | None = None) -> dict[str, Any]:
21
+ '''Create a final response event with optional artifacts and overrides.
22
+
23
+ Args:
24
+ content: Human readable message for the final response.
25
+ artifacts: Optional list of artifact dictionaries to attach.
26
+ metadata_options: Metadata overrides passed through to the underlying builder.
27
+ status: Top-level status string; defaults to ``"success"``.
28
+ task_state: State string describing the task; defaults to ``"completed"``.
29
+ extra_fields: Additional top-level fields to merge onto the event.
30
+ timestamp: Explicit timestamp for the event. Defaults to ``datetime.now(UTC)``.
31
+
32
+ Returns:
33
+ dict[str, Any]: Final response event payload ready for downstream streaming.
34
+ '''
@@ -0,0 +1,231 @@
1
+ """Utilities for working with the shared formatter LLM invoker.
2
+
3
+ Authors:
4
+ Raymond Christopher (raymond.christopher@gdplabs.id)
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import asyncio
10
+ import os
11
+ import threading
12
+ from collections.abc import Awaitable, Callable
13
+ from typing import Any, TypeVar
14
+
15
+ from gllm_inference.builder import build_lm_invoker
16
+ from gllm_inference.lm_invoker.lm_invoker import BaseLMInvoker
17
+
18
+ from aip_agents.utils.logger import get_logger
19
+
20
+ logger = get_logger(__name__)
21
+
22
+ FORMATTER_ENV_VAR = "DEFAULT_MODEL_FORMATTER"
23
+ T = TypeVar("T")
24
+
25
+
26
+ class FormatterInvokerUnavailableError(RuntimeError):
27
+ """Raised when no formatter LLM invoker can be resolved."""
28
+
29
+
30
+ class FormatterInvocationError(RuntimeError):
31
+ """Raised when invoking the formatter LLM fails."""
32
+
33
+
34
+ class FormatterLLMClient:
35
+ """Stateful helper that manages formatter invoker resolution and execution."""
36
+
37
+ def __init__(self) -> None:
38
+ """Initialize the formatter LLM client with caching and thread safety."""
39
+ self._failed_sentinel = object()
40
+ self._invoker_cache: dict[str, BaseLMInvoker | object] = {}
41
+ self._lock = threading.Lock()
42
+
43
+ # ------------------------------------------------------------------
44
+ # Public API
45
+ # ------------------------------------------------------------------
46
+ def seed_default(self, default_model_id: str | None) -> None:
47
+ """Populate ``DEFAULT_MODEL_FORMATTER`` when unset.
48
+
49
+ Args:
50
+ default_model_id: Preferred formatter model id to use as a fallback.
51
+ """
52
+ current = self._normalize_model_id(os.getenv(FORMATTER_ENV_VAR))
53
+ if current:
54
+ return
55
+
56
+ fallback = self._normalize_model_id(default_model_id)
57
+ if fallback:
58
+ os.environ[FORMATTER_ENV_VAR] = fallback
59
+
60
+ def resolve_invoker(self, *, reset_cache: bool = False) -> BaseLMInvoker | None:
61
+ """Return the cached formatter invoker, optionally refreshing it.
62
+
63
+ Args:
64
+ reset_cache: When True, clear the cached invoker before resolving.
65
+
66
+ Returns:
67
+ BaseLMInvoker | None: Cached invoker if the formatter is configured, otherwise None.
68
+ """
69
+ resolved = self._normalize_model_id(os.getenv(FORMATTER_ENV_VAR))
70
+ if not resolved:
71
+ logger.warning("DEFAULT_MODEL_FORMATTER is not set; formatter summaries are disabled.")
72
+ return None
73
+
74
+ with self._lock:
75
+ if reset_cache:
76
+ self._invoker_cache.pop(resolved, None)
77
+
78
+ cached = self._invoker_cache.get(resolved)
79
+ if cached is self._failed_sentinel:
80
+ return None
81
+ if cached is not None:
82
+ return cached # type: ignore[return-value]
83
+
84
+ try:
85
+ invoker = build_lm_invoker(model_id=resolved)
86
+ except Exception as exc: # pragma: no cover - best effort
87
+ logger.warning("Failed to initialize formatter LLM invoker (%s): %s", resolved, exc)
88
+ self._invoker_cache[resolved] = self._failed_sentinel
89
+ return None
90
+
91
+ self._invoker_cache[resolved] = invoker
92
+ return invoker
93
+
94
+ async def invoke(
95
+ self,
96
+ *args: Any,
97
+ invoker: BaseLMInvoker | None = None,
98
+ timeout: float | None = None,
99
+ **kwargs: Any,
100
+ ) -> Any:
101
+ """Dispatch formatter prompts asynchronously with timeout/error handling.
102
+
103
+ Args:
104
+ *args: Positional arguments forwarded to the invoker.
105
+ invoker: Explicit invoker instance to reuse instead of resolving one.
106
+ timeout: Optional timeout (seconds) enforced with ``asyncio.timeout``.
107
+ **kwargs: Keyword arguments forwarded to the invoker.
108
+
109
+ Returns:
110
+ Any: Result returned by the formatter LLM.
111
+
112
+ Raises:
113
+ FormatterInvokerUnavailableError: If no formatter model is configured.
114
+ FormatterInvocationError: When the invocation fails or exceeds the timeout.
115
+ """
116
+ resolved = invoker or self.resolve_invoker()
117
+ if not resolved:
118
+ raise FormatterInvokerUnavailableError("Formatter LLM invoker is unavailable.")
119
+
120
+ try:
121
+ invocation = resolved.invoke(*args, **kwargs)
122
+ if timeout is not None:
123
+ async with asyncio.timeout(timeout):
124
+ return await invocation
125
+ return await invocation
126
+ except asyncio.CancelledError:
127
+ raise
128
+ except TimeoutError:
129
+ raise FormatterInvocationError("Formatter LLM invocation timed out") from None
130
+ except Exception as exc: # pragma: no cover - best effort
131
+ raise FormatterInvocationError(f"Formatter LLM invocation failed: {exc}") from exc
132
+
133
+ def invoke_blocking(
134
+ self,
135
+ *args: Any,
136
+ invoker: BaseLMInvoker | None = None,
137
+ timeout: float | None = None,
138
+ **kwargs: Any,
139
+ ) -> Any:
140
+ """Invoke the formatter LLM from synchronous contexts.
141
+
142
+ Args:
143
+ *args: Positional arguments forwarded to ``invoke``.
144
+ invoker: Optional invoker to reuse.
145
+ timeout: Optional timeout (seconds) for the async invocation.
146
+ **kwargs: Keyword arguments forwarded to ``invoke``.
147
+
148
+ Returns:
149
+ Any: Result returned by the formatter LLM.
150
+ """
151
+
152
+ async def _runner() -> Any:
153
+ return await self.invoke(*args, invoker=invoker, timeout=timeout, **kwargs)
154
+
155
+ return self._run_coroutine_blocking(_runner)
156
+
157
+ # ------------------------------------------------------------------
158
+ # Internal helpers
159
+ # ------------------------------------------------------------------
160
+ @staticmethod
161
+ def _normalize_model_id(value: str | None) -> str | None:
162
+ """Strip whitespace and return the model id when a value was provided.
163
+
164
+ Args:
165
+ value: Raw model identifier pulled from the environment.
166
+
167
+ Returns:
168
+ str | None: Sanitized model id or None when the input was blank.
169
+ """
170
+ if isinstance(value, str):
171
+ stripped = value.strip()
172
+ if stripped:
173
+ return stripped
174
+ return None
175
+
176
+ def _run_coroutine_blocking(self, factory: Callable[[], Awaitable[T]]) -> T:
177
+ """Execute an awaitable from sync code, even when a loop is already running.
178
+
179
+ Args:
180
+ factory: Callable returning the coroutine to execute.
181
+
182
+ Returns:
183
+ T: Result of the awaited coroutine.
184
+ """
185
+
186
+ async def _wrapper() -> T:
187
+ return await factory()
188
+
189
+ try:
190
+ asyncio.get_running_loop()
191
+ except RuntimeError:
192
+ return asyncio.run(_wrapper())
193
+
194
+ result: dict[str, T] = {}
195
+ error: list[BaseException] = []
196
+ done = threading.Event()
197
+
198
+ def _thread_runner() -> None:
199
+ try:
200
+ value = asyncio.run(_wrapper())
201
+ result["value"] = value
202
+ except Exception as exc:
203
+ error.append(exc)
204
+ finally:
205
+ done.set()
206
+
207
+ thread = threading.Thread(target=_thread_runner, daemon=True)
208
+ thread.start()
209
+ done.wait()
210
+ thread.join()
211
+
212
+ if error:
213
+ raise error[0]
214
+ return result["value"]
215
+
216
+
217
+ _formatter_llm_client = FormatterLLMClient()
218
+
219
+
220
+ def get_formatter_llm_client() -> FormatterLLMClient:
221
+ """Return the process-wide formatter LLM client."""
222
+ return _formatter_llm_client
223
+
224
+
225
+ def seed_formatter_llm_default(default_model_id: str | None) -> None:
226
+ """Convenience wrapper for seeding the formatter default model.
227
+
228
+ Args:
229
+ default_model_id: Formatter model identifier to seed when missing.
230
+ """
231
+ get_formatter_llm_client().seed_default(default_model_id)