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
autogen/a2a/client.py
ADDED
|
@@ -0,0 +1,357 @@
|
|
|
1
|
+
# Copyright (c) 2023 - 2025, AG2ai, Inc., AG2ai open-source projects maintainers and core contributors
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
|
|
5
|
+
import asyncio
|
|
6
|
+
import logging
|
|
7
|
+
from collections.abc import Sequence
|
|
8
|
+
from pprint import pformat
|
|
9
|
+
from typing import Any, cast
|
|
10
|
+
from uuid import uuid4
|
|
11
|
+
|
|
12
|
+
import httpx
|
|
13
|
+
from a2a.client import A2ACardResolver, A2AClientHTTPError, Client, ClientCallInterceptor, ClientConfig, ClientEvent
|
|
14
|
+
from a2a.client import ClientFactory as A2AClientFactory
|
|
15
|
+
from a2a.types import AgentCard, Message, Task, TaskIdParams, TaskQueryParams, TaskState
|
|
16
|
+
from a2a.utils.constants import AGENT_CARD_WELL_KNOWN_PATH, EXTENDED_AGENT_CARD_PATH, PREV_AGENT_CARD_WELL_KNOWN_PATH
|
|
17
|
+
from typing_extensions import Self
|
|
18
|
+
|
|
19
|
+
from autogen import ConversableAgent
|
|
20
|
+
from autogen.agentchat.group import ContextVariables
|
|
21
|
+
from autogen.doc_utils import export_module
|
|
22
|
+
from autogen.events.agent_events import TerminationEvent
|
|
23
|
+
from autogen.io.base import IOStream
|
|
24
|
+
from autogen.oai.client import OpenAIWrapper
|
|
25
|
+
from autogen.remote.httpx_client_factory import ClientFactory, EmptyClientFactory
|
|
26
|
+
from autogen.remote.protocol import RequestMessage, ResponseMessage
|
|
27
|
+
|
|
28
|
+
from .errors import A2aAgentNotFoundError, A2aClientError
|
|
29
|
+
from .utils import (
|
|
30
|
+
request_message_to_a2a,
|
|
31
|
+
response_message_from_a2a_message,
|
|
32
|
+
response_message_from_a2a_task,
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
logger = logging.getLogger(__name__)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
@export_module("autogen.a2a")
|
|
39
|
+
class A2aRemoteAgent(ConversableAgent):
|
|
40
|
+
"""`a2a-sdk`-based client for handling asynchronous communication with an A2A server.
|
|
41
|
+
|
|
42
|
+
It has fully-compatible with original `ConversableAgent` API, so you can easily integrate
|
|
43
|
+
remote A2A agents to existing collaborations.
|
|
44
|
+
|
|
45
|
+
Args:
|
|
46
|
+
url: The URL of the A2A server to connect to.
|
|
47
|
+
name: A unique identifier for this client instance.
|
|
48
|
+
silent: whether to print the message sent. If None, will use the value of silent in each function.
|
|
49
|
+
client: An optional HTTPX client instance factory.
|
|
50
|
+
client_config: A2A Client configuration options.
|
|
51
|
+
max_reconnects: Maximum number of reconnection attempts before giving up.
|
|
52
|
+
polling_interval: Time in seconds between polling operations. Works for A2A Servers doesn't support streaming.
|
|
53
|
+
interceptors: A list of interceptors to use for the client.
|
|
54
|
+
"""
|
|
55
|
+
|
|
56
|
+
def __init__(
|
|
57
|
+
self,
|
|
58
|
+
url: str,
|
|
59
|
+
name: str,
|
|
60
|
+
*,
|
|
61
|
+
silent: bool | None = None,
|
|
62
|
+
client: ClientFactory | None = None,
|
|
63
|
+
client_config: ClientConfig | None = None,
|
|
64
|
+
interceptors: Sequence[ClientCallInterceptor] = (),
|
|
65
|
+
max_reconnects: int = 3,
|
|
66
|
+
polling_interval: float = 0.5,
|
|
67
|
+
) -> None:
|
|
68
|
+
self.url = url # make it public for backward compatibility
|
|
69
|
+
|
|
70
|
+
self._httpx_client_factory = client or EmptyClientFactory()
|
|
71
|
+
self._card_resolver = A2ACardResolver(
|
|
72
|
+
httpx_client=self._httpx_client_factory(),
|
|
73
|
+
base_url=url,
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
self._max_reconnects = max_reconnects
|
|
77
|
+
self._polling_interval = polling_interval
|
|
78
|
+
|
|
79
|
+
super().__init__(name, silent=silent)
|
|
80
|
+
|
|
81
|
+
self.__llm_config: dict[str, Any] = {}
|
|
82
|
+
|
|
83
|
+
self._client_config = client_config or ClientConfig()
|
|
84
|
+
self._interceptors = list(interceptors)
|
|
85
|
+
self._agent_card: AgentCard | None = None
|
|
86
|
+
|
|
87
|
+
self.replace_reply_func(
|
|
88
|
+
ConversableAgent.generate_oai_reply,
|
|
89
|
+
A2aRemoteAgent.generate_remote_reply,
|
|
90
|
+
)
|
|
91
|
+
self.replace_reply_func(
|
|
92
|
+
ConversableAgent.a_generate_oai_reply,
|
|
93
|
+
A2aRemoteAgent.a_generate_remote_reply,
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
@classmethod
|
|
97
|
+
def from_card(
|
|
98
|
+
cls,
|
|
99
|
+
card: AgentCard,
|
|
100
|
+
*,
|
|
101
|
+
silent: bool | None = None,
|
|
102
|
+
client: ClientFactory | None = None,
|
|
103
|
+
client_config: ClientConfig | None = None,
|
|
104
|
+
max_reconnects: int = 3,
|
|
105
|
+
polling_interval: float = 0.5,
|
|
106
|
+
interceptors: Sequence[ClientCallInterceptor] = (),
|
|
107
|
+
) -> Self:
|
|
108
|
+
"""Creates an A2aRemoteAgent instance from an existing AgentCard.
|
|
109
|
+
|
|
110
|
+
This method allows you to instantiate an A2aRemoteAgent directly using a pre-existing
|
|
111
|
+
AgentCard, such as one retrieved from a discovery service or constructed manually.
|
|
112
|
+
The resulting agent will use the data from the given card and avoid redundant card
|
|
113
|
+
fetching. The agent's registryURL is set to "UNKNOWN" since it is assumed to be derived
|
|
114
|
+
from the card.
|
|
115
|
+
|
|
116
|
+
Args:
|
|
117
|
+
card: The agent card containing metadata and configuration for the remote agent.
|
|
118
|
+
silent: whether to print the message sent. If None, will use the value of silent in each function.
|
|
119
|
+
client: An optional HTTPX client instance factory.
|
|
120
|
+
client_config: A2A Client configuration options.
|
|
121
|
+
max_reconnects: Maximum number of reconnection attempts before giving up.
|
|
122
|
+
polling_interval: Time in seconds between polling operations. Works for A2A Servers doesn't support streaming.
|
|
123
|
+
interceptors: A list of interceptors to use for the client.
|
|
124
|
+
|
|
125
|
+
Returns:
|
|
126
|
+
Self: An instance of the A2aRemoteAgent configured with the provided card.
|
|
127
|
+
"""
|
|
128
|
+
instance = cls(
|
|
129
|
+
url="UNKNOWN",
|
|
130
|
+
name=card.name,
|
|
131
|
+
silent=silent,
|
|
132
|
+
client=client,
|
|
133
|
+
client_config=client_config,
|
|
134
|
+
max_reconnects=max_reconnects,
|
|
135
|
+
polling_interval=polling_interval,
|
|
136
|
+
interceptors=interceptors,
|
|
137
|
+
)
|
|
138
|
+
instance._agent_card = card
|
|
139
|
+
return instance
|
|
140
|
+
|
|
141
|
+
def generate_remote_reply(
|
|
142
|
+
self,
|
|
143
|
+
messages: list[dict[str, Any]] | None = None,
|
|
144
|
+
sender: ConversableAgent | None = None,
|
|
145
|
+
config: OpenAIWrapper | None = None,
|
|
146
|
+
) -> tuple[bool, dict[str, Any] | None]:
|
|
147
|
+
raise NotImplementedError(f"{self.__class__.__name__} does not support synchronous reply generation")
|
|
148
|
+
|
|
149
|
+
async def a_generate_remote_reply(
|
|
150
|
+
self,
|
|
151
|
+
messages: list[dict[str, Any]] | None = None,
|
|
152
|
+
sender: ConversableAgent | None = None,
|
|
153
|
+
config: OpenAIWrapper | None = None,
|
|
154
|
+
) -> tuple[bool, dict[str, Any] | None]:
|
|
155
|
+
if messages is None:
|
|
156
|
+
messages = self._oai_messages[sender]
|
|
157
|
+
|
|
158
|
+
if not self._agent_card:
|
|
159
|
+
self._agent_card = await self._get_agent_card()
|
|
160
|
+
|
|
161
|
+
context_id = uuid4().hex
|
|
162
|
+
|
|
163
|
+
self._client_config.httpx_client = self._httpx_client_factory()
|
|
164
|
+
async with self._client_config.httpx_client:
|
|
165
|
+
agent_client = A2AClientFactory(self._client_config).create(
|
|
166
|
+
self._agent_card,
|
|
167
|
+
interceptors=self._interceptors,
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
while True:
|
|
171
|
+
initial_message = request_message_to_a2a(
|
|
172
|
+
request_message=RequestMessage(
|
|
173
|
+
messages=messages,
|
|
174
|
+
context=self.context_variables.data,
|
|
175
|
+
client_tools=self.__llm_config.get("tools", []),
|
|
176
|
+
),
|
|
177
|
+
context_id=context_id,
|
|
178
|
+
)
|
|
179
|
+
|
|
180
|
+
if self._agent_card.capabilities.streaming:
|
|
181
|
+
reply = await self._ask_streaming(agent_client, initial_message)
|
|
182
|
+
else:
|
|
183
|
+
reply = await self._ask_polling(agent_client, initial_message)
|
|
184
|
+
|
|
185
|
+
if not reply:
|
|
186
|
+
return True, None
|
|
187
|
+
|
|
188
|
+
messages = reply.messages
|
|
189
|
+
if reply.input_required is not None:
|
|
190
|
+
user_input = await self.a_get_human_input(prompt=f"Input for `{self.name}`\n{reply.input_required}")
|
|
191
|
+
|
|
192
|
+
if user_input == "exit":
|
|
193
|
+
IOStream.get_default().send(
|
|
194
|
+
TerminationEvent(
|
|
195
|
+
termination_reason="User requested to end the conversation",
|
|
196
|
+
sender=self,
|
|
197
|
+
recipient=sender,
|
|
198
|
+
)
|
|
199
|
+
)
|
|
200
|
+
return True, None
|
|
201
|
+
|
|
202
|
+
messages.append({"content": user_input, "role": "user"})
|
|
203
|
+
continue
|
|
204
|
+
|
|
205
|
+
if sender and reply.context:
|
|
206
|
+
context_variables = ContextVariables(reply.context)
|
|
207
|
+
self.context_variables.update(context_variables.to_dict())
|
|
208
|
+
sender.context_variables.update(context_variables.to_dict())
|
|
209
|
+
|
|
210
|
+
return True, reply.messages[-1]
|
|
211
|
+
|
|
212
|
+
async def _ask_streaming(self, client: Client, message: Message) -> ResponseMessage | None:
|
|
213
|
+
connection_attemps = 1
|
|
214
|
+
try:
|
|
215
|
+
async for event in client.send_message(message):
|
|
216
|
+
result, task = self._process_event(event)
|
|
217
|
+
if not task:
|
|
218
|
+
return result
|
|
219
|
+
except httpx.ConnectError as e:
|
|
220
|
+
if task and connection_attemps < self._max_reconnects:
|
|
221
|
+
pass
|
|
222
|
+
|
|
223
|
+
if not self._agent_card:
|
|
224
|
+
raise A2aClientError("Failed to connect to the agent: agent card not found") from e
|
|
225
|
+
raise A2aClientError(f"Failed to connect to the agent: {pformat(self._agent_card.model_dump())}") from e
|
|
226
|
+
|
|
227
|
+
task = cast(Task, task)
|
|
228
|
+
while connection_attemps < self._max_reconnects:
|
|
229
|
+
try:
|
|
230
|
+
async for event in client.resubscribe(TaskIdParams(id=task.id)):
|
|
231
|
+
result, task = self._process_event(event)
|
|
232
|
+
if not task:
|
|
233
|
+
return result
|
|
234
|
+
|
|
235
|
+
except httpx.ConnectError as e:
|
|
236
|
+
connection_attemps += 1
|
|
237
|
+
if connection_attemps < self._max_reconnects:
|
|
238
|
+
pass
|
|
239
|
+
|
|
240
|
+
if not self._agent_card:
|
|
241
|
+
raise A2aClientError("Failed to connect to the agent: agent card not found") from e
|
|
242
|
+
raise A2aClientError(f"Failed to connect to the agent: {pformat(self._agent_card.model_dump())}") from e
|
|
243
|
+
|
|
244
|
+
return None
|
|
245
|
+
|
|
246
|
+
async def _ask_polling(self, client: Client, message: Message) -> ResponseMessage | None:
|
|
247
|
+
try:
|
|
248
|
+
async for event in client.send_message(message):
|
|
249
|
+
result, started_task = self._process_event(event)
|
|
250
|
+
if not started_task:
|
|
251
|
+
return result
|
|
252
|
+
break
|
|
253
|
+
except httpx.ConnectError as e:
|
|
254
|
+
if not self._agent_card:
|
|
255
|
+
raise A2aClientError("Failed to connect to the agent: agent card not found") from e
|
|
256
|
+
raise A2aClientError(f"Failed to connect to the agent: {pformat(self._agent_card.model_dump())}") from e
|
|
257
|
+
|
|
258
|
+
started_task, connection_attemps = cast(Task, started_task), 0
|
|
259
|
+
while connection_attemps < self._max_reconnects:
|
|
260
|
+
while True:
|
|
261
|
+
try:
|
|
262
|
+
task = await client.get_task(TaskQueryParams(id=started_task.id))
|
|
263
|
+
|
|
264
|
+
except httpx.ConnectError as e:
|
|
265
|
+
connection_attemps += 1
|
|
266
|
+
if connection_attemps < self._max_reconnects:
|
|
267
|
+
pass
|
|
268
|
+
|
|
269
|
+
if not self._agent_card:
|
|
270
|
+
raise A2aClientError("Failed to connect to the agent: agent card not found") from e
|
|
271
|
+
raise A2aClientError(
|
|
272
|
+
f"Failed to connect to the agent: {pformat(self._agent_card.model_dump())}"
|
|
273
|
+
) from e
|
|
274
|
+
|
|
275
|
+
else:
|
|
276
|
+
if _is_task_completed(task):
|
|
277
|
+
return response_message_from_a2a_task(task)
|
|
278
|
+
|
|
279
|
+
await asyncio.sleep(self._polling_interval)
|
|
280
|
+
|
|
281
|
+
return None
|
|
282
|
+
|
|
283
|
+
def _process_event(self, event: ClientEvent | Message) -> tuple[ResponseMessage | None, Task | None]:
|
|
284
|
+
if isinstance(event, Message):
|
|
285
|
+
return response_message_from_a2a_message(event), None
|
|
286
|
+
|
|
287
|
+
task, _ = event
|
|
288
|
+
if _is_task_completed(task):
|
|
289
|
+
return response_message_from_a2a_task(task), None
|
|
290
|
+
|
|
291
|
+
return None, task
|
|
292
|
+
|
|
293
|
+
def update_tool_signature(
|
|
294
|
+
self,
|
|
295
|
+
tool_sig: str | dict[str, Any],
|
|
296
|
+
is_remove: bool,
|
|
297
|
+
silent_override: bool = False,
|
|
298
|
+
) -> None:
|
|
299
|
+
self.__llm_config = self._update_tool_config(
|
|
300
|
+
self.__llm_config,
|
|
301
|
+
tool_sig=tool_sig,
|
|
302
|
+
is_remove=is_remove,
|
|
303
|
+
silent_override=silent_override,
|
|
304
|
+
)
|
|
305
|
+
|
|
306
|
+
async def _get_agent_card(
|
|
307
|
+
self,
|
|
308
|
+
auth_http_kwargs: dict[str, Any] | None = None,
|
|
309
|
+
) -> AgentCard:
|
|
310
|
+
card: AgentCard | None = None
|
|
311
|
+
|
|
312
|
+
try:
|
|
313
|
+
logger.info(
|
|
314
|
+
f"Attempting to fetch public agent card from: {self._card_resolver.base_url}{AGENT_CARD_WELL_KNOWN_PATH}"
|
|
315
|
+
)
|
|
316
|
+
|
|
317
|
+
try:
|
|
318
|
+
card = await self._card_resolver.get_agent_card(relative_card_path=AGENT_CARD_WELL_KNOWN_PATH)
|
|
319
|
+
except A2AClientHTTPError as e_public:
|
|
320
|
+
if e_public.status_code == 404:
|
|
321
|
+
logger.info(
|
|
322
|
+
f"Attempting to fetch public agent card from: {self._card_resolver.base_url}{PREV_AGENT_CARD_WELL_KNOWN_PATH}"
|
|
323
|
+
)
|
|
324
|
+
card = await self._card_resolver.get_agent_card(relative_card_path=PREV_AGENT_CARD_WELL_KNOWN_PATH)
|
|
325
|
+
else:
|
|
326
|
+
raise e_public
|
|
327
|
+
|
|
328
|
+
if card.supports_authenticated_extended_card:
|
|
329
|
+
try:
|
|
330
|
+
card = await self._card_resolver.get_agent_card(
|
|
331
|
+
relative_card_path=EXTENDED_AGENT_CARD_PATH,
|
|
332
|
+
http_kwargs=auth_http_kwargs,
|
|
333
|
+
)
|
|
334
|
+
except Exception as e_extended:
|
|
335
|
+
logger.warning(
|
|
336
|
+
f"Failed to fetch extended agent card: {e_extended}. Will proceed with public card.",
|
|
337
|
+
exc_info=True,
|
|
338
|
+
)
|
|
339
|
+
|
|
340
|
+
except Exception as e:
|
|
341
|
+
raise A2aAgentNotFoundError(f"{self.name}: {self._card_resolver.base_url}") from e
|
|
342
|
+
|
|
343
|
+
return card
|
|
344
|
+
|
|
345
|
+
|
|
346
|
+
def _is_task_completed(task: Task) -> bool:
|
|
347
|
+
if task.status.state is TaskState.failed:
|
|
348
|
+
raise A2aClientError(f"Task failed: {pformat(task.model_dump())}")
|
|
349
|
+
|
|
350
|
+
if task.status.state is TaskState.rejected:
|
|
351
|
+
raise A2aClientError(f"Task rejected: {pformat(task.model_dump())}")
|
|
352
|
+
|
|
353
|
+
return task.status.state in (
|
|
354
|
+
TaskState.completed,
|
|
355
|
+
TaskState.canceled,
|
|
356
|
+
TaskState.input_required,
|
|
357
|
+
)
|
autogen/a2a/errors.py
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
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
|
+
from autogen.remote.errors import RemoteAgentError, RemoteAgentNotFoundError
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class A2aClientError(RemoteAgentError):
|
|
10
|
+
"""Base class for A2A agent errors"""
|
|
11
|
+
|
|
12
|
+
pass
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class A2aAgentNotFoundError(A2aClientError, RemoteAgentNotFoundError):
|
|
16
|
+
"""Raised when a A2A agent is not found"""
|
|
17
|
+
|
|
18
|
+
pass
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# Copyright (c) 2023 - 2025, AG2ai, Inc., AG2ai open-source projects maintainers and core contributors
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
|
|
5
|
+
from typing import Any
|
|
6
|
+
from uuid import uuid4
|
|
7
|
+
|
|
8
|
+
from a2a.types import AgentCapabilities, AgentCard, DataPart, Message, Part, Role, SendMessageSuccessResponse, TextPart
|
|
9
|
+
from a2a.utils.constants import AGENT_CARD_WELL_KNOWN_PATH, EXTENDED_AGENT_CARD_PATH, PREV_AGENT_CARD_WELL_KNOWN_PATH
|
|
10
|
+
from httpx import MockTransport, Request, Response
|
|
11
|
+
|
|
12
|
+
from autogen.doc_utils import export_module
|
|
13
|
+
from autogen.remote.httpx_client_factory import HttpxClientFactory
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@export_module("autogen.a2a")
|
|
17
|
+
def MockClient( # noqa: N802
|
|
18
|
+
response_message: str | dict[str, Any] | TextPart | DataPart | Part,
|
|
19
|
+
) -> HttpxClientFactory:
|
|
20
|
+
"""Create a mock HTTP client for testing A2A agent interactions.
|
|
21
|
+
|
|
22
|
+
This function creates a mock HTTP client that simulates responses from an A2A agent server.
|
|
23
|
+
It handles both agent card requests and message sending requests with configurable responses.
|
|
24
|
+
|
|
25
|
+
Args:
|
|
26
|
+
response_message: The message to return in response to SendMessage requests.
|
|
27
|
+
|
|
28
|
+
Returns:
|
|
29
|
+
An HttpxClientFactory configured with a mock transport that handles requests
|
|
30
|
+
to agent card endpoints and message sending endpoints.
|
|
31
|
+
|
|
32
|
+
Example:
|
|
33
|
+
>>> client = MockClient("Hello, world!")
|
|
34
|
+
>>> agent = A2aRemoteAgent(name="remote", url="http://fake", client=client)
|
|
35
|
+
"""
|
|
36
|
+
if isinstance(response_message, Part):
|
|
37
|
+
parts = [response_message]
|
|
38
|
+
elif isinstance(response_message, (DataPart, TextPart)):
|
|
39
|
+
parts = [Part(root=response_message)]
|
|
40
|
+
elif isinstance(response_message, str):
|
|
41
|
+
parts = [Part(root=DataPart(data={"role": "assistant", "content": response_message}))]
|
|
42
|
+
elif isinstance(response_message, dict):
|
|
43
|
+
parts = [Part(root=DataPart(data={"role": "assistant", **response_message}))]
|
|
44
|
+
else:
|
|
45
|
+
raise ValueError(f"Invalid message type: {type(response_message)}")
|
|
46
|
+
|
|
47
|
+
async def mock_handler(request: Request) -> Response:
|
|
48
|
+
if (
|
|
49
|
+
request.url.path == AGENT_CARD_WELL_KNOWN_PATH
|
|
50
|
+
or request.url.path == EXTENDED_AGENT_CARD_PATH
|
|
51
|
+
or request.url.path == PREV_AGENT_CARD_WELL_KNOWN_PATH
|
|
52
|
+
):
|
|
53
|
+
return Response(
|
|
54
|
+
status_code=200,
|
|
55
|
+
content=AgentCard(
|
|
56
|
+
capabilities=AgentCapabilities(streaming=False),
|
|
57
|
+
default_input_modes=["text"],
|
|
58
|
+
default_output_modes=["text"],
|
|
59
|
+
name="mock_agent",
|
|
60
|
+
description="mock_agent",
|
|
61
|
+
url="http://localhost:8000",
|
|
62
|
+
supports_authenticated_extended_card=False,
|
|
63
|
+
version="0.1.0",
|
|
64
|
+
skills=[],
|
|
65
|
+
).model_dump_json(),
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
return Response(
|
|
69
|
+
status_code=200,
|
|
70
|
+
content=SendMessageSuccessResponse(
|
|
71
|
+
result=Message(
|
|
72
|
+
message_id=str(uuid4()),
|
|
73
|
+
role=Role.agent,
|
|
74
|
+
parts=parts,
|
|
75
|
+
),
|
|
76
|
+
).model_dump_json(),
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
return HttpxClientFactory(transport=MockTransport(handler=mock_handler))
|
autogen/a2a/server.py
ADDED
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
# Copyright (c) 2023 - 2025, AG2ai, Inc., AG2ai open-source projects maintainers and core contributors
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
|
|
5
|
+
import warnings
|
|
6
|
+
from collections.abc import Callable
|
|
7
|
+
from typing import TYPE_CHECKING
|
|
8
|
+
|
|
9
|
+
from a2a.server.request_handlers import DefaultRequestHandler
|
|
10
|
+
from a2a.server.tasks import InMemoryTaskStore
|
|
11
|
+
from a2a.types import AgentCapabilities, AgentCard, AgentSkill
|
|
12
|
+
from pydantic import Field
|
|
13
|
+
|
|
14
|
+
from autogen import ConversableAgent
|
|
15
|
+
from autogen.doc_utils import export_module
|
|
16
|
+
|
|
17
|
+
from .agent_executor import AutogenAgentExecutor
|
|
18
|
+
|
|
19
|
+
if TYPE_CHECKING:
|
|
20
|
+
from a2a.server.agent_execution import RequestContextBuilder
|
|
21
|
+
from a2a.server.apps import CallContextBuilder
|
|
22
|
+
from a2a.server.context import ServerCallContext
|
|
23
|
+
from a2a.server.events import QueueManager
|
|
24
|
+
from a2a.server.request_handlers import RequestHandler
|
|
25
|
+
from a2a.server.tasks import PushNotificationConfigStore, PushNotificationSender, TaskStore
|
|
26
|
+
from starlette.applications import Starlette
|
|
27
|
+
|
|
28
|
+
from autogen import ConversableAgent
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@export_module("autogen.a2a")
|
|
32
|
+
class CardSettings(AgentCard):
|
|
33
|
+
"""Original A2A AgentCard object inheritor making some fields optional."""
|
|
34
|
+
|
|
35
|
+
name: str | None = None # type: ignore[assignment]
|
|
36
|
+
"""
|
|
37
|
+
A human-readable name for the agent. Uses original agent name if not set.
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
description: str | None = None # type: ignore[assignment]
|
|
41
|
+
"""
|
|
42
|
+
A human-readable description of the agent, assisting users and other agents
|
|
43
|
+
in understanding its purpose. Uses original agent description if not set.
|
|
44
|
+
"""
|
|
45
|
+
|
|
46
|
+
url: str | None = None # type: ignore[assignment]
|
|
47
|
+
"""
|
|
48
|
+
The preferred endpoint URL for interacting with the agent.
|
|
49
|
+
This URL MUST support the transport specified by 'preferredTransport'.
|
|
50
|
+
Uses original A2aAgentServer url if not set.
|
|
51
|
+
"""
|
|
52
|
+
|
|
53
|
+
version: str = "0.1.0"
|
|
54
|
+
"""
|
|
55
|
+
The agent's own version number. The format is defined by the provider.
|
|
56
|
+
"""
|
|
57
|
+
|
|
58
|
+
default_input_modes: list[str] = Field(default_factory=lambda: ["text"])
|
|
59
|
+
"""
|
|
60
|
+
Default set of supported input MIME types for all skills, which can be
|
|
61
|
+
overridden on a per-skill basis.
|
|
62
|
+
"""
|
|
63
|
+
|
|
64
|
+
default_output_modes: list[str] = Field(default_factory=lambda: ["text"])
|
|
65
|
+
"""
|
|
66
|
+
Default set of supported output MIME types for all skills, which can be
|
|
67
|
+
overridden on a per-skill basis.
|
|
68
|
+
"""
|
|
69
|
+
|
|
70
|
+
capabilities: AgentCapabilities = Field(default_factory=lambda: AgentCapabilities(streaming=True))
|
|
71
|
+
"""
|
|
72
|
+
A declaration of optional capabilities supported by the agent.
|
|
73
|
+
"""
|
|
74
|
+
|
|
75
|
+
skills: list[AgentSkill] = Field(default_factory=list)
|
|
76
|
+
"""
|
|
77
|
+
The set of skills, or distinct capabilities, that the agent can perform.
|
|
78
|
+
"""
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
@export_module("autogen.a2a")
|
|
82
|
+
class A2aAgentServer:
|
|
83
|
+
"""A server wrapper for running an AG2 agent via the A2A protocol.
|
|
84
|
+
|
|
85
|
+
This class provides functionality to wrap an AG2 ConversableAgent into an A2A server
|
|
86
|
+
that can be used to interact with the agent through A2A requests.
|
|
87
|
+
"""
|
|
88
|
+
|
|
89
|
+
def __init__(
|
|
90
|
+
self,
|
|
91
|
+
agent: "ConversableAgent",
|
|
92
|
+
*,
|
|
93
|
+
url: str | None = "http://localhost:8000",
|
|
94
|
+
agent_card: CardSettings | None = None,
|
|
95
|
+
card_modifier: Callable[["AgentCard"], "AgentCard"] | None = None,
|
|
96
|
+
extended_agent_card: CardSettings | None = None,
|
|
97
|
+
extended_card_modifier: Callable[["AgentCard", "ServerCallContext"], "AgentCard"] | None = None,
|
|
98
|
+
) -> None:
|
|
99
|
+
"""Initialize the A2aAgentServer.
|
|
100
|
+
|
|
101
|
+
Args:
|
|
102
|
+
agent: The Autogen ConversableAgent to serve.
|
|
103
|
+
url: The base URL for the A2A server.
|
|
104
|
+
agent_card: Configuration for the base agent card.
|
|
105
|
+
card_modifier: Function to modify the base agent card.
|
|
106
|
+
extended_agent_card: Configuration for the extended agent card.
|
|
107
|
+
extended_card_modifier: Function to modify the extended agent card.
|
|
108
|
+
"""
|
|
109
|
+
self.agent = agent
|
|
110
|
+
|
|
111
|
+
if not agent_card:
|
|
112
|
+
agent_card = CardSettings()
|
|
113
|
+
|
|
114
|
+
if agent_card.url and url != "http://localhost:8000":
|
|
115
|
+
warnings.warn(
|
|
116
|
+
(
|
|
117
|
+
"You can't use `agent_card.url` and `url` options in the same time. "
|
|
118
|
+
f"`agent_card.url` has a higher priority, so `{agent_card.url}` will be used."
|
|
119
|
+
),
|
|
120
|
+
RuntimeWarning,
|
|
121
|
+
stacklevel=2,
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
self.card = AgentCard.model_validate({
|
|
125
|
+
# use agent options by default
|
|
126
|
+
"name": agent.name,
|
|
127
|
+
"description": agent.description,
|
|
128
|
+
"url": url,
|
|
129
|
+
"supports_authenticated_extended_card": extended_agent_card is not None,
|
|
130
|
+
# exclude name and description if not provided
|
|
131
|
+
**agent_card.model_dump(exclude_none=True),
|
|
132
|
+
})
|
|
133
|
+
|
|
134
|
+
self.extended_agent_card: AgentCard | None = None
|
|
135
|
+
if extended_agent_card:
|
|
136
|
+
if extended_agent_card.url and url != "http://localhost:8000":
|
|
137
|
+
warnings.warn(
|
|
138
|
+
(
|
|
139
|
+
"You can't use `extended_agent_card.url` and `url` options in the same time. "
|
|
140
|
+
f"`agent_card.url` has a higher priority, so `{extended_agent_card.url}` will be used."
|
|
141
|
+
),
|
|
142
|
+
RuntimeWarning,
|
|
143
|
+
stacklevel=2,
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
self.extended_agent_card = AgentCard.model_validate({
|
|
147
|
+
"name": agent.name,
|
|
148
|
+
"description": agent.description,
|
|
149
|
+
"url": url,
|
|
150
|
+
**extended_agent_card.model_dump(exclude_none=True),
|
|
151
|
+
})
|
|
152
|
+
|
|
153
|
+
self.card_modifier = card_modifier
|
|
154
|
+
self.extended_card_modifier = extended_card_modifier
|
|
155
|
+
|
|
156
|
+
@property
|
|
157
|
+
def executor(self) -> AutogenAgentExecutor:
|
|
158
|
+
"""Get the A2A agent executor."""
|
|
159
|
+
return AutogenAgentExecutor(self.agent)
|
|
160
|
+
|
|
161
|
+
def build_request_handler(
|
|
162
|
+
self,
|
|
163
|
+
*,
|
|
164
|
+
task_store: "TaskStore | None" = None,
|
|
165
|
+
queue_manager: "QueueManager | None" = None,
|
|
166
|
+
push_config_store: "PushNotificationConfigStore | None" = None,
|
|
167
|
+
push_sender: "PushNotificationSender | None" = None,
|
|
168
|
+
request_context_builder: "RequestContextBuilder | None" = None,
|
|
169
|
+
) -> "RequestHandler":
|
|
170
|
+
"""Build a request handler for A2A application.
|
|
171
|
+
|
|
172
|
+
Args:
|
|
173
|
+
task_store: The task store to use.
|
|
174
|
+
queue_manager: The queue manager to use.
|
|
175
|
+
push_config_store: The push notification config store to use.
|
|
176
|
+
push_sender: The push notification sender to use.
|
|
177
|
+
request_context_builder: The request context builder to use.
|
|
178
|
+
|
|
179
|
+
Returns:
|
|
180
|
+
A configured RequestHandler instance.
|
|
181
|
+
"""
|
|
182
|
+
return DefaultRequestHandler(
|
|
183
|
+
agent_executor=self.executor,
|
|
184
|
+
task_store=task_store or InMemoryTaskStore(),
|
|
185
|
+
queue_manager=queue_manager,
|
|
186
|
+
push_config_store=push_config_store,
|
|
187
|
+
push_sender=push_sender,
|
|
188
|
+
request_context_builder=request_context_builder,
|
|
189
|
+
)
|
|
190
|
+
|
|
191
|
+
def build_starlette_app(
|
|
192
|
+
self,
|
|
193
|
+
*,
|
|
194
|
+
request_handler: "RequestHandler | None" = None,
|
|
195
|
+
context_builder: "CallContextBuilder | None" = None,
|
|
196
|
+
) -> "Starlette":
|
|
197
|
+
"""Build a Starlette A2A application for ASGI server.
|
|
198
|
+
|
|
199
|
+
Args:
|
|
200
|
+
request_handler: The request handler to use.
|
|
201
|
+
context_builder: The context builder to use.
|
|
202
|
+
|
|
203
|
+
Returns:
|
|
204
|
+
A configured Starlette application instance.
|
|
205
|
+
"""
|
|
206
|
+
from a2a.server.apps import A2AStarletteApplication
|
|
207
|
+
|
|
208
|
+
return A2AStarletteApplication(
|
|
209
|
+
agent_card=self.card,
|
|
210
|
+
extended_agent_card=self.extended_agent_card,
|
|
211
|
+
http_handler=request_handler
|
|
212
|
+
or DefaultRequestHandler(
|
|
213
|
+
agent_executor=self.executor,
|
|
214
|
+
task_store=InMemoryTaskStore(),
|
|
215
|
+
),
|
|
216
|
+
context_builder=context_builder,
|
|
217
|
+
card_modifier=self.card_modifier,
|
|
218
|
+
extended_card_modifier=self.extended_card_modifier,
|
|
219
|
+
).build()
|
|
220
|
+
|
|
221
|
+
build = build_starlette_app # default alias for build_starlette_app
|