File size: 2,429 Bytes
5a46e5d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
"""In-memory-only BarunAction simulator; no tool handler or network access exists here."""

from __future__ import annotations

from dataclasses import dataclass
from typing import Any

from barunlm.evaluation.action_ir import ActionIR, Decision

from .inference import assess_policy
from .schema import ToolDeclaration

SIMULATOR_SCHEMA_VERSION = "barunaction-sandbox-simulator-v1"


@dataclass(frozen=True, slots=True)
class SimulationResult:
    status: str
    blocked_reasons: tuple[str, ...]
    simulated_calls: tuple[dict[str, Any], ...]
    external_side_effects: bool = False

    def to_dict(self) -> dict[str, Any]:
        return {
            "blocked_reasons": list(self.blocked_reasons),
            "external_side_effects": self.external_side_effects,
            "schema_version": SIMULATOR_SCHEMA_VERSION,
            "simulated_calls": list(self.simulated_calls),
            "status": self.status,
        }


def simulate_action(
    action: ActionIR,
    *,
    declarations: tuple[ToolDeclaration, ...],
    externally_authorized: bool = False,
    externally_confirmed: bool = False,
) -> SimulationResult:
    """Apply an action only to a returned in-memory log after explicit external gates."""

    if type(externally_authorized) is not bool or type(externally_confirmed) is not bool:
        raise TypeError("sandbox gate values must be bool")
    registry = {item.schema.name: item.schema for item in declarations}
    policy = assess_policy(action, registry)
    if action.decision not in (Decision.CALL, Decision.CONFIRM):
        return SimulationResult(
            status="no_calls_proposed",
            blocked_reasons=(f"decision_{action.decision.value.lower()}",),
            simulated_calls=(),
        )
    blocked: list[str] = []
    if policy.authorization_required and not externally_authorized:
        blocked.append("external_authorization_missing")
    if policy.confirmation_required and not externally_confirmed:
        blocked.append("external_confirmation_missing")
    if blocked:
        return SimulationResult(
            status="blocked",
            blocked_reasons=tuple(blocked),
            simulated_calls=(),
        )
    return SimulationResult(
        status="simulated",
        blocked_reasons=(),
        simulated_calls=tuple(call.to_dict() for call in action.calls),
    )


__all__ = ["SIMULATOR_SCHEMA_VERSION", "SimulationResult", "simulate_action"]