Skip to content

Conversation

@jayy-77
Copy link

@jayy-77 jayy-77 commented Jan 18, 2026

Link to Issue or Description of Change

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

…3940)

Repeated tool execution can happen when the model emits the same function call
multiple times (same tool name + same arguments), which is especially painful
for slow or expensive tools.

This change introduces an invocation-scoped single-flight cache:
- Adds RunConfig.dedupe_tool_calls (opt-in) to reuse results for identical calls
- Always dedupes BaseTool.is_long_running tools (safer default for long ops)
- Ensures only the first execution applies tool side effects (state/artifacts)
- Emits cached responses with per-call function_response.id and debug metadata

Tests:
- Added unit tests covering duplicate calls across steps and within one step.
…#3573)

When a client reconnects to a live (BIDI) session using SQLite or database
persistence, user messages were stored correctly in the database but not
replayed to the reconnecting client. This caused the UI to show only agent
responses after reconnection, making conversations appear incomplete.

Root Cause:
The /run_live websocket endpoint was loading the session (including all
events) but only forwarding new events generated by the runner. There was
no logic to replay existing events back to the reconnecting client.

Changes:
- Modified adk_web_server.py run_agent_live() to replay all existing
  session events to the client before starting the live runner
- Added comprehensive error handling to continue replay even if individual
  events fail to serialize
- Added logging to track event replay for debugging

Testing:
- Added test_live_session_restoration.py with 3 unit tests covering:
  * Successful replay of all user and agent events on reconnection
  * Graceful handling of sessions with no events
  * Continuation of replay even if one event fails

Fixes google#3573
)

This fix addresses duplicate agent responses that occur during agent
transfers and session resumption when using Gemini Live API.

Problem:
When the Gemini Live API performs transparent session resumption (replaying
the model's last response automatically), our manual event replay logic in
the /run_live endpoint conflicts with this, causing the same response to be
sent twice to the client.

Root Cause:
Issue google#3573's fix added event replay for BIDI session reconnections, which
works perfectly for text-only sessions. However, for live/audio sessions,
the Gemini Live API has built-in session resumption that already replays the
model's response. When both mechanisms are active, duplicates occur.

Solution:
Added intelligent session detection logic that distinguishes between:
- Text-only sessions: Replay all events (maintains google#3573 fix)
- Live/audio sessions: Skip manual replay, rely on Gemini Live API's
  transparent session resumption

Detection is based on the presence of:
- Input/output transcription data
- Audio or video content in recent events

Changes:
- Modified src/google/adk/cli/adk_web_server.py:
  * Added is_live_session() helper to detect live/audio sessions
  * Made event replay conditional based on session type
  * Added detailed logging for debugging session restoration

- Enhanced tests/unittests/cli/test_live_session_restoration.py:
  * Added test_live_session_skips_replay_for_audio_sessions
  * Added test_text_session_replays_events_normally
  * Ensures both google#3573 and google#3395 fixes work correctly

Dependencies:
This fix builds on PR google#4194 (Issue google#3573) which adds the event replay
mechanism. The google#3395 fix makes that mechanism smart enough to avoid
conflicts with Gemini Live API.

Testing:
✅ All 5 unit tests pass:
  * test_live_session_replays_all_events_on_reconnection (google#3573)
  * test_live_session_handles_empty_events_gracefully (google#3573)
  * test_live_session_continues_after_replay_failure (google#3573)
  * test_live_session_skips_replay_for_audio_sessions (google#3395)
  * test_text_session_replays_events_normally (google#3395)

Fixes google#3395
@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @jayy-77, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request enhances the agent's invocation context by introducing a robust tool call deduplication system, which caches and reuses results for identical tool calls, thereby optimizing performance. Concurrently, it refines the live session event replay mechanism within the web server, ensuring that events are only replayed for text-based interactions and are intelligently skipped for live/audio sessions to prevent redundant output, leveraging the Gemini Live API's native resumption capabilities. These changes collectively aim to improve the efficiency and user experience of interactive agent sessions.

Highlights

  • Tool Call Deduplication: Implemented a mechanism to deduplicate identical tool calls (same tool name and arguments) within a single invocation. This prevents redundant tool executions, improving efficiency, especially for slow or frequently repeated tool calls by the model.
  • Live Session Event Replay Logic Refinement: Modified the live web server to intelligently handle event replay for sessions. It now skips replaying events for live/audio sessions (where the Gemini Live API provides transparent session resumption) to avoid duplicate responses, while ensuring events are correctly replayed for text-only sessions.
  • New Configuration Option: Introduced a dedupe_tool_calls boolean field in RunConfig to allow explicit control over whether tool call deduplication is enabled for a given invocation.
  • Comprehensive Testing: Added new unit tests to validate both the tool call deduplication functionality and the refined live session event replay logic, ensuring correct behavior for various session types and error conditions.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@adk-bot adk-bot added the live [Component] This issue is related to live, voice and video chat label Jan 18, 2026
Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces two significant improvements. First, it fixes an issue with duplicate responses in live sessions by intelligently skipping event replay when the Gemini Live API's transparent session resumption is active, while ensuring text-only sessions still replay correctly. Second, it adds a tool call deduplication feature to prevent redundant tool executions within a single invocation, which is particularly useful for slow or long-running tools. The changes are well-implemented with robust asynchronous caching logic and are accompanied by a comprehensive set of new unit tests. My feedback includes a couple of minor suggestions to improve code simplicity and test maintainability.

def is_live_session(events: list) -> bool:
"""Check if session contains audio/video or transcription data."""
# Check last few events for live session indicators
for event in reversed(events[-5:] if len(events) > 5 else events):
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

The conditional slicing events[-5:] if len(events) > 5 else events is a bit redundant. Python's list slicing handles this gracefully. You can simplify this to just events[-5:], which works correctly even for lists with fewer than 5 elements.

Suggested change
for event in reversed(events[-5:] if len(events) > 5 else events):
for event in reversed(events[-5:]):

Comment on lines +267 to +285
def is_live_session(events: list) -> bool:
for event in reversed(events[-5:] if len(events) > 5 else events):
if hasattr(event, 'input_transcription') and event.input_transcription:
return True
if hasattr(event, 'output_transcription') and event.output_transcription:
return True
if event.content:
for part in event.content.parts:
if part.inline_data and (
part.inline_data.mime_type.startswith("audio/")
or part.inline_data.mime_type.startswith("video/")
):
return True
if part.file_data and (
part.file_data.mime_type.startswith("audio/")
or part.file_data.mime_type.startswith("video/")
):
return True
return False
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

The helper function is_live_session is duplicated in test_live_session_skips_replay_for_audio_sessions and test_text_session_replays_events_normally. To improve maintainability and avoid code duplication, consider defining it once at the module level within this test file.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

live [Component] This issue is related to live, voice and video chat

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Live] Multiple responses after agent transfer and repeat response on session resumption

2 participants