ag2 0.9.1__py3-none-any.whl → 0.9.1.post0__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.1.dist-info → ag2-0.9.1.post0.dist-info}/METADATA +264 -73
- ag2-0.9.1.post0.dist-info/RECORD +392 -0
- {ag2-0.9.1.dist-info → ag2-0.9.1.post0.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 +4020 -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 +1010 -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 +113 -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 +379 -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/mcp_client.py +208 -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 +1435 -0
- autogen/oai/client_utils.py +169 -0
- autogen/oai/cohere.py +479 -0
- autogen/oai/gemini.py +990 -0
- autogen/oai/gemini_types.py +129 -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 +43 -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/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
- ag2-0.9.1.dist-info/RECORD +0 -6
- ag2-0.9.1.dist-info/top_level.txt +0 -1
- {ag2-0.9.1.dist-info → ag2-0.9.1.post0.dist-info/licenses}/LICENSE +0 -0
- {ag2-0.9.1.dist-info → ag2-0.9.1.post0.dist-info/licenses}/NOTICE.md +0 -0
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
# Copyright (c) 2023 - 2025, AG2ai, Inc., AG2ai open-source projects maintainers and core contributors
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
|
|
5
|
+
import asyncio
|
|
6
|
+
from collections.abc import AsyncGenerator
|
|
7
|
+
from logging import Logger
|
|
8
|
+
from typing import Any, AsyncContextManager, Callable, Literal, Optional, Protocol, TypeVar, Union, runtime_checkable
|
|
9
|
+
|
|
10
|
+
from asyncer import create_task_group
|
|
11
|
+
|
|
12
|
+
from .....doc_utils import export_module
|
|
13
|
+
from .....llm_config import LLMConfig
|
|
14
|
+
from ..realtime_events import InputAudioBufferDelta, RealtimeEvent
|
|
15
|
+
|
|
16
|
+
__all__ = ["RealtimeClientProtocol", "Role", "get_client", "register_realtime_client"]
|
|
17
|
+
|
|
18
|
+
# define role literal type for typing
|
|
19
|
+
Role = Literal["user", "assistant", "system"]
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@runtime_checkable
|
|
23
|
+
@export_module("autogen.agentchat.realtime.experimental.clients")
|
|
24
|
+
class RealtimeClientProtocol(Protocol):
|
|
25
|
+
async def send_function_result(self, call_id: str, result: str) -> None:
|
|
26
|
+
"""Send the result of a function call to a Realtime API.
|
|
27
|
+
|
|
28
|
+
Args:
|
|
29
|
+
call_id (str): The ID of the function call.
|
|
30
|
+
result (str): The result of the function call.
|
|
31
|
+
"""
|
|
32
|
+
...
|
|
33
|
+
|
|
34
|
+
async def send_text(self, *, role: Role, text: str) -> None:
|
|
35
|
+
"""Send a text message to a Realtime API.
|
|
36
|
+
|
|
37
|
+
Args:
|
|
38
|
+
role (str): The role of the message.
|
|
39
|
+
text (str): The text of the message.
|
|
40
|
+
"""
|
|
41
|
+
...
|
|
42
|
+
|
|
43
|
+
async def send_audio(self, audio: str) -> None:
|
|
44
|
+
"""Send audio to a Realtime API.
|
|
45
|
+
|
|
46
|
+
Args:
|
|
47
|
+
audio (str): The audio to send.
|
|
48
|
+
"""
|
|
49
|
+
...
|
|
50
|
+
|
|
51
|
+
async def truncate_audio(self, audio_end_ms: int, content_index: int, item_id: str) -> None:
|
|
52
|
+
"""Truncate audio in a Realtime API.
|
|
53
|
+
|
|
54
|
+
Args:
|
|
55
|
+
audio_end_ms (int): The end of the audio to truncate.
|
|
56
|
+
content_index (int): The index of the content to truncate.
|
|
57
|
+
item_id (str): The ID of the item to truncate.
|
|
58
|
+
"""
|
|
59
|
+
...
|
|
60
|
+
|
|
61
|
+
async def session_update(self, session_options: dict[str, Any]) -> None:
|
|
62
|
+
"""Send a session update to a Realtime API.
|
|
63
|
+
|
|
64
|
+
Args:
|
|
65
|
+
session_options (dict[str, Any]): The session options to update.
|
|
66
|
+
"""
|
|
67
|
+
...
|
|
68
|
+
|
|
69
|
+
def connect(self) -> AsyncContextManager[None]: ...
|
|
70
|
+
|
|
71
|
+
def read_events(self) -> AsyncGenerator[RealtimeEvent, None]:
|
|
72
|
+
"""Read events from a Realtime Client."""
|
|
73
|
+
...
|
|
74
|
+
|
|
75
|
+
async def _read_from_connection(self) -> AsyncGenerator[RealtimeEvent, None]:
|
|
76
|
+
"""Read events from a Realtime connection."""
|
|
77
|
+
...
|
|
78
|
+
|
|
79
|
+
def _parse_message(self, message: dict[str, Any]) -> list[RealtimeEvent]:
|
|
80
|
+
"""Parse a message from a Realtime API.
|
|
81
|
+
|
|
82
|
+
Args:
|
|
83
|
+
message (dict[str, Any]): The message to parse.
|
|
84
|
+
|
|
85
|
+
Returns:
|
|
86
|
+
list[RealtimeEvent]: The parsed events.
|
|
87
|
+
"""
|
|
88
|
+
...
|
|
89
|
+
|
|
90
|
+
@classmethod
|
|
91
|
+
def get_factory(
|
|
92
|
+
cls, llm_config: Union[LLMConfig, dict[str, Any]], logger: Logger, **kwargs: Any
|
|
93
|
+
) -> Optional[Callable[[], "RealtimeClientProtocol"]]:
|
|
94
|
+
"""Create a Realtime API client.
|
|
95
|
+
|
|
96
|
+
Args:
|
|
97
|
+
llm_config: The config for the client.
|
|
98
|
+
logger: The logger to use for logging events.
|
|
99
|
+
**kwargs: Additional arguments.
|
|
100
|
+
|
|
101
|
+
Returns:
|
|
102
|
+
RealtimeClientProtocol: The Realtime API client is returned if the model matches the pattern
|
|
103
|
+
"""
|
|
104
|
+
...
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
class RealtimeClientBase:
|
|
108
|
+
def __init__(self):
|
|
109
|
+
self._eventQueue = asyncio.Queue()
|
|
110
|
+
|
|
111
|
+
async def add_event(self, event: Optional[RealtimeEvent]):
|
|
112
|
+
await self._eventQueue.put(event)
|
|
113
|
+
|
|
114
|
+
async def get_event(self) -> Optional[RealtimeEvent]:
|
|
115
|
+
return await self._eventQueue.get()
|
|
116
|
+
|
|
117
|
+
async def _read_from_connection_task(self):
|
|
118
|
+
async for event in self._read_from_connection():
|
|
119
|
+
await self.add_event(event)
|
|
120
|
+
await self.add_event(None)
|
|
121
|
+
|
|
122
|
+
async def _read_events(self) -> AsyncGenerator[RealtimeEvent, None]:
|
|
123
|
+
"""Read events from a Realtime Client."""
|
|
124
|
+
async with create_task_group() as tg:
|
|
125
|
+
tg.start_soon(self._read_from_connection_task)
|
|
126
|
+
while True:
|
|
127
|
+
try:
|
|
128
|
+
event = await self._eventQueue.get()
|
|
129
|
+
if event is not None:
|
|
130
|
+
yield event
|
|
131
|
+
else:
|
|
132
|
+
break
|
|
133
|
+
except Exception:
|
|
134
|
+
break
|
|
135
|
+
|
|
136
|
+
async def queue_input_audio_buffer_delta(self, audio: str) -> None:
|
|
137
|
+
"""queue InputAudioBufferDelta.
|
|
138
|
+
|
|
139
|
+
Args:
|
|
140
|
+
audio (str): The audio.
|
|
141
|
+
"""
|
|
142
|
+
await self.add_event(InputAudioBufferDelta(delta=audio, item_id=None, raw_message=dict()))
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
_realtime_client_classes: dict[str, type[RealtimeClientProtocol]] = {}
|
|
146
|
+
|
|
147
|
+
T = TypeVar("T", bound=RealtimeClientProtocol)
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def register_realtime_client() -> Callable[[type[T]], type[T]]:
|
|
151
|
+
"""Register a Realtime API client.
|
|
152
|
+
|
|
153
|
+
Returns:
|
|
154
|
+
Callable[[type[T]], type[T]]: The decorator to register the Realtime API client
|
|
155
|
+
"""
|
|
156
|
+
|
|
157
|
+
def decorator(client_cls: type[T]) -> type[T]:
|
|
158
|
+
"""Register a Realtime API client.
|
|
159
|
+
|
|
160
|
+
Args:
|
|
161
|
+
client_cls: The client to register.
|
|
162
|
+
"""
|
|
163
|
+
global _realtime_client_classes
|
|
164
|
+
fqn = f"{client_cls.__module__}.{client_cls.__name__}"
|
|
165
|
+
_realtime_client_classes[fqn] = client_cls
|
|
166
|
+
|
|
167
|
+
return client_cls
|
|
168
|
+
|
|
169
|
+
return decorator
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
@export_module("autogen.agentchat.realtime.experimental.clients")
|
|
173
|
+
def get_client(llm_config: Union[LLMConfig, dict[str, Any]], logger: Logger, **kwargs: Any) -> "RealtimeClientProtocol":
|
|
174
|
+
"""Get a registered Realtime API client.
|
|
175
|
+
|
|
176
|
+
Args:
|
|
177
|
+
llm_config: The config for the client.
|
|
178
|
+
logger: The logger to use for logging events.
|
|
179
|
+
**kwargs: Additional arguments.
|
|
180
|
+
|
|
181
|
+
Returns:
|
|
182
|
+
RealtimeClientProtocol: The Realtime API client.
|
|
183
|
+
"""
|
|
184
|
+
global _realtime_client_classes
|
|
185
|
+
for _, client_cls in _realtime_client_classes.items():
|
|
186
|
+
factory = client_cls.get_factory(llm_config=llm_config, logger=logger, **kwargs)
|
|
187
|
+
if factory:
|
|
188
|
+
return factory()
|
|
189
|
+
|
|
190
|
+
raise ValueError("Realtime API client not found.")
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# Copyright (c) 2023 - 2025, AG2ai, Inc., AG2ai open-source projects maintainers and core contributors
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
|
|
5
|
+
import asyncio
|
|
6
|
+
import json
|
|
7
|
+
from typing import TYPE_CHECKING, Any, Optional
|
|
8
|
+
|
|
9
|
+
from asyncer import asyncify
|
|
10
|
+
from pydantic import BaseModel
|
|
11
|
+
|
|
12
|
+
from ....doc_utils import export_module
|
|
13
|
+
from .realtime_events import FunctionCall, RealtimeEvent
|
|
14
|
+
from .realtime_observer import RealtimeObserver
|
|
15
|
+
|
|
16
|
+
if TYPE_CHECKING:
|
|
17
|
+
from logging import Logger
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@export_module("autogen.agentchat.realtime.experimental")
|
|
21
|
+
class FunctionObserver(RealtimeObserver):
|
|
22
|
+
"""Observer for handling function calls from the OpenAI Realtime API."""
|
|
23
|
+
|
|
24
|
+
def __init__(self, *, logger: Optional["Logger"] = None) -> None:
|
|
25
|
+
"""Observer for handling function calls from the OpenAI Realtime API."""
|
|
26
|
+
super().__init__(logger=logger)
|
|
27
|
+
|
|
28
|
+
async def on_event(self, event: RealtimeEvent) -> None:
|
|
29
|
+
"""Handle function call events from the OpenAI Realtime API.
|
|
30
|
+
|
|
31
|
+
Args:
|
|
32
|
+
event (dict[str, Any]): The event from the OpenAI Realtime API.
|
|
33
|
+
"""
|
|
34
|
+
if isinstance(event, FunctionCall):
|
|
35
|
+
self.logger.info("Received function call event")
|
|
36
|
+
await self.call_function(
|
|
37
|
+
call_id=event.call_id,
|
|
38
|
+
name=event.name,
|
|
39
|
+
kwargs=event.arguments,
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
async def call_function(self, call_id: str, name: str, kwargs: dict[str, Any]) -> None:
|
|
43
|
+
"""Call a function registered with the agent.
|
|
44
|
+
|
|
45
|
+
Args:
|
|
46
|
+
call_id (str): The ID of the function call.
|
|
47
|
+
name (str): The name of the function to call.
|
|
48
|
+
kwargs (Any[str, Any]): The arguments to pass to the function.
|
|
49
|
+
"""
|
|
50
|
+
if name in self.agent.registered_realtime_tools:
|
|
51
|
+
func = self.agent.registered_realtime_tools[name].func
|
|
52
|
+
func = func if asyncio.iscoroutinefunction(func) else asyncify(func)
|
|
53
|
+
try:
|
|
54
|
+
result = await func(**kwargs)
|
|
55
|
+
except Exception:
|
|
56
|
+
result = "Function call failed"
|
|
57
|
+
self.logger.info(f"Function call failed: {name=}, {kwargs=}", stack_info=True)
|
|
58
|
+
|
|
59
|
+
if isinstance(result, BaseModel):
|
|
60
|
+
result = result.model_dump_json()
|
|
61
|
+
elif not isinstance(result, str):
|
|
62
|
+
try:
|
|
63
|
+
result = json.dumps(result)
|
|
64
|
+
except Exception:
|
|
65
|
+
result = str(result)
|
|
66
|
+
|
|
67
|
+
await self.realtime_client.send_function_result(call_id, result)
|
|
68
|
+
else:
|
|
69
|
+
self.logger.warning(f"Function {name} called, but is not registered with the realtime agent.")
|
|
70
|
+
|
|
71
|
+
async def initialize_session(self) -> None:
|
|
72
|
+
"""Add registered tools to OpenAI with a session update."""
|
|
73
|
+
session_update = {
|
|
74
|
+
"tools": [tool.realtime_tool_schema for tool in self.agent.registered_realtime_tools.values()],
|
|
75
|
+
"tool_choice": "auto",
|
|
76
|
+
}
|
|
77
|
+
await self.realtime_client.session_update(session_update)
|
|
78
|
+
|
|
79
|
+
async def run_loop(self) -> None:
|
|
80
|
+
"""Run the observer loop."""
|
|
81
|
+
pass
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
if TYPE_CHECKING:
|
|
85
|
+
function_observer: RealtimeObserver = FunctionObserver()
|
|
@@ -0,0 +1,158 @@
|
|
|
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 dataclasses import dataclass
|
|
6
|
+
from logging import Logger, getLogger
|
|
7
|
+
from typing import Any, Callable, Optional, TypeVar, Union
|
|
8
|
+
|
|
9
|
+
from anyio import lowlevel
|
|
10
|
+
from asyncer import create_task_group
|
|
11
|
+
|
|
12
|
+
from ....doc_utils import export_module
|
|
13
|
+
from ....llm_config import LLMConfig
|
|
14
|
+
from ....tools import Tool
|
|
15
|
+
from .clients.realtime_client import RealtimeClientProtocol, get_client
|
|
16
|
+
from .function_observer import FunctionObserver
|
|
17
|
+
from .realtime_observer import RealtimeObserver
|
|
18
|
+
|
|
19
|
+
F = TypeVar("F", bound=Callable[..., Any])
|
|
20
|
+
|
|
21
|
+
global_logger = getLogger(__name__)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@dataclass
|
|
25
|
+
class RealtimeAgentCallbacks:
|
|
26
|
+
"""Callbacks for the Realtime Agent."""
|
|
27
|
+
|
|
28
|
+
# async empty placeholder function
|
|
29
|
+
on_observers_ready: Callable[[], Any] = lambda: lowlevel.checkpoint()
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
@export_module("autogen.agentchat.realtime.experimental")
|
|
33
|
+
class RealtimeAgent:
|
|
34
|
+
def __init__(
|
|
35
|
+
self,
|
|
36
|
+
*,
|
|
37
|
+
name: str,
|
|
38
|
+
audio_adapter: Optional[RealtimeObserver] = None,
|
|
39
|
+
system_message: str = "You are a helpful AI Assistant.",
|
|
40
|
+
llm_config: Optional[Union[LLMConfig, dict[str, Any]]] = None,
|
|
41
|
+
logger: Optional[Logger] = None,
|
|
42
|
+
observers: Optional[list[RealtimeObserver]] = None,
|
|
43
|
+
**client_kwargs: Any,
|
|
44
|
+
):
|
|
45
|
+
"""(Experimental) Agent for interacting with the Realtime Clients.
|
|
46
|
+
|
|
47
|
+
Args:
|
|
48
|
+
name (str): The name of the agent.
|
|
49
|
+
audio_adapter (Optional[RealtimeObserver] = None): The audio adapter for the agent.
|
|
50
|
+
system_message (str): The system message for the agent.
|
|
51
|
+
llm_config (LLMConfig, dict[str, Any], bool): The config for the agent.
|
|
52
|
+
logger (Optional[Logger]): The logger for the agent.
|
|
53
|
+
observers (Optional[list[RealtimeObserver]]): The additional observers for the agent.
|
|
54
|
+
**client_kwargs (Any): The keyword arguments for the client.
|
|
55
|
+
"""
|
|
56
|
+
self._logger = logger
|
|
57
|
+
self._name = name
|
|
58
|
+
self._system_message = system_message
|
|
59
|
+
|
|
60
|
+
llm_config = LLMConfig.get_current_llm_config(llm_config)
|
|
61
|
+
|
|
62
|
+
self._realtime_client: RealtimeClientProtocol = get_client(
|
|
63
|
+
llm_config=llm_config, logger=self.logger, **client_kwargs
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
self._registered_realtime_tools: dict[str, Tool] = {}
|
|
67
|
+
self._observers: list[RealtimeObserver] = observers if observers else []
|
|
68
|
+
self._observers.append(FunctionObserver(logger=logger))
|
|
69
|
+
if audio_adapter:
|
|
70
|
+
self._observers.append(audio_adapter)
|
|
71
|
+
|
|
72
|
+
self.callbacks = RealtimeAgentCallbacks()
|
|
73
|
+
|
|
74
|
+
@property
|
|
75
|
+
def system_message(self) -> str:
|
|
76
|
+
"""Get the system message for the agent."""
|
|
77
|
+
return self._system_message
|
|
78
|
+
|
|
79
|
+
@property
|
|
80
|
+
def logger(self) -> Logger:
|
|
81
|
+
"""Get the logger for the agent."""
|
|
82
|
+
return self._logger or global_logger
|
|
83
|
+
|
|
84
|
+
@property
|
|
85
|
+
def realtime_client(self) -> RealtimeClientProtocol:
|
|
86
|
+
"""Get the OpenAI Realtime Client."""
|
|
87
|
+
return self._realtime_client
|
|
88
|
+
|
|
89
|
+
@property
|
|
90
|
+
def registered_realtime_tools(self) -> dict[str, Tool]:
|
|
91
|
+
"""Get the registered realtime tools."""
|
|
92
|
+
return self._registered_realtime_tools
|
|
93
|
+
|
|
94
|
+
def register_observer(self, observer: RealtimeObserver) -> None:
|
|
95
|
+
"""Register an observer with the Realtime Agent.
|
|
96
|
+
|
|
97
|
+
Args:
|
|
98
|
+
observer (RealtimeObserver): The observer to register.
|
|
99
|
+
"""
|
|
100
|
+
self._observers.append(observer)
|
|
101
|
+
|
|
102
|
+
async def start_observers(self) -> None:
|
|
103
|
+
for observer in self._observers:
|
|
104
|
+
self._tg.soonify(observer.run)(self)
|
|
105
|
+
|
|
106
|
+
# wait for the observers to be ready
|
|
107
|
+
for observer in self._observers:
|
|
108
|
+
await observer.wait_for_ready()
|
|
109
|
+
|
|
110
|
+
await self.callbacks.on_observers_ready()
|
|
111
|
+
|
|
112
|
+
async def run(self) -> None:
|
|
113
|
+
"""Run the agent."""
|
|
114
|
+
# everything is run in the same task group to enable easy cancellation using self._tg.cancel_scope.cancel()
|
|
115
|
+
async with create_task_group() as self._tg: # noqa: SIM117
|
|
116
|
+
# connect with the client first (establishes a connection and initializes a session)
|
|
117
|
+
async with self._realtime_client.connect():
|
|
118
|
+
# start the observers and wait for them to be ready
|
|
119
|
+
await self.realtime_client.session_update(session_options={"instructions": self.system_message})
|
|
120
|
+
await self.start_observers()
|
|
121
|
+
|
|
122
|
+
# iterate over the events
|
|
123
|
+
async for event in self.realtime_client.read_events():
|
|
124
|
+
for observer in self._observers:
|
|
125
|
+
await observer.on_event(event)
|
|
126
|
+
|
|
127
|
+
def register_realtime_function(
|
|
128
|
+
self,
|
|
129
|
+
*,
|
|
130
|
+
name: Optional[str] = None,
|
|
131
|
+
description: Optional[str] = None,
|
|
132
|
+
) -> Callable[[Union[F, Tool]], Tool]:
|
|
133
|
+
"""Decorator for registering a function to be used by an agent.
|
|
134
|
+
|
|
135
|
+
Args:
|
|
136
|
+
name (str): The name of the function.
|
|
137
|
+
description (str): The description of the function.
|
|
138
|
+
|
|
139
|
+
Returns:
|
|
140
|
+
Callable[[Union[F, Tool]], Tool]: The decorator for registering a function.
|
|
141
|
+
"""
|
|
142
|
+
|
|
143
|
+
def _decorator(func_or_tool: Union[F, Tool]) -> Tool:
|
|
144
|
+
"""Decorator for registering a function to be used by an agent.
|
|
145
|
+
|
|
146
|
+
Args:
|
|
147
|
+
func_or_tool (Union[F, Tool]): The function or tool to register.
|
|
148
|
+
|
|
149
|
+
Returns:
|
|
150
|
+
Tool: The registered tool.
|
|
151
|
+
"""
|
|
152
|
+
tool = Tool(func_or_tool=func_or_tool, name=name, description=description)
|
|
153
|
+
|
|
154
|
+
self._registered_realtime_tools[tool.name] = tool
|
|
155
|
+
|
|
156
|
+
return tool
|
|
157
|
+
|
|
158
|
+
return _decorator
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Copyright (c) 2023 - 2025, AG2ai, Inc., AG2ai open-source projects maintainers and core contributors
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
|
|
5
|
+
from typing import Any, Literal
|
|
6
|
+
|
|
7
|
+
from pydantic import BaseModel
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class RealtimeEvent(BaseModel):
|
|
11
|
+
raw_message: dict[str, Any]
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class SessionCreated(RealtimeEvent):
|
|
15
|
+
type: Literal["session.created"] = "session.created"
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class SessionUpdated(RealtimeEvent):
|
|
19
|
+
type: Literal["session.updated"] = "session.updated"
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class AudioDelta(RealtimeEvent):
|
|
23
|
+
type: Literal["response.audio.delta"] = "response.audio.delta"
|
|
24
|
+
delta: str
|
|
25
|
+
item_id: Any
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class InputAudioBufferDelta(RealtimeEvent):
|
|
29
|
+
type: Literal["input_audio_buffer.delta"] = "input_audio_buffer.delta"
|
|
30
|
+
delta: str
|
|
31
|
+
item_id: Any
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class SpeechStarted(RealtimeEvent):
|
|
35
|
+
type: Literal["input_audio_buffer.speech_started"] = "input_audio_buffer.speech_started"
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class FunctionCall(RealtimeEvent):
|
|
39
|
+
type: Literal["response.function_call_arguments.done"] = "response.function_call_arguments.done"
|
|
40
|
+
name: str
|
|
41
|
+
arguments: dict[str, Any]
|
|
42
|
+
call_id: str
|
|
@@ -0,0 +1,100 @@
|
|
|
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 abc import ABC, abstractmethod
|
|
6
|
+
from logging import Logger, getLogger
|
|
7
|
+
from typing import TYPE_CHECKING, Optional
|
|
8
|
+
|
|
9
|
+
from anyio import Event
|
|
10
|
+
|
|
11
|
+
from ....doc_utils import export_module
|
|
12
|
+
from .clients.realtime_client import RealtimeClientProtocol
|
|
13
|
+
from .realtime_events import RealtimeEvent
|
|
14
|
+
|
|
15
|
+
if TYPE_CHECKING:
|
|
16
|
+
from .realtime_agent import RealtimeAgent
|
|
17
|
+
|
|
18
|
+
__all__ = ["RealtimeObserver"]
|
|
19
|
+
|
|
20
|
+
global_logger = getLogger(__name__)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@export_module("autogen.agentchat.realtime.experimental")
|
|
24
|
+
class RealtimeObserver(ABC):
|
|
25
|
+
"""Observer for the OpenAI Realtime API."""
|
|
26
|
+
|
|
27
|
+
def __init__(self, *, logger: Optional[Logger] = None) -> None:
|
|
28
|
+
"""Observer for the OpenAI Realtime API.
|
|
29
|
+
|
|
30
|
+
Args:
|
|
31
|
+
logger (Logger): The logger for the observer.
|
|
32
|
+
"""
|
|
33
|
+
self._ready_event = Event()
|
|
34
|
+
self._agent: Optional[RealtimeAgent] = None
|
|
35
|
+
self._logger = logger
|
|
36
|
+
|
|
37
|
+
@property
|
|
38
|
+
def logger(self) -> Logger:
|
|
39
|
+
return self._logger or global_logger
|
|
40
|
+
|
|
41
|
+
@property
|
|
42
|
+
def agent(self) -> "RealtimeAgent":
|
|
43
|
+
if self._agent is None:
|
|
44
|
+
raise RuntimeError("Agent has not been set.")
|
|
45
|
+
return self._agent
|
|
46
|
+
|
|
47
|
+
@property
|
|
48
|
+
def realtime_client(self) -> RealtimeClientProtocol:
|
|
49
|
+
if self._agent is None:
|
|
50
|
+
raise RuntimeError("Agent has not been set.")
|
|
51
|
+
if self._agent.realtime_client is None:
|
|
52
|
+
raise RuntimeError("Realtime client has not been set.")
|
|
53
|
+
|
|
54
|
+
return self._agent.realtime_client
|
|
55
|
+
|
|
56
|
+
async def run(self, agent: "RealtimeAgent") -> None:
|
|
57
|
+
"""Run the observer with the agent.
|
|
58
|
+
|
|
59
|
+
When implementing, be sure to call `self._ready_event.set()` when the observer is ready to process events.
|
|
60
|
+
|
|
61
|
+
Args:
|
|
62
|
+
agent (RealtimeAgent): The realtime agent attached to the observer.
|
|
63
|
+
"""
|
|
64
|
+
self._agent = agent
|
|
65
|
+
await self.initialize_session()
|
|
66
|
+
self._ready_event.set()
|
|
67
|
+
|
|
68
|
+
await self.run_loop()
|
|
69
|
+
|
|
70
|
+
@abstractmethod
|
|
71
|
+
async def run_loop(self) -> None:
|
|
72
|
+
"""Run the loop if needed.
|
|
73
|
+
|
|
74
|
+
This method is called after the observer is ready to process events.
|
|
75
|
+
Events will be processed by the on_event method, this is just a hook for additional processing.
|
|
76
|
+
Use initialize_session to set up the session.
|
|
77
|
+
"""
|
|
78
|
+
...
|
|
79
|
+
|
|
80
|
+
@abstractmethod
|
|
81
|
+
async def initialize_session(self) -> None:
|
|
82
|
+
"""Initialize the session for the observer."""
|
|
83
|
+
...
|
|
84
|
+
|
|
85
|
+
async def wait_for_ready(self) -> None:
|
|
86
|
+
"""Get the event that is set when the observer is ready."""
|
|
87
|
+
await self._ready_event.wait()
|
|
88
|
+
|
|
89
|
+
@abstractmethod
|
|
90
|
+
async def on_event(self, event: RealtimeEvent) -> None:
|
|
91
|
+
"""Handle an event from the OpenAI Realtime API.
|
|
92
|
+
|
|
93
|
+
Args:
|
|
94
|
+
event (RealtimeServerEvent): The event from the OpenAI Realtime API.
|
|
95
|
+
"""
|
|
96
|
+
...
|
|
97
|
+
|
|
98
|
+
async def on_close(self) -> None:
|
|
99
|
+
"""Handle close of RealtimeClient."""
|
|
100
|
+
...
|