ag2 0.10.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 (423) hide show
  1. ag2-0.10.2.dist-info/METADATA +819 -0
  2. ag2-0.10.2.dist-info/RECORD +423 -0
  3. ag2-0.10.2.dist-info/WHEEL +4 -0
  4. ag2-0.10.2.dist-info/licenses/LICENSE +201 -0
  5. ag2-0.10.2.dist-info/licenses/NOTICE.md +19 -0
  6. autogen/__init__.py +88 -0
  7. autogen/_website/__init__.py +3 -0
  8. autogen/_website/generate_api_references.py +426 -0
  9. autogen/_website/generate_mkdocs.py +1216 -0
  10. autogen/_website/notebook_processor.py +475 -0
  11. autogen/_website/process_notebooks.py +656 -0
  12. autogen/_website/utils.py +413 -0
  13. autogen/a2a/__init__.py +36 -0
  14. autogen/a2a/agent_executor.py +86 -0
  15. autogen/a2a/client.py +357 -0
  16. autogen/a2a/errors.py +18 -0
  17. autogen/a2a/httpx_client_factory.py +79 -0
  18. autogen/a2a/server.py +221 -0
  19. autogen/a2a/utils.py +207 -0
  20. autogen/agentchat/__init__.py +47 -0
  21. autogen/agentchat/agent.py +180 -0
  22. autogen/agentchat/assistant_agent.py +86 -0
  23. autogen/agentchat/chat.py +325 -0
  24. autogen/agentchat/contrib/__init__.py +5 -0
  25. autogen/agentchat/contrib/agent_eval/README.md +7 -0
  26. autogen/agentchat/contrib/agent_eval/agent_eval.py +108 -0
  27. autogen/agentchat/contrib/agent_eval/criterion.py +43 -0
  28. autogen/agentchat/contrib/agent_eval/critic_agent.py +44 -0
  29. autogen/agentchat/contrib/agent_eval/quantifier_agent.py +39 -0
  30. autogen/agentchat/contrib/agent_eval/subcritic_agent.py +45 -0
  31. autogen/agentchat/contrib/agent_eval/task.py +42 -0
  32. autogen/agentchat/contrib/agent_optimizer.py +432 -0
  33. autogen/agentchat/contrib/capabilities/__init__.py +5 -0
  34. autogen/agentchat/contrib/capabilities/agent_capability.py +20 -0
  35. autogen/agentchat/contrib/capabilities/generate_images.py +301 -0
  36. autogen/agentchat/contrib/capabilities/teachability.py +393 -0
  37. autogen/agentchat/contrib/capabilities/text_compressors.py +66 -0
  38. autogen/agentchat/contrib/capabilities/tools_capability.py +22 -0
  39. autogen/agentchat/contrib/capabilities/transform_messages.py +93 -0
  40. autogen/agentchat/contrib/capabilities/transforms.py +578 -0
  41. autogen/agentchat/contrib/capabilities/transforms_util.py +122 -0
  42. autogen/agentchat/contrib/capabilities/vision_capability.py +215 -0
  43. autogen/agentchat/contrib/captainagent/__init__.py +9 -0
  44. autogen/agentchat/contrib/captainagent/agent_builder.py +790 -0
  45. autogen/agentchat/contrib/captainagent/captainagent.py +514 -0
  46. autogen/agentchat/contrib/captainagent/tool_retriever.py +334 -0
  47. autogen/agentchat/contrib/captainagent/tools/README.md +44 -0
  48. autogen/agentchat/contrib/captainagent/tools/__init__.py +5 -0
  49. autogen/agentchat/contrib/captainagent/tools/data_analysis/calculate_correlation.py +40 -0
  50. autogen/agentchat/contrib/captainagent/tools/data_analysis/calculate_skewness_and_kurtosis.py +28 -0
  51. autogen/agentchat/contrib/captainagent/tools/data_analysis/detect_outlier_iqr.py +28 -0
  52. autogen/agentchat/contrib/captainagent/tools/data_analysis/detect_outlier_zscore.py +28 -0
  53. autogen/agentchat/contrib/captainagent/tools/data_analysis/explore_csv.py +21 -0
  54. autogen/agentchat/contrib/captainagent/tools/data_analysis/shapiro_wilk_test.py +30 -0
  55. autogen/agentchat/contrib/captainagent/tools/information_retrieval/arxiv_download.py +27 -0
  56. autogen/agentchat/contrib/captainagent/tools/information_retrieval/arxiv_search.py +53 -0
  57. autogen/agentchat/contrib/captainagent/tools/information_retrieval/extract_pdf_image.py +53 -0
  58. autogen/agentchat/contrib/captainagent/tools/information_retrieval/extract_pdf_text.py +38 -0
  59. autogen/agentchat/contrib/captainagent/tools/information_retrieval/get_wikipedia_text.py +21 -0
  60. autogen/agentchat/contrib/captainagent/tools/information_retrieval/get_youtube_caption.py +34 -0
  61. autogen/agentchat/contrib/captainagent/tools/information_retrieval/image_qa.py +60 -0
  62. autogen/agentchat/contrib/captainagent/tools/information_retrieval/optical_character_recognition.py +61 -0
  63. autogen/agentchat/contrib/captainagent/tools/information_retrieval/perform_web_search.py +47 -0
  64. autogen/agentchat/contrib/captainagent/tools/information_retrieval/scrape_wikipedia_tables.py +33 -0
  65. autogen/agentchat/contrib/captainagent/tools/information_retrieval/transcribe_audio_file.py +21 -0
  66. autogen/agentchat/contrib/captainagent/tools/information_retrieval/youtube_download.py +35 -0
  67. autogen/agentchat/contrib/captainagent/tools/math/calculate_circle_area_from_diameter.py +21 -0
  68. autogen/agentchat/contrib/captainagent/tools/math/calculate_day_of_the_week.py +18 -0
  69. autogen/agentchat/contrib/captainagent/tools/math/calculate_fraction_sum.py +28 -0
  70. autogen/agentchat/contrib/captainagent/tools/math/calculate_matrix_power.py +31 -0
  71. autogen/agentchat/contrib/captainagent/tools/math/calculate_reflected_point.py +16 -0
  72. autogen/agentchat/contrib/captainagent/tools/math/complex_numbers_product.py +25 -0
  73. autogen/agentchat/contrib/captainagent/tools/math/compute_currency_conversion.py +23 -0
  74. autogen/agentchat/contrib/captainagent/tools/math/count_distinct_permutations.py +27 -0
  75. autogen/agentchat/contrib/captainagent/tools/math/evaluate_expression.py +28 -0
  76. autogen/agentchat/contrib/captainagent/tools/math/find_continuity_point.py +34 -0
  77. autogen/agentchat/contrib/captainagent/tools/math/fraction_to_mixed_numbers.py +39 -0
  78. autogen/agentchat/contrib/captainagent/tools/math/modular_inverse_sum.py +23 -0
  79. autogen/agentchat/contrib/captainagent/tools/math/simplify_mixed_numbers.py +36 -0
  80. autogen/agentchat/contrib/captainagent/tools/math/sum_of_digit_factorials.py +15 -0
  81. autogen/agentchat/contrib/captainagent/tools/math/sum_of_primes_below.py +15 -0
  82. autogen/agentchat/contrib/captainagent/tools/requirements.txt +10 -0
  83. autogen/agentchat/contrib/captainagent/tools/tool_description.tsv +34 -0
  84. autogen/agentchat/contrib/gpt_assistant_agent.py +526 -0
  85. autogen/agentchat/contrib/graph_rag/__init__.py +9 -0
  86. autogen/agentchat/contrib/graph_rag/document.py +29 -0
  87. autogen/agentchat/contrib/graph_rag/falkor_graph_query_engine.py +167 -0
  88. autogen/agentchat/contrib/graph_rag/falkor_graph_rag_capability.py +103 -0
  89. autogen/agentchat/contrib/graph_rag/graph_query_engine.py +53 -0
  90. autogen/agentchat/contrib/graph_rag/graph_rag_capability.py +63 -0
  91. autogen/agentchat/contrib/graph_rag/neo4j_graph_query_engine.py +263 -0
  92. autogen/agentchat/contrib/graph_rag/neo4j_graph_rag_capability.py +83 -0
  93. autogen/agentchat/contrib/graph_rag/neo4j_native_graph_query_engine.py +210 -0
  94. autogen/agentchat/contrib/graph_rag/neo4j_native_graph_rag_capability.py +93 -0
  95. autogen/agentchat/contrib/img_utils.py +397 -0
  96. autogen/agentchat/contrib/llamaindex_conversable_agent.py +117 -0
  97. autogen/agentchat/contrib/llava_agent.py +189 -0
  98. autogen/agentchat/contrib/math_user_proxy_agent.py +464 -0
  99. autogen/agentchat/contrib/multimodal_conversable_agent.py +125 -0
  100. autogen/agentchat/contrib/qdrant_retrieve_user_proxy_agent.py +325 -0
  101. autogen/agentchat/contrib/rag/__init__.py +10 -0
  102. autogen/agentchat/contrib/rag/chromadb_query_engine.py +268 -0
  103. autogen/agentchat/contrib/rag/llamaindex_query_engine.py +195 -0
  104. autogen/agentchat/contrib/rag/mongodb_query_engine.py +319 -0
  105. autogen/agentchat/contrib/rag/query_engine.py +76 -0
  106. autogen/agentchat/contrib/retrieve_assistant_agent.py +59 -0
  107. autogen/agentchat/contrib/retrieve_user_proxy_agent.py +704 -0
  108. autogen/agentchat/contrib/society_of_mind_agent.py +200 -0
  109. autogen/agentchat/contrib/swarm_agent.py +1404 -0
  110. autogen/agentchat/contrib/text_analyzer_agent.py +79 -0
  111. autogen/agentchat/contrib/vectordb/__init__.py +5 -0
  112. autogen/agentchat/contrib/vectordb/base.py +224 -0
  113. autogen/agentchat/contrib/vectordb/chromadb.py +316 -0
  114. autogen/agentchat/contrib/vectordb/couchbase.py +405 -0
  115. autogen/agentchat/contrib/vectordb/mongodb.py +551 -0
  116. autogen/agentchat/contrib/vectordb/pgvectordb.py +927 -0
  117. autogen/agentchat/contrib/vectordb/qdrant.py +320 -0
  118. autogen/agentchat/contrib/vectordb/utils.py +126 -0
  119. autogen/agentchat/contrib/web_surfer.py +304 -0
  120. autogen/agentchat/conversable_agent.py +4307 -0
  121. autogen/agentchat/group/__init__.py +67 -0
  122. autogen/agentchat/group/available_condition.py +91 -0
  123. autogen/agentchat/group/context_condition.py +77 -0
  124. autogen/agentchat/group/context_expression.py +238 -0
  125. autogen/agentchat/group/context_str.py +39 -0
  126. autogen/agentchat/group/context_variables.py +182 -0
  127. autogen/agentchat/group/events/transition_events.py +111 -0
  128. autogen/agentchat/group/group_tool_executor.py +324 -0
  129. autogen/agentchat/group/group_utils.py +659 -0
  130. autogen/agentchat/group/guardrails.py +179 -0
  131. autogen/agentchat/group/handoffs.py +303 -0
  132. autogen/agentchat/group/llm_condition.py +93 -0
  133. autogen/agentchat/group/multi_agent_chat.py +291 -0
  134. autogen/agentchat/group/on_condition.py +55 -0
  135. autogen/agentchat/group/on_context_condition.py +51 -0
  136. autogen/agentchat/group/patterns/__init__.py +18 -0
  137. autogen/agentchat/group/patterns/auto.py +160 -0
  138. autogen/agentchat/group/patterns/manual.py +177 -0
  139. autogen/agentchat/group/patterns/pattern.py +295 -0
  140. autogen/agentchat/group/patterns/random.py +106 -0
  141. autogen/agentchat/group/patterns/round_robin.py +117 -0
  142. autogen/agentchat/group/reply_result.py +24 -0
  143. autogen/agentchat/group/safeguards/__init__.py +21 -0
  144. autogen/agentchat/group/safeguards/api.py +241 -0
  145. autogen/agentchat/group/safeguards/enforcer.py +1158 -0
  146. autogen/agentchat/group/safeguards/events.py +140 -0
  147. autogen/agentchat/group/safeguards/validator.py +435 -0
  148. autogen/agentchat/group/speaker_selection_result.py +41 -0
  149. autogen/agentchat/group/targets/__init__.py +4 -0
  150. autogen/agentchat/group/targets/function_target.py +245 -0
  151. autogen/agentchat/group/targets/group_chat_target.py +133 -0
  152. autogen/agentchat/group/targets/group_manager_target.py +151 -0
  153. autogen/agentchat/group/targets/transition_target.py +424 -0
  154. autogen/agentchat/group/targets/transition_utils.py +6 -0
  155. autogen/agentchat/groupchat.py +1832 -0
  156. autogen/agentchat/realtime/__init__.py +3 -0
  157. autogen/agentchat/realtime/experimental/__init__.py +20 -0
  158. autogen/agentchat/realtime/experimental/audio_adapters/__init__.py +8 -0
  159. autogen/agentchat/realtime/experimental/audio_adapters/twilio_audio_adapter.py +148 -0
  160. autogen/agentchat/realtime/experimental/audio_adapters/websocket_audio_adapter.py +139 -0
  161. autogen/agentchat/realtime/experimental/audio_observer.py +42 -0
  162. autogen/agentchat/realtime/experimental/clients/__init__.py +15 -0
  163. autogen/agentchat/realtime/experimental/clients/gemini/__init__.py +7 -0
  164. autogen/agentchat/realtime/experimental/clients/gemini/client.py +274 -0
  165. autogen/agentchat/realtime/experimental/clients/oai/__init__.py +8 -0
  166. autogen/agentchat/realtime/experimental/clients/oai/base_client.py +220 -0
  167. autogen/agentchat/realtime/experimental/clients/oai/rtc_client.py +243 -0
  168. autogen/agentchat/realtime/experimental/clients/oai/utils.py +48 -0
  169. autogen/agentchat/realtime/experimental/clients/realtime_client.py +191 -0
  170. autogen/agentchat/realtime/experimental/function_observer.py +84 -0
  171. autogen/agentchat/realtime/experimental/realtime_agent.py +158 -0
  172. autogen/agentchat/realtime/experimental/realtime_events.py +42 -0
  173. autogen/agentchat/realtime/experimental/realtime_observer.py +100 -0
  174. autogen/agentchat/realtime/experimental/realtime_swarm.py +533 -0
  175. autogen/agentchat/realtime/experimental/websockets.py +21 -0
  176. autogen/agentchat/realtime_agent/__init__.py +21 -0
  177. autogen/agentchat/user_proxy_agent.py +114 -0
  178. autogen/agentchat/utils.py +206 -0
  179. autogen/agents/__init__.py +3 -0
  180. autogen/agents/contrib/__init__.py +10 -0
  181. autogen/agents/contrib/time/__init__.py +8 -0
  182. autogen/agents/contrib/time/time_reply_agent.py +74 -0
  183. autogen/agents/contrib/time/time_tool_agent.py +52 -0
  184. autogen/agents/experimental/__init__.py +27 -0
  185. autogen/agents/experimental/deep_research/__init__.py +7 -0
  186. autogen/agents/experimental/deep_research/deep_research.py +52 -0
  187. autogen/agents/experimental/discord/__init__.py +7 -0
  188. autogen/agents/experimental/discord/discord.py +66 -0
  189. autogen/agents/experimental/document_agent/__init__.py +19 -0
  190. autogen/agents/experimental/document_agent/chroma_query_engine.py +301 -0
  191. autogen/agents/experimental/document_agent/docling_doc_ingest_agent.py +113 -0
  192. autogen/agents/experimental/document_agent/document_agent.py +643 -0
  193. autogen/agents/experimental/document_agent/document_conditions.py +50 -0
  194. autogen/agents/experimental/document_agent/document_utils.py +376 -0
  195. autogen/agents/experimental/document_agent/inmemory_query_engine.py +214 -0
  196. autogen/agents/experimental/document_agent/parser_utils.py +134 -0
  197. autogen/agents/experimental/document_agent/url_utils.py +417 -0
  198. autogen/agents/experimental/reasoning/__init__.py +7 -0
  199. autogen/agents/experimental/reasoning/reasoning_agent.py +1178 -0
  200. autogen/agents/experimental/slack/__init__.py +7 -0
  201. autogen/agents/experimental/slack/slack.py +73 -0
  202. autogen/agents/experimental/telegram/__init__.py +7 -0
  203. autogen/agents/experimental/telegram/telegram.py +76 -0
  204. autogen/agents/experimental/websurfer/__init__.py +7 -0
  205. autogen/agents/experimental/websurfer/websurfer.py +70 -0
  206. autogen/agents/experimental/wikipedia/__init__.py +7 -0
  207. autogen/agents/experimental/wikipedia/wikipedia.py +88 -0
  208. autogen/browser_utils.py +309 -0
  209. autogen/cache/__init__.py +10 -0
  210. autogen/cache/abstract_cache_base.py +71 -0
  211. autogen/cache/cache.py +203 -0
  212. autogen/cache/cache_factory.py +88 -0
  213. autogen/cache/cosmos_db_cache.py +144 -0
  214. autogen/cache/disk_cache.py +97 -0
  215. autogen/cache/in_memory_cache.py +54 -0
  216. autogen/cache/redis_cache.py +119 -0
  217. autogen/code_utils.py +598 -0
  218. autogen/coding/__init__.py +30 -0
  219. autogen/coding/base.py +120 -0
  220. autogen/coding/docker_commandline_code_executor.py +283 -0
  221. autogen/coding/factory.py +56 -0
  222. autogen/coding/func_with_reqs.py +203 -0
  223. autogen/coding/jupyter/__init__.py +23 -0
  224. autogen/coding/jupyter/base.py +36 -0
  225. autogen/coding/jupyter/docker_jupyter_server.py +160 -0
  226. autogen/coding/jupyter/embedded_ipython_code_executor.py +182 -0
  227. autogen/coding/jupyter/import_utils.py +82 -0
  228. autogen/coding/jupyter/jupyter_client.py +224 -0
  229. autogen/coding/jupyter/jupyter_code_executor.py +154 -0
  230. autogen/coding/jupyter/local_jupyter_server.py +164 -0
  231. autogen/coding/local_commandline_code_executor.py +341 -0
  232. autogen/coding/markdown_code_extractor.py +44 -0
  233. autogen/coding/utils.py +55 -0
  234. autogen/coding/yepcode_code_executor.py +197 -0
  235. autogen/doc_utils.py +35 -0
  236. autogen/environments/__init__.py +10 -0
  237. autogen/environments/docker_python_environment.py +365 -0
  238. autogen/environments/python_environment.py +125 -0
  239. autogen/environments/system_python_environment.py +85 -0
  240. autogen/environments/venv_python_environment.py +220 -0
  241. autogen/environments/working_directory.py +74 -0
  242. autogen/events/__init__.py +7 -0
  243. autogen/events/agent_events.py +1016 -0
  244. autogen/events/base_event.py +100 -0
  245. autogen/events/client_events.py +168 -0
  246. autogen/events/helpers.py +44 -0
  247. autogen/events/print_event.py +45 -0
  248. autogen/exception_utils.py +73 -0
  249. autogen/extensions/__init__.py +5 -0
  250. autogen/fast_depends/__init__.py +16 -0
  251. autogen/fast_depends/_compat.py +75 -0
  252. autogen/fast_depends/core/__init__.py +14 -0
  253. autogen/fast_depends/core/build.py +206 -0
  254. autogen/fast_depends/core/model.py +527 -0
  255. autogen/fast_depends/dependencies/__init__.py +15 -0
  256. autogen/fast_depends/dependencies/model.py +30 -0
  257. autogen/fast_depends/dependencies/provider.py +40 -0
  258. autogen/fast_depends/library/__init__.py +10 -0
  259. autogen/fast_depends/library/model.py +46 -0
  260. autogen/fast_depends/py.typed +6 -0
  261. autogen/fast_depends/schema.py +66 -0
  262. autogen/fast_depends/use.py +272 -0
  263. autogen/fast_depends/utils.py +177 -0
  264. autogen/formatting_utils.py +83 -0
  265. autogen/function_utils.py +13 -0
  266. autogen/graph_utils.py +173 -0
  267. autogen/import_utils.py +539 -0
  268. autogen/interop/__init__.py +22 -0
  269. autogen/interop/crewai/__init__.py +7 -0
  270. autogen/interop/crewai/crewai.py +88 -0
  271. autogen/interop/interoperability.py +71 -0
  272. autogen/interop/interoperable.py +46 -0
  273. autogen/interop/langchain/__init__.py +8 -0
  274. autogen/interop/langchain/langchain_chat_model_factory.py +156 -0
  275. autogen/interop/langchain/langchain_tool.py +78 -0
  276. autogen/interop/litellm/__init__.py +7 -0
  277. autogen/interop/litellm/litellm_config_factory.py +178 -0
  278. autogen/interop/pydantic_ai/__init__.py +7 -0
  279. autogen/interop/pydantic_ai/pydantic_ai.py +172 -0
  280. autogen/interop/registry.py +70 -0
  281. autogen/io/__init__.py +15 -0
  282. autogen/io/base.py +151 -0
  283. autogen/io/console.py +56 -0
  284. autogen/io/processors/__init__.py +12 -0
  285. autogen/io/processors/base.py +21 -0
  286. autogen/io/processors/console_event_processor.py +61 -0
  287. autogen/io/run_response.py +294 -0
  288. autogen/io/thread_io_stream.py +63 -0
  289. autogen/io/websockets.py +214 -0
  290. autogen/json_utils.py +42 -0
  291. autogen/llm_clients/MIGRATION_TO_V2.md +782 -0
  292. autogen/llm_clients/__init__.py +77 -0
  293. autogen/llm_clients/client_v2.py +122 -0
  294. autogen/llm_clients/models/__init__.py +55 -0
  295. autogen/llm_clients/models/content_blocks.py +389 -0
  296. autogen/llm_clients/models/unified_message.py +145 -0
  297. autogen/llm_clients/models/unified_response.py +83 -0
  298. autogen/llm_clients/openai_completions_client.py +444 -0
  299. autogen/llm_config/__init__.py +11 -0
  300. autogen/llm_config/client.py +59 -0
  301. autogen/llm_config/config.py +461 -0
  302. autogen/llm_config/entry.py +169 -0
  303. autogen/llm_config/types.py +37 -0
  304. autogen/llm_config/utils.py +223 -0
  305. autogen/logger/__init__.py +11 -0
  306. autogen/logger/base_logger.py +129 -0
  307. autogen/logger/file_logger.py +262 -0
  308. autogen/logger/logger_factory.py +42 -0
  309. autogen/logger/logger_utils.py +57 -0
  310. autogen/logger/sqlite_logger.py +524 -0
  311. autogen/math_utils.py +338 -0
  312. autogen/mcp/__init__.py +7 -0
  313. autogen/mcp/__main__.py +78 -0
  314. autogen/mcp/helpers.py +45 -0
  315. autogen/mcp/mcp_client.py +349 -0
  316. autogen/mcp/mcp_proxy/__init__.py +19 -0
  317. autogen/mcp/mcp_proxy/fastapi_code_generator_helpers.py +62 -0
  318. autogen/mcp/mcp_proxy/mcp_proxy.py +577 -0
  319. autogen/mcp/mcp_proxy/operation_grouping.py +166 -0
  320. autogen/mcp/mcp_proxy/operation_renaming.py +110 -0
  321. autogen/mcp/mcp_proxy/patch_fastapi_code_generator.py +98 -0
  322. autogen/mcp/mcp_proxy/security.py +399 -0
  323. autogen/mcp/mcp_proxy/security_schema_visitor.py +37 -0
  324. autogen/messages/__init__.py +7 -0
  325. autogen/messages/agent_messages.py +946 -0
  326. autogen/messages/base_message.py +108 -0
  327. autogen/messages/client_messages.py +172 -0
  328. autogen/messages/print_message.py +48 -0
  329. autogen/oai/__init__.py +61 -0
  330. autogen/oai/anthropic.py +1516 -0
  331. autogen/oai/bedrock.py +800 -0
  332. autogen/oai/cerebras.py +302 -0
  333. autogen/oai/client.py +1658 -0
  334. autogen/oai/client_utils.py +196 -0
  335. autogen/oai/cohere.py +494 -0
  336. autogen/oai/gemini.py +1045 -0
  337. autogen/oai/gemini_types.py +156 -0
  338. autogen/oai/groq.py +319 -0
  339. autogen/oai/mistral.py +311 -0
  340. autogen/oai/oai_models/__init__.py +23 -0
  341. autogen/oai/oai_models/_models.py +16 -0
  342. autogen/oai/oai_models/chat_completion.py +86 -0
  343. autogen/oai/oai_models/chat_completion_audio.py +32 -0
  344. autogen/oai/oai_models/chat_completion_message.py +97 -0
  345. autogen/oai/oai_models/chat_completion_message_tool_call.py +60 -0
  346. autogen/oai/oai_models/chat_completion_token_logprob.py +62 -0
  347. autogen/oai/oai_models/completion_usage.py +59 -0
  348. autogen/oai/ollama.py +657 -0
  349. autogen/oai/openai_responses.py +451 -0
  350. autogen/oai/openai_utils.py +897 -0
  351. autogen/oai/together.py +387 -0
  352. autogen/remote/__init__.py +18 -0
  353. autogen/remote/agent.py +199 -0
  354. autogen/remote/agent_service.py +197 -0
  355. autogen/remote/errors.py +17 -0
  356. autogen/remote/httpx_client_factory.py +131 -0
  357. autogen/remote/protocol.py +37 -0
  358. autogen/remote/retry.py +102 -0
  359. autogen/remote/runtime.py +96 -0
  360. autogen/retrieve_utils.py +490 -0
  361. autogen/runtime_logging.py +161 -0
  362. autogen/testing/__init__.py +12 -0
  363. autogen/testing/messages.py +45 -0
  364. autogen/testing/test_agent.py +111 -0
  365. autogen/token_count_utils.py +280 -0
  366. autogen/tools/__init__.py +20 -0
  367. autogen/tools/contrib/__init__.py +9 -0
  368. autogen/tools/contrib/time/__init__.py +7 -0
  369. autogen/tools/contrib/time/time.py +40 -0
  370. autogen/tools/dependency_injection.py +249 -0
  371. autogen/tools/experimental/__init__.py +54 -0
  372. autogen/tools/experimental/browser_use/__init__.py +7 -0
  373. autogen/tools/experimental/browser_use/browser_use.py +154 -0
  374. autogen/tools/experimental/code_execution/__init__.py +7 -0
  375. autogen/tools/experimental/code_execution/python_code_execution.py +86 -0
  376. autogen/tools/experimental/crawl4ai/__init__.py +7 -0
  377. autogen/tools/experimental/crawl4ai/crawl4ai.py +150 -0
  378. autogen/tools/experimental/deep_research/__init__.py +7 -0
  379. autogen/tools/experimental/deep_research/deep_research.py +329 -0
  380. autogen/tools/experimental/duckduckgo/__init__.py +7 -0
  381. autogen/tools/experimental/duckduckgo/duckduckgo_search.py +103 -0
  382. autogen/tools/experimental/firecrawl/__init__.py +7 -0
  383. autogen/tools/experimental/firecrawl/firecrawl_tool.py +836 -0
  384. autogen/tools/experimental/google/__init__.py +14 -0
  385. autogen/tools/experimental/google/authentication/__init__.py +11 -0
  386. autogen/tools/experimental/google/authentication/credentials_hosted_provider.py +43 -0
  387. autogen/tools/experimental/google/authentication/credentials_local_provider.py +91 -0
  388. autogen/tools/experimental/google/authentication/credentials_provider.py +35 -0
  389. autogen/tools/experimental/google/drive/__init__.py +9 -0
  390. autogen/tools/experimental/google/drive/drive_functions.py +124 -0
  391. autogen/tools/experimental/google/drive/toolkit.py +88 -0
  392. autogen/tools/experimental/google/model.py +17 -0
  393. autogen/tools/experimental/google/toolkit_protocol.py +19 -0
  394. autogen/tools/experimental/google_search/__init__.py +8 -0
  395. autogen/tools/experimental/google_search/google_search.py +93 -0
  396. autogen/tools/experimental/google_search/youtube_search.py +181 -0
  397. autogen/tools/experimental/messageplatform/__init__.py +17 -0
  398. autogen/tools/experimental/messageplatform/discord/__init__.py +7 -0
  399. autogen/tools/experimental/messageplatform/discord/discord.py +284 -0
  400. autogen/tools/experimental/messageplatform/slack/__init__.py +7 -0
  401. autogen/tools/experimental/messageplatform/slack/slack.py +385 -0
  402. autogen/tools/experimental/messageplatform/telegram/__init__.py +7 -0
  403. autogen/tools/experimental/messageplatform/telegram/telegram.py +271 -0
  404. autogen/tools/experimental/perplexity/__init__.py +7 -0
  405. autogen/tools/experimental/perplexity/perplexity_search.py +249 -0
  406. autogen/tools/experimental/reliable/__init__.py +10 -0
  407. autogen/tools/experimental/reliable/reliable.py +1311 -0
  408. autogen/tools/experimental/searxng/__init__.py +7 -0
  409. autogen/tools/experimental/searxng/searxng_search.py +142 -0
  410. autogen/tools/experimental/tavily/__init__.py +7 -0
  411. autogen/tools/experimental/tavily/tavily_search.py +176 -0
  412. autogen/tools/experimental/web_search_preview/__init__.py +7 -0
  413. autogen/tools/experimental/web_search_preview/web_search_preview.py +120 -0
  414. autogen/tools/experimental/wikipedia/__init__.py +7 -0
  415. autogen/tools/experimental/wikipedia/wikipedia.py +284 -0
  416. autogen/tools/function_utils.py +412 -0
  417. autogen/tools/tool.py +188 -0
  418. autogen/tools/toolkit.py +86 -0
  419. autogen/types.py +29 -0
  420. autogen/version.py +7 -0
  421. templates/client_template/main.jinja2 +72 -0
  422. templates/config_template/config.jinja2 +7 -0
  423. templates/main.jinja2 +61 -0
