refactor(backend): 更新 agent 服务和配置层
This commit is contained in:
@@ -11,6 +11,7 @@ from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from models.agent_chat_message import AgentChatMessage, AgentChatMessageRole
|
||||
from models.agent_chat_session import AgentChatSession
|
||||
from models.system_agents import SystemAgents
|
||||
from schemas.messages.chat_message import (
|
||||
AgentChatMessage as AgentChatMessageSchema,
|
||||
AgentChatMessageMetadata,
|
||||
@@ -194,6 +195,45 @@ class AgentRepository:
|
||||
"messages": snapshot_messages,
|
||||
}
|
||||
|
||||
async def get_recent_messages_by_user_window(
|
||||
self, *, session_id: str, user_message_limit: int
|
||||
) -> list[dict[str, object]]:
|
||||
try:
|
||||
session_uuid = UUID(session_id)
|
||||
except ValueError as exc:
|
||||
raise HTTPException(status_code=422, detail="Invalid session_id") from exc
|
||||
|
||||
safe_user_limit = max(int(user_message_limit), 1)
|
||||
message_stmt = (
|
||||
select(AgentChatMessage)
|
||||
.where(AgentChatMessage.session_id == session_uuid)
|
||||
.where(AgentChatMessage.deleted_at.is_(None))
|
||||
.order_by(AgentChatMessage.seq.desc())
|
||||
)
|
||||
messages_desc = (await self._session.execute(message_stmt)).scalars().all()
|
||||
if not messages_desc:
|
||||
return []
|
||||
|
||||
selected_desc: list[AgentChatMessage] = []
|
||||
user_count = 0
|
||||
for message in messages_desc:
|
||||
selected_desc.append(message)
|
||||
role = (
|
||||
message.role.value
|
||||
if isinstance(message.role, AgentChatMessageRole)
|
||||
else str(message.role)
|
||||
)
|
||||
if role == AgentChatMessageRole.USER.value:
|
||||
user_count += 1
|
||||
if user_count >= safe_user_limit:
|
||||
break
|
||||
|
||||
selected = list(reversed(selected_desc))
|
||||
snapshot_messages: list[dict[str, object]] = []
|
||||
for message in selected:
|
||||
snapshot_messages.append(await self._to_snapshot_message(message))
|
||||
return snapshot_messages
|
||||
|
||||
async def get_latest_session_id_for_user(self, *, user_id: str) -> str | None:
|
||||
try:
|
||||
user_uuid = UUID(user_id)
|
||||
@@ -211,6 +251,23 @@ class AgentRepository:
|
||||
return None
|
||||
return str(latest_id)
|
||||
|
||||
async def get_system_agent_config(
|
||||
self, *, agent_type: str
|
||||
) -> dict[str, object] | None:
|
||||
normalized_type = agent_type.strip().lower()
|
||||
if not normalized_type:
|
||||
return None
|
||||
stmt = select(SystemAgents).where(SystemAgents.agent_type == normalized_type)
|
||||
row = (await self._session.execute(stmt)).scalar_one_or_none()
|
||||
if row is None:
|
||||
return None
|
||||
config_payload = row.config if isinstance(row.config, dict) else {}
|
||||
return {
|
||||
"agent_type": normalized_type,
|
||||
"status": str(row.status),
|
||||
"config": config_payload,
|
||||
}
|
||||
|
||||
async def _to_snapshot_message(
|
||||
self, message: AgentChatMessage
|
||||
) -> dict[str, object]:
|
||||
|
||||
@@ -168,10 +168,18 @@ class AgentService:
|
||||
)
|
||||
await self._repository.commit()
|
||||
|
||||
forwarded_props = getattr(run_input, "forwarded_props", None)
|
||||
system_agent_mode = "worker"
|
||||
if isinstance(forwarded_props, dict):
|
||||
raw_mode = forwarded_props.get("system_agent_mode")
|
||||
if isinstance(raw_mode, str) and raw_mode.strip():
|
||||
system_agent_mode = raw_mode.strip().lower()
|
||||
|
||||
task_id = await self._queue.enqueue(
|
||||
command={
|
||||
"command": "run",
|
||||
"owner_id": str(current_user.id),
|
||||
"system_agent_mode": system_agent_mode,
|
||||
"run_input": run_input.model_dump(
|
||||
mode="json", by_alias=True, exclude_none=True
|
||||
),
|
||||
@@ -185,45 +193,6 @@ class AgentService:
|
||||
created=created,
|
||||
)
|
||||
|
||||
async def load_agent_input_messages(
|
||||
self,
|
||||
*,
|
||||
thread_id: str,
|
||||
) -> dict[str, object] | None:
|
||||
"""Load recent messages for runtime agent input.
|
||||
|
||||
Returns messages from today and yesterday (if exists).
|
||||
"""
|
||||
today = await self._repository.get_history_day(
|
||||
session_id=thread_id,
|
||||
before=None,
|
||||
)
|
||||
if not today:
|
||||
return None
|
||||
|
||||
yesterday = await self._repository.get_history_day(
|
||||
session_id=thread_id,
|
||||
before=self._parse_history_day(today.get("day")),
|
||||
)
|
||||
|
||||
messages: list[dict[str, object]] = []
|
||||
if yesterday and yesterday.get("messages"):
|
||||
messages.extend(yesterday["messages"]) # type: ignore
|
||||
if today.get("messages"):
|
||||
messages.extend(today["messages"]) # type: ignore
|
||||
|
||||
return {"messages": messages}
|
||||
|
||||
def _parse_history_day(self, value: object) -> date | None:
|
||||
if isinstance(value, date):
|
||||
return value
|
||||
if isinstance(value, str):
|
||||
try:
|
||||
return date.fromisoformat(value)
|
||||
except ValueError:
|
||||
return None
|
||||
return None
|
||||
|
||||
async def _prepare_user_message(
|
||||
self,
|
||||
*,
|
||||
|
||||
@@ -24,7 +24,7 @@ def convert_message_to_history(
|
||||
|
||||
转换规则:
|
||||
- role=user: 读取 metadata.user_message_attachments,转换为 attachments[]
|
||||
- role=assistant: 读取 metadata.worker_agent_output.ui_hints,编译成 ui_schema
|
||||
- role=assistant: 读取 metadata.agent_output.ui_hints,编译成 ui_schema
|
||||
"""
|
||||
role = message.role
|
||||
content = message.content
|
||||
@@ -91,34 +91,31 @@ def _convert_user_attachments(
|
||||
def _compile_worker_ui_hints(
|
||||
metadata: AgentChatMessageMetadata | dict[str, Any] | None,
|
||||
) -> dict[str, Any] | None:
|
||||
"""编译 assistant 消息的 worker ui_hints"""
|
||||
"""编译 assistant 消息的 agent ui_hints"""
|
||||
if not metadata:
|
||||
return None
|
||||
|
||||
if isinstance(metadata, AgentChatMessageMetadata):
|
||||
worker_output = metadata.worker_agent_output
|
||||
agent_output = metadata.agent_output
|
||||
else:
|
||||
worker_output_data = metadata.get("worker_agent_output")
|
||||
if not worker_output_data:
|
||||
agent_output_data = metadata.get("agent_output")
|
||||
if not agent_output_data:
|
||||
return None
|
||||
if isinstance(worker_output_data, dict):
|
||||
raw_ui_schema = worker_output_data.get("ui_schema")
|
||||
if isinstance(agent_output_data, dict):
|
||||
raw_ui_schema = agent_output_data.get("ui_schema")
|
||||
if isinstance(raw_ui_schema, dict):
|
||||
return raw_ui_schema
|
||||
legacy_ui_schema = worker_output_data.get("uiSchema")
|
||||
if isinstance(legacy_ui_schema, dict):
|
||||
return legacy_ui_schema
|
||||
from schemas.agent.runtime_models import WorkerAgentOutputRich
|
||||
from schemas.agent.runtime_models import AgentOutput
|
||||
|
||||
try:
|
||||
worker_output = WorkerAgentOutputRich.model_validate(worker_output_data)
|
||||
agent_output = AgentOutput.model_validate(agent_output_data)
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
if not worker_output:
|
||||
if not agent_output:
|
||||
return None
|
||||
|
||||
ui_hints = worker_output.ui_hints
|
||||
ui_hints = agent_output.ui_hints
|
||||
if not ui_hints:
|
||||
return None
|
||||
|
||||
|
||||
Reference in New Issue
Block a user