refactor: unify skills+cli runtime and streamline ag-ui flow

This commit is contained in:
qzl
2026-04-22 17:09:37 +08:00
parent eeed737949
commit 4d55df45ab
111 changed files with 4858 additions and 3264 deletions
@@ -38,12 +38,12 @@ async def test_attachment_storage_rejects_unexpected_bucket(
storage = SupabaseService()
monkeypatch.setattr(
app_config.storage,
app_config.storage.attachment,
"bucket",
"allowed-bucket",
)
with pytest.raises(RuntimeError, match="Invalid attachment bucket"):
with pytest.raises(RuntimeError, match="Invalid storage bucket"):
await storage.upload_bytes(
bucket="other-bucket",
path="agent-inputs/u/t/r/file.png",
@@ -62,7 +62,7 @@ async def test_attachment_storage_accepts_configured_bucket(
fake_bucket = _FakeBucket()
fake_client = SimpleNamespace(storage=_FakeStorage(fake_bucket))
monkeypatch.setattr(
app_config.storage,
app_config.storage.attachment,
"bucket",
"allowed-bucket",
)
@@ -3,7 +3,7 @@ from __future__ import annotations
from uuid import uuid4
import pytest
from fastapi import HTTPException
from core.http.errors import ApiProblemError
from core.auth.models import CurrentUser
from v1.agent.service import ensure_session_owner
@@ -12,5 +12,5 @@ from v1.agent.service import ensure_session_owner
def test_owner_guard_denies_non_owner() -> None:
user = CurrentUser(id=uuid4(), phone="self@example.com")
with pytest.raises(HTTPException):
with pytest.raises(ApiProblemError):
ensure_session_owner(owner_id="other-user", current_user=user)
+17 -19
View File
@@ -6,10 +6,10 @@ from urllib.parse import quote
from uuid import UUID
from ag_ui.core import RunAgentInput
from fastapi import HTTPException
import pytest
import v1.agent.service as agent_service_module
from core.http.errors import ApiProblemError
from core.auth.models import CurrentUser
from core.config.settings import config
from schemas.domain.chat_message import AgentChatMessageMetadata
@@ -25,7 +25,7 @@ class _FakeRepository:
async def get_session_owner(self, *, session_id: str) -> str:
if session_id == "00000000-0000-0000-0000-000000000001":
return "00000000-0000-0000-0000-000000000001"
raise HTTPException(status_code=404, detail="Session not found")
raise ApiProblemError(status_code=404, detail="Session not found")
async def create_session_for_user(
self, *, user_id: str, session_id: str | None = None
@@ -92,7 +92,7 @@ class _FakeRepository:
"timeout_seconds": 30,
"visibility_consumer_bit": bit,
"context_messages": {"mode": "number", "count": 20},
"enabled_tools": [],
"enabled_skills": [],
},
}
@@ -201,7 +201,7 @@ def _build_run_input(*, urls: list[str], runtime_mode: str = "chat") -> RunAgent
@pytest.mark.asyncio
async def test_enqueue_run_rejects_non_project_host_signed_url(monkeypatch) -> None:
monkeypatch.setattr(
agent_service_module.config.storage, "bucket", "agent-test-bucket"
agent_service_module.config.storage.attachment, "bucket", "agent-test-bucket"
)
service = AgentService(
repository=_FakeRepository(),
@@ -215,11 +215,11 @@ async def test_enqueue_run_rejects_non_project_host_signed_url(monkeypatch) -> N
]
)
with pytest.raises(HTTPException) as exc_info:
with pytest.raises(ApiProblemError) as exc_info:
await service.enqueue_run(run_input=run_input, current_user=_user())
assert exc_info.value.status_code == 422
assert exc_info.value.detail == "INVALID_BINARY_URL_HOST"
assert exc_info.value.detail == "Invalid binary url host"
@pytest.mark.asyncio
@@ -227,7 +227,7 @@ async def test_enqueue_run_persists_attachment_and_queue_without_user_token(
monkeypatch,
) -> None:
monkeypatch.setattr(
agent_service_module.config.storage, "bucket", "agent-test-bucket"
agent_service_module.config.storage.attachment, "bucket", "agent-test-bucket"
)
repository = _FakeRepository()
queue = _FakeQueue()
@@ -274,7 +274,7 @@ async def test_enqueue_run_persists_attachment_and_queue_without_user_token(
@pytest.mark.asyncio
async def test_enqueue_run_rejects_unknown_agent_type(monkeypatch) -> None:
monkeypatch.setattr(
agent_service_module.config.storage, "bucket", "agent-test-bucket"
agent_service_module.config.storage.attachment, "bucket", "agent-test-bucket"
)
service = AgentService(
repository=_FakeRepository(),
@@ -294,7 +294,7 @@ async def test_enqueue_run_rejects_unknown_agent_type(monkeypatch) -> None:
runtime_mode="planner",
)
with pytest.raises(HTTPException) as exc_info:
with pytest.raises(ApiProblemError) as exc_info:
await service.enqueue_run(run_input=run_input, current_user=_user())
assert exc_info.value.status_code == 422
@@ -303,7 +303,7 @@ async def test_enqueue_run_rejects_unknown_agent_type(monkeypatch) -> None:
@pytest.mark.asyncio
async def test_enqueue_run_rejects_invalid_runtime_mode(monkeypatch) -> None:
monkeypatch.setattr(
agent_service_module.config.storage, "bucket", "agent-test-bucket"
agent_service_module.config.storage.attachment, "bucket", "agent-test-bucket"
)
repository = _FakeRepository()
service = AgentService(
@@ -314,7 +314,7 @@ async def test_enqueue_run_rejects_invalid_runtime_mode(monkeypatch) -> None:
)
run_input = _build_run_input(urls=[], runtime_mode="planner")
with pytest.raises(HTTPException) as exc_info:
with pytest.raises(ApiProblemError) as exc_info:
await service.enqueue_run(run_input=run_input, current_user=_user())
assert exc_info.value.status_code == 422
@@ -324,7 +324,7 @@ async def test_enqueue_run_rejects_invalid_runtime_mode(monkeypatch) -> None:
@pytest.mark.asyncio
async def test_create_attachment_signed_url_returns_url(monkeypatch) -> None:
monkeypatch.setattr(
agent_service_module.config.storage, "bucket", "agent-test-bucket"
agent_service_module.config.storage.attachment, "bucket", "agent-test-bucket"
)
service = AgentService(
repository=_FakeRepository(),
@@ -349,7 +349,7 @@ async def test_create_attachment_signed_url_rejects_out_of_scope_path(
monkeypatch,
) -> None:
monkeypatch.setattr(
agent_service_module.config.storage, "bucket", "agent-test-bucket"
agent_service_module.config.storage.attachment, "bucket", "agent-test-bucket"
)
service = AgentService(
repository=_FakeRepository(),
@@ -358,7 +358,7 @@ async def test_create_attachment_signed_url_rejects_out_of_scope_path(
attachment_storage=_FakeAttachmentStorage(),
)
with pytest.raises(HTTPException) as exc_info:
with pytest.raises(ApiProblemError) as exc_info:
await service.create_attachment_signed_url(
bucket="agent-test-bucket",
path="agent-inputs/other-user/thread-x/uploads/a.png",
@@ -371,7 +371,7 @@ async def test_create_attachment_signed_url_rejects_out_of_scope_path(
@pytest.mark.asyncio
async def test_enqueue_run_rejects_too_many_attachments(monkeypatch) -> None:
monkeypatch.setattr(
agent_service_module.config.storage, "bucket", "agent-test-bucket"
agent_service_module.config.storage.attachment, "bucket", "agent-test-bucket"
)
service = AgentService(
repository=_FakeRepository(),
@@ -405,7 +405,7 @@ async def test_enqueue_run_rejects_too_many_attachments(monkeypatch) -> None:
]
)
with pytest.raises(HTTPException) as exc_info:
with pytest.raises(ApiProblemError) as exc_info:
await service.enqueue_run(run_input=run_input, current_user=_user())
assert exc_info.value.status_code == 422
@@ -461,8 +461,6 @@ async def test_get_history_snapshot_filters_out_tool_messages() -> None:
"agent_output": {
"status": "success",
"answer": "今天共有 3 条日程。",
"key_points": [],
"result_type": "summary",
"suggested_actions": [],
},
},
@@ -529,7 +527,7 @@ async def test_cancel_run_rejects_non_owner() -> None:
phone="+8613812340000",
)
with pytest.raises(HTTPException) as exc_info:
with pytest.raises(ApiProblemError) as exc_info:
await service.cancel_run(
thread_id="00000000-0000-0000-0000-000000000001",
run_id="run-cancel-2",
+2 -3
View File
@@ -30,7 +30,7 @@ def test_convert_message_to_history_does_not_attach_ui_schema_for_tool_message()
assert "uiSchema" not in result
def test_convert_message_to_history_uses_ui_schema_key_for_assistant_message() -> None:
def test_convert_message_to_history_does_not_attach_ui_schema_for_assistant_message() -> None:
message = _FakeMessage(
role="assistant",
metadata={
@@ -40,9 +40,8 @@ def test_convert_message_to_history_uses_ui_schema_key_for_assistant_message() -
result = convert_message_to_history(message) # type: ignore[arg-type]
assert "ui_schema" in result
assert "ui_schema" not in result
assert "uiSchema" not in result
assert result["ui_schema"] == {"version": "2.0", "root": {"type": "stack"}}
def test_convert_message_to_history_returns_multiple_user_attachments() -> None: