When a BaseArchytasModel config (namely OpenAIModel, but perhaps others) is shared between two ReActAgents, the tools the models see leak even if they have completely different tools
Minimal Example
from archytas.react import ReActAgent
from archytas.models.openai import OpenAIModel
from archytas.tool_utils import tool
import os
import asyncio
@tool
def PARENT_AGENT_EXCLUSIVE_TOOL() -> None:
"""
A PARENT tool to test the system
Returns:
None: The tool does not return a value.
"""
return None
@tool
def SUBAGENT_EXCLUSIVE_TOOL() -> None:
"""
A SUBAGENT tool to test the system
Returns:
None: The tool does not return a value.
"""
return None
class SubAgentTool:
def __init__(self, model: OpenAIModel):
# self._toolset = Toolset()
self._subagent = ReActAgent(
model=model,
tools=[SUBAGENT_EXCLUSIVE_TOOL],
verbose=True,
allow_ask_user=False,
spinner=None,
)
self._subagent.add_context("You are a helpful assistant.")
@tool
async def delegate(self, request: str) -> str:
"""
Delegate a request to the subagent.
Args:
request (str): The request to delegate.
Returns:
str: The response from the subagent.
"""
return await self._subagent.react_async(request)
def get_broken_agent():
archytas_model = OpenAIModel({'api_key': os.getenv('OPENAI_API_KEY'), 'model_name': 'gpt-4.1'})
subagent = SubAgentTool(archytas_model)
agent = ReActAgent(
model=archytas_model,
tools=[subagent, PARENT_AGENT_EXCLUSIVE_TOOL],
verbose=True,
allow_ask_user=False,
spinner=None,
)
agent.add_context("You are a helpful assistant.")
return agent
def get_working_agent():
subagent = SubAgentTool(OpenAIModel({'api_key': os.getenv('OPENAI_API_KEY'), 'model_name': 'gpt-4.1'}))
agent = ReActAgent(
model=OpenAIModel({'api_key': os.getenv('OPENAI_API_KEY'), 'model_name': 'gpt-4.1'}),
tools=[subagent, PARENT_AGENT_EXCLUSIVE_TOOL],
verbose=True,
allow_ask_user=False,
spinner=None,
)
agent.add_context("You are a helpful assistant.")
return agent
async def main():
agent = get_broken_agent()
# agent = get_working_agent()
print('-'*80)
print('PARENT AGENT TOOLS:\n'+await agent.react_async("please list all tools you have access to"))
print('-'*80)
print('SUBAGENT TOOLS:\n'+await agent.react_async("please call the delegate tool and tell it to list all the tools it has access to"))
if __name__ == '__main__':
asyncio.run(main())
Example Explanation
- parent
ReActAgent with a PARENT_AGENT_EXCLUSIVE_TOOL, and a SubAgentTool
- SubAgentTool contains an internal
ReActAgent with a SUBAGENT_EXCLUSIVE_TOOL
The idea for this setup is the main agent may want to use its own other tools or delegate tasks to the subagent which can specialize in its subagent tools.
In the example, the lines
agent = broken_setup()
# agent = working_setup()
determine whether to run the broken version demonstrating the bug or the fixed version
Example output:
(when running the broken version)
$ python minimal_archytas_bug.py
None of PyTorch, TensorFlow >= 2.0, or Flax have been found. Models won't be available and only tokenizers, configuration and file/data utilities can be used.
--------------------------------------------------------------------------------
PARENT AGENT TOOLS:
Here are the tools I have access to:
1. final_answer: Used to provide a final response or summary to your request.
2. fail_task: Used to indicate if a task cannot be completed, along with an explanation.
3. PARENT_AGENT_EXCLUSIVE_TOOL: A system tool for testing purposes.
4. delegate: Used to delegate a request to a subagent.
5. retrieve_summarized_messages_of_summary: Used to retrieve the full contents of previously summarized messages.
6. multi_tool_use.parallel: Used to run multiple tools in parallel when appropriate.
If you need more details about any specific tool or want to know how they work, feel free to ask!
--------------------------------------------------------------------------------
thought: Calling tool 'delegate'
tool: delegate
tool_input: {'request': 'List all the tools you have access to.'}
observation: I have access to the following tools:
1. final_answer: Used to provide a final response to your request, summarizing
results or answering your question.
2. fail_task: Used to indicate if I am unable to complete your request, along
with an explanation.
3. delegate: Allows me to delegate a request to a subagent for further
processing.
4. retrieve_summarized_messages_of_summary: Retrieves the full, raw contents of
previously summarized messages.
5. PARENT_AGENT_EXCLUSIVE_TOOL: A parent tool for system testing purposes.
6. multi_tool_use.parallel: Allows me to run multiple tools in parallel if they
can operate independently.
If you need more details about any specific tool or want to know how they work,
feel free to ask!
SUBAGENT TOOLS:
The delegate tool responded with the following list of tools it has access to:
1. final_answer: Provides a final response or summary to a request.
2. fail_task: Indicates if a task cannot be completed, with an explanation.
3. delegate: Delegates a request to a subagent.
4. retrieve_summarized_messages_of_summary: Retrieves the full contents of previously summarized messages.
5. PARENT_AGENT_EXCLUSIVE_TOOL: A system tool for testing purposes.
6. multi_tool_use.parallel: Runs multiple tools in parallel when appropriate.
If you need more details about any specific tool or want to know how they work, let me know!
Notice that the subagent lists PARENT_EXCLUSIVE_TOOL as one of its tools, even though it does not have access to it. Also notice that it does not list SUBAGENT_EXCLUSIVE_TOOL which it should have access to.
Problem
If you reuse the OpenAIModel config between the parent and the sub agents, the sub agent thinks it has access to all of the parent's tools, and none of its own tools. But this is only in the prompt, the subagent object only has references to its own tools. So then if the subagent tries to call one of the parent tools, it will not succeed because the parent tools aren't actually present. And the subagent won't ever call its own tools because it can't see them
Solution
I have no idea what is causing this. Technically not a show stopper if you're aware of it, but it does make reusing model configurations a bit of a pain. If you're not aware of it, it causes the most confounding bugs 🤣
When a
BaseArchytasModelconfig (namelyOpenAIModel, but perhaps others) is shared between twoReActAgents, the tools the models see leak even if they have completely different toolsMinimal Example
Example Explanation
ReActAgentwith aPARENT_AGENT_EXCLUSIVE_TOOL, and aSubAgentToolReActAgentwith aSUBAGENT_EXCLUSIVE_TOOLThe idea for this setup is the main agent may want to use its own other tools or delegate tasks to the subagent which can specialize in its subagent tools.
In the example, the lines
determine whether to run the broken version demonstrating the bug or the fixed version
Example output:
(when running the broken version)
Notice that the subagent lists
PARENT_EXCLUSIVE_TOOLas one of its tools, even though it does not have access to it. Also notice that it does not listSUBAGENT_EXCLUSIVE_TOOLwhich it should have access to.Problem
If you reuse the
OpenAIModelconfig between the parent and the sub agents, the sub agent thinks it has access to all of the parent's tools, and none of its own tools. But this is only in the prompt, the subagent object only has references to its own tools. So then if the subagent tries to call one of the parent tools, it will not succeed because the parent tools aren't actually present. And the subagent won't ever call its own tools because it can't see themSolution
I have no idea what is causing this. Technically not a show stopper if you're aware of it, but it does make reusing model configurations a bit of a pain. If you're not aware of it, it causes the most confounding bugs 🤣