Skip to content

fix(runners): Preserve state_delta in NodeRunner path#5767

Open
trongthanht3 wants to merge 5 commits into
google:mainfrom
trongthanht3:fix/node-runner-state-delta
Open

fix(runners): Preserve state_delta in NodeRunner path#5767
trongthanht3 wants to merge 5 commits into
google:mainfrom
trongthanht3:fix/node-runner-state-delta

Conversation

@trongthanht3
Copy link
Copy Markdown

Please ensure you have read the contribution guide before creating a pull request.

Link to Issue or Description of Change

1. Link to an existing issue (if applicable):

Problem:
/run and /run_sse already pass state_delta into Runner.run_async, but the ADK 2.0 NodeRunner execution path was not attaching that delta to the initial user event. As a result, workflow nodes and root LlmAgent executions could not see the requested state before running.

Solution:
Thread state_delta through the NodeRunner path and persist non-empty deltas on the initial user event via EventActions, matching the legacy runner behavior while preserving existing user-event isolation-scope handling.

Testing Plan

Unit Tests:

  • I have added or updated unit tests for my change.
  • All unit tests pass locally.

Passed results:

pre-commit run --files src/google/adk/runners.py tests/unittests/runners/test_runner_state_delta.py
Passed

uv run pytest tests/unittests/runners/test_runner_state_delta.py tests/unittests/runners/test_runner_node.py
33 passed

uv run pytest tests/unittests
6622 passed, 18 skipped, 31 xfailed, 9 xpassed

tox
py310: OK
py311: OK
py312: OK
py313: OK
py314: OK

Manual End-to-End (E2E) Tests:

Ran adk web with an agent callback that logs session state before execution:

uv run adk web \
  --host 127.0.0.1 \
  --port 8765 \
  --session_service_uri memory:// \
  --artifact_service_uri memory:// \
  --no-reload \
  /tmp/adk_state_delta_e2e

Sent /run and /run_sse requests with:

{
  "app_name": "state_delta_app",
  "user_id": "e2e-user",
  "session_id": "e2e-session",
  "new_message": {
    "role": "user",
    "parts": [
      {
        "text": "hello"
      }
    ]
  },
  "state_delta": {
    "test_state": "must_change"
  }
}

Observed:

/run callback log:
STATE_DELTA_E2E test_state=must_change

/run session state:
"state":{"test_state":"must_change"}

/run user event:
"actions":{"stateDelta":{"test_state":"must_change"}}

/run_sse callback log:
STATE_DELTA_E2E test_state=must_change_sse

/run_sse session state:
"state":{"test_state":"must_change_sse"}

/run_sse user event:
"actions":{"stateDelta":{"test_state":"must_change_sse"}}

Checklist

  • I have read the CONTRIBUTING.md document.
  • I have performed a self-review of my own code.
  • I have commented my code, particularly in hard-to-understand areas.
  • I have added tests that prove my fix is effective or that my feature works.
  • New and existing unit tests pass locally with my changes.
  • I have manually tested my changes end-to-end.
  • Any dependent changes have been merged and published in downstream modules.

Additional context

No dependent changes are required.

@DeanChensj
Copy link
Copy Markdown
Collaborator

@gemini-cli /review

@github-actions
Copy link
Copy Markdown

🤖 Hi @DeanChensj, I've received your request, and I'm working on it now! You can track my progress in the logs for more details.

Copy link
Copy Markdown

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

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

The changes look solid and correctly address the issue where state_delta was not being attached to the initial user event in the ADK 2.0 NodeRunner path. This ensures that session state updates requested via /run or /run_sse are visible to nodes and agents before they execute.

I've left one minor suggestion for code conciseness in runners.py, but overall this is a great fix with excellent test coverage. Approving!

Comment thread src/google/adk/runners.py
author='user',
actions=EventActions(state_delta=state_delta),
content=content,
)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

This is a good fix. It correctly threads state_delta through the NodeRunner path, ensuring the session state is updated before any nodes or agents execute.

One minor suggestion: this block could be slightly more concise, though the current version is perfectly clear.

    event = Event(
        invocation_id=ic.invocation_id,
        author='user',
        actions=EventActions(state_delta=state_delta) if state_delta else None,
        content=content,
    )

@@ -0,0 +1,161 @@
# Copyright 2026 Google LLC
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Excellent test coverage. Verifying both BaseNode and LlmAgent callback scenarios ensures that the state delta is correctly applied in different execution paths.

@@ -0,0 +1,161 @@
# Copyright 2026 Google LLC
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Could you move the tests to tests/unittests/runners/test_runner_node.py?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

I moved tests to tests/unittests/runners/test_runner_node.py as your request

@adk-bot adk-bot added the core [Component] This issue is related to the core interface and implementation label May 20, 2026
@adk-bot
Copy link
Copy Markdown
Collaborator

adk-bot commented May 20, 2026

Response from ADK Triaging Agent

Hello @trongthanht3, thank you for creating this PR!

Your PR description is very detailed, and we appreciate the thorough testing plan and logs! However, we noticed that the pre-commit CI check has failed.

To resolve any formatting or style issues, please ensure you run pre-commit locally across all files:

pre-commit run --all-files

You can refer to the Development Setup section of our contributing guidelines for details.

This will help us review and merge your changes more quickly. Thanks!

@rohityan rohityan assigned rohityan and DeanChensj and unassigned rohityan May 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

core [Component] This issue is related to the core interface and implementation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

state_delta passed to /run endpoint is silently ignored in Workflow (NodeRunner) path

4 participants