"""Tool 调用策略:人格白名单、权限和副作用边界。""" from dataclasses import dataclass from typing import Literal from app.core.errors import AppError @dataclass(frozen=True) class ToolPolicy: personas: tuple[str, ...] effect: Literal["read", "draft"] required_permissions: tuple[str, ...] = () class HarnessPolicyEngine: def can_use( self, *, persona: str, allowed_by_persona: tuple[str, ...], tool_name: str, policy: ToolPolicy, permissions: tuple[str, ...], ) -> bool: if tool_name not in allowed_by_persona or persona not in policy.personas: return False if persona == "operation" and policy.effect != "read": return False return not ( policy.required_permissions and "*" not in permissions and not set(policy.required_permissions).intersection(permissions) ) def authorize( self, *, persona: str, allowed_by_persona: tuple[str, ...], tool_name: str, policy: ToolPolicy, permissions: tuple[str, ...], ) -> None: if tool_name not in allowed_by_persona or persona not in policy.personas: raise AppError( "AGENT_TOOL_NOT_ALLOWED", f"当前Agent人格不能使用工具:{tool_name}", 403, ) if persona == "operation" and policy.effect != "read": raise AppError( "AGENT_OPERATION_READ_ONLY", "运营Agent只允许执行只读工具", 403, ) if ( policy.required_permissions and "*" not in permissions and not set(policy.required_permissions).intersection(permissions) ): raise AppError( "PERMISSION_DENIED", f"缺少工具权限:{tool_name}", 403, )