mirror of
https://github.com/OpenHands/OpenHands.git
synced 2026-03-22 13:47:19 +08:00
Refactor system message handling to use event stream (#7824)
Co-authored-by: openhands <openhands@all-hands.dev> Co-authored-by: Calvin Smith <email@cjsmith.io>
This commit is contained in:
@@ -5,10 +5,13 @@ if TYPE_CHECKING:
|
||||
from openhands.controller.state.state import State
|
||||
from openhands.core.config import AgentConfig
|
||||
from openhands.events.action import Action
|
||||
from openhands.events.action.message import SystemMessageAction
|
||||
from openhands.core.exceptions import (
|
||||
AgentAlreadyRegisteredError,
|
||||
AgentNotRegisteredError,
|
||||
)
|
||||
from openhands.core.logger import openhands_logger as logger
|
||||
from openhands.events.event import EventSource
|
||||
from openhands.llm.llm import LLM
|
||||
from openhands.runtime.plugins import PluginRequirement
|
||||
|
||||
@@ -38,6 +41,42 @@ class Agent(ABC):
|
||||
self._complete = False
|
||||
self.prompt_manager: 'PromptManager' | None = None
|
||||
self.mcp_tools: list[dict] = []
|
||||
self.tools: list = []
|
||||
|
||||
def get_system_message(self) -> 'SystemMessageAction | None':
|
||||
"""
|
||||
Returns a SystemMessageAction containing the system message and tools.
|
||||
This will be added to the event stream as the first message.
|
||||
|
||||
Returns:
|
||||
SystemMessageAction: The system message action with content and tools
|
||||
None: If there was an error generating the system message
|
||||
"""
|
||||
# Import here to avoid circular imports
|
||||
from openhands.events.action.message import SystemMessageAction
|
||||
|
||||
try:
|
||||
if not self.prompt_manager:
|
||||
logger.warning(
|
||||
f'[{self.name}] Prompt manager not initialized before getting system message'
|
||||
)
|
||||
return None
|
||||
|
||||
system_message = self.prompt_manager.get_system_message()
|
||||
|
||||
# Get tools if available
|
||||
tools = getattr(self, 'tools', None)
|
||||
|
||||
system_message_action = SystemMessageAction(
|
||||
content=system_message, tools=tools
|
||||
)
|
||||
# Set the source attribute
|
||||
system_message_action._source = EventSource.AGENT # type: ignore
|
||||
|
||||
return system_message_action
|
||||
except Exception as e:
|
||||
logger.warning(f'[{self.name}] Failed to generate system message: {e}')
|
||||
return None
|
||||
|
||||
@property
|
||||
def complete(self) -> bool:
|
||||
|
||||
@@ -54,6 +54,7 @@ from openhands.events.action import (
|
||||
IPythonRunCellAction,
|
||||
MessageAction,
|
||||
NullAction,
|
||||
SystemMessageAction,
|
||||
)
|
||||
from openhands.events.action.agent import CondensationAction, RecallAction
|
||||
from openhands.events.event import Event
|
||||
@@ -163,6 +164,31 @@ class AgentController:
|
||||
# replay-related
|
||||
self._replay_manager = ReplayManager(replay_events)
|
||||
|
||||
# Add the system message to the event stream
|
||||
self._add_system_message()
|
||||
|
||||
def _add_system_message(self):
|
||||
for event in self.event_stream.get_events(start_id=self.state.start_id):
|
||||
if isinstance(event, MessageAction) and event.source == EventSource.USER:
|
||||
# FIXME: Remove this after 6/1/2025
|
||||
# Do not try to add a system message if we first run into
|
||||
# a user message -- this means the eventstream exits before
|
||||
# SystemMessageAction is introduced.
|
||||
# We expect *agent* to handle this case gracefully.
|
||||
return
|
||||
|
||||
if isinstance(event, SystemMessageAction):
|
||||
# Do not try to add the system message if it already exists
|
||||
return
|
||||
|
||||
# Add the system message to the event stream
|
||||
# This should be done for all agents, including delegates
|
||||
system_message = self.agent.get_system_message()
|
||||
logger.debug(f'System message got from agent: {system_message}')
|
||||
if system_message:
|
||||
self.event_stream.add_event(system_message, EventSource.AGENT)
|
||||
logger.debug(f'System message added to event stream: {system_message}')
|
||||
|
||||
async def close(self, set_stop_state=True) -> None:
|
||||
"""Closes the agent controller, canceling any ongoing tasks and unsubscribing from the event stream.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user