ag2 0.9.7__py3-none-any.whl → 0.9.9__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.7.dist-info → ag2-0.9.9.dist-info}/METADATA +102 -75
- ag2-0.9.9.dist-info/RECORD +387 -0
- autogen/__init__.py +1 -2
- autogen/_website/generate_api_references.py +4 -5
- autogen/_website/generate_mkdocs.py +9 -15
- autogen/_website/notebook_processor.py +13 -14
- autogen/_website/process_notebooks.py +10 -10
- autogen/_website/utils.py +5 -4
- autogen/agentchat/agent.py +13 -13
- autogen/agentchat/assistant_agent.py +7 -6
- autogen/agentchat/contrib/agent_eval/agent_eval.py +3 -3
- autogen/agentchat/contrib/agent_eval/critic_agent.py +3 -3
- autogen/agentchat/contrib/agent_eval/quantifier_agent.py +3 -3
- autogen/agentchat/contrib/agent_eval/subcritic_agent.py +3 -3
- autogen/agentchat/contrib/agent_optimizer.py +3 -3
- autogen/agentchat/contrib/capabilities/generate_images.py +11 -11
- autogen/agentchat/contrib/capabilities/teachability.py +15 -15
- autogen/agentchat/contrib/capabilities/transforms.py +17 -18
- autogen/agentchat/contrib/capabilities/transforms_util.py +5 -5
- autogen/agentchat/contrib/capabilities/vision_capability.py +4 -3
- autogen/agentchat/contrib/captainagent/agent_builder.py +30 -30
- autogen/agentchat/contrib/captainagent/captainagent.py +22 -21
- autogen/agentchat/contrib/captainagent/tool_retriever.py +2 -3
- autogen/agentchat/contrib/gpt_assistant_agent.py +9 -9
- autogen/agentchat/contrib/graph_rag/document.py +3 -3
- autogen/agentchat/contrib/graph_rag/falkor_graph_query_engine.py +3 -3
- autogen/agentchat/contrib/graph_rag/falkor_graph_rag_capability.py +6 -6
- autogen/agentchat/contrib/graph_rag/graph_query_engine.py +3 -3
- autogen/agentchat/contrib/graph_rag/neo4j_graph_query_engine.py +5 -11
- autogen/agentchat/contrib/graph_rag/neo4j_graph_rag_capability.py +6 -6
- autogen/agentchat/contrib/graph_rag/neo4j_native_graph_query_engine.py +7 -7
- autogen/agentchat/contrib/graph_rag/neo4j_native_graph_rag_capability.py +6 -6
- autogen/agentchat/contrib/img_utils.py +1 -1
- autogen/agentchat/contrib/llamaindex_conversable_agent.py +11 -11
- autogen/agentchat/contrib/llava_agent.py +18 -4
- autogen/agentchat/contrib/math_user_proxy_agent.py +11 -11
- autogen/agentchat/contrib/multimodal_conversable_agent.py +8 -8
- autogen/agentchat/contrib/qdrant_retrieve_user_proxy_agent.py +6 -5
- autogen/agentchat/contrib/rag/chromadb_query_engine.py +22 -26
- autogen/agentchat/contrib/rag/llamaindex_query_engine.py +14 -17
- autogen/agentchat/contrib/rag/mongodb_query_engine.py +27 -37
- autogen/agentchat/contrib/rag/query_engine.py +7 -5
- autogen/agentchat/contrib/retrieve_assistant_agent.py +5 -5
- autogen/agentchat/contrib/retrieve_user_proxy_agent.py +8 -7
- autogen/agentchat/contrib/society_of_mind_agent.py +15 -14
- autogen/agentchat/contrib/swarm_agent.py +76 -98
- autogen/agentchat/contrib/text_analyzer_agent.py +7 -7
- autogen/agentchat/contrib/vectordb/base.py +10 -18
- autogen/agentchat/contrib/vectordb/chromadb.py +2 -1
- autogen/agentchat/contrib/vectordb/couchbase.py +18 -20
- autogen/agentchat/contrib/vectordb/mongodb.py +6 -5
- autogen/agentchat/contrib/vectordb/pgvectordb.py +40 -41
- autogen/agentchat/contrib/vectordb/qdrant.py +5 -5
- autogen/agentchat/contrib/web_surfer.py +20 -19
- autogen/agentchat/conversable_agent.py +292 -290
- autogen/agentchat/group/context_str.py +1 -3
- autogen/agentchat/group/context_variables.py +15 -25
- autogen/agentchat/group/group_tool_executor.py +10 -10
- autogen/agentchat/group/group_utils.py +15 -15
- autogen/agentchat/group/guardrails.py +7 -7
- autogen/agentchat/group/handoffs.py +19 -36
- autogen/agentchat/group/multi_agent_chat.py +7 -7
- autogen/agentchat/group/on_condition.py +4 -7
- autogen/agentchat/group/on_context_condition.py +4 -7
- autogen/agentchat/group/patterns/auto.py +8 -7
- autogen/agentchat/group/patterns/manual.py +7 -6
- autogen/agentchat/group/patterns/pattern.py +13 -12
- autogen/agentchat/group/patterns/random.py +3 -3
- autogen/agentchat/group/patterns/round_robin.py +3 -3
- autogen/agentchat/group/reply_result.py +2 -4
- autogen/agentchat/group/speaker_selection_result.py +5 -5
- autogen/agentchat/group/targets/group_chat_target.py +7 -6
- autogen/agentchat/group/targets/group_manager_target.py +4 -4
- autogen/agentchat/group/targets/transition_target.py +2 -1
- autogen/agentchat/groupchat.py +60 -63
- autogen/agentchat/realtime/experimental/audio_adapters/twilio_audio_adapter.py +4 -4
- autogen/agentchat/realtime/experimental/audio_adapters/websocket_audio_adapter.py +4 -4
- autogen/agentchat/realtime/experimental/clients/gemini/client.py +7 -7
- autogen/agentchat/realtime/experimental/clients/oai/base_client.py +8 -8
- autogen/agentchat/realtime/experimental/clients/oai/rtc_client.py +6 -6
- autogen/agentchat/realtime/experimental/clients/realtime_client.py +10 -9
- autogen/agentchat/realtime/experimental/realtime_agent.py +10 -9
- autogen/agentchat/realtime/experimental/realtime_observer.py +3 -3
- autogen/agentchat/realtime/experimental/realtime_swarm.py +44 -44
- autogen/agentchat/user_proxy_agent.py +10 -9
- autogen/agentchat/utils.py +3 -3
- autogen/agents/contrib/time/time_reply_agent.py +6 -5
- autogen/agents/contrib/time/time_tool_agent.py +2 -1
- autogen/agents/experimental/deep_research/deep_research.py +3 -3
- autogen/agents/experimental/discord/discord.py +2 -2
- autogen/agents/experimental/document_agent/chroma_query_engine.py +29 -44
- autogen/agents/experimental/document_agent/docling_doc_ingest_agent.py +9 -14
- autogen/agents/experimental/document_agent/document_agent.py +15 -16
- autogen/agents/experimental/document_agent/document_conditions.py +3 -3
- autogen/agents/experimental/document_agent/document_utils.py +5 -9
- autogen/agents/experimental/document_agent/inmemory_query_engine.py +14 -20
- autogen/agents/experimental/document_agent/parser_utils.py +4 -4
- autogen/agents/experimental/document_agent/url_utils.py +14 -23
- autogen/agents/experimental/reasoning/reasoning_agent.py +33 -33
- autogen/agents/experimental/slack/slack.py +2 -2
- autogen/agents/experimental/telegram/telegram.py +2 -3
- autogen/agents/experimental/websurfer/websurfer.py +4 -4
- autogen/agents/experimental/wikipedia/wikipedia.py +5 -7
- autogen/browser_utils.py +8 -8
- autogen/cache/abstract_cache_base.py +5 -5
- autogen/cache/cache.py +12 -12
- autogen/cache/cache_factory.py +4 -4
- autogen/cache/cosmos_db_cache.py +9 -9
- autogen/cache/disk_cache.py +6 -6
- autogen/cache/in_memory_cache.py +4 -4
- autogen/cache/redis_cache.py +4 -4
- autogen/code_utils.py +18 -18
- autogen/coding/base.py +6 -6
- autogen/coding/docker_commandline_code_executor.py +9 -9
- autogen/coding/func_with_reqs.py +7 -6
- autogen/coding/jupyter/base.py +3 -3
- autogen/coding/jupyter/docker_jupyter_server.py +3 -4
- autogen/coding/jupyter/import_utils.py +3 -3
- autogen/coding/jupyter/jupyter_client.py +5 -5
- autogen/coding/jupyter/jupyter_code_executor.py +3 -4
- autogen/coding/jupyter/local_jupyter_server.py +2 -6
- autogen/coding/local_commandline_code_executor.py +8 -7
- autogen/coding/markdown_code_extractor.py +1 -2
- autogen/coding/utils.py +1 -2
- autogen/doc_utils.py +3 -2
- autogen/environments/docker_python_environment.py +19 -29
- autogen/environments/python_environment.py +8 -17
- autogen/environments/system_python_environment.py +3 -4
- autogen/environments/venv_python_environment.py +8 -12
- autogen/environments/working_directory.py +1 -2
- autogen/events/agent_events.py +106 -109
- autogen/events/base_event.py +6 -5
- autogen/events/client_events.py +15 -14
- autogen/events/helpers.py +1 -1
- autogen/events/print_event.py +4 -5
- autogen/fast_depends/_compat.py +10 -15
- autogen/fast_depends/core/build.py +17 -36
- autogen/fast_depends/core/model.py +64 -113
- autogen/fast_depends/dependencies/model.py +2 -1
- autogen/fast_depends/dependencies/provider.py +3 -2
- autogen/fast_depends/library/model.py +4 -4
- autogen/fast_depends/schema.py +7 -7
- autogen/fast_depends/use.py +17 -25
- autogen/fast_depends/utils.py +10 -30
- autogen/formatting_utils.py +6 -6
- autogen/graph_utils.py +1 -4
- autogen/import_utils.py +38 -27
- autogen/interop/crewai/crewai.py +2 -2
- autogen/interop/interoperable.py +2 -2
- autogen/interop/langchain/langchain_chat_model_factory.py +3 -2
- autogen/interop/langchain/langchain_tool.py +2 -6
- autogen/interop/litellm/litellm_config_factory.py +6 -7
- autogen/interop/pydantic_ai/pydantic_ai.py +4 -7
- autogen/interop/registry.py +2 -1
- autogen/io/base.py +5 -5
- autogen/io/run_response.py +33 -32
- autogen/io/websockets.py +6 -5
- autogen/json_utils.py +1 -2
- autogen/llm_config/__init__.py +11 -0
- autogen/llm_config/client.py +58 -0
- autogen/llm_config/config.py +384 -0
- autogen/llm_config/entry.py +154 -0
- autogen/logger/base_logger.py +4 -3
- autogen/logger/file_logger.py +2 -1
- autogen/logger/logger_factory.py +2 -2
- autogen/logger/logger_utils.py +2 -2
- autogen/logger/sqlite_logger.py +2 -1
- autogen/math_utils.py +4 -5
- autogen/mcp/__main__.py +6 -6
- autogen/mcp/helpers.py +4 -4
- autogen/mcp/mcp_client.py +170 -29
- autogen/mcp/mcp_proxy/fastapi_code_generator_helpers.py +3 -4
- autogen/mcp/mcp_proxy/mcp_proxy.py +23 -26
- autogen/mcp/mcp_proxy/operation_grouping.py +4 -5
- autogen/mcp/mcp_proxy/operation_renaming.py +6 -10
- autogen/mcp/mcp_proxy/security.py +2 -3
- autogen/messages/agent_messages.py +96 -98
- autogen/messages/base_message.py +6 -5
- autogen/messages/client_messages.py +15 -14
- autogen/messages/print_message.py +4 -5
- autogen/oai/__init__.py +1 -2
- autogen/oai/anthropic.py +42 -41
- autogen/oai/bedrock.py +68 -57
- autogen/oai/cerebras.py +26 -25
- autogen/oai/client.py +113 -139
- autogen/oai/client_utils.py +3 -3
- autogen/oai/cohere.py +34 -11
- autogen/oai/gemini.py +39 -17
- autogen/oai/gemini_types.py +11 -12
- autogen/oai/groq.py +22 -10
- autogen/oai/mistral.py +17 -11
- autogen/oai/oai_models/__init__.py +14 -2
- autogen/oai/oai_models/_models.py +2 -2
- autogen/oai/oai_models/chat_completion.py +13 -14
- autogen/oai/oai_models/chat_completion_message.py +11 -9
- autogen/oai/oai_models/chat_completion_message_tool_call.py +26 -3
- autogen/oai/oai_models/chat_completion_token_logprob.py +3 -4
- autogen/oai/oai_models/completion_usage.py +8 -9
- autogen/oai/ollama.py +19 -9
- autogen/oai/openai_responses.py +40 -17
- autogen/oai/openai_utils.py +48 -38
- autogen/oai/together.py +29 -14
- autogen/retrieve_utils.py +6 -7
- autogen/runtime_logging.py +5 -4
- autogen/token_count_utils.py +7 -4
- autogen/tools/contrib/time/time.py +0 -1
- autogen/tools/dependency_injection.py +5 -6
- autogen/tools/experimental/browser_use/browser_use.py +10 -10
- autogen/tools/experimental/code_execution/python_code_execution.py +5 -7
- autogen/tools/experimental/crawl4ai/crawl4ai.py +12 -15
- autogen/tools/experimental/deep_research/deep_research.py +9 -8
- autogen/tools/experimental/duckduckgo/duckduckgo_search.py +5 -11
- autogen/tools/experimental/firecrawl/firecrawl_tool.py +98 -115
- autogen/tools/experimental/google/authentication/credentials_local_provider.py +1 -1
- autogen/tools/experimental/google/drive/drive_functions.py +4 -4
- autogen/tools/experimental/google/drive/toolkit.py +5 -5
- autogen/tools/experimental/google_search/google_search.py +5 -5
- autogen/tools/experimental/google_search/youtube_search.py +5 -5
- autogen/tools/experimental/messageplatform/discord/discord.py +8 -12
- autogen/tools/experimental/messageplatform/slack/slack.py +14 -20
- autogen/tools/experimental/messageplatform/telegram/telegram.py +8 -12
- autogen/tools/experimental/perplexity/perplexity_search.py +18 -29
- autogen/tools/experimental/reliable/reliable.py +68 -74
- autogen/tools/experimental/searxng/searxng_search.py +20 -19
- autogen/tools/experimental/tavily/tavily_search.py +12 -19
- autogen/tools/experimental/web_search_preview/web_search_preview.py +13 -7
- autogen/tools/experimental/wikipedia/wikipedia.py +7 -10
- autogen/tools/function_utils.py +7 -7
- autogen/tools/tool.py +8 -6
- autogen/types.py +2 -2
- autogen/version.py +1 -1
- ag2-0.9.7.dist-info/RECORD +0 -421
- autogen/llm_config.py +0 -385
- {ag2-0.9.7.dist-info → ag2-0.9.9.dist-info}/WHEEL +0 -0
- {ag2-0.9.7.dist-info → ag2-0.9.9.dist-info}/licenses/LICENSE +0 -0
- {ag2-0.9.7.dist-info → ag2-0.9.9.dist-info}/licenses/NOTICE.md +0 -0
autogen/mcp/__main__.py
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
#
|
|
3
3
|
# SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
import logging
|
|
5
|
-
from typing import Annotated, Literal
|
|
5
|
+
from typing import Annotated, Literal
|
|
6
6
|
|
|
7
7
|
from .. import __version__
|
|
8
8
|
from ..import_utils import optional_import_block, require_optional_import
|
|
@@ -27,7 +27,7 @@ def create_typer_app() -> "typer.Typer":
|
|
|
27
27
|
@app.callback()
|
|
28
28
|
def callback(
|
|
29
29
|
version: Annotated[
|
|
30
|
-
|
|
30
|
+
bool | None,
|
|
31
31
|
typer.Option("--version", help="Show the version and exit.", callback=version_callback),
|
|
32
32
|
] = None,
|
|
33
33
|
) -> None:
|
|
@@ -41,19 +41,19 @@ def create_typer_app() -> "typer.Typer":
|
|
|
41
41
|
@app.command()
|
|
42
42
|
def create(
|
|
43
43
|
openapi_specification: Annotated[
|
|
44
|
-
|
|
44
|
+
str | None,
|
|
45
45
|
"Specification of the OpenAPI to use for the proxy generation.",
|
|
46
46
|
] = None,
|
|
47
47
|
openapi_url: Annotated[
|
|
48
|
-
|
|
48
|
+
str | None,
|
|
49
49
|
"URL to the OpenAPI specification to use for the proxy generation.",
|
|
50
50
|
] = None,
|
|
51
51
|
client_source_path: Annotated[
|
|
52
|
-
|
|
52
|
+
str | None,
|
|
53
53
|
"Path to the generated proxy client source code.",
|
|
54
54
|
] = None,
|
|
55
55
|
server_url: Annotated[
|
|
56
|
-
|
|
56
|
+
str | None,
|
|
57
57
|
"Comma-separated list of server URLs to use for the proxy generation.",
|
|
58
58
|
] = None,
|
|
59
59
|
configuration_type: Annotated[
|
autogen/mcp/helpers.py
CHANGED
|
@@ -5,21 +5,21 @@ import asyncio
|
|
|
5
5
|
import os
|
|
6
6
|
import signal
|
|
7
7
|
from asyncio.subprocess import PIPE, Process, create_subprocess_exec
|
|
8
|
+
from collections.abc import AsyncGenerator
|
|
8
9
|
from contextlib import asynccontextmanager
|
|
9
|
-
from typing import AsyncGenerator, Dict, Optional
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
@asynccontextmanager
|
|
13
13
|
async def run_streamable_http_client(
|
|
14
|
-
*, mcp_server_path: str, env_vars:
|
|
14
|
+
*, mcp_server_path: str, env_vars: dict[str, str] | None = None, startup_wait_secs: float = 5.0
|
|
15
15
|
) -> AsyncGenerator[Process, None]:
|
|
16
|
-
"""
|
|
17
|
-
Async context manager to run a Python subprocess for streamable-http with custom env vars.
|
|
16
|
+
"""Async context manager to run a Python subprocess for streamable-http with custom env vars.
|
|
18
17
|
|
|
19
18
|
Args:
|
|
20
19
|
mcp_server_path: Path to the Python script to run.
|
|
21
20
|
env_vars: Environment variables to export to the subprocess.
|
|
22
21
|
startup_wait_secs: Time to wait for the server to start (in seconds).
|
|
22
|
+
|
|
23
23
|
Yields:
|
|
24
24
|
An asyncio.subprocess.Process object.
|
|
25
25
|
"""
|
autogen/mcp/mcp_client.py
CHANGED
|
@@ -3,38 +3,153 @@
|
|
|
3
3
|
# SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
|
|
5
5
|
|
|
6
|
-
import
|
|
7
|
-
from
|
|
6
|
+
from collections.abc import AsyncIterator
|
|
7
|
+
from contextlib import AbstractAsyncContextManager, AsyncExitStack, asynccontextmanager
|
|
8
|
+
from datetime import datetime, timedelta
|
|
8
9
|
from pathlib import Path
|
|
9
|
-
from typing import Annotated, Any,
|
|
10
|
+
from typing import Annotated, Any, Literal, Protocol, cast
|
|
10
11
|
|
|
11
12
|
import anyio
|
|
12
|
-
from
|
|
13
|
+
from anyio.streams.memory import MemoryObjectReceiveStream, MemoryObjectSendStream
|
|
14
|
+
from mcp.client.session import ClientSession
|
|
15
|
+
from mcp.client.sse import sse_client
|
|
16
|
+
from mcp.client.stdio import StdioServerParameters, stdio_client
|
|
17
|
+
from pydantic import AnyUrl, BaseModel, Field
|
|
13
18
|
|
|
14
19
|
from ..doc_utils import export_module
|
|
15
20
|
from ..import_utils import optional_import_block, require_optional_import
|
|
16
21
|
from ..tools import Tool, Toolkit
|
|
17
22
|
|
|
18
23
|
with optional_import_block():
|
|
19
|
-
from mcp import
|
|
20
|
-
from mcp.types import
|
|
21
|
-
|
|
22
|
-
ReadResourceResult,
|
|
23
|
-
ResourceTemplate,
|
|
24
|
-
TextContent,
|
|
25
|
-
)
|
|
26
|
-
from mcp.types import (
|
|
27
|
-
Tool as MCPTool,
|
|
28
|
-
)
|
|
24
|
+
from mcp.shared.message import SessionMessage
|
|
25
|
+
from mcp.types import CallToolResult, ReadResourceResult, ResourceTemplate, TextContent
|
|
26
|
+
from mcp.types import Tool as MCPTool
|
|
29
27
|
|
|
30
28
|
__all__ = ["ResultSaved", "create_toolkit"]
|
|
31
29
|
|
|
30
|
+
# Type definitions
|
|
31
|
+
EncodingErrorHandlerType = Literal["strict", "ignore", "replace"]
|
|
32
|
+
|
|
33
|
+
# Default constants
|
|
34
|
+
DEFAULT_TEXT_ENCODING = "utf-8"
|
|
35
|
+
DEFAULT_TEXT_ENCODING_ERROR_HANDLER: EncodingErrorHandlerType = "strict"
|
|
36
|
+
DEFAULT_HTTP_REQUEST_TIMEOUT = 5
|
|
37
|
+
DEFAULT_SSE_EVENT_READ_TIMEOUT = 60 * 5
|
|
38
|
+
DEFAULT_STREAMABLE_HTTP_REQUEST_TIMEOUT = timedelta(seconds=30)
|
|
39
|
+
DEFAULT_STREAMABLE_HTTP_SSE_EVENT_READ_TIMEOUT = timedelta(seconds=60 * 5)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class SessionConfigProtocol(Protocol):
|
|
43
|
+
"""Protocol for session configuration classes that can create MCP sessions."""
|
|
44
|
+
|
|
45
|
+
server_name: str
|
|
46
|
+
|
|
47
|
+
@asynccontextmanager
|
|
48
|
+
async def create_session(self, exit_stack: AsyncExitStack) -> AsyncIterator[ClientSession]:
|
|
49
|
+
"""Create a session using the given exit stack."""
|
|
50
|
+
try:
|
|
51
|
+
yield cast(ClientSession, None) # placeholder yield to satisfy AsyncIterator type
|
|
52
|
+
except Exception:
|
|
53
|
+
raise NotImplementedError
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
class BasicSessionConfig(BaseModel):
|
|
57
|
+
"""Basic session configuration."""
|
|
58
|
+
|
|
59
|
+
server_name: str = Field(..., description="Name of the server")
|
|
60
|
+
|
|
61
|
+
async def initialize(
|
|
62
|
+
self,
|
|
63
|
+
client: AbstractAsyncContextManager[
|
|
64
|
+
tuple[
|
|
65
|
+
MemoryObjectReceiveStream[SessionMessage | Exception],
|
|
66
|
+
MemoryObjectSendStream[SessionMessage],
|
|
67
|
+
]
|
|
68
|
+
],
|
|
69
|
+
exit_stack: AsyncExitStack,
|
|
70
|
+
) -> ClientSession:
|
|
71
|
+
"""Initialize the session."""
|
|
72
|
+
reader, writer = await exit_stack.enter_async_context(client)
|
|
73
|
+
session = cast(
|
|
74
|
+
ClientSession,
|
|
75
|
+
await exit_stack.enter_async_context(ClientSession(reader, writer)),
|
|
76
|
+
)
|
|
77
|
+
return session
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
class SseConfig(BasicSessionConfig):
|
|
81
|
+
"""Configuration for a single SSE MCP server."""
|
|
82
|
+
|
|
83
|
+
url: str = Field(..., description="URL of the SSE server")
|
|
84
|
+
headers: dict[str, Any] | None = Field(default=None, description="HTTP headers to send to the SSE endpoint")
|
|
85
|
+
timeout: float = Field(default=DEFAULT_HTTP_REQUEST_TIMEOUT, description="HTTP timeout")
|
|
86
|
+
sse_read_timeout: float = Field(default=DEFAULT_SSE_EVENT_READ_TIMEOUT, description="SSE read timeout")
|
|
87
|
+
|
|
88
|
+
@asynccontextmanager
|
|
89
|
+
async def create_session(self, exit_stack: AsyncExitStack) -> AsyncIterator[ClientSession]:
|
|
90
|
+
"""
|
|
91
|
+
Create a new session to an MCP server using SSE transport.
|
|
92
|
+
|
|
93
|
+
Args:
|
|
94
|
+
exit_stack: AsyncExitStack for managing async resources
|
|
95
|
+
|
|
96
|
+
Yields:
|
|
97
|
+
ClientSession: The MCP client session
|
|
98
|
+
"""
|
|
99
|
+
# Create and store the connection
|
|
100
|
+
client = sse_client(self.url, self.headers, self.timeout, self.sse_read_timeout)
|
|
101
|
+
yield await self.initialize(client, exit_stack)
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
class StdioConfig(BasicSessionConfig):
|
|
105
|
+
"""Configuration for a single stdio MCP server."""
|
|
106
|
+
|
|
107
|
+
command: str = Field(..., description="Command to execute")
|
|
108
|
+
args: list[str] = Field(..., description="Arguments for the command")
|
|
109
|
+
transport: Literal["stdio"] = Field(default="stdio", description="Transport type")
|
|
110
|
+
environment: dict[str, str] | None = Field(default=None, description="Environment variables")
|
|
111
|
+
working_dir: str | Path | None = Field(default=None, description="Working directory")
|
|
112
|
+
encoding: str = Field(default=DEFAULT_TEXT_ENCODING, description="Character encoding")
|
|
113
|
+
encoding_error_handler: EncodingErrorHandlerType = Field(
|
|
114
|
+
default=DEFAULT_TEXT_ENCODING_ERROR_HANDLER, description="How to handle encoding errors"
|
|
115
|
+
)
|
|
116
|
+
session_options: dict[str, Any] | None = Field(default=None, description="Additional session options")
|
|
117
|
+
|
|
118
|
+
@asynccontextmanager
|
|
119
|
+
async def create_session(self, exit_stack: AsyncExitStack) -> AsyncIterator[ClientSession]:
|
|
120
|
+
"""
|
|
121
|
+
Create a new session to an MCP server using stdio transport.
|
|
122
|
+
|
|
123
|
+
Args:
|
|
124
|
+
exit_stack: AsyncExitStack for managing async resources
|
|
125
|
+
|
|
126
|
+
Yields:
|
|
127
|
+
ClientSession: The MCP client session
|
|
128
|
+
"""
|
|
129
|
+
client = stdio_client(
|
|
130
|
+
StdioServerParameters(
|
|
131
|
+
command=self.command,
|
|
132
|
+
args=self.args,
|
|
133
|
+
env=self.environment,
|
|
134
|
+
encoding=self.encoding,
|
|
135
|
+
encoding_error_handler=self.encoding_error_handler,
|
|
136
|
+
)
|
|
137
|
+
)
|
|
138
|
+
yield await self.initialize(client, exit_stack)
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
class MCPConfig(BaseModel):
|
|
142
|
+
"""Configuration for multiple MCP sessions using stdio transport."""
|
|
143
|
+
|
|
144
|
+
# we should use final classes to allow pydantic to validate the type
|
|
145
|
+
servers: list[SseConfig | StdioConfig] = Field(..., description="List of stdio & sse server configurations")
|
|
146
|
+
|
|
32
147
|
|
|
33
148
|
class MCPClient:
|
|
34
149
|
@staticmethod
|
|
35
150
|
def _convert_call_tool_result( # type: ignore[no-any-unimported]
|
|
36
151
|
call_tool_result: "CallToolResult", # type: ignore[no-any-unimported]
|
|
37
|
-
) -> tuple[
|
|
152
|
+
) -> tuple[str | list[str], Any]:
|
|
38
153
|
text_contents: list[TextContent] = [] # type: ignore[no-any-unimported]
|
|
39
154
|
non_text_contents = []
|
|
40
155
|
for content in call_tool_result.content:
|
|
@@ -43,7 +158,7 @@ class MCPClient:
|
|
|
43
158
|
else:
|
|
44
159
|
non_text_contents.append(content)
|
|
45
160
|
|
|
46
|
-
tool_content:
|
|
161
|
+
tool_content: str | list[str] = [content.text for content in text_contents]
|
|
47
162
|
if len(text_contents) == 1:
|
|
48
163
|
tool_content = tool_content[0]
|
|
49
164
|
|
|
@@ -65,7 +180,7 @@ class MCPClient:
|
|
|
65
180
|
|
|
66
181
|
async def call_tool( # type: ignore[no-any-unimported]
|
|
67
182
|
**arguments: dict[str, Any],
|
|
68
|
-
) -> tuple[
|
|
183
|
+
) -> tuple[str | list[str], Any]:
|
|
69
184
|
call_tool_result = await session.call_tool(tool.name, arguments)
|
|
70
185
|
return MCPClient._convert_call_tool_result(call_tool_result)
|
|
71
186
|
|
|
@@ -83,7 +198,7 @@ class MCPClient:
|
|
|
83
198
|
cls,
|
|
84
199
|
resource_template: Any,
|
|
85
200
|
session: "ClientSession",
|
|
86
|
-
resource_download_folder:
|
|
201
|
+
resource_download_folder: Path | None,
|
|
87
202
|
**kwargs: Any,
|
|
88
203
|
) -> Tool:
|
|
89
204
|
if not isinstance(resource_template, ResourceTemplate):
|
|
@@ -97,8 +212,8 @@ Here is the correct format for the URI template:
|
|
|
97
212
|
{mcp_resource.uriTemplate}
|
|
98
213
|
"""
|
|
99
214
|
|
|
100
|
-
async def call_resource(uri: Annotated[str, uri_description]) ->
|
|
101
|
-
result = await session.read_resource(uri)
|
|
215
|
+
async def call_resource(uri: Annotated[str, uri_description]) -> ReadResourceResult | ResultSaved: # type: ignore[no-any-unimported]
|
|
216
|
+
result = await session.read_resource(AnyUrl(uri))
|
|
102
217
|
|
|
103
218
|
if not resource_download_folder:
|
|
104
219
|
return result
|
|
@@ -131,7 +246,7 @@ Here is the correct format for the URI template:
|
|
|
131
246
|
*,
|
|
132
247
|
use_mcp_tools: bool,
|
|
133
248
|
use_mcp_resources: bool,
|
|
134
|
-
resource_download_folder:
|
|
249
|
+
resource_download_folder: Path | None,
|
|
135
250
|
) -> Toolkit: # type: ignore[no-any-unimported]
|
|
136
251
|
"""Load all available MCP tools and convert them to AG2 Toolkit."""
|
|
137
252
|
all_ag2_tools: list[Tool] = []
|
|
@@ -156,10 +271,7 @@ Here is the correct format for the URI template:
|
|
|
156
271
|
return Toolkit(tools=all_ag2_tools)
|
|
157
272
|
|
|
158
273
|
@classmethod
|
|
159
|
-
def get_unsupported_reason(cls) ->
|
|
160
|
-
if sys.version_info < (3, 10):
|
|
161
|
-
return "This submodule is only supported for Python versions 3.10 and above"
|
|
162
|
-
|
|
274
|
+
def get_unsupported_reason(cls) -> str | None:
|
|
163
275
|
with optional_import_block() as result:
|
|
164
276
|
import mcp # noqa: F401
|
|
165
277
|
|
|
@@ -169,13 +281,42 @@ Here is the correct format for the URI template:
|
|
|
169
281
|
return None
|
|
170
282
|
|
|
171
283
|
|
|
284
|
+
class MCPClientSessionManager:
|
|
285
|
+
"""
|
|
286
|
+
A class to manage MCP client sessions.
|
|
287
|
+
"""
|
|
288
|
+
|
|
289
|
+
def __init__(self) -> None:
|
|
290
|
+
"""Initialize the MCP client session manager."""
|
|
291
|
+
self.exit_stack = AsyncExitStack()
|
|
292
|
+
self.sessions: dict[str, ClientSession] = {}
|
|
293
|
+
|
|
294
|
+
@asynccontextmanager
|
|
295
|
+
async def open_session(
|
|
296
|
+
self,
|
|
297
|
+
config: SessionConfigProtocol,
|
|
298
|
+
) -> AsyncIterator[ClientSession]:
|
|
299
|
+
"""Open a new session to an MCP server based on configuration.
|
|
300
|
+
|
|
301
|
+
Args:
|
|
302
|
+
config: SessionConfigProtocol object containing session configuration
|
|
303
|
+
|
|
304
|
+
Yields:
|
|
305
|
+
ClientSession: The MCP client session
|
|
306
|
+
"""
|
|
307
|
+
async with config.create_session(self.exit_stack) as session:
|
|
308
|
+
await session.initialize()
|
|
309
|
+
self.sessions[config.server_name] = session
|
|
310
|
+
yield session
|
|
311
|
+
|
|
312
|
+
|
|
172
313
|
@export_module("autogen.mcp")
|
|
173
314
|
async def create_toolkit(
|
|
174
315
|
session: "ClientSession",
|
|
175
316
|
*,
|
|
176
317
|
use_mcp_tools: bool = True,
|
|
177
318
|
use_mcp_resources: bool = True,
|
|
178
|
-
resource_download_folder:
|
|
319
|
+
resource_download_folder: Path | str | None = None,
|
|
179
320
|
) -> Toolkit: # type: ignore[no-any-unimported]
|
|
180
321
|
"""Create a toolkit from the MCP client session.
|
|
181
322
|
|
|
@@ -184,12 +325,12 @@ async def create_toolkit(
|
|
|
184
325
|
use_mcp_tools (bool): Whether to include MCP tools in the toolkit.
|
|
185
326
|
use_mcp_resources (bool): Whether to include MCP resources in the toolkit.
|
|
186
327
|
resource_download_folder (Optional[Union[Path, str]]): The folder to download files to.
|
|
328
|
+
|
|
187
329
|
Returns:
|
|
188
330
|
Toolkit: The toolkit containing the converted tools.
|
|
189
331
|
"""
|
|
190
|
-
if resource_download_folder:
|
|
191
|
-
|
|
192
|
-
resource_download_folder = Path(resource_download_folder)
|
|
332
|
+
if resource_download_folder is not None:
|
|
333
|
+
resource_download_folder = Path(resource_download_folder)
|
|
193
334
|
await anyio.to_thread.run_sync(lambda: resource_download_folder.mkdir(parents=True, exist_ok=True))
|
|
194
335
|
|
|
195
336
|
return await MCPClient.load_mcp_toolkit(
|
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
from collections.abc import Iterator
|
|
5
5
|
from contextlib import contextmanager
|
|
6
6
|
from functools import cached_property
|
|
7
|
-
from typing import Optional, Union
|
|
8
7
|
|
|
9
8
|
from ...import_utils import optional_import_block
|
|
10
9
|
|
|
@@ -24,7 +23,7 @@ __all__ = ["SUCCESFUL_IMPORT", "patch_get_parameter_type"]
|
|
|
24
23
|
@contextmanager
|
|
25
24
|
def patch_get_parameter_type() -> Iterator[None]:
|
|
26
25
|
class ArgumentWithDescription(Argument): # type: ignore[misc]
|
|
27
|
-
description:
|
|
26
|
+
description: str | None = None
|
|
28
27
|
|
|
29
28
|
@cached_property
|
|
30
29
|
def argument(self) -> str:
|
|
@@ -43,10 +42,10 @@ def patch_get_parameter_type() -> Iterator[None]:
|
|
|
43
42
|
|
|
44
43
|
def get_parameter_type(
|
|
45
44
|
self: OpenAPIParser,
|
|
46
|
-
parameters:
|
|
45
|
+
parameters: ReferenceObject | ParameterObject,
|
|
47
46
|
snake_case: bool,
|
|
48
47
|
path: list[str],
|
|
49
|
-
) ->
|
|
48
|
+
) -> Argument | None:
|
|
50
49
|
# get the original argument
|
|
51
50
|
argument = original_get_parameter_type(self, parameters, snake_case, path)
|
|
52
51
|
|
|
@@ -8,7 +8,7 @@ import json
|
|
|
8
8
|
import re
|
|
9
9
|
import sys
|
|
10
10
|
import tempfile
|
|
11
|
-
from collections.abc import Iterable, Iterator, Mapping
|
|
11
|
+
from collections.abc import Callable, Iterable, Iterator, Mapping
|
|
12
12
|
from contextlib import contextmanager
|
|
13
13
|
from functools import wraps
|
|
14
14
|
from logging import getLogger
|
|
@@ -17,10 +17,7 @@ from types import ModuleType
|
|
|
17
17
|
from typing import (
|
|
18
18
|
TYPE_CHECKING,
|
|
19
19
|
Any,
|
|
20
|
-
Callable,
|
|
21
20
|
Literal,
|
|
22
|
-
Optional,
|
|
23
|
-
Union,
|
|
24
21
|
)
|
|
25
22
|
|
|
26
23
|
import requests
|
|
@@ -49,7 +46,7 @@ logger = getLogger(__name__)
|
|
|
49
46
|
|
|
50
47
|
|
|
51
48
|
@contextmanager
|
|
52
|
-
def optional_temp_path(path:
|
|
49
|
+
def optional_temp_path(path: str | None = None) -> Iterator[Path]:
|
|
53
50
|
if path is None:
|
|
54
51
|
with tempfile.TemporaryDirectory() as temp_dir:
|
|
55
52
|
yield Path(temp_dir)
|
|
@@ -74,7 +71,7 @@ def add_to_builtins(new_globals: dict[str, Any]) -> Iterator[None]:
|
|
|
74
71
|
|
|
75
72
|
|
|
76
73
|
class MCPProxy:
|
|
77
|
-
def __init__(self, servers: list[dict[str, Any]], title:
|
|
74
|
+
def __init__(self, servers: list[dict[str, Any]], title: str | None = None, **kwargs: Any) -> None:
|
|
78
75
|
"""Proxy class to generate client from OpenAPI schema."""
|
|
79
76
|
self._servers = servers
|
|
80
77
|
self._title = title or "MCP Proxy"
|
|
@@ -83,7 +80,7 @@ class MCPProxy:
|
|
|
83
80
|
self._globals: dict[str, Any] = {}
|
|
84
81
|
|
|
85
82
|
self._security: dict[str, list[BaseSecurity]] = {}
|
|
86
|
-
self._security_params: dict[
|
|
83
|
+
self._security_params: dict[str | None, BaseSecurityParameters] = {}
|
|
87
84
|
self._tags: set[str] = set()
|
|
88
85
|
|
|
89
86
|
self._function_group: dict[str, list[str]] = {}
|
|
@@ -100,7 +97,7 @@ class MCPProxy:
|
|
|
100
97
|
return result
|
|
101
98
|
|
|
102
99
|
@staticmethod
|
|
103
|
-
def _get_params(path: str, func: Callable[..., Any]) -> tuple[set[str], set[str],
|
|
100
|
+
def _get_params(path: str, func: Callable[..., Any]) -> tuple[set[str], set[str], str | None, bool]:
|
|
104
101
|
sig = inspect.signature(func)
|
|
105
102
|
|
|
106
103
|
params_names = set(sig.parameters.keys())
|
|
@@ -118,11 +115,11 @@ class MCPProxy:
|
|
|
118
115
|
return q_params, path_params, body, security
|
|
119
116
|
|
|
120
117
|
def get_mcp(self, **settings: Any) -> "FastMCP":
|
|
121
|
-
mcp = FastMCP(
|
|
118
|
+
mcp = FastMCP(name=self._title, **settings) # newer mcp
|
|
122
119
|
|
|
123
120
|
for func in self._registered_funcs:
|
|
124
121
|
try:
|
|
125
|
-
mcp.tool()(func)
|
|
122
|
+
mcp.tool()(func)
|
|
126
123
|
except PydanticInvalidForJsonSchema as e:
|
|
127
124
|
logger.warning("Could not register function %s: %s", func.__name__, e)
|
|
128
125
|
|
|
@@ -157,7 +154,7 @@ class MCPProxy:
|
|
|
157
154
|
|
|
158
155
|
return url, params, body_dict
|
|
159
156
|
|
|
160
|
-
def set_security_params(self, security_params: BaseSecurityParameters, name:
|
|
157
|
+
def set_security_params(self, security_params: BaseSecurityParameters, name: str | None = None) -> None:
|
|
161
158
|
if name is not None:
|
|
162
159
|
security = self._security.get(name)
|
|
163
160
|
if security is None:
|
|
@@ -180,7 +177,7 @@ class MCPProxy:
|
|
|
180
177
|
return match_security
|
|
181
178
|
raise ValueError(f"Security parameters {security_params} does not match any given security {security}")
|
|
182
179
|
|
|
183
|
-
def _get_security_params(self, name: str) -> tuple[
|
|
180
|
+
def _get_security_params(self, name: str) -> tuple[BaseSecurityParameters | None, BaseSecurity | None]:
|
|
184
181
|
# check if security is set for the method
|
|
185
182
|
security = self._security.get(name)
|
|
186
183
|
if not security:
|
|
@@ -203,8 +200,8 @@ class MCPProxy:
|
|
|
203
200
|
self,
|
|
204
201
|
method: Literal["put", "get", "post", "head", "delete", "patch"],
|
|
205
202
|
path: str,
|
|
206
|
-
description:
|
|
207
|
-
security:
|
|
203
|
+
description: str | None = None,
|
|
204
|
+
security: list[BaseSecurity] | None = None,
|
|
208
205
|
**kwargs: Any,
|
|
209
206
|
) -> Callable[..., dict[str, Any]]:
|
|
210
207
|
def decorator(func: Callable[..., Any]) -> Callable[..., dict[str, Any]]:
|
|
@@ -275,7 +272,7 @@ class MCPProxy:
|
|
|
275
272
|
input_text: str,
|
|
276
273
|
output_dir: Path,
|
|
277
274
|
disable_timestamp: bool = False,
|
|
278
|
-
custom_visitors:
|
|
275
|
+
custom_visitors: list[Path] | None = None,
|
|
279
276
|
) -> str:
|
|
280
277
|
if custom_visitors is None:
|
|
281
278
|
custom_visitors = []
|
|
@@ -318,10 +315,10 @@ class MCPProxy:
|
|
|
318
315
|
def create(
|
|
319
316
|
cls,
|
|
320
317
|
*,
|
|
321
|
-
openapi_specification:
|
|
322
|
-
openapi_url:
|
|
323
|
-
client_source_path:
|
|
324
|
-
servers:
|
|
318
|
+
openapi_specification: str | None = None,
|
|
319
|
+
openapi_url: str | None = None,
|
|
320
|
+
client_source_path: str | None = None,
|
|
321
|
+
servers: list[dict[str, Any]] | None = None,
|
|
325
322
|
rename_functions: bool = False,
|
|
326
323
|
group_functions: bool = False,
|
|
327
324
|
configuration_type: Literal["json", "yaml"] = "json",
|
|
@@ -392,7 +389,7 @@ class MCPProxy:
|
|
|
392
389
|
|
|
393
390
|
def dump_configurations(self, output_dir: Path) -> None:
|
|
394
391
|
for tag in self._function_group:
|
|
395
|
-
output_file = output_dir / "mcp_config_{}.json"
|
|
392
|
+
output_file = output_dir / f"mcp_config_{tag}.json"
|
|
396
393
|
|
|
397
394
|
functions = [
|
|
398
395
|
registered_function
|
|
@@ -458,8 +455,8 @@ class MCPProxy:
|
|
|
458
455
|
|
|
459
456
|
def _get_functions_to_register(
|
|
460
457
|
self,
|
|
461
|
-
functions:
|
|
462
|
-
) -> dict[Callable[..., Any], dict[str,
|
|
458
|
+
functions: Iterable[str | Mapping[str, Mapping[str, str]]] | None = None,
|
|
459
|
+
) -> dict[Callable[..., Any], dict[str, str | None]]:
|
|
463
460
|
if functions is None:
|
|
464
461
|
return {
|
|
465
462
|
f: {
|
|
@@ -469,7 +466,7 @@ class MCPProxy:
|
|
|
469
466
|
for f in self._registered_funcs
|
|
470
467
|
}
|
|
471
468
|
|
|
472
|
-
functions_with_name_desc: dict[str, dict[str,
|
|
469
|
+
functions_with_name_desc: dict[str, dict[str, str | None]] = {}
|
|
473
470
|
|
|
474
471
|
for f in functions:
|
|
475
472
|
if isinstance(f, str):
|
|
@@ -485,7 +482,7 @@ class MCPProxy:
|
|
|
485
482
|
else:
|
|
486
483
|
raise ValueError(f"Invalid type {type(f)} for function {f}")
|
|
487
484
|
|
|
488
|
-
funcs_to_register: dict[Callable[..., Any], dict[str,
|
|
485
|
+
funcs_to_register: dict[Callable[..., Any], dict[str, str | None]] = {
|
|
489
486
|
f: functions_with_name_desc[f.__name__]
|
|
490
487
|
for f in self._registered_funcs
|
|
491
488
|
if f.__name__ in functions_with_name_desc
|
|
@@ -528,7 +525,7 @@ class MCPProxy:
|
|
|
528
525
|
def _register_for_llm(
|
|
529
526
|
self,
|
|
530
527
|
agent: "ConversableAgent",
|
|
531
|
-
functions:
|
|
528
|
+
functions: Iterable[str | Mapping[str, Mapping[str, str]]] | None = None,
|
|
532
529
|
) -> None:
|
|
533
530
|
funcs_to_register = self._get_functions_to_register(functions)
|
|
534
531
|
|
|
@@ -543,7 +540,7 @@ class MCPProxy:
|
|
|
543
540
|
def _register_for_execution(
|
|
544
541
|
self,
|
|
545
542
|
agent: "ConversableAgent",
|
|
546
|
-
functions:
|
|
543
|
+
functions: Iterable[str | Mapping[str, Mapping[str, str]]] | None = None,
|
|
547
544
|
) -> None:
|
|
548
545
|
funcs_to_register = self._get_functions_to_register(functions)
|
|
549
546
|
|
|
@@ -5,7 +5,6 @@
|
|
|
5
5
|
import json
|
|
6
6
|
import logging
|
|
7
7
|
from pathlib import Path
|
|
8
|
-
from typing import Dict, List
|
|
9
8
|
|
|
10
9
|
from autogen.import_utils import optional_import_block
|
|
11
10
|
|
|
@@ -58,11 +57,11 @@ GROUP_ASSIGNMENT_MESSAGE = (
|
|
|
58
57
|
)
|
|
59
58
|
|
|
60
59
|
|
|
61
|
-
def chunk_list(items:
|
|
60
|
+
def chunk_list(items: list, size: int) -> list[list]:
|
|
62
61
|
return [items[i : i + size] for i in range(0, len(items), size)]
|
|
63
62
|
|
|
64
63
|
|
|
65
|
-
def discover_groups(operations:
|
|
64
|
+
def discover_groups(operations: list["Operation"], chunk_size: int = 30) -> dict[str, str]:
|
|
66
65
|
llm_config = LLMConfig.get_current_llm_config().copy()
|
|
67
66
|
|
|
68
67
|
for config in llm_config.config_list:
|
|
@@ -130,13 +129,13 @@ def assign_operation_to_group(operation: "Operation", groups: dict[str, str]) ->
|
|
|
130
129
|
return groups
|
|
131
130
|
|
|
132
131
|
|
|
133
|
-
def refine_group_names(groups:
|
|
132
|
+
def refine_group_names(groups: dict[str, str]) -> dict[str, str]:
|
|
134
133
|
# Optional: normalize names, merge similar ones (e.g., using embeddings or string similarity)
|
|
135
134
|
# Placeholder for now:
|
|
136
135
|
return groups
|
|
137
136
|
|
|
138
137
|
|
|
139
|
-
def custom_visitor(parser: "OpenAPIParser", model_path: Path) ->
|
|
138
|
+
def custom_visitor(parser: "OpenAPIParser", model_path: Path) -> dict[str, object]:
|
|
140
139
|
operations = sorted(parser.operations.values(), key=lambda op: op.path)
|
|
141
140
|
|
|
142
141
|
# ---- PASS 1: DISCOVER GROUPS ----
|
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
|
|
5
5
|
import logging
|
|
6
6
|
from pathlib import Path
|
|
7
|
-
from typing import Dict, List
|
|
8
7
|
|
|
9
8
|
from autogen.import_utils import optional_import_block
|
|
10
9
|
|
|
@@ -28,9 +27,8 @@ SYSTEM_MESSAGE = (
|
|
|
28
27
|
)
|
|
29
28
|
|
|
30
29
|
|
|
31
|
-
def validate_function_name(name: str, taken_names:
|
|
32
|
-
"""
|
|
33
|
-
Validate the generated function name against length, format, and uniqueness constraints.
|
|
30
|
+
def validate_function_name(name: str, taken_names: list[str]) -> str:
|
|
31
|
+
"""Validate the generated function name against length, format, and uniqueness constraints.
|
|
34
32
|
|
|
35
33
|
Returns:
|
|
36
34
|
'exit' if the name is valid, or an error message string otherwise.
|
|
@@ -44,9 +42,8 @@ def validate_function_name(name: str, taken_names: List[str]) -> str:
|
|
|
44
42
|
return "exit"
|
|
45
43
|
|
|
46
44
|
|
|
47
|
-
def get_new_function_name(operation: "Operation", taken_names:
|
|
48
|
-
"""
|
|
49
|
-
Ask an AI agent to generate a new function name for a given OpenAPI operation.
|
|
45
|
+
def get_new_function_name(operation: "Operation", taken_names: list[str]) -> str:
|
|
46
|
+
"""Ask an AI agent to generate a new function name for a given OpenAPI operation.
|
|
50
47
|
|
|
51
48
|
Args:
|
|
52
49
|
operation: The OpenAPI operation that needs renaming.
|
|
@@ -88,9 +85,8 @@ def get_new_function_name(operation: "Operation", taken_names: List[str]) -> str
|
|
|
88
85
|
return response.summary
|
|
89
86
|
|
|
90
87
|
|
|
91
|
-
def custom_visitor(parser: "OpenAPIParser", model_path: Path) ->
|
|
92
|
-
"""
|
|
93
|
-
Visits and optionally renames operations in the OpenAPI parser.
|
|
88
|
+
def custom_visitor(parser: "OpenAPIParser", model_path: Path) -> dict[str, object]:
|
|
89
|
+
"""Visits and optionally renames operations in the OpenAPI parser.
|
|
94
90
|
|
|
95
91
|
Args:
|
|
96
92
|
parser: An OpenAPIParser instance containing API operations.
|
|
@@ -4,11 +4,10 @@
|
|
|
4
4
|
import base64
|
|
5
5
|
import json
|
|
6
6
|
import logging
|
|
7
|
-
from typing import Any, ClassVar, Literal,
|
|
7
|
+
from typing import Any, ClassVar, Literal, TypeAlias
|
|
8
8
|
|
|
9
9
|
import requests
|
|
10
10
|
from pydantic import BaseModel, model_validator
|
|
11
|
-
from typing_extensions import TypeAlias
|
|
12
11
|
|
|
13
12
|
# Get the logger
|
|
14
13
|
logger = logging.getLogger(__name__)
|
|
@@ -343,7 +342,7 @@ class OAuth2PasswordBearer(BaseSecurity):
|
|
|
343
342
|
|
|
344
343
|
username: str = "USERNAME"
|
|
345
344
|
password: str = "PASSWORD"
|
|
346
|
-
bearer_token:
|
|
345
|
+
bearer_token: str | None = None
|
|
347
346
|
token_url: str = "TOKEN_URL"
|
|
348
347
|
|
|
349
348
|
# @model_validator(mode="before")
|