import asyncio
from timbal import Agent, Tool
from timbal.types.approval import ApprovalResolution
from timbal.types.events import ApprovalEvent
def refund_customer(amount: int, customer_id: str) -> str:
return f"refunded ${amount} to {customer_id}"
refund = Tool(
handler=refund_customer,
requires_approval=lambda amount, **_: amount > 100,
approval_prompt=lambda amount, customer_id: (
f"Approve refunding ${amount} to {customer_id}?"
),
approval_redact_keys=["customer_id"],
)
agent = Agent(
name="support_agent",
model="openai/gpt-5",
tools=[refund],
)
async def main() -> None:
# First call — agent will try to refund and pause for approval.
pending: list[ApprovalEvent] = []
async for event in agent(prompt="Refund $250 to customer C-42"):
if isinstance(event, ApprovalEvent):
pending.append(event)
# Show the reviewer the redacted prompt + input.
for event in pending:
print(event.prompt, event.input)
# event.input["customer_id"] == "***" (redacted)
# Second call — resume with the reviewer's decision.
decisions = {
event.approval_id: ApprovalResolution(
approved=True,
approver_id="user_42",
comment="Verified invoice and customer history.",
)
for event in pending
}
result = await agent(
prompt="Refund $250 to customer C-42",
approval_decisions=decisions,
).collect()
print(result.output.collect_text())
# Refund executed, agent reports success.
asyncio.run(main())