ag2 0.9.1.post0__py3-none-any.whl → 0.9.3__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.post0.dist-info → ag2-0.9.3.dist-info}/METADATA +22 -12
- {ag2-0.9.1.post0.dist-info → ag2-0.9.3.dist-info}/RECORD +37 -23
- autogen/agentchat/contrib/capabilities/transforms.py +22 -9
- autogen/agentchat/conversable_agent.py +37 -34
- autogen/agentchat/group/group_utils.py +65 -20
- autogen/agentchat/group/handoffs.py +81 -5
- autogen/agentchat/group/on_context_condition.py +2 -2
- autogen/agentchat/group/patterns/pattern.py +7 -1
- autogen/agentchat/groupchat.py +2 -2
- autogen/agentchat/realtime/experimental/realtime_swarm.py +12 -4
- autogen/agents/experimental/document_agent/document_agent.py +232 -40
- autogen/events/agent_events.py +7 -4
- autogen/interop/litellm/litellm_config_factory.py +68 -2
- autogen/llm_config.py +4 -1
- autogen/mcp/__main__.py +78 -0
- autogen/mcp/mcp_proxy/__init__.py +19 -0
- autogen/mcp/mcp_proxy/fastapi_code_generator_helpers.py +63 -0
- autogen/mcp/mcp_proxy/mcp_proxy.py +581 -0
- autogen/mcp/mcp_proxy/operation_grouping.py +158 -0
- autogen/mcp/mcp_proxy/operation_renaming.py +114 -0
- autogen/mcp/mcp_proxy/patch_fastapi_code_generator.py +98 -0
- autogen/mcp/mcp_proxy/security.py +400 -0
- autogen/mcp/mcp_proxy/security_schema_visitor.py +37 -0
- autogen/oai/client.py +11 -2
- autogen/oai/gemini.py +20 -3
- autogen/oai/gemini_types.py +27 -0
- autogen/oai/oai_models/chat_completion.py +1 -1
- autogen/tools/experimental/__init__.py +5 -0
- autogen/tools/experimental/reliable/__init__.py +10 -0
- autogen/tools/experimental/reliable/reliable.py +1316 -0
- autogen/version.py +1 -1
- templates/client_template/main.jinja2 +69 -0
- templates/config_template/config.jinja2 +7 -0
- templates/main.jinja2 +61 -0
- {ag2-0.9.1.post0.dist-info → ag2-0.9.3.dist-info}/WHEEL +0 -0
- {ag2-0.9.1.post0.dist-info → ag2-0.9.3.dist-info}/licenses/LICENSE +0 -0
- {ag2-0.9.1.post0.dist-info → ag2-0.9.3.dist-info}/licenses/NOTICE.md +0 -0
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
import os
|
|
6
6
|
from abc import ABC, abstractmethod
|
|
7
|
-
from typing import Any, Callable, TypeVar, Union
|
|
7
|
+
from typing import Any, Callable, Optional, TypeVar, Union
|
|
8
8
|
|
|
9
9
|
from ...doc_utils import export_module
|
|
10
10
|
from ...llm_config import LLMConfig
|
|
@@ -15,19 +15,85 @@ __all__ = ["LiteLLmConfigFactory"]
|
|
|
15
15
|
T = TypeVar("T", bound="LiteLLmConfigFactory")
|
|
16
16
|
|
|
17
17
|
|
|
18
|
+
def get_crawl4ai_version() -> Optional[str]:
|
|
19
|
+
"""Get the installed crawl4ai version."""
|
|
20
|
+
try:
|
|
21
|
+
import crawl4ai
|
|
22
|
+
|
|
23
|
+
version = getattr(crawl4ai, "__version__", None)
|
|
24
|
+
return version if isinstance(version, str) else None
|
|
25
|
+
except (ImportError, AttributeError):
|
|
26
|
+
return None
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def is_crawl4ai_v05_or_higher() -> bool:
|
|
30
|
+
"""Check if crawl4ai version is 0.5 or higher."""
|
|
31
|
+
version = get_crawl4ai_version()
|
|
32
|
+
if version is None:
|
|
33
|
+
return False
|
|
34
|
+
|
|
35
|
+
# Parse version string (e.g., "0.5.0" -> [0, 5, 0])
|
|
36
|
+
try:
|
|
37
|
+
version_parts = [int(x) for x in version.split(".")]
|
|
38
|
+
# Check if version >= 0.5.0
|
|
39
|
+
return version_parts >= [0, 5, 0]
|
|
40
|
+
except (ValueError, IndexError):
|
|
41
|
+
return False
|
|
42
|
+
|
|
43
|
+
|
|
18
44
|
@export_module("autogen.interop")
|
|
19
45
|
class LiteLLmConfigFactory(ABC):
|
|
20
46
|
_factories: set["LiteLLmConfigFactory"] = set()
|
|
21
47
|
|
|
22
48
|
@classmethod
|
|
23
49
|
def create_lite_llm_config(cls, llm_config: Union[LLMConfig, dict[str, Any]]) -> dict[str, Any]:
|
|
50
|
+
"""
|
|
51
|
+
Create a lite LLM config compatible with the installed crawl4ai version.
|
|
52
|
+
|
|
53
|
+
For crawl4ai >=0.5: Returns config with llmConfig parameter
|
|
54
|
+
For crawl4ai <0.5: Returns config with provider parameter (legacy)
|
|
55
|
+
"""
|
|
24
56
|
first_llm_config = get_first_llm_config(llm_config)
|
|
25
57
|
for factory in LiteLLmConfigFactory._factories:
|
|
26
58
|
if factory.accepts(first_llm_config):
|
|
27
|
-
|
|
59
|
+
base_config = factory.create(first_llm_config)
|
|
60
|
+
|
|
61
|
+
# Check crawl4ai version and adapt config accordingly
|
|
62
|
+
if is_crawl4ai_v05_or_higher():
|
|
63
|
+
return cls._adapt_for_crawl4ai_v05(base_config)
|
|
64
|
+
else:
|
|
65
|
+
return base_config # Use legacy format
|
|
28
66
|
|
|
29
67
|
raise ValueError("Could not find a factory for the given config.")
|
|
30
68
|
|
|
69
|
+
@classmethod
|
|
70
|
+
def _adapt_for_crawl4ai_v05(cls, base_config: dict[str, Any]) -> dict[str, Any]:
|
|
71
|
+
"""
|
|
72
|
+
Adapt the config for crawl4ai >=0.5 by moving deprecated parameters
|
|
73
|
+
into an llmConfig object.
|
|
74
|
+
"""
|
|
75
|
+
adapted_config = base_config.copy()
|
|
76
|
+
|
|
77
|
+
# Extract deprecated parameters
|
|
78
|
+
llm_config_params = {}
|
|
79
|
+
|
|
80
|
+
if "provider" in adapted_config:
|
|
81
|
+
llm_config_params["provider"] = adapted_config.pop("provider")
|
|
82
|
+
|
|
83
|
+
if "api_token" in adapted_config:
|
|
84
|
+
llm_config_params["api_token"] = adapted_config.pop("api_token")
|
|
85
|
+
|
|
86
|
+
# Add other parameters that should be in llmConfig
|
|
87
|
+
for param in ["base_url", "api_base", "api_version"]:
|
|
88
|
+
if param in adapted_config:
|
|
89
|
+
llm_config_params[param] = adapted_config.pop(param)
|
|
90
|
+
|
|
91
|
+
# Create the llmConfig object if we have parameters for it
|
|
92
|
+
if llm_config_params:
|
|
93
|
+
adapted_config["llmConfig"] = llm_config_params
|
|
94
|
+
|
|
95
|
+
return adapted_config
|
|
96
|
+
|
|
31
97
|
@classmethod
|
|
32
98
|
def register_factory(cls) -> Callable[[type[T]], type[T]]:
|
|
33
99
|
def decorator(factory: type[T]) -> type[T]:
|
autogen/llm_config.py
CHANGED
|
@@ -138,7 +138,10 @@ class LLMConfig(metaclass=MetaLLMConfig):
|
|
|
138
138
|
if len(filtered_config_list) == 0:
|
|
139
139
|
raise ValueError(f"No config found that satisfies the filter criteria: {kwargs}")
|
|
140
140
|
|
|
141
|
-
|
|
141
|
+
kwargs = self.model_dump()
|
|
142
|
+
kwargs["config_list"] = filtered_config_list
|
|
143
|
+
|
|
144
|
+
return LLMConfig(**kwargs)
|
|
142
145
|
|
|
143
146
|
# @functools.wraps(BaseModel.model_dump)
|
|
144
147
|
def model_dump(self, *args: Any, exclude_none: bool = True, **kwargs: Any) -> dict[str, Any]:
|
autogen/mcp/__main__.py
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# Copyright (c) 2023 - 2025, AG2ai, Inc., AG2ai open-source projects maintainers and core contributors
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
import logging
|
|
5
|
+
from typing import Annotated, Literal, Optional
|
|
6
|
+
|
|
7
|
+
from .. import __version__
|
|
8
|
+
from ..import_utils import optional_import_block, require_optional_import
|
|
9
|
+
from .mcp_proxy import MCPProxy
|
|
10
|
+
|
|
11
|
+
logger = logging.getLogger(__name__)
|
|
12
|
+
|
|
13
|
+
with optional_import_block():
|
|
14
|
+
import typer
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@require_optional_import(["typer"], "mcp-proxy-gen")
|
|
18
|
+
def create_typer_app() -> "typer.Typer":
|
|
19
|
+
"""Create a Typer app for the mcp proxy CLI."""
|
|
20
|
+
app = typer.Typer(rich_markup_mode="rich")
|
|
21
|
+
|
|
22
|
+
def version_callback(value: bool) -> None:
|
|
23
|
+
if value:
|
|
24
|
+
typer.echo(f"{__version__}")
|
|
25
|
+
raise typer.Exit()
|
|
26
|
+
|
|
27
|
+
@app.callback()
|
|
28
|
+
def callback(
|
|
29
|
+
version: Annotated[
|
|
30
|
+
Optional[bool],
|
|
31
|
+
typer.Option("--version", help="Show the version and exit.", callback=version_callback),
|
|
32
|
+
] = None,
|
|
33
|
+
) -> None:
|
|
34
|
+
"""AG2 mcp proxy CLI - The [bold]mcp proxy[/bold] command line app. 😎
|
|
35
|
+
|
|
36
|
+
Generate mcp proxy for your [bold]AG2[/bold] projects.
|
|
37
|
+
|
|
38
|
+
Read more in the docs: ...
|
|
39
|
+
""" # noqa: D415
|
|
40
|
+
|
|
41
|
+
@app.command()
|
|
42
|
+
def create(
|
|
43
|
+
openapi_specification: Annotated[
|
|
44
|
+
Optional[str],
|
|
45
|
+
"Specification of the OpenAPI to use for the proxy generation.",
|
|
46
|
+
] = None,
|
|
47
|
+
openapi_url: Annotated[
|
|
48
|
+
Optional[str],
|
|
49
|
+
"URL to the OpenAPI specification to use for the proxy generation.",
|
|
50
|
+
] = None,
|
|
51
|
+
client_source_path: Annotated[
|
|
52
|
+
Optional[str],
|
|
53
|
+
"Path to the generated proxy client source code.",
|
|
54
|
+
] = None,
|
|
55
|
+
server_url: Annotated[
|
|
56
|
+
Optional[str],
|
|
57
|
+
"Comma-separated list of server URLs to use for the proxy generation.",
|
|
58
|
+
] = None,
|
|
59
|
+
configuration_type: Annotated[
|
|
60
|
+
Literal["json", "yaml"],
|
|
61
|
+
"Configuration type of the specification. Can be 'json' or 'yaml'.",
|
|
62
|
+
] = "json",
|
|
63
|
+
) -> None:
|
|
64
|
+
"""Generate mcp proxy for your AG2 projects."""
|
|
65
|
+
MCPProxy.create(
|
|
66
|
+
openapi_specification=openapi_specification,
|
|
67
|
+
openapi_url=openapi_url,
|
|
68
|
+
client_source_path=client_source_path,
|
|
69
|
+
servers=[{"url": server_url}],
|
|
70
|
+
configuration_type=configuration_type,
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
return app
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
if __name__ == "__main__":
|
|
77
|
+
app = create_typer_app()
|
|
78
|
+
app(prog_name="mcp_proxy")
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Copyright (c) 2023 - 2025, AG2ai, Inc., AG2ai open-source projects maintainers and core contributors
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
|
|
5
|
+
from autogen.import_utils import optional_import_block
|
|
6
|
+
|
|
7
|
+
from .patch_fastapi_code_generator import ( # noqa: E402
|
|
8
|
+
SUCCESFUL_IMPORT,
|
|
9
|
+
patch_function_name_parsing,
|
|
10
|
+
patch_generate_code,
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
if SUCCESFUL_IMPORT:
|
|
14
|
+
patch_function_name_parsing()
|
|
15
|
+
patch_generate_code()
|
|
16
|
+
|
|
17
|
+
from .mcp_proxy import MCPProxy # noqa: E402
|
|
18
|
+
|
|
19
|
+
__all__ = ["MCPProxy", "optional_import_block"]
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# Copyright (c) 2023 - 2025, AG2ai, Inc., AG2ai open-source projects maintainers and core contributors
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
from collections.abc import Iterator
|
|
5
|
+
from contextlib import contextmanager
|
|
6
|
+
from functools import cached_property
|
|
7
|
+
from typing import Optional, Union
|
|
8
|
+
|
|
9
|
+
from ...import_utils import optional_import_block
|
|
10
|
+
|
|
11
|
+
with optional_import_block() as result:
|
|
12
|
+
from fastapi_code_generator.parser import (
|
|
13
|
+
Argument,
|
|
14
|
+
OpenAPIParser,
|
|
15
|
+
ParameterObject,
|
|
16
|
+
ReferenceObject,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
SUCCESFUL_IMPORT = result.is_successful
|
|
20
|
+
|
|
21
|
+
__all__ = ["SUCCESFUL_IMPORT", "patch_get_parameter_type"]
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@contextmanager
|
|
25
|
+
def patch_get_parameter_type() -> Iterator[None]:
|
|
26
|
+
class ArgumentWithDescription(Argument): # type: ignore[misc]
|
|
27
|
+
description: Optional[str] = None
|
|
28
|
+
|
|
29
|
+
@cached_property
|
|
30
|
+
def argument(self) -> str:
|
|
31
|
+
if self.description:
|
|
32
|
+
description = self.description.replace('"""', '"""')
|
|
33
|
+
type_hint = f'Annotated[{self.type_hint}, """{description}"""]'
|
|
34
|
+
else:
|
|
35
|
+
type_hint = self.type_hint
|
|
36
|
+
|
|
37
|
+
if self.default is None and self.required:
|
|
38
|
+
return f"{self.name}: {type_hint}"
|
|
39
|
+
|
|
40
|
+
return f"{self.name}: {type_hint} = {self.default}"
|
|
41
|
+
|
|
42
|
+
original_get_parameter_type = OpenAPIParser.get_parameter_type
|
|
43
|
+
|
|
44
|
+
def get_parameter_type(
|
|
45
|
+
self: OpenAPIParser,
|
|
46
|
+
parameters: Union[ReferenceObject, ParameterObject],
|
|
47
|
+
snake_case: bool,
|
|
48
|
+
path: list[str],
|
|
49
|
+
) -> Optional[Argument]:
|
|
50
|
+
# get the original argument
|
|
51
|
+
argument = original_get_parameter_type(self, parameters, snake_case, path)
|
|
52
|
+
|
|
53
|
+
# add description to the argument
|
|
54
|
+
parameters = self.resolve_object(parameters, ParameterObject)
|
|
55
|
+
argument_with_description = ArgumentWithDescription(description=parameters.description, **argument.model_dump())
|
|
56
|
+
return argument_with_description
|
|
57
|
+
|
|
58
|
+
OpenAPIParser.get_parameter_type = get_parameter_type
|
|
59
|
+
|
|
60
|
+
try:
|
|
61
|
+
yield
|
|
62
|
+
finally:
|
|
63
|
+
OpenAPIParser.get_parameter_type = original_get_parameter_type
|