refactor: 重构 AgentScope 运行时模块并优化前端附件展示

This commit is contained in:
qzl
2026-03-13 15:42:01 +08:00
parent a10a2db27a
commit 4c10929498
28 changed files with 1494 additions and 2163 deletions
+40 -78
View File
@@ -12,6 +12,7 @@ from sqlalchemy.ext.asyncio import AsyncSession
from core.config.settings import config
from models.agent_chat_message import AgentChatMessage, AgentChatMessageRole
from models.agent_chat_session import AgentChatSession
from services.base.supabase import supabase_service
class ToolResultPayloadStorage(Protocol):
@@ -201,61 +202,6 @@ class AgentRepository:
return None
return str(latest_id)
async def get_message_attachment_reference(
self,
*,
session_id: str,
message_id: str,
attachment_index: int,
) -> dict[str, str] | None:
try:
session_uuid = UUID(session_id)
message_uuid = UUID(message_id)
except ValueError as exc:
raise HTTPException(
status_code=422, detail="Invalid message/session id"
) from exc
stmt = (
select(AgentChatMessage)
.where(AgentChatMessage.id == message_uuid)
.where(AgentChatMessage.session_id == session_uuid)
.where(AgentChatMessage.deleted_at.is_(None))
)
message = (await self._session.execute(stmt)).scalar_one_or_none()
if message is None:
return None
metadata = (
message.metadata_json if isinstance(message.metadata_json, dict) else {}
)
attachments_raw = metadata.get("attachments")
if not isinstance(attachments_raw, list):
return None
if attachment_index < 0 or attachment_index >= len(attachments_raw):
return None
attachment = attachments_raw[attachment_index]
if not isinstance(attachment, dict):
return None
bucket = attachment.get("bucket")
path = attachment.get("path")
mime_type = attachment.get("mimeType")
if (
not isinstance(bucket, str)
or not bucket
or not isinstance(path, str)
or not path
or not isinstance(mime_type, str)
or not mime_type
):
return None
return {
"bucket": bucket,
"path": path,
"mimeType": mime_type,
}
async def _to_snapshot_message(
self, message: AgentChatMessage
) -> dict[str, object]:
@@ -350,29 +296,45 @@ class AgentRepository:
payload["content"] = display_content
else:
payload["content"] = message.content
metadata = message.metadata_json or {}
attachments = (
metadata.get("attachments") if isinstance(metadata, dict) else None
)
if isinstance(attachments, list):
rendered: list[dict[str, object]] = []
for index, item in enumerate(attachments):
if not isinstance(item, dict):
continue
mime_type = item.get("mimeType")
if not isinstance(mime_type, str) or not mime_type:
continue
rendered.append(
{
"mimeType": mime_type,
"previewPath": (
f"/api/v1/agent/runs/{message.session_id}/attachments/"
f"{message.id}/{index}"
),
}
)
if rendered:
payload["attachments"] = rendered
if role == AgentChatMessageRole.USER.value:
metadata = message.metadata_json or {}
user_attachments = metadata.get("user_message_attachments")
if isinstance(user_attachments, dict):
bucket = user_attachments.get("bucket")
path = user_attachments.get("path")
mime_type = user_attachments.get("mime_type")
if (
isinstance(bucket, str)
and isinstance(path, str)
and isinstance(mime_type, str)
):
try:
signed_url = await supabase_service.create_signed_url(
bucket=bucket,
path=path,
expires_in_seconds=3600,
)
attachment_block = {
"type": "binary",
"mimeType": mime_type,
"url": signed_url,
}
existing_content = message.content
if (
isinstance(existing_content, str)
and existing_content.strip()
):
content_blocks = [
{"type": "text", "text": existing_content}
]
content_blocks.append(attachment_block)
payload["content"] = content_blocks
else:
payload["content"] = [attachment_block]
except Exception: # noqa: BLE001
pass
return payload