Skip to content

[AI-303] google_adk_agents: graph workflows, dynamic workflows, and durable HITL (ADK v2) - #1675

Open
DABH wants to merge 25 commits into
mainfrom
google-adk-v2-graph-hitl
Open

[AI-303] google_adk_agents: graph workflows, dynamic workflows, and durable HITL (ADK v2)#1675
DABH wants to merge 25 commits into
mainfrom
google-adk-v2-graph-hitl

Conversation

@DABH

@DABH DABH commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

What was changed

ADK v2 moved to a graph runtime. Its scheduler is plain asyncio driven by session events, so it already runs deterministically inside a workflow with TemporalModel, the MCP toolsets, and activity_as_tool intercepting as before. This PR adds the missing pieces (AI-303):

  • activity_node(...): run a Temporal activity as an ADK FunctionNode, either in a Workflow(edges=...) graph or via ctx.run_node(...).
  • HITL helpers HitlRequest, pending_hitl_requests, hitl_input_response, hitl_confirmation_response for ADK's adk_request_input / adk_request_confirmation pause-and-resume protocol (auth requests are out of scope; see the README). The durable wait itself is just workflow code: query the pending requests, wait on a signal or update, call run_async again. Works with activity_as_tool behind FunctionTool(require_confirmation=True).
  • Bug fix: the plugin's ADK time/uuid providers were never active inside workflows. ADK keeps them in ContextVars, and workflow code runs on executor threads that never saw the set_*_provider calls. Replay only compares commands, so nobody noticed until HITL, which matches responses on generated ids. The providers (time, uuid, and now random) are installed as ContextVar defaults instead.
  • Also passes the optional anthropic, litellm, and openai SDKs through the workflow sandbox. ADK probes them on every LLM turn, and importing an installed one inside each sandbox was slow enough to trip the deadlock detector. That was behind the duplicate-span flake in test_single_agent_telemetry on the macOS CI runner.
  • google-adk floor bumped to 2.8.0. It's the first release with fix: route workflow IDs and retry jitter through platform seams google/adk-python#6468, which routes RequestInput ids, node-tool call ids, and retry jitter through google.adk.platform; without that the fix above doesn't reach those call sites. The old git pin to ADK main is gone. 2.8.0 now resolves from PyPI under the normal two-week exclude-newer window.
  • README sections and CHANGELOG entries.

Testing

16 new tests (graph, dynamic, HITL) with max_cached_workflows=0 so every task replays, plus two recorded histories in the replay test. 71 passed, 5 skipped (env-gated) on 2.8.0. Lint clean.

@DABH
DABH force-pushed the google-adk-v2-graph-hitl branch from 3d4be86 to 697e407 Compare July 24, 2026 23:15
DABH added 4 commits July 27, 2026 15:40
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
DABH force-pushed the google-adk-v2-graph-hitl branch from 697e407 to 41276f8 Compare July 27, 2026 20:42
…d bindings)

basedpyright fails CI on warnings: replace typing.Optional/typing.Mapping
with PEP 604/collections.abc forms, drop two unused query-result bindings,
and mark the intentionally-unused node_input parameters (the name is
load-bearing for ADK FunctionNode binding) with targeted ignores.
@DABH
DABH force-pushed the google-adk-v2-graph-hitl branch from 41276f8 to 51dc7a5 Compare July 27, 2026 20:59
@DABH DABH changed the title google_adk_agents: graph workflows, dynamic workflows, and durable HITL (ADK v2) [AI-303] google_adk_agents: graph workflows, dynamic workflows, and durable HITL (ADK v2) Aug 14, 2026
DABH added 6 commits August 17, 2026 19:28
# Conflicts:
#	pyproject.toml
#	temporalio/contrib/google_adk_agents/README.md
#	temporalio/contrib/google_adk_agents/_plugin.py
#	tests/contrib/google_adk_agents/test_adk_streaming.py
google-adk 2.8.0 (released 2026-08-26) is the first release containing the
platform seams this plugin relies on: the random provider and the routing of
RequestInput interrupt ids, _ToolNode function-call ids, and retry jitter
through google.adk.platform (google/adk-python@8f85107c), plus the
deterministic ParallelWorker failure selection (google/adk-python@d31b5e7d).
Resolve google-adk from PyPI again and raise the extra's floor accordingly.

The repo's exclude-newer window is two weeks, so a per-package
exclude-newer-package override admits 2.8.0 until it ages into the window
(2026-09-10); it can be removed after that.
@DABH
DABH marked this pull request as ready for review September 4, 2026 07:06
@DABH
DABH requested review from a team as code owners September 4, 2026 07:06

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Positional-only activity signatures are mishandled, and the temporary dependency cutoff remains committed.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

