All checks were successful
CI / test (pull_request) Successful in 3m55s
4.1 新增三个评估场景(急诊分诊、慢病管理、健康咨询),各 3 个用例,
全部使用无模型绑定依赖的规则;急诊场景编码 <20s 延迟验收标准
4.2 ModelGateway 由每次请求新建 httpx.AsyncClient 改为单实例共享客户端
(复用 TCP/TLS 连接),引擎与模型连通性测试端点负责关闭;
tutu 通道已具备同等优化,无需改动
4.3 Reports.tsx 单次报告顶部新增上线评估横幅:go/no-go/conditional
三态 banner + 各验收标准达标情况标签
版本号升至 1.3.1(v1.3.1-final)。
门禁:pytest tests/unit 709 passed;ruff 全绿;
前端 tsc --noEmit + vitest 232 passed。
附带修复 RunList 测试时区缺陷:started_at 用 UTC 日期构造,
本地 00:00-08:00 之间会被默认"今天"过滤器排除导致误报失败。
129 lines
4.5 KiB
Python
129 lines
4.5 KiB
Python
"""API routes for centralized model configurations."""
|
|
|
|
from datetime import datetime, timezone
|
|
|
|
from fastapi import APIRouter, Depends, HTTPException, Query
|
|
from sqlmodel import Session
|
|
|
|
from agenteval.model_gateway import ModelGateway, ModelGatewayError
|
|
from agenteval.models import ModelCapability
|
|
from agenteval.services.model_configs import (
|
|
ModelConfigError,
|
|
ModelConfigInUseError,
|
|
ModelConfigNotFoundError,
|
|
ModelConfigService,
|
|
)
|
|
from agenteval.storage.db import ScenarioDB
|
|
from agenteval.web.deps import get_db
|
|
from agenteval.web.model_config_schemas import (
|
|
ModelConfigCreate,
|
|
ModelConfigReference,
|
|
ModelConfigResponse,
|
|
ModelConfigUpdate,
|
|
ModelConnectionTestResponse,
|
|
)
|
|
|
|
router = APIRouter()
|
|
|
|
|
|
def _http_error(exc: ModelConfigError) -> HTTPException:
|
|
if isinstance(exc, ModelConfigNotFoundError):
|
|
return HTTPException(status_code=404, detail=str(exc))
|
|
if isinstance(exc, ModelConfigInUseError):
|
|
return HTTPException(status_code=409, detail=str(exc))
|
|
return HTTPException(status_code=400, detail=str(exc))
|
|
|
|
|
|
@router.get("", response_model=list[ModelConfigResponse])
|
|
def list_model_configs(
|
|
capability: ModelCapability | None = Query(default=None),
|
|
enabled: bool | None = Query(default=None),
|
|
session: Session = Depends(get_db),
|
|
) -> list[ModelConfigResponse]:
|
|
configs = ModelConfigService(session).repo.list_all(
|
|
capability=capability.value if capability else None,
|
|
enabled=enabled,
|
|
)
|
|
return [ModelConfigResponse.from_db(config) for config in configs]
|
|
|
|
|
|
@router.post("", response_model=ModelConfigResponse)
|
|
def create_model_config(payload: ModelConfigCreate, session: Session = Depends(get_db)) -> ModelConfigResponse:
|
|
try:
|
|
config = ModelConfigService(session).create(**payload.model_dump(mode="json"))
|
|
except ModelConfigError as exc:
|
|
raise _http_error(exc) from exc
|
|
return ModelConfigResponse.from_db(config)
|
|
|
|
|
|
@router.get("/{config_id}", response_model=ModelConfigResponse)
|
|
def get_model_config(config_id: str, session: Session = Depends(get_db)) -> ModelConfigResponse:
|
|
try:
|
|
config = ModelConfigService(session).require(config_id)
|
|
except ModelConfigError as exc:
|
|
raise _http_error(exc) from exc
|
|
return ModelConfigResponse.from_db(config)
|
|
|
|
|
|
@router.put("/{config_id}", response_model=ModelConfigResponse)
|
|
def update_model_config(
|
|
config_id: str,
|
|
payload: ModelConfigUpdate,
|
|
session: Session = Depends(get_db),
|
|
) -> ModelConfigResponse:
|
|
try:
|
|
config = ModelConfigService(session).update(config_id, **payload.model_dump(mode="json"))
|
|
except ModelConfigError as exc:
|
|
raise _http_error(exc) from exc
|
|
return ModelConfigResponse.from_db(config)
|
|
|
|
|
|
@router.delete("/{config_id}")
|
|
def delete_model_config(config_id: str, session: Session = Depends(get_db)) -> dict[str, bool]:
|
|
try:
|
|
ModelConfigService(session).delete(config_id)
|
|
except ModelConfigError as exc:
|
|
raise _http_error(exc) from exc
|
|
return {"ok": True}
|
|
|
|
|
|
@router.get("/{config_id}/references", response_model=list[ModelConfigReference])
|
|
def list_model_config_references(
|
|
config_id: str,
|
|
session: Session = Depends(get_db),
|
|
) -> list[ModelConfigReference]:
|
|
service = ModelConfigService(session)
|
|
try:
|
|
service.require(config_id)
|
|
except ModelConfigError as exc:
|
|
raise _http_error(exc) from exc
|
|
references = []
|
|
for binding in service.repo.list_references(config_id):
|
|
scenario = session.get(ScenarioDB, binding.scenario_id)
|
|
references.append(
|
|
ModelConfigReference(
|
|
scenario_id=binding.scenario_id,
|
|
scenario_name=scenario.name if scenario else binding.scenario_id,
|
|
purpose=binding.purpose,
|
|
)
|
|
)
|
|
return references
|
|
|
|
|
|
@router.post("/{config_id}/test", response_model=ModelConnectionTestResponse)
|
|
async def test_model_config(
|
|
config_id: str,
|
|
session: Session = Depends(get_db),
|
|
) -> ModelConnectionTestResponse:
|
|
gateway = ModelGateway()
|
|
try:
|
|
runtime = ModelConfigService(session).resolve(config_id)
|
|
message = await gateway.test_connection(runtime)
|
|
except ModelConfigError as exc:
|
|
raise _http_error(exc) from exc
|
|
except ModelGatewayError as exc:
|
|
return ModelConnectionTestResponse(ok=False, message=str(exc), tested_at=datetime.now(timezone.utc))
|
|
finally:
|
|
await gateway.close()
|
|
return ModelConnectionTestResponse(ok=True, message=message, tested_at=datetime.now(timezone.utc))
|