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,197 @@
|
|
|
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 typing import Any, Literal, cast
|
|
7
|
+
|
|
8
|
+
from autogen.agentchat import ConversableAgent
|
|
9
|
+
from autogen.agentchat.conversable_agent import normilize_message_to_oai
|
|
10
|
+
from autogen.agentchat.group.context_variables import ContextVariables
|
|
11
|
+
from autogen.agentchat.group.group_tool_executor import GroupToolExecutor
|
|
12
|
+
from autogen.agentchat.group.reply_result import ReplyResult
|
|
13
|
+
from autogen.agentchat.group.targets.transition_target import AskUserTarget, TransitionTarget
|
|
14
|
+
from autogen.events.agent_events import TerminationAndHumanReplyNoInputEvent, TerminationEvent, UsingAutoReplyEvent
|
|
15
|
+
from autogen.events.base_event import BaseEvent
|
|
16
|
+
from autogen.io.base import AsyncIOStreamProtocol
|
|
17
|
+
|
|
18
|
+
from .protocol import RemoteService, RequestMessage, ResponseMessage, get_tool_names
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class AgentService(RemoteService):
|
|
22
|
+
def __init__(self, agent: ConversableAgent) -> None:
|
|
23
|
+
self.name = agent.name
|
|
24
|
+
self.agent = agent
|
|
25
|
+
|
|
26
|
+
async def __call__(self, state: RequestMessage) -> ResponseMessage | None:
|
|
27
|
+
out_message: dict[str, Any] | None
|
|
28
|
+
if guardrail_result := self.agent.run_input_guardrails(state.messages):
|
|
29
|
+
# input guardrail activated by initial messages
|
|
30
|
+
_, out_message = normilize_message_to_oai(guardrail_result.reply, self.agent.name, role="assistant")
|
|
31
|
+
return ResponseMessage(messages=[out_message], context=state.context)
|
|
32
|
+
|
|
33
|
+
context_variables = ContextVariables(state.context)
|
|
34
|
+
tool_executor = self._make_tool_executor(context_variables)
|
|
35
|
+
|
|
36
|
+
local_history: list[dict[str, Any]] = []
|
|
37
|
+
while True:
|
|
38
|
+
messages = state.messages + local_history
|
|
39
|
+
|
|
40
|
+
stream = HITLStream()
|
|
41
|
+
await self.agent.a_check_termination_and_human_reply(messages, iostream=stream)
|
|
42
|
+
if stream.is_input_required:
|
|
43
|
+
return ResponseMessage(
|
|
44
|
+
messages=local_history,
|
|
45
|
+
context=context_variables.data or None,
|
|
46
|
+
input_required=stream.input_prompt,
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
reply = await self.agent.a_generate_reply(
|
|
50
|
+
messages,
|
|
51
|
+
exclude=(
|
|
52
|
+
ConversableAgent.check_termination_and_human_reply,
|
|
53
|
+
ConversableAgent.a_check_termination_and_human_reply,
|
|
54
|
+
ConversableAgent.generate_oai_reply,
|
|
55
|
+
ConversableAgent.a_generate_oai_reply,
|
|
56
|
+
),
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
if not reply:
|
|
60
|
+
_, reply = await self.agent.a_generate_oai_reply(
|
|
61
|
+
messages,
|
|
62
|
+
tools=state.client_tools,
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
should_continue, out_message = self._add_message_to_local_history(reply, role="assistant")
|
|
66
|
+
if out_message:
|
|
67
|
+
local_history.append(out_message)
|
|
68
|
+
if not should_continue:
|
|
69
|
+
break
|
|
70
|
+
out_message = cast(dict[str, Any], out_message)
|
|
71
|
+
|
|
72
|
+
called_tools = get_tool_names(out_message.get("tool_calls", []))
|
|
73
|
+
if state.client_tool_names.intersection(called_tools):
|
|
74
|
+
break # return client tool execution command back to client
|
|
75
|
+
|
|
76
|
+
tool_result, updated_context_variables, return_to_user = self._try_execute_local_tool(
|
|
77
|
+
tool_executor, out_message
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
if updated_context_variables:
|
|
81
|
+
context_variables.update(updated_context_variables.to_dict())
|
|
82
|
+
|
|
83
|
+
should_continue, out_message = self._add_message_to_local_history(tool_result, role="tool")
|
|
84
|
+
if out_message:
|
|
85
|
+
local_history.append(out_message)
|
|
86
|
+
|
|
87
|
+
if return_to_user:
|
|
88
|
+
return ResponseMessage(
|
|
89
|
+
messages=local_history,
|
|
90
|
+
context=context_variables.data or None,
|
|
91
|
+
input_required="Please, provide additional information:\n",
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
if not should_continue:
|
|
95
|
+
break
|
|
96
|
+
|
|
97
|
+
if not local_history:
|
|
98
|
+
return None
|
|
99
|
+
|
|
100
|
+
return ResponseMessage(
|
|
101
|
+
messages=local_history,
|
|
102
|
+
context=context_variables.data or None,
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
def _add_message_to_local_history(
|
|
106
|
+
self, message: str | dict[str, Any] | None, role: str
|
|
107
|
+
) -> tuple[Literal[True], dict[str, Any]] | tuple[Literal[False], dict[str, Any] | None]:
|
|
108
|
+
if message is None:
|
|
109
|
+
return False, None # output message is empty, interrupt the loop
|
|
110
|
+
|
|
111
|
+
if guardrail_result := self.agent.run_output_guardrails(message):
|
|
112
|
+
_, out_message = normilize_message_to_oai(guardrail_result.reply, self.agent.name, role=role)
|
|
113
|
+
return False, out_message # output guardrail activated, interrupt the loop
|
|
114
|
+
|
|
115
|
+
valid, out_message = normilize_message_to_oai(message, self.agent.name, role=role)
|
|
116
|
+
if not valid:
|
|
117
|
+
return False, None # tool result is not valid OAI message, interrupt the loop
|
|
118
|
+
|
|
119
|
+
return True, out_message
|
|
120
|
+
|
|
121
|
+
def _make_tool_executor(self, context_variables: ContextVariables) -> GroupToolExecutor:
|
|
122
|
+
tool_executor = GroupToolExecutor()
|
|
123
|
+
for tool in self.agent.tools:
|
|
124
|
+
# TODO: inject ChatContext to tool
|
|
125
|
+
new_tool = tool_executor.make_tool_copy_with_context_variables(tool, context_variables) or tool
|
|
126
|
+
tool_executor.register_for_execution(serialize=False, silent_override=True)(new_tool)
|
|
127
|
+
return tool_executor
|
|
128
|
+
|
|
129
|
+
def _try_execute_local_tool(
|
|
130
|
+
self,
|
|
131
|
+
tool_executor: GroupToolExecutor,
|
|
132
|
+
tool_message: dict[str, Any],
|
|
133
|
+
) -> tuple[dict[str, Any] | None, ContextVariables | None, bool]:
|
|
134
|
+
tool_result: dict[str, Any] | None = None
|
|
135
|
+
updated_context_variables: ContextVariables | None = None
|
|
136
|
+
|
|
137
|
+
if "tool_calls" in tool_message:
|
|
138
|
+
_, tool_result = tool_executor.generate_tool_calls_reply([tool_message])
|
|
139
|
+
if tool_result is None:
|
|
140
|
+
return tool_result, updated_context_variables, False
|
|
141
|
+
|
|
142
|
+
if "tool_responses" in tool_result:
|
|
143
|
+
# TODO: catch handoffs
|
|
144
|
+
for tool_response in tool_result["tool_responses"]:
|
|
145
|
+
content = tool_response["content"]
|
|
146
|
+
|
|
147
|
+
if isinstance(content, AskUserTarget):
|
|
148
|
+
return tool_result, updated_context_variables, True
|
|
149
|
+
|
|
150
|
+
if isinstance(content, TransitionTarget):
|
|
151
|
+
warnings.warn(
|
|
152
|
+
f"Tool {self.agent.name} returned a target, which is not supported in remote mode"
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
elif isinstance(content, ReplyResult):
|
|
156
|
+
if content.context_variables:
|
|
157
|
+
updated_context_variables = content.context_variables
|
|
158
|
+
tool_response["content"] = content.message
|
|
159
|
+
|
|
160
|
+
if isinstance(content.target, AskUserTarget):
|
|
161
|
+
return tool_result, updated_context_variables, True
|
|
162
|
+
|
|
163
|
+
if content.target:
|
|
164
|
+
warnings.warn(
|
|
165
|
+
f"Tool {self.agent.name} returned a target, which is not supported in remote mode"
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
return tool_result, updated_context_variables, False
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
class HITLStream(AsyncIOStreamProtocol):
|
|
172
|
+
def __init__(self) -> None:
|
|
173
|
+
self.input_prompt = ""
|
|
174
|
+
|
|
175
|
+
@property
|
|
176
|
+
def is_input_required(self) -> bool:
|
|
177
|
+
return bool(self.input_prompt)
|
|
178
|
+
|
|
179
|
+
async def input(self, prompt: str = "", *, password: bool = False) -> str:
|
|
180
|
+
self.input_prompt = prompt
|
|
181
|
+
return ""
|
|
182
|
+
|
|
183
|
+
def print(self, *objects: Any, sep: str = " ", end: str = "\n", flush: bool = False) -> None:
|
|
184
|
+
raise NotImplementedError("HITLStream does not support printing")
|
|
185
|
+
|
|
186
|
+
def send(self, message: BaseEvent) -> None:
|
|
187
|
+
if isinstance(
|
|
188
|
+
message,
|
|
189
|
+
(
|
|
190
|
+
UsingAutoReplyEvent,
|
|
191
|
+
TerminationAndHumanReplyNoInputEvent,
|
|
192
|
+
TerminationEvent,
|
|
193
|
+
),
|
|
194
|
+
):
|
|
195
|
+
return
|
|
196
|
+
|
|
197
|
+
raise NotImplementedError("HITLStream does not support sending messages")
|
autogen/remote/errors.py
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
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
|
+
class RemoteAgentError(Exception):
|
|
7
|
+
"""Base class for remote agent errors"""
|
|
8
|
+
|
|
9
|
+
pass
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class RemoteAgentNotFoundError(RemoteAgentError):
|
|
13
|
+
"""Raised when a remote agent is not found"""
|
|
14
|
+
|
|
15
|
+
def __init__(self, agent_name: str) -> None:
|
|
16
|
+
self.agent_name = agent_name
|
|
17
|
+
super().__init__(f"Remote agent `{agent_name}` not found")
|
|
@@ -0,0 +1,131 @@
|
|
|
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 ssl
|
|
6
|
+
import typing
|
|
7
|
+
from typing import Protocol
|
|
8
|
+
|
|
9
|
+
from httpx._client import AsyncClient, Client, EventHook
|
|
10
|
+
from httpx._config import DEFAULT_LIMITS, DEFAULT_MAX_REDIRECTS, DEFAULT_TIMEOUT_CONFIG, Limits
|
|
11
|
+
from httpx._transports.base import AsyncBaseTransport
|
|
12
|
+
from httpx._types import AuthTypes, CertTypes, CookieTypes, HeaderTypes, ProxyTypes, QueryParamTypes, TimeoutTypes
|
|
13
|
+
from httpx._urls import URL
|
|
14
|
+
|
|
15
|
+
from autogen.doc_utils import export_module
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class ClientFactory(Protocol):
|
|
19
|
+
def __call__(self) -> AsyncClient: ...
|
|
20
|
+
|
|
21
|
+
def make_sync(self) -> Client: ...
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@export_module("autogen.a2a")
|
|
25
|
+
class HttpxClientFactory(ClientFactory):
|
|
26
|
+
"""
|
|
27
|
+
An asynchronous HTTP client factory, with connection pooling, HTTP/2, redirects,
|
|
28
|
+
cookie persistence, etc.
|
|
29
|
+
|
|
30
|
+
It can be shared between tasks.
|
|
31
|
+
|
|
32
|
+
Usage:
|
|
33
|
+
|
|
34
|
+
```python
|
|
35
|
+
>>> factory = HttpxClientFactory()
|
|
36
|
+
>>> async with factory() as client:
|
|
37
|
+
>>> response = await client.get('https://example.org')
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
**Parameters:**
|
|
41
|
+
|
|
42
|
+
* **auth** - *(optional)* An authentication class to use when sending
|
|
43
|
+
requests.
|
|
44
|
+
* **params** - *(optional)* Query parameters to include in request URLs, as
|
|
45
|
+
a string, dictionary, or sequence of two-tuples.
|
|
46
|
+
* **headers** - *(optional)* Dictionary of HTTP headers to include when
|
|
47
|
+
sending requests.
|
|
48
|
+
* **cookies** - *(optional)* Dictionary of Cookie items to include when
|
|
49
|
+
sending requests.
|
|
50
|
+
* **verify** - *(optional)* Either `True` to use an SSL context with the
|
|
51
|
+
default CA bundle, `False` to disable verification, or an instance of
|
|
52
|
+
`ssl.SSLContext` to use a custom context.
|
|
53
|
+
* **http2** - *(optional)* A boolean indicating if HTTP/2 support should be
|
|
54
|
+
enabled. Defaults to `False`.
|
|
55
|
+
* **proxy** - *(optional)* A proxy URL where all the traffic should be routed.
|
|
56
|
+
* **timeout** - *(optional)* The timeout configuration to use when sending
|
|
57
|
+
requests.
|
|
58
|
+
* **limits** - *(optional)* The limits configuration to use.
|
|
59
|
+
* **max_redirects** - *(optional)* The maximum number of redirect responses
|
|
60
|
+
that should be followed.
|
|
61
|
+
* **base_url** - *(optional)* A URL to use as the base when building
|
|
62
|
+
request URLs.
|
|
63
|
+
* **transport** - *(optional)* A transport class to use for sending requests
|
|
64
|
+
over the network.
|
|
65
|
+
* **trust_env** - *(optional)* Enables or disables usage of environment
|
|
66
|
+
variables for configuration.
|
|
67
|
+
* **default_encoding** - *(optional)* The default encoding to use for decoding
|
|
68
|
+
response text, if no charset information is included in a response Content-Type
|
|
69
|
+
header. Set to a callable for automatic character set detection. Default: "utf-8".
|
|
70
|
+
"""
|
|
71
|
+
|
|
72
|
+
def __init__(
|
|
73
|
+
self,
|
|
74
|
+
*,
|
|
75
|
+
auth: AuthTypes | None = None,
|
|
76
|
+
params: QueryParamTypes | None = None,
|
|
77
|
+
headers: HeaderTypes | None = None,
|
|
78
|
+
cookies: CookieTypes | None = None,
|
|
79
|
+
verify: ssl.SSLContext | str | bool = True,
|
|
80
|
+
cert: CertTypes | None = None,
|
|
81
|
+
http1: bool = True,
|
|
82
|
+
http2: bool = False,
|
|
83
|
+
proxy: ProxyTypes | None = None,
|
|
84
|
+
mounts: None | (typing.Mapping[str, AsyncBaseTransport | None]) = None,
|
|
85
|
+
timeout: TimeoutTypes = DEFAULT_TIMEOUT_CONFIG,
|
|
86
|
+
follow_redirects: bool = False,
|
|
87
|
+
limits: Limits = DEFAULT_LIMITS,
|
|
88
|
+
max_redirects: int = DEFAULT_MAX_REDIRECTS,
|
|
89
|
+
event_hooks: None | (typing.Mapping[str, list[EventHook]]) = None,
|
|
90
|
+
base_url: URL | str = "",
|
|
91
|
+
transport: AsyncBaseTransport | None = None,
|
|
92
|
+
trust_env: bool = True,
|
|
93
|
+
default_encoding: str | typing.Callable[[bytes], str] = "utf-8",
|
|
94
|
+
**kwargs: typing.Any,
|
|
95
|
+
) -> None:
|
|
96
|
+
self.options = {
|
|
97
|
+
"auth": auth,
|
|
98
|
+
"params": params,
|
|
99
|
+
"headers": headers,
|
|
100
|
+
"cookies": cookies,
|
|
101
|
+
"verify": verify,
|
|
102
|
+
"cert": cert,
|
|
103
|
+
"http1": http1,
|
|
104
|
+
"http2": http2,
|
|
105
|
+
"proxy": proxy,
|
|
106
|
+
"mounts": mounts,
|
|
107
|
+
"timeout": timeout,
|
|
108
|
+
"follow_redirects": follow_redirects,
|
|
109
|
+
"limits": limits,
|
|
110
|
+
"max_redirects": max_redirects,
|
|
111
|
+
"event_hooks": event_hooks,
|
|
112
|
+
"base_url": base_url,
|
|
113
|
+
"transport": transport,
|
|
114
|
+
"trust_env": trust_env,
|
|
115
|
+
"default_encoding": default_encoding,
|
|
116
|
+
**kwargs,
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
def __call__(self) -> AsyncClient:
|
|
120
|
+
return AsyncClient(**self.options)
|
|
121
|
+
|
|
122
|
+
def make_sync(self) -> Client:
|
|
123
|
+
return Client(**self.options)
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
class EmptyClientFactory(ClientFactory):
|
|
127
|
+
def __call__(self) -> AsyncClient:
|
|
128
|
+
return AsyncClient(timeout=30.0)
|
|
129
|
+
|
|
130
|
+
def make_sync(self) -> Client:
|
|
131
|
+
return Client(timeout=30.0)
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Copyright (c) 2023 - 2025, AG2ai, Inc., AG2ai open-source projects maintainers and core contributors
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
from typing import Any, Protocol
|
|
5
|
+
|
|
6
|
+
from pydantic import BaseModel, Field
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class AgentBusMessage(BaseModel):
|
|
10
|
+
messages: list[dict[str, Any]] = Field(default_factory=list)
|
|
11
|
+
context: dict[str, Any] | None = None
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class RequestMessage(AgentBusMessage):
|
|
15
|
+
client_tools: list[dict[str, Any]] = Field(default_factory=list)
|
|
16
|
+
|
|
17
|
+
@property
|
|
18
|
+
def client_tool_names(self) -> set[str]:
|
|
19
|
+
return get_tool_names(self.client_tools)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class ResponseMessage(AgentBusMessage):
|
|
23
|
+
input_required: str | None = None
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class RemoteService(Protocol):
|
|
27
|
+
"""Interface to make AgentBus compatible with non AG2 systems."""
|
|
28
|
+
|
|
29
|
+
name: str
|
|
30
|
+
|
|
31
|
+
async def __call__(self, state: RequestMessage) -> ResponseMessage | None:
|
|
32
|
+
"""Executable that consumes Conversation State and returns a new state."""
|
|
33
|
+
...
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def get_tool_names(tools: list[dict[str, Any]]) -> set[str]:
|
|
37
|
+
return set(filter(bool, (tool.get("function", {}).get("name", "") for tool in tools)))
|
autogen/remote/retry.py
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# Copyright (c) 2023 - 2025, AG2ai, Inc., AG2ai open-source projects maintainers and core contributors
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
import time
|
|
5
|
+
from types import TracebackType
|
|
6
|
+
from typing import Protocol
|
|
7
|
+
|
|
8
|
+
import anyio
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class RetryPolicyManager(Protocol):
|
|
12
|
+
def __enter__(self) -> None:
|
|
13
|
+
pass
|
|
14
|
+
|
|
15
|
+
async def __aenter__(self) -> None:
|
|
16
|
+
pass
|
|
17
|
+
|
|
18
|
+
def __exit__(
|
|
19
|
+
self, exc_type: type[BaseException] | None, exc_value: BaseException | None, traceback: TracebackType | None
|
|
20
|
+
) -> None | bool:
|
|
21
|
+
pass
|
|
22
|
+
|
|
23
|
+
async def __aexit__(
|
|
24
|
+
self, exc_type: type[BaseException] | None, exc_value: BaseException | None, traceback: TracebackType | None
|
|
25
|
+
) -> None | bool:
|
|
26
|
+
pass
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class RetryPolicy(Protocol):
|
|
30
|
+
def __call__(self) -> RetryPolicyManager: ...
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class SleepRetryPolicy(RetryPolicy):
|
|
34
|
+
def __init__(self, retry_interval: float = 10.0, retry_count: int = 3) -> None:
|
|
35
|
+
self.retry_interval = retry_interval
|
|
36
|
+
self.retry_count = retry_count
|
|
37
|
+
|
|
38
|
+
def __call__(self) -> RetryPolicyManager:
|
|
39
|
+
return _SleepRetryPolicy(self.retry_interval, self.retry_count)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class _SleepRetryPolicy(RetryPolicyManager):
|
|
43
|
+
def __init__(self, retry_interval: float = 10.0, retry_count: int = 3) -> None:
|
|
44
|
+
self.retry_interval = retry_interval
|
|
45
|
+
self.retry_count = retry_count
|
|
46
|
+
self.errors_count = 0
|
|
47
|
+
|
|
48
|
+
def __enter__(self) -> None:
|
|
49
|
+
pass
|
|
50
|
+
|
|
51
|
+
async def __aenter__(self) -> None:
|
|
52
|
+
pass
|
|
53
|
+
|
|
54
|
+
def __exit__(
|
|
55
|
+
self,
|
|
56
|
+
exc_type: type[BaseException] | None,
|
|
57
|
+
exc_value: BaseException | None,
|
|
58
|
+
traceback: TracebackType | None,
|
|
59
|
+
) -> None | bool:
|
|
60
|
+
if exc_type is not None:
|
|
61
|
+
self.errors_count += 1
|
|
62
|
+
should_suppress = self.errors_count < self.retry_count
|
|
63
|
+
time.sleep(self.retry_interval)
|
|
64
|
+
return should_suppress
|
|
65
|
+
return None
|
|
66
|
+
|
|
67
|
+
async def __aexit__(
|
|
68
|
+
self,
|
|
69
|
+
exc_type: type[BaseException] | None,
|
|
70
|
+
exc_value: BaseException | None,
|
|
71
|
+
traceback: TracebackType | None,
|
|
72
|
+
) -> None | bool:
|
|
73
|
+
if exc_type is not None:
|
|
74
|
+
self.errors_count += 1
|
|
75
|
+
should_suppress = self.errors_count < self.retry_count
|
|
76
|
+
await anyio.sleep(self.retry_interval)
|
|
77
|
+
return should_suppress
|
|
78
|
+
return None
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
class NoRetryPolicy(RetryPolicyManager):
|
|
82
|
+
def __enter__(self) -> None:
|
|
83
|
+
pass
|
|
84
|
+
|
|
85
|
+
async def __aenter__(self) -> None:
|
|
86
|
+
pass
|
|
87
|
+
|
|
88
|
+
async def __aexit__(
|
|
89
|
+
self,
|
|
90
|
+
exc_type: type[BaseException] | None,
|
|
91
|
+
exc_value: BaseException | None,
|
|
92
|
+
traceback: TracebackType | None,
|
|
93
|
+
) -> None | bool:
|
|
94
|
+
pass
|
|
95
|
+
|
|
96
|
+
def __exit__(
|
|
97
|
+
self,
|
|
98
|
+
exc_type: type[BaseException] | None,
|
|
99
|
+
exc_value: BaseException | None,
|
|
100
|
+
traceback: TracebackType | None,
|
|
101
|
+
) -> None | bool:
|
|
102
|
+
pass
|
|
@@ -0,0 +1,96 @@
|
|
|
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
|
+
from collections.abc import Awaitable, Callable, Iterable, MutableMapping
|
|
7
|
+
from itertools import chain
|
|
8
|
+
from typing import Any
|
|
9
|
+
from uuid import UUID, uuid4
|
|
10
|
+
|
|
11
|
+
from fastapi import FastAPI, HTTPException, Response, status
|
|
12
|
+
|
|
13
|
+
from autogen.agentchat import ConversableAgent
|
|
14
|
+
|
|
15
|
+
from .agent_service import AgentService
|
|
16
|
+
from .protocol import RemoteService, RequestMessage, ResponseMessage
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class HTTPAgentBus:
|
|
20
|
+
def __init__(
|
|
21
|
+
self,
|
|
22
|
+
agents: Iterable[ConversableAgent] = (),
|
|
23
|
+
*,
|
|
24
|
+
long_polling_interval: float = 10.0,
|
|
25
|
+
additional_services: Iterable[RemoteService] = (),
|
|
26
|
+
) -> None:
|
|
27
|
+
"""Create HTTPAgentBus runtime.
|
|
28
|
+
|
|
29
|
+
Makes the passed agents capable of processing remote calls.
|
|
30
|
+
|
|
31
|
+
Args:
|
|
32
|
+
agents: Agents to register as remote services.
|
|
33
|
+
long_polling_interval: Timeout to respond on task status calls for long-living executions.
|
|
34
|
+
Should be less than clients' HTTP request timeout.
|
|
35
|
+
additional_services: Additional services to register.
|
|
36
|
+
"""
|
|
37
|
+
self.app = FastAPI()
|
|
38
|
+
|
|
39
|
+
for service in chain(map(AgentService, agents), additional_services):
|
|
40
|
+
register_agent_endpoints(
|
|
41
|
+
app=self.app,
|
|
42
|
+
service=service,
|
|
43
|
+
long_polling_interval=long_polling_interval,
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
async def __call__(
|
|
47
|
+
self,
|
|
48
|
+
scope: MutableMapping[str, Any],
|
|
49
|
+
receive: Callable[[], Awaitable[MutableMapping[str, Any]]],
|
|
50
|
+
send: Callable[[MutableMapping[str, Any]], Awaitable[None]],
|
|
51
|
+
) -> None:
|
|
52
|
+
"""ASGI interface."""
|
|
53
|
+
await self.app(scope, receive, send)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def register_agent_endpoints(
|
|
57
|
+
app: FastAPI,
|
|
58
|
+
service: RemoteService,
|
|
59
|
+
long_polling_interval: float,
|
|
60
|
+
) -> None:
|
|
61
|
+
tasks: dict[UUID, asyncio.Task[ResponseMessage | None]] = {}
|
|
62
|
+
|
|
63
|
+
@app.get(f"/{service.name}" + "/{task_id}", response_model=ResponseMessage | None)
|
|
64
|
+
async def remote_call_result(task_id: UUID) -> Response | ResponseMessage | None:
|
|
65
|
+
if task_id not in tasks:
|
|
66
|
+
raise HTTPException(
|
|
67
|
+
detail=f"`{task_id}` task not found",
|
|
68
|
+
status_code=status.HTTP_404_NOT_FOUND,
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
task = tasks[task_id]
|
|
72
|
+
|
|
73
|
+
await asyncio.wait(
|
|
74
|
+
(task, asyncio.create_task(asyncio.sleep(long_polling_interval))),
|
|
75
|
+
return_when=asyncio.FIRST_COMPLETED,
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
if not task.done():
|
|
79
|
+
return Response(status_code=status.HTTP_425_TOO_EARLY)
|
|
80
|
+
|
|
81
|
+
try:
|
|
82
|
+
reply = task.result() # Task inner errors raising here
|
|
83
|
+
finally:
|
|
84
|
+
# TODO: how to clear hanged tasks?
|
|
85
|
+
tasks.pop(task_id, None)
|
|
86
|
+
|
|
87
|
+
if reply is None:
|
|
88
|
+
return Response(status_code=status.HTTP_204_NO_CONTENT)
|
|
89
|
+
|
|
90
|
+
return reply
|
|
91
|
+
|
|
92
|
+
@app.post(f"/{service.name}", status_code=status.HTTP_202_ACCEPTED)
|
|
93
|
+
async def remote_call_starter(state: RequestMessage) -> UUID:
|
|
94
|
+
task, task_id = asyncio.create_task(service(state)), uuid4()
|
|
95
|
+
tasks[task_id] = task
|
|
96
|
+
return task_id
|