Adds ADK v2 graph, dynamic workflow, and durable human-in-the-loop support to the Temporal Google ADK integration.

Changes:

  • Adds activity_node and HITL request/response helpers.
  • Installs deterministic ADK time, UUID, and random providers.
  • Adds documentation, dependency updates, integration tests, and replay histories.
File summaries
File Description
CHANGELOG.md Documents new ADK v2 capabilities and version floor.
pyproject.toml Raises Google ADK minimum and adds a temporary cutoff override.
uv.lock Locks Google ADK 2.8.0 and updated dependencies.
temporalio/contrib/google_adk_agents/__init__.py Exports HITL APIs.
temporalio/contrib/google_adk_agents/_hitl.py Implements HITL request parsing and response construction.
temporalio/contrib/google_adk_agents/_plugin.py Installs deterministic platform providers.
temporalio/contrib/google_adk_agents/workflow.py Adds activity-backed graph nodes.
temporalio/contrib/google_adk_agents/README.md Documents graph, dynamic, and HITL workflows.
tests/contrib/google_adk_agents/test_adk_graph_workflows.py Tests graph execution and replay safety.
tests/contrib/google_adk_agents/test_adk_dynamic_workflows.py Tests dynamic nodes and resume behavior.
tests/contrib/google_adk_agents/test_adk_hitl.py Tests durable input and confirmation flows.
tests/contrib/google_adk_agents/test_google_adk_agents_replay.py Extends recorded-history replay coverage.
tests/contrib/google_adk_agents/histories/graph_workflow.json Adds graph workflow replay history.
tests/contrib/google_adk_agents/histories/hitl_workflow.json Adds HITL workflow replay history.
Review details
  • Files reviewed: 13/14 changed files
  • Comments generated: 2
  • Review effort level: Balanced

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread pyproject.toml Outdated
Comment thread temporalio/contrib/google_adk_agents/workflow.py
Comment thread temporalio/contrib/google_adk_agents/_hitl.py Outdated
DABH added 6 commits September 8, 2026 11:42
activity.defn only rejects keyword-only parameters, so positional-only ones
are valid activity signatures. activity_node filtered them out of its
parameter list, so a single positional-only parameter fell into the
zero-argument branch and the activity was scheduled without its input, and
mixed signatures were miscounted. Include positional-only parameters and
bind dict inputs to positional arguments by name, with clear errors for
missing or unexpected keys, instead of Signature.bind, which cannot bind
positional-only parameters from keywords.
pending_hitl_requests surfaced adk_request_credential calls as
kind="credential", but no helper could build the adk_request_credential
response ADK's auth path consumes, so an auth flow discovered through this
API could never be resumed. Supporting it properly is more than a response
helper: ADK exchanges the credential with network I/O inside the flow, and
the exchanged secret would be recorded in workflow history. Leave auth
requests out of the helpers and document that credentials should be
resolved worker-side.
ADK's content processor probes for the anthropic, litellm, and openai
model classes on every LLM turn. Any of those SDKs that is installed but
not yet imported gets imported inside each workflow sandbox on the first
turn, which is slow enough to trip the workflow deadlock detector and fail
the workflow task; the retried task re-executes live, which is how the
duplicate-span failure in test_single_agent_telemetry showed up in CI.
Pass them through like the OpenAI Agents plugin does for openai.
google-adk 2.8.0 is now older than the repository's two-week exclude-newer
window, so it resolves from PyPI under the normal cutoff and the per-package
override (and the lock entry it generated) is no longer needed.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Existing-workflow RNG compatibility, variadic activity handling, and HITL interrupt filtering need correction.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details
  • Files reviewed: 13/14 changed files
  • Comments generated: 3
  • Review effort level: Balanced

Comment thread temporalio/contrib/google_adk_agents/_plugin.py
Comment thread temporalio/contrib/google_adk_agents/_hitl.py
Comment thread temporalio/contrib/google_adk_agents/workflow.py
activity.defn allows *args and **kwargs, but activity_node binds node_input
to named parameters, so a variadic activity fell into the zero-argument
branch and was scheduled without its input. Fail at wrap time instead.
@DABH

DABH commented Sep 11, 2026

Copy link
Copy Markdown
Contributor Author

@copilot resolve the merge conflicts in this pull request

auto-merge was automatically disabled September 11, 2026 20:05

Head branch was pushed to by a user without write access

@CLAassistant

CLAassistant commented Sep 11, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

Copilot AI commented Sep 11, 2026

Copy link
Copy Markdown

@copilot resolve the merge conflicts in this pull request

Merged main into this branch and resolved the PR merge state in commit 4d7e5cb.

@DABH
DABH force-pushed the google-adk-v2-graph-hitl branch from 4d7e5cb to 79fa3cb Compare September 11, 2026 20:37
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.

5 participants