| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566 |
- """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,
- )
|