Skip to content

Fix tool calls not shown until there is some text in message#15

Closed
fr33z00 wants to merge 10 commits intomoeru-ai:mainfrom
fr33z00:fix-show-starting-tool-call
Closed

Fix tool calls not shown until there is some text in message#15
fr33z00 wants to merge 10 commits intomoeru-ai:mainfrom
fr33z00:fix-show-starting-tool-call

Conversation

@fr33z00
Copy link
Contributor

@fr33z00 fr33z00 commented Dec 14, 2025

No description provided.

@gemini-code-assist
Copy link

Summary of Changes

Hello @fr33z00, 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 and resolves an issue where tool calls were not immediately visible in the user interface until some text content was present in the message. The changes introduce a new mechanism for displaying intermediate reasoning steps and ensure that message content is properly initialized when tool calls begin. This is supported by a significant upgrade of core @xsai dependencies, enhancing the real-time display of AI responses, particularly for complex interactions involving tool usage and reasoning.

Highlights

  • Tool Call Visibility Fix: Tool calls will now be displayed immediately in the UI, even if there is no preceding text in the message, resolving a previous rendering delay.
  • New Reasoning Content Type: Handling for a new reasoning-delta event type has been introduced, allowing for the display of intermediate reasoning steps as part of the message content.
  • Dependency Upgrades: Key @xsai packages, including @xsai/shared-chat, @xsai/stream-text, @xsai/tool, @xsai/utils-reasoning, @xsai/shared, and xsschema, have been updated to version 0.4.0-beta.10.
  • Type Refactoring: Message part types have been updated across part-parser.ts and types/ui.ts to use CommonContentPart and RefusalContentPart instead of the more general Part, aligning with the new package versions and improving type clarity.
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

@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 support for streaming 'reasoning' steps and fixes an issue where tool calls would not be displayed until some text was present in the message. The changes are mostly in call-api.ts to handle the new 'reasoning-delta' event and to correctly initialize the message content for tool calls. I've found a few areas in the new logic that could be made more type-safe and robust to prevent potential runtime errors.

Comment on lines +48 to +53
if (part && !shouldNewReasoningNext) {
part.reasoning += event.text
}
else {
parts.push({ reasoning: event.text, type: 'reasoning' })
}

Choose a reason for hiding this comment

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

high

The current implementation is not type-safe. part is of type UIMessagePart | undefined, and accessing part.reasoning directly can lead to a runtime error if part is not a UIMessageReasoningPart. Although findLast filters by type, TypeScript's control flow analysis doesn't automatically narrow the type here. You can add an explicit check for part.type to ensure type safety.

Suggested change
if (part && !shouldNewReasoningNext) {
part.reasoning += event.text
}
else {
parts.push({ reasoning: event.text, type: 'reasoning' })
}
if (part && part.type === 'reasoning' && !shouldNewReasoningNext) {
part.reasoning += event.text;
}
else {
parts.push({ reasoning: event.text, type: 'reasoning' });
}

parts.push({ reasoning: event.text, type: 'reasoning' })
}

message.content = (message.content as string ?? '') + event.text

Choose a reason for hiding this comment

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

high

The type assertion message.content as string is unsafe. If message.content is an array of parts, it will be coerced to a string like "[object Object]" at runtime, which is likely not the intended behavior. To safely handle this, you should check if message.content is a string before concatenating. This same issue exists on line 40 for text-delta and should be addressed there as well, although it's outside the current diff.

Suggested change
message.content = (message.content as string ?? '') + event.text
message.content = (typeof message.content === 'string' ? message.content : '') + event.text

},
type: 'tool-call',
})
message.content = message.content as string ?? ''

Choose a reason for hiding this comment

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

high

The type assertion message.content as string is unsafe here. If message.content is an array of parts, it will not be converted to an empty string as intended. A safer approach is to check the type of message.content to ensure it's a string, and initialize to an empty string otherwise. This correctly implements the fix for showing tool calls without prior text content.

Suggested change
message.content = message.content as string ?? ''
message.content = typeof message.content === 'string' ? message.content : ''

@fr33z00
Copy link
Contributor Author

fr33z00 commented Dec 14, 2025

Hello.

As said in the title, but not commented because I was tricked one more time by github that I don't use much, This PR intends to fix the fact that no part of the message other than user prompt is available when LLM decides to start with tool calls, and this, until it writes text.

I only changed one line, in this one, but code base is my previous PR.

"name": "@xsai-use/shared",
"type": "module",
"version": "0.0.2",
"version": "0.0.2-reasoning",
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
"version": "0.0.2-reasoning",
"version": "0.0.2",

@kwaa
Copy link
Member

kwaa commented Dec 15, 2025

I only changed one line, in this one, but code base is my previous PR.

Perhaps you should wait until the previous PR is merged before submitting a new one.

@fr33z00
Copy link
Contributor Author

fr33z00 commented Dec 15, 2025

This PR could/should have been done on the base code, because it is valid independently of the previous PR.
I apologize for the mess, when one creates a PR is his fork, github decides as default it is against the base, not the fork, that's where I was tricked.
Do you prefer me to close this one and create a new PR on the base with this only change?

@kwaa
Copy link
Member

kwaa commented Dec 15, 2025

Do you prefer me to close this one and create a new PR on the base with this only change?

Sure.

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.

2 participants