ag2 0.9.1a1__py3-none-any.whl → 0.9.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.
Potentially problematic release.
This version of ag2 might be problematic. Click here for more details.
- {ag2-0.9.1a1.dist-info → ag2-0.9.2.dist-info}/METADATA +272 -75
- ag2-0.9.2.dist-info/RECORD +406 -0
- {ag2-0.9.1a1.dist-info → ag2-0.9.2.dist-info}/WHEEL +1 -2
- autogen/__init__.py +89 -0
- autogen/_website/__init__.py +3 -0
- autogen/_website/generate_api_references.py +427 -0
- autogen/_website/generate_mkdocs.py +1174 -0
- autogen/_website/notebook_processor.py +476 -0
- autogen/_website/process_notebooks.py +656 -0
- autogen/_website/utils.py +412 -0
- autogen/agentchat/__init__.py +44 -0
- autogen/agentchat/agent.py +182 -0
- autogen/agentchat/assistant_agent.py +85 -0
- autogen/agentchat/chat.py +309 -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 +429 -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 +566 -0
- autogen/agentchat/contrib/capabilities/transforms_util.py +122 -0
- autogen/agentchat/contrib/capabilities/vision_capability.py +214 -0
- autogen/agentchat/contrib/captainagent/__init__.py +9 -0
- autogen/agentchat/contrib/captainagent/agent_builder.py +790 -0
- autogen/agentchat/contrib/captainagent/captainagent.py +512 -0
- autogen/agentchat/contrib/captainagent/tool_retriever.py +335 -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 +170 -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 +268 -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 +187 -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 +324 -0
- autogen/agentchat/contrib/rag/__init__.py +10 -0
- autogen/agentchat/contrib/rag/chromadb_query_engine.py +272 -0
- autogen/agentchat/contrib/rag/llamaindex_query_engine.py +198 -0
- autogen/agentchat/contrib/rag/mongodb_query_engine.py +329 -0
- autogen/agentchat/contrib/rag/query_engine.py +74 -0
- autogen/agentchat/contrib/retrieve_assistant_agent.py +56 -0
- autogen/agentchat/contrib/retrieve_user_proxy_agent.py +703 -0
- autogen/agentchat/contrib/society_of_mind_agent.py +199 -0
- autogen/agentchat/contrib/swarm_agent.py +1425 -0
- autogen/agentchat/contrib/text_analyzer_agent.py +79 -0
- autogen/agentchat/contrib/vectordb/__init__.py +5 -0
- autogen/agentchat/contrib/vectordb/base.py +232 -0
- autogen/agentchat/contrib/vectordb/chromadb.py +315 -0
- autogen/agentchat/contrib/vectordb/couchbase.py +407 -0
- autogen/agentchat/contrib/vectordb/mongodb.py +550 -0
- autogen/agentchat/contrib/vectordb/pgvectordb.py +928 -0
- autogen/agentchat/contrib/vectordb/qdrant.py +320 -0
- autogen/agentchat/contrib/vectordb/utils.py +126 -0
- autogen/agentchat/contrib/web_surfer.py +303 -0
- autogen/agentchat/conversable_agent.py +4023 -0
- autogen/agentchat/group/__init__.py +64 -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 +41 -0
- autogen/agentchat/group/context_variables.py +192 -0
- autogen/agentchat/group/group_tool_executor.py +202 -0
- autogen/agentchat/group/group_utils.py +591 -0
- autogen/agentchat/group/handoffs.py +244 -0
- autogen/agentchat/group/llm_condition.py +93 -0
- autogen/agentchat/group/multi_agent_chat.py +237 -0
- autogen/agentchat/group/on_condition.py +58 -0
- autogen/agentchat/group/on_context_condition.py +54 -0
- autogen/agentchat/group/patterns/__init__.py +18 -0
- autogen/agentchat/group/patterns/auto.py +159 -0
- autogen/agentchat/group/patterns/manual.py +176 -0
- autogen/agentchat/group/patterns/pattern.py +288 -0
- autogen/agentchat/group/patterns/random.py +106 -0
- autogen/agentchat/group/patterns/round_robin.py +117 -0
- autogen/agentchat/group/reply_result.py +26 -0
- autogen/agentchat/group/speaker_selection_result.py +41 -0
- autogen/agentchat/group/targets/__init__.py +4 -0
- autogen/agentchat/group/targets/group_chat_target.py +132 -0
- autogen/agentchat/group/targets/group_manager_target.py +151 -0
- autogen/agentchat/group/targets/transition_target.py +413 -0
- autogen/agentchat/group/targets/transition_utils.py +6 -0
- autogen/agentchat/groupchat.py +1694 -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 +190 -0
- autogen/agentchat/realtime/experimental/function_observer.py +85 -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 +475 -0
- autogen/agentchat/realtime/experimental/websockets.py +21 -0
- autogen/agentchat/realtime_agent/__init__.py +21 -0
- autogen/agentchat/user_proxy_agent.py +111 -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 +73 -0
- autogen/agents/contrib/time/time_tool_agent.py +51 -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 +316 -0
- autogen/agents/experimental/document_agent/docling_doc_ingest_agent.py +118 -0
- autogen/agents/experimental/document_agent/document_agent.py +461 -0
- autogen/agents/experimental/document_agent/document_conditions.py +50 -0
- autogen/agents/experimental/document_agent/document_utils.py +380 -0
- autogen/agents/experimental/document_agent/inmemory_query_engine.py +220 -0
- autogen/agents/experimental/document_agent/parser_utils.py +130 -0
- autogen/agents/experimental/document_agent/url_utils.py +426 -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 +77 -0
- autogen/agents/experimental/websurfer/__init__.py +7 -0
- autogen/agents/experimental/websurfer/websurfer.py +62 -0
- autogen/agents/experimental/wikipedia/__init__.py +7 -0
- autogen/agents/experimental/wikipedia/wikipedia.py +90 -0
- autogen/browser_utils.py +309 -0
- autogen/cache/__init__.py +10 -0
- autogen/cache/abstract_cache_base.py +75 -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 +102 -0
- autogen/cache/in_memory_cache.py +58 -0
- autogen/cache/redis_cache.py +123 -0
- autogen/code_utils.py +596 -0
- autogen/coding/__init__.py +22 -0
- autogen/coding/base.py +119 -0
- autogen/coding/docker_commandline_code_executor.py +268 -0
- autogen/coding/factory.py +47 -0
- autogen/coding/func_with_reqs.py +202 -0
- autogen/coding/jupyter/__init__.py +23 -0
- autogen/coding/jupyter/base.py +36 -0
- autogen/coding/jupyter/docker_jupyter_server.py +167 -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 +231 -0
- autogen/coding/jupyter/jupyter_code_executor.py +160 -0
- autogen/coding/jupyter/local_jupyter_server.py +172 -0
- autogen/coding/local_commandline_code_executor.py +405 -0
- autogen/coding/markdown_code_extractor.py +45 -0
- autogen/coding/utils.py +56 -0
- autogen/doc_utils.py +34 -0
- autogen/events/__init__.py +7 -0
- autogen/events/agent_events.py +1013 -0
- autogen/events/base_event.py +99 -0
- autogen/events/client_events.py +167 -0
- autogen/events/helpers.py +36 -0
- autogen/events/print_event.py +46 -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 +80 -0
- autogen/fast_depends/core/__init__.py +14 -0
- autogen/fast_depends/core/build.py +225 -0
- autogen/fast_depends/core/model.py +576 -0
- autogen/fast_depends/dependencies/__init__.py +15 -0
- autogen/fast_depends/dependencies/model.py +29 -0
- autogen/fast_depends/dependencies/provider.py +39 -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 +280 -0
- autogen/fast_depends/utils.py +187 -0
- autogen/formatting_utils.py +83 -0
- autogen/function_utils.py +13 -0
- autogen/graph_utils.py +178 -0
- autogen/import_utils.py +526 -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 +155 -0
- autogen/interop/langchain/langchain_tool.py +82 -0
- autogen/interop/litellm/__init__.py +7 -0
- autogen/interop/litellm/litellm_config_factory.py +179 -0
- autogen/interop/pydantic_ai/__init__.py +7 -0
- autogen/interop/pydantic_ai/pydantic_ai.py +168 -0
- autogen/interop/registry.py +69 -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 +56 -0
- autogen/io/run_response.py +293 -0
- autogen/io/thread_io_stream.py +63 -0
- autogen/io/websockets.py +213 -0
- autogen/json_utils.py +43 -0
- autogen/llm_config.py +382 -0
- autogen/logger/__init__.py +11 -0
- autogen/logger/base_logger.py +128 -0
- autogen/logger/file_logger.py +261 -0
- autogen/logger/logger_factory.py +42 -0
- autogen/logger/logger_utils.py +57 -0
- autogen/logger/sqlite_logger.py +523 -0
- autogen/math_utils.py +339 -0
- autogen/mcp/__init__.py +7 -0
- autogen/mcp/__main__.py +78 -0
- autogen/mcp/mcp_client.py +208 -0
- autogen/mcp/mcp_proxy/__init__.py +19 -0
- autogen/mcp/mcp_proxy/fastapi_code_generator_helpers.py +63 -0
- autogen/mcp/mcp_proxy/mcp_proxy.py +581 -0
- autogen/mcp/mcp_proxy/operation_grouping.py +158 -0
- autogen/mcp/mcp_proxy/operation_renaming.py +114 -0
- autogen/mcp/mcp_proxy/patch_fastapi_code_generator.py +98 -0
- autogen/mcp/mcp_proxy/security.py +400 -0
- autogen/mcp/mcp_proxy/security_schema_visitor.py +37 -0
- autogen/messages/__init__.py +7 -0
- autogen/messages/agent_messages.py +948 -0
- autogen/messages/base_message.py +107 -0
- autogen/messages/client_messages.py +171 -0
- autogen/messages/print_message.py +49 -0
- autogen/oai/__init__.py +53 -0
- autogen/oai/anthropic.py +714 -0
- autogen/oai/bedrock.py +628 -0
- autogen/oai/cerebras.py +299 -0
- autogen/oai/client.py +1444 -0
- autogen/oai/client_utils.py +169 -0
- autogen/oai/cohere.py +479 -0
- autogen/oai/gemini.py +998 -0
- autogen/oai/gemini_types.py +155 -0
- autogen/oai/groq.py +305 -0
- autogen/oai/mistral.py +303 -0
- autogen/oai/oai_models/__init__.py +11 -0
- autogen/oai/oai_models/_models.py +16 -0
- autogen/oai/oai_models/chat_completion.py +87 -0
- autogen/oai/oai_models/chat_completion_audio.py +32 -0
- autogen/oai/oai_models/chat_completion_message.py +86 -0
- autogen/oai/oai_models/chat_completion_message_tool_call.py +37 -0
- autogen/oai/oai_models/chat_completion_token_logprob.py +63 -0
- autogen/oai/oai_models/completion_usage.py +60 -0
- autogen/oai/ollama.py +643 -0
- autogen/oai/openai_utils.py +881 -0
- autogen/oai/together.py +370 -0
- autogen/retrieve_utils.py +491 -0
- autogen/runtime_logging.py +160 -0
- autogen/token_count_utils.py +267 -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 +41 -0
- autogen/tools/dependency_injection.py +254 -0
- autogen/tools/experimental/__init__.py +48 -0
- autogen/tools/experimental/browser_use/__init__.py +7 -0
- autogen/tools/experimental/browser_use/browser_use.py +161 -0
- autogen/tools/experimental/crawl4ai/__init__.py +7 -0
- autogen/tools/experimental/crawl4ai/crawl4ai.py +153 -0
- autogen/tools/experimental/deep_research/__init__.py +7 -0
- autogen/tools/experimental/deep_research/deep_research.py +328 -0
- autogen/tools/experimental/duckduckgo/__init__.py +7 -0
- autogen/tools/experimental/duckduckgo/duckduckgo_search.py +109 -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 +288 -0
- autogen/tools/experimental/messageplatform/slack/__init__.py +7 -0
- autogen/tools/experimental/messageplatform/slack/slack.py +391 -0
- autogen/tools/experimental/messageplatform/telegram/__init__.py +7 -0
- autogen/tools/experimental/messageplatform/telegram/telegram.py +275 -0
- autogen/tools/experimental/perplexity/__init__.py +7 -0
- autogen/tools/experimental/perplexity/perplexity_search.py +260 -0
- autogen/tools/experimental/reliable/__init__.py +10 -0
- autogen/tools/experimental/reliable/reliable.py +1316 -0
- autogen/tools/experimental/tavily/__init__.py +7 -0
- autogen/tools/experimental/tavily/tavily_search.py +183 -0
- autogen/tools/experimental/web_search_preview/__init__.py +7 -0
- autogen/tools/experimental/web_search_preview/web_search_preview.py +114 -0
- autogen/tools/experimental/wikipedia/__init__.py +7 -0
- autogen/tools/experimental/wikipedia/wikipedia.py +287 -0
- autogen/tools/function_utils.py +411 -0
- autogen/tools/tool.py +187 -0
- autogen/tools/toolkit.py +86 -0
- autogen/types.py +29 -0
- autogen/version.py +7 -0
- templates/client_template/main.jinja2 +69 -0
- templates/config_template/config.jinja2 +7 -0
- templates/main.jinja2 +61 -0
- ag2-0.9.1a1.dist-info/RECORD +0 -6
- ag2-0.9.1a1.dist-info/top_level.txt +0 -1
- {ag2-0.9.1a1.dist-info → ag2-0.9.2.dist-info/licenses}/LICENSE +0 -0
- {ag2-0.9.1a1.dist-info → ag2-0.9.2.dist-info/licenses}/NOTICE.md +0 -0
autogen/math_utils.py
ADDED
|
@@ -0,0 +1,339 @@
|
|
|
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
|
+
# Portions derived from https://github.com/microsoft/autogen are under the MIT License.
|
|
6
|
+
# SPDX-License-Identifier: MIT
|
|
7
|
+
from typing import Optional
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def remove_boxed(string: str) -> Optional[str]:
|
|
11
|
+
"""Source: https://github.com/hendrycks/math
|
|
12
|
+
Extract the text within a \\boxed`{...}` environment.
|
|
13
|
+
|
|
14
|
+
Example:
|
|
15
|
+
```python
|
|
16
|
+
> remove_boxed("\\boxed{\\frac{2}{3}}")
|
|
17
|
+
|
|
18
|
+
\\frac{2}{3}
|
|
19
|
+
```
|
|
20
|
+
"""
|
|
21
|
+
left = "\\boxed{"
|
|
22
|
+
try:
|
|
23
|
+
if not all((string[: len(left)] == left, string[-1] == "}")):
|
|
24
|
+
raise AssertionError
|
|
25
|
+
|
|
26
|
+
return string[len(left) : -1]
|
|
27
|
+
except Exception:
|
|
28
|
+
return None
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def last_boxed_only_string(string: str) -> Optional[str]:
|
|
32
|
+
"""Source: https://github.com/hendrycks/math
|
|
33
|
+
Extract the last \\boxed`{...}` or \\fbox`{...}` element from a string.
|
|
34
|
+
"""
|
|
35
|
+
idx = string.rfind("\\boxed")
|
|
36
|
+
if idx < 0:
|
|
37
|
+
idx = string.rfind("\\fbox")
|
|
38
|
+
if idx < 0:
|
|
39
|
+
return None
|
|
40
|
+
|
|
41
|
+
i = idx
|
|
42
|
+
right_brace_idx = None
|
|
43
|
+
num_left_braces_open = 0
|
|
44
|
+
while i < len(string):
|
|
45
|
+
if string[i] == "{":
|
|
46
|
+
num_left_braces_open += 1
|
|
47
|
+
if string[i] == "}":
|
|
48
|
+
num_left_braces_open -= 1
|
|
49
|
+
if num_left_braces_open == 0:
|
|
50
|
+
right_brace_idx = i
|
|
51
|
+
break
|
|
52
|
+
i += 1
|
|
53
|
+
|
|
54
|
+
retval = None if right_brace_idx is None else string[idx : right_brace_idx + 1]
|
|
55
|
+
|
|
56
|
+
return retval
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def _fix_fracs(string: str) -> str:
|
|
60
|
+
"""Source: https://github.com/hendrycks/math
|
|
61
|
+
Reformat fractions.
|
|
62
|
+
|
|
63
|
+
Examples:
|
|
64
|
+
```
|
|
65
|
+
>>> _fix_fracs("\\frac1b")
|
|
66
|
+
\frac{1}{b}
|
|
67
|
+
>>> _fix_fracs("\\frac12")
|
|
68
|
+
\frac{1}{2}
|
|
69
|
+
>>> _fix_fracs("\\frac1{72}")
|
|
70
|
+
\frac{1}{72}
|
|
71
|
+
```
|
|
72
|
+
"""
|
|
73
|
+
substrs = string.split("\\frac")
|
|
74
|
+
new_str = substrs[0]
|
|
75
|
+
if len(substrs) > 1:
|
|
76
|
+
substrs = substrs[1:]
|
|
77
|
+
for substr in substrs:
|
|
78
|
+
new_str += "\\frac"
|
|
79
|
+
if substr[0] == "{":
|
|
80
|
+
new_str += substr
|
|
81
|
+
else:
|
|
82
|
+
try:
|
|
83
|
+
if not len(substr) >= 2:
|
|
84
|
+
raise AssertionError
|
|
85
|
+
except Exception:
|
|
86
|
+
return string
|
|
87
|
+
a = substr[0]
|
|
88
|
+
b = substr[1]
|
|
89
|
+
if b != "{":
|
|
90
|
+
if len(substr) > 2:
|
|
91
|
+
post_substr = substr[2:]
|
|
92
|
+
new_str += "{" + a + "}{" + b + "}" + post_substr
|
|
93
|
+
else:
|
|
94
|
+
new_str += "{" + a + "}{" + b + "}"
|
|
95
|
+
else:
|
|
96
|
+
if len(substr) > 2:
|
|
97
|
+
post_substr = substr[2:]
|
|
98
|
+
new_str += "{" + a + "}" + b + post_substr
|
|
99
|
+
else:
|
|
100
|
+
new_str += "{" + a + "}" + b
|
|
101
|
+
string = new_str
|
|
102
|
+
return string
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def _fix_a_slash_b(string: str) -> str:
|
|
106
|
+
"""Source: https://github.com/hendrycks/math
|
|
107
|
+
Reformat fractions formatted as a/b to \\`frac{a}{b}`.
|
|
108
|
+
|
|
109
|
+
Example:
|
|
110
|
+
```
|
|
111
|
+
>>> _fix_a_slash_b("2/3")
|
|
112
|
+
\frac{2}{3}
|
|
113
|
+
```
|
|
114
|
+
"""
|
|
115
|
+
if len(string.split("/")) != 2:
|
|
116
|
+
return string
|
|
117
|
+
a_str = string.split("/")[0]
|
|
118
|
+
b_str = string.split("/")[1]
|
|
119
|
+
try:
|
|
120
|
+
a = int(a_str)
|
|
121
|
+
b = int(b_str)
|
|
122
|
+
if not string == f"{a}/{b}":
|
|
123
|
+
raise AssertionError
|
|
124
|
+
new_string = "\\frac{" + str(a) + "}{" + str(b) + "}"
|
|
125
|
+
return new_string
|
|
126
|
+
except Exception:
|
|
127
|
+
return string
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def _remove_right_units(string: str) -> str:
|
|
131
|
+
"""Source: https://github.com/hendrycks/math
|
|
132
|
+
Remove units (on the right).
|
|
133
|
+
"\\text{ " only ever occurs (at least in the val set) when describing units.
|
|
134
|
+
"""
|
|
135
|
+
if "\\text{ " in string:
|
|
136
|
+
splits = string.split("\\text{ ")
|
|
137
|
+
if not len(splits) == 2:
|
|
138
|
+
raise AssertionError
|
|
139
|
+
return splits[0]
|
|
140
|
+
else:
|
|
141
|
+
return string
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
def _fix_sqrt(string: str) -> str:
|
|
145
|
+
"""Source: https://github.com/hendrycks/math
|
|
146
|
+
Reformat square roots.
|
|
147
|
+
|
|
148
|
+
Example:
|
|
149
|
+
```
|
|
150
|
+
>>> _fix_sqrt("\\sqrt3")
|
|
151
|
+
\\sqrt{3}
|
|
152
|
+
```
|
|
153
|
+
"""
|
|
154
|
+
if "\\sqrt" not in string:
|
|
155
|
+
return string
|
|
156
|
+
splits = string.split("\\sqrt")
|
|
157
|
+
new_string = splits[0]
|
|
158
|
+
for split in splits[1:]:
|
|
159
|
+
if split[0] != "{":
|
|
160
|
+
a = split[0]
|
|
161
|
+
new_substr = "\\sqrt{" + a + "}" + split[1:]
|
|
162
|
+
else:
|
|
163
|
+
new_substr = "\\sqrt" + split
|
|
164
|
+
new_string += new_substr
|
|
165
|
+
return new_string
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
def _strip_string(string: str) -> str:
|
|
169
|
+
"""Source: https://github.com/hendrycks/math
|
|
170
|
+
Apply the reformatting helper functions above.
|
|
171
|
+
"""
|
|
172
|
+
# linebreaks
|
|
173
|
+
string = string.replace("\n", "")
|
|
174
|
+
# print(string)
|
|
175
|
+
|
|
176
|
+
# remove inverse spaces
|
|
177
|
+
string = string.replace("\\!", "")
|
|
178
|
+
# print(string)
|
|
179
|
+
|
|
180
|
+
# replace \\ with \
|
|
181
|
+
string = string.replace("\\\\", "\\")
|
|
182
|
+
# print(string)
|
|
183
|
+
|
|
184
|
+
# replace tfrac and dfrac with frac
|
|
185
|
+
string = string.replace("tfrac", "frac")
|
|
186
|
+
string = string.replace("dfrac", "frac")
|
|
187
|
+
# print(string)
|
|
188
|
+
|
|
189
|
+
# remove \left and \right
|
|
190
|
+
string = string.replace("\\left", "")
|
|
191
|
+
string = string.replace("\\right", "")
|
|
192
|
+
# print(string)
|
|
193
|
+
|
|
194
|
+
# Remove circ (degrees)
|
|
195
|
+
string = string.replace("^{\\circ}", "")
|
|
196
|
+
string = string.replace("^\\circ", "")
|
|
197
|
+
|
|
198
|
+
# remove dollar signs
|
|
199
|
+
string = string.replace("\\$", "")
|
|
200
|
+
|
|
201
|
+
# remove units (on the right)
|
|
202
|
+
string = _remove_right_units(string)
|
|
203
|
+
|
|
204
|
+
# remove percentage
|
|
205
|
+
string = string.replace("\\%", "")
|
|
206
|
+
string = string.replace("%", "")
|
|
207
|
+
|
|
208
|
+
# " 0." equivalent to " ." and "{0." equivalent to "{." Alternatively, add "0" if "." is the start of the string
|
|
209
|
+
string = string.replace(" .", " 0.")
|
|
210
|
+
string = string.replace("{.", "{0.")
|
|
211
|
+
# if empty, return empty string
|
|
212
|
+
if len(string) == 0:
|
|
213
|
+
return string
|
|
214
|
+
if string[0] == ".":
|
|
215
|
+
string = "0" + string
|
|
216
|
+
|
|
217
|
+
# to consider: get rid of e.g. "k = " or "q = " at beginning
|
|
218
|
+
if len(string.split("=")) == 2 and len(string.split("=")[0]) <= 2:
|
|
219
|
+
string = string.split("=")[1]
|
|
220
|
+
|
|
221
|
+
# fix sqrt3 --> sqrt{3}
|
|
222
|
+
string = _fix_sqrt(string)
|
|
223
|
+
|
|
224
|
+
# remove spaces
|
|
225
|
+
string = string.replace(" ", "")
|
|
226
|
+
|
|
227
|
+
# \frac1b or \frac12 --> \frac{1}{b} and \frac{1}{2}, etc.
|
|
228
|
+
# Even works with \frac1{72} (but not \frac{72}1).
|
|
229
|
+
# Also does a/b --> \\frac{a}{b}
|
|
230
|
+
string = _fix_fracs(string)
|
|
231
|
+
|
|
232
|
+
# manually change 0.5 --> \frac{1}{2}
|
|
233
|
+
if string == "0.5":
|
|
234
|
+
string = "\\frac{1}{2}"
|
|
235
|
+
|
|
236
|
+
# NOTE: X/Y changed to \frac{X}{Y} in dataset, but in simple cases fix in case the model output is X/Y
|
|
237
|
+
string = _fix_a_slash_b(string)
|
|
238
|
+
|
|
239
|
+
return string
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
def get_answer(solution: Optional[str]) -> Optional[str]:
|
|
243
|
+
if solution is None:
|
|
244
|
+
return None
|
|
245
|
+
last_boxed = last_boxed_only_string(solution)
|
|
246
|
+
if last_boxed is None:
|
|
247
|
+
return None
|
|
248
|
+
answer = remove_boxed(last_boxed)
|
|
249
|
+
if answer is None:
|
|
250
|
+
return None
|
|
251
|
+
return answer
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
def is_equiv(str1: Optional[str], str2: Optional[str]) -> float:
|
|
255
|
+
"""Returns (as a float) whether two strings containing math are equivalent up to differences of formatting in
|
|
256
|
+
- units
|
|
257
|
+
- fractions
|
|
258
|
+
- square roots
|
|
259
|
+
- superfluous LaTeX.
|
|
260
|
+
Source: https://github.com/hendrycks/math
|
|
261
|
+
"""
|
|
262
|
+
if str1 is None and str2 is None:
|
|
263
|
+
print("WARNING: Both None")
|
|
264
|
+
return 1.0
|
|
265
|
+
if str1 is None or str2 is None:
|
|
266
|
+
return 0.0
|
|
267
|
+
|
|
268
|
+
try:
|
|
269
|
+
ss1 = _strip_string(str1)
|
|
270
|
+
ss2 = _strip_string(str2)
|
|
271
|
+
return float(ss1 == ss2)
|
|
272
|
+
except Exception:
|
|
273
|
+
return float(str1 == str2)
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
def is_equiv_chain_of_thought(str1: str, str2: str) -> float:
|
|
277
|
+
"""Strips the solution first before calling `is_equiv`."""
|
|
278
|
+
ans1 = get_answer(str1)
|
|
279
|
+
ans2 = get_answer(str2)
|
|
280
|
+
|
|
281
|
+
return is_equiv(ans1, ans2)
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
def voting_counts(responses):
|
|
285
|
+
answers = {}
|
|
286
|
+
for i in range(len(responses)):
|
|
287
|
+
equiv = i
|
|
288
|
+
if get_answer(responses[i]) is None:
|
|
289
|
+
# ignore None answers
|
|
290
|
+
continue
|
|
291
|
+
for j in answers:
|
|
292
|
+
if is_equiv_chain_of_thought(responses[i], responses[j]):
|
|
293
|
+
equiv = j
|
|
294
|
+
break
|
|
295
|
+
if equiv in answers:
|
|
296
|
+
answers[equiv] += 1
|
|
297
|
+
else:
|
|
298
|
+
answers[equiv] = 1
|
|
299
|
+
return answers
|
|
300
|
+
|
|
301
|
+
|
|
302
|
+
def eval_math_responses(responses, solution=None):
|
|
303
|
+
"""Select a response for a math problem using voting, and check if the response is correct if the solution is provided.
|
|
304
|
+
|
|
305
|
+
Args:
|
|
306
|
+
responses: The list of responses.
|
|
307
|
+
solution: The canonical solution.
|
|
308
|
+
|
|
309
|
+
Returns:
|
|
310
|
+
dict: The success metrics.
|
|
311
|
+
"""
|
|
312
|
+
n = len(responses)
|
|
313
|
+
if not n:
|
|
314
|
+
return {
|
|
315
|
+
"expected_success": 0,
|
|
316
|
+
"success": False,
|
|
317
|
+
"success_vote": 0,
|
|
318
|
+
"voted_answer": None,
|
|
319
|
+
"votes": 0,
|
|
320
|
+
}
|
|
321
|
+
success_list = []
|
|
322
|
+
if solution is not None:
|
|
323
|
+
for i in range(n):
|
|
324
|
+
response = responses[i]
|
|
325
|
+
succeed = is_equiv_chain_of_thought(response, solution)
|
|
326
|
+
success_list.append(succeed)
|
|
327
|
+
# voting
|
|
328
|
+
answers = voting_counts(responses)
|
|
329
|
+
# find the answer with highest votes in answers
|
|
330
|
+
answer, votes = max(answers.items(), key=lambda x: x[1], default=(0, 0))
|
|
331
|
+
# check if the answer is correct
|
|
332
|
+
success_vote = is_equiv_chain_of_thought(responses[answer], solution)
|
|
333
|
+
return {
|
|
334
|
+
"expected_success": 1 - pow(1 - sum(success_list) / n, n),
|
|
335
|
+
"success": any(s for s in success_list),
|
|
336
|
+
"success_vote": success_vote,
|
|
337
|
+
"voted_answer": responses[answer],
|
|
338
|
+
"votes": votes,
|
|
339
|
+
}
|
autogen/mcp/__init__.py
ADDED
autogen/mcp/__main__.py
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
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 logging
|
|
5
|
+
from typing import Annotated, Literal, Optional
|
|
6
|
+
|
|
7
|
+
from .. import __version__
|
|
8
|
+
from ..import_utils import optional_import_block, require_optional_import
|
|
9
|
+
from .mcp_proxy import MCPProxy
|
|
10
|
+
|
|
11
|
+
logger = logging.getLogger(__name__)
|
|
12
|
+
|
|
13
|
+
with optional_import_block():
|
|
14
|
+
import typer
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@require_optional_import(["typer"], "mcp-proxy-gen")
|
|
18
|
+
def create_typer_app() -> "typer.Typer":
|
|
19
|
+
"""Create a Typer app for the mcp proxy CLI."""
|
|
20
|
+
app = typer.Typer(rich_markup_mode="rich")
|
|
21
|
+
|
|
22
|
+
def version_callback(value: bool) -> None:
|
|
23
|
+
if value:
|
|
24
|
+
typer.echo(f"{__version__}")
|
|
25
|
+
raise typer.Exit()
|
|
26
|
+
|
|
27
|
+
@app.callback()
|
|
28
|
+
def callback(
|
|
29
|
+
version: Annotated[
|
|
30
|
+
Optional[bool],
|
|
31
|
+
typer.Option("--version", help="Show the version and exit.", callback=version_callback),
|
|
32
|
+
] = None,
|
|
33
|
+
) -> None:
|
|
34
|
+
"""AG2 mcp proxy CLI - The [bold]mcp proxy[/bold] command line app. 😎
|
|
35
|
+
|
|
36
|
+
Generate mcp proxy for your [bold]AG2[/bold] projects.
|
|
37
|
+
|
|
38
|
+
Read more in the docs: ...
|
|
39
|
+
""" # noqa: D415
|
|
40
|
+
|
|
41
|
+
@app.command()
|
|
42
|
+
def create(
|
|
43
|
+
openapi_specification: Annotated[
|
|
44
|
+
Optional[str],
|
|
45
|
+
"Specification of the OpenAPI to use for the proxy generation.",
|
|
46
|
+
] = None,
|
|
47
|
+
openapi_url: Annotated[
|
|
48
|
+
Optional[str],
|
|
49
|
+
"URL to the OpenAPI specification to use for the proxy generation.",
|
|
50
|
+
] = None,
|
|
51
|
+
client_source_path: Annotated[
|
|
52
|
+
Optional[str],
|
|
53
|
+
"Path to the generated proxy client source code.",
|
|
54
|
+
] = None,
|
|
55
|
+
server_url: Annotated[
|
|
56
|
+
Optional[str],
|
|
57
|
+
"Comma-separated list of server URLs to use for the proxy generation.",
|
|
58
|
+
] = None,
|
|
59
|
+
configuration_type: Annotated[
|
|
60
|
+
Literal["json", "yaml"],
|
|
61
|
+
"Configuration type of the specification. Can be 'json' or 'yaml'.",
|
|
62
|
+
] = "json",
|
|
63
|
+
) -> None:
|
|
64
|
+
"""Generate mcp proxy for your AG2 projects."""
|
|
65
|
+
MCPProxy.create(
|
|
66
|
+
openapi_specification=openapi_specification,
|
|
67
|
+
openapi_url=openapi_url,
|
|
68
|
+
client_source_path=client_source_path,
|
|
69
|
+
servers=[{"url": server_url}],
|
|
70
|
+
configuration_type=configuration_type,
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
return app
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
if __name__ == "__main__":
|
|
77
|
+
app = create_typer_app()
|
|
78
|
+
app(prog_name="mcp_proxy")
|
|
@@ -0,0 +1,208 @@
|
|
|
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
|
+
import sys
|
|
7
|
+
from datetime import datetime
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
from typing import Annotated, Any, Optional, Union
|
|
10
|
+
|
|
11
|
+
import anyio
|
|
12
|
+
from pydantic import BaseModel
|
|
13
|
+
|
|
14
|
+
from ..doc_utils import export_module
|
|
15
|
+
from ..import_utils import optional_import_block, require_optional_import
|
|
16
|
+
from ..tools import Tool, Toolkit
|
|
17
|
+
|
|
18
|
+
with optional_import_block():
|
|
19
|
+
from mcp import ClientSession
|
|
20
|
+
from mcp.types import (
|
|
21
|
+
CallToolResult,
|
|
22
|
+
ReadResourceResult,
|
|
23
|
+
ResourceTemplate,
|
|
24
|
+
TextContent,
|
|
25
|
+
)
|
|
26
|
+
from mcp.types import (
|
|
27
|
+
Tool as MCPTool,
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
__all__ = ["ResultSaved", "create_toolkit"]
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class MCPClient:
|
|
34
|
+
@staticmethod
|
|
35
|
+
def _convert_call_tool_result( # type: ignore[no-any-unimported]
|
|
36
|
+
call_tool_result: "CallToolResult", # type: ignore[no-any-unimported]
|
|
37
|
+
) -> tuple[Union[str, list[str]], Any]:
|
|
38
|
+
text_contents: list[TextContent] = [] # type: ignore[no-any-unimported]
|
|
39
|
+
non_text_contents = []
|
|
40
|
+
for content in call_tool_result.content:
|
|
41
|
+
if isinstance(content, TextContent):
|
|
42
|
+
text_contents.append(content)
|
|
43
|
+
else:
|
|
44
|
+
non_text_contents.append(content)
|
|
45
|
+
|
|
46
|
+
tool_content: Union[str, list[str]] = [content.text for content in text_contents]
|
|
47
|
+
if len(text_contents) == 1:
|
|
48
|
+
tool_content = tool_content[0]
|
|
49
|
+
|
|
50
|
+
if call_tool_result.isError:
|
|
51
|
+
raise ValueError(f"Tool call failed: {tool_content}")
|
|
52
|
+
|
|
53
|
+
return tool_content, non_text_contents or None
|
|
54
|
+
|
|
55
|
+
@classmethod
|
|
56
|
+
@require_optional_import("mcp", "mcp")
|
|
57
|
+
def convert_tool( # type: ignore[no-any-unimported]
|
|
58
|
+
cls, tool: Any, session: "ClientSession", **kwargs: Any
|
|
59
|
+
) -> Tool:
|
|
60
|
+
if not isinstance(tool, MCPTool):
|
|
61
|
+
raise ValueError(f"Expected an instance of `mcp.types.Tool`, got {type(tool)}")
|
|
62
|
+
|
|
63
|
+
# needed for type checking
|
|
64
|
+
mcp_tool: MCPTool = tool # type: ignore[no-any-unimported]
|
|
65
|
+
|
|
66
|
+
async def call_tool( # type: ignore[no-any-unimported]
|
|
67
|
+
**arguments: dict[str, Any],
|
|
68
|
+
) -> tuple[Union[str, list[str]], Any]:
|
|
69
|
+
call_tool_result = await session.call_tool(tool.name, arguments)
|
|
70
|
+
return MCPClient._convert_call_tool_result(call_tool_result)
|
|
71
|
+
|
|
72
|
+
ag2_tool = Tool(
|
|
73
|
+
name=mcp_tool.name,
|
|
74
|
+
description=mcp_tool.description,
|
|
75
|
+
func_or_tool=call_tool,
|
|
76
|
+
parameters_json_schema=mcp_tool.inputSchema,
|
|
77
|
+
)
|
|
78
|
+
return ag2_tool
|
|
79
|
+
|
|
80
|
+
@classmethod
|
|
81
|
+
@require_optional_import("mcp", "mcp")
|
|
82
|
+
def convert_resource( # type: ignore[no-any-unimported]
|
|
83
|
+
cls,
|
|
84
|
+
resource_template: Any,
|
|
85
|
+
session: "ClientSession",
|
|
86
|
+
resource_download_folder: Optional[Path],
|
|
87
|
+
**kwargs: Any,
|
|
88
|
+
) -> Tool:
|
|
89
|
+
if not isinstance(resource_template, ResourceTemplate):
|
|
90
|
+
raise ValueError(f"Expected an instance of `mcp.types.ResourceTemplate`, got {type(resource_template)}")
|
|
91
|
+
|
|
92
|
+
# needed for type checking
|
|
93
|
+
mcp_resource: ResourceTemplate = resource_template # type: ignore[no-any-unimported]
|
|
94
|
+
|
|
95
|
+
uri_description = f"""A URI template (according to RFC 6570) that can be used to construct resource URIs.
|
|
96
|
+
Here is the correct format for the URI template:
|
|
97
|
+
{mcp_resource.uriTemplate}
|
|
98
|
+
"""
|
|
99
|
+
|
|
100
|
+
async def call_resource(uri: Annotated[str, uri_description]) -> Union[ReadResourceResult, ResultSaved]: # type: ignore[no-any-unimported]
|
|
101
|
+
result = await session.read_resource(uri)
|
|
102
|
+
|
|
103
|
+
if not resource_download_folder:
|
|
104
|
+
return result
|
|
105
|
+
|
|
106
|
+
timestamp = datetime.now().strftime("%Y%m%d%H%M%S")
|
|
107
|
+
filename = uri.split("://")[-1] + f"_{timestamp}"
|
|
108
|
+
file_path = resource_download_folder / filename
|
|
109
|
+
|
|
110
|
+
async with await anyio.open_file(file_path, "w") as f:
|
|
111
|
+
await f.write(result.model_dump_json(indent=4))
|
|
112
|
+
|
|
113
|
+
return ResultSaved(
|
|
114
|
+
explanation=f"Request for uri {uri} was saved to {file_path}",
|
|
115
|
+
file_path=file_path,
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
# Wrap resource as AG2 tool
|
|
119
|
+
ag2_tool = Tool(
|
|
120
|
+
name=mcp_resource.name,
|
|
121
|
+
description=mcp_resource.description,
|
|
122
|
+
func_or_tool=call_resource,
|
|
123
|
+
)
|
|
124
|
+
return ag2_tool
|
|
125
|
+
|
|
126
|
+
@classmethod
|
|
127
|
+
@require_optional_import("mcp", "mcp")
|
|
128
|
+
async def load_mcp_toolkit(
|
|
129
|
+
cls,
|
|
130
|
+
session: "ClientSession",
|
|
131
|
+
*,
|
|
132
|
+
use_mcp_tools: bool,
|
|
133
|
+
use_mcp_resources: bool,
|
|
134
|
+
resource_download_folder: Optional[Path],
|
|
135
|
+
) -> Toolkit: # type: ignore[no-any-unimported]
|
|
136
|
+
"""Load all available MCP tools and convert them to AG2 Toolkit."""
|
|
137
|
+
all_ag2_tools: list[Tool] = []
|
|
138
|
+
|
|
139
|
+
if use_mcp_tools:
|
|
140
|
+
tools = await session.list_tools()
|
|
141
|
+
ag2_tools: list[Tool] = [cls.convert_tool(tool=tool, session=session) for tool in tools.tools]
|
|
142
|
+
all_ag2_tools.extend(ag2_tools)
|
|
143
|
+
|
|
144
|
+
if use_mcp_resources:
|
|
145
|
+
resource_templates = await session.list_resource_templates()
|
|
146
|
+
ag2_resources: list[Tool] = [
|
|
147
|
+
cls.convert_resource(
|
|
148
|
+
resource_template=resource_template,
|
|
149
|
+
session=session,
|
|
150
|
+
resource_download_folder=resource_download_folder,
|
|
151
|
+
)
|
|
152
|
+
for resource_template in resource_templates.resourceTemplates
|
|
153
|
+
]
|
|
154
|
+
all_ag2_tools.extend(ag2_resources)
|
|
155
|
+
|
|
156
|
+
return Toolkit(tools=all_ag2_tools)
|
|
157
|
+
|
|
158
|
+
@classmethod
|
|
159
|
+
def get_unsupported_reason(cls) -> Optional[str]:
|
|
160
|
+
if sys.version_info < (3, 10):
|
|
161
|
+
return "This submodule is only supported for Python versions 3.10 and above"
|
|
162
|
+
|
|
163
|
+
with optional_import_block() as result:
|
|
164
|
+
import mcp # noqa: F401
|
|
165
|
+
|
|
166
|
+
if not result.is_successful:
|
|
167
|
+
return "Please install `mcp` extra to use this module:\n\n\tpip install ag2[mcp]"
|
|
168
|
+
|
|
169
|
+
return None
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
@export_module("autogen.mcp")
|
|
173
|
+
async def create_toolkit(
|
|
174
|
+
session: "ClientSession",
|
|
175
|
+
*,
|
|
176
|
+
use_mcp_tools: bool = True,
|
|
177
|
+
use_mcp_resources: bool = True,
|
|
178
|
+
resource_download_folder: Optional[Union[Path, str]] = None,
|
|
179
|
+
) -> Toolkit: # type: ignore[no-any-unimported]
|
|
180
|
+
"""Create a toolkit from the MCP client session.
|
|
181
|
+
|
|
182
|
+
Args:
|
|
183
|
+
session (ClientSession): The MCP client session.
|
|
184
|
+
use_mcp_tools (bool): Whether to include MCP tools in the toolkit.
|
|
185
|
+
use_mcp_resources (bool): Whether to include MCP resources in the toolkit.
|
|
186
|
+
resource_download_folder (Optional[Union[Path, str]]): The folder to download files to.
|
|
187
|
+
Returns:
|
|
188
|
+
Toolkit: The toolkit containing the converted tools.
|
|
189
|
+
"""
|
|
190
|
+
if resource_download_folder:
|
|
191
|
+
if isinstance(resource_download_folder, str):
|
|
192
|
+
resource_download_folder = Path(resource_download_folder)
|
|
193
|
+
await anyio.to_thread.run_sync(lambda: resource_download_folder.mkdir(parents=True, exist_ok=True))
|
|
194
|
+
|
|
195
|
+
return await MCPClient.load_mcp_toolkit(
|
|
196
|
+
session=session,
|
|
197
|
+
use_mcp_tools=use_mcp_tools,
|
|
198
|
+
use_mcp_resources=use_mcp_resources,
|
|
199
|
+
resource_download_folder=resource_download_folder,
|
|
200
|
+
)
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
@export_module("autogen.mcp.mcp_client")
|
|
204
|
+
class ResultSaved(BaseModel):
|
|
205
|
+
"""Result saved to a file"""
|
|
206
|
+
|
|
207
|
+
explanation: str
|
|
208
|
+
file_path: Path
|
|
@@ -0,0 +1,19 @@
|
|
|
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 autogen.import_utils import optional_import_block
|
|
6
|
+
|
|
7
|
+
from .patch_fastapi_code_generator import ( # noqa: E402
|
|
8
|
+
SUCCESFUL_IMPORT,
|
|
9
|
+
patch_function_name_parsing,
|
|
10
|
+
patch_generate_code,
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
if SUCCESFUL_IMPORT:
|
|
14
|
+
patch_function_name_parsing()
|
|
15
|
+
patch_generate_code()
|
|
16
|
+
|
|
17
|
+
from .mcp_proxy import MCPProxy # noqa: E402
|
|
18
|
+
|
|
19
|
+
__all__ = ["MCPProxy", "optional_import_block"]
|