ag2 0.9.5__py3-none-any.whl → 0.9.7__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.5.dist-info → ag2-0.9.7.dist-info}/METADATA +1 -1
- {ag2-0.9.5.dist-info → ag2-0.9.7.dist-info}/RECORD +25 -17
- autogen/agentchat/conversable_agent.py +19 -5
- autogen/coding/docker_commandline_code_executor.py +29 -9
- autogen/environments/__init__.py +10 -0
- autogen/environments/docker_python_environment.py +375 -0
- autogen/environments/python_environment.py +134 -0
- autogen/environments/system_python_environment.py +86 -0
- autogen/environments/venv_python_environment.py +224 -0
- autogen/environments/working_directory.py +75 -0
- autogen/llm_config.py +6 -3
- autogen/logger/sqlite_logger.py +1 -1
- autogen/mcp/mcp_proxy/mcp_proxy.py +4 -4
- autogen/oai/client.py +34 -7
- autogen/oai/gemini.py +1 -0
- autogen/oai/ollama.py +3 -1
- autogen/oai/openai_utils.py +111 -47
- autogen/tools/experimental/__init__.py +2 -0
- autogen/tools/experimental/code_execution/__init__.py +7 -0
- autogen/tools/experimental/code_execution/python_code_execution.py +88 -0
- autogen/tools/tool.py +1 -2
- autogen/version.py +1 -1
- {ag2-0.9.5.dist-info → ag2-0.9.7.dist-info}/WHEEL +0 -0
- {ag2-0.9.5.dist-info → ag2-0.9.7.dist-info}/licenses/LICENSE +0 -0
- {ag2-0.9.5.dist-info → ag2-0.9.7.dist-info}/licenses/NOTICE.md +0 -0
autogen/oai/ollama.py
CHANGED
|
@@ -22,6 +22,7 @@ Resources:
|
|
|
22
22
|
|
|
23
23
|
from __future__ import annotations
|
|
24
24
|
|
|
25
|
+
import ast
|
|
25
26
|
import copy
|
|
26
27
|
import json
|
|
27
28
|
import random
|
|
@@ -59,6 +60,7 @@ class OllamaLLMConfigEntry(LLMConfigEntry):
|
|
|
59
60
|
top_k: int = Field(default=40)
|
|
60
61
|
top_p: float = Field(default=0.9)
|
|
61
62
|
hide_tools: Literal["if_all_run", "if_any_run", "never"] = "never"
|
|
63
|
+
native_tool_calls: bool = False
|
|
62
64
|
|
|
63
65
|
def create_client(self):
|
|
64
66
|
raise NotImplementedError("OllamaLLMConfigEntry.create_client is not implemented.")
|
|
@@ -612,7 +614,7 @@ def _object_to_tool_call(data_object: Any) -> list[dict[str, Any]]:
|
|
|
612
614
|
is_invalid = False
|
|
613
615
|
for i, item in enumerate(data_copy):
|
|
614
616
|
try:
|
|
615
|
-
new_item =
|
|
617
|
+
new_item = ast.literal_eval(item)
|
|
616
618
|
if isinstance(new_item, dict):
|
|
617
619
|
if is_valid_tool_call_item(new_item):
|
|
618
620
|
data_object[i] = new_item
|
autogen/oai/openai_utils.py
CHANGED
|
@@ -467,59 +467,70 @@ def filter_config(
|
|
|
467
467
|
filter_dict: Optional[dict[str, Union[list[Union[str, None]], set[Union[str, None]]]]],
|
|
468
468
|
exclude: bool = False,
|
|
469
469
|
) -> list[dict[str, Any]]:
|
|
470
|
-
"""
|
|
471
|
-
|
|
470
|
+
"""Filter configuration dictionaries based on specified criteria.
|
|
471
|
+
|
|
472
|
+
This function filters a list of configuration dictionaries by applying ALL criteria specified in `filter_dict`.
|
|
473
|
+
A configuration is included in the result if it satisfies every key-value constraint in the filter dictionary.
|
|
474
|
+
For each filter key, the configuration's corresponding field value must match at least one of the acceptable
|
|
475
|
+
values (OR logic within each criteria, AND logic between different criteria).
|
|
472
476
|
|
|
473
477
|
Args:
|
|
474
478
|
config_list (list of dict): A list of configuration dictionaries to be filtered.
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
479
|
+
|
|
480
|
+
filter_dict (dict, optional): A dictionary specifying filter criteria where:
|
|
481
|
+
- Keys are field names to check in each configuration dictionary
|
|
482
|
+
- Values are lists/sets of acceptable values for that field
|
|
483
|
+
- A configuration matches if ALL filter keys are satisfied AND for each key,
|
|
484
|
+
the config's field value matches at least one acceptable value
|
|
485
|
+
- If a filter value includes None, configurations missing that field will match
|
|
486
|
+
- If None, no filtering is applied
|
|
487
|
+
|
|
488
|
+
exclude (bool, optional): If False (default), return configurations that match the filter.
|
|
489
|
+
If True, return configurations that do NOT match the filter.
|
|
484
490
|
|
|
485
491
|
Returns:
|
|
486
|
-
list of dict:
|
|
487
|
-
in `filter_dict`.
|
|
492
|
+
list of dict: Filtered list of configuration dictionaries.
|
|
488
493
|
|
|
489
|
-
|
|
494
|
+
Matching Logic:
|
|
495
|
+
- **Between different filter keys**: AND logic (all criteria must be satisfied)
|
|
496
|
+
- **Within each filter key's values**: OR logic (any acceptable value can match)
|
|
497
|
+
- **For list-type config values**: Match if there's any intersection with acceptable values
|
|
498
|
+
- **For scalar config values**: Match if the value is in the list of acceptable values
|
|
499
|
+
- **Missing fields**: Only match if None is included in the acceptable values for that field
|
|
500
|
+
|
|
501
|
+
Examples:
|
|
490
502
|
```python
|
|
491
|
-
# Example configuration list with various models and API types
|
|
492
503
|
configs = [
|
|
493
|
-
{"model": "gpt-3.5-turbo"},
|
|
494
|
-
{"model": "gpt-4"},
|
|
495
|
-
{"model": "gpt-3.5-turbo", "api_type": "azure"},
|
|
496
|
-
{"model": "gpt-
|
|
504
|
+
{"model": "gpt-3.5-turbo", "api_type": "openai"},
|
|
505
|
+
{"model": "gpt-4", "api_type": "openai"},
|
|
506
|
+
{"model": "gpt-3.5-turbo", "api_type": "azure", "api_version": "2024-02-01"},
|
|
507
|
+
{"model": "gpt-4", "tags": ["premium", "latest"]},
|
|
497
508
|
]
|
|
498
|
-
|
|
499
|
-
#
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
#
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
# [{
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
#
|
|
513
|
-
|
|
514
|
-
#
|
|
515
|
-
|
|
509
|
+
|
|
510
|
+
# Example 1: Single criterion - matches any model in the list
|
|
511
|
+
filter_dict = {"model": ["gpt-4", "gpt-4o"]}
|
|
512
|
+
result = filter_config(configs, filter_dict)
|
|
513
|
+
# Returns: [{"model": "gpt-4", "api_type": "openai"}, {"model": "gpt-4", "tags": ["premium", "latest"]}]
|
|
514
|
+
|
|
515
|
+
# Example 2: Multiple criteria - must satisfy ALL conditions
|
|
516
|
+
filter_dict = {"model": ["gpt-3.5-turbo"], "api_type": ["azure"]}
|
|
517
|
+
result = filter_config(configs, filter_dict)
|
|
518
|
+
# Returns: [{"model": "gpt-3.5-turbo", "api_type": "azure", "api_version": "2024-02-01"}]
|
|
519
|
+
|
|
520
|
+
# Example 3: Tag filtering with list intersection
|
|
521
|
+
filter_dict = {"tags": ["premium"]}
|
|
522
|
+
result = filter_config(configs, filter_dict)
|
|
523
|
+
# Returns: [{"model": "gpt-4", "tags": ["premium", "latest"]}]
|
|
524
|
+
|
|
525
|
+
# Example 4: Exclude matching configurations
|
|
526
|
+
filter_dict = {"api_type": ["openai"]}
|
|
527
|
+
result = filter_config(configs, filter_dict, exclude=True)
|
|
528
|
+
# Returns configs that do NOT have api_type="openai"
|
|
516
529
|
```
|
|
517
530
|
Note:
|
|
518
531
|
- If `filter_dict` is empty or None, no filtering is applied and `config_list` is returned as is.
|
|
519
532
|
- If a configuration dictionary in `config_list` does not contain a key specified in `filter_dict`,
|
|
520
533
|
it is considered a non-match and is excluded from the result.
|
|
521
|
-
- If the list of acceptable values for a key in `filter_dict` includes None, then configuration
|
|
522
|
-
dictionaries that do not have that key will also be considered a match.
|
|
523
534
|
|
|
524
535
|
"""
|
|
525
536
|
if inspect.stack()[1].function != "where":
|
|
@@ -538,18 +549,73 @@ def filter_config(
|
|
|
538
549
|
return config_list
|
|
539
550
|
|
|
540
551
|
|
|
541
|
-
def _satisfies_criteria(
|
|
542
|
-
if value
|
|
552
|
+
def _satisfies_criteria(config_value: Any, criteria_values: Any) -> bool:
|
|
553
|
+
"""Check if a configuration field value satisfies the filter criteria.
|
|
554
|
+
|
|
555
|
+
This helper function implements the matching logic between a single configuration
|
|
556
|
+
field value and the acceptable values specified in the filter criteria. It handles
|
|
557
|
+
both scalar and list-type configuration values with appropriate matching strategies.
|
|
558
|
+
|
|
559
|
+
Args:
|
|
560
|
+
config_value (Any): The value from a configuration dictionary field.
|
|
561
|
+
Can be None, a scalar value, or a list of values.
|
|
562
|
+
criteria_values (Any): The acceptable values from the filter dictionary.
|
|
563
|
+
Can be a single value or a list/set of acceptable values.
|
|
564
|
+
|
|
565
|
+
Returns:
|
|
566
|
+
bool: True if the config_value satisfies the criteria, False otherwise.
|
|
567
|
+
|
|
568
|
+
Matching Logic:
|
|
569
|
+
- **None config values**: Always return False (missing fields don't match)
|
|
570
|
+
- **List config values**:
|
|
571
|
+
- If criteria is a list: Match if there's any intersection (set overlap)
|
|
572
|
+
- If criteria is scalar: Match if the scalar is contained in the config list
|
|
573
|
+
- **Scalar config values**:
|
|
574
|
+
- If criteria is a list: Match if the config value is in the criteria list
|
|
575
|
+
- If criteria is scalar: Match if the values are exactly equal
|
|
576
|
+
|
|
577
|
+
Examples:
|
|
578
|
+
```python
|
|
579
|
+
# List config value with list criteria (intersection matching)
|
|
580
|
+
_satisfies_criteria(["gpt-4", "gpt-3.5"], ["gpt-4", "claude"]) # True (gpt-4 intersects)
|
|
581
|
+
_satisfies_criteria(["tag1", "tag2"], ["tag3", "tag4"]) # False (no intersection)
|
|
582
|
+
|
|
583
|
+
# List config value with scalar criteria (containment matching)
|
|
584
|
+
_satisfies_criteria(["premium", "latest"], "premium") # True (premium is in list)
|
|
585
|
+
_satisfies_criteria(["tag1", "tag2"], "tag3") # False (tag3 not in list)
|
|
586
|
+
|
|
587
|
+
# Scalar config value with list criteria (membership matching)
|
|
588
|
+
_satisfies_criteria("gpt-4", ["gpt-4", "gpt-3.5"]) # True (gpt-4 in criteria)
|
|
589
|
+
_satisfies_criteria("claude", ["gpt-4", "gpt-3.5"]) # False (claude not in criteria)
|
|
590
|
+
|
|
591
|
+
# Scalar config value with scalar criteria (equality matching)
|
|
592
|
+
_satisfies_criteria("openai", "openai") # True (exact match)
|
|
593
|
+
_satisfies_criteria("openai", "azure") # False (different values)
|
|
594
|
+
|
|
595
|
+
# None config values (missing fields)
|
|
596
|
+
_satisfies_criteria(None, ["gpt-4"]) # False (missing field)
|
|
597
|
+
_satisfies_criteria(None, "gpt-4") # False (missing field)
|
|
598
|
+
```
|
|
599
|
+
|
|
600
|
+
Note:
|
|
601
|
+
This is an internal helper function used by `filter_config()`. The function
|
|
602
|
+
assumes that both parameters can be of various types and handles type
|
|
603
|
+
checking internally to determine the appropriate matching strategy.
|
|
604
|
+
"""
|
|
605
|
+
if config_value is None:
|
|
543
606
|
return False
|
|
544
607
|
|
|
545
|
-
if isinstance(
|
|
546
|
-
|
|
608
|
+
if isinstance(config_value, list):
|
|
609
|
+
if isinstance(criteria_values, list):
|
|
610
|
+
return bool(set(config_value) & set(criteria_values)) # Non-empty intersection
|
|
611
|
+
else:
|
|
612
|
+
return criteria_values in config_value
|
|
547
613
|
else:
|
|
548
614
|
# In filter_dict, filter could be either a list of values or a single value.
|
|
549
615
|
# For example, filter_dict = {"model": ["gpt-3.5-turbo"]} or {"model": "gpt-3.5-turbo"}
|
|
550
616
|
if isinstance(criteria_values, list):
|
|
551
|
-
return
|
|
552
|
-
return bool(
|
|
617
|
+
return config_value in criteria_values
|
|
618
|
+
return bool(config_value == criteria_values)
|
|
553
619
|
|
|
554
620
|
|
|
555
621
|
@export_module("autogen")
|
|
@@ -620,8 +686,6 @@ def config_list_from_json(
|
|
|
620
686
|
with open(config_list_path) as json_file:
|
|
621
687
|
config_list = json.load(json_file)
|
|
622
688
|
|
|
623
|
-
config_list = filter_config(config_list, filter_dict)
|
|
624
|
-
|
|
625
689
|
return filter_config(config_list, filter_dict)
|
|
626
690
|
|
|
627
691
|
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
# SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
|
|
5
5
|
from .browser_use import BrowserUseTool
|
|
6
|
+
from .code_execution import PythonCodeExecutionTool
|
|
6
7
|
from .crawl4ai import Crawl4AITool
|
|
7
8
|
from .deep_research import DeepResearchTool
|
|
8
9
|
from .duckduckgo import DuckDuckGoSearchTool
|
|
@@ -34,6 +35,7 @@ __all__ = [
|
|
|
34
35
|
"FirecrawlTool",
|
|
35
36
|
"GoogleSearchTool",
|
|
36
37
|
"PerplexitySearchTool",
|
|
38
|
+
"PythonCodeExecutionTool",
|
|
37
39
|
"ReliableTool",
|
|
38
40
|
"ReliableToolError",
|
|
39
41
|
"SearxngSearchTool",
|
|
@@ -0,0 +1,88 @@
|
|
|
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 os
|
|
6
|
+
import tempfile
|
|
7
|
+
from typing import Annotated, Any, Optional
|
|
8
|
+
|
|
9
|
+
from pydantic import BaseModel, Field
|
|
10
|
+
|
|
11
|
+
from ....doc_utils import export_module
|
|
12
|
+
from ....environments import WorkingDirectory
|
|
13
|
+
from ....environments.python_environment import PythonEnvironment
|
|
14
|
+
from ... import Tool
|
|
15
|
+
|
|
16
|
+
__all__ = ["PythonCodeExecutionTool"]
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@export_module("autogen.tools.experimental")
|
|
20
|
+
class PythonCodeExecutionTool(Tool):
|
|
21
|
+
"""Executes Python code in a given environment and returns the result."""
|
|
22
|
+
|
|
23
|
+
def __init__(
|
|
24
|
+
self,
|
|
25
|
+
*,
|
|
26
|
+
timeout: int = 30,
|
|
27
|
+
working_directory: Optional[WorkingDirectory] = None,
|
|
28
|
+
python_environment: Optional[PythonEnvironment] = None,
|
|
29
|
+
) -> None:
|
|
30
|
+
"""
|
|
31
|
+
Initialize the PythonCodeExecutionTool.
|
|
32
|
+
|
|
33
|
+
**CAUTION**: If provided a local environment, this tool will execute code in your local environment, which can be dangerous if the code is untrusted.
|
|
34
|
+
|
|
35
|
+
Args:
|
|
36
|
+
timeout: Maximum execution time allowed in seconds, will raise a TimeoutError exception if exceeded.
|
|
37
|
+
working_directory: Optional WorkingDirectory context manager to use.
|
|
38
|
+
python_environment: Optional PythonEnvironment to use. If None, will auto-detect or create based on other parameters.
|
|
39
|
+
"""
|
|
40
|
+
# Store configuration parameters
|
|
41
|
+
self.timeout = timeout
|
|
42
|
+
self.working_directory = WorkingDirectory.get_current_working_directory(working_directory)
|
|
43
|
+
tool_python_environment = PythonEnvironment.get_current_python_environment(python_environment)
|
|
44
|
+
|
|
45
|
+
assert self.working_directory, "No Working directory found"
|
|
46
|
+
assert tool_python_environment, "No Python environment found"
|
|
47
|
+
|
|
48
|
+
self.python_environment = tool_python_environment
|
|
49
|
+
|
|
50
|
+
# Pydantic model to contain the code and list of libraries to execute
|
|
51
|
+
class CodeExecutionRequest(BaseModel):
|
|
52
|
+
code: Annotated[str, Field(description="Python code to execute")]
|
|
53
|
+
libraries: Annotated[list[str], Field(description="List of libraries to install before execution")]
|
|
54
|
+
|
|
55
|
+
# The tool function, this is what goes to the LLM
|
|
56
|
+
async def execute_python_code(
|
|
57
|
+
code_execution_request: Annotated[CodeExecutionRequest, "Python code and the libraries required"],
|
|
58
|
+
) -> dict[str, Any]:
|
|
59
|
+
"""
|
|
60
|
+
Executes Python code in the attached environment and returns the result.
|
|
61
|
+
|
|
62
|
+
Args:
|
|
63
|
+
code_execution_request (CodeExecutionRequest): The Python code and libraries to execute
|
|
64
|
+
"""
|
|
65
|
+
code = code_execution_request.code
|
|
66
|
+
|
|
67
|
+
# NOTE: Libraries are not installed (something to consider for future versions)
|
|
68
|
+
|
|
69
|
+
# Prepare a script file path
|
|
70
|
+
script_dir = self._get_script_directory()
|
|
71
|
+
script_path = os.path.join(script_dir, "script.py")
|
|
72
|
+
|
|
73
|
+
# Execute the code
|
|
74
|
+
return await self.python_environment.execute_code(code=code, script_path=script_path, timeout=self.timeout)
|
|
75
|
+
|
|
76
|
+
super().__init__(
|
|
77
|
+
name="python_execute_code",
|
|
78
|
+
description="Executes Python code and returns the result.",
|
|
79
|
+
func_or_tool=execute_python_code,
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
def _get_script_directory(self) -> str:
|
|
83
|
+
"""Get the directory to use for scripts."""
|
|
84
|
+
if self.working_directory and hasattr(self.working_directory, "path") and self.working_directory.path:
|
|
85
|
+
path = self.working_directory.path
|
|
86
|
+
os.makedirs(path, exist_ok=True)
|
|
87
|
+
return path
|
|
88
|
+
return tempfile.mkdtemp(prefix="ag2_script_dir_")
|
autogen/tools/tool.py
CHANGED
|
@@ -96,8 +96,7 @@ class Tool:
|
|
|
96
96
|
"""
|
|
97
97
|
if self._func_schema:
|
|
98
98
|
agent.update_tool_signature(self._func_schema, is_remove=False)
|
|
99
|
-
|
|
100
|
-
agent.register_for_llm()(self)
|
|
99
|
+
agent.register_for_llm()(self)
|
|
101
100
|
|
|
102
101
|
def register_for_execution(self, agent: "ConversableAgent") -> None:
|
|
103
102
|
"""Registers the tool for direct execution by a ConversableAgent.
|
autogen/version.py
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|