Skip to content

Commit

Permalink
moved one_call_at_a_time under ToolConfig
Browse files Browse the repository at this point in the history
  • Loading branch information
VRSEN committed Aug 15, 2024
1 parent b428388 commit e9043bc
Show file tree
Hide file tree
Showing 9 changed files with 46 additions and 22 deletions.
4 changes: 2 additions & 2 deletions agency_swarm/agency/agency.py
Original file line number Diff line number Diff line change
Expand Up @@ -1086,10 +1086,10 @@ def run(self):
SendMessage.caller_agent = agent
if self.async_mode == 'threading':
SendMessage.__doc__ = self.send_message_tool_description_async
SendMessage.one_call_at_a_time = False
SendMessage.ToolConfig.one_call_at_a_time = False
else:
SendMessage.__doc__ = self.send_message_tool_description
SendMessage.one_call_at_a_time = True
SendMessage.ToolConfig.one_call_at_a_time = True

return SendMessage

Expand Down
4 changes: 3 additions & 1 deletion agency_swarm/agency/genesis/ToolCreator/tools/CreateTool.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,9 @@ class CreateTool(BaseTool):
agency_name: str = Field(
None, description="Name of the agency to create the tool for. Defaults to the agency currently being created."
)
one_call_at_a_time: bool = True

class ToolConfig:
one_call_at_a_time: bool = True

def run(self):
if self.agency_name:
Expand Down
3 changes: 2 additions & 1 deletion agency_swarm/agents/BrowsingAgent/tools/ReadURL.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@ class ReadURL(BaseTool):
url: str = Field(
..., description="URL of the webpage.", examples=["https://google.com/search?q=search"]
)
one_call_at_a_time: bool = True

class ToolConfig:
one_call_at_a_time: bool = True

def run(self):
wd = get_web_driver()
Expand Down
4 changes: 3 additions & 1 deletion agency_swarm/agents/Devid/tools/CheckCurrentDir.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ class CheckCurrentDir(BaseTool):
description="Please think step-by-step about what you need to do next, after checking current directory to solve the task.",
exclude=True,
)
one_call_at_a_time: bool = True

class ToolConfig:
one_call_at_a_time: bool = True

def run(self):
import os
Expand Down
4 changes: 3 additions & 1 deletion agency_swarm/agents/Devid/tools/DirectoryNavigator.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ class DirectoryNavigator(BaseTool):
create: bool = Field(
False, description="If True, the directory will be created if it does not exist."
)
one_call_at_a_time: bool = True

class ToolConfig:
one_call_at_a_time: bool = True

def run(self):
try:
Expand Down
4 changes: 3 additions & 1 deletion agency_swarm/agents/Devid/tools/FileWriter.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,9 @@ class FileWriter(BaseTool):
description="Any library dependencies required for the file to be written.",
examples=["numpy", "pandas"]
)
one_call_at_a_time: bool = True

class ToolConfig:
one_call_at_a_time = True

def run(self):
client = get_openai_client()
Expand Down
14 changes: 7 additions & 7 deletions agency_swarm/threads/thread.py
Original file line number Diff line number Diff line change
Expand Up @@ -428,25 +428,25 @@ def execute_tool(self, tool_call, recipient_agent=None, event_handler=None, tool
recipient_agent = self.recipient_agent

funcs = recipient_agent.functions
func = next((func for func in funcs if func.__name__ == tool_call.function.name), None)
tool = next((func for func in funcs if func.__name__ == tool_call.function.name), None)

if not func:
if not tool:
return f"Error: Function {tool_call.function.name} not found. Available functions: {[func.__name__ for func in funcs]}"

try:
# init tool
args = tool_call.function.arguments
args = json.loads(args) if args else {}
func = func(**args)
tool = tool(**args)
for tool_name in [name for name, _ in tool_outputs_and_names]:
if tool_name == tool_call.function.name and (
hasattr(func, "one_call_at_a_time") and func.one_call_at_a_time):
hasattr(tool, "ToolConfig") and hasattr(tool.ToolConfig, "one_call_at_a_time") and tool.ToolConfig.one_call_at_a_time):
return f"Error: Function {tool_call.function.name} is already called. You can only call this function once at a time. Please wait for the previous call to finish before calling it again."

func.caller_agent = recipient_agent
func.event_handler = event_handler
tool.caller_agent = recipient_agent
tool.event_handler = event_handler

return func.run()
return tool.run()
except Exception as e:
error_message = f"Error: {e}"
if "For further information visit" in error_message:
Expand Down
9 changes: 3 additions & 6 deletions agency_swarm/tools/BaseTool.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ class BaseTool(BaseModel, ABC):
shared_state: ClassVar[SharedState] = None
caller_agent: Any = None
event_handler: Any = None
one_call_at_a_time: bool = False

def __init__(self, **kwargs):
super().__init__(**kwargs)
Expand All @@ -20,6 +19,7 @@ def __init__(self, **kwargs):

class ToolConfig:
strict: bool = False
one_call_at_a_time: bool = False

@classmethod
@property
Expand Down Expand Up @@ -69,7 +69,6 @@ def openai_schema(cls):
properties.pop("caller_agent", None)
properties.pop("shared_state", None)
properties.pop("event_handler", None)
properties.pop("one_call_at_a_time", None)

schema["strict"] = cls.ToolConfig.strict
if cls.ToolConfig.strict:
Expand All @@ -82,16 +81,14 @@ def openai_schema(cls):
required.remove("shared_state")
if "event_handler" in required:
required.remove("event_handler")
if "one_call_at_a_time" in required:
required.remove("one_call_at_a_time")

return schema

def model_dump(self, exclude=None, **kwargs):
if exclude is None:
exclude = {"caller_agent", "shared_state", "event_handler", "one_call_at_a_time"}
exclude = {"caller_agent", "shared_state", "event_handler"}
else:
exclude.update({"caller_agent", "shared_state", "event_handler", "one_call_at_a_time"})
exclude.update({"caller_agent", "shared_state", "event_handler"})
return super().model_dump(exclude=exclude, **kwargs)

@abstractmethod
Expand Down
22 changes: 20 additions & 2 deletions docs/advanced-usage/tools.md
Original file line number Diff line number Diff line change
Expand Up @@ -249,13 +249,31 @@ tools = ToolFactory.from_openapi_schema(
else:
return "Success. The action has been taken."
```
4. Consider `one_call_at_a_time` class attribute to prevent multiple instances of the same tool from running at the same time. This is useful when you want your agents to see the results of the previous action before proceeding with the next one.
4. Consider `one_call_at_a_time` ToolConfig class attribute to prevent multiple instances of the same tool from running at the same time. This is useful when you want your agents to see the results of the previous action before proceeding with the next one.

```python
class Action1(BaseTool):
input: str = Field(...)
one_call_at_a_time: bool = True

class ToolConfig:
one_call_at_a_time = True

def run(self):
# your code here
```
5. Enable [strict mode](https://openai.com/index/introducing-structured-outputs-in-the-api/) for extremely complex nested schemas or mission crictical tools.

```python
class GetWeatherTool(BaseTool):
"""
Determine weather in a specified location.
"""

location: str = Field(..., description="The city and state e.g. San Francisco, CA")

class ToolConfig:
strict = True # setting strict to true

def run(self):
return f"The weather in {self.location} is 30 degrees."
```

0 comments on commit e9043bc

Please sign in to comment.