feat: 添加 Agent 步骤事件与图片附件功能

- 新增 stepStarted/stepFinished 事件类型支持
- 前端实现图片附件上传和预览功能
- 后端增强工具结果存储和事件处理
- 完善相关单元测试和集成测试
This commit is contained in:
zl-q
2026-03-12 09:29:57 +08:00
parent 87215f9d41
commit 7b8865e256
45 changed files with 3869 additions and 308 deletions
@@ -18,8 +18,14 @@ class _FakeAgentService:
def __init__(self) -> None:
self._stream_called = False
async def enqueue_run(self, *, run_input: RunAgentInput, current_user: CurrentUser):
del current_user
async def enqueue_run(
self,
*,
run_input: RunAgentInput,
current_user: CurrentUser,
user_token: str | None = None,
):
del current_user, user_token
return SimpleNamespace(
task_id="task-run-1",
thread_id=run_input.thread_id,
@@ -33,8 +39,9 @@ class _FakeAgentService:
thread_id: str,
run_input: RunAgentInput,
current_user: CurrentUser,
user_token: str | None = None,
):
del thread_id, current_user
del thread_id, current_user, user_token
return SimpleNamespace(
task_id="task-resume-1",
thread_id=run_input.thread_id,
@@ -109,6 +116,23 @@ class _FakeAgentService:
},
}
async def upload_attachment(
self,
*,
thread_id: str,
filename: str | None,
content_type: str | None,
payload: bytes,
current_user: CurrentUser,
) -> dict[str, str]:
del filename, content_type, payload, current_user
return {
"bucket": "bucket-test",
"path": f"agent-inputs/user/{thread_id}/upload.png",
"mimeType": "image/png",
"url": "https://signed.example/upload.png",
}
class _FailingStreamAgentService(_FakeAgentService):
async def stream_events(
@@ -393,6 +417,31 @@ def test_resume_accepts_tool_message_without_user_message() -> None:
app.dependency_overrides = {}
def test_upload_attachment_returns_reference() -> None:
app.dependency_overrides[get_agent_service] = lambda: _FakeAgentService()
app.dependency_overrides[get_current_user] = lambda: CurrentUser(
id=uuid4(), email="user@example.com"
)
client = TestClient(app)
file_payload = BytesIO(b"png")
file_payload.name = "demo.png"
try:
response = client.post(
"/api/v1/agent/attachments",
data={"threadId": "00000000-0000-0000-0000-000000000001"},
files={"file": ("demo.png", file_payload, "image/png")},
)
assert response.status_code == 200
body = response.json()
attachment = body["attachment"]
assert attachment["mimeType"] == "image/png"
assert "00000000-0000-0000-0000-000000000001" in attachment["path"]
finally:
app.dependency_overrides = {}
def test_asr_transcribe_returns_sync_transcript(monkeypatch) -> None:
app.dependency_overrides[get_current_user] = lambda: CurrentUser(
id=uuid4(), email="user@example.com"