Skip to content

Conversation

@sajanlamsal
Copy link

@sajanlamsal sajanlamsal commented Jan 13, 2026

1. Link to an existing issue:

2. Description of change:

Problem:

The Automatic Function Calling (AFC) loop ignored AutomaticFunctionCallingConfig:

  • disable=True had no effect and AFC continued running
  • maximum_remote_calls was not enforced
  • LLMs could persistently return function calls after the limit, causing infinite loops and no final user response

Solution:

This PR implements two fixes:

  1. AFC Configuration Enforcement

    • disable=True now prevents AFC execution and stops further AFC iterations
    • maximum_remote_calls is enforced in both run_async() and run_live() modes
    • Pre-execution checks prevent function execution once the limit is reached
    • Event counting semantics: one LLM response with multiple parallel function calls counts as one toward maximum_remote_calls
  2. Guardrail Mechanism (Async Mode)

    • Prevents infinite loops when LLMs keep returning function calls after the limit
    • Triggers after 3 consecutive refused function-call events
    • Performs one final LLM call with:
      • Tools removed
      • AFC disabled
      • A system instruction forcing a text-only response
    • Guarantees loop termination and a final user-visible response

Real-world example:
An LLM searches for "unicorn startups in Antarctica". The tool returns empty results, but the LLM keeps retrying with variations. Without the guardrail: infinite loop. With the guardrail: after 3 refused calls, a final response such as "I couldn't find any unicorn startups in Antarctica" is returned and the loop ends.

Testing Plan

Unit Tests:

  • I have added or updated unit tests for my change.
  • All unit tests pass locally.

Coverage:

  • 32 tests across 2 new files
    • test_afc_config.py (20 tests): AFC disable flag and maximum_remote_calls enforcement in async and live modes
    • test_guardrail.py (12 tests): guardrail triggering, tool removal, AFC disabling, and final-response enforcement

Results:

pytest tests/unittests/flows/llm_flows/test_afc_config.py -v
# 20 passed

pytest tests/unittests/flows/llm_flows/test_guardrail.py -v
# 12 passed

pytest tests/unittests/flows/llm_flows/ -q
# 329 passed

pytest tests/unittests/ -v
# 3,832 passed (no regressions)

Manual End-to-End Tests:

Scenario 1: disable=True

WARNING - AFC is disabled. Stopping AFC loop.
INFO - Generated 2 events (no function calls executed)

✅ PASS

Scenario 2: maximum_remote_calls=3

INFO - Iteration 1: Executing function call
INFO - Iteration 2: Executing function call
INFO - Iteration 3: Executing function call
INFO - Generated 7 events (exactly 3 FC events, then stopped)

(Previously: 20+ events due to infinite loop)
✅ PASS

Scenario 3: Guardrail triggered (persistent FCs)

DEBUG - LLM returned FCs after limit (1/3)
DEBUG - LLM returned FCs after limit (2/3)
DEBUG - LLM returned FCs after limit (3/3)
INFO  - Guardrail triggered: forcing final text response
INFO  - Tools removed, AFC disabled
INFO  - LLM returned final text response
INFO  - Loop terminated

✅ PASS

Checklist

  • I have read the CONTRIBUTING.md.
  • I have performed a self-review of my own code.
  • I have commented complex logic.
  • I have added tests that prove the fix is effective.
  • New and existing unit tests pass locally.
  • I have manually tested the changes end-to-end.
  • Any dependent changes have been merged and published.

Additional context

  • maximum_remote_calls counts LLM response events containing function calls, not individual tool invocations.
  • Guardrail logic is applied only in async mode; live mode enforces pre-execution limits only.
  • No public API changes; this is a backward-compatible bug fix.
  • Performance impact is negligible and reduces wasted LLM calls by preventing runaway loops.
  • Reviewer focus: _should_stop_afc_loop() semantics and guardrail cleanup in run_async().

…dling

- Implement tests to verify behavior when AFC is disabled, including stopping the loop after the first response.
- Validate that maximum_remote_calls configuration is respected, including edge cases for zero and negative values.
- Ensure planner hooks are called correctly with various AFC settings.
- Test AFC behavior in live streaming mode, confirming that configurations are enforced as expected.
- Cover scenarios with parallel function calls and their impact on AFC limits.
@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @sajanlamsal, 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 bug where Automatic Function Calling (AFC) configuration settings, such as disabling AFC or limiting the number of remote calls, were being ignored. The fix introduces robust checks throughout the LLM flow to ensure these settings are respected, preventing unintended function executions and potential infinite loops. This change significantly improves the reliability and predictability of AFC behavior, aligning it with the intended API specification.

Highlights

  • New AFC Configuration Helper: Introduced _should_stop_afc_loop() to centralize logic for checking disable and maximum_remote_calls settings for Automatic Function Calling (AFC).
  • Asynchronous Loop Termination: Implemented a check in run_async() to break the Automatic Function Calling (AFC) loop when configuration limits are met or AFC is explicitly disabled.
  • Pre-Execution Function Call Prevention: Added checks in _postprocess_async() and _postprocess_live() to prevent function calls from executing if AFC is disabled or the maximum_remote_calls limit has been reached.
  • Clarified Event Counting Semantics: Documented that maximum_remote_calls counts LLM response events containing function calls, not individual function executions, meaning an event with multiple parallel calls counts as one towards the limit.

🧠 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 core [Component] This issue is related to the core interface and implementation label Jan 13, 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 effectively addresses the bug where Automatic Function Calling (AFC) settings were being ignored. The introduction of the _should_stop_afc_loop helper function is a good approach to centralize the control logic, and the pre-execution checks are correctly placed in the post-processing methods. The new test suite is comprehensive and provides excellent coverage for the fix. I have a couple of suggestions to further improve code readability and maintainability.

@sajanlamsal
Copy link
Author

/gemini review

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 effectively addresses Bug #4133 by correctly enforcing AutomaticFunctionCallingConfig settings and introduces a robust guardrail mechanism to prevent infinite loops in Automatic Function Calling (AFC). The changes are well-structured, thoroughly tested with comprehensive unit tests for both AFC configuration and guardrail functionality, and include detailed logging for observability. The implementation demonstrates careful consideration of edge cases and maintains backward compatibility. This is a significant improvement to the stability and predictability of the AFC system.

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
@sajanlamsal sajanlamsal changed the title # Fix Bug #4133: AutomaticFunctionCallingConfig Settings Ignored fix:Bug #4133: AutomaticFunctionCallingConfig Settings Ignored Jan 14, 2026
@ryanaiagent ryanaiagent self-assigned this Jan 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

core [Component] This issue is related to the core interface and implementation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: AutomaticFunctionCallingConfig(disable=True) is ignored - Planner hook bypassed

3 participants