fix(runners): apply state_delta when resuming without a new_message - #6645
Open
lwangverizon wants to merge 1 commit into
Open
fix(runners): apply state_delta when resuming without a new_message#6645lwangverizon wants to merge 1 commit into
lwangverizon wants to merge 1 commit into
Conversation
`Runner.run_async` accepts a `state_delta` argument and documents it as "Optional state changes to apply to the session", but the delta was only ever applied while appending the user message event, gated on `if new_message:`. Resuming an invocation by `invocation_id` with no `new_message` is a supported call, so in that case a caller-supplied `state_delta` was accepted and then silently discarded - no warning, no error. Apply the delta via a content-less event when there is no user message to carry it. This mirrors the existing rewind path, which already appends `Event(author='user', actions=EventActions(state_delta=...))` with no content.
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.
Link to Issue or Description of Change
1. Link to an existing issue (if applicable):
state_deltais silently ignored when resuming an invocation without anew_message#6644state_deltapassed to/runendpoint is silently ignored in Workflow (NodeRunner) path #5763, fix(runners): Preserve state_delta in NodeRunner path #5767 (thenew_messagehalf of the same root cause)Problem:
Runner.run_asyncaccepts astate_deltaargument and documents it as "Optional statechanges to apply to the session", but the delta is only ever applied while appending the
user message event — so both dispatch paths gate it on
if new_message::runners.py:628→_append_user_event(..., state_delta=...)runners.py:2142in_setup_context_for_resumed_invocation→_handle_new_message(..., state_delta=...)Resuming an invocation by
invocation_idwith nonew_messageis a supported call, so inthat case a caller-supplied
state_deltais accepted and then silently discarded — nowarning, no error, no event. #5767 fixed this for the
new_messagepath; this is theremaining half.
Solution:
Apply the delta via a content-less event when there is no user message to carry it.
This mirrors the existing rewind path, which already appends
Event(author='user', actions=EventActions(state_delta=...))with no content(
runners.py:1373-1381) — so the shape is established in this file rather than new.The new
_append_state_delta_eventhelper sits next to_append_user_eventand reuses thesame surrounding machinery (
_apply_run_config_custom_metadata,stamp_event_branch_context,session_service.append_event), then it is called from thetwo
if new_message:sites as anelif state_delta:branch. Net effect: a documentedparameter stops losing data, and nothing changes on any path that already worked.
I deliberately did not make this raise or warn on an unsupported combination, and did not
change when
state_deltais accepted — the parameter is already public and documented, sohonouring it is the smaller and more backward-compatible change.
Testing Plan
Unit Tests:
Added
test_run_async_applies_state_delta_when_resuming_without_new_messageas the siblingof the existing
test_run_passes_state_delta(tests/unittests/test_runners.py:734), whichcovers only the
new_messagepath.Confirmed the test actually pins the fix — with the
runners.pychange stashed it fails,and passes with it:
Full file:
Adjacent suites, compared against pristine
main@a5864a0ein a separate worktree:The 44 failures are pre-existing on
mainand unrelated to this change (mostlytest_vertex_ai_session_service.py); I diffed the twoFAILEDlists and they areidentical, so this branch introduces no regressions.
test_audio_transcriber.pyis excludedfrom both runs — it fails to collect on
mainfor a missing test dependency.pyink --checkreports both changed files unchanged.Manual End-to-End (E2E) Tests:
Ran a standalone script that exercises both runner dispatch paths, since
LlmAgentis aBaseNodeand takes the node path while a plainBaseAgenttakes the legacy path. It uses astub model, so it needs no network, API key, or model access. Each case does a normal run to
create an invocation, then resumes it by
invocation_idwith astate_deltaand nonew_message.repro.py
Before — pristine
main@a5864a0e, both paths drop the delta:After — this branch, both paths apply it:
Checklist
Additional context
Scope note: this only adds an
elifbranch on the two sites that were already dropping thedelta, plus the helper they call. No existing path changes behavior, and the event it appends
is the same shape the rewind path already writes — so it should be a no-op for anyone not
passing
state_deltawithout anew_message.While tracing this I checked a third
if new_message:site,_handle_new_message(
runners.py:2296onmain), and deliberately left it alone:types.Contentdefines no__bool__, sobool(types.Content())andbool(types.Content(parts=[]))are bothTrueand the guard there can never be falsy when reached. Adding a branch would have been dead
code.