Skip to content

Apply Google ADK deterministic providers inside workflow tasks - #1854

Open
DABH wants to merge 2 commits into
mainfrom
fix/adk-providers-in-workflow-threads
Open

Apply Google ADK deterministic providers inside workflow tasks#1854
DABH wants to merge 2 commits into
mainfrom
fix/adk-providers-in-workflow-threads

Conversation

@DABH

@DABH DABH commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

ADK keeps its time and uuid providers in contextvars.ContextVars, and GoogleAdkPlugin set them from the worker's context. Workflow tasks run on the workflow task executor's threads, which start with an empty context, so inside a workflow ADK still used wall-clock time and uuid.uuid4() for session, event, invocation, and function-call ids. Only debug mode, which runs activations inline, saw the deterministic values.

The plugin now rebinds each google.adk.platform ContextVar (time, uuid, and the random seam added in ADK 2.8.0) to one whose default is the Temporal provider, so it applies in every context on Worker and Replayer, sandboxed or not. Installation is idempotent; outside a workflow the providers fall back to the standard library.

Breaking: the google-adk extra now requires google-adk>=2.8.0, the first release with the _random seam.

Tested with a real Worker (sandboxed and unsandboxed) plus replay, and a fresh-thread check that fails on main. Lock and doc notes are in the first comment.

Same approach as _install_provider in #1675, which can rebase onto this.

ADK keeps its time, id, and random providers in contextvars.ContextVars.
GoogleAdkPlugin set them in the worker's context, but workflow tasks run
on the workflow task executor's threads, which start with an empty
context, so ADK code inside a workflow read the defaults: wall-clock time
and uuid.uuid4() for session, event, invocation, and function-call ids.
Only debug mode, which runs activations inline, saw the deterministic
values.

Rebind each google.adk.platform ContextVar to one whose default is the
Temporal provider so it is visible from every context, on Worker and
Replayer alike. Also install the random provider ADK added in 2.8.0 and
raise the google-adk floor to 2.8.0.
@DABH
DABH requested review from a team as code owners September 11, 2026 06:07
Use workflow.time() for the time provider, warn when installing replaces
a provider set earlier in the calling context, and document that
overrides must be made after the worker starts and that ADK id and
random generation raise ReadOnlyContextError in read-only contexts.
Tests assert provider identity.
@DABH

DABH commented Sep 11, 2026

Copy link
Copy Markdown
Contributor Author

Notes for review:

  • uv.lock: besides google-adk 2.4.0 -> 2.8.0, the diff carries google-genai 2.11.0 -> 2.20.0 (ADK 2.8.0 requires google-genai>=2.19), a new aiohttp edge, and marker/exclude-newer re-serialization from a newer uv. uv lock --check passes.
  • Behaviour documented in the CHANGELOG and README: installation warns if it replaces an ADK provider set earlier in the calling context (overrides must be made after the worker starts or from workflow code), and, like workflow.uuid4(), ADK id generation and get_random() in query handlers and update validators now raise ReadOnlyContextError instead of returning a random value.
  • The README's "Support for custom span exporters" bullet is removed as a stale-doc cleanup, unrelated to the fix.
  • Validation: uv run pytest tests/contrib/google_adk_agents -> 58 passed, 5 skipped (tests needing GOOGLE_API_KEY and the CI-skipped MCP tests); uv run poe lint (ruff, pyright, mypy, basedpyright, pydocstyle) passes.

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

ADK’s public reset functions can restore nondeterministic standard-library providers inside workflows.

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

Pull request overview

Ensures Google ADK uses Temporal’s deterministic time, UUID, and random providers across worker and replay threads.

Changes:

  • Installs thread-visible, idempotent ADK provider defaults.
  • Adds worker, sandbox, replay, fallback, and override tests.
  • Requires Google ADK 2.8.0 and documents compatibility implications.
File summaries
File Description
temporalio/contrib/google_adk_agents/_plugin.py Implements deterministic provider installation.
tests/contrib/google_adk_agents/test_adk_platform_providers.py Tests provider behavior across execution contexts.
temporalio/contrib/google_adk_agents/README.md Documents provider semantics.
pyproject.toml Raises the Google ADK minimum version.
uv.lock Locks Google ADK 2.8.0 and dependencies.
CHANGELOG.md Records the fix and replay compatibility warning.
Review details
  • Files reviewed: 5/6 changed files
  • Comments generated: 1
  • Review effort level: Balanced

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

UserWarning,
stacklevel=_stacklevel_outside_temporalio(),
)
setattr(module, var_name, contextvars.ContextVar(current.name, default=provider))

def _deterministic_random_provider() -> random.Random:
if workflow.in_workflow():
return workflow.random()

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

workflow.new_random() should be used instead to create a private stream for ADK, simlarly to the Otel integration

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.

3 participants