""" Runtime Slot API. [AC-MRS-09,10] 运行时槽位查询接口 """ import logging from datetime import datetime from typing import Annotated, Any from fastapi import APIRouter, Depends, Query from fastapi.responses import JSONResponse from sqlalchemy.ext.asyncio import AsyncSession from app.core.database import get_session from app.core.exceptions import MissingTenantIdException from app.core.tenant import get_tenant_id from app.services.mid.role_based_field_provider import RoleBasedFieldProvider, InvalidRoleError from app.services.slot_definition_service import SlotDefinitionService from app.schemas.metadata import VALID_FIELD_ROLES logger = logging.getLogger(__name__) router = APIRouter(prefix="/mid/slots", tags=["RuntimeSlot"]) def get_current_tenant_id() -> str: """Get current tenant ID from context.""" tenant_id = get_tenant_id() if not tenant_id: raise MissingTenantIdException() return tenant_id @router.get( "/by-role", operation_id="getSlotsByRole", summary="Get slots by role", description="[AC-MRS-10] 运行时接口,按角色获取槽位定义及关联的元数据字段信息", ) async def get_slots_by_role( tenant_id: Annotated[str, Depends(get_current_tenant_id)], session: Annotated[AsyncSession, Depends(get_session)], role: Annotated[str, Query( description="[AC-MRS-10] 字段角色: resource_filter/slot/prompt_var/routing_signal" )] = "slot", ) -> JSONResponse: """ [AC-MRS-10] 按角色获取槽位定义 Args: role: 字段角色,默认为 slot """ logger.info( f"[AC-MRS-10] Getting slots by role: tenant={tenant_id}, role={role}" ) provider = RoleBasedFieldProvider(session) try: slots = await provider.get_slot_definitions_by_role(tenant_id, role) except InvalidRoleError as e: return JSONResponse( status_code=400, content={ "error_code": "INVALID_ROLE", "message": str(e), "details": { "valid_roles": e.valid_roles } } ) return JSONResponse(content=slots) @router.get( "/{slot_key}", operation_id="getSlotValue", summary="Get runtime slot value", description="[AC-MRS-09] 获取指定槽位的运行时值,包含来源、置信度、更新时间", ) async def get_slot_value( tenant_id: Annotated[str, Depends(get_current_tenant_id)], session: Annotated[AsyncSession, Depends(get_session)], slot_key: str, user_id: Annotated[str | None, Query( description="用户 ID" )] = None, session_id: Annotated[str | None, Query( description="会话 ID" )] = None, ) -> JSONResponse: """ [AC-MRS-09] 获取运行时槽位值 Args: slot_key: 槽位键名 user_id: 用户 ID session_id: 会话 ID """ logger.info( f"[AC-MRS-09] Getting slot value: tenant={tenant_id}, slot_key={slot_key}, " f"user_id={user_id}, session_id={session_id}" ) service = SlotDefinitionService(session) slot_def = await service.get_slot_definition_by_key(tenant_id, slot_key) if not slot_def: return JSONResponse( status_code=404, content={ "error_code": "NOT_FOUND", "message": f"Slot '{slot_key}' not found", } ) value = slot_def.default_value source = "default" confidence = 1.0 if value is None: if slot_def.type == "string": value = "" elif slot_def.type == "number": value = 0 elif slot_def.type == "boolean": value = False elif slot_def.type in ["enum", "array_enum"]: value = [] if slot_def.type == "array_enum" else "" return JSONResponse( content={ "key": slot_key, "value": value, "source": source, "confidence": confidence, "updated_at": datetime.utcnow().isoformat(), } )