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.
- ag2-0.10.2.dist-info/METADATA +819 -0
- ag2-0.10.2.dist-info/RECORD +423 -0
- ag2-0.10.2.dist-info/WHEEL +4 -0
- ag2-0.10.2.dist-info/licenses/LICENSE +201 -0
- ag2-0.10.2.dist-info/licenses/NOTICE.md +19 -0
- autogen/__init__.py +88 -0
- autogen/_website/__init__.py +3 -0
- autogen/_website/generate_api_references.py +426 -0
- autogen/_website/generate_mkdocs.py +1216 -0
- autogen/_website/notebook_processor.py +475 -0
- autogen/_website/process_notebooks.py +656 -0
- autogen/_website/utils.py +413 -0
- autogen/a2a/__init__.py +36 -0
- autogen/a2a/agent_executor.py +86 -0
- autogen/a2a/client.py +357 -0
- autogen/a2a/errors.py +18 -0
- autogen/a2a/httpx_client_factory.py +79 -0
- autogen/a2a/server.py +221 -0
- autogen/a2a/utils.py +207 -0
- autogen/agentchat/__init__.py +47 -0
- autogen/agentchat/agent.py +180 -0
- autogen/agentchat/assistant_agent.py +86 -0
- autogen/agentchat/chat.py +325 -0
- autogen/agentchat/contrib/__init__.py +5 -0
- autogen/agentchat/contrib/agent_eval/README.md +7 -0
- autogen/agentchat/contrib/agent_eval/agent_eval.py +108 -0
- autogen/agentchat/contrib/agent_eval/criterion.py +43 -0
- autogen/agentchat/contrib/agent_eval/critic_agent.py +44 -0
- autogen/agentchat/contrib/agent_eval/quantifier_agent.py +39 -0
- autogen/agentchat/contrib/agent_eval/subcritic_agent.py +45 -0
- autogen/agentchat/contrib/agent_eval/task.py +42 -0
- autogen/agentchat/contrib/agent_optimizer.py +432 -0
- autogen/agentchat/contrib/capabilities/__init__.py +5 -0
- autogen/agentchat/contrib/capabilities/agent_capability.py +20 -0
- autogen/agentchat/contrib/capabilities/generate_images.py +301 -0
- autogen/agentchat/contrib/capabilities/teachability.py +393 -0
- autogen/agentchat/contrib/capabilities/text_compressors.py +66 -0
- autogen/agentchat/contrib/capabilities/tools_capability.py +22 -0
- autogen/agentchat/contrib/capabilities/transform_messages.py +93 -0
- autogen/agentchat/contrib/capabilities/transforms.py +578 -0
- autogen/agentchat/contrib/capabilities/transforms_util.py +122 -0
- autogen/agentchat/contrib/capabilities/vision_capability.py +215 -0
- autogen/agentchat/contrib/captainagent/__init__.py +9 -0
- autogen/agentchat/contrib/captainagent/agent_builder.py +790 -0
- autogen/agentchat/contrib/captainagent/captainagent.py +514 -0
- autogen/agentchat/contrib/captainagent/tool_retriever.py +334 -0
- autogen/agentchat/contrib/captainagent/tools/README.md +44 -0
- autogen/agentchat/contrib/captainagent/tools/__init__.py +5 -0
- autogen/agentchat/contrib/captainagent/tools/data_analysis/calculate_correlation.py +40 -0
- autogen/agentchat/contrib/captainagent/tools/data_analysis/calculate_skewness_and_kurtosis.py +28 -0
- autogen/agentchat/contrib/captainagent/tools/data_analysis/detect_outlier_iqr.py +28 -0
- autogen/agentchat/contrib/captainagent/tools/data_analysis/detect_outlier_zscore.py +28 -0
- autogen/agentchat/contrib/captainagent/tools/data_analysis/explore_csv.py +21 -0
- autogen/agentchat/contrib/captainagent/tools/data_analysis/shapiro_wilk_test.py +30 -0
- autogen/agentchat/contrib/captainagent/tools/information_retrieval/arxiv_download.py +27 -0
- autogen/agentchat/contrib/captainagent/tools/information_retrieval/arxiv_search.py +53 -0
- autogen/agentchat/contrib/captainagent/tools/information_retrieval/extract_pdf_image.py +53 -0
- autogen/agentchat/contrib/captainagent/tools/information_retrieval/extract_pdf_text.py +38 -0
- autogen/agentchat/contrib/captainagent/tools/information_retrieval/get_wikipedia_text.py +21 -0
- autogen/agentchat/contrib/captainagent/tools/information_retrieval/get_youtube_caption.py +34 -0
- autogen/agentchat/contrib/captainagent/tools/information_retrieval/image_qa.py +60 -0
- autogen/agentchat/contrib/captainagent/tools/information_retrieval/optical_character_recognition.py +61 -0
- autogen/agentchat/contrib/captainagent/tools/information_retrieval/perform_web_search.py +47 -0
- autogen/agentchat/contrib/captainagent/tools/information_retrieval/scrape_wikipedia_tables.py +33 -0
- autogen/agentchat/contrib/captainagent/tools/information_retrieval/transcribe_audio_file.py +21 -0
- autogen/agentchat/contrib/captainagent/tools/information_retrieval/youtube_download.py +35 -0
- autogen/agentchat/contrib/captainagent/tools/math/calculate_circle_area_from_diameter.py +21 -0
- autogen/agentchat/contrib/captainagent/tools/math/calculate_day_of_the_week.py +18 -0
- autogen/agentchat/contrib/captainagent/tools/math/calculate_fraction_sum.py +28 -0
- autogen/agentchat/contrib/captainagent/tools/math/calculate_matrix_power.py +31 -0
- autogen/agentchat/contrib/captainagent/tools/math/calculate_reflected_point.py +16 -0
- autogen/agentchat/contrib/captainagent/tools/math/complex_numbers_product.py +25 -0
- autogen/agentchat/contrib/captainagent/tools/math/compute_currency_conversion.py +23 -0
- autogen/agentchat/contrib/captainagent/tools/math/count_distinct_permutations.py +27 -0
- autogen/agentchat/contrib/captainagent/tools/math/evaluate_expression.py +28 -0
- autogen/agentchat/contrib/captainagent/tools/math/find_continuity_point.py +34 -0
- autogen/agentchat/contrib/captainagent/tools/math/fraction_to_mixed_numbers.py +39 -0
- autogen/agentchat/contrib/captainagent/tools/math/modular_inverse_sum.py +23 -0
- autogen/agentchat/contrib/captainagent/tools/math/simplify_mixed_numbers.py +36 -0
- autogen/agentchat/contrib/captainagent/tools/math/sum_of_digit_factorials.py +15 -0
- autogen/agentchat/contrib/captainagent/tools/math/sum_of_primes_below.py +15 -0
- autogen/agentchat/contrib/captainagent/tools/requirements.txt +10 -0
- autogen/agentchat/contrib/captainagent/tools/tool_description.tsv +34 -0
- autogen/agentchat/contrib/gpt_assistant_agent.py +526 -0
- autogen/agentchat/contrib/graph_rag/__init__.py +9 -0
- autogen/agentchat/contrib/graph_rag/document.py +29 -0
- autogen/agentchat/contrib/graph_rag/falkor_graph_query_engine.py +167 -0
- autogen/agentchat/contrib/graph_rag/falkor_graph_rag_capability.py +103 -0
- autogen/agentchat/contrib/graph_rag/graph_query_engine.py +53 -0
- autogen/agentchat/contrib/graph_rag/graph_rag_capability.py +63 -0
- autogen/agentchat/contrib/graph_rag/neo4j_graph_query_engine.py +263 -0
- autogen/agentchat/contrib/graph_rag/neo4j_graph_rag_capability.py +83 -0
- autogen/agentchat/contrib/graph_rag/neo4j_native_graph_query_engine.py +210 -0
- autogen/agentchat/contrib/graph_rag/neo4j_native_graph_rag_capability.py +93 -0
- autogen/agentchat/contrib/img_utils.py +397 -0
- autogen/agentchat/contrib/llamaindex_conversable_agent.py +117 -0
- autogen/agentchat/contrib/llava_agent.py +189 -0
- autogen/agentchat/contrib/math_user_proxy_agent.py +464 -0
- autogen/agentchat/contrib/multimodal_conversable_agent.py +125 -0
- autogen/agentchat/contrib/qdrant_retrieve_user_proxy_agent.py +325 -0
- autogen/agentchat/contrib/rag/__init__.py +10 -0
- autogen/agentchat/contrib/rag/chromadb_query_engine.py +268 -0
- autogen/agentchat/contrib/rag/llamaindex_query_engine.py +195 -0
- autogen/agentchat/contrib/rag/mongodb_query_engine.py +319 -0
- autogen/agentchat/contrib/rag/query_engine.py +76 -0
- autogen/agentchat/contrib/retrieve_assistant_agent.py +59 -0
- autogen/agentchat/contrib/retrieve_user_proxy_agent.py +704 -0
- autogen/agentchat/contrib/society_of_mind_agent.py +200 -0
- autogen/agentchat/contrib/swarm_agent.py +1404 -0
- autogen/agentchat/contrib/text_analyzer_agent.py +79 -0
- autogen/agentchat/contrib/vectordb/__init__.py +5 -0
- autogen/agentchat/contrib/vectordb/base.py +224 -0
- autogen/agentchat/contrib/vectordb/chromadb.py +316 -0
- autogen/agentchat/contrib/vectordb/couchbase.py +405 -0
- autogen/agentchat/contrib/vectordb/mongodb.py +551 -0
- autogen/agentchat/contrib/vectordb/pgvectordb.py +927 -0
- autogen/agentchat/contrib/vectordb/qdrant.py +320 -0
- autogen/agentchat/contrib/vectordb/utils.py +126 -0
- autogen/agentchat/contrib/web_surfer.py +304 -0
- autogen/agentchat/conversable_agent.py +4307 -0
- autogen/agentchat/group/__init__.py +67 -0
- autogen/agentchat/group/available_condition.py +91 -0
- autogen/agentchat/group/context_condition.py +77 -0
- autogen/agentchat/group/context_expression.py +238 -0
- autogen/agentchat/group/context_str.py +39 -0
- autogen/agentchat/group/context_variables.py +182 -0
- autogen/agentchat/group/events/transition_events.py +111 -0
- autogen/agentchat/group/group_tool_executor.py +324 -0
- autogen/agentchat/group/group_utils.py +659 -0
- autogen/agentchat/group/guardrails.py +179 -0
- autogen/agentchat/group/handoffs.py +303 -0
- autogen/agentchat/group/llm_condition.py +93 -0
- autogen/agentchat/group/multi_agent_chat.py +291 -0
- autogen/agentchat/group/on_condition.py +55 -0
- autogen/agentchat/group/on_context_condition.py +51 -0
- autogen/agentchat/group/patterns/__init__.py +18 -0
- autogen/agentchat/group/patterns/auto.py +160 -0
- autogen/agentchat/group/patterns/manual.py +177 -0
- autogen/agentchat/group/patterns/pattern.py +295 -0
- autogen/agentchat/group/patterns/random.py +106 -0
- autogen/agentchat/group/patterns/round_robin.py +117 -0
- autogen/agentchat/group/reply_result.py +24 -0
- autogen/agentchat/group/safeguards/__init__.py +21 -0
- autogen/agentchat/group/safeguards/api.py +241 -0
- autogen/agentchat/group/safeguards/enforcer.py +1158 -0
- autogen/agentchat/group/safeguards/events.py +140 -0
- autogen/agentchat/group/safeguards/validator.py +435 -0
- autogen/agentchat/group/speaker_selection_result.py +41 -0
- autogen/agentchat/group/targets/__init__.py +4 -0
- autogen/agentchat/group/targets/function_target.py +245 -0
- autogen/agentchat/group/targets/group_chat_target.py +133 -0
- autogen/agentchat/group/targets/group_manager_target.py +151 -0
- autogen/agentchat/group/targets/transition_target.py +424 -0
- autogen/agentchat/group/targets/transition_utils.py +6 -0
- autogen/agentchat/groupchat.py +1832 -0
- autogen/agentchat/realtime/__init__.py +3 -0
- autogen/agentchat/realtime/experimental/__init__.py +20 -0
- autogen/agentchat/realtime/experimental/audio_adapters/__init__.py +8 -0
- autogen/agentchat/realtime/experimental/audio_adapters/twilio_audio_adapter.py +148 -0
- autogen/agentchat/realtime/experimental/audio_adapters/websocket_audio_adapter.py +139 -0
- autogen/agentchat/realtime/experimental/audio_observer.py +42 -0
- autogen/agentchat/realtime/experimental/clients/__init__.py +15 -0
- autogen/agentchat/realtime/experimental/clients/gemini/__init__.py +7 -0
- autogen/agentchat/realtime/experimental/clients/gemini/client.py +274 -0
- autogen/agentchat/realtime/experimental/clients/oai/__init__.py +8 -0
- autogen/agentchat/realtime/experimental/clients/oai/base_client.py +220 -0
- autogen/agentchat/realtime/experimental/clients/oai/rtc_client.py +243 -0
- autogen/agentchat/realtime/experimental/clients/oai/utils.py +48 -0
- autogen/agentchat/realtime/experimental/clients/realtime_client.py +191 -0
- autogen/agentchat/realtime/experimental/function_observer.py +84 -0
- autogen/agentchat/realtime/experimental/realtime_agent.py +158 -0
- autogen/agentchat/realtime/experimental/realtime_events.py +42 -0
- autogen/agentchat/realtime/experimental/realtime_observer.py +100 -0
- autogen/agentchat/realtime/experimental/realtime_swarm.py +533 -0
- autogen/agentchat/realtime/experimental/websockets.py +21 -0
- autogen/agentchat/realtime_agent/__init__.py +21 -0
- autogen/agentchat/user_proxy_agent.py +114 -0
- autogen/agentchat/utils.py +206 -0
- autogen/agents/__init__.py +3 -0
- autogen/agents/contrib/__init__.py +10 -0
- autogen/agents/contrib/time/__init__.py +8 -0
- autogen/agents/contrib/time/time_reply_agent.py +74 -0
- autogen/agents/contrib/time/time_tool_agent.py +52 -0
- autogen/agents/experimental/__init__.py +27 -0
- autogen/agents/experimental/deep_research/__init__.py +7 -0
- autogen/agents/experimental/deep_research/deep_research.py +52 -0
- autogen/agents/experimental/discord/__init__.py +7 -0
- autogen/agents/experimental/discord/discord.py +66 -0
- autogen/agents/experimental/document_agent/__init__.py +19 -0
- autogen/agents/experimental/document_agent/chroma_query_engine.py +301 -0
- autogen/agents/experimental/document_agent/docling_doc_ingest_agent.py +113 -0
- autogen/agents/experimental/document_agent/document_agent.py +643 -0
- autogen/agents/experimental/document_agent/document_conditions.py +50 -0
- autogen/agents/experimental/document_agent/document_utils.py +376 -0
- autogen/agents/experimental/document_agent/inmemory_query_engine.py +214 -0
- autogen/agents/experimental/document_agent/parser_utils.py +134 -0
- autogen/agents/experimental/document_agent/url_utils.py +417 -0
- autogen/agents/experimental/reasoning/__init__.py +7 -0
- autogen/agents/experimental/reasoning/reasoning_agent.py +1178 -0
- autogen/agents/experimental/slack/__init__.py +7 -0
- autogen/agents/experimental/slack/slack.py +73 -0
- autogen/agents/experimental/telegram/__init__.py +7 -0
- autogen/agents/experimental/telegram/telegram.py +76 -0
- autogen/agents/experimental/websurfer/__init__.py +7 -0
- autogen/agents/experimental/websurfer/websurfer.py +70 -0
- autogen/agents/experimental/wikipedia/__init__.py +7 -0
- autogen/agents/experimental/wikipedia/wikipedia.py +88 -0
- autogen/browser_utils.py +309 -0
- autogen/cache/__init__.py +10 -0
- autogen/cache/abstract_cache_base.py +71 -0
- autogen/cache/cache.py +203 -0
- autogen/cache/cache_factory.py +88 -0
- autogen/cache/cosmos_db_cache.py +144 -0
- autogen/cache/disk_cache.py +97 -0
- autogen/cache/in_memory_cache.py +54 -0
- autogen/cache/redis_cache.py +119 -0
- autogen/code_utils.py +598 -0
- autogen/coding/__init__.py +30 -0
- autogen/coding/base.py +120 -0
- autogen/coding/docker_commandline_code_executor.py +283 -0
- autogen/coding/factory.py +56 -0
- autogen/coding/func_with_reqs.py +203 -0
- autogen/coding/jupyter/__init__.py +23 -0
- autogen/coding/jupyter/base.py +36 -0
- autogen/coding/jupyter/docker_jupyter_server.py +160 -0
- autogen/coding/jupyter/embedded_ipython_code_executor.py +182 -0
- autogen/coding/jupyter/import_utils.py +82 -0
- autogen/coding/jupyter/jupyter_client.py +224 -0
- autogen/coding/jupyter/jupyter_code_executor.py +154 -0
- autogen/coding/jupyter/local_jupyter_server.py +164 -0
- autogen/coding/local_commandline_code_executor.py +341 -0
- autogen/coding/markdown_code_extractor.py +44 -0
- autogen/coding/utils.py +55 -0
- autogen/coding/yepcode_code_executor.py +197 -0
- autogen/doc_utils.py +35 -0
- autogen/environments/__init__.py +10 -0
- autogen/environments/docker_python_environment.py +365 -0
- autogen/environments/python_environment.py +125 -0
- autogen/environments/system_python_environment.py +85 -0
- autogen/environments/venv_python_environment.py +220 -0
- autogen/environments/working_directory.py +74 -0
- autogen/events/__init__.py +7 -0
- autogen/events/agent_events.py +1016 -0
- autogen/events/base_event.py +100 -0
- autogen/events/client_events.py +168 -0
- autogen/events/helpers.py +44 -0
- autogen/events/print_event.py +45 -0
- autogen/exception_utils.py +73 -0
- autogen/extensions/__init__.py +5 -0
- autogen/fast_depends/__init__.py +16 -0
- autogen/fast_depends/_compat.py +75 -0
- autogen/fast_depends/core/__init__.py +14 -0
- autogen/fast_depends/core/build.py +206 -0
- autogen/fast_depends/core/model.py +527 -0
- autogen/fast_depends/dependencies/__init__.py +15 -0
- autogen/fast_depends/dependencies/model.py +30 -0
- autogen/fast_depends/dependencies/provider.py +40 -0
- autogen/fast_depends/library/__init__.py +10 -0
- autogen/fast_depends/library/model.py +46 -0
- autogen/fast_depends/py.typed +6 -0
- autogen/fast_depends/schema.py +66 -0
- autogen/fast_depends/use.py +272 -0
- autogen/fast_depends/utils.py +177 -0
- autogen/formatting_utils.py +83 -0
- autogen/function_utils.py +13 -0
- autogen/graph_utils.py +173 -0
- autogen/import_utils.py +539 -0
- autogen/interop/__init__.py +22 -0
- autogen/interop/crewai/__init__.py +7 -0
- autogen/interop/crewai/crewai.py +88 -0
- autogen/interop/interoperability.py +71 -0
- autogen/interop/interoperable.py +46 -0
- autogen/interop/langchain/__init__.py +8 -0
- autogen/interop/langchain/langchain_chat_model_factory.py +156 -0
- autogen/interop/langchain/langchain_tool.py +78 -0
- autogen/interop/litellm/__init__.py +7 -0
- autogen/interop/litellm/litellm_config_factory.py +178 -0
- autogen/interop/pydantic_ai/__init__.py +7 -0
- autogen/interop/pydantic_ai/pydantic_ai.py +172 -0
- autogen/interop/registry.py +70 -0
- autogen/io/__init__.py +15 -0
- autogen/io/base.py +151 -0
- autogen/io/console.py +56 -0
- autogen/io/processors/__init__.py +12 -0
- autogen/io/processors/base.py +21 -0
- autogen/io/processors/console_event_processor.py +61 -0
- autogen/io/run_response.py +294 -0
- autogen/io/thread_io_stream.py +63 -0
- autogen/io/websockets.py +214 -0
- autogen/json_utils.py +42 -0
- autogen/llm_clients/MIGRATION_TO_V2.md +782 -0
- autogen/llm_clients/__init__.py +77 -0
- autogen/llm_clients/client_v2.py +122 -0
- autogen/llm_clients/models/__init__.py +55 -0
- autogen/llm_clients/models/content_blocks.py +389 -0
- autogen/llm_clients/models/unified_message.py +145 -0
- autogen/llm_clients/models/unified_response.py +83 -0
- autogen/llm_clients/openai_completions_client.py +444 -0
- autogen/llm_config/__init__.py +11 -0
- autogen/llm_config/client.py +59 -0
- autogen/llm_config/config.py +461 -0
- autogen/llm_config/entry.py +169 -0
- autogen/llm_config/types.py +37 -0
- autogen/llm_config/utils.py +223 -0
- autogen/logger/__init__.py +11 -0
- autogen/logger/base_logger.py +129 -0
- autogen/logger/file_logger.py +262 -0
- autogen/logger/logger_factory.py +42 -0
- autogen/logger/logger_utils.py +57 -0
- autogen/logger/sqlite_logger.py +524 -0
- autogen/math_utils.py +338 -0
- autogen/mcp/__init__.py +7 -0
- autogen/mcp/__main__.py +78 -0
- autogen/mcp/helpers.py +45 -0
- autogen/mcp/mcp_client.py +349 -0
- autogen/mcp/mcp_proxy/__init__.py +19 -0
- autogen/mcp/mcp_proxy/fastapi_code_generator_helpers.py +62 -0
- autogen/mcp/mcp_proxy/mcp_proxy.py +577 -0
- autogen/mcp/mcp_proxy/operation_grouping.py +166 -0
- autogen/mcp/mcp_proxy/operation_renaming.py +110 -0
- autogen/mcp/mcp_proxy/patch_fastapi_code_generator.py +98 -0
- autogen/mcp/mcp_proxy/security.py +399 -0
- autogen/mcp/mcp_proxy/security_schema_visitor.py +37 -0
- autogen/messages/__init__.py +7 -0
- autogen/messages/agent_messages.py +946 -0
- autogen/messages/base_message.py +108 -0
- autogen/messages/client_messages.py +172 -0
- autogen/messages/print_message.py +48 -0
- autogen/oai/__init__.py +61 -0
- autogen/oai/anthropic.py +1516 -0
- autogen/oai/bedrock.py +800 -0
- autogen/oai/cerebras.py +302 -0
- autogen/oai/client.py +1658 -0
- autogen/oai/client_utils.py +196 -0
- autogen/oai/cohere.py +494 -0
- autogen/oai/gemini.py +1045 -0
- autogen/oai/gemini_types.py +156 -0
- autogen/oai/groq.py +319 -0
- autogen/oai/mistral.py +311 -0
- autogen/oai/oai_models/__init__.py +23 -0
- autogen/oai/oai_models/_models.py +16 -0
- autogen/oai/oai_models/chat_completion.py +86 -0
- autogen/oai/oai_models/chat_completion_audio.py +32 -0
- autogen/oai/oai_models/chat_completion_message.py +97 -0
- autogen/oai/oai_models/chat_completion_message_tool_call.py +60 -0
- autogen/oai/oai_models/chat_completion_token_logprob.py +62 -0
- autogen/oai/oai_models/completion_usage.py +59 -0
- autogen/oai/ollama.py +657 -0
- autogen/oai/openai_responses.py +451 -0
- autogen/oai/openai_utils.py +897 -0
- autogen/oai/together.py +387 -0
- autogen/remote/__init__.py +18 -0
- autogen/remote/agent.py +199 -0
- autogen/remote/agent_service.py +197 -0
- autogen/remote/errors.py +17 -0
- autogen/remote/httpx_client_factory.py +131 -0
- autogen/remote/protocol.py +37 -0
- autogen/remote/retry.py +102 -0
- autogen/remote/runtime.py +96 -0
- autogen/retrieve_utils.py +490 -0
- autogen/runtime_logging.py +161 -0
- autogen/testing/__init__.py +12 -0
- autogen/testing/messages.py +45 -0
- autogen/testing/test_agent.py +111 -0
- autogen/token_count_utils.py +280 -0
- autogen/tools/__init__.py +20 -0
- autogen/tools/contrib/__init__.py +9 -0
- autogen/tools/contrib/time/__init__.py +7 -0
- autogen/tools/contrib/time/time.py +40 -0
- autogen/tools/dependency_injection.py +249 -0
- autogen/tools/experimental/__init__.py +54 -0
- autogen/tools/experimental/browser_use/__init__.py +7 -0
- autogen/tools/experimental/browser_use/browser_use.py +154 -0
- autogen/tools/experimental/code_execution/__init__.py +7 -0
- autogen/tools/experimental/code_execution/python_code_execution.py +86 -0
- autogen/tools/experimental/crawl4ai/__init__.py +7 -0
- autogen/tools/experimental/crawl4ai/crawl4ai.py +150 -0
- autogen/tools/experimental/deep_research/__init__.py +7 -0
- autogen/tools/experimental/deep_research/deep_research.py +329 -0
- autogen/tools/experimental/duckduckgo/__init__.py +7 -0
- autogen/tools/experimental/duckduckgo/duckduckgo_search.py +103 -0
- autogen/tools/experimental/firecrawl/__init__.py +7 -0
- autogen/tools/experimental/firecrawl/firecrawl_tool.py +836 -0
- autogen/tools/experimental/google/__init__.py +14 -0
- autogen/tools/experimental/google/authentication/__init__.py +11 -0
- autogen/tools/experimental/google/authentication/credentials_hosted_provider.py +43 -0
- autogen/tools/experimental/google/authentication/credentials_local_provider.py +91 -0
- autogen/tools/experimental/google/authentication/credentials_provider.py +35 -0
- autogen/tools/experimental/google/drive/__init__.py +9 -0
- autogen/tools/experimental/google/drive/drive_functions.py +124 -0
- autogen/tools/experimental/google/drive/toolkit.py +88 -0
- autogen/tools/experimental/google/model.py +17 -0
- autogen/tools/experimental/google/toolkit_protocol.py +19 -0
- autogen/tools/experimental/google_search/__init__.py +8 -0
- autogen/tools/experimental/google_search/google_search.py +93 -0
- autogen/tools/experimental/google_search/youtube_search.py +181 -0
- autogen/tools/experimental/messageplatform/__init__.py +17 -0
- autogen/tools/experimental/messageplatform/discord/__init__.py +7 -0
- autogen/tools/experimental/messageplatform/discord/discord.py +284 -0
- autogen/tools/experimental/messageplatform/slack/__init__.py +7 -0
- autogen/tools/experimental/messageplatform/slack/slack.py +385 -0
- autogen/tools/experimental/messageplatform/telegram/__init__.py +7 -0
- autogen/tools/experimental/messageplatform/telegram/telegram.py +271 -0
- autogen/tools/experimental/perplexity/__init__.py +7 -0
- autogen/tools/experimental/perplexity/perplexity_search.py +249 -0
- autogen/tools/experimental/reliable/__init__.py +10 -0
- autogen/tools/experimental/reliable/reliable.py +1311 -0
- autogen/tools/experimental/searxng/__init__.py +7 -0
- autogen/tools/experimental/searxng/searxng_search.py +142 -0
- autogen/tools/experimental/tavily/__init__.py +7 -0
- autogen/tools/experimental/tavily/tavily_search.py +176 -0
- autogen/tools/experimental/web_search_preview/__init__.py +7 -0
- autogen/tools/experimental/web_search_preview/web_search_preview.py +120 -0
- autogen/tools/experimental/wikipedia/__init__.py +7 -0
- autogen/tools/experimental/wikipedia/wikipedia.py +284 -0
- autogen/tools/function_utils.py +412 -0
- autogen/tools/tool.py +188 -0
- autogen/tools/toolkit.py +86 -0
- autogen/types.py +29 -0
- autogen/version.py +7 -0
- templates/client_template/main.jinja2 +72 -0
- templates/config_template/config.jinja2 +7 -0
- 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
|