Spaces:
Sleeping
Sleeping
| """Structured action contract. | |
| The agent's only output is a typed, structured object describing a single action | |
| it wishes to take. That object is validated *locally* — before it ever reaches | |
| the governance gate — so that malformed proposals (missing fields, bad enum | |
| values, wrong types) are rejected with a clear error rather than being parsed | |
| out of free-text. The agent never executes; it only proposes. | |
| Two models live here: | |
| - :class:`ProposedAction` — the action itself (the rows of the action table). | |
| - :class:`AgentDecision` — the enclosing object the agent emits: a summary, a | |
| risk level, the proposed action, and any prohibited actions it detected while | |
| reasoning (surfaced, never acted upon). | |
| """ | |
| from __future__ import annotations | |
| from enum import Enum | |
| from typing import Any | |
| from pydantic import BaseModel, ConfigDict, Field, field_validator | |
| class AutonomyTier(str, Enum): | |
| """The four autonomy tiers.""" | |
| L0_READ_ONLY = "L0_READ_ONLY" | |
| L1_RECOMMEND_ONLY = "L1_RECOMMEND_ONLY" | |
| L2_BOUNDED_ACTION = "L2_BOUNDED_ACTION" | |
| L3_APPROVAL_REQUIRED_ACTION = "L3_APPROVAL_REQUIRED_ACTION" | |
| class Backend(str, Enum): | |
| """The four execution backends.""" | |
| DIRECT_API = "direct_api" | |
| FUNCTION_CALL = "function_call" | |
| MCP_CLIENT = "mcp_client" | |
| CLI_EXECUTOR = "cli_executor" | |
| class RiskLevel(str, Enum): | |
| """Agent-assessed risk level for the enclosing decision.""" | |
| LOW = "low" | |
| MEDIUM = "medium" | |
| HIGH = "high" | |
| CRITICAL = "critical" | |
| # Reject unknown fields and forbid coercion that would silently accept the wrong | |
| # type (e.g. an int where a string is required). `strict=True` makes Pydantic | |
| # refuse to coerce "1" -> 1 and similar, which the "wrong type" rule needs. | |
| _MODEL_CONFIG = ConfigDict(extra="forbid", strict=True) | |
| class ProposedAction(BaseModel): | |
| """A single action the agent proposes. | |
| Required string fields must be non-empty; `arguments` is a structured map and | |
| `evidence` is a list of identifiers. Validation failures raise | |
| ``pydantic.ValidationError``. | |
| """ | |
| model_config = _MODEL_CONFIG | |
| incident_id: str = Field(min_length=1, description="Incident/case identifier.") | |
| agent_id: str = Field(min_length=1, description="Identity of the proposing agent.") | |
| # `strict=False` lets the enum accept its string value (the agent emits JSON | |
| # strings); membership is still enforced, so unknown values are rejected. | |
| autonomy_tier: AutonomyTier = Field( | |
| strict=False, description="Tier the action requires." | |
| ) | |
| backend: Backend = Field(strict=False, description="Target execution path.") | |
| action_name: str = Field(min_length=1, description="Requested backend action.") | |
| arguments: dict[str, Any] = Field( | |
| default_factory=dict, description="Arguments for the action." | |
| ) | |
| reason: str = Field(min_length=1, description="Why the action is proposed.") | |
| evidence: list[str] = Field( | |
| default_factory=list, description="Supporting evidence identifiers." | |
| ) | |
| def _not_blank(cls, v: str) -> str: | |
| """Reject whitespace-only values that ``min_length`` alone would pass.""" | |
| if not v.strip(): | |
| raise ValueError("must not be empty or whitespace") | |
| return v | |
| def _evidence_ids_non_empty(cls, v: list[str]) -> list[str]: | |
| """Evidence entries are identifiers; none may be blank.""" | |
| for item in v: | |
| if not item.strip(): | |
| raise ValueError("evidence identifiers must not be empty") | |
| return v | |
| class AgentDecision(BaseModel): | |
| """The enclosing object the agent emits. | |
| Carries a human-readable summary, an assessed risk level, the proposed | |
| action, and any prohibited actions the agent detected while reasoning but did | |
| not act on. | |
| """ | |
| model_config = _MODEL_CONFIG | |
| summary: str = Field(min_length=1, description="Human-readable decision summary.") | |
| risk_level: RiskLevel = Field(strict=False, description="Assessed risk level.") | |
| proposed_action: ProposedAction = Field(description="The single proposed action.") | |
| prohibited_actions_detected: list[str] = Field( | |
| default_factory=list, | |
| description="Prohibited actions the agent detected but did not act on.", | |
| ) | |
| def _summary_not_blank(cls, v: str) -> str: | |
| if not v.strip(): | |
| raise ValueError("summary must not be empty or whitespace") | |
| return v | |