Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Conversation

@baptmont
Copy link
Contributor

@baptmont baptmont commented Dec 3, 2025

Add retry callback example.
Add base_flow tests.

@baptmont baptmont requested a review from dpasiukevich December 3, 2025 13:51
@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @baptmont, 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 LLM agent's tool execution flow by ensuring that BeforeToolCallbacks are always triggered, even when the LLM attempts to call a tool that isn't registered. This enhancement provides a critical interception point for developers to implement custom logic, such as retry strategies or alternative responses, before the system encounters an "unknown tool" error. The changes include core logic adjustments, updated documentation, and a practical example demonstrating a retry callback.

Highlights

  • Enhanced Tool Callback Execution: The handleFunctionCalls logic has been modified to ensure that BeforeToolCallbacks are invoked even when the LLM proposes a function call for a tool that does not exist. This allows for proactive handling of such scenarios.
  • Flexible Error Handling and Retry Mechanisms: This change enables developers to implement custom logic within BeforeToolCallbacks to intercept and respond to calls to non-existent tools, such as providing a default response, logging an error, or initiating a retry without the system throwing an "unknown tool" error immediately.
  • Updated Callback Documentation: The documentation for BeforeToolCallback and AfterToolCallback in llmagent.go has been updated to explicitly state that the tool parameter can be nil if the invoked tool does not exist or if a BeforeToolCallback generates a result or an error.
  • New Retry Callback Example: A new example (examples/tools/retrytool/main.go) has been added to demonstrate how to leverage this new functionality to create a retry mechanism when an LLM calls an incorrectly named tool.
  • Comprehensive Test Coverage: New test cases have been added in base_flow_test.go to validate the behavior of handleFunctionCalls when dealing with both existing and non-existent tool calls, especially focusing on how BeforeToolCallbacks and AfterToolCallbacks interact in these situations.
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 introduces a significant enhancement by allowing beforeToolCallbacks to execute even when a tool does not exist. This is useful for implementing custom error handling or retry logic, as demonstrated by the new retrytool example. The core logic in handleFunctionCalls has been refactored to support this, and the changes are well-covered by new unit tests. The documentation for BeforeToolCallback and AfterToolCallback has also been updated to reflect the new behavior where the tool parameter can be nil. My review identifies a few minor typos in a variable name within the new example and in error messages within the tests, for which I've suggested corrections.

examples/tools/retrytool/main.go Outdated Show resolved Hide resolved
examples/tools/retrytool/main.go Outdated Show resolved Hide resolved
internal/llminternal/base_flow_test.go Outdated Show resolved Hide resolved
internal/llminternal/base_flow_test.go Outdated Show resolved Hide resolved
examples/tools/retrytool/main.go Show resolved Hide resolved
if !ok {
return nil, fmt.Errorf("tool %q is not a function tool", curTool.Name())
}
curTool, toolExists := toolsDict[fnCall.Name]
Copy link
Member

@squee1945 squee1945 Dec 3, 2025

Choose a reason for hiding this comment

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

Could the framework just do this?

if !toolExists {
  return map[string]any{"error": fmt.Errorf("tool %q does not exist, please choose another tool", fnCall.Name)}, nil
}

Copy link
Member

Choose a reason for hiding this comment

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

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This seems like a good option. Simply notify the llm instead of returning the err all the way back to the runner.

spans := telemetry.StartTrace(ctx, "execute_tool "+fnCall.Name)

result := f.callTool(funcTool, fnCall.Args, toolCtx)
result, err := f.invokeBeforeToolCallbacks(funcTool, fnCall.Args, toolCtx)
Copy link
Member

Choose a reason for hiding this comment

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

With this change, it seems the contract with the client is changed: now the tool can be nil.

This could cause runtime errors with existing clients.

ADK-Python seems to have a different callback for tool errors - and it generates a fake tool to hold the name of the tool that had the error. https://github.com/google/adk-python/blob/main/src/google/adk/flows/llm_flows/functions.py#L326-L332

Should ADK-Go do something similar?

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.

3 participants

Morty Proxy This is a proxified and sanitized view of the page, visit original site.