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,140 @@
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
+ from __future__ import annotations
6
+
7
+ from collections.abc import Callable
8
+ from typing import Any, Literal
9
+ from uuid import UUID
10
+
11
+ from termcolor import colored
12
+
13
+ from ....events.base_event import BaseEvent, wrap_event
14
+
15
+ # Type for termcolor colors
16
+ TermColor = Literal[
17
+ "black",
18
+ "grey",
19
+ "red",
20
+ "green",
21
+ "yellow",
22
+ "blue",
23
+ "magenta",
24
+ "cyan",
25
+ "light_grey",
26
+ "dark_grey",
27
+ "light_red",
28
+ "light_green",
29
+ "light_yellow",
30
+ "light_blue",
31
+ "light_magenta",
32
+ "light_cyan",
33
+ "white",
34
+ ]
35
+
36
+
37
+ @wrap_event
38
+ class SafeguardEvent(BaseEvent):
39
+ """Event for safeguard actions"""
40
+
41
+ event_type: str # e.g., "load", "check", "violation", "action"
42
+ message: str
43
+ source_agent: str | None = None
44
+ target_agent: str | None = None
45
+ guardrail_type: str | None = None
46
+ action: str | None = None
47
+ content_preview: str | None = None
48
+
49
+ def __init__(
50
+ self,
51
+ *,
52
+ uuid: UUID | None = None,
53
+ event_type: str,
54
+ message: str,
55
+ source_agent: str | None = None,
56
+ target_agent: str | None = None,
57
+ guardrail_type: str | None = None,
58
+ action: str | None = None,
59
+ content_preview: str | None = None,
60
+ ):
61
+ super().__init__(
62
+ uuid=uuid,
63
+ event_type=event_type,
64
+ message=message,
65
+ source_agent=source_agent,
66
+ target_agent=target_agent,
67
+ guardrail_type=guardrail_type,
68
+ action=action,
69
+ content_preview=content_preview,
70
+ )
71
+
72
+ def print(self, f: Callable[..., Any] | None = None) -> None:
73
+ f = f or print
74
+
75
+ # Choose color based on event type
76
+ color: TermColor = "green"
77
+ if self.event_type == "load":
78
+ color = "green"
79
+ elif self.event_type == "check":
80
+ color = "cyan"
81
+ elif self.event_type == "violation":
82
+ color = "red"
83
+ elif self.event_type == "action":
84
+ color = "yellow"
85
+
86
+ # Choose emoji based on event type
87
+ emoji = ""
88
+ if self.event_type == "load":
89
+ emoji = "✅"
90
+ elif self.event_type == "check":
91
+ emoji = "🔍"
92
+ elif self.event_type == "violation":
93
+ emoji = "🛡️"
94
+ elif self.event_type == "action":
95
+ if self.action == "block":
96
+ emoji = "🚨"
97
+ elif self.action == "mask":
98
+ emoji = "🎭"
99
+ elif self.action == "warning":
100
+ emoji = "⚠️"
101
+ else:
102
+ emoji = "⚙️"
103
+
104
+ # Create header based on event type (skip for load events)
105
+ if self.event_type == "check":
106
+ header = f"***** Safeguard Check: {self.message} *****"
107
+ f(colored(header, color), flush=True)
108
+ elif self.event_type == "violation":
109
+ header = "***** Safeguard Violation: DETECTED *****"
110
+ f(colored(header, color), flush=True)
111
+ elif self.event_type == "action":
112
+ header = f"***** Safeguard Enforcement Action: {self.action.upper() if self.action else 'APPLIED'} *****"
113
+ f(colored(header, color), flush=True)
114
+
115
+ # Format the output
116
+ output_parts = [f"{emoji} {self.message}" if emoji else self.message]
117
+
118
+ if self.source_agent and self.target_agent:
119
+ output_parts.append(f" • From: {self.source_agent}")
120
+ output_parts.append(f" • To: {self.target_agent}")
121
+ elif self.source_agent:
122
+ output_parts.append(f" • Agent: {self.source_agent}")
123
+
124
+ if self.guardrail_type:
125
+ output_parts.append(f" • Guardrail: {self.guardrail_type}")
126
+
127
+ if self.action:
128
+ output_parts.append(f" • Action: {self.action}")
129
+
130
+ if self.content_preview:
131
+ # Replace actual newlines with \n for display
132
+ content_display = self.content_preview.replace("\n", "\\n").replace("\r", "\\r")
133
+ output_parts.append(f" • Content: {content_display}")
134
+
135
+ f(colored("\n".join(output_parts), color), flush=True)
136
+
137
+ # Print footer with matching length (skip for load events)
138
+ if self.event_type in ["check", "violation", "action"]:
139
+ footer = "*" * len(header)
140
+ f(colored(footer, color), flush=True)
@@ -0,0 +1,435 @@
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
+ from __future__ import annotations
6
+
7
+ import re
8
+ from typing import Any
9
+
10
+
11
+ class SafeguardValidator:
12
+ """Validator for safeguard policy format and content."""
13
+
14
+ def __init__(self, policy: dict[str, Any]):
15
+ """Initialize validator with policy.
16
+
17
+ Args:
18
+ policy: The safeguard policy to validate
19
+ """
20
+ self.policy = policy
21
+
22
+ def validate_policy_structure(self) -> None:
23
+ """Validate policy format and syntax only."""
24
+ if not isinstance(self.policy, dict):
25
+ raise ValueError("Policy must be a dictionary")
26
+
27
+ # Validate inter-agent safeguards
28
+ if "inter_agent_safeguards" in self.policy:
29
+ self._validate_inter_agent_safeguards()
30
+
31
+ # Validate environment safeguards
32
+ if "agent_environment_safeguards" in self.policy:
33
+ self._validate_environment_safeguards()
34
+
35
+ def validate_policy_complete(self, agent_names: list[str], agent_tool_mapping: dict[str, list[str]]) -> None:
36
+ """Validate agent and tool names (assumes policy structure already validated).
37
+
38
+ Args:
39
+ agent_names: List of available agent names for validation
40
+ agent_tool_mapping: Mapping of agent names to their tool names
41
+ """
42
+ # Validate agent names
43
+ self.validate_agent_names(agent_names)
44
+
45
+ # Validate tool names if any tools exist
46
+ if any(tools for tools in agent_tool_mapping.values()):
47
+ self.validate_tool_names(agent_tool_mapping, agent_names)
48
+
49
+ def _validate_inter_agent_safeguards(self) -> None:
50
+ """Validate inter-agent safeguards section."""
51
+ inter_agent = self.policy["inter_agent_safeguards"]
52
+ if not isinstance(inter_agent, dict):
53
+ raise ValueError("inter_agent_safeguards must be a dictionary")
54
+
55
+ # Validate agent_transitions
56
+ if "agent_transitions" in inter_agent:
57
+ if not isinstance(inter_agent["agent_transitions"], list):
58
+ raise ValueError("agent_transitions must be a list")
59
+
60
+ for i, rule in enumerate(inter_agent["agent_transitions"]):
61
+ if not isinstance(rule, dict):
62
+ raise ValueError(f"agent_transitions[{i}] must be a dictionary")
63
+
64
+ # Required fields
65
+ required_fields = ["message_source", "message_destination"]
66
+ for field in required_fields:
67
+ if field not in rule:
68
+ raise ValueError(f"agent_transitions[{i}] missing required field: {field}")
69
+
70
+ # Check method validation - no default, must be explicit
71
+ if "check_method" not in rule:
72
+ raise ValueError(f"agent_transitions[{i}] missing required field: check_method")
73
+ check_method = rule["check_method"]
74
+ if check_method not in ["llm", "regex"]:
75
+ raise ValueError(
76
+ f"agent_transitions[{i}] invalid check_method: {check_method}. Must be 'llm' or 'regex'"
77
+ )
78
+
79
+ # LLM-specific validation
80
+ if check_method == "llm":
81
+ if "custom_prompt" not in rule and "disallow_item" not in rule:
82
+ raise ValueError(
83
+ f"agent_transitions[{i}] with check_method 'llm' must have either 'custom_prompt' or 'disallow_item'"
84
+ )
85
+ if "disallow_item" in rule and not isinstance(rule["disallow_item"], list):
86
+ raise ValueError(f"agent_transitions[{i}] disallow_item must be a list")
87
+
88
+ # Regex-specific validation
89
+ if check_method == "regex":
90
+ if "pattern" not in rule:
91
+ raise ValueError(f"agent_transitions[{i}] with check_method 'regex' must have 'pattern'")
92
+ if not isinstance(rule["pattern"], str):
93
+ raise ValueError(f"agent_transitions[{i}] pattern must be a string")
94
+
95
+ # Test regex pattern validity
96
+ try:
97
+ re.compile(rule["pattern"])
98
+ except re.error as e:
99
+ raise ValueError(f"agent_transitions[{i}] invalid regex pattern '{rule['pattern']}': {e}")
100
+
101
+ # Validate action - no default, must be explicit
102
+ if "violation_response" not in rule and "action" not in rule:
103
+ raise ValueError(f"agent_transitions[{i}] missing required field: violation_response or action")
104
+ action = rule.get("violation_response", rule.get("action"))
105
+ if action not in ["block", "mask", "warning"]:
106
+ raise ValueError(
107
+ f"agent_transitions[{i}] invalid action: {action}. Must be 'block', 'mask', or 'warning'"
108
+ )
109
+
110
+ # Validate groupchat_message_check
111
+ if "groupchat_message_check" in inter_agent:
112
+ rule = inter_agent["groupchat_message_check"]
113
+ if not isinstance(rule, dict):
114
+ raise ValueError("groupchat_message_check must be a dictionary")
115
+ if "disallow_item" in rule and not isinstance(rule["disallow_item"], list):
116
+ raise ValueError("groupchat_message_check disallow_item must be a list")
117
+
118
+ def _validate_environment_safeguards(self) -> None:
119
+ """Validate environment safeguards section."""
120
+ env_rules = self.policy["agent_environment_safeguards"]
121
+ if not isinstance(env_rules, dict):
122
+ raise ValueError("agent_environment_safeguards must be a dictionary")
123
+
124
+ # Validate tool_interaction rules
125
+ if "tool_interaction" in env_rules:
126
+ if not isinstance(env_rules["tool_interaction"], list):
127
+ raise ValueError("tool_interaction must be a list")
128
+
129
+ for i, rule in enumerate(env_rules["tool_interaction"]):
130
+ if not isinstance(rule, dict):
131
+ raise ValueError(f"tool_interaction[{i}] must be a dictionary")
132
+
133
+ # Check method validation - no default, must be explicit
134
+ if "check_method" not in rule:
135
+ raise ValueError(f"tool_interaction[{i}] missing required field: check_method")
136
+ check_method = rule["check_method"]
137
+ if check_method not in ["llm", "regex"]:
138
+ raise ValueError(
139
+ f"tool_interaction[{i}] invalid check_method: {check_method}. Must be 'llm' or 'regex'"
140
+ )
141
+
142
+ # Validate action - no default, must be explicit
143
+ if "violation_response" not in rule and "action" not in rule:
144
+ raise ValueError(f"tool_interaction[{i}] missing required field: violation_response or action")
145
+ action = rule.get("violation_response", rule.get("action"))
146
+ if action not in ["block", "mask", "warning"]:
147
+ raise ValueError(
148
+ f"tool_interaction[{i}] invalid action: {action}. Must be 'block', 'mask', or 'warning'"
149
+ )
150
+
151
+ # All tool_interaction rules must have message_source and message_destination
152
+ if "message_source" not in rule or "message_destination" not in rule:
153
+ raise ValueError(f"tool_interaction[{i}] must have 'message_source' and 'message_destination'")
154
+
155
+ if check_method == "llm":
156
+ # LLM-based checking requires either custom_prompt or disallow_item
157
+ if "custom_prompt" not in rule and "disallow_item" not in rule:
158
+ raise ValueError(
159
+ f"tool_interaction[{i}] with check_method 'llm' must have either 'custom_prompt' or 'disallow_item'"
160
+ )
161
+ if "disallow_item" in rule and not isinstance(rule["disallow_item"], list):
162
+ raise ValueError(f"tool_interaction[{i}] disallow_item must be a list")
163
+
164
+ elif check_method == "regex":
165
+ # Regex-based checking requires pattern
166
+ if "pattern" not in rule:
167
+ raise ValueError(f"tool_interaction[{i}] with check_method 'regex' must have 'pattern'")
168
+ if not isinstance(rule["pattern"], str):
169
+ raise ValueError(f"tool_interaction[{i}] pattern must be a string")
170
+ # Test regex pattern validity
171
+ try:
172
+ re.compile(rule["pattern"])
173
+ except re.error as e:
174
+ raise ValueError(f"tool_interaction[{i}] invalid regex pattern '{rule['pattern']}': {e}")
175
+
176
+ # Validate llm_interaction rules
177
+ if "llm_interaction" in env_rules:
178
+ if not isinstance(env_rules["llm_interaction"], list):
179
+ raise ValueError("llm_interaction must be a list")
180
+
181
+ for i, rule in enumerate(env_rules["llm_interaction"]):
182
+ if not isinstance(rule, dict):
183
+ raise ValueError(f"llm_interaction[{i}] must be a dictionary")
184
+
185
+ # Check method validation - no default, must be explicit
186
+ if "check_method" not in rule:
187
+ raise ValueError(f"llm_interaction[{i}] missing required field: check_method")
188
+ check_method = rule["check_method"]
189
+ if check_method not in ["llm", "regex"]:
190
+ raise ValueError(
191
+ f"llm_interaction[{i}] invalid check_method: {check_method}. Must be 'llm' or 'regex'"
192
+ )
193
+
194
+ # Validate action - no default, must be explicit
195
+ if "action" not in rule:
196
+ raise ValueError(f"llm_interaction[{i}] missing required field: action")
197
+ action = rule["action"]
198
+ if action not in ["block", "mask", "warning"]:
199
+ raise ValueError(
200
+ f"llm_interaction[{i}] invalid action: {action}. Must be 'block', 'mask', or 'warning'"
201
+ )
202
+
203
+ # All llm_interaction rules must have message_source and message_destination
204
+ if "message_source" not in rule or "message_destination" not in rule:
205
+ raise ValueError(f"llm_interaction[{i}] must have 'message_source' and 'message_destination'")
206
+
207
+ if check_method == "llm":
208
+ # LLM-based checking requires either custom_prompt or disallow_item
209
+ if "custom_prompt" not in rule and "disallow_item" not in rule:
210
+ raise ValueError(
211
+ f"llm_interaction[{i}] with check_method 'llm' must have either 'custom_prompt' or 'disallow_item'"
212
+ )
213
+ if "disallow_item" in rule and not isinstance(rule["disallow_item"], list):
214
+ raise ValueError(f"llm_interaction[{i}] disallow_item must be a list")
215
+
216
+ elif check_method == "regex":
217
+ # Regex-based checking requires pattern
218
+ if "pattern" not in rule:
219
+ raise ValueError(f"llm_interaction[{i}] with check_method 'regex' must have 'pattern'")
220
+ if not isinstance(rule["pattern"], str):
221
+ raise ValueError(f"llm_interaction[{i}] pattern must be a string")
222
+ # Test regex pattern validity
223
+ try:
224
+ re.compile(rule["pattern"])
225
+ except re.error as e:
226
+ raise ValueError(f"llm_interaction[{i}] invalid regex pattern '{rule['pattern']}': {e}")
227
+
228
+ # Validate user_interaction rules
229
+ if "user_interaction" in env_rules:
230
+ if not isinstance(env_rules["user_interaction"], list):
231
+ raise ValueError("user_interaction must be a list")
232
+
233
+ for i, rule in enumerate(env_rules["user_interaction"]):
234
+ if not isinstance(rule, dict):
235
+ raise ValueError(f"user_interaction[{i}] must be a dictionary")
236
+
237
+ # Check method validation - no default, must be explicit
238
+ if "check_method" not in rule:
239
+ raise ValueError(f"user_interaction[{i}] missing required field: check_method")
240
+ check_method = rule["check_method"]
241
+ if check_method not in ["llm", "regex"]:
242
+ raise ValueError(
243
+ f"user_interaction[{i}] invalid check_method: {check_method}. Must be 'llm' or 'regex'"
244
+ )
245
+
246
+ # Validate action - no default, must be explicit
247
+ if "action" not in rule:
248
+ raise ValueError(f"user_interaction[{i}] missing required field: action")
249
+ action = rule["action"]
250
+ if action not in ["block", "mask", "warning"]:
251
+ raise ValueError(
252
+ f"user_interaction[{i}] invalid action: {action}. Must be 'block', 'mask', or 'warning'"
253
+ )
254
+
255
+ # All user_interaction rules must have message_source and message_destination
256
+ if "message_source" not in rule or "message_destination" not in rule:
257
+ raise ValueError(f"user_interaction[{i}] must have 'message_source' and 'message_destination'")
258
+
259
+ if check_method == "llm":
260
+ # LLM-based checking requires either custom_prompt or disallow_item
261
+ if "custom_prompt" not in rule and "disallow_item" not in rule:
262
+ raise ValueError(
263
+ f"user_interaction[{i}] with check_method 'llm' must have either 'custom_prompt' or 'disallow_item'"
264
+ )
265
+ if "disallow_item" in rule and not isinstance(rule["disallow_item"], list):
266
+ raise ValueError(f"user_interaction[{i}] disallow_item must be a list")
267
+
268
+ elif check_method == "regex":
269
+ # Regex-based checking requires pattern
270
+ if "pattern" not in rule:
271
+ raise ValueError(f"user_interaction[{i}] with check_method 'regex' must have 'pattern'")
272
+ if not isinstance(rule["pattern"], str):
273
+ raise ValueError(f"user_interaction[{i}] pattern must be a string")
274
+ # Test regex pattern validity
275
+ try:
276
+ re.compile(rule["pattern"])
277
+ except re.error as e:
278
+ raise ValueError(f"user_interaction[{i}] invalid regex pattern '{rule['pattern']}': {e}")
279
+
280
+ def validate_agent_names(self, agent_names: list[str]) -> None:
281
+ """Validate that agent names referenced in policy actually exist."""
282
+ available_agents = set(agent_names)
283
+
284
+ # Check inter-agent safeguards
285
+ if "inter_agent_safeguards" in self.policy:
286
+ inter_agent = self.policy["inter_agent_safeguards"]
287
+
288
+ # Check agent_transitions
289
+ for i, rule in enumerate(inter_agent.get("agent_transitions", [])):
290
+ src_agent = rule.get("message_source")
291
+ dst_agent = rule.get("message_destination")
292
+
293
+ # Skip wildcard patterns
294
+ if src_agent != "*" and src_agent not in available_agents:
295
+ raise ValueError(
296
+ f"agent_transitions[{i}] references unknown source agent: '{src_agent}'. Available agents: {sorted(available_agents)}"
297
+ )
298
+
299
+ if dst_agent != "*" and dst_agent not in available_agents:
300
+ raise ValueError(
301
+ f"agent_transitions[{i}] references unknown destination agent: '{dst_agent}'. Available agents: {sorted(available_agents)}"
302
+ )
303
+
304
+ # Check environment safeguards
305
+ if "agent_environment_safeguards" in self.policy:
306
+ env_rules = self.policy["agent_environment_safeguards"]
307
+
308
+ # Check tool_interaction rules - only support message_source/message_destination format
309
+ for i, rule in enumerate(env_rules.get("tool_interaction", [])):
310
+ # Only validate message_source/message_destination format
311
+ if "message_source" in rule and "message_destination" in rule:
312
+ # Skip detailed validation since we can't distinguish agent vs tool names
313
+ pass
314
+ elif "pattern" in rule and "message_source" not in rule:
315
+ # Simple pattern rules are allowed
316
+ pass
317
+ else:
318
+ raise ValueError(
319
+ f"tool_interaction[{i}] must use either (message_source, message_destination) or pattern-only format"
320
+ )
321
+
322
+ # Check llm_interaction rules
323
+ for i, rule in enumerate(env_rules.get("llm_interaction", [])):
324
+ # New format
325
+ if "message_source" in rule and "message_destination" in rule:
326
+ src = rule["message_source"]
327
+ dst = rule["message_destination"]
328
+
329
+ # Check agent references (LLM interactions have agent <-> llm)
330
+ if src != "llm" and src.lower() != "llm" and src not in available_agents:
331
+ raise ValueError(
332
+ f"llm_interaction[{i}] references unknown agent: '{src}'. Available agents: {sorted(available_agents)}"
333
+ )
334
+ if dst != "llm" and dst.lower() != "llm" and dst not in available_agents:
335
+ raise ValueError(
336
+ f"llm_interaction[{i}] references unknown agent: '{dst}'. Available agents: {sorted(available_agents)}"
337
+ )
338
+
339
+ elif "agent_name" in rule:
340
+ agent_name = rule["agent_name"]
341
+ if agent_name not in available_agents:
342
+ raise ValueError(
343
+ f"llm_interaction[{i}] references unknown agent: '{agent_name}'. Available agents: {sorted(available_agents)}"
344
+ )
345
+
346
+ # Check user_interaction rules
347
+ for i, rule in enumerate(env_rules.get("user_interaction", [])):
348
+ agent_name = rule.get("agent")
349
+ if agent_name and agent_name not in available_agents:
350
+ raise ValueError(
351
+ f"user_interaction[{i}] references unknown agent: '{agent_name}'. Available agents: {sorted(available_agents)}"
352
+ )
353
+
354
+ def validate_tool_names(self, agent_tool_mapping: dict[str, list[str]], agent_names: list[str]) -> None:
355
+ """Validate that tool names referenced in policy actually exist and belong to the correct agents.
356
+
357
+ Args:
358
+ agent_tool_mapping: Dict mapping agent names to their tool names
359
+ agent_names: List of available agent names
360
+ """
361
+ available_agents = set(agent_names)
362
+ # Get all available tools across all agents
363
+ all_available_tools = set()
364
+ for tools in agent_tool_mapping.values():
365
+ all_available_tools.update(tools)
366
+
367
+ # Check environment safeguards for tool references
368
+ if "agent_environment_safeguards" in self.policy:
369
+ env_rules = self.policy["agent_environment_safeguards"]
370
+
371
+ # Check tool_interaction rules
372
+ for i, rule in enumerate(env_rules.get("tool_interaction", [])):
373
+ # Check message_source/message_destination format
374
+ if "message_source" in rule and "message_destination" in rule:
375
+ src = rule["message_source"]
376
+ dst = rule["message_destination"]
377
+
378
+ # Validate agent-tool relationships
379
+ self._validate_agent_tool_relationship(
380
+ i, "message_source", src, dst, available_agents, agent_tool_mapping, all_available_tools
381
+ )
382
+
383
+ def _validate_agent_tool_relationship(
384
+ self,
385
+ rule_index: int,
386
+ src_field: str,
387
+ src: str,
388
+ dst: str,
389
+ available_agents: set[str],
390
+ agent_tool_mapping: dict[str, list[str]],
391
+ all_available_tools: set[str],
392
+ ) -> None:
393
+ """Validate that agent-tool relationships in policy are correct."""
394
+ # Skip wildcards and special cases
395
+ if src == "*" or dst == "*" or src.lower() == "user" or dst.lower() == "user":
396
+ return
397
+
398
+ # Case 1: Agent -> Tool (agent uses tool)
399
+ if src in available_agents and dst not in available_agents:
400
+ # dst should be a tool that belongs to src agent
401
+ if dst not in all_available_tools:
402
+ raise ValueError(
403
+ f"tool_interaction[{rule_index}] references unknown tool: '{dst}'. Available tools: {sorted(all_available_tools)}"
404
+ )
405
+ if dst not in agent_tool_mapping.get(src, []):
406
+ agent_tools = agent_tool_mapping.get(src, [])
407
+ raise ValueError(
408
+ f"tool_interaction[{rule_index}] agent '{src}' does not have access to tool '{dst}'. "
409
+ f"Agent's tools: {sorted(agent_tools)}"
410
+ )
411
+
412
+ # Case 2: Tool -> Agent (tool output to agent)
413
+ elif src not in available_agents and dst in available_agents:
414
+ # src should be a tool that belongs to dst agent
415
+ if src not in all_available_tools:
416
+ raise ValueError(
417
+ f"tool_interaction[{rule_index}] references unknown tool: '{src}'. Available tools: {sorted(all_available_tools)}"
418
+ )
419
+ if src not in agent_tool_mapping.get(dst, []):
420
+ agent_tools = agent_tool_mapping.get(dst, [])
421
+ raise ValueError(
422
+ f"tool_interaction[{rule_index}] agent '{dst}' does not have access to tool '{src}'. "
423
+ f"Agent's tools: {sorted(agent_tools)}"
424
+ )
425
+
426
+ # Case 3: Tool -> Tool (unusual, but validate both exist)
427
+ elif src not in available_agents and dst not in available_agents:
428
+ if src not in all_available_tools:
429
+ raise ValueError(
430
+ f"tool_interaction[{rule_index}] references unknown tool: '{src}'. Available tools: {sorted(all_available_tools)}"
431
+ )
432
+ if dst not in all_available_tools:
433
+ raise ValueError(
434
+ f"tool_interaction[{rule_index}] references unknown tool: '{dst}'. Available tools: {sorted(all_available_tools)}"
435
+ )
@@ -0,0 +1,41 @@
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
+ from typing import TYPE_CHECKING
6
+
7
+ from pydantic import BaseModel
8
+
9
+ from ..agent import Agent
10
+
11
+ if TYPE_CHECKING:
12
+ # Avoid circular import
13
+ from ..groupchat import GroupChat
14
+
15
+
16
+ class SpeakerSelectionResult(BaseModel):
17
+ """Represents a speaker selection result that will be returned to GroupChat._prepare_and_select_agents to determine the next speaker.
18
+
19
+ This class can return an Agent, a None to end the conversation, or a string for a speaker selection method.
20
+ """
21
+
22
+ terminate: bool | None = None
23
+ agent_name: str | None = None
24
+ speaker_selection_method: str | None = None
25
+
26
+ def get_speaker_selection_result(self, groupchat: "GroupChat") -> Agent | str | None:
27
+ """Get the speaker selection result. If None, the conversation will end."""
28
+ if self.agent_name is not None:
29
+ # Find the agent by name in the groupchat
30
+ for agent in groupchat.agents:
31
+ if agent.name == self.agent_name:
32
+ return agent
33
+ raise ValueError(f"Agent '{self.agent_name}' not found in groupchat.")
34
+ elif self.speaker_selection_method is not None:
35
+ return self.speaker_selection_method
36
+ elif self.terminate is not None and self.terminate:
37
+ return None
38
+ else:
39
+ raise ValueError(
40
+ "Unable to establish speaker selection result. No terminate, agent, or speaker selection method provided."
41
+ )
@@ -0,0 +1,4 @@
1
+ # Copyright (c) 2023 - 2025, AG2ai, Inc., AG2ai open-source projects maintainers and core contributors
2
+ #
3
+ # SPDX-License-Identifier: Apache-2.0
4
+ #