aip-agents-binary 0.0.0b2__py3-none-any.whl → 0.5.12__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 (426) hide show
  1. aip_agents/__init__.py +65 -0
  2. aip_agents/a2a/__init__.py +19 -0
  3. aip_agents/a2a/server/__init__.py +10 -0
  4. aip_agents/a2a/server/base_executor.py +1086 -0
  5. aip_agents/a2a/server/google_adk_executor.py +198 -0
  6. aip_agents/a2a/server/langflow_executor.py +180 -0
  7. aip_agents/a2a/server/langgraph_executor.py +270 -0
  8. aip_agents/a2a/types.py +232 -0
  9. aip_agents/agent/__init__.py +27 -0
  10. aip_agents/agent/base_agent.py +970 -0
  11. aip_agents/agent/base_langgraph_agent.py +2942 -0
  12. aip_agents/agent/google_adk_agent.py +926 -0
  13. aip_agents/agent/google_adk_constants.py +6 -0
  14. aip_agents/agent/hitl/__init__.py +24 -0
  15. aip_agents/agent/hitl/config.py +28 -0
  16. aip_agents/agent/hitl/langgraph_hitl_mixin.py +515 -0
  17. aip_agents/agent/hitl/manager.py +532 -0
  18. aip_agents/agent/hitl/models.py +18 -0
  19. aip_agents/agent/hitl/prompt/__init__.py +9 -0
  20. aip_agents/agent/hitl/prompt/base.py +42 -0
  21. aip_agents/agent/hitl/prompt/deferred.py +73 -0
  22. aip_agents/agent/hitl/registry.py +149 -0
  23. aip_agents/agent/{interface.pyi → interface.py} +70 -13
  24. aip_agents/agent/interfaces.py +65 -0
  25. aip_agents/agent/langflow_agent.py +464 -0
  26. aip_agents/agent/langgraph_memory_enhancer_agent.py +433 -0
  27. aip_agents/agent/langgraph_react_agent.py +2514 -0
  28. aip_agents/agent/system_instruction_context.py +34 -0
  29. aip_agents/clients/__init__.py +10 -0
  30. aip_agents/clients/langflow/__init__.py +10 -0
  31. aip_agents/clients/langflow/client.py +477 -0
  32. aip_agents/clients/langflow/types.py +18 -0
  33. aip_agents/constants.py +23 -0
  34. aip_agents/credentials/manager.py +132 -0
  35. aip_agents/examples/__init__.py +5 -0
  36. aip_agents/examples/compare_streaming_client.py +783 -0
  37. aip_agents/examples/compare_streaming_server.py +142 -0
  38. aip_agents/examples/demo_memory_recall.py +401 -0
  39. aip_agents/examples/hello_world_a2a_google_adk_client.py +49 -0
  40. aip_agents/examples/hello_world_a2a_google_adk_client_agent.py +48 -0
  41. aip_agents/examples/hello_world_a2a_google_adk_client_streaming.py +60 -0
  42. aip_agents/examples/hello_world_a2a_google_adk_server.py +79 -0
  43. aip_agents/examples/hello_world_a2a_langchain_client.py +39 -0
  44. aip_agents/examples/hello_world_a2a_langchain_client_agent.py +39 -0
  45. aip_agents/examples/hello_world_a2a_langchain_client_lm_invoker.py +37 -0
  46. aip_agents/examples/hello_world_a2a_langchain_client_streaming.py +41 -0
  47. aip_agents/examples/hello_world_a2a_langchain_reference_client_streaming.py +60 -0
  48. aip_agents/examples/hello_world_a2a_langchain_reference_server.py +105 -0
  49. aip_agents/examples/hello_world_a2a_langchain_server.py +79 -0
  50. aip_agents/examples/hello_world_a2a_langchain_server_lm_invoker.py +78 -0
  51. aip_agents/examples/hello_world_a2a_langflow_client.py +83 -0
  52. aip_agents/examples/hello_world_a2a_langflow_server.py +82 -0
  53. aip_agents/examples/hello_world_a2a_langgraph_artifact_client.py +73 -0
  54. aip_agents/examples/hello_world_a2a_langgraph_artifact_client_streaming.py +76 -0
  55. aip_agents/examples/hello_world_a2a_langgraph_artifact_server.py +92 -0
  56. aip_agents/examples/hello_world_a2a_langgraph_client.py +54 -0
  57. aip_agents/examples/hello_world_a2a_langgraph_client_agent.py +54 -0
  58. aip_agents/examples/hello_world_a2a_langgraph_client_agent_lm_invoker.py +32 -0
  59. aip_agents/examples/hello_world_a2a_langgraph_client_streaming.py +50 -0
  60. aip_agents/examples/hello_world_a2a_langgraph_client_streaming_lm_invoker.py +44 -0
  61. aip_agents/examples/hello_world_a2a_langgraph_client_streaming_tool_streaming.py +92 -0
  62. aip_agents/examples/hello_world_a2a_langgraph_server.py +84 -0
  63. aip_agents/examples/hello_world_a2a_langgraph_server_lm_invoker.py +79 -0
  64. aip_agents/examples/hello_world_a2a_langgraph_server_tool_streaming.py +132 -0
  65. aip_agents/examples/hello_world_a2a_mcp_langgraph.py +196 -0
  66. aip_agents/examples/hello_world_a2a_three_level_agent_hierarchy_client.py +244 -0
  67. aip_agents/examples/hello_world_a2a_three_level_agent_hierarchy_server.py +251 -0
  68. aip_agents/examples/hello_world_a2a_with_metadata_langchain_client.py +57 -0
  69. aip_agents/examples/hello_world_a2a_with_metadata_langchain_server_lm_invoker.py +80 -0
  70. aip_agents/examples/hello_world_google_adk.py +41 -0
  71. aip_agents/examples/hello_world_google_adk_mcp_http.py +34 -0
  72. aip_agents/examples/hello_world_google_adk_mcp_http_stream.py +40 -0
  73. aip_agents/examples/hello_world_google_adk_mcp_sse.py +44 -0
  74. aip_agents/examples/hello_world_google_adk_mcp_sse_stream.py +48 -0
  75. aip_agents/examples/hello_world_google_adk_mcp_stdio.py +44 -0
  76. aip_agents/examples/hello_world_google_adk_mcp_stdio_stream.py +48 -0
  77. aip_agents/examples/hello_world_google_adk_stream.py +44 -0
  78. aip_agents/examples/hello_world_langchain.py +28 -0
  79. aip_agents/examples/hello_world_langchain_lm_invoker.py +15 -0
  80. aip_agents/examples/hello_world_langchain_mcp_http.py +34 -0
  81. aip_agents/examples/hello_world_langchain_mcp_http_interactive.py +130 -0
  82. aip_agents/examples/hello_world_langchain_mcp_http_stream.py +42 -0
  83. aip_agents/examples/hello_world_langchain_mcp_multi_server.py +155 -0
  84. aip_agents/examples/hello_world_langchain_mcp_sse.py +34 -0
  85. aip_agents/examples/hello_world_langchain_mcp_sse_stream.py +40 -0
  86. aip_agents/examples/hello_world_langchain_mcp_stdio.py +30 -0
  87. aip_agents/examples/hello_world_langchain_mcp_stdio_stream.py +41 -0
  88. aip_agents/examples/hello_world_langchain_stream.py +36 -0
  89. aip_agents/examples/hello_world_langchain_stream_lm_invoker.py +39 -0
  90. aip_agents/examples/hello_world_langflow_agent.py +163 -0
  91. aip_agents/examples/hello_world_langgraph.py +39 -0
  92. aip_agents/examples/hello_world_langgraph_bosa_twitter.py +41 -0
  93. aip_agents/examples/hello_world_langgraph_mcp_http.py +31 -0
  94. aip_agents/examples/hello_world_langgraph_mcp_http_stream.py +34 -0
  95. aip_agents/examples/hello_world_langgraph_mcp_sse.py +35 -0
  96. aip_agents/examples/hello_world_langgraph_mcp_sse_stream.py +50 -0
  97. aip_agents/examples/hello_world_langgraph_mcp_stdio.py +35 -0
  98. aip_agents/examples/hello_world_langgraph_mcp_stdio_stream.py +50 -0
  99. aip_agents/examples/hello_world_langgraph_stream.py +43 -0
  100. aip_agents/examples/hello_world_langgraph_stream_lm_invoker.py +37 -0
  101. aip_agents/examples/hello_world_model_switch_cli.py +210 -0
  102. aip_agents/examples/hello_world_multi_agent_adk.py +75 -0
  103. aip_agents/examples/hello_world_multi_agent_langchain.py +54 -0
  104. aip_agents/examples/hello_world_multi_agent_langgraph.py +66 -0
  105. aip_agents/examples/hello_world_multi_agent_langgraph_lm_invoker.py +69 -0
  106. aip_agents/examples/hello_world_pii_logger.py +21 -0
  107. aip_agents/examples/hello_world_sentry.py +133 -0
  108. aip_agents/examples/hello_world_step_limits.py +273 -0
  109. aip_agents/examples/hello_world_stock_a2a_server.py +103 -0
  110. aip_agents/examples/hello_world_tool_output_client.py +46 -0
  111. aip_agents/examples/hello_world_tool_output_server.py +114 -0
  112. aip_agents/examples/hitl_demo.py +724 -0
  113. aip_agents/examples/mcp_configs/configs.py +63 -0
  114. aip_agents/examples/mcp_servers/common.py +76 -0
  115. aip_agents/examples/mcp_servers/mcp_name.py +29 -0
  116. aip_agents/examples/mcp_servers/mcp_server_http.py +19 -0
  117. aip_agents/examples/mcp_servers/mcp_server_sse.py +19 -0
  118. aip_agents/examples/mcp_servers/mcp_server_stdio.py +19 -0
  119. aip_agents/examples/mcp_servers/mcp_time.py +10 -0
  120. aip_agents/examples/pii_demo_langgraph_client.py +69 -0
  121. aip_agents/examples/pii_demo_langgraph_server.py +126 -0
  122. aip_agents/examples/pii_demo_multi_agent_client.py +80 -0
  123. aip_agents/examples/pii_demo_multi_agent_server.py +247 -0
  124. aip_agents/examples/todolist_planning_a2a_langchain_client.py +70 -0
  125. aip_agents/examples/todolist_planning_a2a_langgraph_server.py +88 -0
  126. aip_agents/examples/tools/__init__.py +27 -0
  127. aip_agents/examples/tools/{adk_arithmetic_tools.pyi → adk_arithmetic_tools.py} +12 -0
  128. aip_agents/examples/tools/adk_weather_tool.py +60 -0
  129. aip_agents/examples/tools/data_generator_tool.py +103 -0
  130. aip_agents/examples/tools/data_visualization_tool.py +312 -0
  131. aip_agents/examples/tools/image_artifact_tool.py +136 -0
  132. aip_agents/examples/tools/langchain_arithmetic_tools.py +26 -0
  133. aip_agents/examples/tools/langchain_currency_exchange_tool.py +88 -0
  134. aip_agents/examples/tools/langchain_graph_artifact_tool.py +172 -0
  135. aip_agents/examples/tools/langchain_weather_tool.py +48 -0
  136. aip_agents/examples/tools/langgraph_streaming_tool.py +130 -0
  137. aip_agents/examples/tools/mock_retrieval_tool.py +56 -0
  138. aip_agents/examples/tools/pii_demo_tools.py +189 -0
  139. aip_agents/examples/tools/random_chart_tool.py +142 -0
  140. aip_agents/examples/tools/serper_tool.py +202 -0
  141. aip_agents/examples/tools/stock_tools.py +82 -0
  142. aip_agents/examples/tools/table_generator_tool.py +167 -0
  143. aip_agents/examples/tools/time_tool.py +82 -0
  144. aip_agents/examples/tools/weather_forecast_tool.py +38 -0
  145. aip_agents/executor/agent_executor.py +473 -0
  146. aip_agents/executor/base.py +48 -0
  147. aip_agents/mcp/__init__.py +1 -0
  148. aip_agents/mcp/client/__init__.py +14 -0
  149. aip_agents/mcp/client/base_mcp_client.py +369 -0
  150. aip_agents/mcp/client/connection_manager.py +193 -0
  151. aip_agents/mcp/client/google_adk/__init__.py +11 -0
  152. aip_agents/mcp/client/google_adk/client.py +381 -0
  153. aip_agents/mcp/client/langchain/__init__.py +11 -0
  154. aip_agents/mcp/client/langchain/client.py +265 -0
  155. aip_agents/mcp/client/persistent_session.py +359 -0
  156. aip_agents/mcp/client/session_pool.py +351 -0
  157. aip_agents/mcp/client/transports.py +215 -0
  158. aip_agents/mcp/utils/__init__.py +7 -0
  159. aip_agents/mcp/utils/config_validator.py +139 -0
  160. aip_agents/memory/__init__.py +14 -0
  161. aip_agents/memory/adapters/__init__.py +10 -0
  162. aip_agents/memory/adapters/base_adapter.py +717 -0
  163. aip_agents/memory/adapters/mem0.py +84 -0
  164. aip_agents/memory/{base.pyi → base.py} +40 -5
  165. aip_agents/memory/constants.py +49 -0
  166. aip_agents/memory/factory.py +86 -0
  167. aip_agents/memory/guidance.py +20 -0
  168. aip_agents/memory/simple_memory.py +47 -0
  169. aip_agents/middleware/__init__.py +17 -0
  170. aip_agents/middleware/base.py +88 -0
  171. aip_agents/middleware/manager.py +128 -0
  172. aip_agents/middleware/todolist.py +274 -0
  173. aip_agents/schema/__init__.py +69 -0
  174. aip_agents/schema/a2a.py +56 -0
  175. aip_agents/schema/agent.py +111 -0
  176. aip_agents/schema/hitl.py +157 -0
  177. aip_agents/schema/langgraph.py +37 -0
  178. aip_agents/schema/model_id.py +97 -0
  179. aip_agents/schema/step_limit.py +108 -0
  180. aip_agents/schema/storage.py +40 -0
  181. aip_agents/sentry/__init__.py +11 -0
  182. aip_agents/sentry/sentry.py +151 -0
  183. aip_agents/storage/__init__.py +41 -0
  184. aip_agents/storage/{base.pyi → base.py} +30 -4
  185. aip_agents/storage/clients/__init__.py +12 -0
  186. aip_agents/storage/clients/minio_client.py +318 -0
  187. aip_agents/storage/config.py +62 -0
  188. aip_agents/storage/providers/__init__.py +15 -0
  189. aip_agents/storage/providers/{base.pyi → base.py} +23 -6
  190. aip_agents/storage/providers/{memory.pyi → memory.py} +38 -3
  191. aip_agents/storage/providers/object_storage.py +214 -0
  192. aip_agents/tools/__init__.py +6 -0
  193. aip_agents/tools/bosa_tools.py +105 -0
  194. aip_agents/tools/browser_use/__init__.py +82 -0
  195. aip_agents/tools/browser_use/action_parser.py +103 -0
  196. aip_agents/tools/browser_use/browser_use_tool.py +1112 -0
  197. aip_agents/tools/browser_use/llm_config.py +120 -0
  198. aip_agents/tools/browser_use/minio_storage.py +198 -0
  199. aip_agents/tools/browser_use/schemas.py +119 -0
  200. aip_agents/tools/browser_use/session.py +76 -0
  201. aip_agents/tools/browser_use/session_errors.py +132 -0
  202. aip_agents/tools/browser_use/steel_session_recording.py +317 -0
  203. aip_agents/tools/browser_use/streaming.py +813 -0
  204. aip_agents/tools/browser_use/structured_data_parser.py +257 -0
  205. aip_agents/tools/browser_use/structured_data_recovery.py +204 -0
  206. aip_agents/tools/browser_use/types.py +78 -0
  207. aip_agents/tools/code_sandbox/__init__.py +26 -0
  208. aip_agents/tools/code_sandbox/constant.py +13 -0
  209. aip_agents/tools/code_sandbox/e2b_cloud_sandbox_extended.py +257 -0
  210. aip_agents/tools/code_sandbox/e2b_sandbox_tool.py +411 -0
  211. aip_agents/tools/constants.py +165 -0
  212. aip_agents/tools/document_loader/__init__.py +37 -0
  213. aip_agents/tools/document_loader/base_reader.py +262 -0
  214. aip_agents/tools/document_loader/docx_reader_tool.py +53 -0
  215. aip_agents/tools/document_loader/excel_reader_tool.py +160 -0
  216. aip_agents/tools/document_loader/pdf_reader_tool.py +67 -0
  217. aip_agents/tools/document_loader/pdf_splitter.py +169 -0
  218. aip_agents/tools/gl_connector/__init__.py +5 -0
  219. aip_agents/tools/gl_connector/tool.py +351 -0
  220. aip_agents/tools/memory_search/__init__.py +22 -0
  221. aip_agents/tools/memory_search/base.py +200 -0
  222. aip_agents/tools/memory_search/mem0.py +258 -0
  223. aip_agents/tools/memory_search/schema.py +48 -0
  224. aip_agents/tools/memory_search_tool.py +26 -0
  225. aip_agents/tools/tool_config_injector.py +300 -0
  226. aip_agents/tools/web_search/__init__.py +15 -0
  227. aip_agents/tools/web_search/serper_tool.py +187 -0
  228. aip_agents/types/__init__.py +70 -0
  229. aip_agents/types/a2a_events.py +13 -0
  230. aip_agents/utils/__init__.py +79 -0
  231. aip_agents/utils/a2a_connector.py +1757 -0
  232. aip_agents/utils/artifact_helpers.py +502 -0
  233. aip_agents/utils/constants.py +22 -0
  234. aip_agents/utils/datetime/__init__.py +34 -0
  235. aip_agents/utils/datetime/normalization.py +231 -0
  236. aip_agents/utils/datetime/timezone.py +206 -0
  237. aip_agents/utils/env_loader.py +27 -0
  238. aip_agents/utils/event_handler_registry.py +58 -0
  239. aip_agents/utils/file_prompt_utils.py +176 -0
  240. aip_agents/utils/final_response_builder.py +211 -0
  241. aip_agents/utils/formatter_llm_client.py +231 -0
  242. aip_agents/utils/langgraph/__init__.py +19 -0
  243. aip_agents/utils/langgraph/converter.py +128 -0
  244. aip_agents/utils/langgraph/tool_managers/__init__.py +15 -0
  245. aip_agents/utils/langgraph/tool_managers/a2a_tool_manager.py +99 -0
  246. aip_agents/utils/langgraph/tool_managers/{base_tool_manager.pyi → base_tool_manager.py} +25 -8
  247. aip_agents/utils/langgraph/tool_managers/delegation_tool_manager.py +1071 -0
  248. aip_agents/utils/langgraph/tool_output_management.py +967 -0
  249. aip_agents/utils/logger.py +195 -0
  250. aip_agents/utils/metadata/__init__.py +27 -0
  251. aip_agents/utils/metadata/activity_metadata_helper.py +407 -0
  252. aip_agents/utils/metadata/activity_narrative/__init__.py +35 -0
  253. aip_agents/utils/metadata/activity_narrative/builder.py +817 -0
  254. aip_agents/utils/metadata/activity_narrative/constants.py +51 -0
  255. aip_agents/utils/metadata/activity_narrative/context.py +49 -0
  256. aip_agents/utils/metadata/activity_narrative/formatters.py +230 -0
  257. aip_agents/utils/metadata/activity_narrative/utils.py +35 -0
  258. aip_agents/utils/metadata/schemas/__init__.py +16 -0
  259. aip_agents/utils/metadata/schemas/activity_schema.py +29 -0
  260. aip_agents/utils/metadata/schemas/thinking_schema.py +31 -0
  261. aip_agents/utils/metadata/thinking_metadata_helper.py +38 -0
  262. aip_agents/utils/metadata_helper.py +358 -0
  263. aip_agents/utils/name_preprocessor/__init__.py +17 -0
  264. aip_agents/utils/name_preprocessor/{base_name_preprocessor.pyi → base_name_preprocessor.py} +22 -2
  265. aip_agents/utils/name_preprocessor/google_name_preprocessor.py +100 -0
  266. aip_agents/utils/name_preprocessor/name_preprocessor.py +87 -0
  267. aip_agents/utils/name_preprocessor/{openai_name_preprocessor.pyi → openai_name_preprocessor.py} +19 -5
  268. aip_agents/utils/pii/__init__.py +25 -0
  269. aip_agents/utils/pii/pii_handler.py +397 -0
  270. aip_agents/utils/pii/pii_helper.py +207 -0
  271. aip_agents/utils/pii/uuid_deanonymizer_mapping.py +195 -0
  272. aip_agents/utils/reference_helper.py +273 -0
  273. aip_agents/utils/sse_chunk_transformer.py +831 -0
  274. aip_agents/utils/step_limit_manager.py +265 -0
  275. aip_agents/utils/token_usage_helper.py +156 -0
  276. aip_agents_binary-0.5.12.dist-info/METADATA +689 -0
  277. aip_agents_binary-0.5.12.dist-info/RECORD +279 -0
  278. {aip_agents_binary-0.0.0b2.dist-info → aip_agents_binary-0.5.12.dist-info}/WHEEL +2 -1
  279. aip_agents_binary-0.5.12.dist-info/top_level.txt +1 -0
  280. aip_agents/__init__.pyi +0 -0
  281. aip_agents/a2a/__init__.pyi +0 -3
  282. aip_agents/a2a/server/__init__.pyi +0 -4
  283. aip_agents/a2a/server/base_executor.pyi +0 -63
  284. aip_agents/a2a/server/google_adk_executor.pyi +0 -51
  285. aip_agents/a2a/server/langgraph_executor.pyi +0 -48
  286. aip_agents/a2a/types.pyi +0 -125
  287. aip_agents/agent/__init__.pyi +0 -7
  288. aip_agents/agent/base_agent.pyi +0 -205
  289. aip_agents/agent/base_langgraph_agent.pyi +0 -164
  290. aip_agents/agent/google_adk_agent.pyi +0 -128
  291. aip_agents/agent/langgraph_react_agent.pyi +0 -131
  292. aip_agents/agent/types.pyi +0 -106
  293. aip_agents/constants.pyi +0 -6
  294. aip_agents/examples/__init__.pyi +0 -0
  295. aip_agents/examples/hello_world_a2a_google_adk_client.pyi +0 -9
  296. aip_agents/examples/hello_world_a2a_google_adk_client_agent.pyi +0 -9
  297. aip_agents/examples/hello_world_a2a_google_adk_client_streaming.pyi +0 -9
  298. aip_agents/examples/hello_world_a2a_google_adk_server.pyi +0 -10
  299. aip_agents/examples/hello_world_a2a_langchain_client.pyi +0 -5
  300. aip_agents/examples/hello_world_a2a_langchain_client_agent.pyi +0 -5
  301. aip_agents/examples/hello_world_a2a_langchain_client_lm_invoker.pyi +0 -5
  302. aip_agents/examples/hello_world_a2a_langchain_client_streaming.pyi +0 -5
  303. aip_agents/examples/hello_world_a2a_langchain_reference_client_streaming.pyi +0 -5
  304. aip_agents/examples/hello_world_a2a_langchain_reference_server.pyi +0 -10
  305. aip_agents/examples/hello_world_a2a_langchain_server.pyi +0 -10
  306. aip_agents/examples/hello_world_a2a_langchain_server_lm_invoker.pyi +0 -10
  307. aip_agents/examples/hello_world_a2a_langgraph_artifact_client.pyi +0 -5
  308. aip_agents/examples/hello_world_a2a_langgraph_artifact_client_streaming.pyi +0 -5
  309. aip_agents/examples/hello_world_a2a_langgraph_artifact_server.pyi +0 -11
  310. aip_agents/examples/hello_world_a2a_langgraph_client.pyi +0 -9
  311. aip_agents/examples/hello_world_a2a_langgraph_client_agent.pyi +0 -9
  312. aip_agents/examples/hello_world_a2a_langgraph_client_agent_lm_invoker.pyi +0 -2
  313. aip_agents/examples/hello_world_a2a_langgraph_client_streaming.pyi +0 -9
  314. aip_agents/examples/hello_world_a2a_langgraph_client_streaming_lm_invoker.pyi +0 -5
  315. aip_agents/examples/hello_world_a2a_langgraph_client_streaming_tool_streaming.pyi +0 -5
  316. aip_agents/examples/hello_world_a2a_langgraph_server.pyi +0 -9
  317. aip_agents/examples/hello_world_a2a_langgraph_server_lm_invoker.pyi +0 -10
  318. aip_agents/examples/hello_world_a2a_langgraph_server_tool_streaming.pyi +0 -10
  319. aip_agents/examples/hello_world_a2a_mcp_langgraph.pyi +0 -48
  320. aip_agents/examples/hello_world_a2a_multi_agent_coordinator_client.pyi +0 -15
  321. aip_agents/examples/hello_world_a2a_multi_agent_coordinator_client_streaming.pyi +0 -5
  322. aip_agents/examples/hello_world_a2a_multi_agent_coordinator_server.pyi +0 -11
  323. aip_agents/examples/hello_world_a2a_three_level_agent_hierarchy_client.pyi +0 -23
  324. aip_agents/examples/hello_world_a2a_three_level_agent_hierarchy_server.pyi +0 -17
  325. aip_agents/examples/hello_world_a2a_with_metadata_langchain_client.pyi +0 -5
  326. aip_agents/examples/hello_world_a2a_with_metadata_langchain_server_lm_invoker.pyi +0 -10
  327. aip_agents/examples/hello_world_google_adk.pyi +0 -5
  328. aip_agents/examples/hello_world_google_adk_mcp_http.pyi +0 -5
  329. aip_agents/examples/hello_world_google_adk_mcp_http_stream.pyi +0 -5
  330. aip_agents/examples/hello_world_google_adk_mcp_sse.pyi +0 -5
  331. aip_agents/examples/hello_world_google_adk_mcp_sse_stream.pyi +0 -5
  332. aip_agents/examples/hello_world_google_adk_mcp_stdio.pyi +0 -5
  333. aip_agents/examples/hello_world_google_adk_mcp_stdio_stream.pyi +0 -5
  334. aip_agents/examples/hello_world_google_adk_stream.pyi +0 -5
  335. aip_agents/examples/hello_world_langchain.pyi +0 -5
  336. aip_agents/examples/hello_world_langchain_lm_invoker.pyi +0 -2
  337. aip_agents/examples/hello_world_langchain_mcp_http.pyi +0 -5
  338. aip_agents/examples/hello_world_langchain_mcp_http_stream.pyi +0 -5
  339. aip_agents/examples/hello_world_langchain_mcp_sse.pyi +0 -5
  340. aip_agents/examples/hello_world_langchain_mcp_sse_stream.pyi +0 -5
  341. aip_agents/examples/hello_world_langchain_mcp_stdio.pyi +0 -5
  342. aip_agents/examples/hello_world_langchain_mcp_stdio_stream.pyi +0 -5
  343. aip_agents/examples/hello_world_langchain_stream.pyi +0 -5
  344. aip_agents/examples/hello_world_langchain_stream_lm_invoker.pyi +0 -5
  345. aip_agents/examples/hello_world_langgraph.pyi +0 -5
  346. aip_agents/examples/hello_world_langgraph_bosa.pyi +0 -5
  347. aip_agents/examples/hello_world_langgraph_bosa_twitter.pyi +0 -5
  348. aip_agents/examples/hello_world_langgraph_mcp_http.pyi +0 -5
  349. aip_agents/examples/hello_world_langgraph_mcp_http_stream.pyi +0 -5
  350. aip_agents/examples/hello_world_langgraph_mcp_sse.pyi +0 -5
  351. aip_agents/examples/hello_world_langgraph_mcp_sse_stream.pyi +0 -5
  352. aip_agents/examples/hello_world_langgraph_mcp_stdio.pyi +0 -5
  353. aip_agents/examples/hello_world_langgraph_mcp_stdio_stream.pyi +0 -5
  354. aip_agents/examples/hello_world_langgraph_stream.pyi +0 -5
  355. aip_agents/examples/hello_world_langgraph_stream_lm_invoker.pyi +0 -5
  356. aip_agents/examples/hello_world_model_switch_cli.pyi +0 -15
  357. aip_agents/examples/hello_world_multi_agent_adk.pyi +0 -6
  358. aip_agents/examples/hello_world_multi_agent_langchain.pyi +0 -5
  359. aip_agents/examples/hello_world_multi_agent_langgraph.pyi +0 -5
  360. aip_agents/examples/hello_world_multi_agent_langgraph_lm_invoker.pyi +0 -5
  361. aip_agents/examples/hello_world_pii_logger.pyi +0 -5
  362. aip_agents/examples/hello_world_sentry.pyi +0 -21
  363. aip_agents/examples/hello_world_stock_a2a_server.pyi +0 -12
  364. aip_agents/examples/hello_world_tool_output_client.pyi +0 -5
  365. aip_agents/examples/hello_world_tool_output_server.pyi +0 -14
  366. aip_agents/examples/tools/__init__.pyi +0 -7
  367. aip_agents/examples/tools/adk_weather_tool.pyi +0 -18
  368. aip_agents/examples/tools/data_generator_tool.pyi +0 -15
  369. aip_agents/examples/tools/data_visualization_tool.pyi +0 -17
  370. aip_agents/examples/tools/image_artifact_tool.pyi +0 -24
  371. aip_agents/examples/tools/langchain_arithmetic_tools.pyi +0 -10
  372. aip_agents/examples/tools/langchain_currency_exchange_tool.pyi +0 -21
  373. aip_agents/examples/tools/langchain_graph_artifact_tool.pyi +0 -23
  374. aip_agents/examples/tools/langchain_weather_tool.pyi +0 -19
  375. aip_agents/examples/tools/langgraph_streaming_tool.pyi +0 -43
  376. aip_agents/examples/tools/pr_details_bosa_tool.pyi +0 -26
  377. aip_agents/examples/tools/serper_tool.pyi +0 -16
  378. aip_agents/examples/tools/stock_tools.pyi +0 -21
  379. aip_agents/examples/tools/table_generator_tool.pyi +0 -22
  380. aip_agents/examples/tools/time_tool.pyi +0 -15
  381. aip_agents/examples/tools/weather_forecast_tool.pyi +0 -14
  382. aip_agents/mcp/__init__.pyi +0 -0
  383. aip_agents/mcp/client/__init__.pyi +0 -4
  384. aip_agents/mcp/client/google_adk/__init__.pyi +0 -3
  385. aip_agents/mcp/client/google_adk/client.pyi +0 -38
  386. aip_agents/mcp/client/langchain/__init__.pyi +0 -3
  387. aip_agents/mcp/client/langchain/client.pyi +0 -3
  388. aip_agents/memory/__init__.pyi +0 -0
  389. aip_agents/memory/simple_memory.pyi +0 -22
  390. aip_agents/sentry/__init__.pyi +0 -3
  391. aip_agents/sentry/sentry.pyi +0 -48
  392. aip_agents/storage/__init__.pyi +0 -8
  393. aip_agents/storage/clients/__init__.pyi +0 -3
  394. aip_agents/storage/clients/minio_client.pyi +0 -137
  395. aip_agents/storage/config.pyi +0 -66
  396. aip_agents/storage/providers/__init__.pyi +0 -5
  397. aip_agents/storage/providers/object_storage.pyi +0 -98
  398. aip_agents/tools/__init__.pyi +0 -3
  399. aip_agents/tools/base.pyi +0 -44
  400. aip_agents/tools/base_bosa_tools.pyi +0 -12
  401. aip_agents/tools/bosa_connector.pyi +0 -30
  402. aip_agents/tools/bosa_tools.pyi +0 -37
  403. aip_agents/tools/bosa_tools_interface.pyi +0 -26
  404. aip_agents/tools/constants.pyi +0 -130
  405. aip_agents/tools/nested_agent_tool.pyi +0 -45
  406. aip_agents/tools/tool_config_injector.pyi +0 -26
  407. aip_agents/types/__init__.pyi +0 -3
  408. aip_agents/types/a2a_events.pyi +0 -74
  409. aip_agents/utils/__init__.pyi +0 -5
  410. aip_agents/utils/a2a_connector.pyi +0 -135
  411. aip_agents/utils/artifact_helpers.pyi +0 -179
  412. aip_agents/utils/langgraph/__init__.pyi +0 -3
  413. aip_agents/utils/langgraph/converter.pyi +0 -49
  414. aip_agents/utils/langgraph/tool_managers/__init__.pyi +0 -5
  415. aip_agents/utils/langgraph/tool_managers/a2a_tool_manager.pyi +0 -35
  416. aip_agents/utils/langgraph/tool_managers/delegation_tool_manager.pyi +0 -50
  417. aip_agents/utils/langgraph/tool_output_management.pyi +0 -310
  418. aip_agents/utils/logger_manager.pyi +0 -151
  419. aip_agents/utils/metadata_helper.pyi +0 -110
  420. aip_agents/utils/name_preprocessor/__init__.pyi +0 -6
  421. aip_agents/utils/name_preprocessor/google_name_preprocessor.pyi +0 -38
  422. aip_agents/utils/name_preprocessor/name_preprocessor.pyi +0 -41
  423. aip_agents/utils/reference_helper.pyi +0 -49
  424. aip_agents/utils/token_usage_helper.pyi +0 -60
  425. aip_agents_binary-0.0.0b2.dist-info/METADATA +0 -277
  426. aip_agents_binary-0.0.0b2.dist-info/RECORD +0 -157
