You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

test_assistant_agent.py 39 kB

feat: Add thought process handling in tool calls and expose ThoughtEvent through stream in AgentChat (#5500) Resolves #5192 Test ```python import asyncio import os from random import randint from typing import List from autogen_core.tools import BaseTool, FunctionTool from autogen_ext.models.openai import OpenAIChatCompletionClient from autogen_agentchat.agents import AssistantAgent from autogen_agentchat.ui import Console async def get_current_time(city: str) -> str: return f"The current time in {city} is {randint(0, 23)}:{randint(0, 59)}." tools: List[BaseTool] = [ FunctionTool( get_current_time, name="get_current_time", description="Get current time for a city.", ), ] model_client = OpenAIChatCompletionClient( model="anthropic/claude-3.5-haiku-20241022", base_url="https://openrouter.ai/api/v1", api_key=os.environ["OPENROUTER_API_KEY"], model_info={ "family": "claude-3.5-haiku", "function_calling": True, "vision": False, "json_output": False, } ) agent = AssistantAgent( name="Agent", model_client=model_client, tools=tools, system_message= "You are an assistant with some tools that can be used to answer some questions", ) async def main() -> None: await Console(agent.run_stream(task="What is current time of Paris and Toronto?")) asyncio.run(main()) ``` ``` ---------- user ---------- What is current time of Paris and Toronto? ---------- Agent ---------- I'll help you find the current time for Paris and Toronto by using the get_current_time function for each city. ---------- Agent ---------- [FunctionCall(id='toolu_01NwP3fNAwcYKn1x656Dq9xW', arguments='{"city": "Paris"}', name='get_current_time'), FunctionCall(id='toolu_018d4cWSy3TxXhjgmLYFrfRt', arguments='{"city": "Toronto"}', name='get_current_time')] ---------- Agent ---------- [FunctionExecutionResult(content='The current time in Paris is 1:10.', call_id='toolu_01NwP3fNAwcYKn1x656Dq9xW', is_error=False), FunctionExecutionResult(content='The current time in Toronto is 7:28.', call_id='toolu_018d4cWSy3TxXhjgmLYFrfRt', is_error=False)] ---------- Agent ---------- The current time in Paris is 1:10. The current time in Toronto is 7:28. ``` --------- Co-authored-by: Jack Gerrits <jackgerrits@users.noreply.github.com>
1 year ago
feat: Add thought process handling in tool calls and expose ThoughtEvent through stream in AgentChat (#5500) Resolves #5192 Test ```python import asyncio import os from random import randint from typing import List from autogen_core.tools import BaseTool, FunctionTool from autogen_ext.models.openai import OpenAIChatCompletionClient from autogen_agentchat.agents import AssistantAgent from autogen_agentchat.ui import Console async def get_current_time(city: str) -> str: return f"The current time in {city} is {randint(0, 23)}:{randint(0, 59)}." tools: List[BaseTool] = [ FunctionTool( get_current_time, name="get_current_time", description="Get current time for a city.", ), ] model_client = OpenAIChatCompletionClient( model="anthropic/claude-3.5-haiku-20241022", base_url="https://openrouter.ai/api/v1", api_key=os.environ["OPENROUTER_API_KEY"], model_info={ "family": "claude-3.5-haiku", "function_calling": True, "vision": False, "json_output": False, } ) agent = AssistantAgent( name="Agent", model_client=model_client, tools=tools, system_message= "You are an assistant with some tools that can be used to answer some questions", ) async def main() -> None: await Console(agent.run_stream(task="What is current time of Paris and Toronto?")) asyncio.run(main()) ``` ``` ---------- user ---------- What is current time of Paris and Toronto? ---------- Agent ---------- I'll help you find the current time for Paris and Toronto by using the get_current_time function for each city. ---------- Agent ---------- [FunctionCall(id='toolu_01NwP3fNAwcYKn1x656Dq9xW', arguments='{"city": "Paris"}', name='get_current_time'), FunctionCall(id='toolu_018d4cWSy3TxXhjgmLYFrfRt', arguments='{"city": "Toronto"}', name='get_current_time')] ---------- Agent ---------- [FunctionExecutionResult(content='The current time in Paris is 1:10.', call_id='toolu_01NwP3fNAwcYKn1x656Dq9xW', is_error=False), FunctionExecutionResult(content='The current time in Toronto is 7:28.', call_id='toolu_018d4cWSy3TxXhjgmLYFrfRt', is_error=False)] ---------- Agent ---------- The current time in Paris is 1:10. The current time in Toronto is 7:28. ``` --------- Co-authored-by: Jack Gerrits <jackgerrits@users.noreply.github.com>
1 year ago
feat: Add thought process handling in tool calls and expose ThoughtEvent through stream in AgentChat (#5500) Resolves #5192 Test ```python import asyncio import os from random import randint from typing import List from autogen_core.tools import BaseTool, FunctionTool from autogen_ext.models.openai import OpenAIChatCompletionClient from autogen_agentchat.agents import AssistantAgent from autogen_agentchat.ui import Console async def get_current_time(city: str) -> str: return f"The current time in {city} is {randint(0, 23)}:{randint(0, 59)}." tools: List[BaseTool] = [ FunctionTool( get_current_time, name="get_current_time", description="Get current time for a city.", ), ] model_client = OpenAIChatCompletionClient( model="anthropic/claude-3.5-haiku-20241022", base_url="https://openrouter.ai/api/v1", api_key=os.environ["OPENROUTER_API_KEY"], model_info={ "family": "claude-3.5-haiku", "function_calling": True, "vision": False, "json_output": False, } ) agent = AssistantAgent( name="Agent", model_client=model_client, tools=tools, system_message= "You are an assistant with some tools that can be used to answer some questions", ) async def main() -> None: await Console(agent.run_stream(task="What is current time of Paris and Toronto?")) asyncio.run(main()) ``` ``` ---------- user ---------- What is current time of Paris and Toronto? ---------- Agent ---------- I'll help you find the current time for Paris and Toronto by using the get_current_time function for each city. ---------- Agent ---------- [FunctionCall(id='toolu_01NwP3fNAwcYKn1x656Dq9xW', arguments='{"city": "Paris"}', name='get_current_time'), FunctionCall(id='toolu_018d4cWSy3TxXhjgmLYFrfRt', arguments='{"city": "Toronto"}', name='get_current_time')] ---------- Agent ---------- [FunctionExecutionResult(content='The current time in Paris is 1:10.', call_id='toolu_01NwP3fNAwcYKn1x656Dq9xW', is_error=False), FunctionExecutionResult(content='The current time in Toronto is 7:28.', call_id='toolu_018d4cWSy3TxXhjgmLYFrfRt', is_error=False)] ---------- Agent ---------- The current time in Paris is 1:10. The current time in Toronto is 7:28. ``` --------- Co-authored-by: Jack Gerrits <jackgerrits@users.noreply.github.com>
1 year ago
feat: Add thought process handling in tool calls and expose ThoughtEvent through stream in AgentChat (#5500) Resolves #5192 Test ```python import asyncio import os from random import randint from typing import List from autogen_core.tools import BaseTool, FunctionTool from autogen_ext.models.openai import OpenAIChatCompletionClient from autogen_agentchat.agents import AssistantAgent from autogen_agentchat.ui import Console async def get_current_time(city: str) -> str: return f"The current time in {city} is {randint(0, 23)}:{randint(0, 59)}." tools: List[BaseTool] = [ FunctionTool( get_current_time, name="get_current_time", description="Get current time for a city.", ), ] model_client = OpenAIChatCompletionClient( model="anthropic/claude-3.5-haiku-20241022", base_url="https://openrouter.ai/api/v1", api_key=os.environ["OPENROUTER_API_KEY"], model_info={ "family": "claude-3.5-haiku", "function_calling": True, "vision": False, "json_output": False, } ) agent = AssistantAgent( name="Agent", model_client=model_client, tools=tools, system_message= "You are an assistant with some tools that can be used to answer some questions", ) async def main() -> None: await Console(agent.run_stream(task="What is current time of Paris and Toronto?")) asyncio.run(main()) ``` ``` ---------- user ---------- What is current time of Paris and Toronto? ---------- Agent ---------- I'll help you find the current time for Paris and Toronto by using the get_current_time function for each city. ---------- Agent ---------- [FunctionCall(id='toolu_01NwP3fNAwcYKn1x656Dq9xW', arguments='{"city": "Paris"}', name='get_current_time'), FunctionCall(id='toolu_018d4cWSy3TxXhjgmLYFrfRt', arguments='{"city": "Toronto"}', name='get_current_time')] ---------- Agent ---------- [FunctionExecutionResult(content='The current time in Paris is 1:10.', call_id='toolu_01NwP3fNAwcYKn1x656Dq9xW', is_error=False), FunctionExecutionResult(content='The current time in Toronto is 7:28.', call_id='toolu_018d4cWSy3TxXhjgmLYFrfRt', is_error=False)] ---------- Agent ---------- The current time in Paris is 1:10. The current time in Toronto is 7:28. ``` --------- Co-authored-by: Jack Gerrits <jackgerrits@users.noreply.github.com>
1 year ago
feat: Add thought process handling in tool calls and expose ThoughtEvent through stream in AgentChat (#5500) Resolves #5192 Test ```python import asyncio import os from random import randint from typing import List from autogen_core.tools import BaseTool, FunctionTool from autogen_ext.models.openai import OpenAIChatCompletionClient from autogen_agentchat.agents import AssistantAgent from autogen_agentchat.ui import Console async def get_current_time(city: str) -> str: return f"The current time in {city} is {randint(0, 23)}:{randint(0, 59)}." tools: List[BaseTool] = [ FunctionTool( get_current_time, name="get_current_time", description="Get current time for a city.", ), ] model_client = OpenAIChatCompletionClient( model="anthropic/claude-3.5-haiku-20241022", base_url="https://openrouter.ai/api/v1", api_key=os.environ["OPENROUTER_API_KEY"], model_info={ "family": "claude-3.5-haiku", "function_calling": True, "vision": False, "json_output": False, } ) agent = AssistantAgent( name="Agent", model_client=model_client, tools=tools, system_message= "You are an assistant with some tools that can be used to answer some questions", ) async def main() -> None: await Console(agent.run_stream(task="What is current time of Paris and Toronto?")) asyncio.run(main()) ``` ``` ---------- user ---------- What is current time of Paris and Toronto? ---------- Agent ---------- I'll help you find the current time for Paris and Toronto by using the get_current_time function for each city. ---------- Agent ---------- [FunctionCall(id='toolu_01NwP3fNAwcYKn1x656Dq9xW', arguments='{"city": "Paris"}', name='get_current_time'), FunctionCall(id='toolu_018d4cWSy3TxXhjgmLYFrfRt', arguments='{"city": "Toronto"}', name='get_current_time')] ---------- Agent ---------- [FunctionExecutionResult(content='The current time in Paris is 1:10.', call_id='toolu_01NwP3fNAwcYKn1x656Dq9xW', is_error=False), FunctionExecutionResult(content='The current time in Toronto is 7:28.', call_id='toolu_018d4cWSy3TxXhjgmLYFrfRt', is_error=False)] ---------- Agent ---------- The current time in Paris is 1:10. The current time in Toronto is 7:28. ``` --------- Co-authored-by: Jack Gerrits <jackgerrits@users.noreply.github.com>
1 year ago
feat: Add thought process handling in tool calls and expose ThoughtEvent through stream in AgentChat (#5500) Resolves #5192 Test ```python import asyncio import os from random import randint from typing import List from autogen_core.tools import BaseTool, FunctionTool from autogen_ext.models.openai import OpenAIChatCompletionClient from autogen_agentchat.agents import AssistantAgent from autogen_agentchat.ui import Console async def get_current_time(city: str) -> str: return f"The current time in {city} is {randint(0, 23)}:{randint(0, 59)}." tools: List[BaseTool] = [ FunctionTool( get_current_time, name="get_current_time", description="Get current time for a city.", ), ] model_client = OpenAIChatCompletionClient( model="anthropic/claude-3.5-haiku-20241022", base_url="https://openrouter.ai/api/v1", api_key=os.environ["OPENROUTER_API_KEY"], model_info={ "family": "claude-3.5-haiku", "function_calling": True, "vision": False, "json_output": False, } ) agent = AssistantAgent( name="Agent", model_client=model_client, tools=tools, system_message= "You are an assistant with some tools that can be used to answer some questions", ) async def main() -> None: await Console(agent.run_stream(task="What is current time of Paris and Toronto?")) asyncio.run(main()) ``` ``` ---------- user ---------- What is current time of Paris and Toronto? ---------- Agent ---------- I'll help you find the current time for Paris and Toronto by using the get_current_time function for each city. ---------- Agent ---------- [FunctionCall(id='toolu_01NwP3fNAwcYKn1x656Dq9xW', arguments='{"city": "Paris"}', name='get_current_time'), FunctionCall(id='toolu_018d4cWSy3TxXhjgmLYFrfRt', arguments='{"city": "Toronto"}', name='get_current_time')] ---------- Agent ---------- [FunctionExecutionResult(content='The current time in Paris is 1:10.', call_id='toolu_01NwP3fNAwcYKn1x656Dq9xW', is_error=False), FunctionExecutionResult(content='The current time in Toronto is 7:28.', call_id='toolu_018d4cWSy3TxXhjgmLYFrfRt', is_error=False)] ---------- Agent ---------- The current time in Paris is 1:10. The current time in Toronto is 7:28. ``` --------- Co-authored-by: Jack Gerrits <jackgerrits@users.noreply.github.com>
1 year ago
feat: Add thought process handling in tool calls and expose ThoughtEvent through stream in AgentChat (#5500) Resolves #5192 Test ```python import asyncio import os from random import randint from typing import List from autogen_core.tools import BaseTool, FunctionTool from autogen_ext.models.openai import OpenAIChatCompletionClient from autogen_agentchat.agents import AssistantAgent from autogen_agentchat.ui import Console async def get_current_time(city: str) -> str: return f"The current time in {city} is {randint(0, 23)}:{randint(0, 59)}." tools: List[BaseTool] = [ FunctionTool( get_current_time, name="get_current_time", description="Get current time for a city.", ), ] model_client = OpenAIChatCompletionClient( model="anthropic/claude-3.5-haiku-20241022", base_url="https://openrouter.ai/api/v1", api_key=os.environ["OPENROUTER_API_KEY"], model_info={ "family": "claude-3.5-haiku", "function_calling": True, "vision": False, "json_output": False, } ) agent = AssistantAgent( name="Agent", model_client=model_client, tools=tools, system_message= "You are an assistant with some tools that can be used to answer some questions", ) async def main() -> None: await Console(agent.run_stream(task="What is current time of Paris and Toronto?")) asyncio.run(main()) ``` ``` ---------- user ---------- What is current time of Paris and Toronto? ---------- Agent ---------- I'll help you find the current time for Paris and Toronto by using the get_current_time function for each city. ---------- Agent ---------- [FunctionCall(id='toolu_01NwP3fNAwcYKn1x656Dq9xW', arguments='{"city": "Paris"}', name='get_current_time'), FunctionCall(id='toolu_018d4cWSy3TxXhjgmLYFrfRt', arguments='{"city": "Toronto"}', name='get_current_time')] ---------- Agent ---------- [FunctionExecutionResult(content='The current time in Paris is 1:10.', call_id='toolu_01NwP3fNAwcYKn1x656Dq9xW', is_error=False), FunctionExecutionResult(content='The current time in Toronto is 7:28.', call_id='toolu_018d4cWSy3TxXhjgmLYFrfRt', is_error=False)] ---------- Agent ---------- The current time in Paris is 1:10. The current time in Toronto is 7:28. ``` --------- Co-authored-by: Jack Gerrits <jackgerrits@users.noreply.github.com>
1 year ago
feat: Add thought process handling in tool calls and expose ThoughtEvent through stream in AgentChat (#5500) Resolves #5192 Test ```python import asyncio import os from random import randint from typing import List from autogen_core.tools import BaseTool, FunctionTool from autogen_ext.models.openai import OpenAIChatCompletionClient from autogen_agentchat.agents import AssistantAgent from autogen_agentchat.ui import Console async def get_current_time(city: str) -> str: return f"The current time in {city} is {randint(0, 23)}:{randint(0, 59)}." tools: List[BaseTool] = [ FunctionTool( get_current_time, name="get_current_time", description="Get current time for a city.", ), ] model_client = OpenAIChatCompletionClient( model="anthropic/claude-3.5-haiku-20241022", base_url="https://openrouter.ai/api/v1", api_key=os.environ["OPENROUTER_API_KEY"], model_info={ "family": "claude-3.5-haiku", "function_calling": True, "vision": False, "json_output": False, } ) agent = AssistantAgent( name="Agent", model_client=model_client, tools=tools, system_message= "You are an assistant with some tools that can be used to answer some questions", ) async def main() -> None: await Console(agent.run_stream(task="What is current time of Paris and Toronto?")) asyncio.run(main()) ``` ``` ---------- user ---------- What is current time of Paris and Toronto? ---------- Agent ---------- I'll help you find the current time for Paris and Toronto by using the get_current_time function for each city. ---------- Agent ---------- [FunctionCall(id='toolu_01NwP3fNAwcYKn1x656Dq9xW', arguments='{"city": "Paris"}', name='get_current_time'), FunctionCall(id='toolu_018d4cWSy3TxXhjgmLYFrfRt', arguments='{"city": "Toronto"}', name='get_current_time')] ---------- Agent ---------- [FunctionExecutionResult(content='The current time in Paris is 1:10.', call_id='toolu_01NwP3fNAwcYKn1x656Dq9xW', is_error=False), FunctionExecutionResult(content='The current time in Toronto is 7:28.', call_id='toolu_018d4cWSy3TxXhjgmLYFrfRt', is_error=False)] ---------- Agent ---------- The current time in Paris is 1:10. The current time in Toronto is 7:28. ``` --------- Co-authored-by: Jack Gerrits <jackgerrits@users.noreply.github.com>
1 year ago
feat: Add thought process handling in tool calls and expose ThoughtEvent through stream in AgentChat (#5500) Resolves #5192 Test ```python import asyncio import os from random import randint from typing import List from autogen_core.tools import BaseTool, FunctionTool from autogen_ext.models.openai import OpenAIChatCompletionClient from autogen_agentchat.agents import AssistantAgent from autogen_agentchat.ui import Console async def get_current_time(city: str) -> str: return f"The current time in {city} is {randint(0, 23)}:{randint(0, 59)}." tools: List[BaseTool] = [ FunctionTool( get_current_time, name="get_current_time", description="Get current time for a city.", ), ] model_client = OpenAIChatCompletionClient( model="anthropic/claude-3.5-haiku-20241022", base_url="https://openrouter.ai/api/v1", api_key=os.environ["OPENROUTER_API_KEY"], model_info={ "family": "claude-3.5-haiku", "function_calling": True, "vision": False, "json_output": False, } ) agent = AssistantAgent( name="Agent", model_client=model_client, tools=tools, system_message= "You are an assistant with some tools that can be used to answer some questions", ) async def main() -> None: await Console(agent.run_stream(task="What is current time of Paris and Toronto?")) asyncio.run(main()) ``` ``` ---------- user ---------- What is current time of Paris and Toronto? ---------- Agent ---------- I'll help you find the current time for Paris and Toronto by using the get_current_time function for each city. ---------- Agent ---------- [FunctionCall(id='toolu_01NwP3fNAwcYKn1x656Dq9xW', arguments='{"city": "Paris"}', name='get_current_time'), FunctionCall(id='toolu_018d4cWSy3TxXhjgmLYFrfRt', arguments='{"city": "Toronto"}', name='get_current_time')] ---------- Agent ---------- [FunctionExecutionResult(content='The current time in Paris is 1:10.', call_id='toolu_01NwP3fNAwcYKn1x656Dq9xW', is_error=False), FunctionExecutionResult(content='The current time in Toronto is 7:28.', call_id='toolu_018d4cWSy3TxXhjgmLYFrfRt', is_error=False)] ---------- Agent ---------- The current time in Paris is 1:10. The current time in Toronto is 7:28. ``` --------- Co-authored-by: Jack Gerrits <jackgerrits@users.noreply.github.com>
1 year ago
feat: Add thought process handling in tool calls and expose ThoughtEvent through stream in AgentChat (#5500) Resolves #5192 Test ```python import asyncio import os from random import randint from typing import List from autogen_core.tools import BaseTool, FunctionTool from autogen_ext.models.openai import OpenAIChatCompletionClient from autogen_agentchat.agents import AssistantAgent from autogen_agentchat.ui import Console async def get_current_time(city: str) -> str: return f"The current time in {city} is {randint(0, 23)}:{randint(0, 59)}." tools: List[BaseTool] = [ FunctionTool( get_current_time, name="get_current_time", description="Get current time for a city.", ), ] model_client = OpenAIChatCompletionClient( model="anthropic/claude-3.5-haiku-20241022", base_url="https://openrouter.ai/api/v1", api_key=os.environ["OPENROUTER_API_KEY"], model_info={ "family": "claude-3.5-haiku", "function_calling": True, "vision": False, "json_output": False, } ) agent = AssistantAgent( name="Agent", model_client=model_client, tools=tools, system_message= "You are an assistant with some tools that can be used to answer some questions", ) async def main() -> None: await Console(agent.run_stream(task="What is current time of Paris and Toronto?")) asyncio.run(main()) ``` ``` ---------- user ---------- What is current time of Paris and Toronto? ---------- Agent ---------- I'll help you find the current time for Paris and Toronto by using the get_current_time function for each city. ---------- Agent ---------- [FunctionCall(id='toolu_01NwP3fNAwcYKn1x656Dq9xW', arguments='{"city": "Paris"}', name='get_current_time'), FunctionCall(id='toolu_018d4cWSy3TxXhjgmLYFrfRt', arguments='{"city": "Toronto"}', name='get_current_time')] ---------- Agent ---------- [FunctionExecutionResult(content='The current time in Paris is 1:10.', call_id='toolu_01NwP3fNAwcYKn1x656Dq9xW', is_error=False), FunctionExecutionResult(content='The current time in Toronto is 7:28.', call_id='toolu_018d4cWSy3TxXhjgmLYFrfRt', is_error=False)] ---------- Agent ---------- The current time in Paris is 1:10. The current time in Toronto is 7:28. ``` --------- Co-authored-by: Jack Gerrits <jackgerrits@users.noreply.github.com>
1 year ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026
  1. import asyncio
  2. import json
  3. import logging
  4. from typing import Any, AsyncGenerator, List
  5. import pytest
  6. from autogen_agentchat import EVENT_LOGGER_NAME
  7. from autogen_agentchat.agents import AssistantAgent
  8. from autogen_agentchat.base import Handoff, TaskResult
  9. from autogen_agentchat.messages import (
  10. ChatMessage,
  11. HandoffMessage,
  12. MemoryQueryEvent,
  13. ModelClientStreamingChunkEvent,
  14. MultiModalMessage,
  15. TextMessage,
  16. ThoughtEvent,
  17. ToolCallExecutionEvent,
  18. ToolCallRequestEvent,
  19. ToolCallSummaryMessage,
  20. )
  21. from autogen_core import ComponentModel, FunctionCall, Image
  22. from autogen_core.memory import ListMemory, Memory, MemoryContent, MemoryMimeType, MemoryQueryResult
  23. from autogen_core.model_context import BufferedChatCompletionContext
  24. from autogen_core.models import (
  25. AssistantMessage,
  26. CreateResult,
  27. FunctionExecutionResult,
  28. LLMMessage,
  29. RequestUsage,
  30. SystemMessage,
  31. UserMessage,
  32. )
  33. from autogen_core.models._model_client import ModelFamily
  34. from autogen_core.tools import FunctionTool
  35. from autogen_ext.models.openai import OpenAIChatCompletionClient
  36. from autogen_ext.models.replay import ReplayChatCompletionClient
  37. from openai.resources.chat.completions import AsyncCompletions
  38. from openai.types.chat.chat_completion import ChatCompletion, Choice
  39. from openai.types.chat.chat_completion_chunk import ChatCompletionChunk
  40. from openai.types.chat.chat_completion_message import ChatCompletionMessage
  41. from openai.types.chat.chat_completion_message_tool_call import (
  42. ChatCompletionMessageToolCall,
  43. Function,
  44. )
  45. from openai.types.completion_usage import CompletionUsage
  46. from utils import FileLogHandler
  47. logger = logging.getLogger(EVENT_LOGGER_NAME)
  48. logger.setLevel(logging.DEBUG)
  49. logger.addHandler(FileLogHandler("test_assistant_agent.log"))
  50. class _MockChatCompletion:
  51. def __init__(self, chat_completions: List[ChatCompletion]) -> None:
  52. self._saved_chat_completions = chat_completions
  53. self.curr_index = 0
  54. self.calls: List[List[LLMMessage]] = []
  55. async def mock_create(
  56. self, *args: Any, **kwargs: Any
  57. ) -> ChatCompletion | AsyncGenerator[ChatCompletionChunk, None]:
  58. self.calls.append(kwargs["messages"]) # Save the call
  59. await asyncio.sleep(0.1)
  60. completion = self._saved_chat_completions[self.curr_index]
  61. self.curr_index += 1
  62. return completion
  63. def _pass_function(input: str) -> str:
  64. return "pass"
  65. async def _fail_function(input: str) -> str:
  66. return "fail"
  67. async def _echo_function(input: str) -> str:
  68. return input
  69. @pytest.mark.asyncio
  70. async def test_run_with_tools(monkeypatch: pytest.MonkeyPatch) -> None:
  71. model = "gpt-4o-2024-05-13"
  72. chat_completions = [
  73. ChatCompletion(
  74. id="id1",
  75. choices=[
  76. Choice(
  77. finish_reason="tool_calls",
  78. index=0,
  79. message=ChatCompletionMessage(
  80. content="Calling pass function",
  81. tool_calls=[
  82. ChatCompletionMessageToolCall(
  83. id="1",
  84. type="function",
  85. function=Function(
  86. name="_pass_function",
  87. arguments=json.dumps({"input": "task"}),
  88. ),
  89. )
  90. ],
  91. role="assistant",
  92. ),
  93. )
  94. ],
  95. created=0,
  96. model=model,
  97. object="chat.completion",
  98. usage=CompletionUsage(prompt_tokens=10, completion_tokens=5, total_tokens=0),
  99. ),
  100. ChatCompletion(
  101. id="id2",
  102. choices=[
  103. Choice(
  104. finish_reason="stop",
  105. index=0,
  106. message=ChatCompletionMessage(content="pass", role="assistant"),
  107. )
  108. ],
  109. created=0,
  110. model=model,
  111. object="chat.completion",
  112. usage=CompletionUsage(prompt_tokens=10, completion_tokens=5, total_tokens=0),
  113. ),
  114. ChatCompletion(
  115. id="id2",
  116. choices=[
  117. Choice(
  118. finish_reason="stop",
  119. index=0,
  120. message=ChatCompletionMessage(content="TERMINATE", role="assistant"),
  121. )
  122. ],
  123. created=0,
  124. model=model,
  125. object="chat.completion",
  126. usage=CompletionUsage(prompt_tokens=10, completion_tokens=5, total_tokens=0),
  127. ),
  128. ]
  129. mock = _MockChatCompletion(chat_completions)
  130. monkeypatch.setattr(AsyncCompletions, "create", mock.mock_create)
  131. agent = AssistantAgent(
  132. "tool_use_agent",
  133. model_client=OpenAIChatCompletionClient(model=model, api_key=""),
  134. tools=[
  135. _pass_function,
  136. _fail_function,
  137. FunctionTool(_echo_function, description="Echo"),
  138. ],
  139. )
  140. result = await agent.run(task="task")
  141. assert len(result.messages) == 5
  142. assert isinstance(result.messages[0], TextMessage)
  143. assert result.messages[0].models_usage is None
  144. assert isinstance(result.messages[1], ThoughtEvent)
  145. assert result.messages[1].content == "Calling pass function"
  146. assert isinstance(result.messages[2], ToolCallRequestEvent)
  147. assert result.messages[2].models_usage is not None
  148. assert result.messages[2].models_usage.completion_tokens == 5
  149. assert result.messages[2].models_usage.prompt_tokens == 10
  150. assert isinstance(result.messages[3], ToolCallExecutionEvent)
  151. assert result.messages[3].models_usage is None
  152. assert isinstance(result.messages[4], ToolCallSummaryMessage)
  153. assert result.messages[4].content == "pass"
  154. assert result.messages[4].models_usage is None
  155. # Test streaming.
  156. mock.curr_index = 0 # Reset the mock
  157. index = 0
  158. async for message in agent.run_stream(task="task"):
  159. if isinstance(message, TaskResult):
  160. assert message == result
  161. else:
  162. assert message == result.messages[index]
  163. index += 1
  164. # Test state saving and loading.
  165. state = await agent.save_state()
  166. agent2 = AssistantAgent(
  167. "tool_use_agent",
  168. model_client=OpenAIChatCompletionClient(model=model, api_key=""),
  169. tools=[_pass_function, _fail_function, FunctionTool(_echo_function, description="Echo")],
  170. )
  171. await agent2.load_state(state)
  172. state2 = await agent2.save_state()
  173. assert state == state2
  174. @pytest.mark.asyncio
  175. async def test_run_with_tools_and_reflection(monkeypatch: pytest.MonkeyPatch) -> None:
  176. model = "gpt-4o-2024-05-13"
  177. chat_completions = [
  178. ChatCompletion(
  179. id="id1",
  180. choices=[
  181. Choice(
  182. finish_reason="tool_calls",
  183. index=0,
  184. message=ChatCompletionMessage(
  185. content=None,
  186. tool_calls=[
  187. ChatCompletionMessageToolCall(
  188. id="1",
  189. type="function",
  190. function=Function(
  191. name="_pass_function",
  192. arguments=json.dumps({"input": "task"}),
  193. ),
  194. )
  195. ],
  196. role="assistant",
  197. ),
  198. )
  199. ],
  200. created=0,
  201. model=model,
  202. object="chat.completion",
  203. usage=CompletionUsage(prompt_tokens=10, completion_tokens=5, total_tokens=0),
  204. ),
  205. ChatCompletion(
  206. id="id2",
  207. choices=[
  208. Choice(finish_reason="stop", index=0, message=ChatCompletionMessage(content="Hello", role="assistant"))
  209. ],
  210. created=0,
  211. model=model,
  212. object="chat.completion",
  213. usage=CompletionUsage(prompt_tokens=10, completion_tokens=5, total_tokens=0),
  214. ),
  215. ChatCompletion(
  216. id="id2",
  217. choices=[
  218. Choice(
  219. finish_reason="stop", index=0, message=ChatCompletionMessage(content="TERMINATE", role="assistant")
  220. )
  221. ],
  222. created=0,
  223. model=model,
  224. object="chat.completion",
  225. usage=CompletionUsage(prompt_tokens=10, completion_tokens=5, total_tokens=0),
  226. ),
  227. ]
  228. mock = _MockChatCompletion(chat_completions)
  229. monkeypatch.setattr(AsyncCompletions, "create", mock.mock_create)
  230. agent = AssistantAgent(
  231. "tool_use_agent",
  232. model_client=OpenAIChatCompletionClient(model=model, api_key=""),
  233. tools=[_pass_function, _fail_function, FunctionTool(_echo_function, description="Echo")],
  234. reflect_on_tool_use=True,
  235. )
  236. result = await agent.run(task="task")
  237. assert len(result.messages) == 4
  238. assert isinstance(result.messages[0], TextMessage)
  239. assert result.messages[0].models_usage is None
  240. assert isinstance(result.messages[1], ToolCallRequestEvent)
  241. assert result.messages[1].models_usage is not None
  242. assert result.messages[1].models_usage.completion_tokens == 5
  243. assert result.messages[1].models_usage.prompt_tokens == 10
  244. assert isinstance(result.messages[2], ToolCallExecutionEvent)
  245. assert result.messages[2].models_usage is None
  246. assert isinstance(result.messages[3], TextMessage)
  247. assert result.messages[3].content == "Hello"
  248. assert result.messages[3].models_usage is not None
  249. assert result.messages[3].models_usage.completion_tokens == 5
  250. assert result.messages[3].models_usage.prompt_tokens == 10
  251. # Test streaming.
  252. mock.curr_index = 0 # pyright: ignore
  253. index = 0
  254. async for message in agent.run_stream(task="task"):
  255. if isinstance(message, TaskResult):
  256. assert message == result
  257. else:
  258. assert message == result.messages[index]
  259. index += 1
  260. # Test state saving and loading.
  261. state = await agent.save_state()
  262. agent2 = AssistantAgent(
  263. "tool_use_agent",
  264. model_client=OpenAIChatCompletionClient(model=model, api_key=""),
  265. tools=[
  266. _pass_function,
  267. _fail_function,
  268. FunctionTool(_echo_function, description="Echo"),
  269. ],
  270. )
  271. await agent2.load_state(state)
  272. state2 = await agent2.save_state()
  273. assert state == state2
  274. @pytest.mark.asyncio
  275. async def test_run_with_parallel_tools(monkeypatch: pytest.MonkeyPatch) -> None:
  276. model = "gpt-4o-2024-05-13"
  277. chat_completions = [
  278. ChatCompletion(
  279. id="id1",
  280. choices=[
  281. Choice(
  282. finish_reason="tool_calls",
  283. index=0,
  284. message=ChatCompletionMessage(
  285. content="Calling pass and echo functions",
  286. tool_calls=[
  287. ChatCompletionMessageToolCall(
  288. id="1",
  289. type="function",
  290. function=Function(
  291. name="_pass_function",
  292. arguments=json.dumps({"input": "task1"}),
  293. ),
  294. ),
  295. ChatCompletionMessageToolCall(
  296. id="2",
  297. type="function",
  298. function=Function(
  299. name="_pass_function",
  300. arguments=json.dumps({"input": "task2"}),
  301. ),
  302. ),
  303. ChatCompletionMessageToolCall(
  304. id="3",
  305. type="function",
  306. function=Function(
  307. name="_echo_function",
  308. arguments=json.dumps({"input": "task3"}),
  309. ),
  310. ),
  311. ],
  312. role="assistant",
  313. ),
  314. )
  315. ],
  316. created=0,
  317. model=model,
  318. object="chat.completion",
  319. usage=CompletionUsage(prompt_tokens=10, completion_tokens=5, total_tokens=0),
  320. ),
  321. ChatCompletion(
  322. id="id2",
  323. choices=[
  324. Choice(
  325. finish_reason="stop",
  326. index=0,
  327. message=ChatCompletionMessage(content="pass", role="assistant"),
  328. )
  329. ],
  330. created=0,
  331. model=model,
  332. object="chat.completion",
  333. usage=CompletionUsage(prompt_tokens=10, completion_tokens=5, total_tokens=0),
  334. ),
  335. ChatCompletion(
  336. id="id2",
  337. choices=[
  338. Choice(
  339. finish_reason="stop",
  340. index=0,
  341. message=ChatCompletionMessage(content="TERMINATE", role="assistant"),
  342. )
  343. ],
  344. created=0,
  345. model=model,
  346. object="chat.completion",
  347. usage=CompletionUsage(prompt_tokens=10, completion_tokens=5, total_tokens=0),
  348. ),
  349. ]
  350. mock = _MockChatCompletion(chat_completions)
  351. monkeypatch.setattr(AsyncCompletions, "create", mock.mock_create)
  352. agent = AssistantAgent(
  353. "tool_use_agent",
  354. model_client=OpenAIChatCompletionClient(model=model, api_key=""),
  355. tools=[
  356. _pass_function,
  357. _fail_function,
  358. FunctionTool(_echo_function, description="Echo"),
  359. ],
  360. )
  361. result = await agent.run(task="task")
  362. assert len(result.messages) == 5
  363. assert isinstance(result.messages[0], TextMessage)
  364. assert result.messages[0].models_usage is None
  365. assert isinstance(result.messages[1], ThoughtEvent)
  366. assert result.messages[1].content == "Calling pass and echo functions"
  367. assert isinstance(result.messages[2], ToolCallRequestEvent)
  368. assert result.messages[2].content == [
  369. FunctionCall(id="1", arguments=r'{"input": "task1"}', name="_pass_function"),
  370. FunctionCall(id="2", arguments=r'{"input": "task2"}', name="_pass_function"),
  371. FunctionCall(id="3", arguments=r'{"input": "task3"}', name="_echo_function"),
  372. ]
  373. assert result.messages[2].models_usage is not None
  374. assert result.messages[2].models_usage.completion_tokens == 5
  375. assert result.messages[2].models_usage.prompt_tokens == 10
  376. assert isinstance(result.messages[3], ToolCallExecutionEvent)
  377. expected_content = [
  378. FunctionExecutionResult(call_id="1", content="pass", is_error=False),
  379. FunctionExecutionResult(call_id="2", content="pass", is_error=False),
  380. FunctionExecutionResult(call_id="3", content="task3", is_error=False),
  381. ]
  382. for expected in expected_content:
  383. assert expected in result.messages[3].content
  384. assert result.messages[3].models_usage is None
  385. assert isinstance(result.messages[4], ToolCallSummaryMessage)
  386. assert result.messages[4].content == "pass\npass\ntask3"
  387. assert result.messages[4].models_usage is None
  388. # Test streaming.
  389. mock.curr_index = 0 # Reset the mock
  390. index = 0
  391. async for message in agent.run_stream(task="task"):
  392. if isinstance(message, TaskResult):
  393. assert message == result
  394. else:
  395. assert message == result.messages[index]
  396. index += 1
  397. # Test state saving and loading.
  398. state = await agent.save_state()
  399. agent2 = AssistantAgent(
  400. "tool_use_agent",
  401. model_client=OpenAIChatCompletionClient(model=model, api_key=""),
  402. tools=[_pass_function, _fail_function, FunctionTool(_echo_function, description="Echo")],
  403. )
  404. await agent2.load_state(state)
  405. state2 = await agent2.save_state()
  406. assert state == state2
  407. @pytest.mark.asyncio
  408. async def test_run_with_parallel_tools_with_empty_call_ids(monkeypatch: pytest.MonkeyPatch) -> None:
  409. model = "gpt-4o-2024-05-13"
  410. chat_completions = [
  411. ChatCompletion(
  412. id="id1",
  413. choices=[
  414. Choice(
  415. finish_reason="tool_calls",
  416. index=0,
  417. message=ChatCompletionMessage(
  418. content=None,
  419. tool_calls=[
  420. ChatCompletionMessageToolCall(
  421. id="",
  422. type="function",
  423. function=Function(
  424. name="_pass_function",
  425. arguments=json.dumps({"input": "task1"}),
  426. ),
  427. ),
  428. ChatCompletionMessageToolCall(
  429. id="",
  430. type="function",
  431. function=Function(
  432. name="_pass_function",
  433. arguments=json.dumps({"input": "task2"}),
  434. ),
  435. ),
  436. ChatCompletionMessageToolCall(
  437. id="",
  438. type="function",
  439. function=Function(
  440. name="_echo_function",
  441. arguments=json.dumps({"input": "task3"}),
  442. ),
  443. ),
  444. ],
  445. role="assistant",
  446. ),
  447. )
  448. ],
  449. created=0,
  450. model=model,
  451. object="chat.completion",
  452. usage=CompletionUsage(prompt_tokens=10, completion_tokens=5, total_tokens=0),
  453. ),
  454. ChatCompletion(
  455. id="id2",
  456. choices=[
  457. Choice(
  458. finish_reason="stop",
  459. index=0,
  460. message=ChatCompletionMessage(content="pass", role="assistant"),
  461. )
  462. ],
  463. created=0,
  464. model=model,
  465. object="chat.completion",
  466. usage=CompletionUsage(prompt_tokens=10, completion_tokens=5, total_tokens=0),
  467. ),
  468. ChatCompletion(
  469. id="id2",
  470. choices=[
  471. Choice(
  472. finish_reason="stop",
  473. index=0,
  474. message=ChatCompletionMessage(content="TERMINATE", role="assistant"),
  475. )
  476. ],
  477. created=0,
  478. model=model,
  479. object="chat.completion",
  480. usage=CompletionUsage(prompt_tokens=10, completion_tokens=5, total_tokens=0),
  481. ),
  482. ]
  483. mock = _MockChatCompletion(chat_completions)
  484. monkeypatch.setattr(AsyncCompletions, "create", mock.mock_create)
  485. agent = AssistantAgent(
  486. "tool_use_agent",
  487. model_client=OpenAIChatCompletionClient(model=model, api_key=""),
  488. tools=[
  489. _pass_function,
  490. _fail_function,
  491. FunctionTool(_echo_function, description="Echo"),
  492. ],
  493. )
  494. result = await agent.run(task="task")
  495. assert len(result.messages) == 4
  496. assert isinstance(result.messages[0], TextMessage)
  497. assert result.messages[0].models_usage is None
  498. assert isinstance(result.messages[1], ToolCallRequestEvent)
  499. assert result.messages[1].content == [
  500. FunctionCall(id="", arguments=r'{"input": "task1"}', name="_pass_function"),
  501. FunctionCall(id="", arguments=r'{"input": "task2"}', name="_pass_function"),
  502. FunctionCall(id="", arguments=r'{"input": "task3"}', name="_echo_function"),
  503. ]
  504. assert result.messages[1].models_usage is not None
  505. assert result.messages[1].models_usage.completion_tokens == 5
  506. assert result.messages[1].models_usage.prompt_tokens == 10
  507. assert isinstance(result.messages[2], ToolCallExecutionEvent)
  508. expected_content = [
  509. FunctionExecutionResult(call_id="", content="pass", is_error=False),
  510. FunctionExecutionResult(call_id="", content="pass", is_error=False),
  511. FunctionExecutionResult(call_id="", content="task3", is_error=False),
  512. ]
  513. for expected in expected_content:
  514. assert expected in result.messages[2].content
  515. assert result.messages[2].models_usage is None
  516. assert isinstance(result.messages[3], ToolCallSummaryMessage)
  517. assert result.messages[3].content == "pass\npass\ntask3"
  518. assert result.messages[3].models_usage is None
  519. # Test streaming.
  520. mock.curr_index = 0 # Reset the mock
  521. index = 0
  522. async for message in agent.run_stream(task="task"):
  523. if isinstance(message, TaskResult):
  524. assert message == result
  525. else:
  526. assert message == result.messages[index]
  527. index += 1
  528. # Test state saving and loading.
  529. state = await agent.save_state()
  530. agent2 = AssistantAgent(
  531. "tool_use_agent",
  532. model_client=OpenAIChatCompletionClient(model=model, api_key=""),
  533. tools=[_pass_function, _fail_function, FunctionTool(_echo_function, description="Echo")],
  534. )
  535. await agent2.load_state(state)
  536. state2 = await agent2.save_state()
  537. assert state == state2
  538. @pytest.mark.asyncio
  539. async def test_handoffs(monkeypatch: pytest.MonkeyPatch) -> None:
  540. handoff = Handoff(target="agent2")
  541. model = "gpt-4o-2024-05-13"
  542. chat_completions = [
  543. ChatCompletion(
  544. id="id1",
  545. choices=[
  546. Choice(
  547. finish_reason="tool_calls",
  548. index=0,
  549. message=ChatCompletionMessage(
  550. content=None,
  551. tool_calls=[
  552. ChatCompletionMessageToolCall(
  553. id="1",
  554. type="function",
  555. function=Function(
  556. name=handoff.name,
  557. arguments=json.dumps({}),
  558. ),
  559. )
  560. ],
  561. role="assistant",
  562. ),
  563. )
  564. ],
  565. created=0,
  566. model=model,
  567. object="chat.completion",
  568. usage=CompletionUsage(prompt_tokens=42, completion_tokens=43, total_tokens=85),
  569. ),
  570. ]
  571. mock = _MockChatCompletion(chat_completions)
  572. monkeypatch.setattr(AsyncCompletions, "create", mock.mock_create)
  573. tool_use_agent = AssistantAgent(
  574. "tool_use_agent",
  575. model_client=OpenAIChatCompletionClient(model=model, api_key=""),
  576. tools=[
  577. _pass_function,
  578. _fail_function,
  579. FunctionTool(_echo_function, description="Echo"),
  580. ],
  581. handoffs=[handoff],
  582. )
  583. assert HandoffMessage in tool_use_agent.produced_message_types
  584. result = await tool_use_agent.run(task="task")
  585. assert len(result.messages) == 4
  586. assert isinstance(result.messages[0], TextMessage)
  587. assert result.messages[0].models_usage is None
  588. assert isinstance(result.messages[1], ToolCallRequestEvent)
  589. assert result.messages[1].models_usage is not None
  590. assert result.messages[1].models_usage.completion_tokens == 43
  591. assert result.messages[1].models_usage.prompt_tokens == 42
  592. assert isinstance(result.messages[2], ToolCallExecutionEvent)
  593. assert result.messages[2].models_usage is None
  594. assert isinstance(result.messages[3], HandoffMessage)
  595. assert result.messages[3].content == handoff.message
  596. assert result.messages[3].target == handoff.target
  597. assert result.messages[3].models_usage is None
  598. # Test streaming.
  599. mock.curr_index = 0 # pyright: ignore
  600. index = 0
  601. async for message in tool_use_agent.run_stream(task="task"):
  602. if isinstance(message, TaskResult):
  603. assert message == result
  604. else:
  605. assert message == result.messages[index]
  606. index += 1
  607. @pytest.mark.asyncio
  608. async def test_multi_modal_task(monkeypatch: pytest.MonkeyPatch) -> None:
  609. model = "gpt-4o-2024-05-13"
  610. chat_completions = [
  611. ChatCompletion(
  612. id="id2",
  613. choices=[
  614. Choice(
  615. finish_reason="stop",
  616. index=0,
  617. message=ChatCompletionMessage(content="Hello", role="assistant"),
  618. )
  619. ],
  620. created=0,
  621. model=model,
  622. object="chat.completion",
  623. usage=CompletionUsage(prompt_tokens=10, completion_tokens=5, total_tokens=0),
  624. ),
  625. ]
  626. mock = _MockChatCompletion(chat_completions)
  627. monkeypatch.setattr(AsyncCompletions, "create", mock.mock_create)
  628. agent = AssistantAgent(
  629. name="assistant",
  630. model_client=OpenAIChatCompletionClient(model=model, api_key=""),
  631. )
  632. # Generate a random base64 image.
  633. img_base64 = "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAADElEQVR4nGP4//8/AAX+Av4N70a4AAAAAElFTkSuQmCC"
  634. result = await agent.run(task=MultiModalMessage(source="user", content=["Test", Image.from_base64(img_base64)]))
  635. assert len(result.messages) == 2
  636. @pytest.mark.asyncio
  637. async def test_invalid_model_capabilities() -> None:
  638. model = "random-model"
  639. model_client = OpenAIChatCompletionClient(
  640. model=model,
  641. api_key="",
  642. model_info={"vision": False, "function_calling": False, "json_output": False, "family": ModelFamily.UNKNOWN},
  643. )
  644. with pytest.raises(ValueError):
  645. agent = AssistantAgent(
  646. name="assistant",
  647. model_client=model_client,
  648. tools=[
  649. _pass_function,
  650. _fail_function,
  651. FunctionTool(_echo_function, description="Echo"),
  652. ],
  653. )
  654. await agent.run(task=TextMessage(source="user", content="Test"))
  655. with pytest.raises(ValueError):
  656. agent = AssistantAgent(name="assistant", model_client=model_client, handoffs=["agent2"])
  657. await agent.run(task=TextMessage(source="user", content="Test"))
  658. @pytest.mark.asyncio
  659. async def test_remove_images(monkeypatch: pytest.MonkeyPatch) -> None:
  660. model = "random-model"
  661. model_client_1 = OpenAIChatCompletionClient(
  662. model=model,
  663. api_key="",
  664. model_info={"vision": False, "function_calling": False, "json_output": False, "family": ModelFamily.UNKNOWN},
  665. )
  666. model_client_2 = OpenAIChatCompletionClient(
  667. model=model,
  668. api_key="",
  669. model_info={"vision": True, "function_calling": False, "json_output": False, "family": ModelFamily.UNKNOWN},
  670. )
  671. img_base64 = "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAADElEQVR4nGP4//8/AAX+Av4N70a4AAAAAElFTkSuQmCC"
  672. messages: List[LLMMessage] = [
  673. SystemMessage(content="System.1"),
  674. UserMessage(content=["User.1", Image.from_base64(img_base64)], source="user.1"),
  675. AssistantMessage(content="Assistant.1", source="assistant.1"),
  676. UserMessage(content="User.2", source="assistant.2"),
  677. ]
  678. agent_1 = AssistantAgent(name="assistant_1", model_client=model_client_1)
  679. result = agent_1._get_compatible_context(messages) # type: ignore
  680. assert len(result) == 4
  681. assert isinstance(result[1].content, str)
  682. agent_2 = AssistantAgent(name="assistant_2", model_client=model_client_2)
  683. result = agent_2._get_compatible_context(messages) # type: ignore
  684. assert len(result) == 4
  685. assert isinstance(result[1].content, list)
  686. @pytest.mark.asyncio
  687. async def test_list_chat_messages(monkeypatch: pytest.MonkeyPatch) -> None:
  688. model = "gpt-4o-2024-05-13"
  689. chat_completions = [
  690. ChatCompletion(
  691. id="id1",
  692. choices=[
  693. Choice(
  694. finish_reason="stop",
  695. index=0,
  696. message=ChatCompletionMessage(content="Response to message 1", role="assistant"),
  697. )
  698. ],
  699. created=0,
  700. model=model,
  701. object="chat.completion",
  702. usage=CompletionUsage(prompt_tokens=10, completion_tokens=5, total_tokens=15),
  703. ),
  704. ]
  705. mock = _MockChatCompletion(chat_completions)
  706. monkeypatch.setattr(AsyncCompletions, "create", mock.mock_create)
  707. agent = AssistantAgent(
  708. "test_agent",
  709. model_client=OpenAIChatCompletionClient(model=model, api_key=""),
  710. )
  711. # Create a list of chat messages
  712. messages: List[ChatMessage] = [
  713. TextMessage(content="Message 1", source="user"),
  714. TextMessage(content="Message 2", source="user"),
  715. ]
  716. # Test run method with list of messages
  717. result = await agent.run(task=messages)
  718. assert len(result.messages) == 3 # 2 input messages + 1 response message
  719. assert isinstance(result.messages[0], TextMessage)
  720. assert result.messages[0].content == "Message 1"
  721. assert result.messages[0].source == "user"
  722. assert isinstance(result.messages[1], TextMessage)
  723. assert result.messages[1].content == "Message 2"
  724. assert result.messages[1].source == "user"
  725. assert isinstance(result.messages[2], TextMessage)
  726. assert result.messages[2].content == "Response to message 1"
  727. assert result.messages[2].source == "test_agent"
  728. assert result.messages[2].models_usage is not None
  729. assert result.messages[2].models_usage.completion_tokens == 5
  730. assert result.messages[2].models_usage.prompt_tokens == 10
  731. # Test run_stream method with list of messages
  732. mock.curr_index = 0 # Reset mock index using public attribute
  733. index = 0
  734. async for message in agent.run_stream(task=messages):
  735. if isinstance(message, TaskResult):
  736. assert message == result
  737. else:
  738. assert message == result.messages[index]
  739. index += 1
  740. @pytest.mark.asyncio
  741. async def test_model_context(monkeypatch: pytest.MonkeyPatch) -> None:
  742. model = "gpt-4o-2024-05-13"
  743. chat_completions = [
  744. ChatCompletion(
  745. id="id1",
  746. choices=[
  747. Choice(
  748. finish_reason="stop",
  749. index=0,
  750. message=ChatCompletionMessage(content="Response to message 3", role="assistant"),
  751. )
  752. ],
  753. created=0,
  754. model=model,
  755. object="chat.completion",
  756. usage=CompletionUsage(prompt_tokens=10, completion_tokens=5, total_tokens=15),
  757. ),
  758. ]
  759. mock = _MockChatCompletion(chat_completions)
  760. monkeypatch.setattr(AsyncCompletions, "create", mock.mock_create)
  761. model_context = BufferedChatCompletionContext(buffer_size=2)
  762. agent = AssistantAgent(
  763. "test_agent",
  764. model_client=OpenAIChatCompletionClient(model=model, api_key=""),
  765. model_context=model_context,
  766. )
  767. messages = [
  768. TextMessage(content="Message 1", source="user"),
  769. TextMessage(content="Message 2", source="user"),
  770. TextMessage(content="Message 3", source="user"),
  771. ]
  772. await agent.run(task=messages)
  773. # Check if the mock client is called with only the last two messages.
  774. assert len(mock.calls) == 1
  775. # 2 message from the context + 1 system message
  776. assert len(mock.calls[0]) == 3
  777. @pytest.mark.asyncio
  778. async def test_run_with_memory(monkeypatch: pytest.MonkeyPatch) -> None:
  779. model = "gpt-4o-2024-05-13"
  780. chat_completions = [
  781. ChatCompletion(
  782. id="id1",
  783. choices=[
  784. Choice(
  785. finish_reason="stop",
  786. index=0,
  787. message=ChatCompletionMessage(content="Hello", role="assistant"),
  788. )
  789. ],
  790. created=0,
  791. model=model,
  792. object="chat.completion",
  793. usage=CompletionUsage(prompt_tokens=10, completion_tokens=5, total_tokens=0),
  794. ),
  795. ]
  796. b64_image_str = "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAADElEQVR4nGP4//8/AAX+Av4N70a4AAAAAElFTkSuQmCC"
  797. mock = _MockChatCompletion(chat_completions)
  798. monkeypatch.setattr(AsyncCompletions, "create", mock.mock_create)
  799. # Test basic memory properties and empty context
  800. memory = ListMemory(name="test_memory")
  801. assert memory.name == "test_memory"
  802. empty_context = BufferedChatCompletionContext(buffer_size=2)
  803. empty_results = await memory.update_context(empty_context)
  804. assert len(empty_results.memories.results) == 0
  805. # Test various content types
  806. memory = ListMemory()
  807. await memory.add(MemoryContent(content="text content", mime_type=MemoryMimeType.TEXT))
  808. await memory.add(MemoryContent(content={"key": "value"}, mime_type=MemoryMimeType.JSON))
  809. await memory.add(MemoryContent(content=Image.from_base64(b64_image_str), mime_type=MemoryMimeType.IMAGE))
  810. # Test query functionality
  811. query_result = await memory.query(MemoryContent(content="", mime_type=MemoryMimeType.TEXT))
  812. assert isinstance(query_result, MemoryQueryResult)
  813. # Should have all three memories we added
  814. assert len(query_result.results) == 3
  815. # Test clear and cleanup
  816. await memory.clear()
  817. empty_query = await memory.query(MemoryContent(content="", mime_type=MemoryMimeType.TEXT))
  818. assert len(empty_query.results) == 0
  819. await memory.close() # Should not raise
  820. # Test invalid memory type
  821. with pytest.raises(TypeError):
  822. AssistantAgent(
  823. "test_agent",
  824. model_client=OpenAIChatCompletionClient(model=model, api_key=""),
  825. memory="invalid", # type: ignore
  826. )
  827. # Test with agent
  828. memory2 = ListMemory()
  829. await memory2.add(MemoryContent(content="test instruction", mime_type=MemoryMimeType.TEXT))
  830. agent = AssistantAgent(
  831. "test_agent", model_client=OpenAIChatCompletionClient(model=model, api_key=""), memory=[memory2]
  832. )
  833. # Test dump and load component with memory
  834. agent_config: ComponentModel = agent.dump_component()
  835. assert agent_config.provider == "autogen_agentchat.agents.AssistantAgent"
  836. agent2 = AssistantAgent.load_component(agent_config)
  837. result = await agent2.run(task="test task")
  838. assert len(result.messages) > 0
  839. memory_event = next((msg for msg in result.messages if isinstance(msg, MemoryQueryEvent)), None)
  840. assert memory_event is not None
  841. assert len(memory_event.content) > 0
  842. assert isinstance(memory_event.content[0], MemoryContent)
  843. # Test memory protocol
  844. class BadMemory:
  845. pass
  846. assert not isinstance(BadMemory(), Memory)
  847. assert isinstance(ListMemory(), Memory)
  848. @pytest.mark.asyncio
  849. async def test_assistant_agent_declarative(monkeypatch: pytest.MonkeyPatch) -> None:
  850. model = "gpt-4o-2024-05-13"
  851. chat_completions = [
  852. ChatCompletion(
  853. id="id1",
  854. choices=[
  855. Choice(
  856. finish_reason="stop",
  857. index=0,
  858. message=ChatCompletionMessage(content="Response to message 3", role="assistant"),
  859. )
  860. ],
  861. created=0,
  862. model=model,
  863. object="chat.completion",
  864. usage=CompletionUsage(prompt_tokens=10, completion_tokens=5, total_tokens=15),
  865. ),
  866. ]
  867. mock = _MockChatCompletion(chat_completions)
  868. monkeypatch.setattr(AsyncCompletions, "create", mock.mock_create)
  869. model_context = BufferedChatCompletionContext(buffer_size=2)
  870. agent = AssistantAgent(
  871. "test_agent",
  872. model_client=OpenAIChatCompletionClient(model=model, api_key=""),
  873. model_context=model_context,
  874. memory=[ListMemory(name="test_memory")],
  875. )
  876. agent_config: ComponentModel = agent.dump_component()
  877. assert agent_config.provider == "autogen_agentchat.agents.AssistantAgent"
  878. agent2 = AssistantAgent.load_component(agent_config)
  879. assert agent2.name == agent.name
  880. agent3 = AssistantAgent(
  881. "test_agent",
  882. model_client=OpenAIChatCompletionClient(model=model, api_key=""),
  883. model_context=model_context,
  884. tools=[
  885. _pass_function,
  886. _fail_function,
  887. FunctionTool(_echo_function, description="Echo"),
  888. ],
  889. )
  890. agent3_config = agent3.dump_component()
  891. assert agent3_config.provider == "autogen_agentchat.agents.AssistantAgent"
  892. @pytest.mark.asyncio
  893. async def test_model_client_stream() -> None:
  894. mock_client = ReplayChatCompletionClient(
  895. [
  896. "Response to message 3",
  897. ]
  898. )
  899. agent = AssistantAgent(
  900. "test_agent",
  901. model_client=mock_client,
  902. model_client_stream=True,
  903. )
  904. chunks: List[str] = []
  905. async for message in agent.run_stream(task="task"):
  906. if isinstance(message, TaskResult):
  907. assert message.messages[-1].content == "Response to message 3"
  908. elif isinstance(message, ModelClientStreamingChunkEvent):
  909. chunks.append(message.content)
  910. assert "".join(chunks) == "Response to message 3"
  911. @pytest.mark.asyncio
  912. async def test_model_client_stream_with_tool_calls() -> None:
  913. mock_client = ReplayChatCompletionClient(
  914. [
  915. CreateResult(
  916. content=[
  917. FunctionCall(id="1", name="_pass_function", arguments=r'{"input": "task"}'),
  918. FunctionCall(id="3", name="_echo_function", arguments=r'{"input": "task"}'),
  919. ],
  920. finish_reason="function_calls",
  921. usage=RequestUsage(prompt_tokens=10, completion_tokens=5),
  922. cached=False,
  923. ),
  924. "Example response 2 to task",
  925. ]
  926. )
  927. mock_client._model_info["function_calling"] = True # pyright: ignore
  928. agent = AssistantAgent(
  929. "test_agent",
  930. model_client=mock_client,
  931. model_client_stream=True,
  932. reflect_on_tool_use=True,
  933. tools=[_pass_function, _echo_function],
  934. )
  935. chunks: List[str] = []
  936. async for message in agent.run_stream(task="task"):
  937. if isinstance(message, TaskResult):
  938. assert message.messages[-1].content == "Example response 2 to task"
  939. assert message.messages[1].content == [
  940. FunctionCall(id="1", name="_pass_function", arguments=r'{"input": "task"}'),
  941. FunctionCall(id="3", name="_echo_function", arguments=r'{"input": "task"}'),
  942. ]
  943. assert message.messages[2].content == [
  944. FunctionExecutionResult(call_id="1", content="pass", is_error=False),
  945. FunctionExecutionResult(call_id="3", content="task", is_error=False),
  946. ]
  947. elif isinstance(message, ModelClientStreamingChunkEvent):
  948. chunks.append(message.content)
  949. assert "".join(chunks) == "Example response 2 to task"