- harness/es.py: append-only event store + проекции (образец — кооп-портал) - harness/levels.py: уровни 1с/1м/1ч/1д, контекст ∝ масштабу - harness/scheduler.py: уровневые потоки, идемпотентные тики, absorbed-стабы - harness/isolated_runner.py + _llm_worker.py: LLM-тик в сабпроцессе (глобальный asyncio-рантайм Strands не переживает 2+ create_harness) - cli.py: init/task/tasks/status/events + requeue (написан самим минутным агентом) - 9router: отдельный ключ sk-simbiot, модель auto (glm-5.3 первым)
133 lines
5.5 KiB
Python
133 lines
5.5 KiB
Python
"""Session manager interface for agent session management."""
|
|
|
|
import logging
|
|
from abc import ABC, abstractmethod
|
|
from typing import TYPE_CHECKING, Any, Generic
|
|
|
|
from typing_extensions import TypeVar
|
|
|
|
from ..experimental.bidi.hooks import BidiAgentStopEvent
|
|
from ..hooks.events import (
|
|
AfterInvocationEvent,
|
|
AfterMultiAgentInvocationEvent,
|
|
AfterNodeCallEvent,
|
|
AgentInitializedEvent,
|
|
MessageAddedEvent,
|
|
MultiAgentInitializedEvent,
|
|
)
|
|
from ..hooks.registry import HookProvider, HookRegistry
|
|
from ..types.content import Message
|
|
|
|
if TYPE_CHECKING:
|
|
from ..agent.agent import Agent
|
|
from ..multiagent.base import MultiAgentBase
|
|
from ..types.agent import LocalAgent
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
_SessionAgentT = TypeVar("_SessionAgentT", bound="LocalAgent", default="Agent", contravariant=True)
|
|
|
|
|
|
class SessionManager(HookProvider, ABC, Generic[_SessionAgentT]):
|
|
"""Abstract interface for managing sessions.
|
|
|
|
A session manager is in charge of persisting the conversation and state of an agent across its interaction.
|
|
Changes made to the agents conversation, state, or other attributes should be persisted immediately after
|
|
they are changed. The different methods introduced in this class are called at important lifecycle events
|
|
for an agent, and should be persisted in the session.
|
|
|
|
The agent type defaults to Agent. Managers supporting both Agent and BidiAgent
|
|
implement SessionManager[LocalAgent].
|
|
"""
|
|
|
|
session_id: str
|
|
"""The unique session identifier for this session manager."""
|
|
|
|
def register_hooks(self, registry: HookRegistry, **kwargs: Any) -> None:
|
|
"""Register hooks for persisting the agent to the session."""
|
|
# After the normal Agent initialization behavior, call the session initialize function to restore the agent
|
|
registry.add_callback(AgentInitializedEvent, lambda event: self.initialize(event.agent))
|
|
|
|
# For each message appended to the Agents messages, store that message in the session
|
|
registry.add_callback(MessageAddedEvent, lambda event: self.append_message(event.message, event.agent))
|
|
|
|
# Sync the agent into the session for each message in case the agent state was updated
|
|
registry.add_callback(MessageAddedEvent, lambda event: self.sync_agent(event.agent))
|
|
|
|
# After an agent was invoked, sync it with the session to capture any conversation manager state updates
|
|
registry.add_callback(AfterInvocationEvent, lambda event: self.sync_agent(event.agent))
|
|
|
|
registry.add_callback(MultiAgentInitializedEvent, lambda event: self.initialize_multi_agent(event.source))
|
|
registry.add_callback(AfterNodeCallEvent, lambda event: self.sync_multi_agent(event.source))
|
|
registry.add_callback(AfterMultiAgentInvocationEvent, lambda event: self.sync_multi_agent(event.source))
|
|
|
|
registry.add_callback(BidiAgentStopEvent, lambda event: self.sync_agent(event.agent))
|
|
|
|
@abstractmethod
|
|
def redact_latest_message(self, redact_message: Message, agent: _SessionAgentT, **kwargs: Any) -> None:
|
|
"""Redact the message most recently appended to the agent in the session.
|
|
|
|
Args:
|
|
redact_message: New message to use that contains the redact content
|
|
agent: Agent to apply the message redaction to
|
|
**kwargs: Additional keyword arguments for future extensibility.
|
|
"""
|
|
|
|
@abstractmethod
|
|
def append_message(self, message: Message, agent: _SessionAgentT, **kwargs: Any) -> None:
|
|
"""Append a message to the agent's session.
|
|
|
|
Args:
|
|
message: Message to add to the agent in the session
|
|
agent: Agent to append the message to
|
|
**kwargs: Additional keyword arguments for future extensibility.
|
|
"""
|
|
|
|
@abstractmethod
|
|
def sync_agent(self, agent: _SessionAgentT, **kwargs: Any) -> None:
|
|
"""Serialize and sync the agent with the session storage.
|
|
|
|
Args:
|
|
agent: Agent who should be synchronized with the session storage
|
|
**kwargs: Additional keyword arguments for future extensibility.
|
|
"""
|
|
|
|
@abstractmethod
|
|
def initialize(self, agent: _SessionAgentT, **kwargs: Any) -> None:
|
|
"""Initialize an agent with a session.
|
|
|
|
Args:
|
|
agent: Agent to initialize
|
|
**kwargs: Additional keyword arguments for future extensibility.
|
|
"""
|
|
|
|
def sync_multi_agent(self, source: "MultiAgentBase", **kwargs: Any) -> None:
|
|
"""Serialize and sync multi-agent with the session storage.
|
|
|
|
Args:
|
|
source: Multi-agent source object to persist
|
|
**kwargs: Additional keyword arguments for future extensibility.
|
|
"""
|
|
raise NotImplementedError(
|
|
f"{self.__class__.__name__} does not support multi-agent persistence "
|
|
"(sync_multi_agent). Provide an implementation or use a "
|
|
"SessionManager with session_type=SessionType.MULTI_AGENT."
|
|
)
|
|
|
|
def initialize_multi_agent(self, source: "MultiAgentBase", **kwargs: Any) -> None:
|
|
"""Read multi-agent state from persistent storage.
|
|
|
|
Args:
|
|
**kwargs: Additional keyword arguments for future extensibility.
|
|
source: Multi-agent state to initialize.
|
|
|
|
Returns:
|
|
Multi-agent state dictionary or empty dict if not found.
|
|
|
|
"""
|
|
raise NotImplementedError(
|
|
f"{self.__class__.__name__} does not support multi-agent persistence "
|
|
"(initialize_multi_agent). Provide an implementation or use a "
|
|
"SessionManager with session_type=SessionType.MULTI_AGENT."
|
|
)
|