google_adk_agents: graph workflows, dynamic workflows, and durable HITL (ADK v2)#1675
Draft
DABH wants to merge 4 commits into
Draft
google_adk_agents: graph workflows, dynamic workflows, and durable HITL (ADK v2)#1675DABH wants to merge 4 commits into
DABH wants to merge 4 commits into
Conversation
Graph/dynamic workflow support relies on Workflow-as-Tool (added in ADK 2.4.0) and HITL resumption for standalone nodes and NodeTool plus related resumable-mode hardening (added in ADK 2.5.0). Existing contrib tests pass unchanged against 2.5.0. The exclude-newer-package exemption can be removed once 2.5.0 (published 2026-07-16) passes the two-week cooldown.
…K v2 - activity_node() wraps a Temporal activity as an ADK FunctionNode for use in Workflow graphs and dynamic ctx.run_node() calls. - HITL helpers (HitlRequest, pending_hitl_requests, hitl_input_response, hitl_confirmation_response) cover ADK's pause/resume wire format so workflows can durably wait on human input via signals/updates. - setup_deterministic_runtime() additionally installs a workflow.random()- backed provider on ADK versions exposing the platform random seam. - README sections for graph workflows, dynamic workflows, durable HITL, and determinism notes.
ADK holds its platform time/uuid/random providers in ContextVars, and the public set_*_provider helpers only affect the calling context. Temporal executes workflow code on executor threads whose contexts never see the run_context call, so the deterministic providers were previously never active inside workflows: event/function-call ids came from stdlib uuid4 and Event timestamps from wall-clock time. This went unnoticed because Temporal replay compares command sequences, not payloads — but any flow whose control depends on a generated id (HITL resume matching recorded responses by interrupt/function-call id) diverged on replay and hung. Rebind each platform module's ContextVar with the deterministic provider as its default. Context-local set_*_provider calls still override it, and the providers fall back to real primitives outside workflows.
- Graph: sequential/conditional-routing/parallel-join graphs with activity-backed nodes, LlmAgent node through the invoke_model activity, node timeout (durable timer), ADK RetryConfig retry, and a seam-gated jittered-retry replay test. All run with max_cached_workflows=0 so every workflow task fully replays. - Dynamic: ctx.run_node loops and asyncio.gather fan-out, Workflow-as-Tool, and HITL resume proving completed activity children are served from the session cache (exactly one real execution). - HITL: human-input node resume via query + update, activity_tool behind FunctionTool(require_confirmation=True) with the gated activity running exactly once on approval and never on rejection (replay-proven via forced eviction), multiple pending requests with partial responses, and a seam-gated default-interrupt-id replay test. - Replay: recorded graph_workflow.json and hitl_workflow.json histories added to the replay regression test. Tests marked seam-gated skip on google-adk releases that predate the upstream platform-seam routing (google/adk-python PR) and run against a build that includes it.
DABH
force-pushed
the
google-adk-v2-graph-hitl
branch
from
July 24, 2026 23:15
3d4be86 to
697e407
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What was changed
Adds ADK Python v2 feature support to
temporalio.contrib.google_adk_agents(JIRA AI-303: graph workflows, dynamic workflows, and human-in-the-loop):activity_node(activity_def, *, name=None, rerun_on_resume=False, **activity_config)(in.workflow, sibling ofactivity_tool) — wraps a Temporal activity as an ADKFunctionNodefor use inWorkflow(edges=[...])graphs and dynamicctx.run_node(...)calls. Single-param activities receive the upstream node's output directly; multi-param activities bind by name from a dict; local ADK runs call the function directly.HitlRequest,pending_hitl_requests(event),hitl_input_response(...),hitl_confirmation_response(...)— cover ADK's pause/resume wire format (adk_request_input/adk_request_confirmationfunction calls answered byFunctionResponses) so a workflow can expose pending requests via a query, wait durably on a signal/update, and resume the runner. Tool confirmation composes withactivity_tool:FunctionTool(func=activity_tool(fn, ...), require_confirmation=True)never schedules the activity until a human approves.ContextVars; workflow code runs on executor threads whose contexts never saw the plugin'sset_*_providercalls, so generated ids were stdlibuuid4andEventtimestamps wall-clock all along (masked because replay compares command sequences, not payloads — HITL makes it fatal since resume matches recorded responses by generated id).setup_deterministic_runtime()now installs the providers as ContextVar defaults, and additionally installs aworkflow.random()-backed provider on ADK builds that expose the new random seam.>=2.5.0,<3(Workflow-as-Tool needs ≥2.4; standalone-node/NodeTool HITL resumption and resumable-mode hardening need 2.5). Theexclude-newer-packageexemption is removable after 2026-07-30.Upstream dependencies (built on the assumption they merge)
Two adk-python PRs route the remaining seam-bypassing call sites through
google.adk.platform:RequestInput.interrupt_id,_ToolNode.function_call_id, retry jitter (adds the platform random seam)_ParallelWorkerTwo tests are seam-gated: they skip on stock 2.5.0 and pass against a build containing #6468 (verified locally via a branch install). Before merge, the floor should bump to the first ADK release containing them.
Why
ADK v2 (2.0–2.5) rebuilt the framework around a graph runtime; the integration predates it. The graph engine is pure-asyncio and session-event-driven, so it runs deterministically inside workflows with the existing activity seams (
TemporalModel, MCP,activity_tool) intercepting unchanged — this PR adds the node-level helper, the HITL mapping, tests proving replay safety, and the provider fix that HITL surfaced.Checklist
tests/contrib/google_adk_agents/(graph sequential/routing/parallel-join/agent-node/timeout/retry; dynamic loop/gather/Workflow-as-Tool/resume-with-exactly-once-activity; HITL input-node resume via update, confirmation approve/reject with activity-execution counting, multi-pending partial responses) — run withmax_cached_workflows=0so every workflow task fully replays; 2 new recorded replay histories; full suite green on stock 2.5.0 (35 passed, 7 skipped incl. 2 seam-gated + 5 pre-existing) and on the #6468 branch (37 passed); pyright/mypy/ruff/pydocstyle clean.