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,77 @@
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
+ """
6
+ LLM Clients package for AG2.
7
+
8
+ This package provides the next-generation LLM client interface (ModelClientV2)
9
+ and unified response models that support rich content blocks from all providers.
10
+
11
+ Key Features:
12
+ - Provider-agnostic response format (UnifiedResponse)
13
+ - Rich content blocks (reasoning, thinking, citations, etc.)
14
+ - Forward compatibility with unknown content types via GenericContent
15
+ - Backward compatibility with existing ChatCompletion-based interface
16
+ - Extensible content type registry
17
+
18
+ Usage:
19
+ from autogen.llm_clients import OpenAICompletionsClient, UnifiedResponse
20
+ from autogen.llm_clients.models import ContentParser, ReasoningContent
21
+
22
+ # Use OpenAI Chat Completions Client
23
+ client = OpenAICompletionsClient(api_key="...")
24
+ response = client.create({
25
+ "model": "o1-preview",
26
+ "messages": [{"role": "user", "content": "Explain quantum computing"}]
27
+ })
28
+
29
+ # Access reasoning blocks
30
+ for reasoning in response.reasoning:
31
+ print(reasoning.reasoning)
32
+
33
+ # Register custom content types
34
+ ContentParser.register("custom_type", CustomContent)
35
+ """
36
+
37
+ from .client_v2 import ModelClientV2
38
+ from .models import (
39
+ AudioContent,
40
+ BaseContent,
41
+ CitationContent,
42
+ ContentBlock,
43
+ ContentParser,
44
+ GenericContent,
45
+ ImageContent,
46
+ ReasoningContent,
47
+ TextContent,
48
+ ToolCallContent,
49
+ ToolResultContent,
50
+ UnifiedMessage,
51
+ UnifiedResponse,
52
+ VideoContent,
53
+ )
54
+ from .openai_completions_client import OpenAICompletionsClient
55
+
56
+ __all__ = [ # noqa: RUF022
57
+ # Protocol
58
+ "ModelClientV2",
59
+ # Clients
60
+ "OpenAICompletionsClient",
61
+ # Content blocks
62
+ "AudioContent",
63
+ "BaseContent",
64
+ "CitationContent",
65
+ "ContentBlock",
66
+ "ContentParser",
67
+ "GenericContent",
68
+ "ImageContent",
69
+ "ReasoningContent",
70
+ "TextContent",
71
+ "ToolCallContent",
72
+ "ToolResultContent",
73
+ "VideoContent",
74
+ # Unified formats
75
+ "UnifiedMessage",
76
+ "UnifiedResponse",
77
+ ]
@@ -0,0 +1,122 @@
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
+ """
6
+ ModelClientV2 protocol for next-generation LLM client interface.
7
+
8
+ This protocol defines the interface for LLM clients that return rich,
9
+ provider-agnostic responses (UnifiedResponse) while maintaining backward
10
+ compatibility with the existing ChatCompletion-based interface.
11
+ """
12
+
13
+ from typing import Any, Protocol
14
+
15
+ from .models.unified_response import UnifiedResponse
16
+
17
+
18
+ class ModelClientV2(Protocol):
19
+ """Next-generation client interface with rich unified responses.
20
+
21
+ This protocol extends the current ModelClient interface to support:
22
+ - Rich content blocks (reasoning, thinking, citations, etc.)
23
+ - Provider-agnostic response format
24
+ - Forward compatibility with unknown content types
25
+ - Backward compatibility via create_v1_compatible()
26
+
27
+ Design Philosophy:
28
+ - Returns UnifiedResponse with typed content blocks for direct access
29
+ - Users should access content via response properties (text, reasoning, etc.)
30
+ - No message_retrieval() method - use response.text or response.messages directly
31
+ - For ModelClient compatibility, implementations should inherit ModelClient
32
+
33
+ Migration Path:
34
+ 1. Implement create() to return UnifiedResponse
35
+ 2. Implement create_v1_compatible() for backward compatibility
36
+ 3. Gradually migrate agents to use UnifiedResponse directly
37
+ 4. Eventually deprecate v1 compatibility layer
38
+
39
+ Example Implementation:
40
+ class OpenAIClientV2:
41
+ def create(self, params: dict[str, Any]) -> UnifiedResponse:
42
+ # Call OpenAI API
43
+ raw_response = openai.chat.completions.create(**params)
44
+
45
+ # Transform to UnifiedResponse with rich content blocks
46
+ return self._to_unified_response(raw_response)
47
+
48
+ def create_v1_compatible(self, params: dict[str, Any]) -> ChatCompletionExtended:
49
+ # Get rich response
50
+ response = self.create(params)
51
+
52
+ # Convert to legacy format
53
+ return self._to_v1(response)
54
+
55
+ Example Usage:
56
+ client = OpenAIClientV2()
57
+ response = client.create({"model": "o1-preview", "messages": [...]})
58
+
59
+ # Direct access to rich content
60
+ text = response.text # Get all text content
61
+ reasoning = response.reasoning # Get reasoning blocks
62
+ citations = response.get_content_by_type("citation") # Get specific types
63
+ """
64
+
65
+ RESPONSE_USAGE_KEYS: list[str] = ["prompt_tokens", "completion_tokens", "total_tokens", "cost", "model"]
66
+
67
+ def create(self, params: dict[str, Any]) -> UnifiedResponse:
68
+ """Create a completion and return unified response.
69
+
70
+ Args:
71
+ params: Request parameters (messages, model, temperature, etc.)
72
+
73
+ Returns:
74
+ UnifiedResponse with rich content blocks preserving all provider features
75
+ """
76
+ ...
77
+
78
+ def create_v1_compatible(self, params: dict[str, Any]) -> Any:
79
+ """Backward compatible - returns ChatCompletionExtended.
80
+ TODO Remove this method after migrating clients to V2.
81
+
82
+ This method provides backward compatibility during migration by:
83
+ 1. Calling create() to get UnifiedResponse
84
+ 2. Converting to ChatCompletionExtended format
85
+ 3. Flattening rich content to legacy format
86
+
87
+ Args:
88
+ params: Request parameters (same as create())
89
+
90
+ Returns:
91
+ ChatCompletionExtended for compatibility with existing agents
92
+
93
+ Note:
94
+ This method may lose information (reasoning blocks, citations, etc.)
95
+ when converting to the legacy format. Prefer create() for new code.
96
+ """
97
+ ...
98
+
99
+ def cost(self, response: UnifiedResponse) -> float:
100
+ """Calculate cost from response.
101
+ TODO Move this method to private after migrating clients to V2.
102
+
103
+ Args:
104
+ response: UnifiedResponse from create()
105
+
106
+ Returns:
107
+ Cost in USD for the API call
108
+ """
109
+ ...
110
+
111
+ @staticmethod
112
+ def get_usage(response: UnifiedResponse) -> dict[str, Any]:
113
+ """Extract usage statistics from response.
114
+ TODO Move this method to private after migrating clients to V2.
115
+
116
+ Args:
117
+ response: UnifiedResponse from create()
118
+
119
+ Returns:
120
+ Dict with keys from RESPONSE_USAGE_KEYS
121
+ """
122
+ ...
@@ -0,0 +1,55 @@
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
+ """
6
+ Unified response models for LLM clients.
7
+
8
+ This package provides:
9
+ - Content block system with extensibility via GenericContent
10
+ - UnifiedMessage format supporting all provider features
11
+ - UnifiedResponse provider-agnostic format
12
+ - ContentParser for registry-based content type handling
13
+ """
14
+
15
+ from .content_blocks import (
16
+ AudioContent,
17
+ BaseContent,
18
+ CitationContent,
19
+ ContentBlock,
20
+ ContentParser,
21
+ ContentType,
22
+ GenericContent,
23
+ ImageContent,
24
+ ReasoningContent,
25
+ TextContent,
26
+ ToolCallContent,
27
+ ToolResultContent,
28
+ VideoContent,
29
+ )
30
+ from .unified_message import UnifiedMessage, UserRoleEnum, UserRoleType, normalize_role
31
+ from .unified_response import UnifiedResponse
32
+
33
+ __all__ = [ # noqa: RUF022
34
+ # Content blocks
35
+ "AudioContent",
36
+ "BaseContent",
37
+ "CitationContent",
38
+ "ContentBlock",
39
+ "ContentParser",
40
+ "ContentType",
41
+ "GenericContent",
42
+ "ImageContent",
43
+ "ReasoningContent",
44
+ "TextContent",
45
+ "ToolCallContent",
46
+ "ToolResultContent",
47
+ "VideoContent",
48
+ # Unified formats
49
+ "UnifiedMessage",
50
+ "UnifiedResponse",
51
+ # Role types
52
+ "UserRoleEnum",
53
+ "UserRoleType",
54
+ "normalize_role",
55
+ ]
@@ -0,0 +1,389 @@
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
+ """
6
+ Content block system for unified LLM responses.
7
+
8
+ This module provides an extensible content block architecture that supports:
9
+ - Known content types (text, image, audio, video, reasoning, thinking, citations, tool calls)
10
+ - Unknown content types via GenericContent (forward compatibility)
11
+ - Registry-based parsing for extensibility
12
+ """
13
+
14
+ import warnings
15
+ from enum import Enum
16
+ from typing import Any, Literal
17
+
18
+ from pydantic import BaseModel, Field
19
+
20
+ # ============================================================================
21
+ # Content Type Enum
22
+ # ============================================================================
23
+
24
+
25
+ class ContentType(str, Enum):
26
+ """Known content types supported by the system.
27
+
28
+ This enum provides type safety for known content types while still allowing
29
+ unknown types via str union in BaseContent.
30
+ """
31
+
32
+ TEXT = "text"
33
+ IMAGE = "image"
34
+ AUDIO = "audio"
35
+ VIDEO = "video"
36
+ REASONING = "reasoning"
37
+ CITATION = "citation"
38
+ TOOL_CALL = "tool_call"
39
+ TOOL_RESULT = "tool_result"
40
+
41
+
42
+ # ============================================================================
43
+ # Base Content Block
44
+ # ============================================================================
45
+
46
+
47
+ class BaseContent(BaseModel):
48
+ """Base class for all content blocks with extension points.
49
+
50
+ This serves as the foundation for all content types, providing:
51
+ - Common type field for discriminated unions (ContentType enum or str for unknown types)
52
+ - Extra field for storing unknown provider-specific data
53
+ - Pydantic configuration for flexible field handling
54
+ - text property for extracting text representation
55
+ """
56
+
57
+ type: ContentType | str # Enum for known types, str for forward compatibility
58
+
59
+ # Extension point for unknown fields
60
+ extra: dict[str, Any] = Field(default_factory=dict)
61
+
62
+ class Config:
63
+ # Allow extra fields to be stored in model
64
+ extra = "allow"
65
+
66
+ def get_text(self) -> str:
67
+ """Extract text representation of content block.
68
+
69
+ Override in subclasses to provide specific text extraction logic.
70
+ Default returns empty string for content blocks without text.
71
+ """
72
+ return ""
73
+
74
+
75
+ # ============================================================================
76
+ # Known Content Types
77
+ # ============================================================================
78
+
79
+
80
+ class TextContent(BaseContent):
81
+ """Plain text content block."""
82
+
83
+ type: Literal[ContentType.TEXT] = ContentType.TEXT
84
+ text: str
85
+
86
+ def get_text(self) -> str:
87
+ """Get text content."""
88
+ return self.text
89
+
90
+
91
+ class ImageContent(BaseContent):
92
+ """Image content with optional detail level.
93
+
94
+ Supports both URLs and data URIs (base64-encoded blob data):
95
+ - image_url: Remote HTTP(S) URL to the image
96
+ - data_uri: Base64-encoded image data (e.g., "data:image/png;base64,...")
97
+
98
+ Note: Provide either image_url OR data_uri, not both.
99
+ """
100
+
101
+ type: Literal[ContentType.IMAGE] = ContentType.IMAGE
102
+ image_url: str | None = None
103
+ data_uri: str | None = None
104
+ detail: Literal["auto", "low", "high"] | None = None
105
+
106
+ # Inherits get_text() -> "" from BaseContent
107
+
108
+
109
+ class AudioContent(BaseContent):
110
+ """Audio content with optional transcript.
111
+
112
+ Supports both URLs and data URIs (base64-encoded blob data):
113
+ - audio_url: Remote HTTP(S) URL to the audio file
114
+ - data_uri: Base64-encoded audio data (e.g., "data:audio/mp3;base64,...")
115
+
116
+ Note: Provide either audio_url OR data_uri, not both.
117
+ """
118
+
119
+ type: Literal[ContentType.AUDIO] = ContentType.AUDIO
120
+ audio_url: str | None = None
121
+ data_uri: str | None = None
122
+ transcript: str | None = None
123
+
124
+ def get_text(self) -> str:
125
+ """Get audio transcript as text."""
126
+ if self.transcript:
127
+ return f"audio transcript:{self.transcript}"
128
+ return ""
129
+
130
+
131
+ class VideoContent(BaseContent):
132
+ """Video content block.
133
+
134
+ Supports both URLs and data URIs (base64-encoded blob data):
135
+ - video_url: Remote HTTP(S) URL to the video file
136
+ - data_uri: Base64-encoded video data (e.g., "data:video/mp4;base64,...")
137
+
138
+ Note: Provide either video_url OR data_uri, not both.
139
+ """
140
+
141
+ type: Literal[ContentType.VIDEO] = ContentType.VIDEO
142
+ video_url: str | None = None
143
+ data_uri: str | None = None
144
+
145
+ # Inherits get_text() -> "" from BaseContent
146
+
147
+
148
+ class ReasoningContent(BaseContent):
149
+ """Reasoning/chain-of-thought content (e.g., OpenAI o1/o3 models)."""
150
+
151
+ type: Literal[ContentType.REASONING] = ContentType.REASONING
152
+ reasoning: str
153
+ summary: str | None = None
154
+
155
+ def get_text(self) -> str:
156
+ """Get reasoning text."""
157
+ return self.reasoning
158
+
159
+
160
+ class CitationContent(BaseContent):
161
+ """Web search citation or reference."""
162
+
163
+ type: Literal[ContentType.CITATION] = ContentType.CITATION
164
+ url: str
165
+ title: str
166
+ snippet: str
167
+ relevance_score: float | None = None
168
+
169
+ def get_text(self) -> str:
170
+ """Get citation title as text."""
171
+ if self.title:
172
+ return f"citation: {self.title}"
173
+ return ""
174
+
175
+
176
+ class ToolCallContent(BaseContent):
177
+ """Tool/function call request."""
178
+
179
+ type: Literal[ContentType.TOOL_CALL] = ContentType.TOOL_CALL
180
+ id: str
181
+ name: str
182
+ arguments: str
183
+
184
+ def get_text(self) -> str:
185
+ """Get tool call as text."""
186
+ return f"tool call name: {self.name} tool call arguments: {self.arguments}"
187
+
188
+
189
+ class ToolResultContent(BaseContent):
190
+ """Tool/function execution result."""
191
+
192
+ type: Literal[ContentType.TOOL_RESULT] = ContentType.TOOL_RESULT
193
+ tool_call_id: str
194
+ output: str
195
+
196
+ def get_text(self) -> str:
197
+ """Get tool result as text."""
198
+ return f"tool result: {self.output}"
199
+
200
+
201
+ # ============================================================================
202
+ # Generic Content Block (Handles Unknown Types) - KEY FOR EXTENSIBILITY!
203
+ # ============================================================================
204
+
205
+
206
+ class GenericContent(BaseContent):
207
+ """Handles content blocks we don't have specific types for yet.
208
+
209
+ This is the KEY to forward compatibility:
210
+ - When a provider adds a new content type (e.g., "reflection", "video_analysis")
211
+ - We don't have a specific class defined yet
212
+ - GenericContent catches it and preserves ALL fields using Pydantic's native extra='allow'
213
+ - Users can access fields via attribute access or helper methods
214
+ - Later we can add a specific typed class without breaking anything
215
+
216
+ Example:
217
+ # Provider returns new "reflection" type
218
+ reflection = GenericContent(
219
+ type="reflection",
220
+ reflection="Upon reviewing...",
221
+ confidence=0.87,
222
+ corrections=["fix1", "fix2"]
223
+ )
224
+
225
+ # Access fields immediately
226
+ print(reflection.type) # "reflection"
227
+ print(reflection.reflection) # "Upon reviewing..." (attribute access)
228
+ print(reflection.confidence) # 0.87 (attribute access)
229
+
230
+ # Extract all fields
231
+ print(reflection.get_all_fields()) # All fields as dict
232
+ print(reflection.get_extra_fields()) # Only unknown fields
233
+ """
234
+
235
+ type: ContentType | str # Inherits from BaseContent, can be enum or any string
236
+
237
+ def get(self, key: str, default: Any = None) -> Any:
238
+ """Dict-style get for any field (defined or extra).
239
+
240
+ Example:
241
+ content.get("reflection", "N/A")
242
+ content.get("confidence", 0.0)
243
+ """
244
+ # Try model_extra first (unknown fields)
245
+ if self.model_extra and key in self.model_extra:
246
+ return self.model_extra[key]
247
+ # Fall back to getattr for defined fields
248
+ return getattr(self, key, default)
249
+
250
+ def get_all_fields(self) -> dict[str, Any]:
251
+ """Get all fields (defined + extra) as a single dict.
252
+
253
+ This is equivalent to model_dump() but more explicitly named.
254
+
255
+ Example:
256
+ all_data = content.get_all_fields()
257
+ """
258
+ return self.model_dump()
259
+
260
+ def get_extra_fields(self) -> dict[str, Any]:
261
+ """Get only the extra (unknown) fields.
262
+
263
+ Example:
264
+ extras = content.get_extra_fields()
265
+ for key, value in extras.items():
266
+ print(f"{key}: {value}")
267
+ """
268
+ return self.model_extra if self.model_extra else {}
269
+
270
+ def has_field(self, key: str) -> bool:
271
+ """Check if field exists (defined or extra).
272
+
273
+ Example:
274
+ if content.has_field("reflection"):
275
+ print(content.reflection)
276
+ """
277
+ return hasattr(self, key)
278
+
279
+ # Backward compatibility property for migration
280
+ @property
281
+ def data(self) -> dict[str, Any]:
282
+ """Backward compatibility: access extra fields as .data
283
+
284
+ Deprecated: Use get_extra_fields() or model_extra instead.
285
+ """
286
+ return self.get_extra_fields()
287
+
288
+
289
+ # ============================================================================
290
+ # Smart Content Parser - Routes to Specific or Generic Types
291
+ # ============================================================================
292
+
293
+
294
+ class ContentParser:
295
+ """Parses content blocks with automatic fallback to GenericContent.
296
+
297
+ This enables extensibility:
298
+ 1. Try to parse as known type (TextContent, ReasoningContent, etc.)
299
+ 2. If unknown type or parsing fails → GenericContent (preserves data)
300
+ 3. Later add new types to registry without breaking existing code
301
+ """
302
+
303
+ # Registry of known types (maps both enum values and string values)
304
+ _registry: dict[ContentType | str, type[BaseContent]] = {
305
+ ContentType.TEXT: TextContent,
306
+ "text": TextContent,
307
+ ContentType.IMAGE: ImageContent,
308
+ "image": ImageContent,
309
+ ContentType.AUDIO: AudioContent,
310
+ "audio": AudioContent,
311
+ ContentType.VIDEO: VideoContent,
312
+ "video": VideoContent,
313
+ ContentType.REASONING: ReasoningContent,
314
+ "reasoning": ReasoningContent,
315
+ ContentType.CITATION: CitationContent,
316
+ "citation": CitationContent,
317
+ ContentType.TOOL_CALL: ToolCallContent,
318
+ "tool_call": ToolCallContent,
319
+ ContentType.TOOL_RESULT: ToolResultContent,
320
+ "tool_result": ToolResultContent,
321
+ # Registry grows as we add types - no code changes elsewhere!
322
+ }
323
+
324
+ @classmethod
325
+ def register(cls, content_type: str, content_class: type[BaseContent]) -> None:
326
+ """Register a new content type.
327
+
328
+ Example:
329
+ # Add support for new "reflection" type
330
+ class ReflectionContent(BaseContent):
331
+ type: Literal["reflection"] = "reflection"
332
+ reflection: str
333
+ confidence: float
334
+
335
+ ContentParser.register("reflection", ReflectionContent)
336
+ """
337
+ cls._registry[content_type] = content_class
338
+
339
+ @classmethod
340
+ def parse(cls, data: dict[str, Any]) -> BaseContent:
341
+ """Parse content block data to appropriate type.
342
+
343
+ Returns:
344
+ - Specific type (TextContent, ReasoningContent, etc.) if known
345
+ - GenericContent if unknown type or parsing fails
346
+ - Always succeeds - never raises for unknown types!
347
+ """
348
+ content_type = data.get("type", "unknown")
349
+
350
+ # Try known type
351
+ if content_type in cls._registry:
352
+ content_class = cls._registry[content_type]
353
+ try:
354
+ return content_class(**data)
355
+ except Exception as e:
356
+ # Parsing failed - fall back to generic
357
+ # This ensures we never lose data due to validation errors
358
+ warnings.warn(
359
+ f"Failed to parse {content_type} as {content_class.__name__}: {e}. Using GenericContent instead.",
360
+ UserWarning,
361
+ stacklevel=2,
362
+ )
363
+ return GenericContent(**data)
364
+
365
+ # Unknown type - use generic (KEY FOR FORWARD COMPATIBILITY!)
366
+ # Ensure 'type' field is present for GenericContent validation
367
+ data_with_type = {"type": content_type, **data}
368
+ return GenericContent(**data_with_type)
369
+
370
+
371
+ # ============================================================================
372
+ # Union of all content types - easily extensible
373
+ # ============================================================================
374
+
375
+ # Union of all content types
376
+ ContentBlock = (
377
+ TextContent
378
+ | ImageContent
379
+ | AudioContent
380
+ | VideoContent
381
+ | ReasoningContent
382
+ | CitationContent
383
+ | ToolCallContent
384
+ | ToolResultContent
385
+ | GenericContent
386
+ ) # Always last - catches unknown types!
387
+
388
+ # Note: GenericContent must be last in the Union so that specific types
389
+ # are matched first during isinstance checks