From 39489ba395e8683df51ce4fd6df4ec7ec67c952b Mon Sep 17 00:00:00 2001 From: Jack Gerrits Date: Wed, 7 Aug 2024 16:08:13 -0400 Subject: [PATCH] Rename fields in agent metadata (#336) * Rename fields in agent metadata * team one fixes * another fix --- .../GAIA/Templates/TeamOne/scenario.py | 8 ++--- .../HumanEval/Templates/TwoAgents/scenario.py | 4 +-- python/docs/src/cookbook/type-routed-agent.md | 2 +- .../common/agents/_chat_completion_agent.py | 10 +++--- .../common/agents/_image_generation_agent.py | 4 +-- .../samples/common/agents/_oai_assistant.py | 2 +- python/samples/common/agents/_user_proxy.py | 2 +- .../common/patterns/_group_chat_utils.py | 8 ++--- .../common/patterns/_orchestrator_chat.py | 10 +++--- python/samples/core/inner_outer_direct.py | 4 +-- python/samples/core/two_agents_pub_sub.py | 6 ++-- python/samples/demos/assistant.py | 2 +- python/samples/demos/chat_room.py | 6 ++-- python/samples/demos/illustrator_critics.py | 6 ++-- python/samples/demos/utils.py | 2 +- python/samples/patterns/coder_executor.py | 4 +-- python/samples/patterns/coder_reviewer.py | 4 +-- python/samples/patterns/group_chat.py | 6 ++-- python/samples/patterns/mixture_of_agents.py | 4 +-- python/samples/patterns/multi_agent_debate.py | 8 ++--- python/samples/tool-use/coding_direct.py | 4 +-- python/samples/tool-use/coding_pub_sub.py | 4 +-- .../_single_threaded_agent_runtime.py | 3 +- .../src/agnext/components/_closure_agent.py | 4 +-- python/src/agnext/core/_agent_metadata.py | 4 +-- python/src/agnext/core/_base_agent.py | 4 +-- .../src/team_one/agents/base_agent.py | 2 +- .../src/team_one/agents/base_orchestrator.py | 10 +++--- .../src/team_one/agents/base_worker.py | 4 +-- .../multimodal_web_surfer.py | 14 ++++---- .../src/team_one/agents/orchestrator.py | 32 +++++++++---------- .../src/team_one/agents/reflex_agents.py | 2 +- 32 files changed, 94 insertions(+), 95 deletions(-) diff --git a/python/benchmarks/GAIA/Templates/TeamOne/scenario.py b/python/benchmarks/GAIA/Templates/TeamOne/scenario.py index ac7a3bfb5..c0b1ccf74 100644 --- a/python/benchmarks/GAIA/Templates/TeamOne/scenario.py +++ b/python/benchmarks/GAIA/Templates/TeamOne/scenario.py @@ -29,7 +29,7 @@ import tiktoken from agnext.components.models import AssistantMessage -encoding = None +encoding = None def count_token(value: str) -> int: # TODO:: Migrate to model_client.count_tokens global encoding @@ -40,7 +40,7 @@ def count_token(value: str) -> int: async def response_preparer(task: str, source: str, client: ChatCompletionClient, transcript: List[LLMMessage]) -> str: messages: List[LLMMessage] = [] - # copy them to this context + # copy them to this context for message in transcript: messages.append( UserMessage( @@ -168,7 +168,7 @@ async def main() -> None: run_context = runtime.start() - actual_surfer = await runtime.try_get_underlying_agent_instance(web_surfer.id, type=MultimodalWebSurfer) + actual_surfer = await runtime.try_get_underlying_agent_instance(web_surfer.id, type=MultimodalWebSurfer) await actual_surfer.init(model_client=client, downloads_folder=os.getcwd(), browser_channel="chromium") #await runtime.send_message(RequestReplyMessage(), user_proxy.id) @@ -206,7 +206,7 @@ async def main() -> None: # Output the final answer actual_orchestrator = await runtime.try_get_underlying_agent_instance(orchestrator.id, type=LedgerOrchestrator) transcript: List[LLMMessage] = actual_orchestrator._chat_history # type: ignore - print(await response_preparer(task=task, source=(await orchestrator.metadata)["name"], client=client, transcript=transcript)) + print(await response_preparer(task=task, source=(await orchestrator.metadata)["type"], client=client, transcript=transcript)) diff --git a/python/benchmarks/HumanEval/Templates/TwoAgents/scenario.py b/python/benchmarks/HumanEval/Templates/TwoAgents/scenario.py index b17c106a6..fedc66484 100644 --- a/python/benchmarks/HumanEval/Templates/TwoAgents/scenario.py +++ b/python/benchmarks/HumanEval/Templates/TwoAgents/scenario.py @@ -100,7 +100,7 @@ If the code has executed successfully, and the problem is stolved, reply "TERMIN ) assert isinstance(response.content, str) self._session_memory[session_id].append( - AssistantMessage(content=response.content, source=self.metadata["name"]) + AssistantMessage(content=response.content, source=self.metadata["type"]) ) await self.publish_message( @@ -138,7 +138,7 @@ If the code has executed successfully, and the problem is stolved, reply "TERMIN ) assert isinstance(response.content, str) self._session_memory[message.session_id].append( - AssistantMessage(content=response.content, source=self.metadata["name"]) + AssistantMessage(content=response.content, source=self.metadata["type"]) ) if "TERMINATE" in response.content: diff --git a/python/docs/src/cookbook/type-routed-agent.md b/python/docs/src/cookbook/type-routed-agent.md index c5f3f4636..77ef44160 100644 --- a/python/docs/src/cookbook/type-routed-agent.md +++ b/python/docs/src/cookbook/type-routed-agent.md @@ -56,7 +56,7 @@ class MyAgent(TypeRoutedAgent): await self.publish_message( TextMessage( content=f"I received a message from {message.source}. Message received #{self._received_count}", - source=self.metadata["name"], + source=self.metadata["type"], ) ) diff --git a/python/samples/common/agents/_chat_completion_agent.py b/python/samples/common/agents/_chat_completion_agent.py index 8cb98a2d8..a3a921440 100644 --- a/python/samples/common/agents/_chat_completion_agent.py +++ b/python/samples/common/agents/_chat_completion_agent.py @@ -175,7 +175,7 @@ class ChatCompletionAgent(TypeRoutedAgent): # Get a response from the model. hisorical_messages = await self._memory.get_messages() response = await self._client.create( - self._system_messages + convert_messages_to_llm_messages(hisorical_messages, self.metadata["name"]), + self._system_messages + convert_messages_to_llm_messages(hisorical_messages, self.metadata["type"]), tools=self._tools, json_output=response_format == ResponseFormat.json_object, ) @@ -190,14 +190,14 @@ class ChatCompletionAgent(TypeRoutedAgent): ): # Send a function call message to itself. response = await self.send_message( - message=FunctionCallMessage(content=response.content, source=self.metadata["name"]), + message=FunctionCallMessage(content=response.content, source=self.metadata["type"]), recipient=self.id, cancellation_token=cancellation_token, ) # Make an assistant message from the response. hisorical_messages = await self._memory.get_messages() response = await self._client.create( - self._system_messages + convert_messages_to_llm_messages(hisorical_messages, self.metadata["name"]), + self._system_messages + convert_messages_to_llm_messages(hisorical_messages, self.metadata["type"]), tools=self._tools, json_output=response_format == ResponseFormat.json_object, ) @@ -205,10 +205,10 @@ class ChatCompletionAgent(TypeRoutedAgent): final_response: Message if isinstance(response.content, str): # If the response is a string, return a text message. - final_response = TextMessage(content=response.content, source=self.metadata["name"]) + final_response = TextMessage(content=response.content, source=self.metadata["type"]) elif isinstance(response.content, list) and all(isinstance(x, FunctionCall) for x in response.content): # If the response is a list of function calls, return a function call message. - final_response = FunctionCallMessage(content=response.content, source=self.metadata["name"]) + final_response = FunctionCallMessage(content=response.content, source=self.metadata["type"]) else: raise ValueError(f"Unexpected response: {response.content}") diff --git a/python/samples/common/agents/_image_generation_agent.py b/python/samples/common/agents/_image_generation_agent.py index f20d55c3e..b9a08ade0 100644 --- a/python/samples/common/agents/_image_generation_agent.py +++ b/python/samples/common/agents/_image_generation_agent.py @@ -63,7 +63,7 @@ class ImageGenerationAgent(TypeRoutedAgent): messages = await self._memory.get_messages() if len(messages) == 0: return MultiModalMessage( - content=["I need more information to generate an image."], source=self.metadata["name"] + content=["I need more information to generate an image."], source=self.metadata["type"] ) prompt = "" for m in messages: @@ -74,5 +74,5 @@ class ImageGenerationAgent(TypeRoutedAgent): assert len(response.data) > 0 and response.data[0].b64_json is not None # Create a MultiModalMessage with the image. image = Image.from_base64(response.data[0].b64_json) - multi_modal_message = MultiModalMessage(content=[image], source=self.metadata["name"]) + multi_modal_message = MultiModalMessage(content=[image], source=self.metadata["type"]) return multi_modal_message diff --git a/python/samples/common/agents/_oai_assistant.py b/python/samples/common/agents/_oai_assistant.py index ee4484c83..ae0833917 100644 --- a/python/samples/common/agents/_oai_assistant.py +++ b/python/samples/common/agents/_oai_assistant.py @@ -121,7 +121,7 @@ class OpenAIAssistantAgent(TypeRoutedAgent): raise ValueError(f"Expected text content in the last message: {last_message_content}") # TODO: handle multiple text content. - return TextMessage(content=text_content[0].text.value, source=self.metadata["name"]) + return TextMessage(content=text_content[0].text.value, source=self.metadata["type"]) def save_state(self) -> Mapping[str, Any]: return { diff --git a/python/samples/common/agents/_user_proxy.py b/python/samples/common/agents/_user_proxy.py index ec7f23b83..048dac1b6 100644 --- a/python/samples/common/agents/_user_proxy.py +++ b/python/samples/common/agents/_user_proxy.py @@ -23,7 +23,7 @@ class UserProxyAgent(TypeRoutedAgent): async def on_publish_now(self, message: PublishNow, cancellation_token: CancellationToken) -> None: """Handle a publish now message. This method prompts the user for input, then publishes it.""" user_input = await self.get_user_input(self._user_input_prompt) - await self.publish_message(TextMessage(content=user_input, source=self.metadata["name"])) + await self.publish_message(TextMessage(content=user_input, source=self.metadata["type"])) async def get_user_input(self, prompt: str) -> str: """Get user input from the console. Override this method to customize how user input is retrieved.""" diff --git a/python/samples/common/patterns/_group_chat_utils.py b/python/samples/common/patterns/_group_chat_utils.py index 4b0d7ebda..980365b8a 100644 --- a/python/samples/common/patterns/_group_chat_utils.py +++ b/python/samples/common/patterns/_group_chat_utils.py @@ -23,11 +23,11 @@ async def select_speaker(memory: ChatMemory[Message], client: ChatCompletionClie # Construct agent roles. roles = "\n".join( - [f"{(await agent.metadata)['name']}: {(await agent.metadata)['description']}".strip() for agent in agents] + [f"{(await agent.metadata)['type']}: {(await agent.metadata)['description']}".strip() for agent in agents] ) # Construct agent list. - participants = str([(await agent.metadata)["name"] for agent in agents]) + participants = str([(await agent.metadata)["type"] for agent in agents]) # Select the next speaker. select_speaker_prompt = f"""You are in a role play game. The following roles are available: @@ -48,7 +48,7 @@ Read the above conversation. Then select the next role from {participants} to pl # Get the index of the selected agent by name agent_index = 0 for i, agent in enumerate(agents): - if (await agent.metadata)["name"] == agent_name: + if (await agent.metadata)["type"] == agent_name: agent_index = i break @@ -74,7 +74,7 @@ async def mentioned_agents(message_content: str, agents: List[AgentProxy]) -> Di for agent in agents: # Finds agent mentions, taking word boundaries into account, # accommodates escaping underscores and underscores as spaces - name = (await agent.metadata)["name"] + name = (await agent.metadata)["type"] regex = ( r"(?<=\W)(" + re.escape(name) diff --git a/python/samples/common/patterns/_orchestrator_chat.py b/python/samples/common/patterns/_orchestrator_chat.py index 9ebb438dd..a6d8b1772 100644 --- a/python/samples/common/patterns/_orchestrator_chat.py +++ b/python/samples/common/patterns/_orchestrator_chat.py @@ -73,7 +73,7 @@ Some additional points to consider: # Send the task specs to the orchestrator and specialists. for agent in [*self._specialists, self._orchestrator]: - await (await self.send_message(TextMessage(content=task_specs, source=self.metadata["name"]), agent)) + await (await self.send_message(TextMessage(content=task_specs, source=self.metadata["type"]), agent)) # Inner loop. stalled_turns = 0 @@ -85,7 +85,7 @@ Some additional points to consider: if data["is_request_satisfied"]["answer"]: return TextMessage( content=f"The task has been successfully addressed. {data['is_request_satisfied']['reason']}", - source=self.metadata["name"], + source=self.metadata["type"], ) # Update stalled turns. @@ -111,7 +111,7 @@ Some additional points to consider: if educated_guess["has_educated_guesses"]["answer"]: return TextMessage( content=f"The task is addressed with an educated guess. {educated_guess['has_educated_guesses']['reason']}", - source=self.metadata["name"], + source=self.metadata["type"], ) # Come up with a new plan. @@ -129,7 +129,7 @@ Some additional points to consider: for agent in [*self._specialists, self._orchestrator]: _ = await ( await self.send_message( - TextMessage(content=subtask, source=self.metadata["name"]), + TextMessage(content=subtask, source=self.metadata["type"]), agent, ) ) @@ -161,7 +161,7 @@ Some additional points to consider: return TextMessage( content="The task was not addressed. The maximum number of turns was reached.", - source=self.metadata["name"], + source=self.metadata["type"], ) async def _prepare_task(self, task: str, sender: str) -> Tuple[str, str, str, str]: diff --git a/python/samples/core/inner_outer_direct.py b/python/samples/core/inner_outer_direct.py index d90ee0eef..5196df0e2 100644 --- a/python/samples/core/inner_outer_direct.py +++ b/python/samples/core/inner_outer_direct.py @@ -27,7 +27,7 @@ class Inner(TypeRoutedAgent): @message_handler() async def on_new_message(self, message: MessageType, cancellation_token: CancellationToken) -> MessageType: - return MessageType(body=f"Inner: {message.body}", sender=self.metadata["name"]) + return MessageType(body=f"Inner: {message.body}", sender=self.metadata["type"]) class Outer(TypeRoutedAgent): @@ -40,7 +40,7 @@ class Outer(TypeRoutedAgent): inner_response = self.send_message(message, self._inner) inner_message = await inner_response assert isinstance(inner_message, MessageType) - return MessageType(body=f"Outer: {inner_message.body}", sender=self.metadata["name"]) + return MessageType(body=f"Outer: {inner_message.body}", sender=self.metadata["type"]) async def main() -> None: diff --git a/python/samples/core/two_agents_pub_sub.py b/python/samples/core/two_agents_pub_sub.py index e33db7d3d..b715b6361 100644 --- a/python/samples/core/two_agents_pub_sub.py +++ b/python/samples/core/two_agents_pub_sub.py @@ -63,13 +63,13 @@ class ChatCompletionAgent(TypeRoutedAgent): return llm_messages: List[LLMMessage] = [] for m in self._memory[-10:]: - if m.source == self.metadata["name"]: - llm_messages.append(AssistantMessage(content=m.content, source=self.metadata["name"])) + if m.source == self.metadata["type"]: + llm_messages.append(AssistantMessage(content=m.content, source=self.metadata["type"])) else: llm_messages.append(UserMessage(content=m.content, source=m.source)) response = await self._model_client.create(self._system_messages + llm_messages) assert isinstance(response.content, str) - await self.publish_message(Message(content=response.content, source=self.metadata["name"])) + await self.publish_message(Message(content=response.content, source=self.metadata["type"])) async def main() -> None: diff --git a/python/samples/demos/assistant.py b/python/samples/demos/assistant.py index 781f7b5fc..e231f213c 100644 --- a/python/samples/demos/assistant.py +++ b/python/samples/demos/assistant.py @@ -108,7 +108,7 @@ class UserProxyAgent(TypeRoutedAgent): # type: ignore return else: # Publish user input and exit handler. - await self.publish_message(TextMessage(content=user_input, source=self.metadata["name"])) + await self.publish_message(TextMessage(content=user_input, source=self.metadata["type"])) return diff --git a/python/samples/demos/chat_room.py b/python/samples/demos/chat_room.py index da9966992..18830e54a 100644 --- a/python/samples/demos/chat_room.py +++ b/python/samples/demos/chat_room.py @@ -60,13 +60,13 @@ Use the following JSON format to provide your thought on the latest message and # Get a response from the model. raw_response = await self._client.create( self._system_messages - + convert_messages_to_llm_messages(await self._memory.get_messages(), self_name=self.metadata["name"]), + + convert_messages_to_llm_messages(await self._memory.get_messages(), self_name=self.metadata["type"]), json_output=True, ) assert isinstance(raw_response.content, str) # Save the response to memory. - await self._memory.add_message(TextMessage(source=self.metadata["name"], content=raw_response.content)) + await self._memory.add_message(TextMessage(source=self.metadata["type"], content=raw_response.content)) # Parse the response. data = json.loads(raw_response.content) @@ -75,7 +75,7 @@ Use the following JSON format to provide your thought on the latest message and # Publish the response if needed. if respond is True or str(respond).lower().strip() == "true": - await self.publish_message(TextMessage(source=self.metadata["name"], content=str(response))) + await self.publish_message(TextMessage(source=self.metadata["type"], content=str(response))) class ChatRoomUserAgent(TextualUserAgent): diff --git a/python/samples/demos/illustrator_critics.py b/python/samples/demos/illustrator_critics.py index a0950bbb3..4e5d9a574 100644 --- a/python/samples/demos/illustrator_critics.py +++ b/python/samples/demos/illustrator_critics.py @@ -86,9 +86,9 @@ async def illustrator_critics(runtime: AgentRuntime, app: TextualChatApp) -> Non app.welcoming_notice = f"""You are now in a group chat with the following agents: -1. 🤖 {(await descriptor.metadata)['name']}: {(await descriptor.metadata).get('description')} -2. 🤖 {(await illustrator.metadata)['name']}: {(await illustrator.metadata).get('description')} -3. 🤖 {(await critic.metadata)['name']}: {(await critic.metadata).get('description')} +1. 🤖 {(await descriptor.metadata)['type']}: {(await descriptor.metadata).get('description')} +2. 🤖 {(await illustrator.metadata)['type']}: {(await illustrator.metadata).get('description')} +3. 🤖 {(await critic.metadata)['type']}: {(await critic.metadata).get('description')} Provide a prompt for the illustrator to generate an image. """ diff --git a/python/samples/demos/utils.py b/python/samples/demos/utils.py index 9918d0354..cf3e05c15 100644 --- a/python/samples/demos/utils.py +++ b/python/samples/demos/utils.py @@ -171,7 +171,7 @@ class TextualUserAgent(TypeRoutedAgent): # type: ignore # Generate a ramdom file name. for content in message.content: if isinstance(content, Image): - filename = f"{self.metadata['name']}_{message.source}_{random.randbytes(16).hex()}.png" + filename = f"{self.metadata['type']}_{message.source}_{random.randbytes(16).hex()}.png" content.image.save(filename) await self._app.post_runtime_message(message) diff --git a/python/samples/patterns/coder_executor.py b/python/samples/patterns/coder_executor.py index 0246c3f20..5c230c879 100644 --- a/python/samples/patterns/coder_executor.py +++ b/python/samples/patterns/coder_executor.py @@ -97,7 +97,7 @@ Reply "TERMINATE" in the end when everything is done.""" response = await self._model_client.create(self._system_messages + self._session_memory[session_id]) assert isinstance(response.content, str) self._session_memory[session_id].append( - AssistantMessage(content=response.content, source=self.metadata["name"]) + AssistantMessage(content=response.content, source=self.metadata["type"]) ) # Publish the code execution task. @@ -116,7 +116,7 @@ Reply "TERMINATE" in the end when everything is done.""" response = await self._model_client.create(self._system_messages + self._session_memory[message.session_id]) assert isinstance(response.content, str) self._session_memory[message.session_id].append( - AssistantMessage(content=response.content, source=self.metadata["name"]) + AssistantMessage(content=response.content, source=self.metadata["type"]) ) if "TERMINATE" in response.content: diff --git a/python/samples/patterns/coder_reviewer.py b/python/samples/patterns/coder_reviewer.py index 77be82f64..8a7797931 100644 --- a/python/samples/patterns/coder_reviewer.py +++ b/python/samples/patterns/coder_reviewer.py @@ -100,7 +100,7 @@ Please review the code and provide feedback. """ # Generate a response using the chat completion API. response = await self._model_client.create( - self._system_messages + [UserMessage(content=prompt, source=self.metadata["name"])] + self._system_messages + [UserMessage(content=prompt, source=self.metadata["type"])] ) assert isinstance(response.content, str) # TODO: use structured generation library e.g. guidance to ensure the response is in the expected format. @@ -162,7 +162,7 @@ Code: self._session_memory.setdefault(session_id, []).append(message) # Generate a response using the chat completion API. response = await self._model_client.create( - self._system_messages + [UserMessage(content=message.task, source=self.metadata["name"])] + self._system_messages + [UserMessage(content=message.task, source=self.metadata["type"])] ) assert isinstance(response.content, str) # Extract the code block from the response. diff --git a/python/samples/patterns/group_chat.py b/python/samples/patterns/group_chat.py index 9733c1bb4..a496f5285 100644 --- a/python/samples/patterns/group_chat.py +++ b/python/samples/patterns/group_chat.py @@ -97,13 +97,13 @@ class GroupChatParticipant(TypeRoutedAgent): return llm_messages: List[LLMMessage] = [] for m in self._memory[-10:]: - if m.source == self.metadata["name"]: - llm_messages.append(AssistantMessage(content=m.content, source=self.metadata["name"])) + if m.source == self.metadata["type"]: + llm_messages.append(AssistantMessage(content=m.content, source=self.metadata["type"])) else: llm_messages.append(UserMessage(content=m.content, source=m.source)) response = await self._model_client.create(self._system_messages + llm_messages) assert isinstance(response.content, str) - speach = Message(content=response.content, source=self.metadata["name"]) + speach = Message(content=response.content, source=self.metadata["type"]) self._memory.append(speach) await self.publish_message(speach) diff --git a/python/samples/patterns/mixture_of_agents.py b/python/samples/patterns/mixture_of_agents.py index 4b1f5c073..d4b84d397 100644 --- a/python/samples/patterns/mixture_of_agents.py +++ b/python/samples/patterns/mixture_of_agents.py @@ -62,7 +62,7 @@ class ReferenceAgent(TypeRoutedAgent): @message_handler async def handle_task(self, message: ReferenceAgentTask, cancellation_token: CancellationToken) -> None: """Handle a task message. This method sends the task to the model and publishes the result.""" - task_message = UserMessage(content=message.task, source=self.metadata["name"]) + task_message = UserMessage(content=message.task, source=self.metadata["type"]) response = await self._model_client.create(self._system_messages + [task_message]) assert isinstance(response.content, str) task_result = ReferenceAgentTaskResult(session_id=message.session_id, result=response.content) @@ -100,7 +100,7 @@ class AggregatorAgent(TypeRoutedAgent): if len(self._session_results[message.session_id]) == self._num_references: result = "\n\n".join([r.result for r in self._session_results[message.session_id]]) response = await self._model_client.create( - self._system_messages + [UserMessage(content=result, source=self.metadata["name"])] + self._system_messages + [UserMessage(content=result, source=self.metadata["type"])] ) assert isinstance(response.content, str) task_result = AggregatorTaskResult(result=response.content) diff --git a/python/samples/patterns/multi_agent_debate.py b/python/samples/patterns/multi_agent_debate.py index 485a8a58e..daac66568 100644 --- a/python/samples/patterns/multi_agent_debate.py +++ b/python/samples/patterns/multi_agent_debate.py @@ -94,7 +94,7 @@ class MathSolver(TypeRoutedAgent): def __init__(self, model_client: ChatCompletionClient, neighbor_names: List[str], max_round: int) -> None: super().__init__("A debator.") self._model_client = model_client - if self.metadata["name"] in neighbor_names: + if self.metadata["type"] in neighbor_names: raise ValueError("The agent's name cannot be in the list of neighbor names.") self._neighbor_names = neighbor_names self._memory: Dict[str, List[LLMMessage]] = {} @@ -153,9 +153,9 @@ class MathSolver(TypeRoutedAgent): assert isinstance(response.content, str) # Add the response to the memory. self._memory[message.session_id].append( - AssistantMessage(content=response.content, source=self.metadata["name"]) + AssistantMessage(content=response.content, source=self.metadata["type"]) ) - logger.debug(f"Solver {self.metadata['name']} response: {response.content}") + logger.debug(f"Solver {self.metadata['type']} response: {response.content}") # Extract the answer from the response. match = re.search(r"\{\{(\-?\d+(\.\d+)?)\}\}", response.content) if match is None: @@ -171,7 +171,7 @@ class MathSolver(TypeRoutedAgent): await self.publish_message( IntermediateSolverResponse( content=response.content, - solver_name=self.metadata["name"], + solver_name=self.metadata["type"], answer=answer, session_id=message.session_id, round=self._counters[message.session_id], diff --git a/python/samples/tool-use/coding_direct.py b/python/samples/tool-use/coding_direct.py index ae7e3af0d..a153a2748 100644 --- a/python/samples/tool-use/coding_direct.py +++ b/python/samples/tool-use/coding_direct.py @@ -66,7 +66,7 @@ class ToolUseAgent(TypeRoutedAgent): session: List[LLMMessage] = [] session.append(UserMessage(content=message.content, source="User")) response = await self._model_client.create(self._system_messages + session, tools=self._tool_schema) - session.append(AssistantMessage(content=response.content, source=self.metadata["name"])) + session.append(AssistantMessage(content=response.content, source=self.metadata["type"])) # Keep executing the tools until the response is not a list of function calls. while isinstance(response.content, list) and all(isinstance(item, FunctionCall) for item in response.content): @@ -89,7 +89,7 @@ class ToolUseAgent(TypeRoutedAgent): session.append(FunctionExecutionResultMessage(content=function_results)) # Execute the model again with the new response. response = await self._model_client.create(self._system_messages + session, tools=self._tool_schema) - session.append(AssistantMessage(content=response.content, source=self.metadata["name"])) + session.append(AssistantMessage(content=response.content, source=self.metadata["type"])) assert isinstance(response.content, str) return Message(content=response.content) diff --git a/python/samples/tool-use/coding_pub_sub.py b/python/samples/tool-use/coding_pub_sub.py index 61d4719aa..02ee67833 100644 --- a/python/samples/tool-use/coding_pub_sub.py +++ b/python/samples/tool-use/coding_pub_sub.py @@ -121,7 +121,7 @@ class ToolUseAgent(TypeRoutedAgent): response = await self._model_client.create( self._system_messages + self._sessions[session_id], tools=self._tools ) - self._sessions[session_id].append(AssistantMessage(content=response.content, source=self.metadata["name"])) + self._sessions[session_id].append(AssistantMessage(content=response.content, source=self.metadata["type"])) if isinstance(response.content, str): # If the response is a string, just publish the response. @@ -163,7 +163,7 @@ class ToolUseAgent(TypeRoutedAgent): self._system_messages + self._sessions[message.session_id], tools=self._tools ) self._sessions[message.session_id].append( - AssistantMessage(content=response.content, source=self.metadata["name"]) + AssistantMessage(content=response.content, source=self.metadata["type"]) ) # If the response is a string, just publish the response. if isinstance(response.content, str): diff --git a/python/src/agnext/application/_single_threaded_agent_runtime.py b/python/src/agnext/application/_single_threaded_agent_runtime.py index e70dfadc9..839d0d219 100644 --- a/python/src/agnext/application/_single_threaded_agent_runtime.py +++ b/python/src/agnext/application/_single_threaded_agent_runtime.py @@ -304,8 +304,7 @@ class SingleThreadedAgentRuntime(AgentRuntime): sender_agent = ( await self._get_agent(message_envelope.sender) if message_envelope.sender is not None else None ) - # TODO use id - sender_name = sender_agent.metadata["name"] if sender_agent is not None else "Unknown" + sender_name = str(sender_agent.id) if sender_agent is not None else "Unknown" logger.info( f"Calling message handler for {agent_id.type} with message type {type(message_envelope.message).__name__} published by {sender_name}" ) diff --git a/python/src/agnext/components/_closure_agent.py b/python/src/agnext/components/_closure_agent.py index 792ed1ed0..1636bd2fa 100644 --- a/python/src/agnext/components/_closure_agent.py +++ b/python/src/agnext/components/_closure_agent.py @@ -68,8 +68,8 @@ class ClosureAgent(Agent): def metadata(self) -> AgentMetadata: assert self._id is not None return AgentMetadata( - namespace=self._id.key, - name=self._id.type, + key=self._id.key, + type=self._id.type, description=self._description, subscriptions=self._subscriptions, ) diff --git a/python/src/agnext/core/_agent_metadata.py b/python/src/agnext/core/_agent_metadata.py index 5b8bcb2ed..b4e8db482 100644 --- a/python/src/agnext/core/_agent_metadata.py +++ b/python/src/agnext/core/_agent_metadata.py @@ -2,7 +2,7 @@ from typing import Sequence, TypedDict class AgentMetadata(TypedDict): - name: str - namespace: str + type: str + key: str description: str subscriptions: Sequence[str] diff --git a/python/src/agnext/core/_base_agent.py b/python/src/agnext/core/_base_agent.py index 738881dc8..6963ee1b0 100644 --- a/python/src/agnext/core/_base_agent.py +++ b/python/src/agnext/core/_base_agent.py @@ -15,8 +15,8 @@ class BaseAgent(ABC, Agent): def metadata(self) -> AgentMetadata: assert self._id is not None return AgentMetadata( - namespace=self._id.key, - name=self._id.type, + key=self._id.key, + type=self._id.type, description=self._description, subscriptions=self._subscriptions, ) diff --git a/python/teams/team-one/src/team_one/agents/base_agent.py b/python/teams/team-one/src/team_one/agents/base_agent.py index 323bc31a1..347c4581a 100644 --- a/python/teams/team-one/src/team_one/agents/base_agent.py +++ b/python/teams/team-one/src/team_one/agents/base_agent.py @@ -94,7 +94,7 @@ class TeamOneBaseAgent(TypeRoutedAgent): self._enabled = False logger.info( AgentEvent( - f"{self.metadata['name']} (deactivated)", + f"{self.metadata['type']} (deactivated)", "", ) ) diff --git a/python/teams/team-one/src/team_one/agents/base_orchestrator.py b/python/teams/team-one/src/team_one/agents/base_orchestrator.py index b8a03565e..72e8d2e6f 100644 --- a/python/teams/team-one/src/team_one/agents/base_orchestrator.py +++ b/python/teams/team-one/src/team_one/agents/base_orchestrator.py @@ -40,7 +40,7 @@ class BaseOrchestrator(TeamOneBaseAgent): if self._num_rounds >= self._max_rounds: logger.info( OrchestrationEvent( - f"{self.metadata['name']} (termination condition)", + f"{self.metadata['type']} (termination condition)", f"Max rounds ({self._max_rounds}) reached.", ) ) @@ -49,7 +49,7 @@ class BaseOrchestrator(TeamOneBaseAgent): if message.request_halt: logger.info( OrchestrationEvent( - f"{self.metadata['name']} (termination condition)", + f"{self.metadata['type']} (termination condition)", f"{source} requested halt.", ) ) @@ -59,7 +59,7 @@ class BaseOrchestrator(TeamOneBaseAgent): if next_agent is None: logger.info( OrchestrationEvent( - f"{self.metadata['name']} (termination condition)", + f"{self.metadata['type']} (termination condition)", "No agent selected.", ) ) @@ -69,8 +69,8 @@ class BaseOrchestrator(TeamOneBaseAgent): logger.info( OrchestrationEvent( - source=f"{self.metadata['name']} (thought)", - message=f"Next speaker {(await next_agent.metadata)['name']}" "", + source=f"{self.metadata['type']} (thought)", + message=f"Next speaker {(await next_agent.metadata)['type']}" "", ) ) diff --git a/python/teams/team-one/src/team_one/agents/base_worker.py b/python/teams/team-one/src/team_one/agents/base_worker.py index 423280ca9..af4d13327 100644 --- a/python/teams/team-one/src/team_one/agents/base_worker.py +++ b/python/teams/team-one/src/team_one/agents/base_worker.py @@ -41,10 +41,10 @@ class BaseWorker(TeamOneBaseAgent): """Respond to a reply request.""" request_halt, response = await self._generate_reply(cancellation_token) - assistant_message = AssistantMessage(content=message_content_to_str(response), source=self.metadata["name"]) + assistant_message = AssistantMessage(content=message_content_to_str(response), source=self.metadata["type"]) self._chat_history.append(assistant_message) - user_message = UserMessage(content=response, source=self.metadata["name"]) + user_message = UserMessage(content=response, source=self.metadata["type"]) await self.publish_message(BroadcastMessage(content=user_message, request_halt=request_halt)) async def _generate_reply(self, cancellation_token: CancellationToken) -> Tuple[bool, UserContent]: diff --git a/python/teams/team-one/src/team_one/agents/multimodal_web_surfer/multimodal_web_surfer.py b/python/teams/team-one/src/team_one/agents/multimodal_web_surfer/multimodal_web_surfer.py index e3541686c..568d806a5 100644 --- a/python/teams/team-one/src/team_one/agents/multimodal_web_surfer/multimodal_web_surfer.py +++ b/python/teams/team-one/src/team_one/agents/multimodal_web_surfer/multimodal_web_surfer.py @@ -211,7 +211,7 @@ setInterval(function() {{ await self._page.screenshot(path=os.path.join(self.debug_dir, "screenshot.png")) logger.info( WebSurferEvent( - source=self.metadata["name"], + source=self.metadata["type"], url=self._page.url, message="Resetting browser.", ) @@ -262,7 +262,7 @@ setInterval(function() {{ assert self._page is not None logger.info( WebSurferEvent( - source=self.metadata["name"], + source=self.metadata["type"], url=self._page.url, action=name, arguments=args, @@ -519,7 +519,7 @@ When deciding between tools, consider if the request can be best addressed by: # Add the multimodal message and make the request history.append( - UserMessage(content=[text_prompt, AGImage.from_pil(scaled_screenshot)], source=self.metadata["name"]) + UserMessage(content=[text_prompt, AGImage.from_pil(scaled_screenshot)], source=self.metadata["type"]) ) response = await self._model_client.create( history, tools=tools, extra_create_args={"tool_choice": "auto"} @@ -674,7 +674,7 @@ When deciding between tools, consider if the request can be best addressed by: logger.info( WebSurferEvent( - source=self.metadata["name"], + source=self.metadata["type"], url=self._page.url, message="New tab or window.", ) @@ -758,7 +758,7 @@ When deciding between tools, consider if the request can be best addressed by: prompt + buffer + line, # ag_image, # ], - source=self.metadata["name"], + source=self.metadata["type"], ) remaining = self._model_client.remaining_tokens(messages + [message]) @@ -779,7 +779,7 @@ When deciding between tools, consider if the request can be best addressed by: prompt + buffer, ag_image, ], - source=self.metadata["name"], + source=self.metadata["type"], ) ) @@ -811,7 +811,7 @@ When deciding between tools, consider if the request can be best addressed by: "Please transcribe all visible text on this page, including both main content and the labels of UI elements.", AGImage.from_pil(scaled_screenshot), ], - source=self.metadata["name"], + source=self.metadata["type"], ) ) response = await self._model_client.create(messages) diff --git a/python/teams/team-one/src/team_one/agents/orchestrator.py b/python/teams/team-one/src/team_one/agents/orchestrator.py index 02e8e11ec..42e1ec3b0 100644 --- a/python/teams/team-one/src/team_one/agents/orchestrator.py +++ b/python/teams/team-one/src/team_one/agents/orchestrator.py @@ -83,13 +83,13 @@ class LedgerOrchestrator(BaseOrchestrator): team_description = "" for agent in self._agents: metadata = await agent.metadata - name = metadata["name"] + name = metadata["type"] description = metadata["description"] team_description += f"{name}: {description}\n" return team_description async def _get_team_names(self) -> List[str]: - return [(await agent.metadata)["name"] for agent in self._agents] + return [(await agent.metadata)["type"] for agent in self._agents] def _set_task_str(self, message: LLMMessage) -> None: if len(self._chat_history) == 1: @@ -119,18 +119,18 @@ class LedgerOrchestrator(BaseOrchestrator): # create a closed book task and generate a response and update the chat history cb_task = self._get_closed_book_prompt(self.task_str) cb_user_message = UserMessage( - content=cb_task, source=self.metadata["name"] + content=cb_task, source=self.metadata["type"] ) # TODO: allow images in this message. cb_response = await self._model_client.create(self._system_messages + self._chat_history + [cb_user_message]) facts = cb_response.content assert isinstance(facts, str) - cb_assistant_message = AssistantMessage(content=facts, source=self.metadata["name"]) + cb_assistant_message = AssistantMessage(content=facts, source=self.metadata["type"]) # 2. CREATE A PLAN ## plan based on available information plan_task = self._get_plan_prompt(self.task_str, team_description) plan_user_message = UserMessage( - content=plan_task, source=self.metadata["name"] + content=plan_task, source=self.metadata["type"] ) # TODO: allow images in this message. plan_response = await self._model_client.create( self._system_messages + self._chat_history + [cb_assistant_message, plan_user_message] @@ -148,7 +148,7 @@ class LedgerOrchestrator(BaseOrchestrator): team_description = await self._get_team_description() names = await self._get_team_names() ledger_prompt = self._get_ledger_prompt(self.task_str, team_description, names) - ledger_user_message = UserMessage(content=ledger_prompt, source=self.metadata["name"]) + ledger_user_message = UserMessage(content=ledger_prompt, source=self.metadata["type"]) assert max_json_retries > 0 for _ in range(max_json_retries): @@ -165,7 +165,7 @@ class LedgerOrchestrator(BaseOrchestrator): except json.JSONDecodeError as e: logger.info( OrchestrationEvent( - f"{self.metadata['name']} (error)", + f"{self.metadata['type']} (error)", f"Failed to parse ledger information: {ledger_str}", ) ) @@ -180,10 +180,10 @@ class LedgerOrchestrator(BaseOrchestrator): if self._should_replan: plan_str = await self._plan() - plan_user_message = UserMessage(content=plan_str, source=self.metadata["name"]) + plan_user_message = UserMessage(content=plan_str, source=self.metadata["type"]) logger.info( OrchestrationEvent( - f"{self.metadata['name']} (thought)", + f"{self.metadata['type']} (thought)", f"New plan:\n{plan_str}", ) ) @@ -196,7 +196,7 @@ class LedgerOrchestrator(BaseOrchestrator): ledger_dict = await self.update_ledger() logger.info( OrchestrationEvent( - f"{self.metadata['name']} (thought)", + f"{self.metadata['type']} (thought)", f"Updated Ledger:\n{json.dumps(ledger_dict, indent=2)}", ) ) @@ -204,7 +204,7 @@ class LedgerOrchestrator(BaseOrchestrator): if ledger_dict["is_request_satisfied"]["answer"] is True: logger.info( OrchestrationEvent( - f"{self.metadata['name']} (thought)", + f"{self.metadata['type']} (thought)", "Request satisfied.", ) ) @@ -219,7 +219,7 @@ class LedgerOrchestrator(BaseOrchestrator): if self._replan_counter < self._max_replans: logger.info( OrchestrationEvent( - f"{self.metadata['name']} (thought)", + f"{self.metadata['type']} (thought)", "Stalled.... Replanning...", ) ) @@ -227,7 +227,7 @@ class LedgerOrchestrator(BaseOrchestrator): else: logger.info( OrchestrationEvent( - f"{self.metadata['name']} (thought)", + f"{self.metadata['type']} (thought)", "Replan counter exceeded... Terminating.", ) ) @@ -235,11 +235,11 @@ class LedgerOrchestrator(BaseOrchestrator): next_agent_name = ledger_dict["next_speaker"]["answer"] for agent in self._agents: - if (await agent.metadata)["name"] == next_agent_name: + if (await agent.metadata)["type"] == next_agent_name: # broadcast a new message instruction = ledger_dict["instruction_or_question"]["answer"] - user_message = UserMessage(content=instruction, source=self.metadata["name"]) - logger.info(OrchestrationEvent(f"{self.metadata['name']} (-> {next_agent_name})", instruction)) + user_message = UserMessage(content=instruction, source=self.metadata["type"]) + logger.info(OrchestrationEvent(f"{self.metadata['type']} (-> {next_agent_name})", instruction)) await self.publish_message(BroadcastMessage(content=user_message, request_halt=False)) return agent diff --git a/python/teams/team-one/src/team_one/agents/reflex_agents.py b/python/teams/team-one/src/team_one/agents/reflex_agents.py index 1f9e0cf7b..2c51f6c9a 100644 --- a/python/teams/team-one/src/team_one/agents/reflex_agents.py +++ b/python/teams/team-one/src/team_one/agents/reflex_agents.py @@ -18,7 +18,7 @@ class ReflexAgent(TypeRoutedAgent): async def handle_request_reply_message( self, message: RequestReplyMessage, cancellation_token: CancellationToken ) -> None: - name = self.metadata["name"] + name = self.metadata["type"] response_message = UserMessage( content=f"Hello, world from {name}!",