Skip to content

fix(core): flush transcript for pure tool-call responses to ensure BeforeTool hooks see complete state#20419

Merged
bdmorgan merged 2 commits intogoogle-gemini:mainfrom
krishdef7:fix/transcript-flush-v3
Feb 26, 2026
Merged

fix(core): flush transcript for pure tool-call responses to ensure BeforeTool hooks see complete state#20419
bdmorgan merged 2 commits intogoogle-gemini:mainfrom
krishdef7:fix/transcript-flush-v3

Conversation

@krishdef7
Copy link
Contributor

Summary

Extends #17996 to cover a remaining edge case: when the model emits a functionCall with no response text and no thoughts, recordMessage was never called, leaving BeforeTool hooks with no gemini entry in the transcript at dispatch time.

Details

PR #17996 introduced the hasThoughts flag to flush the transcript when thoughts precede a tool call. However, the flush condition was responseText || hasThoughts — so a pure tool call (no text, no thoughts) still skipped recordMessage.

Before this PR, transcript state at BeforeTool hook dispatch:

{
  "messages": [
    { "type": "user", "content": "analyze test.py" }
  ]
}

After this PR, transcript state at BeforeTool hook dispatch:

{
  "messages": [
    { "type": "user", "content": "analyze test.py" },
    { "type": "gemini", "content": "" }
  ]
}

Changes:

Why processStreamResponse and not ToolExecutor:
An earlier approach considered flushing at the tool dispatch point in CoreToolScheduler. That would require threading chatRecordingService through CoreToolScheduler → ToolExecutor, coupling recording logic into the scheduler. The correct separation of concerns keeps all recording in GeminiChat.processStreamResponse, where it already lives.

Related Issues

Related to #17996, #17922

How to Validate

  1. Create a BeforeTool hook that reads the session transcript file
  2. Send a prompt that causes the model to immediately call a tool with no preamble text
  3. Before this PR: transcript contains only the user message at hook time
  4. After this PR: transcript contains both the user message and a gemini-type entry

Unit test added: should flush transcript before tool dispatch for pure tool call with no text or thoughts in geminiChat.test.ts — mocks a pure functionCall stream and asserts a gemini-type message is written to disk before stream completion.

Pre-Merge Checklist

  • Added/updated tests
  • Validated build passes (npm run build)
  • No breaking changes

…esponses

Extends the fix in google-gemini#17996: when the model emits a functionCall with no
response text and no thoughts, recordMessage was not called, leaving
BeforeTool hooks with no gemini entry in the transcript at dispatch time.

- Add hasThoughts flag (from google-gemini#17996) to track thought-only responses
- Add hasToolCall to flush condition so pure tool calls also trigger a
  transcript write before tool execution
- Add regression test verifying gemini entry is written on pure tool call

Fixes the edge case noted in PR google-gemini#17996 discussion.
@krishdef7 krishdef7 requested a review from a team as a code owner February 26, 2026 10:03
@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @krishdef7, 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 refines the chat transcript recording mechanism to ensure that BeforeTool hooks consistently receive an up-to-date transcript, particularly when the model directly invokes a tool without generating any preceding text or thoughts. The change prevents a previous scenario where the transcript would be incomplete, thereby improving the reliability of tool execution workflows.

Highlights

  • Transcript Flushing Logic: Modified the transcript flushing condition in processStreamResponse to ensure that a 'gemini' entry is recorded even when the model emits a pure tool call (without response text or thoughts). This addresses an edge case where BeforeTool hooks would not see the complete transcript state.
  • New hasThoughts Flag: Introduced a hasThoughts flag to track if the model's response chunk contains any thoughts, which is now incorporated into the transcript flushing logic.
  • Unit Test Coverage: Added a new unit test case (should flush transcript before tool dispatch for pure tool call with no text or thoughts) to validate the corrected transcript flushing behavior for pure tool calls.
Changelog
  • packages/core/src/core/geminiChat.test.ts
    • Added a new test case to verify transcript flushing for pure tool calls without text or thoughts.
  • packages/core/src/core/geminiChat.ts
    • Introduced a hasThoughts flag to track if model responses contain thoughts.
    • Updated the transcript flushing condition to include hasThoughts and hasToolCall, ensuring recordMessage is called for pure tool invocations.
Activity
  • Added/updated tests to cover the new functionality.
  • Validated that the build passes successfully.
  • Confirmed that no breaking changes were introduced.
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.

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 addresses an important edge case where the session transcript was not updated for model responses containing only a tool call, without any accompanying text or thoughts. This could lead to BeforeTool hooks operating on stale state.

The fix correctly extends the condition for recording a model message to include hasToolCall, ensuring that a gemini entry is always added to the transcript when the model produces any output, including a pure tool call. The addition of the hasThoughts flag, while duplicated from another pending PR, is necessary here for completeness.

The new unit test effectively validates this fix by simulating a pure tool call stream and asserting that the transcript is written to disk with the new gemini message. The changes are well-contained and the logic is sound. I have no further comments.

@gemini-cli gemini-cli bot added priority/p1 Important and should be addressed in the near term. area/agent Issues related to Core Agent, Tools, Memory, Sub-Agents, Hooks, Agent Quality help wanted We will accept PRs from all issues marked as "help wanted". Thanks for your support! labels Feb 26, 2026
@bdmorgan bdmorgan added this pull request to the merge queue Feb 26, 2026
@github-merge-queue github-merge-queue bot removed this pull request from the merge queue due to failed status checks Feb 26, 2026
@bdmorgan bdmorgan added this pull request to the merge queue Feb 26, 2026
@github-merge-queue github-merge-queue bot removed this pull request from the merge queue due to failed status checks Feb 26, 2026
@bdmorgan bdmorgan added this pull request to the merge queue Feb 26, 2026
@github-merge-queue github-merge-queue bot removed this pull request from the merge queue due to failed status checks Feb 26, 2026
@bdmorgan bdmorgan added this pull request to the merge queue Feb 26, 2026
Merged via the queue into google-gemini:main with commit f700c92 Feb 26, 2026
27 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/agent Issues related to Core Agent, Tools, Memory, Sub-Agents, Hooks, Agent Quality help wanted We will accept PRs from all issues marked as "help wanted". Thanks for your support! priority/p1 Important and should be addressed in the near term.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants