Run the acceptance suite
Save both files in the same empty directory. Python 3.10 or later is sufficient for offline tests; SQLite is included. The workflow uses a fictional USD 25 order and never transfers money. The tests exercise application behavior with a simulated API adapter, not model quality or live account access.
python -m unittest -v test_refund_workflow.py
# Expected: 9 tests, OK. Each test uses an isolated temporary database.Follow the responsibility boundaries
The model can request an order ID, but cannot supply the owner, amount, approval decision, or operation key. The order lookup returns the server-owned refund policy. An approval binds the owner, order, exact amount, and operation. Only an explicit operator decision changes pending to approved or denied.
Connect a managed session
Live execution requires Agents API access, an accessible model, the OpenAI Python SDK, and OPENAI_API_KEY in your local environment. It uses API credits. In a local Python shell, import the downloaded module and create a session with its two tools. Copy and bind the returned session ID immediately. If creation fails without returning an ID, inspect your account before creating another session.
# pip install --upgrade openai
# Set OPENAI_API_KEY and OPENAI_MODEL in your environment.
import os
from openai import OpenAI
from refund_workflow import TOOLS, Workflow
with OpenAI(max_retries=0, timeout=30.0) as client:
session = client.beta.agents.sessions.create(
agent={'model': os.environ['OPENAI_MODEL'], 'tools': TOOLS,
'instructions': 'Look up the order and policy before requesting a refund. Report tool errors accurately.'},
environment={'type': 'none'},
input='Look up ORDER-100 and request its full fictional refund.',
stream=False,
)
print(session.id)
workflow = Workflow('refund-demo.sqlite')
try:
workflow.bind(session.id, 'demo-user')
finally:
workflow.close()Approve and resume the same work
Run recover with the saved session ID to inspect current required actions and submit available results. Repeat when the harness requests another tool; this command is one inspection pass, not a background worker. A refund stays pending until you inspect its exact proposal and approve or deny it. Restarting the command preserves the SQLite ledger. A network error is not permission to delete that ledger or start a new session.
python refund_workflow.py --session SESSION_ID recover
python refund_workflow.py --session SESSION_ID pending
# Inspect owner, order_id and amount before deciding.
python refund_workflow.py --session SESSION_ID approve --operation demo-user:ORDER-100:full-refund:v1
# Use deny instead of approve to exercise refusal.
python refund_workflow.py --session SESSION_ID recoverInspect the final outcome
Zero submitted results does not establish completion. The inspect command prints root turn statuses, paginated saved items, and the fictional refund ledger. Confirm both the agent's answer and the business result; a completed conversation may correctly report a denied refund. If the root is still queued, in_progress, or waiting, inspect again after handling its dependency.
python refund_workflow.py --session SESSION_ID inspect
# Check root status: completed, failed, or cancelled.
# Check fictional_refunds independently of the agent's answer.Evaluate the safety properties
The suite is an executable release gate for this application layer. It does not measure answer quality, latency, or API spend; run a separate representative live evaluation for those.
| Case | Required outcome |
|---|---|
| Read order and policy | Server-owned amount returned |
| No approval | No refund row |
| Denied approval | Tool failure, no refund row |
| Restart and new duplicate call ID | Same business operation, one refund row |
| Wrong owner or order | No protected order access |
| Model-supplied amount or approval | Rejected arguments |
| Wrong approver or changed decision | Rejected decision |
| Call ID reused with changed arguments | Rejected identity conflict |
| Lost result acknowledgment | Stored result and submission key reused after restart |
Apply the integration controls
Run this CLI only as a trusted local operator: demo-user and bind are not authentication. Keep the database outside a public directory. For a real service, replace operator commands with authenticated, ownership-scoped approval actions and store an audit trail. The fictional refund and result are atomic because they share SQLite; an external payment requires provider-side idempotency, reconciliation, and an outbox. Do not claim exactly-once external execution from a local transaction. Webhook ingestion additionally requires signature verification and durable acceptance. Preserve results before deleting sessions; release any separate compute independently.
Read the official reference
Check the source for current API fields, account requirements, and service limits.
OpenAI: functions Session event submission Session recovery