Skip to content

Commit 78d7009

Browse files
authored
Implement Overwrite Tools Functionality in GPTAssistantAgent (microsoft#1434)
* added overwrite_tools logic to GPTAssistantAgent * added test test_gpt_assistant_tools_overwrite * fetch tools without get_assistant_tools method * fixed code formatting * fixed no .get found
1 parent d365e09 commit 78d7009

File tree

2 files changed

+143
-0
lines changed

2 files changed

+143
-0
lines changed

autogen/agentchat/contrib/gpt_assistant_agent.py

+28
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ def __init__(
2626
instructions: Optional[str] = None,
2727
llm_config: Optional[Union[Dict, bool]] = None,
2828
overwrite_instructions: bool = False,
29+
overwrite_tools: bool = False,
2930
**kwargs,
3031
):
3132
"""
@@ -46,6 +47,7 @@ def __init__(
4647
or build your own tools using Function calling. ref https://platform.openai.com/docs/assistants/tools
4748
- file_ids: files used by retrieval in run
4849
overwrite_instructions (bool): whether to overwrite the instructions of an existing assistant. This parameter is in effect only when assistant_id is specified in llm_config.
50+
overwrite_tools (bool): whether to overwrite the tools of an existing assistant. This parameter is in effect only when assistant_id is specified in llm_config.
4951
kwargs (dict): Additional configuration options for the agent.
5052
- verbose (bool): If set to True, enables more detailed output from the assistant thread.
5153
- Other kwargs: Except verbose, others are passed directly to ConversableAgent.
@@ -108,6 +110,32 @@ def __init__(
108110
"overwrite_instructions is False. Provided instructions will be used without permanently modifying the assistant in the API."
109111
)
110112

113+
# Check if tools are specified in llm_config
114+
specified_tools = llm_config.get("tools", None)
115+
116+
if specified_tools is None:
117+
# Check if the current assistant has tools defined
118+
if self._openai_assistant.tools:
119+
logger.warning(
120+
"No tools were provided for given assistant. Using existing tools from assistant API."
121+
)
122+
else:
123+
logger.info(
124+
"No tools were provided for the assistant, and the assistant currently has no tools set."
125+
)
126+
elif overwrite_tools is True:
127+
# Tools are specified and overwrite_tools is True; update the assistant's tools
128+
logger.warning(
129+
"overwrite_tools is True. Provided tools will be used and will modify the assistant in the API"
130+
)
131+
self._openai_assistant = self._openai_client.beta.assistants.update(
132+
assistant_id=openai_assistant_id,
133+
tools=llm_config.get("tools", []),
134+
)
135+
else:
136+
# Tools are specified but overwrite_tools is False; do not update the assistant's tools
137+
logger.warning("overwrite_tools is False. Using existing tools from assistant API.")
138+
111139
self._verbose = kwargs.pop("verbose", False)
112140
super().__init__(
113141
name=name, system_message=instructions, human_input_mode="NEVER", llm_config=llm_config, **kwargs

test/agentchat/contrib/test_gpt_assistant.py

+115
Original file line numberDiff line numberDiff line change
@@ -398,10 +398,125 @@ def test_assistant_mismatch_retrieval():
398398
assert len(candidates) == 0
399399

400400

401+
@pytest.mark.skipif(
402+
sys.platform in ["darwin", "win32"] or skip,
403+
reason="do not run on MacOS or windows OR dependency is not installed OR requested to skip",
404+
)
405+
def test_gpt_assistant_tools_overwrite():
406+
"""
407+
Test that the tools of a GPTAssistantAgent can be overwritten or not depending on the value of the
408+
`overwrite_tools` parameter when creating a new assistant with the same ID.
409+
410+
Steps:
411+
1. Create a new GPTAssistantAgent with a set of tools.
412+
2. Get the ID of the assistant.
413+
3. Create a new GPTAssistantAgent with the same ID but different tools and `overwrite_tools=True`.
414+
4. Check that the tools of the assistant have been overwritten with the new ones.
415+
"""
416+
417+
name = "For test_gpt_assistant_tools_overwrite"
418+
original_tools = [
419+
{
420+
"type": "function",
421+
"function": {
422+
"name": "calculateTax",
423+
"description": "Calculate tax for a given amount",
424+
"parameters": {
425+
"type": "object",
426+
"properties": {
427+
"amount": {"type": "number", "description": "The amount to calculate tax on"},
428+
"tax_rate": {"type": "number", "description": "The tax rate to apply"},
429+
},
430+
"required": ["amount", "tax_rate"],
431+
},
432+
},
433+
},
434+
{
435+
"type": "function",
436+
"function": {
437+
"name": "convertCurrency",
438+
"description": "Convert currency from one type to another",
439+
"parameters": {
440+
"type": "object",
441+
"properties": {
442+
"amount": {"type": "number", "description": "The amount to convert"},
443+
"from_currency": {"type": "string", "description": "Currency type to convert from"},
444+
"to_currency": {"type": "string", "description": "Currency type to convert to"},
445+
},
446+
"required": ["amount", "from_currency", "to_currency"],
447+
},
448+
},
449+
},
450+
]
451+
452+
new_tools = [
453+
{
454+
"type": "function",
455+
"function": {
456+
"name": "findRestaurant",
457+
"description": "Find a restaurant based on cuisine type and location",
458+
"parameters": {
459+
"type": "object",
460+
"properties": {
461+
"cuisine": {"type": "string", "description": "Type of cuisine"},
462+
"location": {"type": "string", "description": "City or area for the restaurant search"},
463+
},
464+
"required": ["cuisine", "location"],
465+
},
466+
},
467+
},
468+
{
469+
"type": "function",
470+
"function": {
471+
"name": "calculateMortgage",
472+
"description": "Calculate monthly mortgage payments",
473+
"parameters": {
474+
"type": "object",
475+
"properties": {
476+
"principal": {"type": "number", "description": "The principal loan amount"},
477+
"interest_rate": {"type": "number", "description": "Annual interest rate"},
478+
"years": {"type": "integer", "description": "Number of years for the loan"},
479+
},
480+
"required": ["principal", "interest_rate", "years"],
481+
},
482+
},
483+
},
484+
]
485+
486+
# Create an assistant with original tools
487+
assistant = GPTAssistantAgent(
488+
name,
489+
llm_config={
490+
"config_list": config_list,
491+
"tools": original_tools,
492+
},
493+
)
494+
495+
assistant_id = assistant.assistant_id
496+
497+
# Create a new assistant with new tools and overwrite_tools set to True
498+
assistant = GPTAssistantAgent(
499+
name,
500+
llm_config={
501+
"config_list": config_list,
502+
"assistant_id": assistant_id,
503+
"tools": new_tools,
504+
},
505+
overwrite_tools=True,
506+
)
507+
508+
# Add logic to retrieve the tools from the assistant and assert
509+
retrieved_tools = assistant.llm_config.get("tools", [])
510+
assistant.delete_assistant()
511+
512+
assert retrieved_tools == new_tools
513+
514+
401515
if __name__ == "__main__":
402516
test_gpt_assistant_chat()
403517
test_get_assistant_instructions()
404518
test_gpt_assistant_instructions_overwrite()
405519
test_gpt_assistant_existing_no_instructions()
406520
test_get_assistant_files()
407521
test_assistant_mismatch_retrieval()
522+
test_gpt_assistant_tools_overwrite()

0 commit comments

Comments
 (0)