@@ -0,0 +1,365 @@
1
+ # Copyright (c) 2023 - 2025, AG2ai, Inc., AG2ai open-source projects maintainers and core contributors
2
+ #
3
+ # SPDX-License-Identifier: Apache-2.0
4
+
5
+ import logging
6
+ import os
7
+ import shutil
8
+ import subprocess
9
+ import tempfile
10
+ import uuid
11
+ from typing import Any
12
+
13
+ from anyio import to_thread
14
+
15
+ from .python_environment import PythonEnvironment
16
+
17
+ __all__ = ["DockerPythonEnvironment"]
18
+
19
+
20
+ class DockerPythonEnvironment(PythonEnvironment):
21
+ """A Python environment using Docker containers for isolated execution."""
22
+
23
+ def __init__(
24
+ self,
25
+ image: str = "python:3.11-slim",
26
+ container_name_prefix: str = "ag2_docker_env_",
27
+ volumes: dict[str, str] | None = None,
28
+ environment: dict[str, str] | None = None,
29
+ network: str | None = None,
30
+ pip_packages: list[str] | None = None,
31
+ requirements_file: str | None = None,
32
+ dockerfile: str | None = None,
33
+ build_args: dict[str, str] | None = None,
34
+ cleanup_container: bool = True,
35
+ keep_container_running: bool = False,
36
+ container_startup_timeout: int = 30,
37
+ ):
38
+ """Initialize a Docker Python environment.
39
+
40
+ Args:
41
+ image: Docker image to use (ignored if dockerfile is provided)
42
+ container_name_prefix: Prefix for container names
43
+ volumes: Dictionary mapping host paths to container paths for mounting
44
+ environment: Dictionary of environment variables to set in the container
45
+ network: Docker network to attach the container to
46
+ pip_packages: List of pip packages to install in the container
47
+ requirements_file: Path to requirements.txt file to install in the container
48
+ dockerfile: Optional path to a Dockerfile to build and use instead of pulling an image
49
+ build_args: Optional build arguments for the Dockerfile
50
+ cleanup_container: Whether to remove the container after use
51
+ keep_container_running: Whether to keep the container running after execution
52
+ container_startup_timeout: Timeout in seconds for container startup
53
+ """
54
+ self.image = image
55
+ self.container_name_prefix = container_name_prefix
56
+ self.volumes = volumes or {}
57
+ self.environment = environment or {}
58
+ self.network = network
59
+ self.pip_packages = pip_packages or []
60
+ self.requirements_file = requirements_file
61
+ self.dockerfile = dockerfile
62
+ self.build_args = build_args or {}
63
+ self.cleanup_container = cleanup_container
64
+ self.keep_container_running = keep_container_running
65
+ self.container_startup_timeout = container_startup_timeout
66
+
67
+ # Internal state
68
+ self._container_id = None
69
+ self._container_name = None
70
+ self._custom_image_name = None
71
+ self._temp_dir = None
72
+
73
+ super().__init__()
74
+
75
+ def _setup_environment(self) -> None:
76
+ """Set up the Docker environment."""
77
+ # Verify Docker is installed and accessible
78
+ try:
79
+ result = subprocess.run(["docker", "--version"], capture_output=True, text=True, check=True)
80
+ logging.info(f"Docker version: {result.stdout.strip()}")
81
+ except (subprocess.SubprocessError, FileNotFoundError) as e:
82
+ raise RuntimeError(
83
+ "Docker not found or not accessible. Please ensure Docker is installed and running."
84
+ ) from e
85
+
86
+ # Create a temporary directory for file operations
87
+ self._temp_dir = tempfile.mkdtemp(prefix="ag2_docker_")
88
+
89
+ # Generate a unique container name
90
+ self._container_name = f"{self.container_name_prefix}{uuid.uuid4().hex[:8]}"
91
+
92
+ # Build custom image if Dockerfile is provided
93
+ if self.dockerfile:
94
+ self._build_custom_image()
95
+ else:
96
+ # Pull the specified image
97
+ try:
98
+ subprocess.run(
99
+ ["docker", "pull", self.image],
100
+ check=True,
101
+ capture_output=True,
102
+ text=True,
103
+ )
104
+ logging.info(f"Pulled Docker image: {self.image}")
105
+ except subprocess.CalledProcessError as e:
106
+ raise RuntimeError(f"Failed to pull Docker image: {e.stderr}") from e
107
+
108
+ # Start the container
109
+ self._start_container()
110
+
111
+ def _build_custom_image(self) -> None:
112
+ """Build a custom Docker image from the provided Dockerfile."""
113
+ if not os.path.exists(self.dockerfile):
114
+ raise RuntimeError(f"Dockerfile not found at: {self.dockerfile}")
115
+
116
+ # Create a unique image name
117
+ self._custom_image_name = f"ag2-custom-python-{uuid.uuid4().hex[:8]}"
118
+
119
+ # Build command
120
+ build_cmd = ["docker", "build", "-t", self._custom_image_name]
121
+
122
+ # Add build args
123
+ for arg_name, arg_value in self.build_args.items():
124
+ build_cmd.extend(["--build-arg", f"{arg_name}={arg_value}"])
125
+
126
+ # Add Dockerfile path
127
+ build_cmd.extend(["-f", self.dockerfile, os.path.dirname(self.dockerfile)])
128
+
129
+ try:
130
+ logging.info(f"Building custom Docker image: {self._custom_image_name}")
131
+ _ = subprocess.run(
132
+ build_cmd,
133
+ check=True,
134
+ capture_output=True,
135
+ text=True,
136
+ )
137
+ logging.info(f"Built custom Docker image: {self._custom_image_name}")
138
+ except subprocess.CalledProcessError as e:
139
+ raise RuntimeError(f"Failed to build Docker image: {e.stderr}") from e
140
+
141
+ # Use the custom image
142
+ self.image = self._custom_image_name
143
+
144
+ def _start_container(self) -> None:
145
+ """Start the Docker container."""
146
+ # Basic container run command
147
+ run_cmd = ["docker", "run", "--name", self._container_name]
148
+
149
+ # Add detached mode flag to run container in background
150
+ run_cmd.append("-d")
151
+
152
+ # Add network if specified
153
+ if self.network:
154
+ run_cmd.extend(["--network", self.network])
155
+
156
+ # Add environment variables
157
+ for env_name, env_value in self.environment.items():
158
+ run_cmd.extend(["-e", f"{env_name}={env_value}"])
159
+
160
+ # Add volume mounts including temp directory
161
+ work_dir_mount = f"{self._temp_dir}:/workspace"
162
+ run_cmd.extend(["-v", work_dir_mount])
163
+
164
+ for host_path, container_path in self.volumes.items():
165
+ run_cmd.extend(["-v", f"{host_path}:{container_path}"])
166
+
167
+ # Set workspace as working directory
168
+ run_cmd.extend(["-w", "/workspace"])
169
+
170
+ # Add tty to keep container running
171
+ run_cmd.append("-t")
172
+
173
+ # Add image name
174
+ run_cmd.append(self.image)
175
+
176
+ # Initial command to keep container running
177
+ run_cmd.extend(["tail", "-f", "/dev/null"])
178
+
179
+ try:
180
+ # Start the container
181
+ logging.info(f"Starting Docker container: {self._container_name}")
182
+ result = subprocess.run(
183
+ run_cmd,
184
+ check=True,
185
+ capture_output=True,
186
+ text=True,
187
+ )
188
+
189
+ # Get container ID
190
+ self._container_id = result.stdout.strip()
191
+ logging.info(f"Started Docker container: {self._container_name} ({self._container_id})")
192
+
193
+ # Install pip packages if specified
194
+ if self.pip_packages or self.requirements_file:
195
+ self._install_packages()
196
+
197
+ except subprocess.CalledProcessError as e:
198
+ raise RuntimeError(f"Failed to start Docker container: {e.stderr}") from e
199
+
200
+ def _install_packages(self) -> None:
201
+ """Install Python packages in the running container."""
202
+ # Install pip packages
203
+ if self.pip_packages:
204
+ packages_str = " ".join(self.pip_packages)
205
+ try:
206
+ logging.info(f"Installing pip packages: {packages_str}")
207
+ _ = subprocess.run(
208
+ ["docker", "exec", self._container_name, "pip", "install", "--no-cache-dir"] + self.pip_packages,
209
+ check=True,
210
+ capture_output=True,
211
+ text=True,
212
+ )
213
+ logging.info("Successfully installed pip packages")
214
+ except subprocess.CalledProcessError as e:
215
+ logging.warning(f"Failed to install pip packages: {e.stderr}")
216
+
217
+ # Install from requirements file
218
+ if self.requirements_file:
219
+ if os.path.exists(self.requirements_file):
220
+ # Copy requirements file to temp directory
221
+ req_filename = os.path.basename(self.requirements_file)
222
+ temp_req_path = os.path.join(self._temp_dir, req_filename)
223
+ shutil.copy(self.requirements_file, temp_req_path)
224
+
225
+ try:
226
+ logging.info(f"Installing requirements from: {req_filename}")
227
+ _ = subprocess.run(
228
+ [
229
+ "docker",
230
+ "exec",
231
+ self._container_name,
232
+ "pip",
233
+ "install",
234
+ "--no-cache-dir",
235
+ "-r",
236
+ f"/workspace/{req_filename}",
237
+ ],
238
+ check=True,
239
+ capture_output=True,
240
+ text=True,
241
+ )
242
+ logging.info("Successfully installed requirements")
243
+ except subprocess.CalledProcessError as e:
244
+ logging.warning(f"Failed to install requirements: {e.stderr}")
245
+ else:
246
+ logging.warning(f"Requirements file not found: {self.requirements_file}")
247
+
248
+ def _cleanup_environment(self) -> None:
249
+ """Clean up the Docker environment."""
250
+ if self._container_id:
251
+ # Stop the container if it's running and we want to clean it up
252
+ if not self.keep_container_running:
253
+ try:
254
+ logging.info(f"Stopping Docker container: {self._container_name}")
255
+ subprocess.run(
256
+ ["docker", "stop", self._container_name],
257
+ check=True,
258
+ capture_output=True,
259
+ text=True,
260
+ )
261
+ except subprocess.CalledProcessError:
262
+ logging.warning(f"Failed to stop Docker container: {self._container_name}")
263
+
264
+ # Remove the container if cleanup is enabled
265
+ if self.cleanup_container and not self.keep_container_running:
266
+ try:
267
+ logging.info(f"Removing Docker container: {self._container_name}")
268
+ subprocess.run(
269
+ ["docker", "rm", "-f", self._container_name],
270
+ check=True,
271
+ capture_output=True,
272
+ text=True,
273
+ )
274
+ except subprocess.CalledProcessError:
275
+ logging.warning(f"Failed to remove Docker container: {self._container_name}")
276
+
277
+ # Remove the custom image if it was created
278
+ if self._custom_image_name and self.cleanup_container:
279
+ try:
280
+ logging.info(f"Removing custom Docker image: {self._custom_image_name}")
281
+ subprocess.run(
282
+ ["docker", "rmi", self._custom_image_name],
283
+ check=True,
284
+ capture_output=True,
285
+ text=True,
286
+ )
287
+ except subprocess.CalledProcessError:
288
+ logging.warning(f"Failed to remove custom Docker image: {self._custom_image_name}")
289
+
290
+ # Clean up the temporary directory
291
+ if self._temp_dir and os.path.exists(self._temp_dir):
292
+ try:
293
+ shutil.rmtree(self._temp_dir)
294
+ except Exception as e:
295
+ logging.warning(f"Failed to remove temporary directory: {e}")
296
+
297
+ def get_executable(self) -> str:
298
+ """Get the path to the Python executable in the Docker container."""
299
+ # This is a virtual path in the container
300
+ return "python"
301
+
302
+ async def execute_code(self, code: str, script_path: str, timeout: int = 30) -> dict[str, Any]:
303
+ """Execute code in the Docker container."""
304
+ # Ensure the container is running
305
+ if not self._container_id:
306
+ return {"success": False, "error": "Docker container not started"}
307
+
308
+ try:
309
+ # Calculate the relative path within the temp directory
310
+ if os.path.isabs(script_path):
311
+ rel_path = os.path.basename(script_path)
312
+ host_script_path = os.path.join(self._temp_dir, rel_path)
313
+ else:
314
+ rel_path = script_path
315
+ host_script_path = os.path.join(self._temp_dir, rel_path)
316
+
317
+ # Ensure the directory for the script exists
318
+ script_dir = os.path.dirname(host_script_path)
319
+ if script_dir:
320
+ os.makedirs(script_dir, exist_ok=True)
321
+
322
+ # Write the code to the script file on the host
323
+ await to_thread.run_sync(self._write_to_file, host_script_path, code)
324
+
325
+ # Path to the script in the container
326
+ container_script_path = f"/workspace/{rel_path}"
327
+
328
+ # Execute the script in the container
329
+ exec_cmd = ["docker", "exec", self._container_name, "python", container_script_path]
330
+
331
+ # Run the command with a timeout
332
+ result = await to_thread.run_sync(self._run_subprocess_with_timeout, exec_cmd, timeout)
333
+
334
+ return {
335
+ "success": result[0],
336
+ "stdout": result[1],
337
+ "stderr": result[2],
338
+ "returncode": result[3] if result[0] else 1,
339
+ }
340
+
341
+ except Exception as e:
342
+ return {"success": False, "error": f"Execution error: {str(e)}"}
343
+
344
+ def _run_subprocess_with_timeout(self, cmd: list[str], timeout: int) -> tuple[bool, str, str, int]:
345
+ """Run a subprocess with timeout and return status, stdout, stderr, and return code.
346
+
347
+ Args:
348
+ cmd: Command to run as a list of strings
349
+ timeout: Maximum execution time in seconds
350
+
351
+ Returns:
352
+ Tuple of (success, stdout, stderr, return_code)
353
+ """
354
+ try:
355
+ result = subprocess.run(
356
+ cmd,
357
+ capture_output=True,
358
+ text=True,
359
+ timeout=timeout,
360
+ )
361
+ return (result.returncode == 0, result.stdout, result.stderr, result.returncode)
362
+ except subprocess.TimeoutExpired:
363
+ return (False, "", f"Execution timed out after {timeout} seconds", -1)
364
+ except Exception as e:
365
+ return (False, "", str(e), -1)
@@ -0,0 +1,125 @@
1
+ # Copyright (c) 2023 - 2025, AG2ai, Inc., AG2ai open-source projects maintainers and core contributors
2
+ #
3
+ # SPDX-License-Identifier: Apache-2.0
4
+
5
+ import subprocess
6
+ from abc import ABC, abstractmethod
7
+ from contextvars import ContextVar
8
+ from typing import Any, Optional
9
+
10
+ __all__ = ["PythonEnvironment"]
11
+
12
+
13
+ class PythonEnvironment(ABC):
14
+ """Python execution environments base class"""
15
+
16
+ # Shared context variable for tracking the current environment
17
+ _current_python_environment: ContextVar["PythonEnvironment"] = ContextVar("_current_python_environment")
18
+
19
+ def __init__(self):
20
+ """Initialize the Python environment."""
21
+ self._token = None
22
+
23
+ # Set up the environment
24
+ self._setup_environment()
25
+
26
+ def __enter__(self):
27
+ """Enter the environment context.
28
+ Sets this environment as the current one.
29
+ """
30
+ # Set this as the current Python environment in the context
31
+ self._token = PythonEnvironment._current_python_environment.set(self)
32
+
33
+ return self
34
+
35
+ def __exit__(self, exc_type, exc_val, exc_tb):
36
+ """Exit the environment context.
37
+ Resets the current environment and performs cleanup.
38
+ """
39
+ # Reset the context variable if this was the active environment
40
+ if self._token is not None:
41
+ PythonEnvironment._current_python_environment.reset(self._token)
42
+ self._token = None
43
+
44
+ # Clean up resources
45
+ self._cleanup_environment()
46
+
47
+ @abstractmethod
48
+ def _setup_environment(self) -> None:
49
+ """Set up the Python environment. Called by __enter__."""
50
+ pass
51
+
52
+ @abstractmethod
53
+ def _cleanup_environment(self) -> None:
54
+ """Clean up the Python environment. Called by __exit__."""
55
+ pass
56
+
57
+ @abstractmethod
58
+ def get_executable(self) -> str:
59
+ """Get the path to the Python executable in this environment.
60
+
61
+ Returns:
62
+ The full path to the Python executable.
63
+ """
64
+ pass
65
+
66
+ @abstractmethod
67
+ async def execute_code(self, code: str, script_path: str, timeout: int = 30) -> dict[str, Any]:
68
+ """Execute the given code in this environment.
69
+
70
+ Args:
71
+ code: The Python code to execute.
72
+ script_path: Path where the code should be saved before execution.
73
+ timeout: Maximum execution time in seconds.
74
+
75
+ Returns:
76
+ dict with execution results including stdout, stderr, and success status.
77
+ """
78
+ pass
79
+
80
+ # Utility method for subclasses to wrap (for async support)
81
+ def _write_to_file(self, script_path: str, content: str) -> None:
82
+ """Write content to a file (blocking operation).
83
+
84
+ This is a helper method for use with asyncify in async contexts.
85
+
86
+ Args:
87
+ script_path: Path to the file to write.
88
+ content: Content to write to the file.
89
+ """
90
+ with open(script_path, "w") as f:
91
+ f.write(content)
92
+
93
+ # Utility method for subclasses to wrap (for async support)
94
+ def _run_subprocess(self, cmd: list[str], timeout: int) -> subprocess.CompletedProcess:
95
+ """Run a subprocess (blocking operation).
96
+
97
+ This is a helper method for use with asyncify in async contexts.
98
+
99
+ Args:
100
+ cmd: Command to run as a list of strings.
101
+ timeout: Maximum execution time in seconds.
102
+
103
+ Returns:
104
+ CompletedProcess instance with results of the subprocess.
105
+ """
106
+ return subprocess.run(cmd, capture_output=True, text=True, timeout=timeout)
107
+
108
+ @classmethod
109
+ def get_current_python_environment(
110
+ cls, python_environment: Optional["PythonEnvironment"] = None
111
+ ) -> Optional["PythonEnvironment"]:
112
+ """Get the current Python environment or the specified one if provided.
113
+
114
+ Args:
115
+ python_environment: Optional environment to return if specified.
116
+
117
+ Returns:
118
+ The current Python environment or None if none is active.
119
+ """
120
+ if python_environment is not None:
121
+ return python_environment
122
+ try:
123
+ return cls._current_python_environment.get()
124
+ except LookupError:
125
+ return None
@@ -0,0 +1,85 @@
1
+ # Copyright (c) 2023 - 2025, AG2ai, Inc., AG2ai open-source projects maintainers and core contributors
2
+ #
3
+ # SPDX-License-Identifier: Apache-2.0
4
+
5
+ import logging
6
+ import os
7
+ import subprocess
8
+ import sys
9
+ from typing import Any
10
+
11
+ from anyio import to_thread
12
+
13
+ from .python_environment import PythonEnvironment
14
+
15
+ __all__ = ["SystemPythonEnvironment"]
16
+
17
+
18
+ class SystemPythonEnvironment(PythonEnvironment):
19
+ """A Python environment using the system's Python installation."""
20
+
21
+ def __init__(
22
+ self,
23
+ executable: str | None = None,
24
+ ):
25
+ """Initialize a system Python environment.
26
+
27
+ Args:
28
+ executable: Optional path to a specific Python executable. If None, uses the current Python executable.
29
+ """
30
+ self._executable = executable or sys.executable
31
+ super().__init__()
32
+
33
+ def _setup_environment(self) -> None:
34
+ """Set up the system Python environment."""
35
+ # Verify the Python executable exists
36
+ if not os.path.exists(self._executable):
37
+ raise RuntimeError(f"Python executable not found at: {self._executable}")
38
+
39
+ logging.info(f"Using system Python at: {self._executable}")
40
+
41
+ def _cleanup_environment(self) -> None:
42
+ """Clean up the system Python environment."""
43
+ # No cleanup needed for system Python
44
+ pass
45
+
46
+ def get_executable(self) -> str:
47
+ """Get the path to the Python executable."""
48
+ return self._executable
49
+
50
+ async def execute_code(self, code: str, script_path: str, timeout: int = 30) -> dict[str, Any]:
51
+ """Execute code using the system Python."""
52
+ try:
53
+ # Get the Python executable
54
+ python_executable = self.get_executable()
55
+
56
+ # Verify the executable exists
57
+ if not os.path.exists(python_executable):
58
+ return {"success": False, "error": f"Python executable not found at {python_executable}"}
59
+
60
+ # Ensure the directory for the script exists
61
+ script_dir = os.path.dirname(script_path)
62
+ if script_dir:
63
+ os.makedirs(script_dir, exist_ok=True)
64
+
65
+ # Write the code to the script file using anyio.to_thread.run_sync (from base class)
66
+ await to_thread.run_sync(self._write_to_file, script_path, code)
67
+
68
+ logging.info(f"Wrote code to {script_path}")
69
+
70
+ try:
71
+ # Execute directly with subprocess using anyio.to_thread.run_sync for better reliability
72
+ result = await to_thread.run_sync(self._run_subprocess, [python_executable, script_path], timeout)
73
+
74
+ # Main execution result
75
+ return {
76
+ "success": result.returncode == 0,
77
+ "stdout": result.stdout,
78
+ "stderr": result.stderr,
79
+ "returncode": result.returncode,
80
+ }
81
+ except subprocess.TimeoutExpired:
82
+ return {"success": False, "error": f"Execution timed out after {timeout} seconds"}
83
+
84
+ except Exception as e:
85
+ return {"success": False, "error": f"Execution error: {str(e)}"}