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,643 @@
|
|
|
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 logging
|
|
6
|
+
from copy import deepcopy
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from typing import Annotated, Any, cast
|
|
9
|
+
|
|
10
|
+
from pydantic import BaseModel, Field
|
|
11
|
+
|
|
12
|
+
from .... import Agent, ConversableAgent, UpdateSystemMessage
|
|
13
|
+
from ....agentchat.contrib.rag.query_engine import RAGQueryEngine
|
|
14
|
+
from ....agentchat.group.context_condition import ExpressionContextCondition
|
|
15
|
+
from ....agentchat.group.context_expression import ContextExpression
|
|
16
|
+
from ....agentchat.group.context_variables import ContextVariables
|
|
17
|
+
from ....agentchat.group.llm_condition import StringLLMCondition
|
|
18
|
+
from ....agentchat.group.multi_agent_chat import initiate_group_chat
|
|
19
|
+
from ....agentchat.group.on_condition import OnCondition
|
|
20
|
+
from ....agentchat.group.on_context_condition import OnContextCondition
|
|
21
|
+
from ....agentchat.group.patterns.pattern import DefaultPattern
|
|
22
|
+
from ....agentchat.group.reply_result import ReplyResult
|
|
23
|
+
from ....agentchat.group.targets.transition_target import AgentNameTarget, AgentTarget, StayTarget, TerminateTarget
|
|
24
|
+
from ....doc_utils import export_module
|
|
25
|
+
from ....llm_config import LLMConfig
|
|
26
|
+
from ....oai.client import OpenAIWrapper
|
|
27
|
+
from .chroma_query_engine import VectorChromaQueryEngine
|
|
28
|
+
from .docling_doc_ingest_agent import DoclingDocIngestAgent
|
|
29
|
+
from .document_conditions import SummaryTaskAvailableCondition
|
|
30
|
+
from .document_utils import Ingest, Query
|
|
31
|
+
|
|
32
|
+
__all__ = ["DocAgent"]
|
|
33
|
+
|
|
34
|
+
logger = logging.getLogger(__name__)
|
|
35
|
+
|
|
36
|
+
DEFAULT_SYSTEM_MESSAGE = """
|
|
37
|
+
You are a document agent.
|
|
38
|
+
You are given a list of documents to ingest and a list of queries to perform.
|
|
39
|
+
You are responsible for ingesting the documents and answering the queries.
|
|
40
|
+
"""
|
|
41
|
+
TASK_MANAGER_NAME = "TaskManagerAgent"
|
|
42
|
+
TASK_MANAGER_SYSTEM_MESSAGE = """
|
|
43
|
+
You are a task manager agent. You have 2 priorities:
|
|
44
|
+
1. You initiate the tasks which updates the context variables based on the task decisions (DocumentTask) from the DocumentTriageAgent.
|
|
45
|
+
ALWAYS call initiate_tasks first when you receive a message from the DocumentTriageAgent, even if you think there are no new tasks.
|
|
46
|
+
This ensures that any new ingestions or queries from the triage agent are properly recorded.
|
|
47
|
+
Put all ingestion and query tasks into the one tool call.
|
|
48
|
+
i.e. output
|
|
49
|
+
{
|
|
50
|
+
"ingestions": [
|
|
51
|
+
{
|
|
52
|
+
"path_or_url": "path_or_url"
|
|
53
|
+
}
|
|
54
|
+
],
|
|
55
|
+
"queries": [
|
|
56
|
+
{
|
|
57
|
+
"query_type": "RAG_QUERY",
|
|
58
|
+
"query": "query"
|
|
59
|
+
}
|
|
60
|
+
],
|
|
61
|
+
"query_results": [
|
|
62
|
+
{
|
|
63
|
+
"query": "query",
|
|
64
|
+
"result": "result"
|
|
65
|
+
}
|
|
66
|
+
]
|
|
67
|
+
}
|
|
68
|
+
2. If there are no documents to ingest and no queries to run, hand control off to the summary agent.
|
|
69
|
+
|
|
70
|
+
Put all file paths and URLs into the ingestions. A http/https URL is also a valid path and should be ingested.
|
|
71
|
+
|
|
72
|
+
Use the initiate_tasks tool to incorporate all ingestions and queries. Don't call it again until new ingestions or queries are raised.
|
|
73
|
+
|
|
74
|
+
New ingestions and queries may be raised from time to time, so use the initiate_tasks again if you see new ingestions/queries.
|
|
75
|
+
|
|
76
|
+
Once the ingestion and query tasks are done, return to the summary agent, do not ask questions of the user.
|
|
77
|
+
"""
|
|
78
|
+
|
|
79
|
+
DEFAULT_ERROR_GROUP_CHAT_MESSAGE: str = """
|
|
80
|
+
Document Agent failed to perform task.
|
|
81
|
+
"""
|
|
82
|
+
|
|
83
|
+
ERROR_MANAGER_NAME = "ErrorManagerAgent"
|
|
84
|
+
ERROR_MANAGER_SYSTEM_MESSAGE = """
|
|
85
|
+
You communicate errors to the user. Include the original error messages in full. Use the format:
|
|
86
|
+
The following error(s) have occurred:
|
|
87
|
+
- Error 1
|
|
88
|
+
- Error 2
|
|
89
|
+
"""
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
class DocumentTask(BaseModel):
|
|
93
|
+
"""The structured output format for task decisions."""
|
|
94
|
+
|
|
95
|
+
ingestions: list[Ingest] = Field(description="The list of documents to ingest.")
|
|
96
|
+
queries: list[Query] = Field(description="The list of queries to perform.")
|
|
97
|
+
|
|
98
|
+
def format(self) -> str:
|
|
99
|
+
"""Format the DocumentTask as a string for the TaskManager to work with."""
|
|
100
|
+
if len(self.ingestions) == 0 and len(self.queries) == 0:
|
|
101
|
+
return "There were no ingestion or query tasks detected."
|
|
102
|
+
|
|
103
|
+
instructions = "Tasks:\n\n"
|
|
104
|
+
order = 1
|
|
105
|
+
|
|
106
|
+
if len(self.ingestions) > 0:
|
|
107
|
+
instructions += "Ingestions:\n"
|
|
108
|
+
for ingestion in self.ingestions:
|
|
109
|
+
instructions += f"{order}: {ingestion.path_or_url}\n"
|
|
110
|
+
order += 1
|
|
111
|
+
|
|
112
|
+
instructions += "\n"
|
|
113
|
+
|
|
114
|
+
if len(self.queries) > 0:
|
|
115
|
+
instructions += "Queries:\n"
|
|
116
|
+
for query in self.queries:
|
|
117
|
+
instructions += f"{order}: {query.query}\n"
|
|
118
|
+
order += 1
|
|
119
|
+
|
|
120
|
+
return instructions
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
class DocumentTriageAgent(ConversableAgent):
|
|
124
|
+
"""The DocumentTriageAgent is responsible for deciding what type of task to perform from user requests."""
|
|
125
|
+
|
|
126
|
+
def __init__(self, llm_config: LLMConfig | dict[str, Any] | None = None):
|
|
127
|
+
# Add the structured message to the LLM configuration
|
|
128
|
+
structured_config_list = deepcopy(llm_config)
|
|
129
|
+
structured_config_list["response_format"] = DocumentTask # type: ignore[index]
|
|
130
|
+
|
|
131
|
+
super().__init__(
|
|
132
|
+
name="DocumentTriageAgent",
|
|
133
|
+
system_message=(
|
|
134
|
+
"You are a document triage agent. "
|
|
135
|
+
"You are responsible for deciding what type of task to perform from a user's request and populating a DocumentTask formatted response. "
|
|
136
|
+
"If the user specifies files or URLs, add them as individual 'ingestions' to DocumentTask. "
|
|
137
|
+
"You can access external websites if given a URL, so put them in as ingestions. "
|
|
138
|
+
"Add the user's questions about the files/URLs as individual 'RAG_QUERY' queries to the 'query' list in the DocumentTask. "
|
|
139
|
+
"Don't make up questions, keep it as concise and close to the user's request as possible."
|
|
140
|
+
),
|
|
141
|
+
human_input_mode="NEVER",
|
|
142
|
+
llm_config=structured_config_list,
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
@export_module("autogen.agents.experimental")
|
|
147
|
+
class DocAgent(ConversableAgent):
|
|
148
|
+
"""The DocAgent is responsible for ingest and querying documents.
|
|
149
|
+
|
|
150
|
+
Internally, it generates a group chat with a set of agents to ingest, query, and summarize.
|
|
151
|
+
"""
|
|
152
|
+
|
|
153
|
+
def __init__(
|
|
154
|
+
self,
|
|
155
|
+
name: str | None = None,
|
|
156
|
+
llm_config: LLMConfig | dict[str, Any] | None = None,
|
|
157
|
+
system_message: str | None = None,
|
|
158
|
+
parsed_docs_path: str | Path | None = None,
|
|
159
|
+
collection_name: str | None = None,
|
|
160
|
+
query_engine: RAGQueryEngine | None = None,
|
|
161
|
+
):
|
|
162
|
+
"""Initialize the DocAgent.
|
|
163
|
+
|
|
164
|
+
Args:
|
|
165
|
+
name (Optional[str]): The name of the DocAgent.
|
|
166
|
+
llm_config (Optional[LLMConfig, dict[str, Any]]): The configuration for the LLM.
|
|
167
|
+
system_message (Optional[str]): The system message for the DocAgent.
|
|
168
|
+
parsed_docs_path (Union[str, Path]): The path where parsed documents will be stored.
|
|
169
|
+
collection_name (Optional[str]): The unique name for the data store collection. If omitted, a random name will be used. Populate this to reuse previous ingested data.
|
|
170
|
+
query_engine (Optional[RAGQueryEngine]): The query engine to use for querying documents, defaults to VectorChromaQueryEngine if none provided.
|
|
171
|
+
Use enable_query_citations and implement query_with_citations method to enable citation support. e.g. VectorChromaCitationQueryEngine
|
|
172
|
+
|
|
173
|
+
The DocAgent is responsible for generating a group of agents to solve a task.
|
|
174
|
+
|
|
175
|
+
The agents that the DocAgent generates are:
|
|
176
|
+
- Triage Agent: responsible for deciding what type of task to perform from user requests.
|
|
177
|
+
- Task Manager Agent: responsible for managing the tasks.
|
|
178
|
+
- Parser Agent: responsible for parsing the documents.
|
|
179
|
+
- Data Ingestion Agent: responsible for ingesting the documents.
|
|
180
|
+
- Query Agent: responsible for answering the user's questions.
|
|
181
|
+
- Error Agent: responsible for returning errors gracefully.
|
|
182
|
+
- Summary Agent: responsible for generating a summary of the user's questions.
|
|
183
|
+
"""
|
|
184
|
+
name = name or "DocAgent"
|
|
185
|
+
llm_config = llm_config or LLMConfig.get_current_llm_config()
|
|
186
|
+
system_message = system_message or DEFAULT_SYSTEM_MESSAGE
|
|
187
|
+
parsed_docs_path = parsed_docs_path or "./parsed_docs"
|
|
188
|
+
|
|
189
|
+
# Default Query Engine will be ChromaDB
|
|
190
|
+
if query_engine is None:
|
|
191
|
+
query_engine = VectorChromaQueryEngine(collection_name=collection_name)
|
|
192
|
+
|
|
193
|
+
super().__init__(
|
|
194
|
+
name=name,
|
|
195
|
+
system_message=system_message,
|
|
196
|
+
llm_config=llm_config,
|
|
197
|
+
human_input_mode="NEVER",
|
|
198
|
+
)
|
|
199
|
+
self.register_reply([ConversableAgent, None], self.generate_inner_group_chat_reply, position=0)
|
|
200
|
+
|
|
201
|
+
self._triage_agent = DocumentTriageAgent(llm_config=llm_config)
|
|
202
|
+
|
|
203
|
+
def create_error_agent_prompt(agent: ConversableAgent, messages: list[dict[str, Any]]) -> str:
|
|
204
|
+
"""Create the error agent prompt, primarily used to update ingested documents for ending.
|
|
205
|
+
|
|
206
|
+
Args:
|
|
207
|
+
agent: The conversable agent requesting the prompt
|
|
208
|
+
messages: List of conversation messages
|
|
209
|
+
|
|
210
|
+
Returns:
|
|
211
|
+
str: The error manager system message
|
|
212
|
+
"""
|
|
213
|
+
update_ingested_documents()
|
|
214
|
+
|
|
215
|
+
return ERROR_MANAGER_SYSTEM_MESSAGE
|
|
216
|
+
|
|
217
|
+
self._error_agent = ConversableAgent(
|
|
218
|
+
name=ERROR_MANAGER_NAME,
|
|
219
|
+
system_message=ERROR_MANAGER_SYSTEM_MESSAGE,
|
|
220
|
+
llm_config=llm_config,
|
|
221
|
+
update_agent_state_before_reply=[UpdateSystemMessage(create_error_agent_prompt)],
|
|
222
|
+
)
|
|
223
|
+
|
|
224
|
+
def update_ingested_documents() -> None:
|
|
225
|
+
"""Updates the list of ingested documents, persisted so we can keep a list over multiple replies.
|
|
226
|
+
|
|
227
|
+
This function updates self.documents_ingested with any new documents that have been ingested
|
|
228
|
+
by the triage agent, ensuring persistence across multiple DocAgent interactions.
|
|
229
|
+
"""
|
|
230
|
+
agent_documents_ingested = self._triage_agent.context_variables.get("DocumentsIngested", [])
|
|
231
|
+
# Update self.documents_ingested with any new documents ingested
|
|
232
|
+
for doc in agent_documents_ingested: # type: ignore[union-attr]
|
|
233
|
+
if doc not in self.documents_ingested:
|
|
234
|
+
self.documents_ingested.append(doc)
|
|
235
|
+
|
|
236
|
+
class TaskInitInfo(BaseModel):
|
|
237
|
+
ingestions: Annotated[list[Ingest], Field(description="List of documents, files, and URLs to ingest")]
|
|
238
|
+
queries: Annotated[list[Query], Field(description="List of queries to run")]
|
|
239
|
+
|
|
240
|
+
def _deduplicate_ingestions(
|
|
241
|
+
new_ingestions: list[Ingest], existing_ingestions: list[Ingest], documents_ingested: list[str]
|
|
242
|
+
) -> tuple[list[Ingest], list[str]]:
|
|
243
|
+
"""Deduplicate ingestions against existing pending and already ingested documents.
|
|
244
|
+
|
|
245
|
+
Args:
|
|
246
|
+
new_ingestions: List of new ingestion requests to process
|
|
247
|
+
existing_ingestions: List of ingestions already pending
|
|
248
|
+
documents_ingested: List of document paths already ingested
|
|
249
|
+
|
|
250
|
+
Returns:
|
|
251
|
+
tuple: (new_unique_ingestions, ignored_duplicate_paths)
|
|
252
|
+
"""
|
|
253
|
+
unique_ingestions = []
|
|
254
|
+
ignored_paths = []
|
|
255
|
+
|
|
256
|
+
for ingestion in new_ingestions:
|
|
257
|
+
ingestion_path = ingestion.path_or_url
|
|
258
|
+
# Check if already in pending ingestions
|
|
259
|
+
already_pending = any(existing.path_or_url == ingestion_path for existing in existing_ingestions)
|
|
260
|
+
# Check if already ingested
|
|
261
|
+
already_ingested = ingestion_path in documents_ingested
|
|
262
|
+
|
|
263
|
+
if already_pending or already_ingested:
|
|
264
|
+
ignored_paths.append(ingestion_path)
|
|
265
|
+
else:
|
|
266
|
+
unique_ingestions.append(ingestion)
|
|
267
|
+
|
|
268
|
+
return unique_ingestions, ignored_paths
|
|
269
|
+
|
|
270
|
+
def _deduplicate_queries(
|
|
271
|
+
new_queries: list[Query], existing_queries: list[Query]
|
|
272
|
+
) -> tuple[list[Query], list[str]]:
|
|
273
|
+
"""Deduplicate queries against existing pending queries.
|
|
274
|
+
|
|
275
|
+
Args:
|
|
276
|
+
new_queries: List of new query requests to process
|
|
277
|
+
existing_queries: List of queries already pending
|
|
278
|
+
|
|
279
|
+
Returns:
|
|
280
|
+
tuple: (new_unique_queries, ignored_duplicate_query_texts)
|
|
281
|
+
"""
|
|
282
|
+
unique_queries = []
|
|
283
|
+
ignored_query_texts = []
|
|
284
|
+
|
|
285
|
+
for query in new_queries:
|
|
286
|
+
query_text = query.query
|
|
287
|
+
# Check if query already exists in pending queries
|
|
288
|
+
already_pending = any(existing.query == query_text for existing in existing_queries)
|
|
289
|
+
|
|
290
|
+
if already_pending:
|
|
291
|
+
ignored_query_texts.append(query_text)
|
|
292
|
+
else:
|
|
293
|
+
unique_queries.append(query)
|
|
294
|
+
|
|
295
|
+
return unique_queries, ignored_query_texts
|
|
296
|
+
|
|
297
|
+
def _build_response_message(
|
|
298
|
+
added_ingestions: int, ignored_ingestions: list[str], added_queries: int, ignored_queries: list[str]
|
|
299
|
+
) -> str:
|
|
300
|
+
"""Build a descriptive response message about what was added/ignored.
|
|
301
|
+
|
|
302
|
+
Args:
|
|
303
|
+
added_ingestions: Number of unique ingestions added
|
|
304
|
+
ignored_ingestions: List of duplicate ingestion paths ignored
|
|
305
|
+
added_queries: Number of unique queries added
|
|
306
|
+
ignored_queries: List of duplicate query texts ignored
|
|
307
|
+
|
|
308
|
+
Returns:
|
|
309
|
+
str: Formatted message describing the results
|
|
310
|
+
"""
|
|
311
|
+
messages = []
|
|
312
|
+
|
|
313
|
+
if added_ingestions > 0:
|
|
314
|
+
messages.append(f"Added {added_ingestions} new document(s) for ingestion")
|
|
315
|
+
|
|
316
|
+
if ignored_ingestions:
|
|
317
|
+
messages.append(
|
|
318
|
+
f"Ignored {len(ignored_ingestions)} duplicate document(s): {', '.join(ignored_ingestions)}"
|
|
319
|
+
)
|
|
320
|
+
|
|
321
|
+
if added_queries > 0:
|
|
322
|
+
messages.append(f"Added {added_queries} new query/queries")
|
|
323
|
+
|
|
324
|
+
if ignored_queries:
|
|
325
|
+
messages.append(f"Ignored {len(ignored_queries)} duplicate query/queries: {', '.join(ignored_queries)}")
|
|
326
|
+
|
|
327
|
+
if messages:
|
|
328
|
+
return "; ".join(messages)
|
|
329
|
+
else:
|
|
330
|
+
return "All requested tasks were duplicates and ignored"
|
|
331
|
+
|
|
332
|
+
def initiate_tasks(
|
|
333
|
+
task_init_info: Annotated[TaskInitInfo, "Documents, Files, URLs to ingest and the queries to run"],
|
|
334
|
+
context_variables: Annotated[ContextVariables, "Context variables"],
|
|
335
|
+
) -> ReplyResult:
|
|
336
|
+
"""Add documents to ingest and queries to answer when received.
|
|
337
|
+
|
|
338
|
+
Args:
|
|
339
|
+
task_init_info: Information about documents to ingest and queries to run
|
|
340
|
+
context_variables: The current context variables containing task state
|
|
341
|
+
|
|
342
|
+
Returns:
|
|
343
|
+
ReplyResult: Contains response message, updated context, and target agent
|
|
344
|
+
"""
|
|
345
|
+
ingestions = task_init_info.ingestions
|
|
346
|
+
queries = task_init_info.queries
|
|
347
|
+
|
|
348
|
+
if "TaskInitiated" in context_variables:
|
|
349
|
+
# Handle follow-up tasks with deduplication
|
|
350
|
+
added_ingestions_count = 0
|
|
351
|
+
ignored_ingestions = []
|
|
352
|
+
added_queries_count = 0
|
|
353
|
+
ignored_queries = []
|
|
354
|
+
|
|
355
|
+
if ingestions:
|
|
356
|
+
existing_ingestions: list[Ingest] = context_variables.get("DocumentsToIngest", []) # type: ignore[assignment]
|
|
357
|
+
documents_ingested: list[str] = context_variables.get("DocumentsIngested", []) # type: ignore[assignment]
|
|
358
|
+
|
|
359
|
+
unique_ingestions, ignored_ingestion_paths = _deduplicate_ingestions(
|
|
360
|
+
ingestions, existing_ingestions, documents_ingested
|
|
361
|
+
)
|
|
362
|
+
|
|
363
|
+
if unique_ingestions:
|
|
364
|
+
context_variables["DocumentsToIngest"] = existing_ingestions + unique_ingestions
|
|
365
|
+
added_ingestions_count = len(unique_ingestions)
|
|
366
|
+
|
|
367
|
+
ignored_ingestions = ignored_ingestion_paths
|
|
368
|
+
|
|
369
|
+
if queries:
|
|
370
|
+
existing_queries: list[Query] = context_variables.get("QueriesToRun", []) # type: ignore[assignment]
|
|
371
|
+
|
|
372
|
+
unique_queries, ignored_query_texts = _deduplicate_queries(queries, existing_queries)
|
|
373
|
+
|
|
374
|
+
if unique_queries:
|
|
375
|
+
context_variables["QueriesToRun"] = existing_queries + unique_queries
|
|
376
|
+
added_queries_count = len(unique_queries)
|
|
377
|
+
|
|
378
|
+
ignored_queries = ignored_query_texts
|
|
379
|
+
|
|
380
|
+
if not ingestions and not queries:
|
|
381
|
+
return ReplyResult(message="No new tasks to initiate", context_variables=context_variables)
|
|
382
|
+
|
|
383
|
+
response_message = _build_response_message(
|
|
384
|
+
added_ingestions_count, ignored_ingestions, added_queries_count, ignored_queries
|
|
385
|
+
)
|
|
386
|
+
|
|
387
|
+
else:
|
|
388
|
+
# First time initialization - no deduplication needed
|
|
389
|
+
context_variables["DocumentsToIngest"] = ingestions
|
|
390
|
+
context_variables["QueriesToRun"] = list(queries)
|
|
391
|
+
context_variables["TaskInitiated"] = True
|
|
392
|
+
response_message = "Updated context variables with task decisions"
|
|
393
|
+
|
|
394
|
+
return ReplyResult(
|
|
395
|
+
message=response_message,
|
|
396
|
+
context_variables=context_variables,
|
|
397
|
+
target=AgentNameTarget(agent_name=TASK_MANAGER_NAME),
|
|
398
|
+
)
|
|
399
|
+
|
|
400
|
+
self._task_manager_agent = ConversableAgent(
|
|
401
|
+
name=TASK_MANAGER_NAME,
|
|
402
|
+
system_message=TASK_MANAGER_SYSTEM_MESSAGE,
|
|
403
|
+
llm_config=llm_config,
|
|
404
|
+
functions=[initiate_tasks],
|
|
405
|
+
)
|
|
406
|
+
|
|
407
|
+
self._triage_agent.handoffs.set_after_work(target=AgentTarget(agent=self._task_manager_agent))
|
|
408
|
+
|
|
409
|
+
self._data_ingestion_agent = DoclingDocIngestAgent(
|
|
410
|
+
llm_config=llm_config,
|
|
411
|
+
query_engine=query_engine,
|
|
412
|
+
parsed_docs_path=parsed_docs_path,
|
|
413
|
+
return_agent_success=TASK_MANAGER_NAME,
|
|
414
|
+
return_agent_error=ERROR_MANAGER_NAME,
|
|
415
|
+
)
|
|
416
|
+
|
|
417
|
+
def execute_rag_query(context_variables: ContextVariables) -> ReplyResult: # type: ignore[type-arg]
|
|
418
|
+
"""Execute outstanding RAG queries, call the tool once for each outstanding query. Call this tool with no arguments.
|
|
419
|
+
|
|
420
|
+
Args:
|
|
421
|
+
context_variables: The current context variables containing queries to run
|
|
422
|
+
|
|
423
|
+
Returns:
|
|
424
|
+
ReplyResult: Contains query answer, updated context, and target agent
|
|
425
|
+
"""
|
|
426
|
+
if len(context_variables["QueriesToRun"]) == 0:
|
|
427
|
+
return ReplyResult(
|
|
428
|
+
target=AgentNameTarget(agent_name=TASK_MANAGER_NAME),
|
|
429
|
+
message="No queries to run",
|
|
430
|
+
context_variables=context_variables,
|
|
431
|
+
)
|
|
432
|
+
|
|
433
|
+
query = context_variables["QueriesToRun"][0].query
|
|
434
|
+
try:
|
|
435
|
+
if (
|
|
436
|
+
hasattr(query_engine, "enable_query_citations")
|
|
437
|
+
and query_engine.enable_query_citations
|
|
438
|
+
and hasattr(query_engine, "query_with_citations")
|
|
439
|
+
and callable(query_engine.query_with_citations)
|
|
440
|
+
):
|
|
441
|
+
answer_with_citations = query_engine.query_with_citations(query) # type: ignore[union-attr]
|
|
442
|
+
answer = answer_with_citations.answer
|
|
443
|
+
txt_citations = [
|
|
444
|
+
{
|
|
445
|
+
"text_chunk": source.node.get_text(),
|
|
446
|
+
"file_path": source.metadata["file_path"],
|
|
447
|
+
}
|
|
448
|
+
for source in answer_with_citations.citations
|
|
449
|
+
]
|
|
450
|
+
logger.info(f"Citations:\n {txt_citations}")
|
|
451
|
+
else:
|
|
452
|
+
answer = query_engine.query(query)
|
|
453
|
+
txt_citations = []
|
|
454
|
+
context_variables["QueriesToRun"].pop(0)
|
|
455
|
+
context_variables["CompletedTaskCount"] += 1
|
|
456
|
+
context_variables["QueryResults"].append({"query": query, "answer": answer, "citations": txt_citations})
|
|
457
|
+
|
|
458
|
+
# Query completed
|
|
459
|
+
|
|
460
|
+
return ReplyResult(message=answer, context_variables=context_variables)
|
|
461
|
+
except Exception as e:
|
|
462
|
+
return ReplyResult(
|
|
463
|
+
target=AgentNameTarget(agent_name=ERROR_MANAGER_NAME),
|
|
464
|
+
message=f"Query failed for '{query}': {e}",
|
|
465
|
+
context_variables=context_variables,
|
|
466
|
+
)
|
|
467
|
+
|
|
468
|
+
self._query_agent = ConversableAgent(
|
|
469
|
+
name="QueryAgent",
|
|
470
|
+
system_message="""
|
|
471
|
+
You are a query agent.
|
|
472
|
+
You answer the user's questions only using the query function provided to you.
|
|
473
|
+
You can only call use the execute_rag_query tool once per turn.
|
|
474
|
+
""",
|
|
475
|
+
llm_config=llm_config,
|
|
476
|
+
functions=[execute_rag_query],
|
|
477
|
+
)
|
|
478
|
+
|
|
479
|
+
# Summary agent prompt will include the results of the ingestions and queries
|
|
480
|
+
def create_summary_agent_prompt(agent: ConversableAgent, messages: list[dict[str, Any]]) -> str:
|
|
481
|
+
"""Create the summary agent prompt and updates ingested documents.
|
|
482
|
+
|
|
483
|
+
Args:
|
|
484
|
+
agent: The conversable agent requesting the prompt
|
|
485
|
+
messages: List of conversation messages
|
|
486
|
+
|
|
487
|
+
Returns:
|
|
488
|
+
str: The summary agent system message with context information
|
|
489
|
+
"""
|
|
490
|
+
update_ingested_documents()
|
|
491
|
+
|
|
492
|
+
documents_to_ingest: list[Ingest] = cast(list[Ingest], agent.context_variables.get("DocumentsToIngest", []))
|
|
493
|
+
queries_to_run: list[Query] = cast(list[Query], agent.context_variables.get("QueriesToRun", []))
|
|
494
|
+
|
|
495
|
+
system_message = (
|
|
496
|
+
"You are a summary agent and you provide a summary of all completed tasks and the list of queries and their answers. "
|
|
497
|
+
"Output two sections: 'Ingestions:' and 'Queries:' with the results of the tasks. Number the ingestions and queries. "
|
|
498
|
+
"If there are no ingestions output 'No ingestions', if there are no queries output 'No queries' under their respective sections. "
|
|
499
|
+
"Don't add markdown formatting. "
|
|
500
|
+
"For each query, there is one answer and, optionally, a list of citations."
|
|
501
|
+
"For each citation, it contains two fields: 'text_chunk' and 'file_path'."
|
|
502
|
+
"Format the Query and Answers and Citations as 'Query:\nAnswer:\n\nCitations:'. Add a number to each query if more than one. Use the context below:\n"
|
|
503
|
+
"For each query, output the full citation contents and list them one by one,"
|
|
504
|
+
"format each citation as '\nSource [X] (chunk file_path here):\n\nChunk X:\n(text_chunk here)' and mark a separator between each citation using '\n#########################\n\n'."
|
|
505
|
+
"If there are no citations at all, DON'T INCLUDE ANY mention of citations.\n"
|
|
506
|
+
f"Documents ingested: {documents_to_ingest}\n"
|
|
507
|
+
f"Documents left to ingest: {len(documents_to_ingest)}\n"
|
|
508
|
+
f"Queries left to run: {len(queries_to_run)}\n"
|
|
509
|
+
f"Query and Answers and Citations: {queries_to_run}\n"
|
|
510
|
+
)
|
|
511
|
+
|
|
512
|
+
return system_message
|
|
513
|
+
|
|
514
|
+
self._summary_agent = ConversableAgent(
|
|
515
|
+
name="SummaryAgent",
|
|
516
|
+
llm_config=llm_config,
|
|
517
|
+
update_agent_state_before_reply=[UpdateSystemMessage(create_summary_agent_prompt)],
|
|
518
|
+
)
|
|
519
|
+
|
|
520
|
+
self._task_manager_agent.register_handoffs([
|
|
521
|
+
OnContextCondition( # Go straight to data ingestion agent if we have documents to ingest
|
|
522
|
+
target=AgentTarget(agent=self._data_ingestion_agent),
|
|
523
|
+
condition=ExpressionContextCondition(
|
|
524
|
+
expression=ContextExpression(expression="len(${DocumentsToIngest}) > 0")
|
|
525
|
+
),
|
|
526
|
+
),
|
|
527
|
+
OnContextCondition( # Go to Query agent if we have queries to run (ingestion above run first)
|
|
528
|
+
target=AgentTarget(agent=self._query_agent),
|
|
529
|
+
condition=ExpressionContextCondition(
|
|
530
|
+
expression=ContextExpression(expression="len(${QueriesToRun}) > 0")
|
|
531
|
+
),
|
|
532
|
+
),
|
|
533
|
+
# Removed automatic context condition - let task manager decide when to summarize
|
|
534
|
+
OnCondition(
|
|
535
|
+
target=AgentTarget(agent=self._summary_agent),
|
|
536
|
+
condition=StringLLMCondition(
|
|
537
|
+
prompt="Call this function if all work is done and a summary will be created"
|
|
538
|
+
),
|
|
539
|
+
available=SummaryTaskAvailableCondition(), # Custom AvailableCondition class
|
|
540
|
+
),
|
|
541
|
+
])
|
|
542
|
+
self._task_manager_agent.handoffs.set_after_work(target=StayTarget())
|
|
543
|
+
|
|
544
|
+
self._data_ingestion_agent.handoffs.set_after_work(target=AgentTarget(agent=self._task_manager_agent))
|
|
545
|
+
|
|
546
|
+
self._query_agent.handoffs.set_after_work(target=AgentTarget(agent=self._task_manager_agent))
|
|
547
|
+
|
|
548
|
+
# Summary agent terminates the DocumentAgent
|
|
549
|
+
self._summary_agent.handoffs.set_after_work(target=TerminateTarget())
|
|
550
|
+
|
|
551
|
+
# The Error Agent always terminates the DocumentAgent
|
|
552
|
+
self._error_agent.handoffs.set_after_work(target=TerminateTarget())
|
|
553
|
+
|
|
554
|
+
self.register_reply([Agent, None], DocAgent.generate_inner_group_chat_reply)
|
|
555
|
+
|
|
556
|
+
self.documents_ingested: list[str] = []
|
|
557
|
+
self._group_chat_context_variables: ContextVariables | None = None
|
|
558
|
+
|
|
559
|
+
def generate_inner_group_chat_reply(
|
|
560
|
+
self,
|
|
561
|
+
messages: list[dict[str, Any]] | str | None = None,
|
|
562
|
+
sender: Agent | None = None,
|
|
563
|
+
config: OpenAIWrapper | None = None,
|
|
564
|
+
) -> tuple[bool, str | dict[str, Any] | None]:
|
|
565
|
+
"""Reply function that generates the inner group chat reply for the DocAgent.
|
|
566
|
+
|
|
567
|
+
Args:
|
|
568
|
+
messages: Input messages to process
|
|
569
|
+
sender: The agent that sent the message
|
|
570
|
+
config: OpenAI wrapper configuration
|
|
571
|
+
|
|
572
|
+
Returns:
|
|
573
|
+
tuple: (should_terminate, reply_message)
|
|
574
|
+
"""
|
|
575
|
+
# Use existing context_variables if available, otherwise create new ones
|
|
576
|
+
if hasattr(self, "_group_chat_context_variables") and self._group_chat_context_variables is not None:
|
|
577
|
+
context_variables = self._group_chat_context_variables
|
|
578
|
+
# Reset for the new run
|
|
579
|
+
context_variables["DocumentsToIngest"] = [] # type: ignore[index]
|
|
580
|
+
else:
|
|
581
|
+
context_variables = ContextVariables(
|
|
582
|
+
data={
|
|
583
|
+
"CompletedTaskCount": 0,
|
|
584
|
+
"DocumentsToIngest": [],
|
|
585
|
+
"DocumentsIngested": self.documents_ingested,
|
|
586
|
+
"QueriesToRun": [],
|
|
587
|
+
"QueryResults": [],
|
|
588
|
+
}
|
|
589
|
+
)
|
|
590
|
+
self._group_chat_context_variables = context_variables
|
|
591
|
+
|
|
592
|
+
group_chat_agents = [
|
|
593
|
+
self._triage_agent,
|
|
594
|
+
self._task_manager_agent,
|
|
595
|
+
self._data_ingestion_agent,
|
|
596
|
+
self._query_agent,
|
|
597
|
+
self._summary_agent,
|
|
598
|
+
self._error_agent,
|
|
599
|
+
]
|
|
600
|
+
|
|
601
|
+
agent_pattern = DefaultPattern(
|
|
602
|
+
initial_agent=self._triage_agent,
|
|
603
|
+
agents=group_chat_agents,
|
|
604
|
+
context_variables=context_variables,
|
|
605
|
+
group_after_work=TerminateTarget(),
|
|
606
|
+
)
|
|
607
|
+
|
|
608
|
+
chat_result, context_variables, last_speaker = initiate_group_chat(
|
|
609
|
+
pattern=agent_pattern,
|
|
610
|
+
messages=self._get_document_input_message(messages),
|
|
611
|
+
)
|
|
612
|
+
if last_speaker == self._error_agent:
|
|
613
|
+
# If we finish with the error agent, we return their message which contains the error
|
|
614
|
+
return True, chat_result.summary
|
|
615
|
+
if last_speaker != self._summary_agent:
|
|
616
|
+
# If the group chat finished but not with the summary agent, we assume something has gone wrong with the flow
|
|
617
|
+
return True, DEFAULT_ERROR_GROUP_CHAT_MESSAGE
|
|
618
|
+
|
|
619
|
+
return True, chat_result.summary
|
|
620
|
+
|
|
621
|
+
def _get_document_input_message(self, messages: list[dict[str, Any]] | str | None) -> str: # type: ignore[type-arg]
|
|
622
|
+
"""Gets and validates the input message(s) for the document agent.
|
|
623
|
+
|
|
624
|
+
Args:
|
|
625
|
+
messages: Input messages as string or list of message dictionaries
|
|
626
|
+
|
|
627
|
+
Returns:
|
|
628
|
+
str: The extracted message content
|
|
629
|
+
|
|
630
|
+
Raises:
|
|
631
|
+
NotImplementedError: If messages format is invalid
|
|
632
|
+
"""
|
|
633
|
+
if isinstance(messages, str):
|
|
634
|
+
return messages
|
|
635
|
+
elif (
|
|
636
|
+
isinstance(messages, list)
|
|
637
|
+
and len(messages) > 0
|
|
638
|
+
and "content" in messages[-1]
|
|
639
|
+
and isinstance(messages[-1]["content"], str)
|
|
640
|
+
):
|
|
641
|
+
return messages[-1]["content"]
|
|
642
|
+
else:
|
|
643
|
+
raise NotImplementedError("Invalid messages format. Must be a list of messages or a string.")
|