feat(agents): Phase 7-10 API endpoints for hooks, plugins, skills, sessions
This commit is contained in:
17
backend/app/agents/session/__init__.py
Normal file
17
backend/app/agents/session/__init__.py
Normal file
@@ -0,0 +1,17 @@
|
||||
"""Agent Session Management - Phase 10.3"""
|
||||
|
||||
from app.agents.session.manager import (
|
||||
AgentSession,
|
||||
SessionContext,
|
||||
SessionPersistence,
|
||||
create_agent_session,
|
||||
get_agent_session,
|
||||
)
|
||||
|
||||
__all__ = [
|
||||
"AgentSession",
|
||||
"SessionContext",
|
||||
"SessionPersistence",
|
||||
"create_agent_session",
|
||||
"get_agent_session",
|
||||
]
|
||||
238
backend/app/agents/session/manager.py
Normal file
238
backend/app/agents/session/manager.py
Normal file
@@ -0,0 +1,238 @@
|
||||
"""Agent Session 管理 - Phase 10.3
|
||||
|
||||
支持会话层级管理和子会话创建。
|
||||
"""
|
||||
|
||||
import json
|
||||
import os
|
||||
import uuid
|
||||
from dataclasses import asdict, dataclass, field
|
||||
from datetime import datetime
|
||||
from typing import Any
|
||||
|
||||
|
||||
@dataclass
|
||||
class SessionContext:
|
||||
"""会话上下文"""
|
||||
|
||||
session_id: str
|
||||
parent_session_id: str | None = None
|
||||
root_session_id: str | None = None
|
||||
depth: int = 0
|
||||
user_id: str | None = None
|
||||
created_at: str | None = None
|
||||
last_active: str | None = None
|
||||
message_count: int = 0
|
||||
metadata: dict[str, Any] = field(default_factory=dict)
|
||||
|
||||
def __post_init__(self):
|
||||
if self.created_at is None:
|
||||
self.created_at = datetime.now().isoformat()
|
||||
if self.last_active is None:
|
||||
self.last_active = self.created_at
|
||||
|
||||
|
||||
@dataclass
|
||||
class SessionPersistence:
|
||||
"""会话持久化"""
|
||||
|
||||
def __init__(self, persistence_dir: str | None = None):
|
||||
if persistence_dir is None:
|
||||
persistence_dir = os.path.join(
|
||||
os.path.dirname(__file__), "..", "..", "..", "data", "sessions"
|
||||
)
|
||||
self.persistence_dir = persistence_dir
|
||||
|
||||
def _get_session_path(self, session_id: str) -> str:
|
||||
return os.path.join(self.persistence_dir, f"{session_id}.json")
|
||||
|
||||
def save(self, session: "AgentSession") -> bool:
|
||||
"""保存会话"""
|
||||
try:
|
||||
os.makedirs(self.persistence_dir, exist_ok=True)
|
||||
path = self._get_session_path(session.session_id)
|
||||
data = {
|
||||
"session_id": session.session_id,
|
||||
"parent_session_id": session.context.parent_session_id,
|
||||
"root_session_id": session.context.root_session_id,
|
||||
"depth": session.context.depth,
|
||||
"user_id": session.context.user_id,
|
||||
"created_at": session.context.created_at,
|
||||
"last_active": session.context.last_active,
|
||||
"message_count": session.context.message_count,
|
||||
"metadata": session.context.metadata,
|
||||
"history": session._history,
|
||||
}
|
||||
with open(path, "w", encoding="utf-8") as f:
|
||||
json.dump(data, f, indent=2, ensure_ascii=False)
|
||||
return True
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
def load(self, session_id: str) -> dict[str, Any] | None:
|
||||
"""加载会话"""
|
||||
try:
|
||||
path = self._get_session_path(session_id)
|
||||
if not os.path.exists(path):
|
||||
return None
|
||||
with open(path, "r", encoding="utf-8") as f:
|
||||
return json.load(f)
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
def delete(self, session_id: str) -> bool:
|
||||
"""删除会话"""
|
||||
try:
|
||||
path = self._get_session_path(session_id)
|
||||
if os.path.exists(path):
|
||||
os.remove(path)
|
||||
return True
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
def list_sessions(self, user_id: str | None = None) -> list[dict[str, Any]]:
|
||||
"""列出所有会话"""
|
||||
sessions = []
|
||||
try:
|
||||
os.makedirs(self.persistence_dir, exist_ok=True)
|
||||
for filename in os.listdir(self.persistence_dir):
|
||||
if filename.endswith(".json"):
|
||||
path = os.path.join(self.persistence_dir, filename)
|
||||
with open(path, "r", encoding="utf-8") as f:
|
||||
data = json.load(f)
|
||||
if user_id is None or data.get("user_id") == user_id:
|
||||
sessions.append(data)
|
||||
except Exception:
|
||||
pass
|
||||
return sessions
|
||||
|
||||
|
||||
class AgentSession:
|
||||
"""Agent 会话管理器
|
||||
|
||||
支持:
|
||||
- 会话层级(parent/root/depth)
|
||||
- 子会话创建
|
||||
- 会话摘要
|
||||
- 持久化
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
session_id: str | None = None,
|
||||
user_id: str | None = None,
|
||||
parent_session_id: str | None = None,
|
||||
):
|
||||
self.session_id = session_id or str(uuid.uuid4())[:8]
|
||||
self.context = SessionContext(
|
||||
session_id=self.session_id,
|
||||
user_id=user_id,
|
||||
parent_session_id=parent_session_id,
|
||||
depth=0 if parent_session_id is None else 1,
|
||||
)
|
||||
self._history: list[dict[str, Any]] = []
|
||||
self._persistence = SessionPersistence()
|
||||
|
||||
# 如果有父会话,设置 root_session_id
|
||||
if parent_session_id:
|
||||
parent_data = self._persistence.load(parent_session_id)
|
||||
if parent_data:
|
||||
self.context.root_session_id = (
|
||||
parent_data.get("root_session_id") or parent_session_id
|
||||
)
|
||||
self.context.depth = parent_data.get("depth", 0) + 1
|
||||
|
||||
async def initialize(self) -> dict[str, Any]:
|
||||
"""初始化会话"""
|
||||
self.context.last_active = datetime.now().isoformat()
|
||||
self._persistence.save(self)
|
||||
return {
|
||||
"session_id": self.session_id,
|
||||
"depth": self.context.depth,
|
||||
"parent_session_id": self.context.parent_session_id,
|
||||
"root_session_id": self.context.root_session_id,
|
||||
}
|
||||
|
||||
async def process_message(self, message: str, response: str) -> None:
|
||||
"""处理消息并记录到历史"""
|
||||
self.context.message_count += 1
|
||||
self.context.last_active = datetime.now().isoformat()
|
||||
self._history.append(
|
||||
{
|
||||
"role": "user",
|
||||
"content": message,
|
||||
"timestamp": datetime.now().isoformat(),
|
||||
}
|
||||
)
|
||||
self._history.append(
|
||||
{
|
||||
"role": "assistant",
|
||||
"content": response,
|
||||
"timestamp": datetime.now().isoformat(),
|
||||
}
|
||||
)
|
||||
self._persistence.save(self)
|
||||
|
||||
async def spawn_child_session(self, user_id: str | None = None) -> "AgentSession":
|
||||
"""创建子会话"""
|
||||
child = AgentSession(
|
||||
user_id=user_id or self.context.user_id,
|
||||
parent_session_id=self.session_id,
|
||||
)
|
||||
child.context.root_session_id = self.context.root_session_id or self.session_id
|
||||
await child.initialize()
|
||||
return child
|
||||
|
||||
async def get_session_summary(self) -> dict[str, Any]:
|
||||
"""获取会话摘要"""
|
||||
return {
|
||||
"session_id": self.session_id,
|
||||
"parent_session_id": self.context.parent_session_id,
|
||||
"root_session_id": self.context.root_session_id,
|
||||
"depth": self.context.depth,
|
||||
"user_id": self.context.user_id,
|
||||
"created_at": self.context.created_at,
|
||||
"last_active": self.context.last_active,
|
||||
"message_count": self.context.message_count,
|
||||
"history_length": len(self._history),
|
||||
}
|
||||
|
||||
async def persist(self) -> bool:
|
||||
"""持久化会话"""
|
||||
return self._persistence.save(self)
|
||||
|
||||
def get_history(self) -> list[dict[str, Any]]:
|
||||
"""获取会话历史"""
|
||||
return self._history.copy()
|
||||
|
||||
def add_metadata(self, key: str, value: Any) -> None:
|
||||
"""添加会话元数据"""
|
||||
self.context.metadata[key] = value
|
||||
|
||||
def get_metadata(self, key: str) -> Any:
|
||||
"""获取会话元数据"""
|
||||
return self.context.metadata.get(key)
|
||||
|
||||
|
||||
# 全局会话存储(内存中)
|
||||
_sessions: dict[str, AgentSession] = {}
|
||||
|
||||
|
||||
def get_agent_session(session_id: str) -> AgentSession | None:
|
||||
"""获取会话"""
|
||||
return _sessions.get(session_id)
|
||||
|
||||
|
||||
def create_agent_session(
|
||||
session_id: str | None = None,
|
||||
user_id: str | None = None,
|
||||
parent_session_id: str | None = None,
|
||||
) -> AgentSession:
|
||||
"""创建新会话"""
|
||||
session = AgentSession(
|
||||
session_id=session_id,
|
||||
user_id=user_id,
|
||||
parent_session_id=parent_session_id,
|
||||
)
|
||||
_sessions[session.session_id] = session
|
||||
return session
|
||||
Reference in New Issue
Block a user