Skip to content

feat: add HITL approval gateway for production ADK agent workflows#110

Draft
garythomasgeorge wants to merge 2 commits intogoogle:mainfrom
garythomasgeorge:feat/hitl-approval-gateway
Draft

feat: add HITL approval gateway for production ADK agent workflows#110
garythomasgeorge wants to merge 2 commits intogoogle:mainfrom
garythomasgeorge:feat/hitl-approval-gateway

Conversation

@garythomasgeorge
Copy link

@garythomasgeorge garythomasgeorge commented Mar 24, 2026

Summary

Closes #111
Adds a production-ready Human-in-the-Loop approval gateway for Google ADK agents. This addresses a documented gap where ADK's built-in Tool Confirmation feature explicitly does not support DatabaseSessionService or VertexAiSessionService — the two session backends required for production deployments — making structured human oversight unavailable in any persistent production environment.

Problem

ADK's Tool Confirmation (v1.14.0+) is experimental and has three blockers for production use:

  1. Does not support DatabaseSessionService or VertexAiSessionService
  2. Does not trigger inside AgentTool or across A2A boundaries
  3. No structured approval UI, audit trail, or persistence layer

Validated by community issues: #1797, #1851, #2645, #3276, #3567 on google/adk-python.

Solution

A session-agnostic HITL approval gateway that manages approval state in its own persistence layer (SQLite, with a documented path to Postgres), independent of ADK's session service. The agent resumes via ADK's standard REST API after a human decision is submitted.

What's included

Core module (src/google/adk_community/tools/hitl/)

  • gateway.pyhitl_tool decorator that wraps any async function before it is passed to FunctionTool. Adding HITL to an existing tool takes ~5 lines.
  • models.pyApprovalRequest Pydantic model, normalised data contract capturing agent context, payload, risk level, and audit metadata
  • adapters/adk1.py — ADK 1.x adapter translating request_confirmation() events into ApprovalRequest objects

Service (src/google/adk_community/services/hitl_approval/)

  • api.py — FastAPI application
  • routes.py — REST endpoints for approval queue management
  • store.py — SQLite persistence with full audit log

Sample (contributing/samples/hitl_approval/)

  • credit_agent/agent.py — Credit approval agent demonstrating end-to-end integration
  • dashboard/app.py — Reference Streamlit approval inbox UI
  • start_servers.sh — One-command startup for all three services
  • requirements.txt — Sample-only dependencies

Architecture

ADK Agent Pipeline
      ↓
@hitl_tool decorator (wraps async function → FunctionTool)
      ↓ POST /approvals/ — creates ApprovalRequest
FastAPI + SQLite (approval state)
      ↓ serves pending approvals
Streamlit Dashboard (reviewer decides)
      ↓ POST /approvals/{id}/decide
FastAPI updates status in SQLite
      ↓ decorator polls GET /approvals/{id} every 2 s
Agent resumes execution (wrapper unblocks; runs tool if approved)

Forward compatibility

Built with an adapter pattern so the same approval backend and dashboard work with ADK 1.x today and ADK 2.0's RequestInput pattern when it reaches stable — without teams needing to rebuild their approval layer on upgrade.

Testing

Unit tests

All 11 tests passing:

============================= test session starts =============================
platform darwin -- Python 3.11.15, pytest-9.0.2, pluggy-1.6.0
rootdir: /Users/garythomasgeorge/Desktop/Work/AI Dev/adk-python-community
configfile: pyproject.toml
plugins: anyio-4.12.1, asyncio-1.3.0
asyncio: mode=Mode.AUTO, debug=False, asyncio_default_fixture_loop_scope=function, asyncio_default_test_loop_scope=function
collected 11 items                                                                  

tests/unittests/tools/test_hitl_gateway.py ......                             [ 54%]
tests/unittests/services/test_hitl_approval_api.py .....                      [100%]

================================ 11 passed in 1.76s =================================
Exit code: 0

Manual E2E

Full end-to-end flow verified:

  • Agent triggers approval request → appears in Streamlit dashboard ✓
  • Reviewer approves in dashboard → agent resumes correctly ✓
  • Uvicorn restart → SQLite persists previous approvals ✓
ADK_HITL.Demo.webm

Testing plan

For reviewers wanting to reproduce locally:

cd contributing/samples/hitl_approval
uv pip install -r requirements.txt
./start_servers.sh

Then open:

  • ADK Dev UI: http://localhost:8080
  • Streamlit dashboard: http://localhost:8501
  • FastAPI docs: http://localhost:8000/docs

Trigger an approval by asking the credit agent to process an amount over $500.

Notes for reviewers

  • Opening as Draft — happy to address structural feedback before requesting full review
  • ADK 2.0 adapter (adapters/adk2.py) is planned as a follow-up PR once 2.0 moves toward stable
  • Confirmed structure placement from proposal issue: tools/hitl for the gateway and models, services/hitl_approval for the FastAPI backend — let me know if you'd prefer a different organisation

Related

- Add ADK 1.x adapter and data models
- Add FastAPI backend and SQLite state management routes
- Add Streamlit dashboard UI for human reviewers
- Add sample credit_agent showcasing the full @hitl_tool integration
- Fully formatted under pyink and isort conventions
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Proposal: Production-Ready Human-In-The-Loop (HITL) Gateway

1 participant