Skip to content
20 changes: 20 additions & 0 deletions camel/agents/chat_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import json
import logging
import textwrap
import threading
import uuid
from collections import defaultdict
from datetime import datetime
Expand Down Expand Up @@ -151,6 +152,9 @@ class ChatAgent(BaseAgent):
model calling at each step. (default: :obj:`False`)
agent_id (str, optional): The ID of the agent. If not provided, a
random UUID will be generated. (default: :obj:`None`)
stop_event (Optional[threading.Event], optional): Event to signal
termination of the agent's operation. When set, the agent will
terminate its execution. (default: :obj:`None`)
"""

def __init__(
Expand Down Expand Up @@ -182,6 +186,7 @@ def __init__(
scheduling_strategy: str = "round_robin",
single_iteration: bool = False,
agent_id: Optional[str] = None,
stop_event: Optional[threading.Event] = None,
) -> None:
# Resolve model backends and set up model manager
resolved_models = self._resolve_models(model)
Expand Down Expand Up @@ -252,6 +257,7 @@ def __init__(
self.terminated = False
self.response_terminators = response_terminators or []
self.single_iteration = single_iteration
self.stop_event = stop_event

def reset(self):
r"""Resets the :obj:`ChatAgent` to its initial state."""
Expand Down Expand Up @@ -757,6 +763,13 @@ def step(
self._get_full_tool_schemas(),
)

# Terminate Agent if stop_event is set
if self.stop_event and self.stop_event.is_set():
# Use the _step_token_exceed to terminate the agent with reason
return self._step_token_exceed(
num_tokens, tool_call_records, "termination_triggered"
)

if tool_call_requests := response.tool_call_requests:
# Process all tool calls
for tool_call_request in tool_call_requests:
Expand Down Expand Up @@ -849,6 +862,13 @@ async def astep(
self._get_full_tool_schemas(),
)

# Terminate Agent if stop_event is set
if self.stop_event and self.stop_event.is_set():
# Use the _step_token_exceed to terminate the agent with reason
return self._step_token_exceed(
num_tokens, tool_call_records, "termination_triggered"
)
Comment on lines +868 to +870
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_step_token_exceed is a bit confusing since the agent is not terminated since the number of token exceeding the context windows. Could we improve this?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh yes thanks I forgot to mention.

@lightaime Since the function is generic, how about we rename it to _step_terminate because it terminates then returns token number and called functions?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated in #2347

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @Wendong-Fan and @lightaime !


if tool_call_requests := response.tool_call_requests:
# Process all tool calls
for tool_call_request in tool_call_requests:
Expand Down
5 changes: 1 addition & 4 deletions camel/responses/agent_responses.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,5 @@ class ChatAgentResponse(BaseModel):
@property
def msg(self):
if len(self.msgs) != 1:
raise RuntimeError(
"Property msg is only available "
"for a single message in msgs."
)
return None
return self.msgs[0]
12 changes: 12 additions & 0 deletions camel/societies/role_playing.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
# limitations under the License.
# ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. =========
import logging
import threading
from typing import Dict, List, Optional, Sequence, Tuple, Union

from camel.agents import (
Expand Down Expand Up @@ -77,6 +78,9 @@ class RolePlaying:
task specify meta dict with. (default: :obj:`None`)
output_language (str, optional): The language to be output by the
agents. (default: :obj:`None`)
stop_event (Optional[threading.Event], optional): Event to signal
termination of the agent's operation. When set, the agent will
terminate its execution. (default: :obj:`None`)
"""

def __init__(
Expand All @@ -101,6 +105,7 @@ def __init__(
extend_sys_msg_meta_dicts: Optional[List[Dict]] = None,
extend_task_specify_meta_dict: Optional[Dict] = None,
output_language: Optional[str] = None,
stop_event: Optional[threading.Event] = None,
) -> None:
if model is not None:
Comment on lines 106 to 110
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi there, @Wendong-Fan as suggested I have elevated the stop_event to be part of ChatAgent, thus passing the event turned to:

run_society -> society.stop_event = stop_event -> which is passed to ChatAgent in __init__

Since society:OwlRolePlaying has stop_event now, this resulted in updating OwlRolePlaying in camel-ai/owl#450 which is reflected to its parent class RolePlaying here.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, if updating RolePlaying is not appropriate We can revert the last commit ae419f2 and it would constrain changes to OwlRolePlaying only.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks @a7m-1st ! I think current approach is good

logger.warning(
Expand Down Expand Up @@ -156,6 +161,7 @@ def __init__(
assistant_agent_kwargs=assistant_agent_kwargs,
user_agent_kwargs=user_agent_kwargs,
output_language=output_language,
stop_event=stop_event,
)
self.critic: Optional[Union[CriticAgent, Human]] = None
self.critic_sys_msg: Optional[BaseMessage] = None
Expand Down Expand Up @@ -316,6 +322,7 @@ def _init_agents(
assistant_agent_kwargs: Optional[Dict] = None,
user_agent_kwargs: Optional[Dict] = None,
output_language: Optional[str] = None,
stop_event: Optional[threading.Event] = None,
) -> None:
r"""Initialize assistant and user agents with their system messages.

Expand All @@ -330,6 +337,9 @@ def _init_agents(
pass to the user agent. (default: :obj:`None`)
output_language (str, optional): The language to be output by the
agents. (default: :obj:`None`)
stop_event (Optional[threading.Event], optional): Event to signal
termination of the agent's operation. When set, the agent will
terminate its execution. (default: :obj:`None`)
"""
if self.model is not None:
if assistant_agent_kwargs is None:
Expand All @@ -344,13 +354,15 @@ def _init_agents(
self.assistant_agent = ChatAgent(
init_assistant_sys_msg,
output_language=output_language,
stop_event=stop_event,
**(assistant_agent_kwargs or {}),
)
self.assistant_sys_msg = self.assistant_agent.system_message

self.user_agent = ChatAgent(
init_user_sys_msg,
output_language=output_language,
stop_event=stop_event,
**(user_agent_kwargs or {}),
)
self.user_sys_msg = self.user_agent.system_message
Expand Down
Loading