aip-agents-binary 0.6.0__py3-none-any.whl → 0.6.2__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 (306) hide show
  1. aip_agents/agent/langgraph_react_agent.py +194 -2
  2. aip_agents/examples/hello_world_ptc.py +49 -0
  3. aip_agents/ptc/__init__.py +48 -0
  4. aip_agents/ptc/doc_gen.py +122 -0
  5. aip_agents/ptc/exceptions.py +39 -0
  6. aip_agents/ptc/executor.py +143 -0
  7. aip_agents/ptc/mcp/__init__.py +45 -0
  8. aip_agents/ptc/mcp/sandbox_bridge.py +668 -0
  9. aip_agents/ptc/mcp/templates/__init__.py +1 -0
  10. aip_agents/ptc/mcp/templates/mcp_client.py.template +239 -0
  11. aip_agents/ptc/naming.py +184 -0
  12. aip_agents/ptc/payload.py +26 -0
  13. aip_agents/ptc/prompt_builder.py +571 -0
  14. aip_agents/ptc/ptc_helper.py +16 -0
  15. aip_agents/ptc/sandbox_bridge.py +58 -0
  16. aip_agents/ptc/template_utils.py +33 -0
  17. aip_agents/ptc/templates/__init__.py +1 -0
  18. aip_agents/ptc/templates/ptc_helper.py.template +134 -0
  19. aip_agents/sandbox/__init__.py +43 -0
  20. aip_agents/sandbox/defaults.py +9 -0
  21. aip_agents/sandbox/e2b_runtime.py +267 -0
  22. aip_agents/sandbox/template_builder.py +131 -0
  23. aip_agents/sandbox/types.py +24 -0
  24. aip_agents/sandbox/validation.py +50 -0
  25. aip_agents/tools/__init__.py +2 -0
  26. aip_agents/tools/execute_ptc_code.py +308 -0
  27. {aip_agents_binary-0.6.0.dist-info → aip_agents_binary-0.6.2.dist-info}/METADATA +1 -1
  28. {aip_agents_binary-0.6.0.dist-info → aip_agents_binary-0.6.2.dist-info}/RECORD +30 -282
  29. aip_agents/__init__.pyi +0 -19
  30. aip_agents/a2a/__init__.pyi +0 -3
  31. aip_agents/a2a/server/__init__.pyi +0 -4
  32. aip_agents/a2a/server/base_executor.pyi +0 -73
  33. aip_agents/a2a/server/google_adk_executor.pyi +0 -51
  34. aip_agents/a2a/server/langflow_executor.pyi +0 -43
  35. aip_agents/a2a/server/langgraph_executor.pyi +0 -47
  36. aip_agents/a2a/types.pyi +0 -132
  37. aip_agents/agent/__init__.pyi +0 -9
  38. aip_agents/agent/base_agent.pyi +0 -221
  39. aip_agents/agent/base_langgraph_agent.pyi +0 -233
  40. aip_agents/agent/google_adk_agent.pyi +0 -141
  41. aip_agents/agent/google_adk_constants.pyi +0 -3
  42. aip_agents/agent/hitl/__init__.pyi +0 -6
  43. aip_agents/agent/hitl/config.pyi +0 -15
  44. aip_agents/agent/hitl/langgraph_hitl_mixin.pyi +0 -42
  45. aip_agents/agent/hitl/manager.pyi +0 -200
  46. aip_agents/agent/hitl/models.pyi +0 -3
  47. aip_agents/agent/hitl/prompt/__init__.pyi +0 -4
  48. aip_agents/agent/hitl/prompt/base.pyi +0 -24
  49. aip_agents/agent/hitl/prompt/deferred.pyi +0 -30
  50. aip_agents/agent/hitl/registry.pyi +0 -101
  51. aip_agents/agent/interface.pyi +0 -81
  52. aip_agents/agent/interfaces.pyi +0 -44
  53. aip_agents/agent/langflow_agent.pyi +0 -133
  54. aip_agents/agent/langgraph_memory_enhancer_agent.pyi +0 -49
  55. aip_agents/agent/langgraph_react_agent.pyi +0 -131
  56. aip_agents/agent/system_instruction_context.pyi +0 -13
  57. aip_agents/clients/__init__.pyi +0 -4
  58. aip_agents/clients/langflow/__init__.pyi +0 -4
  59. aip_agents/clients/langflow/client.pyi +0 -140
  60. aip_agents/clients/langflow/types.pyi +0 -7
  61. aip_agents/constants.pyi +0 -7
  62. aip_agents/examples/__init__.pyi +0 -0
  63. aip_agents/examples/compare_streaming_client.pyi +0 -48
  64. aip_agents/examples/compare_streaming_server.pyi +0 -18
  65. aip_agents/examples/demo_memory_recall.pyi +0 -58
  66. aip_agents/examples/hello_world_a2a_google_adk_client.pyi +0 -9
  67. aip_agents/examples/hello_world_a2a_google_adk_client_agent.pyi +0 -9
  68. aip_agents/examples/hello_world_a2a_google_adk_client_streaming.pyi +0 -9
  69. aip_agents/examples/hello_world_a2a_google_adk_server.pyi +0 -15
  70. aip_agents/examples/hello_world_a2a_langchain_client.pyi +0 -5
  71. aip_agents/examples/hello_world_a2a_langchain_client_agent.pyi +0 -5
  72. aip_agents/examples/hello_world_a2a_langchain_client_lm_invoker.pyi +0 -5
  73. aip_agents/examples/hello_world_a2a_langchain_client_streaming.pyi +0 -5
  74. aip_agents/examples/hello_world_a2a_langchain_reference_client_streaming.pyi +0 -5
  75. aip_agents/examples/hello_world_a2a_langchain_reference_server.pyi +0 -15
  76. aip_agents/examples/hello_world_a2a_langchain_server.pyi +0 -15
  77. aip_agents/examples/hello_world_a2a_langchain_server_lm_invoker.pyi +0 -15
  78. aip_agents/examples/hello_world_a2a_langflow_client.pyi +0 -9
  79. aip_agents/examples/hello_world_a2a_langflow_server.pyi +0 -14
  80. aip_agents/examples/hello_world_a2a_langgraph_artifact_client.pyi +0 -5
  81. aip_agents/examples/hello_world_a2a_langgraph_artifact_client_streaming.pyi +0 -5
  82. aip_agents/examples/hello_world_a2a_langgraph_artifact_server.pyi +0 -16
  83. aip_agents/examples/hello_world_a2a_langgraph_client.pyi +0 -9
  84. aip_agents/examples/hello_world_a2a_langgraph_client_agent.pyi +0 -9
  85. aip_agents/examples/hello_world_a2a_langgraph_client_agent_lm_invoker.pyi +0 -2
  86. aip_agents/examples/hello_world_a2a_langgraph_client_streaming.pyi +0 -9
  87. aip_agents/examples/hello_world_a2a_langgraph_client_streaming_lm_invoker.pyi +0 -5
  88. aip_agents/examples/hello_world_a2a_langgraph_client_streaming_tool_streaming.pyi +0 -5
  89. aip_agents/examples/hello_world_a2a_langgraph_server.pyi +0 -14
  90. aip_agents/examples/hello_world_a2a_langgraph_server_lm_invoker.pyi +0 -15
  91. aip_agents/examples/hello_world_a2a_langgraph_server_tool_streaming.pyi +0 -15
  92. aip_agents/examples/hello_world_a2a_mcp_langgraph.pyi +0 -48
  93. aip_agents/examples/hello_world_a2a_three_level_agent_hierarchy_client.pyi +0 -48
  94. aip_agents/examples/hello_world_a2a_three_level_agent_hierarchy_server.pyi +0 -45
  95. aip_agents/examples/hello_world_a2a_with_metadata_langchain_client.pyi +0 -5
  96. aip_agents/examples/hello_world_a2a_with_metadata_langchain_server_lm_invoker.pyi +0 -15
  97. aip_agents/examples/hello_world_google_adk.pyi +0 -5
  98. aip_agents/examples/hello_world_google_adk_mcp_http.pyi +0 -5
  99. aip_agents/examples/hello_world_google_adk_mcp_http_stream.pyi +0 -5
  100. aip_agents/examples/hello_world_google_adk_mcp_sse.pyi +0 -5
  101. aip_agents/examples/hello_world_google_adk_mcp_sse_stream.pyi +0 -5
  102. aip_agents/examples/hello_world_google_adk_mcp_stdio.pyi +0 -5
  103. aip_agents/examples/hello_world_google_adk_mcp_stdio_stream.pyi +0 -5
  104. aip_agents/examples/hello_world_google_adk_stream.pyi +0 -5
  105. aip_agents/examples/hello_world_langchain.pyi +0 -5
  106. aip_agents/examples/hello_world_langchain_lm_invoker.pyi +0 -2
  107. aip_agents/examples/hello_world_langchain_mcp_http.pyi +0 -5
  108. aip_agents/examples/hello_world_langchain_mcp_http_interactive.pyi +0 -16
  109. aip_agents/examples/hello_world_langchain_mcp_http_stream.pyi +0 -5
  110. aip_agents/examples/hello_world_langchain_mcp_multi_server.pyi +0 -18
  111. aip_agents/examples/hello_world_langchain_mcp_sse.pyi +0 -5
  112. aip_agents/examples/hello_world_langchain_mcp_sse_stream.pyi +0 -5
  113. aip_agents/examples/hello_world_langchain_mcp_stdio.pyi +0 -5
  114. aip_agents/examples/hello_world_langchain_mcp_stdio_stream.pyi +0 -5
  115. aip_agents/examples/hello_world_langchain_stream.pyi +0 -5
  116. aip_agents/examples/hello_world_langchain_stream_lm_invoker.pyi +0 -5
  117. aip_agents/examples/hello_world_langflow_agent.pyi +0 -35
  118. aip_agents/examples/hello_world_langgraph.pyi +0 -5
  119. aip_agents/examples/hello_world_langgraph_gl_connector_twitter.pyi +0 -5
  120. aip_agents/examples/hello_world_langgraph_mcp_http.pyi +0 -5
  121. aip_agents/examples/hello_world_langgraph_mcp_http_stream.pyi +0 -5
  122. aip_agents/examples/hello_world_langgraph_mcp_sse.pyi +0 -5
  123. aip_agents/examples/hello_world_langgraph_mcp_sse_stream.pyi +0 -5
  124. aip_agents/examples/hello_world_langgraph_mcp_stdio.pyi +0 -5
  125. aip_agents/examples/hello_world_langgraph_mcp_stdio_stream.pyi +0 -5
  126. aip_agents/examples/hello_world_langgraph_stream.pyi +0 -5
  127. aip_agents/examples/hello_world_langgraph_stream_lm_invoker.pyi +0 -5
  128. aip_agents/examples/hello_world_model_switch_cli.pyi +0 -30
  129. aip_agents/examples/hello_world_multi_agent_adk.pyi +0 -6
  130. aip_agents/examples/hello_world_multi_agent_langchain.pyi +0 -5
  131. aip_agents/examples/hello_world_multi_agent_langgraph.pyi +0 -5
  132. aip_agents/examples/hello_world_multi_agent_langgraph_lm_invoker.pyi +0 -5
  133. aip_agents/examples/hello_world_pii_logger.pyi +0 -5
  134. aip_agents/examples/hello_world_sentry.pyi +0 -21
  135. aip_agents/examples/hello_world_step_limits.pyi +0 -17
  136. aip_agents/examples/hello_world_stock_a2a_server.pyi +0 -17
  137. aip_agents/examples/hello_world_tool_output_client.pyi +0 -5
  138. aip_agents/examples/hello_world_tool_output_server.pyi +0 -19
  139. aip_agents/examples/hitl_demo.pyi +0 -67
  140. aip_agents/examples/pii_demo_langgraph_client.pyi +0 -5
  141. aip_agents/examples/pii_demo_langgraph_server.pyi +0 -20
  142. aip_agents/examples/pii_demo_multi_agent_client.pyi +0 -5
  143. aip_agents/examples/pii_demo_multi_agent_server.pyi +0 -40
  144. aip_agents/examples/todolist_planning_a2a_langchain_client.pyi +0 -5
  145. aip_agents/examples/todolist_planning_a2a_langgraph_server.pyi +0 -19
  146. aip_agents/examples/tools/__init__.pyi +0 -9
  147. aip_agents/examples/tools/adk_arithmetic_tools.pyi +0 -24
  148. aip_agents/examples/tools/adk_weather_tool.pyi +0 -18
  149. aip_agents/examples/tools/data_generator_tool.pyi +0 -15
  150. aip_agents/examples/tools/data_visualization_tool.pyi +0 -19
  151. aip_agents/examples/tools/image_artifact_tool.pyi +0 -26
  152. aip_agents/examples/tools/langchain_arithmetic_tools.pyi +0 -17
  153. aip_agents/examples/tools/langchain_currency_exchange_tool.pyi +0 -20
  154. aip_agents/examples/tools/langchain_graph_artifact_tool.pyi +0 -25
  155. aip_agents/examples/tools/langchain_weather_tool.pyi +0 -19
  156. aip_agents/examples/tools/langgraph_streaming_tool.pyi +0 -43
  157. aip_agents/examples/tools/mock_retrieval_tool.pyi +0 -13
  158. aip_agents/examples/tools/pii_demo_tools.pyi +0 -54
  159. aip_agents/examples/tools/random_chart_tool.pyi +0 -20
  160. aip_agents/examples/tools/serper_tool.pyi +0 -16
  161. aip_agents/examples/tools/stock_tools.pyi +0 -36
  162. aip_agents/examples/tools/table_generator_tool.pyi +0 -22
  163. aip_agents/examples/tools/time_tool.pyi +0 -15
  164. aip_agents/examples/tools/weather_forecast_tool.pyi +0 -14
  165. aip_agents/guardrails/__init__.pyi +0 -6
  166. aip_agents/guardrails/engines/__init__.pyi +0 -4
  167. aip_agents/guardrails/engines/base.pyi +0 -61
  168. aip_agents/guardrails/engines/nemo.pyi +0 -46
  169. aip_agents/guardrails/engines/phrase_matcher.pyi +0 -48
  170. aip_agents/guardrails/exceptions.pyi +0 -23
  171. aip_agents/guardrails/manager.pyi +0 -42
  172. aip_agents/guardrails/middleware.pyi +0 -87
  173. aip_agents/guardrails/schemas.pyi +0 -43
  174. aip_agents/guardrails/utils.pyi +0 -19
  175. aip_agents/mcp/__init__.pyi +0 -0
  176. aip_agents/mcp/client/__init__.pyi +0 -5
  177. aip_agents/mcp/client/base_mcp_client.pyi +0 -148
  178. aip_agents/mcp/client/connection_manager.pyi +0 -51
  179. aip_agents/mcp/client/google_adk/__init__.pyi +0 -3
  180. aip_agents/mcp/client/google_adk/client.pyi +0 -75
  181. aip_agents/mcp/client/langchain/__init__.pyi +0 -3
  182. aip_agents/mcp/client/langchain/client.pyi +0 -48
  183. aip_agents/mcp/client/persistent_session.pyi +0 -122
  184. aip_agents/mcp/client/session_pool.pyi +0 -101
  185. aip_agents/mcp/client/transports.pyi +0 -132
  186. aip_agents/mcp/utils/__init__.pyi +0 -0
  187. aip_agents/mcp/utils/config_validator.pyi +0 -82
  188. aip_agents/memory/__init__.pyi +0 -5
  189. aip_agents/memory/adapters/__init__.pyi +0 -4
  190. aip_agents/memory/adapters/base_adapter.pyi +0 -150
  191. aip_agents/memory/adapters/mem0.pyi +0 -22
  192. aip_agents/memory/base.pyi +0 -60
  193. aip_agents/memory/constants.pyi +0 -25
  194. aip_agents/memory/factory.pyi +0 -24
  195. aip_agents/memory/guidance.pyi +0 -3
  196. aip_agents/memory/simple_memory.pyi +0 -23
  197. aip_agents/middleware/__init__.pyi +0 -5
  198. aip_agents/middleware/base.pyi +0 -75
  199. aip_agents/middleware/manager.pyi +0 -84
  200. aip_agents/middleware/todolist.pyi +0 -125
  201. aip_agents/schema/__init__.pyi +0 -9
  202. aip_agents/schema/a2a.pyi +0 -40
  203. aip_agents/schema/agent.pyi +0 -65
  204. aip_agents/schema/hitl.pyi +0 -89
  205. aip_agents/schema/langgraph.pyi +0 -28
  206. aip_agents/schema/model_id.pyi +0 -54
  207. aip_agents/schema/step_limit.pyi +0 -63
  208. aip_agents/schema/storage.pyi +0 -21
  209. aip_agents/sentry/__init__.pyi +0 -3
  210. aip_agents/sentry/sentry.pyi +0 -48
  211. aip_agents/storage/__init__.pyi +0 -8
  212. aip_agents/storage/base.pyi +0 -58
  213. aip_agents/storage/clients/__init__.pyi +0 -3
  214. aip_agents/storage/clients/minio_client.pyi +0 -137
  215. aip_agents/storage/config.pyi +0 -29
  216. aip_agents/storage/providers/__init__.pyi +0 -5
  217. aip_agents/storage/providers/base.pyi +0 -88
  218. aip_agents/storage/providers/memory.pyi +0 -79
  219. aip_agents/storage/providers/object_storage.pyi +0 -98
  220. aip_agents/tools/__init__.pyi +0 -9
  221. aip_agents/tools/browser_use/__init__.pyi +0 -14
  222. aip_agents/tools/browser_use/action_parser.pyi +0 -18
  223. aip_agents/tools/browser_use/browser_use_tool.pyi +0 -50
  224. aip_agents/tools/browser_use/llm_config.pyi +0 -52
  225. aip_agents/tools/browser_use/minio_storage.pyi +0 -109
  226. aip_agents/tools/browser_use/schemas.pyi +0 -32
  227. aip_agents/tools/browser_use/session.pyi +0 -4
  228. aip_agents/tools/browser_use/session_errors.pyi +0 -53
  229. aip_agents/tools/browser_use/steel_session_recording.pyi +0 -63
  230. aip_agents/tools/browser_use/streaming.pyi +0 -81
  231. aip_agents/tools/browser_use/structured_data_parser.pyi +0 -86
  232. aip_agents/tools/browser_use/structured_data_recovery.pyi +0 -43
  233. aip_agents/tools/browser_use/types.pyi +0 -45
  234. aip_agents/tools/code_sandbox/__init__.pyi +0 -3
  235. aip_agents/tools/code_sandbox/constant.pyi +0 -4
  236. aip_agents/tools/code_sandbox/e2b_cloud_sandbox_extended.pyi +0 -102
  237. aip_agents/tools/code_sandbox/e2b_sandbox_tool.pyi +0 -29
  238. aip_agents/tools/constants.pyi +0 -138
  239. aip_agents/tools/document_loader/__init__.pyi +0 -7
  240. aip_agents/tools/document_loader/base_reader.pyi +0 -75
  241. aip_agents/tools/document_loader/docx_reader_tool.pyi +0 -10
  242. aip_agents/tools/document_loader/excel_reader_tool.pyi +0 -26
  243. aip_agents/tools/document_loader/pdf_reader_tool.pyi +0 -11
  244. aip_agents/tools/document_loader/pdf_splitter.pyi +0 -18
  245. aip_agents/tools/gl_connector/__init__.pyi +0 -3
  246. aip_agents/tools/gl_connector/tool.pyi +0 -74
  247. aip_agents/tools/gl_connector_tools.pyi +0 -39
  248. aip_agents/tools/memory_search/__init__.pyi +0 -5
  249. aip_agents/tools/memory_search/base.pyi +0 -69
  250. aip_agents/tools/memory_search/mem0.pyi +0 -19
  251. aip_agents/tools/memory_search/schema.pyi +0 -15
  252. aip_agents/tools/memory_search_tool.pyi +0 -3
  253. aip_agents/tools/time_tool.pyi +0 -16
  254. aip_agents/tools/tool_config_injector.pyi +0 -26
  255. aip_agents/tools/web_search/__init__.pyi +0 -3
  256. aip_agents/tools/web_search/serper_tool.pyi +0 -19
  257. aip_agents/types/__init__.pyi +0 -36
  258. aip_agents/types/a2a_events.pyi +0 -3
  259. aip_agents/utils/__init__.pyi +0 -11
  260. aip_agents/utils/a2a_connector.pyi +0 -146
  261. aip_agents/utils/artifact_helpers.pyi +0 -203
  262. aip_agents/utils/constants.pyi +0 -10
  263. aip_agents/utils/datetime/__init__.pyi +0 -4
  264. aip_agents/utils/datetime/normalization.pyi +0 -95
  265. aip_agents/utils/datetime/timezone.pyi +0 -48
  266. aip_agents/utils/env_loader.pyi +0 -10
  267. aip_agents/utils/event_handler_registry.pyi +0 -23
  268. aip_agents/utils/file_prompt_utils.pyi +0 -21
  269. aip_agents/utils/final_response_builder.pyi +0 -34
  270. aip_agents/utils/formatter_llm_client.pyi +0 -71
  271. aip_agents/utils/langgraph/__init__.pyi +0 -3
  272. aip_agents/utils/langgraph/converter.pyi +0 -49
  273. aip_agents/utils/langgraph/tool_managers/__init__.pyi +0 -5
  274. aip_agents/utils/langgraph/tool_managers/a2a_tool_manager.pyi +0 -35
  275. aip_agents/utils/langgraph/tool_managers/base_tool_manager.pyi +0 -48
  276. aip_agents/utils/langgraph/tool_managers/delegation_tool_manager.pyi +0 -56
  277. aip_agents/utils/langgraph/tool_output_management.pyi +0 -329
  278. aip_agents/utils/logger.pyi +0 -60
  279. aip_agents/utils/metadata/__init__.pyi +0 -5
  280. aip_agents/utils/metadata/activity_metadata_helper.pyi +0 -25
  281. aip_agents/utils/metadata/activity_narrative/__init__.pyi +0 -7
  282. aip_agents/utils/metadata/activity_narrative/builder.pyi +0 -35
  283. aip_agents/utils/metadata/activity_narrative/constants.pyi +0 -10
  284. aip_agents/utils/metadata/activity_narrative/context.pyi +0 -32
  285. aip_agents/utils/metadata/activity_narrative/formatters.pyi +0 -48
  286. aip_agents/utils/metadata/activity_narrative/utils.pyi +0 -12
  287. aip_agents/utils/metadata/schemas/__init__.pyi +0 -4
  288. aip_agents/utils/metadata/schemas/activity_schema.pyi +0 -18
  289. aip_agents/utils/metadata/schemas/thinking_schema.pyi +0 -20
  290. aip_agents/utils/metadata/thinking_metadata_helper.pyi +0 -4
  291. aip_agents/utils/metadata_helper.pyi +0 -117
  292. aip_agents/utils/name_preprocessor/__init__.pyi +0 -6
  293. aip_agents/utils/name_preprocessor/base_name_preprocessor.pyi +0 -52
  294. aip_agents/utils/name_preprocessor/google_name_preprocessor.pyi +0 -38
  295. aip_agents/utils/name_preprocessor/name_preprocessor.pyi +0 -41
  296. aip_agents/utils/name_preprocessor/openai_name_preprocessor.pyi +0 -34
  297. aip_agents/utils/pii/__init__.pyi +0 -5
  298. aip_agents/utils/pii/pii_handler.pyi +0 -96
  299. aip_agents/utils/pii/pii_helper.pyi +0 -78
  300. aip_agents/utils/pii/uuid_deanonymizer_mapping.pyi +0 -73
  301. aip_agents/utils/reference_helper.pyi +0 -81
  302. aip_agents/utils/sse_chunk_transformer.pyi +0 -166
  303. aip_agents/utils/step_limit_manager.pyi +0 -112
  304. aip_agents/utils/token_usage_helper.pyi +0 -60
  305. {aip_agents_binary-0.6.0.dist-info → aip_agents_binary-0.6.2.dist-info}/WHEEL +0 -0
  306. {aip_agents_binary-0.6.0.dist-info → aip_agents_binary-0.6.2.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,134 @@
1
+ """PTC Discovery Helper Module.
2
+
3
+ This module provides discovery functions for exploring available PTC tools
4
+ inside the PTC sandbox. Use these functions to find packages, list tools,
5
+ and get detailed documentation.
6
+
7
+ Usage:
8
+ from tools.ptc_helper import list_packages, list_tools, describe_tool
9
+
10
+ # List all available packages
11
+ packages = list_packages()
12
+
13
+ # List tools in a package
14
+ tools = list_tools("package_name")
15
+
16
+ # Get tool documentation
17
+ doc = describe_tool("package_name", "tool_name")
18
+ """
19
+
20
+ import difflib
21
+ import json
22
+ import os
23
+ from typing import Any
24
+
25
+ # Load the index at module import time
26
+ _INDEX_PATH = os.path.join(os.path.dirname(__file__), "ptc_index.json")
27
+ _DOCS_DIR = os.path.join(os.path.dirname(__file__), "docs")
28
+
29
+ _index: dict[str, Any] = {}
30
+ if os.path.exists(_INDEX_PATH):
31
+ with open(_INDEX_PATH, "r") as f:
32
+ _index = json.load(f)
33
+
34
+
35
+ def _suggest_closest(name: str, valid_names: list[str], kind: str = "name") -> str:
36
+ """Generate a suggestion message for closest match.
37
+
38
+ Args:
39
+ name: The name that was not found.
40
+ valid_names: List of valid names to match against.
41
+ kind: Type of name (package or tool) for the error message.
42
+
43
+ Returns:
44
+ Suggestion string or empty string if no close match.
45
+ """
46
+ matches = difflib.get_close_matches(name, valid_names, n=1, cutoff=0.6)
47
+ if matches:
48
+ return f" Did you mean '{matches[0]}'?"
49
+ return ""
50
+
51
+
52
+ def list_packages() -> list[str]:
53
+ """List all available package names.
54
+
55
+ Returns:
56
+ Sorted list of sanitized package names.
57
+ """
58
+ packages = _index.get("packages", {})
59
+ return sorted(packages.keys())
60
+
61
+
62
+ def list_tools(package: str) -> list[dict[str, str]]:
63
+ """List tools available in a package.
64
+
65
+ Args:
66
+ package: Sanitized package name (e.g., 'deepwiki').
67
+
68
+ Returns:
69
+ List of tool info dicts with 'name' keys.
70
+
71
+ Raises:
72
+ ValueError: If package is not found.
73
+ """
74
+ packages = _index.get("packages", {})
75
+ if package not in packages:
76
+ valid = list(packages.keys())
77
+ suggestion = _suggest_closest(package, valid, "package")
78
+ raise ValueError(f"Unknown package '{package}'.{suggestion}")
79
+
80
+ pkg_data = packages[package]
81
+ tools = pkg_data.get("tools", [])
82
+ return [{"name": t["name"]} for t in tools]
83
+
84
+
85
+ def describe_tool(package: str, tool: str) -> dict[str, Any]:
86
+ """Get detailed documentation for a tool.
87
+
88
+ Args:
89
+ package: Sanitized package name.
90
+ tool: Sanitized tool name.
91
+
92
+ Returns:
93
+ Dict with 'name', 'signature', 'doc', and 'doc_path' keys.
94
+
95
+ Raises:
96
+ ValueError: If package or tool is not found.
97
+ """
98
+ packages = _index.get("packages", {})
99
+ if package not in packages:
100
+ valid = list(packages.keys())
101
+ suggestion = _suggest_closest(package, valid, "package")
102
+ raise ValueError(f"Unknown package '{package}'.{suggestion}")
103
+
104
+ pkg_data = packages[package]
105
+ tools = pkg_data.get("tools", [])
106
+ tool_names = [t["name"] for t in tools]
107
+
108
+ if tool not in tool_names:
109
+ suggestion = _suggest_closest(tool, tool_names, "tool")
110
+ raise ValueError(f"Unknown tool '{tool}' in package '{package}'.{suggestion}")
111
+
112
+ tool_info = next(t for t in tools if t["name"] == tool)
113
+ doc_path = tool_info.get("doc_path", "")
114
+
115
+ doc_content = ""
116
+ if doc_path:
117
+ full_path = os.path.join(os.path.dirname(__file__), doc_path.replace("tools/", ""))
118
+ if os.path.exists(full_path):
119
+ with open(full_path, "r") as f:
120
+ doc_content = f.read()
121
+ else:
122
+ doc_content = f"# {tool}\n\n**Signature:** `{tool_info.get('signature', f'{tool}(**kwargs: Any)')}`"
123
+ else:
124
+ doc_content = f"# {tool}\n\n**Signature:** `{tool_info.get('signature', f'{tool}(**kwargs: Any)')}`"
125
+
126
+ return {
127
+ "name": tool,
128
+ "signature": tool_info.get("signature", f"{tool}(**kwargs)"),
129
+ "doc": doc_content,
130
+ "doc_path": doc_path,
131
+ }
132
+
133
+
134
+ __all__ = ["list_packages", "list_tools", "describe_tool"]
@@ -0,0 +1,43 @@
1
+ # flake8: noqa: F401
2
+ """Sandbox module for isolated code execution.
3
+
4
+ This module provides abstractions for running code in sandboxed environments.
5
+ All components support lazy loading to work with optional dependencies (e2b).
6
+
7
+ Authors:
8
+ Putu Ravindra Wiguna (putu.r.wiguna@gdplabs.id)
9
+ """
10
+
11
+ from typing import TYPE_CHECKING, Any
12
+
13
+ if TYPE_CHECKING:
14
+ from aip_agents.sandbox.e2b_runtime import E2BSandboxRuntime
15
+ from aip_agents.sandbox.template_builder import ensure_ptc_template
16
+ from aip_agents.sandbox.types import SandboxExecutionResult
17
+
18
+ _IMPORT_MAP = {
19
+ "E2BSandboxRuntime": "aip_agents.sandbox.e2b_runtime",
20
+ "ensure_ptc_template": "aip_agents.sandbox.template_builder",
21
+ "SandboxExecutionResult": "aip_agents.sandbox.types",
22
+ }
23
+
24
+ _cache: dict[str, Any] = {}
25
+
26
+
27
+ def __getattr__(name: str) -> Any:
28
+ """Lazy import components on first access."""
29
+ if name in _cache:
30
+ return _cache[name]
31
+
32
+ if name in _IMPORT_MAP:
33
+ try:
34
+ module = __import__(_IMPORT_MAP[name], fromlist=[name])
35
+ _cache[name] = getattr(module, name)
36
+ return _cache[name]
37
+ except ImportError as e:
38
+ raise ImportError(f"Failed to import {name}. Install with: pip install aip-agents[local]") from e
39
+
40
+ raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
41
+
42
+
43
+ __all__ = list(_IMPORT_MAP.keys())
@@ -0,0 +1,9 @@
1
+ """Defaults for PTC sandbox templates and packages."""
2
+
3
+ DEFAULT_PTC_TEMPLATE = "aip-agents-ptc-v1"
4
+ DEFAULT_PTC_PACKAGES: tuple[str, ...] = (
5
+ "aip-agents-binary[local]",
6
+ "mcp",
7
+ "httpx",
8
+ "gllm-plugin-binary==0.0.7",
9
+ )
@@ -0,0 +1,267 @@
1
+ """E2B Sandbox Runtime for PTC.
2
+
3
+ This module provides direct E2B SDK integration for sandbox code execution.
4
+
5
+ Authors:
6
+ Putu Ravindra Wiguna (putu.r.wiguna@gdplabs.id)
7
+ """
8
+
9
+ from e2b_code_interpreter import AsyncSandbox, OutputMessage
10
+
11
+ from aip_agents.sandbox.defaults import DEFAULT_PTC_PACKAGES, DEFAULT_PTC_TEMPLATE
12
+ from aip_agents.sandbox.types import SandboxExecutionResult
13
+ from aip_agents.sandbox.validation import validate_package_names
14
+ from aip_agents.utils.logger import get_logger
15
+
16
+ logger = get_logger(__name__)
17
+
18
+ SANDBOX_NOT_INITIALIZED_ERROR = "Sandbox not initialized"
19
+
20
+
21
+ class E2BSandboxRuntime:
22
+ """E2B Sandbox runtime for executing code in isolated environments.
23
+
24
+ This runtime manages per-run sandbox lifecycle:
25
+ - Create sandbox on first execute
26
+ - Reuse sandbox for subsequent executes
27
+ - Destroy sandbox on cleanup
28
+
29
+ Example:
30
+ runtime = E2BSandboxRuntime()
31
+ result = await runtime.execute(
32
+ code="print('Hello')",
33
+ timeout=60.0,
34
+ files={"tools/mcp.py": "# MCP client code"},
35
+ )
36
+ await runtime.cleanup()
37
+ """
38
+
39
+ def __init__(
40
+ self,
41
+ template: str | None = None,
42
+ ptc_packages: list[str] | None = None,
43
+ ) -> None:
44
+ """Initialize E2B sandbox runtime.
45
+
46
+ Args:
47
+ template: Optional E2B template ID for custom sandbox environments.
48
+ ptc_packages: Packages to install in sandbox. If None or empty, skip install.
49
+ """
50
+ self._template = template
51
+ self._ptc_packages = ptc_packages
52
+ self._sandbox: AsyncSandbox | None = None
53
+ self._sandbox_created_with_template = False
54
+
55
+ async def execute(
56
+ self,
57
+ code: str,
58
+ *,
59
+ timeout: float = 300.0,
60
+ files: dict[str, str] | None = None,
61
+ env: dict[str, str] | None = None,
62
+ template: str | None = None,
63
+ ) -> SandboxExecutionResult:
64
+ """Execute code inside the sandbox.
65
+
66
+ Args:
67
+ code: Python code to execute.
68
+ timeout: Execution timeout in seconds.
69
+ files: Files to upload to the sandbox (path -> content).
70
+ env: Environment variables to set.
71
+ template: Optional template override for this execution.
72
+
73
+ Returns:
74
+ SandboxExecutionResult with stdout, stderr, and exit_code.
75
+ """
76
+ # Create sandbox if not exists
77
+ if self._sandbox is None:
78
+ await self._create_sandbox(template or self._template)
79
+
80
+ # Upload files if provided
81
+ if files:
82
+ await self._upload_files(files)
83
+
84
+ # Execute code
85
+ return await self._run_code(code, timeout, env)
86
+
87
+ async def cleanup(self) -> None:
88
+ """Destroy the sandbox and release resources."""
89
+ if self._sandbox is not None:
90
+ try:
91
+ logger.info("Destroying E2B sandbox")
92
+ await self._sandbox.kill()
93
+ except Exception as e:
94
+ logger.warning(f"Error destroying sandbox: {e}")
95
+ finally:
96
+ self._sandbox = None
97
+
98
+ self._reset_async_transport()
99
+
100
+ @property
101
+ def is_active(self) -> bool:
102
+ """Check if a sandbox is currently active."""
103
+ return self._sandbox is not None
104
+
105
+ def _reset_async_transport(self) -> None:
106
+ try:
107
+ from e2b.api.client_async import AsyncTransportWithLogger
108
+
109
+ AsyncTransportWithLogger.singleton = None
110
+ except Exception:
111
+ return
112
+
113
+ def _should_skip_default_ptc_install(self, template: str | None) -> bool:
114
+ if not self._sandbox_created_with_template:
115
+ return False
116
+
117
+ if template != DEFAULT_PTC_TEMPLATE:
118
+ return False
119
+
120
+ return self._ptc_packages == list(DEFAULT_PTC_PACKAGES)
121
+
122
+ async def _create_sandbox(self, template: str | None = None) -> None:
123
+ """Create a new E2B sandbox.
124
+
125
+ Implements canonical runtime rules:
126
+ - If template provided, try creating sandbox with template
127
+ - On any error, fall back to default sandbox (without template)
128
+ - Install ptc_packages regardless of template usage (even after fallback)
129
+
130
+ Note: Package installation occurs after sandbox creation, so fallback
131
+ to default sandbox does not skip package installation.
132
+
133
+ Args:
134
+ template: Optional template ID.
135
+ """
136
+ logger.info(f"Creating E2B sandbox (template={template})")
137
+
138
+ async def create_default_sandbox() -> None:
139
+ self._sandbox = await AsyncSandbox.create()
140
+ logger.info(f"E2B sandbox created (default): {self._sandbox.sandbox_id}")
141
+
142
+ if template:
143
+ try:
144
+ self._sandbox = await AsyncSandbox.create(template=template)
145
+ self._sandbox_created_with_template = True
146
+ logger.info(f"E2B sandbox created: {self._sandbox.sandbox_id}")
147
+ except Exception as e:
148
+ logger.warning(f"Template creation failed ({template}): {e}")
149
+ logger.info("Falling back to default sandbox")
150
+ self._sandbox_created_with_template = False
151
+ await create_default_sandbox()
152
+ else:
153
+ self._sandbox_created_with_template = False
154
+ await create_default_sandbox()
155
+
156
+ # Install ptc_packages if non-empty
157
+ if self._ptc_packages:
158
+ if self._should_skip_default_ptc_install(template):
159
+ logger.info("Skipping PTC package install (default template already includes defaults)")
160
+ else:
161
+ await self._install_ptc_packages()
162
+
163
+ async def _install_ptc_packages(self) -> None:
164
+ """Install PTC packages in the sandbox."""
165
+ if self._sandbox is None:
166
+ raise RuntimeError(SANDBOX_NOT_INITIALIZED_ERROR)
167
+
168
+ # Validate all packages before constructing command
169
+ validate_package_names(self._ptc_packages)
170
+
171
+ # Note: packages_str is safe because ptc_packages is a controlled list from
172
+ # configuration, not user input. E2B SDK's commands.run() only accepts str,
173
+ # not list, so string joining is required.
174
+ packages_str = " ".join(self._ptc_packages)
175
+ logger.info(f"Installing PTC packages in sandbox: {packages_str}")
176
+
177
+ try:
178
+ result = await self._sandbox.commands.run(
179
+ f"pip install -q {packages_str}",
180
+ timeout=120,
181
+ )
182
+ except Exception as e:
183
+ logger.error(f"Error installing PTC packages: {e}")
184
+ raise
185
+
186
+ if result.exit_code != 0:
187
+ logger.error(f"Failed to install PTC packages: {result.stderr}")
188
+ raise RuntimeError(f"Failed to install PTC packages: {result.stderr}")
189
+
190
+ logger.info("PTC packages installed successfully")
191
+
192
+ async def _upload_files(self, files: dict[str, str]) -> None:
193
+ """Upload files to the sandbox.
194
+
195
+ Args:
196
+ files: Mapping of path -> content.
197
+ """
198
+ if self._sandbox is None:
199
+ raise RuntimeError(SANDBOX_NOT_INITIALIZED_ERROR)
200
+
201
+ for path, content in files.items():
202
+ logger.debug(f"Uploading file to sandbox: {path}")
203
+ await self._sandbox.files.write(path, content)
204
+
205
+ async def _run_code(
206
+ self,
207
+ code: str,
208
+ timeout: float,
209
+ env: dict[str, str] | None = None,
210
+ ) -> SandboxExecutionResult:
211
+ """Run code in the sandbox.
212
+
213
+ Args:
214
+ code: Python code to execute.
215
+ timeout: Execution timeout in seconds.
216
+ env: Environment variables.
217
+
218
+ Returns:
219
+ SandboxExecutionResult with execution output.
220
+ """
221
+ if self._sandbox is None:
222
+ raise RuntimeError(SANDBOX_NOT_INITIALIZED_ERROR)
223
+
224
+ stdout_lines: list[str] = []
225
+ stderr_lines: list[str] = []
226
+
227
+ def on_stdout(msg: OutputMessage) -> None:
228
+ if hasattr(msg, "line"):
229
+ stdout_lines.append(msg.line)
230
+
231
+ def on_stderr(msg: OutputMessage) -> None:
232
+ if hasattr(msg, "line"):
233
+ stderr_lines.append(msg.line)
234
+
235
+ try:
236
+ execution = await self._sandbox.run_code(
237
+ code=code,
238
+ language="python",
239
+ on_stdout=on_stdout,
240
+ on_stderr=on_stderr,
241
+ envs=env,
242
+ timeout=timeout,
243
+ )
244
+
245
+ # Determine exit code
246
+ exit_code = 0
247
+ if execution.error:
248
+ exit_code = 1
249
+ # Add error to stderr
250
+ error_msg = f"{execution.error.name}: {execution.error.value}"
251
+ if execution.error.traceback:
252
+ error_msg = f"{execution.error.traceback}\n{error_msg}"
253
+ stderr_lines.append(error_msg)
254
+
255
+ return SandboxExecutionResult(
256
+ stdout="\n".join(stdout_lines),
257
+ stderr="\n".join(stderr_lines),
258
+ exit_code=exit_code,
259
+ )
260
+
261
+ except Exception as e:
262
+ logger.error(f"Sandbox execution failed: {e}")
263
+ return SandboxExecutionResult(
264
+ stdout="",
265
+ stderr=str(e),
266
+ exit_code=1,
267
+ )
@@ -0,0 +1,131 @@
1
+ """Template builder for PTC sandbox templates.
2
+
3
+ This module provides utilities for creating and managing E2B sandbox templates
4
+ for programmatic tool calling (PTC) environments.
5
+
6
+ Authors:
7
+ Putu Ravindra Wiguna (putu.r.wiguna@gdplabs.id)
8
+ """
9
+
10
+ from e2b import Template, default_build_logger
11
+
12
+ from aip_agents.sandbox.validation import validate_package_names
13
+ from aip_agents.utils.logger import get_logger
14
+
15
+ logger = get_logger(__name__)
16
+
17
+
18
+ def create_ptc_template(base_template: str, ptc_packages: list[str] | None) -> Template:
19
+ """Create a PTC template definition based on a base template.
20
+
21
+ Args:
22
+ base_template: Base template alias to build from (e.g., "code-interpreter-v1").
23
+ ptc_packages: List of packages to install in the template.
24
+ If None or empty, skips pip install step.
25
+
26
+ Returns:
27
+ Template: A configured template ready to be built.
28
+ """
29
+ logger.info(f"Creating template from base: {base_template}")
30
+ template = Template().from_template(base_template)
31
+
32
+ if ptc_packages:
33
+ # Validate all packages before constructing command
34
+ validate_package_names(ptc_packages)
35
+
36
+ # Note: packages_str is safe because ptc_packages is a controlled list from
37
+ # configuration, not user input. Template.run_cmd() only accepts str.
38
+ packages_str = " ".join(ptc_packages)
39
+ logger.info(f"Installing packages: {packages_str}")
40
+ template.run_cmd(f"pip install -q {packages_str}")
41
+
42
+ return template
43
+
44
+
45
+ def _template_exists(template_id: str) -> bool:
46
+ """Check if a template alias exists.
47
+
48
+ Args:
49
+ template_id: The template alias to check.
50
+
51
+ Returns:
52
+ bool: True if alias exists, False otherwise.
53
+ """
54
+ try:
55
+ return Template.alias_exists(template_id)
56
+ except Exception:
57
+ logger.warning(f"Template alias check failed for: {template_id}")
58
+ return False
59
+
60
+
61
+ def _build_template(template: Template, template_id: str) -> bool:
62
+ """Build a template with the given alias.
63
+
64
+ Args:
65
+ template: The template to build.
66
+ template_id: The alias to assign to the built template.
67
+
68
+ Returns:
69
+ bool: True if build succeeded, False otherwise.
70
+ """
71
+ try:
72
+ logger.info(f"Building template: {template_id}")
73
+ Template.build(
74
+ template,
75
+ alias=template_id,
76
+ on_build_logs=default_build_logger(),
77
+ )
78
+ logger.info(f"Template built successfully: {template_id}")
79
+ return True
80
+ except Exception as e:
81
+ logger.warning(f"Template build failed for {template_id}: {e}")
82
+ return False
83
+
84
+
85
+ def ensure_ptc_template(
86
+ template_id: str,
87
+ base_template: str,
88
+ ptc_packages: list[str] | None,
89
+ force_rebuild: bool = False,
90
+ ) -> str | None:
91
+ """Ensure a PTC sandbox template exists, creating it if necessary.
92
+
93
+ This is an explicit helper that apps can call at startup to ensure the
94
+ template exists. It is never run implicitly by the SDK.
95
+
96
+ Args:
97
+ template_id: Unique alias for the template (e.g., "aip-agents-ptc-v1").
98
+ base_template: Base template alias to build from
99
+ (e.g., "code-interpreter-v1").
100
+ ptc_packages: List of packages to install in the template.
101
+ If None or empty, skips pip install step.
102
+ force_rebuild: If True, rebuild even if alias exists.
103
+
104
+ Returns:
105
+ The template_id on success, None if creation failed.
106
+ Never raises exceptions.
107
+ """
108
+ # Fast path: template already exists and we're not forcing rebuild
109
+ if not force_rebuild and _template_exists(template_id):
110
+ logger.info(f"Template already exists: {template_id}")
111
+ return template_id
112
+
113
+ # Create and build the template
114
+ try:
115
+ template = create_ptc_template(base_template, ptc_packages)
116
+ except Exception as e:
117
+ logger.warning(f"Template creation failed for {template_id}: {e}")
118
+ return None
119
+
120
+ # Build the template
121
+ is_success = _build_template(template, template_id)
122
+ if is_success:
123
+ return template_id
124
+
125
+ # Build failed. Check if template exists anyway (race condition: another
126
+ # process may have built it while we were trying)
127
+ if _template_exists(template_id):
128
+ logger.info(f"Template already exists after failed build: {template_id}")
129
+ return template_id
130
+
131
+ return None
@@ -0,0 +1,24 @@
1
+ """Sandbox execution result types.
2
+
3
+ This module defines types for sandbox execution results.
4
+
5
+ Authors:
6
+ Putu Ravindra Wiguna (putu.r.wiguna@gdplabs.id)
7
+ """
8
+
9
+ from dataclasses import dataclass
10
+
11
+
12
+ @dataclass
13
+ class SandboxExecutionResult:
14
+ """Result of a sandbox code execution.
15
+
16
+ Attributes:
17
+ stdout: Standard output from the execution.
18
+ stderr: Standard error from the execution.
19
+ exit_code: Exit code (0 for success, non-zero for failure).
20
+ """
21
+
22
+ stdout: str
23
+ stderr: str
24
+ exit_code: int
@@ -0,0 +1,50 @@
1
+ """Validation utilities for sandbox operations.
2
+
3
+ This module provides validation functions for sandbox-related operations
4
+ such as package name validation.
5
+
6
+ Authors:
7
+ Putu Ravindra Wiguna (putu.r.wiguna@gdplabs.id)
8
+ """
9
+
10
+ import re
11
+
12
+ _PACKAGE_SPEC_PATTERN = re.compile(
13
+ r"^[A-Za-z0-9](?:[A-Za-z0-9._-]*[A-Za-z0-9])?"
14
+ r"(?:\[[A-Za-z0-9._-]+(?:,[A-Za-z0-9._-]+)*\])?"
15
+ r"(?:"
16
+ r"(?:==|!=|<=|>=|~=|<|>)[0-9][A-Za-z0-9.*+!_-]*"
17
+ r"(?:,(?:==|!=|<=|>=|~=|<|>)[0-9][A-Za-z0-9.*+!_-]*)*"
18
+ r")?$"
19
+ )
20
+
21
+
22
+ def validate_package_name(package: str) -> bool:
23
+ """Validate package name/specifier format for pip install.
24
+
25
+ Allows standard pip formats: package, package==version, package[extra].
26
+
27
+ Args:
28
+ package: Package name or specifier to validate.
29
+
30
+ Returns:
31
+ True if package name is valid, False otherwise.
32
+ """
33
+ if not package:
34
+ return False
35
+
36
+ return bool(_PACKAGE_SPEC_PATTERN.fullmatch(package))
37
+
38
+
39
+ def validate_package_names(packages: list[str]) -> None:
40
+ """Validate all package names in a list.
41
+
42
+ Args:
43
+ packages: List of package names or specifiers to validate.
44
+
45
+ Raises:
46
+ ValueError: If any package name is invalid.
47
+ """
48
+ for pkg in packages:
49
+ if not validate_package_name(pkg):
50
+ raise ValueError(f"Invalid package name format: {pkg}")
@@ -46,8 +46,10 @@ _register_optional("aip_agents.tools.code_sandbox", "E2BCodeSandboxTool")
46
46
  _register_optional("aip_agents.tools.document_loader", "DocxReaderTool")
47
47
  _register_optional("aip_agents.tools.document_loader", "ExcelReaderTool")
48
48
  _register_optional("aip_agents.tools.document_loader", "PDFReaderTool")
49
+ _register_optional("aip_agents.tools.execute_ptc_code", "create_execute_ptc_code_tool")
49
50
 
50
51
  if TYPE_CHECKING:
51
52
  from aip_agents.tools.browser_use import BrowserUseTool
52
53
  from aip_agents.tools.code_sandbox import E2BCodeSandboxTool
53
54
  from aip_agents.tools.document_loader import DocxReaderTool, ExcelReaderTool, PDFReaderTool
55
+ from aip_agents.tools.execute_ptc_code import create_execute_ptc_code_tool