-
Notifications
You must be signed in to change notification settings - Fork 8.1k
Introduce workbench #6340
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Introduce workbench #6340
Changes from all commits
Commits
Show all changes
14 commits
Select commit
Hold shift + click to select a range
ffc3d66
Introduce workbench
ekzhu e3f219f
Add static workbench and mcp workbench
ekzhu 8f5c8a7
FEAT: MCP Actor for WorkBench for #6340 (#6360)
SongChiYoung 4077c3d
Merge branch 'main' into ekzhu-workbench
ekzhu eb30233
rename
ekzhu 62e3a87
Fix a bug in FunctionTool, add unit test for StaticWorkbench
ekzhu a1f11b5
Update tests for mcp workbench
ekzhu 177f336
update
ekzhu dd00545
Fix type
ekzhu f1fa042
Fix doc
ekzhu 5b1a457
fix type
ekzhu aee4aae
Update: override return_value_as_string for McpToolAdapter (#6371)
perfogic d809394
Merge branch 'main' into ekzhu-workbench
ekzhu a753bc2
Revert "Update: override return_value_as_string for McpToolAdapter" (…
ekzhu File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
88 changes: 88 additions & 0 deletions
88
python/packages/autogen-core/src/autogen_core/tools/_static_workbench.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,88 @@ | ||
| import asyncio | ||
| from typing import Any, Dict, List, Literal, Mapping | ||
|
|
||
| from pydantic import BaseModel | ||
| from typing_extensions import Self | ||
|
|
||
| from .._cancellation_token import CancellationToken | ||
| from .._component_config import Component, ComponentModel | ||
| from ._base import BaseTool, ToolSchema | ||
| from ._workbench import TextResultContent, ToolResult, Workbench | ||
|
|
||
|
|
||
| class StaticWorkbenchConfig(BaseModel): | ||
| tools: List[ComponentModel] = [] | ||
|
|
||
|
|
||
| class StateicWorkbenchState(BaseModel): | ||
| type: Literal["StaticWorkbenchState"] = "StaticWorkbenchState" | ||
| tools: Dict[str, Mapping[str, Any]] = {} | ||
|
|
||
|
|
||
| class StaticWorkbench(Workbench, Component[StaticWorkbenchConfig]): | ||
| """ | ||
| A workbench that provides a static set of tools that do not change after | ||
| each tool execution. | ||
|
|
||
| Args: | ||
| tools (List[BaseTool[Any, Any]]): A list of tools to be included in the workbench. | ||
| The tools should be subclasses of :class:`~autogen_core.tools.BaseTool`. | ||
| """ | ||
|
|
||
| component_provider_override = "autogen_core.tools.StaticWorkbench" | ||
| component_config_schema = StaticWorkbenchConfig | ||
|
|
||
| def __init__(self, tools: List[BaseTool[Any, Any]]) -> None: | ||
| self._tools = tools | ||
|
|
||
| async def list_tools(self) -> List[ToolSchema]: | ||
| return [tool.schema for tool in self._tools] | ||
|
|
||
| async def call_tool( | ||
| self, name: str, arguments: Mapping[str, Any] | None = None, cancellation_token: CancellationToken | None = None | ||
| ) -> ToolResult: | ||
| tool = next((tool for tool in self._tools if tool.name == name), None) | ||
| if tool is None: | ||
| raise ValueError(f"Tool {name} not found in workbench.") | ||
| if not cancellation_token: | ||
| cancellation_token = CancellationToken() | ||
| if not arguments: | ||
| arguments = {} | ||
| try: | ||
| result_future = asyncio.ensure_future(tool.run_json(arguments, cancellation_token)) | ||
| cancellation_token.link_future(result_future) | ||
| result = await result_future | ||
| is_error = False | ||
| except Exception as e: | ||
| result = str(e) | ||
| is_error = True | ||
| result_str = tool.return_value_as_string(result) | ||
| return ToolResult(name=tool.name, result=[TextResultContent(content=result_str)], is_error=is_error) | ||
|
|
||
| async def start(self) -> None: | ||
| return None | ||
|
|
||
| async def stop(self) -> None: | ||
| return None | ||
|
|
||
| async def reset(self) -> None: | ||
| return None | ||
|
|
||
| async def save_state(self) -> Mapping[str, Any]: | ||
| tool_states = StateicWorkbenchState() | ||
| for tool in self._tools: | ||
| tool_states.tools[tool.name] = await tool.save_state_json() | ||
| return tool_states.model_dump() | ||
|
|
||
| async def load_state(self, state: Mapping[str, Any]) -> None: | ||
| parsed_state = StateicWorkbenchState.model_validate(state) | ||
| for tool in self._tools: | ||
| if tool.name in parsed_state.tools: | ||
| await tool.load_state_json(parsed_state.tools[tool.name]) | ||
|
|
||
| def _to_config(self) -> StaticWorkbenchConfig: | ||
| return StaticWorkbenchConfig(tools=[tool.dump_component() for tool in self._tools]) | ||
|
|
||
| @classmethod | ||
| def _from_config(cls, config: StaticWorkbenchConfig) -> Self: | ||
| return cls(tools=[BaseTool.load_component(tool) for tool in config.tools]) | ||
164 changes: 164 additions & 0 deletions
164
python/packages/autogen-core/src/autogen_core/tools/_workbench.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,164 @@ | ||
| from abc import ABC, abstractmethod | ||
| from types import TracebackType | ||
| from typing import Any, List, Literal, Mapping, Optional, Type | ||
|
|
||
| from pydantic import BaseModel, Field | ||
| from typing_extensions import Annotated, Self | ||
|
|
||
| from .._cancellation_token import CancellationToken | ||
| from .._component_config import ComponentBase | ||
| from .._image import Image | ||
| from ._base import ToolSchema | ||
|
|
||
|
|
||
| class TextResultContent(BaseModel): | ||
| """ | ||
| Text result content of a tool execution. | ||
| """ | ||
|
|
||
| type: Literal["TextResultContent"] = "TextResultContent" | ||
|
|
||
| content: str | ||
| """The text content of the result.""" | ||
|
|
||
|
|
||
| class ImageResultContent(BaseModel): | ||
| """ | ||
| Image result content of a tool execution. | ||
| """ | ||
|
|
||
| type: Literal["ImageResultContent"] = "ImageResultContent" | ||
|
|
||
| content: Image | ||
| """The image content of the result.""" | ||
|
|
||
|
|
||
| ResultContent = Annotated[TextResultContent | ImageResultContent, Field(discriminator="type")] | ||
|
|
||
|
|
||
| class ToolResult(BaseModel): | ||
| """ | ||
| A result of a tool execution by a workbench. | ||
| """ | ||
|
|
||
| type: Literal["ToolResult"] = "ToolResult" | ||
|
|
||
| name: str | ||
| """The name of the tool that was executed.""" | ||
|
|
||
| result: List[ResultContent] | ||
| """The result of the tool execution.""" | ||
|
|
||
| is_error: bool = False | ||
| """Whether the tool execution resulted in an error.""" | ||
|
|
||
|
|
||
| class Workbench(ABC, ComponentBase[BaseModel]): | ||
| """ | ||
| A workbench is a component that provides a set of tools that may share | ||
| resources and state. | ||
|
|
||
| A workbench is responsible for managing the lifecycle of the tools and | ||
| providing a single interface to call them. The tools provided by the workbench | ||
| may be dynamic and their availabilities may change after each tool execution. | ||
|
|
||
| A workbench can be started by calling the :meth:`~autogen_core.tools.Workbench.start` method | ||
| and stopped by calling the :meth:`~autogen_core.tools.Workbench.stop` method. | ||
| It can also be used as an asynchronous context manager, which will automatically | ||
| start and stop the workbench when entering and exiting the context. | ||
| """ | ||
|
|
||
| component_type = "workbench" | ||
|
|
||
| @abstractmethod | ||
| async def list_tools(self) -> List[ToolSchema]: | ||
| """ | ||
| List the currently available tools in the workbench as :class:`ToolSchema` | ||
| objects. | ||
|
|
||
| The list of tools may be dynamic, and their content may change after | ||
| tool execution. | ||
| """ | ||
| ... | ||
|
|
||
| @abstractmethod | ||
| async def call_tool( | ||
| self, name: str, arguments: Mapping[str, Any] | None = None, cancellation_token: CancellationToken | None = None | ||
| ) -> ToolResult: | ||
| """ | ||
| Call a tool in the workbench. | ||
|
|
||
| Args: | ||
| name (str): The name of the tool to call. | ||
| arguments (Mapping[str, Any] | None): The arguments to pass to the tool. | ||
| If None, the tool will be called with no arguments. | ||
| cancellation_token (CancellationToken | None): An optional cancellation token | ||
| to cancel the tool execution. | ||
| Returns: | ||
| ToolResult: The result of the tool execution. | ||
| """ | ||
| ... | ||
|
|
||
| @abstractmethod | ||
| async def start(self) -> None: | ||
| """ | ||
| Start the workbench and initialize any resources. | ||
|
|
||
| This method should be called before using the workbench. | ||
| """ | ||
| ... | ||
|
|
||
| @abstractmethod | ||
| async def stop(self) -> None: | ||
| """ | ||
| Stop the workbench and release any resources. | ||
|
|
||
| This method should be called when the workbench is no longer needed. | ||
| """ | ||
| ... | ||
|
|
||
| @abstractmethod | ||
| async def reset(self) -> None: | ||
| """ | ||
| Reset the workbench to its initialized, started state. | ||
| """ | ||
| ... | ||
|
|
||
| @abstractmethod | ||
| async def save_state(self) -> Mapping[str, Any]: | ||
| """ | ||
| Save the state of the workbench. | ||
|
|
||
| This method should be called to persist the state of the workbench. | ||
| """ | ||
| ... | ||
|
|
||
| @abstractmethod | ||
| async def load_state(self, state: Mapping[str, Any]) -> None: | ||
| """ | ||
| Load the state of the workbench. | ||
|
|
||
| Args: | ||
| state (Mapping[str, Any]): The state to load into the workbench. | ||
| """ | ||
| ... | ||
|
|
||
| async def __aenter__(self) -> Self: | ||
| """ | ||
| Enter the workbench context manager. | ||
|
|
||
| This method is called when the workbench is used in a `with` statement. | ||
| It calls the :meth:`~autogen_core.tools.WorkBench.start` method to start the workbench. | ||
| """ | ||
| await self.start() | ||
| return self | ||
|
|
||
| async def __aexit__( | ||
| self, exc_type: Optional[Type[BaseException]], exc_val: Optional[BaseException], exc_tb: Optional[TracebackType] | ||
| ) -> None: | ||
| """ | ||
| Exit the workbench context manager. | ||
| This method is called when the workbench is used in a `with` statement. | ||
| It calls the :meth:`~autogen_core.tools.WorkBench.stop` method to stop the workbench. | ||
| """ | ||
| await self.stop() | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.