from afk.agents import Agent, PolicyEngine, PolicyRule, FailSafeConfig
from afk.core import Runner, RunnerConfig
# Define policy rules that distinguish read vs write operations
policy = PolicyEngine(rules=[
PolicyRule(
rule_id="gate-delete",
description="Require approval for delete operations",
condition=lambda event: event.tool_name == "delete_resource",
action="request_approval",
reason="Delete operations are irreversible and require human approval.",
),
PolicyRule(
rule_id="deny-unknown-tools",
description="Deny any tool not explicitly registered",
condition=lambda event: (
event.tool_name is not None
and event.tool_name not in {"get_resource", "delete_resource"}
),
action="deny",
reason="Unregistered tools are not permitted.",
),
])
agent = Agent(
name="resource-manager",
model="gpt-5.2-mini",
instructions="Manage resources using the available tools. Always look up a resource before modifying it.",
tools=[get_resource, delete_resource],
fail_safe=FailSafeConfig(
max_tool_calls=10,
max_total_cost_usd=0.10,
),
)
runner = Runner(
policy_engine=policy,
config=RunnerConfig(
interaction_mode="headless",
approval_fallback="deny", # Auto-deny destructive actions in headless mode
sanitize_tool_output=True, # Wrap tool output in untrusted-data markers
),
)
result = runner.run_sync(agent, user_message="Delete resource res-123")
print(f"State: {result.state}")
# In headless mode, the delete is auto-denied. The model sees the denial and responds accordingly.