refactor: 简化 AgentScope 运行时模块与事件处理

- 移除冗余的 user_token 参数传递
- 重构 tool.result 事件使用 ToolAgentOutput 模型
- 重构 text.end 事件使用 WorkerAgentOutput 模型
- 简化 store 模块的 tool result 处理逻辑
- 更新 router/service 适配新事件结构
- 清理废弃的测试文件与设计文档
- 新增 AgentRuns 多模态存储设计文档
This commit is contained in:
qzl
2026-03-13 17:27:18 +08:00
parent 3273d63b23
commit 1c02503d1d
29 changed files with 1259 additions and 2725 deletions
+20 -64
View File
@@ -11,9 +11,7 @@ from typing import Annotated, Union
from ag_ui.core import RunAgentInput
from core.agentscope.events import to_sse_event
from core.auth.jwt_verifier import JwtVerifier, TokenValidationError
from core.auth.models import CurrentUser
from core.config.settings import config
from core.logging import get_logger
from fastapi import (
APIRouter,
@@ -38,6 +36,7 @@ from v1.agent.dependencies import get_agent_service
from v1.agent.schemas import (
AsrTranscribeResponse,
AttachmentReference,
AttachmentSignedUrlResponse,
AttachmentUploadResponse,
TaskAcceptedResponse,
)
@@ -63,42 +62,6 @@ _ALLOWED_AUDIO_CONTENT_TYPES = {
}
def _verified_access_token_for_user(
*,
authorization: str | None,
current_user: CurrentUser,
) -> str:
if not isinstance(authorization, str):
raise HTTPException(status_code=401, detail="Unauthorized")
normalized = authorization.strip()
if not normalized:
raise HTTPException(status_code=401, detail="Unauthorized")
if not normalized.lower().startswith("bearer "):
raise HTTPException(status_code=401, detail="Unauthorized")
token = normalized[7:].strip()
if not token:
raise HTTPException(status_code=401, detail="Unauthorized")
jwt_secret = config.supabase.jwt_secret
if jwt_secret is None:
raise HTTPException(status_code=503, detail="Auth verifier unavailable")
verifier = JwtVerifier(
issuer=str(config.supabase.jwt_issuer),
jwt_secret=jwt_secret.get_secret_value(),
jwt_algorithm=config.supabase.jwt_algorithm,
)
try:
payload = verifier.verify(token)
except TokenValidationError as exc:
raise HTTPException(status_code=401, detail="Unauthorized") from exc
subject = payload.get("sub")
if not isinstance(subject, str) or subject != str(current_user.id):
raise HTTPException(status_code=403, detail="Forbidden")
return token
def _looks_like_wav_header(header: bytes) -> bool:
if len(header) < _WAV_HEADER_MIN_BYTES:
return False
@@ -164,7 +127,6 @@ async def enqueue_run(
request: RunAgentInput,
service: Annotated[AgentService, Depends(get_agent_service)],
current_user: Annotated[CurrentUser, Depends(get_current_user)],
authorization: str | None = Header(default=None, alias="Authorization"),
) -> TaskAcceptedResponse:
try:
normalized = parse_run_input(request.model_dump(mode="json", by_alias=True))
@@ -174,15 +136,10 @@ async def enqueue_run(
allowed = await _allow_run_request(user_id=str(current_user.id))
if not allowed:
raise HTTPException(status_code=429, detail="Too many run requests")
user_token = _verified_access_token_for_user(
authorization=authorization,
current_user=current_user,
)
task = await service.enqueue_run(
run_input=request,
current_user=current_user,
user_token=user_token,
)
return TaskAcceptedResponse(
taskId=task.task_id,
@@ -202,7 +159,6 @@ async def enqueue_resume(
request: RunAgentInput,
service: Annotated[AgentService, Depends(get_agent_service)],
current_user: Annotated[CurrentUser, Depends(get_current_user)],
authorization: str | None = Header(default=None, alias="Authorization"),
) -> TaskAcceptedResponse:
if request.thread_id != thread_id:
raise HTTPException(status_code=422, detail="thread_id path/body mismatch")
@@ -214,15 +170,10 @@ async def enqueue_resume(
allowed = await _allow_run_request(user_id=str(current_user.id))
if not allowed:
raise HTTPException(status_code=429, detail="Too many run requests")
user_token = _verified_access_token_for_user(
authorization=authorization,
current_user=current_user,
)
task = await service.enqueue_resume(
thread_id=thread_id,
run_input=request,
current_user=current_user,
user_token=user_token,
)
return TaskAcceptedResponse(
taskId=task.task_id,
@@ -304,20 +255,6 @@ async def stream_events(
)
@router.get("/runs/{thread_id}/history")
async def get_history_snapshot(
thread_id: str,
service: Annotated[AgentService, Depends(get_agent_service)],
current_user: Annotated[CurrentUser, Depends(get_current_user)],
before: date | None = Query(default=None),
) -> dict[str, object]:
return await service.get_history_snapshot(
thread_id=thread_id,
before=before,
current_user=current_user,
)
@router.get("/history")
async def get_user_history_snapshot(
service: Annotated[AgentService, Depends(get_agent_service)],
@@ -360,6 +297,25 @@ async def upload_attachment(
)
@router.get(
"/attachments/signed-url",
response_model=AttachmentSignedUrlResponse,
status_code=status.HTTP_200_OK,
)
async def create_attachment_signed_url(
service: Annotated[AgentService, Depends(get_agent_service)],
current_user: Annotated[CurrentUser, Depends(get_current_user)],
bucket: str = Query(min_length=1, max_length=100),
path: str = Query(min_length=1, max_length=500),
) -> AttachmentSignedUrlResponse:
signed = await service.create_attachment_signed_url(
bucket=bucket,
path=path,
current_user=current_user,
)
return AttachmentSignedUrlResponse(**signed)
@router.post(
"/transcribe",
response_model=AsrTranscribeResponse,