Skip to content

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

Closed
krishdef7 wants to merge 3 commits intogoogle-gemini:mainfrom
krishdef7:fix/transcript-flush-before-tool-dispatch
Closed

fix(core): flush transcript for pure tool-call responses to ensure BeforeTool hooks see complete state#20418
krishdef7 wants to merge 3 commits intogoogle-gemini:mainfrom
krishdef7:fix/transcript-flush-before-tool-dispatch

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 09:55
@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 addresses a critical issue where BeforeTool hooks might not receive the complete conversation transcript when the model's response consists solely of a tool call. By refining the transcript flushing logic, the system now guarantees that the full context, including the model's tool call, is available at the time of tool dispatch. Additionally, it enhances user input handling by distinguishing between typed and pasted content, which allows for more intelligent processing of commands.

Highlights

  • Transcript Flushing for Pure Tool Calls: Resolved an edge case where the transcript was not flushed for model responses containing only a tool call (without text or thoughts), ensuring BeforeTool hooks always see the complete transcript state.
  • Pasted Input Detection: Introduced an isPasted flag to differentiate between typed and pasted input, preventing unintended @ command expansions when content is pasted into the input prompt.
  • Expanded Flush Condition: The transcript flush condition in processStreamResponse was extended to include hasThoughts and hasToolCall, in addition to responseText, to ensure timely transcript updates.
  • New Unit Test: Added a dedicated unit test to validate that the transcript is correctly flushed before tool dispatch for pure tool calls.
Changelog
  • packages/cli/src/ui/AppContainer.tsx
    • Updated handleFinalSubmit to accept an optional isPasted boolean parameter.
    • Modified calls to submitQuery to pass the new isPasted flag.
  • packages/cli/src/ui/components/InputPrompt.test.tsx
    • Updated various onSubmit expectation calls to include the new isPasted argument, typically set to false.
  • packages/cli/src/ui/components/InputPrompt.tsx
    • Modified the InputPromptProps interface to include an optional isPasted boolean for the onSubmit callback.
    • Implemented logic within handleSubmit to detect if the submitted text originated from a paste event and pass this wasPasted flag to onSubmit.
  • packages/cli/src/ui/hooks/atCommandProcessor.ts
    • Added an optional isPasted boolean to the HandleAtCommandParams interface.
    • Implemented a check in handleAtCommand to skip @ command expansion if isPasted is true.
  • packages/cli/src/ui/hooks/useGeminiStream.ts
    • Updated the handleAtCommand function signature to accept an optional isPasted parameter.
    • Modified the submitQuery function signature to include an optional isPasted property in its options object.
    • Propagated the isPasted flag from submitQuery to handleAtCommand.
  • packages/core/src/core/geminiChat.test.ts
    • Added a new unit test case named 'should flush transcript before tool dispatch for pure tool call with no text or thoughts' to verify the fix.
  • packages/core/src/core/geminiChat.ts
    • Introduced a hasThoughts boolean flag to track if the model's response contains thoughts.
    • Extended the transcript recording condition in processStreamResponse to flush when responseText, hasThoughts, or hasToolCall is present, ensuring gemini entries are recorded for pure tool calls or thoughts.
Activity
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 correctly addresses an edge case where the transcript was not being flushed for pure tool-call responses, ensuring BeforeTool hooks have access to the complete conversation state. The added unit test effectively validates this fix. Regarding the new feature to prevent the expansion of @ commands on pasted input, this appears to be a non-standard UX pattern improvement introduced in a single component. According to repository guidelines (Rule: Maintain consistency with existing UI behavior across components. Defer non-standard UX pattern improvements to be addressed holistically rather than in a single component.), such improvements should be addressed holistically rather than in a single component, so this feature should be deferred for a broader discussion and consistent implementation across the application.

@krishdef7
Copy link
Contributor Author

Closing in favor of #20419 — this branch accidentally included unrelated paste detection changes. The new PR is a clean 1-commit, 2-file diff.

@krishdef7 krishdef7 closed this Feb 26, 2026
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.

1 participant