Skip to content

fix(flows): keep rewound turns out of Interactions API chaining - #7821

Open
adityasingh2400 wants to merge 1 commit into
google:mainfrom
adityasingh2400:fix/interactions-skip-rewound-turns
Open

adityasingh2400 wants to merge 1 commit into
google:mainfrom
adityasingh2400:fix/interactions-skip-rewound-turns

Conversation

@adityasingh2400

Copy link
Copy Markdown
Contributor

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:
On the Interactions API, the model's context is the server-side history behind previous_interaction_id. _find_previous_interaction_state chose that id by scanning raw session.events. After Runner.rewind_async, the next request therefore continued from a rewound turn's interaction, and the turn came back into the model's context. rewind.md promises that ADK "leaves the rewound turns out of every prompt that it builds afterwards".

Solution:
Scan _apply_rewinds(events) instead of events. _rewind_events describes _apply_rewinds as the single source of truth for which events are live, and prompt contents, compaction, memory ingestion and the agent router already use it. After a rewind, the request now continues from the last live interaction, or sends no previous_interaction_id when every interaction was rewound. _managed_agent.py uses the same helper, so it gets the fix as well. The branch filtering and the returned (interaction_id, environment_id) shape are unchanged.

Testing Plan

Unit Tests:

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

Added to tests/unittests/flows/llm_flows/context/test_interactions.py:

  • test_find_previous_interaction_state_skips_rewound_turns: rewinding turn 2 makes the lookup return turn 1's (interaction_id, environment_id).
  • test_find_previous_interaction_state_none_when_every_turn_rewound: returns (None, None).
  • test_find_previous_interaction_state_chains_turns_after_a_rewind: a turn taken after the rewind is still found, as a guard.
# On main (before the fix)
AssertionError: assert ('int_2', 'env_2') == ('int_1', 'env_1')
AssertionError: assert ('int_1', None) == (None, None)
2 failed, 1 passed

# With the fix
$ pytest tests/unittests/flows/llm_flows/context/test_interactions.py
24 passed

$ pytest tests/unittests/flows tests/unittests/runners tests/unittests/agents
2216 passed, 1 skipped, 4 xfailed

pre-commit run passes on the changed files, and mypy reports no issues in _interactions.py.

Manual End-to-End (E2E) Tests:

I ran a real Runner with LlmAgent(model=Gemini("gemini-2.5-flash", use_interactions_api=True)) and an InMemorySessionService. Only interactions_utils.generate_content_via_interactions was stubbed: it records llm_request.previous_interaction_id and returns interaction_id=f"int_{n}". I ran turn 1 ("My name is Ada."), turn 2 ("Actually, call me Bob."), then rewind_async(rewind_before_invocation_id=<turn 2>), then turn 3 ("What is my name?"). The script is in #7820.

=== BEFORE (main) ===
previous_interaction_id per request: [None, 'int_1', 'int_2']
turn 3 continues from: int_2
=== AFTER (this PR) ===
previous_interaction_id per request: [None, 'int_1', 'int_1']
turn 3 continues from: int_1

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

None.

_find_previous_interaction_state scanned raw session events, so after
Runner.rewind_async the next request still set previous_interaction_id to
a rewound turn's interaction. On the Interactions API that id is the
model's context, so the rewound turn came back into it, against the
rewind guarantee. Scan the events that survive _apply_rewinds, as prompt
building and compaction already do. The managed agent uses the same lookup
and gets the fix too.

Fixes google#7820
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.

Interactions API requests chain onto rewound turns after Runner.rewind_async

2 participants