← Selected work
Case study / AI Agents · Deterministic Controls

Banking Agent Harness

A banking simulation that puts policy checks, a separate confirmation turn, and execution verification between an AI agent and a mock ledger.

Problem & context

Explore how a conversational banking agent can propose transfers while deterministic Python tools control validation, explicit confirmation, and simulated transaction outcomes.

My contribution

ADK integration, deterministic transfer policy and confirmation state, mock transaction execution, usage budgets, and redacted audit events.

Deterministic policy replay Executed locally · synthetic ledger
  1. Initiate synthetic transfer{"account_last4": "5678", "amount": 1000, "beneficiary_name": "Aaron Johnson", "status": "PENDING_CONFIRMATION"}
  2. Later user turn: confirm{"amount": 1000, "beneficiary_name": "Aaron Johnson", "new_balance": 199000.0, "status": "SUCCESS", "transaction_id": "TXN001"}
  3. Repeat confirmation{"reason": "There is no pending transfer to confirm.", "status": "NO_PENDING_TRANSFER"}

Mock transaction succeeds once; balance changes from 200000 to 199000. This is an in-memory simulation, with no bank connection.

How this was checked

Executed unchanged deterministic banking tool/service source with synthetic in-memory accounts and mocked SUCCESS executor setting. ADK/provider startup and .env loading were omitted; ToolContext is a lightweight fixture and approval lifetime is the code default of 24 hours. This verifies these function paths only, not model behavior, live banking, production concurrency, or cross-process state.

Inspect recorded output ↗
Product evidence

Inspect the workflow.

Local deterministic harness output with synthetic accounts. No real funds, bank integration, or provider call.

Failure path: The agent attempts confirmation during the original invocation, without a matching staged session proposal, or after deterministic validation rejects the request.

The tool returns an explicit confirmation-required, no-pending-transfer, or rejected status. The executed rejection and confirmation checks leave the mock balance unchanged; policy is revalidated again before execution.

An engineering decision.

confirm_transfer reads the actual staged record, invocation identifier, and user text, then revalidates current policy. The execution gate can be inspected and tested independently of model responses.

Implemented approach

Stage a validated transfer in session state and require an allowlisted confirmation in a later invocation before executing it.

Alternative & tradeoff

Rely on a system-prompt instruction or a model-supplied skip-confirmation flag.

Follow the system.

Contract / Model-selected tool → structured intent

Technical detail / Tool arguments describe a requested action, not permission

A local banking simulation, with deterministic controls around model-selected tools.

Recovery / stateChanged transfer details invalidate pending confirmation; execution results are checked against the mock ledger.

Verified behavior & limitations.

What the evidence establishes

  • Executed locally: initiating a valid synthetic request leaves the mock balance unchanged; explicit confirmation in a later invocation produces SUCCESS and updates the mock balance from 200000 to 199000.
  • Executed locally: repeat confirmation returns NO_PENDING_TRANSFER; confirmation within the initiating invocation returns CONFIRMATION_REQUIRED.
  • Executed locally: a blocked mock beneficiary returns REJECTED with unchanged balance, and a separate session cannot confirm the first session's proposal.
  • Source review: amount validation checks finite positive values and decimal precision, confirmation rechecks current balance/policy, and SUCCESS/PENDING/FAILED outcomes come from a separate mock executor.

Boundaries & remaining work

  • This is an in-memory banking simulation. No real accounts, banking API, payment rail, or durable transaction ledger are connected.
  • The executed scenarios call real deterministic functions with a synthetic ToolContext fixture. They do not verify an LLM conversation, ADK browser flow, Upstash quota integration, or live provider availability.
  • Pending approvals use session state, while mock accounts and transactions are process-local. Cross-process persistence and production concurrency are outside the verified behavior.

Inspect the source.

References are pinned to the reviewed revision. Public sample screens demonstrate the interface with fixtures; source review and executed checks are labelled separately.

Ask Harsh’s AI

Explore Harsh’s work, with sources.

A useful place to start

What would you like
to know?

I can help you explore Harsh’s projects, experience, and skills. You can also paste a short job description to discuss the fit.