@@ -0,0 +1,67 @@
1
+ """Tool to read and extract text from PDF files.
2
+
3
+ Authors:
4
+ Christian Trisno Sen Long Chen (christian.t.s.l.chen@gdplabs.id)
5
+
6
+ References:
7
+ https://github.com/GDP-ADMIN/gdplabs-exploration/blob/ai-agent-app/backend/aip_agents/tools/
8
+ reader/pdf_reader_tool.py
9
+ """
10
+
11
+ from gllm_docproc.loader.pdf import PDFPlumberLoader, PyMuPDFLoader
12
+
13
+ from aip_agents.tools.document_loader.base_reader import BaseDocumentReaderTool
14
+ from aip_agents.tools.document_loader.pdf_splitter import PDFSplitter
15
+ from aip_agents.utils.logger import get_logger
16
+
17
+ logger = get_logger(__name__)
18
+
19
+
20
+ class PDFReaderTool(BaseDocumentReaderTool):
21
+ """Tool to read and extract text from PDF files."""
22
+
23
+ name: str = "pdf_reader_tool"
24
+ description: str = "Read a PDF file and extract its text content. Input should be the path to the PDF file."
25
+
26
+ def _setup_loader(self):
27
+ self.loader.add_loader(PyMuPDFLoader())
28
+ self.loader.add_loader(PDFPlumberLoader())
29
+
30
+ def _split_file(self, file_path: str, batch_size: int) -> list[str]:
31
+ """Split PDF file into temporary files for batch processing.
32
+
33
+ This method uses PDFSplitter.split_by_pages to split the PDF into
34
+ temporary files containing the specified number of pages per batch.
35
+
36
+ Args:
37
+ file_path: Path to the PDF file to be split
38
+ batch_size: Number of pages to include in each split file (1-10)
39
+
40
+ Returns:
41
+ List of temporary file paths containing the split content
42
+
43
+ Raises:
44
+ FileNotFoundError: If the input PDF file doesn't exist
45
+ ValueError: If batch_size is invalid or PDF processing fails
46
+ Exception: For other unexpected errors during PDF splitting
47
+ """
48
+ logger.info(f"Splitting PDF file '{file_path}' with batch_size={batch_size}")
49
+
50
+ try:
51
+ # Use PDFSplitter utility to split the PDF by pages
52
+ temp_files = PDFSplitter.split_by_pages(file_path, batch_size)
53
+
54
+ logger.info(f"Successfully split PDF into {len(temp_files)} batch files")
55
+ logger.debug(f"Created temporary files: {temp_files}")
56
+
57
+ return temp_files
58
+
59
+ except FileNotFoundError:
60
+ logger.error(f"PDF file not found: {file_path}")
61
+ raise
62
+ except ValueError as e:
63
+ logger.error(f"Invalid parameters or corrupted PDF: {str(e)}")
64
+ raise
65
+ except Exception as e:
66
+ logger.error(f"Unexpected error splitting PDF '{file_path}': {str(e)}")
67
+ raise Exception(f"Failed to split PDF file: {str(e)}") from e
@@ -0,0 +1,169 @@
1
+ """PDF splitting utility for batching optimization.
2
+
3
+ Authors
4
+ Christian Trisno Sen Long Chen (christian.t.s.l.chen@gdplabs.id)
5
+ """
6
+
7
+ import os
8
+ import tempfile
9
+
10
+ from PyPDF2 import PdfReader, PdfWriter
11
+
12
+
13
+ class PDFSplitter:
14
+ """Utility class for splitting PDF files into page-based temporary files."""
15
+
16
+ @staticmethod
17
+ def split_by_pages(file_path: str, batch_size: int) -> list[str]:
18
+ """Split PDF into temporary files containing batch_size pages each.
19
+
20
+ Args:
21
+ file_path: Path to the PDF file to split
22
+ batch_size: Number of pages to include in each batch (1-10)
23
+
24
+ Returns:
25
+ List of temporary file paths containing the split PDF batches
26
+
27
+ Raises:
28
+ FileNotFoundError: If the input PDF file doesn't exist
29
+ ValueError: If batch_size is invalid or PDF is corrupted
30
+ Exception: For other PDF processing errors
31
+ """
32
+ PDFSplitter._validate_inputs(file_path, batch_size)
33
+
34
+ try:
35
+ reader = PdfReader(file_path)
36
+ PDFSplitter._validate_pdf_content(reader, file_path)
37
+
38
+ temp_files = []
39
+
40
+ # Split PDF into batches
41
+ for i in range(0, len(reader.pages), batch_size):
42
+ batch_number = i // batch_size + 1
43
+ temp_path = PDFSplitter._create_batch_file(reader, i, batch_size, batch_number, temp_files)
44
+ temp_files.append(temp_path)
45
+
46
+ return temp_files
47
+
48
+ except Exception as e:
49
+ # Handle corrupted or invalid PDF files
50
+ if "temp_files" in locals():
51
+ PDFSplitter._cleanup_temp_files(temp_files)
52
+
53
+ if isinstance(e, FileNotFoundError | ValueError):
54
+ raise
55
+ else:
56
+ raise ValueError(f"Error processing PDF file {file_path}: {str(e)}") from e
57
+
58
+ @staticmethod
59
+ def _validate_inputs(file_path: str, batch_size: int) -> None:
60
+ """Validate input parameters.
61
+
62
+ Args:
63
+ file_path: Path to the PDF file to validate
64
+ batch_size: Batch size to validate
65
+
66
+ Raises:
67
+ FileNotFoundError: If the input PDF file doesn't exist
68
+ ValueError: If batch_size is invalid
69
+ """
70
+ if not os.path.exists(file_path):
71
+ raise FileNotFoundError(f"PDF file not found: {file_path}")
72
+
73
+ @staticmethod
74
+ def _validate_pdf_content(reader: PdfReader, file_path: str) -> None:
75
+ """Validate PDF content has pages.
76
+
77
+ Args:
78
+ reader: PdfReader instance to validate
79
+ file_path: Path to the PDF file for error messages
80
+
81
+ Raises:
82
+ ValueError: If PDF has no pages
83
+ """
84
+ if len(reader.pages) == 0:
85
+ raise ValueError(f"PDF file has no pages: {file_path}")
86
+
87
+ @staticmethod
88
+ def _create_batch_file(
89
+ reader: PdfReader,
90
+ start_page: int,
91
+ batch_size: int,
92
+ batch_number: int,
93
+ temp_files: list[str],
94
+ ) -> str:
95
+ """Create a temporary file containing a batch of PDF pages.
96
+
97
+ Args:
98
+ reader: PdfReader instance containing the source pages
99
+ start_page: Starting page index for this batch
100
+ batch_size: Number of pages to include in the batch
101
+ batch_number: Batch number for file naming
102
+ temp_files: List of existing temp files for cleanup on error
103
+
104
+ Returns:
105
+ Path to the created temporary file
106
+
107
+ Raises:
108
+ ValueError: If page processing or file writing fails
109
+ """
110
+ writer = PdfWriter()
111
+
112
+ # Add pages to this batch
113
+ batch_end = min(start_page + batch_size, len(reader.pages))
114
+ for j in range(start_page, batch_end):
115
+ try:
116
+ writer.add_page(reader.pages[j])
117
+ except Exception as e:
118
+ # Clean up any created temp files before re-raising
119
+ PDFSplitter._cleanup_temp_files(temp_files)
120
+ raise ValueError(f"Error processing page {j + 1}: {str(e)}") from e
121
+
122
+ # Create and write temporary file
123
+ return PDFSplitter._write_batch_to_temp_file(writer, batch_number, temp_files)
124
+
125
+ @staticmethod
126
+ def _write_batch_to_temp_file(writer: PdfWriter, batch_number: int, temp_files: list[str]) -> str:
127
+ """Write a PDF batch to a temporary file.
128
+
129
+ Args:
130
+ writer: PdfWriter instance containing the batch pages
131
+ batch_number: Batch number for file naming
132
+ temp_files: List of existing temp files for cleanup on error
133
+
134
+ Returns:
135
+ Path to the created temporary file
136
+
137
+ Raises:
138
+ ValueError: If file writing fails
139
+ """
140
+ # Create temporary file with proper naming
141
+ temp_fd, temp_path = tempfile.mkstemp(suffix=f"_batch_{batch_number}.pdf", prefix="pdf_split_")
142
+
143
+ try:
144
+ with os.fdopen(temp_fd, "wb") as temp_file:
145
+ writer.write(temp_file)
146
+ return temp_path
147
+ except Exception as e:
148
+ # Close the file descriptor if write fails
149
+ try:
150
+ os.close(temp_fd)
151
+ except OSError:
152
+ pass
153
+ # Clean up any created temp files
154
+ PDFSplitter._cleanup_temp_files(temp_files)
155
+ raise ValueError(f"Error writing batch {batch_number}: {str(e)}") from e
156
+
157
+ @staticmethod
158
+ def _cleanup_temp_files(temp_files: list[str]) -> None:
159
+ """Clean up temporary files.
160
+
161
+ Args:
162
+ temp_files: List of temporary file paths to clean up
163
+ """
164
+ for temp_file in temp_files:
165
+ try:
166
+ if os.path.exists(temp_file):
167
+ os.unlink(temp_file)
168
+ except OSError:
169
+ pass
@@ -0,0 +1,5 @@
1
+ """GL Connector tool wrapper exports."""
2
+
3
+ from aip_agents.tools.gl_connector.tool import GLConnectorTool
4
+
5
+ __all__ = ["GLConnectorTool"]
@@ -0,0 +1,351 @@
1
+ """GL Connector tool wrapper for BOSA connector tools.
2
+
3
+ Authors:
4
+ Saul Sayers (saul.sayers@gdplabs.id)
5
+
6
+ Reference:
7
+ https://gl-docs.gitbook.io/bosa/gl-connector/gl-connector
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ import os
13
+ from collections.abc import Iterable
14
+ from typing import Any
15
+
16
+ from bosa_connectors import BosaConnector, BOSAConnectorToolGenerator
17
+ from langchain_core.runnables import RunnableConfig
18
+ from langchain_core.tools import BaseTool
19
+ from pydantic import ConfigDict, PrivateAttr
20
+
21
+ from aip_agents.tools.constants import ToolType
22
+
23
+ _REQUIRED_ENV_VARS: tuple[str, ...] = (
24
+ "BOSA_BASE_URL",
25
+ "BOSA_API_KEY",
26
+ "BOSA_USERNAME",
27
+ "BOSA_PASSWORD",
28
+ )
29
+ _TOP_LEVEL_KEYS: tuple[str, ...] = (
30
+ "token",
31
+ "identifier",
32
+ "timeout",
33
+ "request",
34
+ )
35
+
36
+
37
+ class _InjectedTool(BaseTool):
38
+ """Wrap a BaseTool to inject token and optional identifier into inputs."""
39
+
40
+ _base_tool: BaseTool = PrivateAttr()
41
+ _token: str = PrivateAttr()
42
+ _identifier: str | None = PrivateAttr(default=None)
43
+
44
+ model_config = ConfigDict(arbitrary_types_allowed=True)
45
+
46
+ def __init__(self, base_tool: BaseTool, token: str, identifier: str | None) -> None:
47
+ """Initialize the injected tool wrapper.
48
+
49
+ Args:
50
+ base_tool: The base tool to wrap.
51
+ token: Authentication token to inject into tool inputs.
52
+ identifier: Optional identifier to inject into tool inputs.
53
+
54
+ Returns:
55
+ None
56
+ """
57
+ base_fields = {field: getattr(base_tool, field) for field in BaseTool.model_fields}
58
+ super().__init__(**base_fields)
59
+ self._base_tool = base_tool
60
+ self._token = token
61
+ self._identifier = identifier
62
+
63
+ def _run(self, *args: Any, **kwargs: Any) -> Any:
64
+ """Execute the wrapped tool synchronously.
65
+
66
+ Args:
67
+ *args: Positional arguments to pass to the base tool.
68
+ **kwargs: Keyword arguments to pass to the base tool.
69
+
70
+ Returns:
71
+ The result of executing the base tool.
72
+ """
73
+ return self._base_tool._run(*args, **kwargs)
74
+
75
+ async def _arun(self, *args: Any, **kwargs: Any) -> Any:
76
+ """Execute the wrapped tool asynchronously.
77
+
78
+ Args:
79
+ *args: Positional arguments to pass to the base tool.
80
+ **kwargs: Keyword arguments to pass to the base tool.
81
+
82
+ Returns:
83
+ The result of executing the base tool.
84
+ """
85
+ return await self._base_tool._arun(*args, **kwargs)
86
+
87
+ def invoke(self, input: Any, config: RunnableConfig | None = None, **kwargs: Any) -> Any:
88
+ """Invoke the tool with token and optional identifier injected.
89
+
90
+ Args:
91
+ input: Tool input to process.
92
+ config: Optional runnable configuration.
93
+ **kwargs: Additional keyword arguments.
94
+
95
+ Returns:
96
+ The result of invoking the tool with injected parameters.
97
+ """
98
+ injected = _inject_params(input, self._token, self._identifier, self._base_tool)
99
+ return super().invoke(injected, config=config, **kwargs)
100
+
101
+ async def ainvoke(self, input: Any, config: RunnableConfig | None = None, **kwargs: Any) -> Any:
102
+ """Invoke the tool asynchronously with token and optional identifier injected.
103
+
104
+ Args:
105
+ input: Tool input to process.
106
+ config: Optional runnable configuration.
107
+ **kwargs: Additional keyword arguments.
108
+
109
+ Returns:
110
+ The result of invoking the tool with injected parameters.
111
+ """
112
+ injected = _inject_params(input, self._token, self._identifier, self._base_tool)
113
+ return await super().ainvoke(injected, config=config, **kwargs)
114
+
115
+ def run(self, tool_input: Any, **kwargs: Any) -> Any:
116
+ """Run the tool with token and optional identifier injected.
117
+
118
+ Args:
119
+ tool_input: Tool input to process.
120
+ **kwargs: Additional keyword arguments.
121
+
122
+ Returns:
123
+ The result of running the tool with injected parameters.
124
+ """
125
+ injected = _inject_params(tool_input, self._token, self._identifier, self._base_tool)
126
+ return super().run(injected, **kwargs)
127
+
128
+ async def arun(self, tool_input: Any, **kwargs: Any) -> Any:
129
+ """Run the tool asynchronously with token and optional identifier injected.
130
+
131
+ Args:
132
+ tool_input: Tool input to process.
133
+ **kwargs: Additional keyword arguments.
134
+
135
+ Returns:
136
+ The result of running the tool with injected parameters.
137
+ """
138
+ injected = _inject_params(tool_input, self._token, self._identifier, self._base_tool)
139
+ return await super().arun(injected, **kwargs)
140
+
141
+
142
+ def GLConnectorTool(
143
+ tool_name: str,
144
+ *,
145
+ api_key: str | None = None,
146
+ identifier: str | None = None,
147
+ ) -> BaseTool:
148
+ """Create a single GL Connector tool by exact tool name.
149
+
150
+ Args:
151
+ tool_name: Exact tool name (not module name).
152
+ api_key: Optional override for BOSA API key.
153
+ identifier: Optional override for BOSA identifier.
154
+
155
+ Returns:
156
+ A single LangChain BaseTool with token injection.
157
+ """
158
+ if not tool_name or not tool_name.strip():
159
+ raise ValueError("tool_name must be a non-empty string")
160
+
161
+ env_values = _load_env(api_key=api_key, identifier=identifier)
162
+ connector = BosaConnector(api_base_url=env_values["BOSA_BASE_URL"], api_key=env_values["BOSA_API_KEY"])
163
+
164
+ modules = _get_available_modules(connector)
165
+ module_name = _resolve_module(tool_name, modules)
166
+
167
+ generator = BOSAConnectorToolGenerator(
168
+ api_base_url=env_values["BOSA_BASE_URL"],
169
+ api_key=env_values["BOSA_API_KEY"],
170
+ app_name=module_name,
171
+ )
172
+ tools = generator.generate_tools(tool_type=ToolType.LANGCHAIN)
173
+
174
+ matching = [tool for tool in tools if getattr(tool, "name", None) == tool_name]
175
+ if not matching:
176
+ raise ValueError(f"Tool '{tool_name}' not found in module '{module_name}'")
177
+ if len(matching) > 1:
178
+ raise ValueError(f"Multiple tools named '{tool_name}' found in module '{module_name}'")
179
+
180
+ token = _create_token(connector, env_values["BOSA_USERNAME"], env_values["BOSA_PASSWORD"])
181
+ return _InjectedTool(matching[0], token, env_values.get("BOSA_IDENTIFIER"))
182
+
183
+
184
+ def _load_env(*, api_key: str | None, identifier: str | None) -> dict[str, str]:
185
+ """Load and validate environment configuration for connector access.
186
+
187
+ Args:
188
+ api_key: Optional override for BOSA API key.
189
+ identifier: Optional override for BOSA identifier.
190
+
191
+ Returns:
192
+ Dictionary containing environment configuration values.
193
+
194
+ Raises:
195
+ ValueError: If required environment variables are missing.
196
+ """
197
+ env = {key: os.getenv(key) for key in _REQUIRED_ENV_VARS}
198
+
199
+ resolved_api_key = api_key or env["BOSA_API_KEY"]
200
+ env["BOSA_API_KEY"] = resolved_api_key
201
+
202
+ optional_identifier = identifier or os.getenv("BOSA_IDENTIFIER")
203
+
204
+ if optional_identifier:
205
+ env["BOSA_IDENTIFIER"] = optional_identifier
206
+
207
+ missing = [key for key, value in env.items() if key in _REQUIRED_ENV_VARS and not value]
208
+ if missing:
209
+ raise ValueError(f"Missing required environment variables: {', '.join(missing)}")
210
+
211
+ return {key: value for key, value in env.items() if value is not None}
212
+
213
+
214
+ def _get_available_modules(connector: BosaConnector) -> list[str]:
215
+ """Return available connector modules or raise an actionable error.
216
+
217
+ Args:
218
+ connector: BOSA connector instance to query for modules.
219
+
220
+ Returns:
221
+ List of available module names.
222
+
223
+ Raises:
224
+ ValueError: If module fetching fails or no modules are available.
225
+ """
226
+ try:
227
+ modules = list(connector.get_available_modules())
228
+ except Exception as exc:
229
+ raise ValueError("Failed to fetch available connector modules") from exc
230
+
231
+ if not modules:
232
+ raise ValueError("No connector modules available")
233
+ return modules
234
+
235
+
236
+ def _resolve_module(tool_name: str, modules: Iterable[str]) -> str:
237
+ """Resolve the module name by longest prefix match.
238
+
239
+ Args:
240
+ tool_name: Name of the tool to resolve module for.
241
+ modules: Iterable of available module names.
242
+
243
+ Returns:
244
+ The resolved module name.
245
+
246
+ Raises:
247
+ ValueError: If no matching module is found or multiple ambiguous matches exist.
248
+ """
249
+ candidates = [module for module in modules if tool_name == module or tool_name.startswith(f"{module}_")]
250
+ if not candidates:
251
+ raise ValueError(f"Unable to resolve module for tool '{tool_name}'. Available modules: {', '.join(modules)}")
252
+
253
+ candidates.sort(key=len, reverse=True)
254
+ if len(candidates) > 1 and len(candidates[0]) == len(candidates[1]):
255
+ raise ValueError(f"Ambiguous module match for tool '{tool_name}'. Matches: {', '.join(candidates)}")
256
+ return candidates[0]
257
+
258
+
259
+ def _create_token(connector: BosaConnector, username: str, password: str) -> str:
260
+ """Authenticate the connector user and return a user token.
261
+
262
+ Args:
263
+ connector: BOSA connector instance for authentication.
264
+ username: BOSA username for authentication.
265
+ password: BOSA password for authentication.
266
+
267
+ Returns:
268
+ Authentication token string.
269
+
270
+ Raises:
271
+ ValueError: If authentication fails or token is missing.
272
+ """
273
+ try:
274
+ user = connector.authenticate_bosa_user(username, password)
275
+ except Exception as exc:
276
+ raise ValueError("Failed to authenticate BOSA user") from exc
277
+
278
+ token = getattr(user, "token", None)
279
+ if not token:
280
+ raise ValueError("BOSA user token missing after authentication")
281
+ return token
282
+
283
+
284
+ def _inject_params(tool_input: Any, token: str, identifier: str | None, base_tool: BaseTool) -> dict[str, Any]:
285
+ """Inject token and optional identifier into tool input.
286
+
287
+ Args:
288
+ tool_input: Original tool input dictionary.
289
+ token: Authentication token to inject.
290
+ identifier: Optional identifier to inject.
291
+ base_tool: Base tool instance for schema inspection.
292
+
293
+ Returns:
294
+ Dictionary with token and optional identifier injected.
295
+
296
+ Raises:
297
+ TypeError: If tool_input is not a dictionary.
298
+ """
299
+ if tool_input is None:
300
+ tool_input = {}
301
+
302
+ if not isinstance(tool_input, dict):
303
+ raise TypeError("Connector tool input must be a dict to inject token")
304
+
305
+ if "args" in tool_input and isinstance(tool_input.get("args"), dict):
306
+ injected_args = dict(tool_input["args"])
307
+ injected_args["token"] = token
308
+ if identifier:
309
+ injected_args["identifier"] = identifier
310
+ injected = dict(tool_input)
311
+ injected["args"] = injected_args
312
+ return injected
313
+
314
+ injected = dict(tool_input)
315
+ injected = _wrap_request_if_needed(injected, base_tool)
316
+ injected["token"] = token
317
+ if identifier:
318
+ injected["identifier"] = identifier
319
+ return injected
320
+
321
+
322
+ def _wrap_request_if_needed(tool_input: dict[str, Any], base_tool: BaseTool) -> dict[str, Any]:
323
+ """Wrap flat inputs into a 'request' payload when required by schema.
324
+
325
+ Args:
326
+ tool_input: Tool input dictionary to potentially wrap.
327
+ base_tool: Base tool instance for schema inspection.
328
+
329
+ Returns:
330
+ Dictionary with inputs wrapped in 'request' key if needed, otherwise unchanged.
331
+ """
332
+ args_schema = getattr(base_tool, "args_schema", None)
333
+ if not (isinstance(args_schema, dict) and "request" in args_schema.get("properties", {})):
334
+ return tool_input
335
+
336
+ request_payload = {}
337
+ existing_request = tool_input.get("request")
338
+ if isinstance(existing_request, dict):
339
+ request_payload.update(existing_request)
340
+
341
+ for key, value in tool_input.items():
342
+ if key in _TOP_LEVEL_KEYS:
343
+ continue
344
+ request_payload.setdefault(key, value)
345
+
346
+ wrapped = dict(tool_input)
347
+ wrapped["request"] = request_payload
348
+ for key in list(wrapped.keys()):
349
+ if key not in _TOP_LEVEL_KEYS:
350
+ wrapped.pop(key, None)
351
+ return wrapped
@@ -0,0 +1,22 @@
1
+ """Memory search tool package exposing shared schemas and implementations.
2
+
3
+ Authors:
4
+ Raymond Christopher (raymond.christopher@gdplabs.id)
5
+ """
6
+
7
+ from aip_agents.tools.memory_search.base import LongTermMemorySearchTool
8
+ from aip_agents.tools.memory_search.mem0 import (
9
+ MEMORY_SEARCH_TOOL_NAME,
10
+ Mem0SearchInput,
11
+ Mem0SearchTool,
12
+ )
13
+ from aip_agents.tools.memory_search.schema import LongTermMemorySearchInput, MemoryConfig
14
+
15
+ __all__ = [
16
+ "MemoryConfig",
17
+ "LongTermMemorySearchInput",
18
+ "LongTermMemorySearchTool",
19
+ "Mem0SearchInput",
20
+ "Mem0SearchTool",
21
+ "MEMORY_SEARCH_TOOL_NAME",
22
+ ]