Skip to content

Conversation

@praneeth999
Copy link
Collaborator

@praneeth999 praneeth999 commented Dec 19, 2025

Description

Adding the gemini interactions api as new backend, this is experimental feature

Type of change

  • New feature (feat:) - Non-breaking change which adds functionality

Checklist

  • I have run pre-commit on my changed files and all checks pass
  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes

Pre-commit status

# Paste the output of running pre-commit on your changed files:
# uv run pre-commit install
# git diff --name-only HEAD~1 | xargs uv run pre-commit run --files # for last commit
# git diff --name-only origin/<base branch>...HEAD | xargs uv run pre-commit run --files # for all commits in PR
# git add <your file> # if any fixes were applied
# git commit -m "chore: apply pre-commit fixes"
# git push origin <branch-name>

How to Test

Add test method for this PR.

Test CLI Command

Write down the test bash command. If there is pre-requests, please emphasize.

Expected Results

Description/screenshots of expected results.

Additional context

Add any other context about the PR here.

Summary by CodeRabbit

Release Notes

  • New Features

    • Introduced Gemini Interactions API backend enabling stateful multi-turn conversations with agent tooling.
    • Added support for web search, code execution, MCP integration, image understanding, and URL context.
    • Multiple models available with flexible polling and streaming interaction modes.
  • Chores

    • Updated dependencies for improved compatibility and stability.

✏️ Tip: You can customize this high-level summary in your review settings.

@praneeth999 praneeth999 marked this pull request as draft December 19, 2025 05:48
@praneeth999 praneeth999 marked this pull request as ready for review December 22, 2025 18:30
@coderabbitai
Copy link

coderabbitai bot commented Jan 9, 2026

📝 Walkthrough

Walkthrough

Adds comprehensive Gemini Interactions API backend support with stateful conversation capabilities. Includes new backend implementation with streaming/polling modes, API params handler, formatter integration, agent config factory method, CLI support, capability registration, and configuration examples. Updates google-genai dependency requirement.

Changes

Cohort / File(s) Summary
Backend Core Implementation
massgen/backend/gemini_interactions.py
New GeminiInteractionsBackend class with exponential backoff, streaming/polling interaction flows, tool execution (custom/MCP), resource management, and state tracking across interactions
Backend Infrastructure
massgen/backend/__init__.py, massgen/backend/capabilities.py
Exports GeminiInteractionsBackend; adds gemini_interactions entry to BACKEND_CAPABILITIES with 6 models, supported features (web_search, code_execution, mcp, image_understanding, url_context), and builtin tools
API Params Handler
massgen/api_params_handler/_gemini_interactions_api_params_handler.py, massgen/api_params_handler/__init__.py
New GeminiInteractionsAPIParamsHandler for building Interactions API config with excluded params aggregation, provider tools building, param mapping (max_tokens → max_output_tokens), and tool_config validation
Agent Configuration
massgen/agent_config.py
Adds create_gemini_interactions_config classmethod to construct backend_params with model, API flags, polling interval, stream mode, and conditional tool enablement
Formatter Enhancement
massgen/formatter/_gemini_formatter.py
New format_tools_for_interactions_api method converting custom tools, MCP functions, and workflow tools into Interactions API format with error handling
CLI Integration
massgen/cli.py
Adds gemini_interactions backend branch in create_backend with API key resolution (GOOGLE_API_KEY or GEMINI_API_KEY environment variables)
Configuration Example
massgen/configs/tools/custom_tools/gemini_interactions_custom_tool_with_mcp.yaml
Example configuration demonstrating Gemini Interactions backend with custom two_num_tool and MCP weather server via stdio command
Dependencies
pyproject.toml, requirements.txt
Bumps google-genai from >=1.27.0 to >=1.55.0 for Interactions API compatibility

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant GeminiInteractionsBackend
    participant GenAIClient as google.genai.Client
    participant InteractionsAPI as Interactions API
    participant Tools as Tool Executor

    User->>GeminiInteractionsBackend: invoke with messages & tools
    GeminiInteractionsBackend->>GeminiInteractionsBackend: determine stream vs poll mode
    
    alt Streaming Mode
        GeminiInteractionsBackend->>GenAIClient: interactions.create (stream=True)
        GenAIClient->>InteractionsAPI: send streaming request
        loop Receive chunks
            InteractionsAPI->>GeminiInteractionsBackend: content/thought/tool_calls chunks
            GeminiInteractionsBackend->>GeminiInteractionsBackend: accumulate & emit chunks
            alt Tool Call Detected
                GeminiInteractionsBackend->>Tools: execute tool
                Tools->>GeminiInteractionsBackend: tool result
                GeminiInteractionsBackend->>GeminiInteractionsBackend: append to messages
            end
        end
    else Polling Mode
        GeminiInteractionsBackend->>GenAIClient: interactions.create (stream=False)
        GenAIClient->>InteractionsAPI: send polling request
        loop Poll with backoff
            GenAIClient->>InteractionsAPI: check interaction status
            InteractionsAPI-->>GenAIClient: response/pending
            alt Complete
                GeminiInteractionsBackend->>GeminiInteractionsBackend: process response
            else Pending + Retryable
                GeminiInteractionsBackend->>GeminiInteractionsBackend: exponential backoff wait
            end
            alt Tool Call in Response
                GeminiInteractionsBackend->>Tools: execute tool
                Tools->>GeminiInteractionsBackend: tool result
                GeminiInteractionsBackend->>GeminiInteractionsBackend: continue interaction
            end
        end
    end
    
    GeminiInteractionsBackend->>User: return final response with usage tracking
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Possibly related issues

  • [FEATURE] Add Gemini interactions API #622: Implementation of "Add Gemini interactions API" feature request — adds complete backend infrastructure with stateful conversation support, tool execution, streaming/polling modes, and MCP integration
🚥 Pre-merge checks | ✅ 3 | ❌ 3
❌ Failed checks (3 warnings)
Check name Status Explanation Resolution
Documentation Updated ⚠️ Warning PR adds Gemini Interactions API backend but lacks user-facing documentation in guides, API references, and YAML schema. Update user_guide/backends.rst, api/backends.rst, reference/yaml_schema.rst, and create design document in docs/dev_notes/.
Capabilities Registry Check ⚠️ Warning The test_capability_strings_are_valid() test fails because "url_context" is unsupported and missing pricing entries exist for six new gemini_interactions models. Add "url_context" to valid_capabilities, add URL_CONTEXT to Capability enum, fix gemini-2.5-flash-lite release date to "2025-07", and add pricing entries for all six new models.
Config Parameter Sync ⚠️ Warning Gemini Interactions-specific parameters are missing from base.py::get_base_excluded_config_params(). Add thinking_level, thinking_budget, include_thoughts, function_calling_mode, interactions_stream_mode, interactions_polling_interval, use_interactions_api, interactions_store, and gemini_backoff_* parameters to get_base_excluded_config_params().
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main change: adding the Gemini Interactions API as a new backend for the project.
Description check ✅ Passed The description includes the required sections (Description, Type of change, Checklist) and identifies the change type correctly, but lacks concrete details for testing sections and pre-commit output.
Docstring Coverage ✅ Passed Docstring coverage is 93.48% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 16

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
massgen/cli.py (2)

601-611: Docstring requirement mismatch: code accepts GEMINI_API_KEY too.

The supported-backend list says gemini_interactions ... requires GOOGLE_API_KEY, but the implementation also accepts GEMINI_API_KEY. Update the docstring (and ideally the CLI help text) to match actual behavior.


6298-6314: Add gemini_interactions to CLI --backend choices.

create_backend() supports gemini_interactions (documented in its docstring and fully implemented), but the argparse --backend argument choices don't include it. This prevents users from using massgen --backend gemini_interactions ... via CLI, even though it works via YAML config.

Proposed diff
         choices=[
             "chatcompletion",
             "claude",
             "gemini",
+            "gemini_interactions",
             "grok",
             "openai",
             "azure_openai",
             "claude_code",
             "zai",
             "lmstudio",
             "vllm",
             "sglang",
         ],
🤖 Fix all issues with AI agents
In @massgen/agent_config.py:
- Around line 465-501: The factory create_gemini_interactions_config currently
lets **kwargs override reserved backend params and doesn't validate
interactions_polling_interval; fix it by preventing overrides of reserved keys
(e.g., "type", "use_interactions_api", "model", "interactions_polling_interval",
"interactions_stream_mode", "enable_web_search", "enable_code_execution") —
either by removing those keys from kwargs before merging or by merging kwargs
first and then reassigning backend_params reserved keys to guaranteed values;
additionally validate interactions_polling_interval (ensure it's a positive
float > 0, raise ValueError otherwise) and then construct backend_params as
before so reserved values cannot be tampered with.

In @massgen/api_params_handler/_gemini_interactions_api_params_handler.py:
- Around line 48-71: The get_provider_tools method currently swallows all errors
when importing provider tool classes for enable_web_search and
enable_code_execution; change the broad excepts to catch ImportError and
AttributeError only (so genuine runtime bugs aren't hidden) and emit a single
warning/error log that includes the exception message and context (e.g.,
mentioning enable_web_search/enable_code_execution and
google.genai.types.Tool/GoogleSearch/ToolCodeExecution) so failures are visible
while still tolerating missing optional provider dependencies.
- Around line 11-47: Add a Google-style docstring to the
GeminiInteractionsAPIParamsHandler.get_excluded_params() method (e.g., """Get
parameters to exclude from Gemini Interactions API calls.""") and ensure the
newly listed YAML/config keys (thinking_level, thinking_budget,
include_thoughts, function_calling_mode, interactions_stream_mode,
interactions_polling_interval, interactions_store, use_multi_mcp, mcp_sdk_auto,
allowed_tools, exclude_tools, custom_tools, etc.) are present in the centralized
base exclusion lists by updating get_base_excluded_config_params() in
massgen/backend/base.py and get_base_excluded_params() in
massgen/api_params_handler/_api_params_handler_base.py so these config
parameters are handled by the backend and not forwarded to APIs.

In @massgen/backend/capabilities.py:
- Around line 287-293: The supported_capabilities set includes "url_context" but
the Capability enum lacks a matching member; add a new enum member named
URL_CONTEXT (or url_context consistent with the enum naming scheme) to the
Capability enum definition so that Capability includes this value and validation
against supported_capabilities succeeds; update any serialization/usage (e.g.,
when comparing strings or using Capability.<NAME>) to use the new Capability
member.
- Around line 296-314: In the model_release_dates mapping update the entry for
"gemini-2.5-flash-lite" from "2025-09" to "2025-07"; locate the
model_release_dates dict (used alongside models, default_model, env_var) and
change the value for the "gemini-2.5-flash-lite" key to "2025-07" to reflect the
correct July 22, 2025 release date.

In @massgen/backend/gemini_interactions.py:
- Around line 177-189: The __init__ docstring in GeminiInteractions is broken by
a line-split in the configuration description ("State pe" / "rsistence"); fix
the docstring by merging the split word into "state persistence", ensure the
interactions_store bullet accurately reads "interactions_store: State
persistence for stateful conversations (bool, default True)" and verify other
bullets (interactions_stream_mode, interactions_polling_interval,
gemini_backoff_*) remain clear and correctly formatted so generated docs and IDE
hovers render properly.
- Around line 1675-1724: In _append_tool_result_message the code treats any
falsy result (0, False, "", etc.) as missing by using `if result`; change the
logic to only treat None as missing so legitimate falsy values are preserved
(i.e., set result_str to "No result" only when result is None, otherwise use
str(result)); update the assignment in _append_tool_result_message accordingly,
keeping the rest of the behavior (storing in self._active_tool_result_store and
appending to updated_messages) unchanged.
- Around line 171-176: The AGENT_PATTERNS class attribute in
GeminiInteractionsBackend should be annotated as a ClassVar and use an immutable
tuple; import ClassVar (and Tuple if needed for older Python) from typing and
change the declaration of AGENT_PATTERNS on the GeminiInteractionsBackend class
to have a type annotation like ClassVar[tuple[str, ...]] (or ClassVar[Tuple[str,
...]]), and set its value to a tuple instead of a list containing
"deep-research", "deep-research-pro", "deep-research-pro-preview".
- Around line 805-1674: The system message is being included twice because
stream_with_tools calls self.formatter.format_messages(messages) (which already
prepends system messages per GeminiFormatter.format_messages) and then later
extracts system_message and either sets interaction_params["system_instruction"]
or prepends it again to interaction_params["input"]; fix by building
full_content from messages with system roles removed (e.g., pass a filtered list
to self.formatter.format_messages or call a helper like messages_no_system = [m
for m in messages if m.get("role") != "system"]) and then only set
interaction_params["system_instruction"] when supports_system_instruction is
True (otherwise prepend the single system_message once to the filtered input),
updating usages of full_content and log_backend_agent_message accordingly to
avoid duplicate instructions.
- Around line 1774-1818: The code in _cleanup_genai_resources currently reaches
into client._api_client._aiohttp_session to close aiohttp sessions; instead call
the public async API await client.aio.aclose() to close the client's internal
transport/session. Replace the block that inspects base_client/_aiohttp_session
with a try/except that awaits client.aio.aclose(), logs success or failure via
log_backend_activity (using the same messages), and optionally await
asyncio.sleep(0) after success to yield control; retain the surrounding
defensive checks for client and existing _try_close_resource calls for other
parts.
- Around line 325-448: In _interactions_create_with_backoff and
_interactions_get_with_backoff you catch broad exceptions but do not preserve
stack traces on the non-retryable path—change the non-retryable branch to log
the error with exc_info=True or use logger.exception (e.g., replace
logger.error(...) with logger.exception(...)) so the trace is kept before
re-raising; additionally, in _interactions_get_with_backoff you unpack
status_code but never use it—either include status_code in the
log_backend_activity payload for the "Rate limited on get, backing off" entry or
rename the returned variable to _status_code to silence the unused-variable
warning.
- Around line 42-52: The module currently adds the NoFunctionCallWarning filter
unconditionally via
logging.getLogger("google_genai.types").addFilter(NoFunctionCallWarning()),
causing a process-wide side effect and potential duplication; guard this call
with the existing GENAI_AVAILABLE boolean (e.g., if GENAI_AVAILABLE:
logging.getLogger("google_genai.types").addFilter(NoFunctionCallWarning())) or
move NoFunctionCallWarning into a shared utility and apply it only when
GENAI_AVAILABLE is true, ensuring you reference the same NoFunctionCallWarning
class and the logging.getLogger("google_genai.types").addFilter invocation so
the filter is only registered when the google-genai SDK is present and to avoid
duplicating the logic also found in the other Gemini backend module.

In @massgen/cli.py:
- Around line 674-679: The branch handling backend_type == "gemini_interactions"
should update the API-key error message to reference both GOOGLE_API_KEY and
GEMINI_API_KEY and remove the potential duplicate api_key in kwargs before
constructing the backend; do this by building api_key from kwargs.get("api_key")
or os.getenv("GOOGLE_API_KEY") or os.getenv("GEMINI_API_KEY"), using
kwargs.pop("api_key", None) to remove any incoming api_key before calling
GeminiInteractionsBackend, and call _api_key_error_message("Gemini
Interactions", "GOOGLE_API_KEY", "GEMINI_API_KEY", config_path) (or otherwise
include both env names in the error text) when raising ConfigurationError.

In @massgen/formatter/_gemini_formatter.py:
- Around line 55-127: In format_tools_for_interactions_api, avoid adding tools
with empty names, dedupe by tool name, and improve exception logging: maintain a
seen_names set and before appending any tool (in the workflow_tools,
custom_tools, and mcp_functions branches) skip if the resolved name is falsy or
already in seen_names; when converting mcp_functions replace the broad
try/except with a narrower except (e.g., AttributeError, TypeError) and call
logger.exception(...) to preserve stack traces; ensure you use the same name
extraction logic (func_def.get("name", "") or getattr(..., "name", "")) and add
the valid name to seen_names only when you append the tool.
🧹 Nitpick comments (2)
massgen/cli.py (1)

54-55: Consider lazy-importing the experimental backend to avoid hard CLI import-time failures.

If gemini_interactions is optional/experimental, importing it at module import time can break massgen even when users never select that backend (e.g., missing optional deps). A local import inside the gemini_interactions branch keeps failures scoped.

Proposed diff
-from .backend.gemini_interactions import GeminiInteractionsBackend
massgen/api_params_handler/_gemini_interactions_api_params_handler.py (1)

73-115: API field names and ToolConfig usage are correct; unused messages/tools are intentional per interface contract.

The Interactions API parameter mapping is sound: max_tokensmax_output_tokens is correct, model exclusion is correct, and ToolConfig(function_calling_config=FunctionCallingConfig(mode=...)) with valid modes {"AUTO", "ANY", "NONE"} matches the google-genai SDK.

The unused messages and tools parameters exist because build_api_params() inherits its signature from APIParamsHandlerBase (the abstract base class all handlers must implement). For the Interactions API, these parameters are intentionally not used here—tools are converted separately in the backend, and messages are transformed into input elsewhere before the API call. While renaming to _messages/_tools would clarify intent, it would require breaking the ABC interface contract.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1fdc710 and dad7fcf.

📒 Files selected for processing (11)
  • massgen/agent_config.py
  • massgen/api_params_handler/__init__.py
  • massgen/api_params_handler/_gemini_interactions_api_params_handler.py
  • massgen/backend/__init__.py
  • massgen/backend/capabilities.py
  • massgen/backend/gemini_interactions.py
  • massgen/cli.py
  • massgen/configs/tools/custom_tools/gemini_interactions_custom_tool_with_mcp.yaml
  • massgen/formatter/_gemini_formatter.py
  • pyproject.toml
  • requirements.txt
🧰 Additional context used
📓 Path-based instructions (6)
**/*.py

📄 CodeRabbit inference engine (Custom checks)

For new or changed functions, include Google-style docstrings

Files:

  • massgen/formatter/_gemini_formatter.py
  • massgen/agent_config.py
  • massgen/backend/capabilities.py
  • massgen/api_params_handler/_gemini_interactions_api_params_handler.py
  • massgen/cli.py
  • massgen/backend/gemini_interactions.py
  • massgen/api_params_handler/__init__.py
  • massgen/backend/__init__.py
massgen/**/*.py

⚙️ CodeRabbit configuration file

massgen/**/*.py: Review Python code for:

  • PEP 8 compliance and Google-style docstrings
  • Proper async/await patterns
  • Type hints where appropriate
  • No security vulnerabilities (command injection, etc.)
  • Consistency with existing code patterns

Files:

  • massgen/formatter/_gemini_formatter.py
  • massgen/agent_config.py
  • massgen/backend/capabilities.py
  • massgen/api_params_handler/_gemini_interactions_api_params_handler.py
  • massgen/cli.py
  • massgen/backend/gemini_interactions.py
  • massgen/api_params_handler/__init__.py
  • massgen/backend/__init__.py
massgen/backend/capabilities.py

📄 CodeRabbit inference engine (Custom checks)

If backend or model changes are detected, check that massgen/backend/capabilities.py is updated with new models/capabilities

When adding new models, update massgen/backend/capabilities.py with the model in models list (newest first), model_release_dates, and supported_capabilities if new features

Files:

  • massgen/backend/capabilities.py
massgen/backend/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

When adding new backends, create backend/new_provider.py inheriting from base, register in backend/init.py, add model mappings to massgen/utils.py, add capabilities to backend/capabilities.py, and update config_validator.py

Files:

  • massgen/backend/capabilities.py
  • massgen/backend/gemini_interactions.py
  • massgen/backend/__init__.py
massgen/backend/**/*.py

⚙️ CodeRabbit configuration file

massgen/backend/**/*.py: Backend code review - CHECK FOR THESE UPDATES:

  1. If adding new model support → ensure massgen/backend/capabilities.py is updated
  2. If adding new capabilities → update supported_capabilities in capabilities.py
  3. Verify inheritance from base classes is correct
  4. Check streaming buffer usage where applicable
  5. Ensure error handling follows existing patterns

Files:

  • massgen/backend/capabilities.py
  • massgen/backend/gemini_interactions.py
  • massgen/backend/__init__.py
massgen/configs/**/*.yaml

📄 CodeRabbit inference engine (Custom checks)

For new config options, include example YAML in massgen/configs/

For new config options, add example YAML in massgen/configs/

Files:

  • massgen/configs/tools/custom_tools/gemini_interactions_custom_tool_with_mcp.yaml

⚙️ CodeRabbit configuration file

massgen/configs/**/*.yaml: Validate YAML configs follow MassGen conventions:

  1. Property placement: cwd at BACKEND-level, context_paths at ORCHESTRATOR-level
  2. Prefer cost-effective models (gpt-5-nano, gpt-5-mini, gemini-2.5-flash)
  3. All agents should have identical system_message for multi-agent setups
  4. Never reference legacy paths or massgen v1
  5. Include "What happens" comments explaining execution flow

Files:

  • massgen/configs/tools/custom_tools/gemini_interactions_custom_tool_with_mcp.yaml
🧠 Learnings (14)
📚 Learning: 2026-01-07T03:57:17.450Z
Learnt from: CR
Repo: massgen/MassGen PR: 0
File: docs/dev_notes/release_checklist.md:0-0
Timestamp: 2026-01-07T03:57:17.450Z
Learning: Applies to docs/dev_notes/massgen/backend/capabilities.py : Update `massgen/backend/capabilities.py` to document backend capability support for new features in the BACKEND_CAPABILITIES registry

Applied to files:

  • massgen/backend/capabilities.py
  • massgen/cli.py
  • massgen/backend/gemini_interactions.py
  • massgen/backend/__init__.py
📚 Learning: 2026-01-07T03:58:49.411Z
Learnt from: CR
Repo: massgen/MassGen PR: 0
File: coderabbit-custom-pre-merge-checks-unique-id-file-non-traceable-F7F2B60C-1728-4C9A-8889-4F2235E186CA.txt:0-0
Timestamp: 2026-01-07T03:58:49.411Z
Learning: Applies to massgen/backend/capabilities.py : If backend or model changes are detected, check that massgen/backend/capabilities.py is updated with new models/capabilities

Applied to files:

  • massgen/backend/capabilities.py
  • massgen/cli.py
  • massgen/backend/gemini_interactions.py
  • massgen/backend/__init__.py
📚 Learning: 2026-01-09T18:46:48.438Z
Learnt from: CR
Repo: massgen/MassGen PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-09T18:46:48.438Z
Learning: Applies to massgen/backend/capabilities.py : When adding new models, update massgen/backend/capabilities.py with the model in models list (newest first), model_release_dates, and supported_capabilities if new features

Applied to files:

  • massgen/backend/capabilities.py
📚 Learning: 2026-01-09T18:46:48.438Z
Learnt from: CR
Repo: massgen/MassGen PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-09T18:46:48.438Z
Learning: Applies to massgen/backend/capabilities.py|massgen/token_manager/token_manager.py : For new models, update massgen/backend/capabilities.py and massgen/token_manager/token_manager.py

Applied to files:

  • massgen/backend/capabilities.py
  • massgen/cli.py
📚 Learning: 2026-01-09T18:46:48.438Z
Learnt from: CR
Repo: massgen/MassGen PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-09T18:46:48.438Z
Learning: Applies to massgen/backend/*.py : When adding new backends, create backend/new_provider.py inheriting from base, register in backend/__init__.py, add model mappings to massgen/utils.py, add capabilities to backend/capabilities.py, and update config_validator.py

Applied to files:

  • massgen/backend/capabilities.py
  • massgen/cli.py
  • massgen/backend/__init__.py
📚 Learning: 2026-01-07T03:58:49.411Z
Learnt from: CR
Repo: massgen/MassGen PR: 0
File: coderabbit-custom-pre-merge-checks-unique-id-file-non-traceable-F7F2B60C-1728-4C9A-8889-4F2235E186CA.txt:0-0
Timestamp: 2026-01-07T03:58:49.411Z
Learning: Applies to massgen/api_params_handler/_api_params_handler_base.py : If new YAML parameters are added, verify massgen/api_params_handler/_api_params_handler_base.py → get_base_excluded_config_params() is updated

Applied to files:

  • massgen/api_params_handler/_gemini_interactions_api_params_handler.py
  • massgen/api_params_handler/__init__.py
📚 Learning: 2026-01-09T18:46:48.438Z
Learnt from: CR
Repo: massgen/MassGen PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-09T18:46:48.438Z
Learning: Applies to massgen/backend/base.py|massgen/api_params_handler/_api_params_handler_base.py : When adding new YAML parameters, update both massgen/backend/base.py → get_base_excluded_config_params() and massgen/api_params_handler/_api_params_handler_base.py → get_base_excluded_config_params()

Applied to files:

  • massgen/api_params_handler/_gemini_interactions_api_params_handler.py
  • massgen/api_params_handler/__init__.py
📚 Learning: 2026-01-07T03:58:49.411Z
Learnt from: CR
Repo: massgen/MassGen PR: 0
File: coderabbit-custom-pre-merge-checks-unique-id-file-non-traceable-F7F2B60C-1728-4C9A-8889-4F2235E186CA.txt:0-0
Timestamp: 2026-01-07T03:58:49.411Z
Learning: Applies to massgen/backend/base.py : If new YAML parameters are added, verify massgen/backend/base.py → get_base_excluded_config_params() is updated

Applied to files:

  • massgen/api_params_handler/_gemini_interactions_api_params_handler.py
📚 Learning: 2026-01-09T18:46:48.438Z
Learnt from: CR
Repo: massgen/MassGen PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-09T18:46:48.438Z
Learning: Applies to massgen/tool/**/TOOL.md : Custom tools in massgen/tool/ require TOOL.md with YAML frontmatter including name, description, category, requires_api_keys, tasks, and keywords

Applied to files:

  • massgen/configs/tools/custom_tools/gemini_interactions_custom_tool_with_mcp.yaml
📚 Learning: 2026-01-07T03:57:17.450Z
Learnt from: CR
Repo: massgen/MassGen PR: 0
File: docs/dev_notes/release_checklist.md:0-0
Timestamp: 2026-01-07T03:57:17.450Z
Learning: Applies to docs/dev_notes/massgen/config_builder.py : Update `massgen/config_builder.py` to add new YAML parameters to interactive wizard, parameter validation, and help text when new configuration options are added

Applied to files:

  • massgen/configs/tools/custom_tools/gemini_interactions_custom_tool_with_mcp.yaml
  • massgen/cli.py
📚 Learning: 2026-01-07T03:57:17.450Z
Learnt from: CR
Repo: massgen/MassGen PR: 0
File: docs/dev_notes/release_checklist.md:0-0
Timestamp: 2026-01-07T03:57:17.450Z
Learning: Applies to docs/dev_notes/massgen/configs/*.yaml : Create example YAML configuration files in `massgen/configs/` organized by category (basic, tools, teams, providers) and test each configuration

Applied to files:

  • massgen/configs/tools/custom_tools/gemini_interactions_custom_tool_with_mcp.yaml
📚 Learning: 2026-01-07T03:58:40.713Z
Learnt from: CR
Repo: massgen/MassGen PR: 0
File: docs/source/development/writing_configs.rst:0-0
Timestamp: 2026-01-07T03:58:40.713Z
Learning: Applies to docs/source/development/examples/tools/**/*.yaml : Use cost-effective default models per agent (e.g., gpt-5-mini, gpt-5-nano, gemini-2.5-flash) unless a feature requires otherwise

Applied to files:

  • massgen/configs/tools/custom_tools/gemini_interactions_custom_tool_with_mcp.yaml
📚 Learning: 2026-01-09T18:46:48.438Z
Learnt from: CR
Repo: massgen/MassGen PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-09T18:46:48.438Z
Learning: Applies to massgen/tests/**/*.py : When creating integration tests for backend functionality, test across all 5 standard backends: Claude, OpenAI, Gemini, OpenRouter, and Grok

Applied to files:

  • massgen/cli.py
  • massgen/backend/gemini_interactions.py
  • massgen/backend/__init__.py
📚 Learning: 2026-01-07T03:58:40.713Z
Learnt from: CR
Repo: massgen/MassGen PR: 0
File: docs/source/development/writing_configs.rst:0-0
Timestamp: 2026-01-07T03:58:40.713Z
Learning: Applies to docs/source/development/examples/tools/**/*.yaml : Use cost-effective backends (e.g., Gemini Flash, GPT-5-mini) unless specific features are needed

Applied to files:

  • massgen/cli.py
🧬 Code graph analysis (5)
massgen/api_params_handler/_gemini_interactions_api_params_handler.py (1)
massgen/api_params_handler/_api_params_handler_base.py (2)
  • APIParamsHandlerBase (13-146)
  • get_base_excluded_params (52-123)
massgen/cli.py (2)
massgen/backend/gemini_interactions.py (1)
  • GeminiInteractionsBackend (171-1828)
massgen/v1/config.py (1)
  • ConfigurationError (24-25)
massgen/backend/gemini_interactions.py (6)
massgen/formatter/_gemini_formatter.py (8)
  • has_coordination_tools (183-204)
  • has_post_evaluation_tools (206-219)
  • format_messages (17-47)
  • build_structured_output_prompt (221-296)
  • build_post_evaluation_prompt (298-323)
  • format_tools_for_interactions_api (55-127)
  • extract_structured_response (325-405)
  • convert_structured_to_tool_calls (407-486)
massgen/logger_config.py (4)
  • log_backend_activity (719-742)
  • log_backend_agent_message (674-716)
  • log_stream_chunk (839-887)
  • log_tool_call (767-808)
massgen/backend/base.py (2)
  • FilesystemSupport (28-33)
  • StreamChunk (37-60)
massgen/mcp_tools/exceptions.py (4)
  • MCPConnectionError (94-128)
  • MCPError (12-91)
  • MCPServerError (131-162)
  • MCPTimeoutError (208-239)
massgen/api_params_handler/_gemini_interactions_api_params_handler.py (1)
  • GeminiInteractionsAPIParamsHandler (11-115)
massgen/mcp_tools/client.py (1)
  • session (168-175)
massgen/api_params_handler/__init__.py (1)
massgen/api_params_handler/_gemini_interactions_api_params_handler.py (1)
  • GeminiInteractionsAPIParamsHandler (11-115)
massgen/backend/__init__.py (1)
massgen/backend/gemini_interactions.py (1)
  • GeminiInteractionsBackend (171-1828)
🪛 Ruff (0.14.10)
massgen/formatter/_gemini_formatter.py

123-123: Do not catch blind exception: Exception

(BLE001)


124-124: Use logging.exception instead of logging.error

Replace with exception

(TRY400)

massgen/api_params_handler/_gemini_interactions_api_params_handler.py

57-58: try-except-pass detected, consider logging the exception

(S110)


57-57: Do not catch blind exception: Exception

(BLE001)


65-66: try-except-pass detected, consider logging the exception

(S110)


65-65: Do not catch blind exception: Exception

(BLE001)


75-75: Unused method argument: messages

(ARG002)


76-76: Unused method argument: tools

(ARG002)

massgen/backend/gemini_interactions.py

175-175: Mutable class attributes should be annotated with typing.ClassVar

(RUF012)


258-260: Avoid specifying long messages outside the exception class

(TRY003)


286-286: Unused method argument: stream

(ARG002)


286-286: Unused method argument: all_params

(ARG002)


286-286: Unused method argument: agent_id

(ARG002)


305-305: Unused method argument: current_messages

(ARG002)


306-306: Unused method argument: tools

(ARG002)


307-307: Unused method argument: client

(ARG002)


308-308: Unused method argument: kwargs

(ARG002)


362-362: Standard pseudo-random generators are not suitable for cryptographic purposes

(S311)


407-407: Unpacked variable status_code is never used

Prefix it with an underscore or any other dummy variable pattern

(RUF059)


427-427: Standard pseudo-random generators are not suitable for cryptographic purposes

(S311)


696-696: Consider moving this statement to an else block

(TRY300)


700-700: Use explicit conversion flag

Replace with conversion flag

(RUF010)


758-758: Abstract raise to an inner function

(TRY301)


758-758: Create your own exception

(TRY002)


758-758: Avoid specifying long messages outside the exception class

(TRY003)


769-769: Abstract raise to an inner function

(TRY301)


769-769: Create your own exception

(TRY002)


769-769: Avoid specifying long messages outside the exception class

(TRY003)


802-802: Use explicit conversion flag

Replace with conversion flag

(RUF010)


851-853: Abstract raise to an inner function

(TRY301)


851-853: Avoid specifying long messages outside the exception class

(TRY003)


975-975: Do not catch blind exception: Exception

(BLE001)


1023-1023: Do not catch blind exception: Exception

(BLE001)


1073-1073: Unnecessary key check before dictionary access

Replace with dict.get

(RUF019)


1078-1078: Unnecessary key check before dictionary access

Replace with dict.get

(RUF019)


1542-1542: Abstract raise to an inner function

(TRY301)


1542-1542: Create your own exception

(TRY002)


1542-1542: Avoid specifying long messages outside the exception class

(TRY003)


1565-1565: Do not catch blind exception: Exception

(BLE001)


1567-1567: Use explicit conversion flag

Replace with conversion flag

(RUF010)


1680-1680: Unused method argument: tool_type

(ARG002)


1708-1708: Unused method argument: tool_type

(ARG002)


1763-1763: Consider moving this statement to an else block

(TRY300)


1764-1764: Do not catch blind exception: Exception

(BLE001)


1800-1800: Do not catch blind exception: Exception

(BLE001)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (11)
  • GitHub Check: pre-commit (ubuntu-latest, 3.10)
  • GitHub Check: pre-commit (ubuntu-latest, 3.11)
  • GitHub Check: pre-commit (macos-14, 3.12)
  • GitHub Check: pre-commit (ubuntu-latest, 3.12)
  • GitHub Check: pre-commit (ubuntu-latest, 3.10)
  • GitHub Check: pre-commit (ubuntu-latest, 3.11)
  • GitHub Check: pre-commit (macos-14, 3.10)
  • GitHub Check: pre-commit (macos-latest, 3.12)
  • GitHub Check: pre-commit (macos-14, 3.11)
  • GitHub Check: pre-commit (ubuntu-latest, 3.12)
  • GitHub Check: pre-commit (macos-latest, 3.10)
🔇 Additional comments (8)
requirements.txt (1)

7-7: Dependency version is consistent with pyproject.toml.

The google-genai version upgrade to >=1.55.0 matches the change in pyproject.toml. Please see the verification comment in pyproject.toml for version and security checks.

massgen/backend/capabilities.py (1)

284-315: Backend capabilities entry follows the correct pattern.

The new gemini_interactions backend entry is well-structured and includes all required fields (backend_type, provider_name, supported_capabilities, builtin_tools, filesystem_support, models, default_model, env_var, notes, model_release_dates). The default_model is correctly included in the models list.

Based on learnings, this correctly updates massgen/backend/capabilities.py with the new backend's models and capabilities.

massgen/api_params_handler/__init__.py (1)

8-8: Import and export of GeminiInteractionsAPIParamsHandler is correct.

The import from ._gemini_interactions_api_params_handler and export in __all__ follows the established pattern for other API params handlers. The class implementation is confirmed in the relevant code snippets.

Also applies to: 17-17

massgen/backend/__init__.py (2)

28-28: Import and export of GeminiInteractionsBackend is correct.

The import from .gemini_interactions and export in __all__ follows the established pattern for other backends. The backend implementation is confirmed in the relevant code snippets.

Based on learnings, this correctly registers the new backend in backend/init.py as required.

Also applies to: 54-54


28-28: Update not required — GeminiInteractionsBackend is already properly registered.

The backend has been correctly integrated: GeminiInteractionsBackend is imported and exported in __init__.py, fully defined in backend/capabilities.py with all model mappings and support details, and properly handled in cli.py. The backend registration follows the codebase pattern where capabilities and model mappings are managed through backend/capabilities.py rather than the files mentioned in the review.

Likely an incorrect or invalid review comment.

pyproject.toml (1)

35-35: No action needed—version 1.55.0 is valid and secure.

The upgrade from google-genai>=1.27.0 to google-genai>=1.55.0 is justified. Version 1.55.0 exists on PyPI, contains no known vulnerabilities, and improves the security baseline (the only historical data exposure issue was fixed in 1.26.0). The new constraint is appropriately conservative—it's not the bleeding-edge 1.57.0, but a stable, well-tested release.

massgen/configs/tools/custom_tools/gemini_interactions_custom_tool_with_mcp.yaml (1)

4-18: The name and function fields in custom_tools correctly use list format for gemini_interactions backend. Other Gemini backends and OpenAI-compatible backends use the same list format; Claude backends use string format instead. The configuration is consistent with existing examples like gemini_custom_tool_with_mcp_example.yaml.

Likely an incorrect or invalid review comment.

massgen/agent_config.py (1)

465-501: Parameter names are correct; confirm model value is acceptable for agent-based workflows.

The parameter names (use_interactions_api, interactions_stream_mode, interactions_polling_interval) are correctly expected by the backend and are properly consumed in gemini_interactions.py (lines 200–201). These match the API params handler and are valid for the Interactions API.

However, the default model "deep-research-pro-preview-12-2025" could not be externally validated. Given the docstring explicitly allows "Model or agent name" and this is marked EXPERIMENTAL, ensure this string is a valid agent identifier in your environment or document it as requiring explicit override.

Comment on lines +465 to +501
@classmethod
def create_gemini_interactions_config(
cls,
model: str = "deep-research-pro-preview-12-2025",
enable_web_search: bool = False,
enable_code_execution: bool = False,
interactions_stream_mode: Optional[bool] = None,
interactions_polling_interval: float = 2.0,
**kwargs,
) -> "AgentConfig":
"""Create Google Gemini Interactions API configuration (EXPERIMENTAL).
Args:
model: Model or agent name (agents use polling, models use streaming by default)
enable_web_search: Enable Google Search retrieval tool
enable_code_execution: Enable code execution tool
interactions_stream_mode: Override execution mode (None = auto-detect)
interactions_polling_interval: Polling interval in seconds (default: 2.0)
**kwargs: Additional backend parameters
"""
backend_params = {
"type": "gemini_interactions",
"model": model,
"use_interactions_api": True,
"interactions_polling_interval": interactions_polling_interval,
**kwargs,
}

if interactions_stream_mode is not None:
backend_params["interactions_stream_mode"] = interactions_stream_mode

if enable_web_search:
backend_params["enable_web_search"] = True
if enable_code_execution:
backend_params["enable_code_execution"] = True

return cls(backend_params=backend_params)
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Prevent **kwargs from overriding reserved backend params + validate polling interval.
Right now **kwargs can silently override "type", "use_interactions_api", and the interactions settings, which is risky for a factory method.

Proposed patch
 @classmethod
 def create_gemini_interactions_config(
@@
     **kwargs,
 ) -> "AgentConfig":
-    """Create Google Gemini Interactions API configuration (EXPERIMENTAL).
+    """Create Google Gemini Interactions API configuration (EXPERIMENTAL).
@@
-    """
+    
+    Returns:
+        AgentConfig: An agent configuration with a Gemini Interactions backend.
+
+    Raises:
+        ValueError: If polling interval is non-positive or reserved keys are passed via kwargs.
+    """
+    if interactions_polling_interval <= 0:
+        raise ValueError(
+            f"interactions_polling_interval must be > 0, got {interactions_polling_interval}"
+        )
+
+    reserved = {
+        "type",
+        "model",
+        "use_interactions_api",
+        "interactions_polling_interval",
+        "interactions_stream_mode",
+        "enable_web_search",
+        "enable_code_execution",
+    }
+    collisions = reserved.intersection(kwargs.keys())
+    if collisions:
+        raise ValueError(
+            "Do not pass reserved backend params via kwargs: "
+            + ", ".join(sorted(collisions))
+        )
+
     backend_params = {
         "type": "gemini_interactions",
         "model": model,
         "use_interactions_api": True,
         "interactions_polling_interval": interactions_polling_interval,
         **kwargs,
     }
🤖 Prompt for AI Agents
In @massgen/agent_config.py around lines 465 - 501, The factory
create_gemini_interactions_config currently lets **kwargs override reserved
backend params and doesn't validate interactions_polling_interval; fix it by
preventing overrides of reserved keys (e.g., "type", "use_interactions_api",
"model", "interactions_polling_interval", "interactions_stream_mode",
"enable_web_search", "enable_code_execution") — either by removing those keys
from kwargs before merging or by merging kwargs first and then reassigning
backend_params reserved keys to guaranteed values; additionally validate
interactions_polling_interval (ensure it's a positive float > 0, raise
ValueError otherwise) and then construct backend_params as before so reserved
values cannot be tampered with.

Comment on lines +11 to +47
class GeminiInteractionsAPIParamsHandler(APIParamsHandlerBase):
"""API params handler for Gemini Interactions API."""

def get_excluded_params(self) -> Set[str]:
base = self.get_base_excluded_params()
extra = {
"enable_web_search",
"enable_google_search",
"enable_code_execution",
"enable_url_context",
"use_interactions_api",
"interactions_polling_interval",
"interactions_stream_mode",
"interactions_store",
"function_calling_mode",
"use_multi_mcp",
"mcp_sdk_auto",
"allowed_tools",
"exclude_tools",
"custom_tools",
"enable_file_generation",
"enable_image_generation",
"enable_audio_generation",
"enable_video_generation",
"gemini_backoff_max_attempts",
"gemini_backoff_initial_delay",
"gemini_backoff_multiplier",
"gemini_backoff_max_delay",
"gemini_backoff_jitter",
"thinking_level",
"thinking_budget",
"include_thoughts",
"response_format",
"response_modalities",
}
return set(base) | extra

Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Step 1: Find base exclusion list methods ==="
rg -n "def get_base_excluded_params|def get_base_excluded_config_params" massgen/backend massgen/api_params_handler --type py || echo "No matches found"

echo -e "\n=== Step 2: Search for new config keys in YAML files ==="
rg -n --glob='**/*.yml' --glob='**/*.yaml' \
  "gemini_backoff_|thinking_level|thinking_budget|include_thoughts|function_calling_mode|interactions_stream_mode|interactions_polling_interval|interactions_store|use_interactions_api" \
  massgen || echo "No YAML matches found"

echo -e "\n=== Step 3: Check the actual file for docstring ==="
cat -n massgen/api_params_handler/_gemini_interactions_api_params_handler.py | head -20

echo -e "\n=== Step 4: Look at APIParamsHandlerBase to understand inheritance ==="
rg -A 5 "def get_excluded_params" massgen/api_params_handler/_api_params_handler_base.py

Repository: massgen/MassGen

Length of output: 1796


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Step 5: Examine base exclusion lists in detail ==="
echo "--- massgen/backend/base.py get_base_excluded_config_params() ---"
sed -n '232,280p' massgen/backend/base.py

echo -e "\n--- massgen/api_params_handler/_api_params_handler_base.py get_base_excluded_params() ---"
sed -n '52,120p' massgen/api_params_handler/_api_params_handler_base.py

echo -e "\n=== Step 6: Check if new keys like thinking_level, thinking_budget, include_thoughts are in base lists ==="
rg -n "thinking_level|thinking_budget|include_thoughts|interactions_stream_mode|function_calling_mode" \
  massgen/backend/base.py massgen/api_params_handler/_api_params_handler_base.py || echo "No matches in base files"

Repository: massgen/MassGen

Length of output: 5584


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Step 7: Check other API handler implementations for pattern ==="
find massgen/api_params_handler -name "*_params_handler.py" -type f | head -5

echo -e "\n=== Step 8: Look at one other handler to understand docstring pattern ==="
cat -n massgen/api_params_handler/_openai_api_params_handler.py | head -25

Repository: massgen/MassGen

Length of output: 613


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Step 8: Look at existing handler for docstring pattern ==="
cat -n massgen/api_params_handler/_claude_api_params_handler.py | head -30

echo -e "\n=== Step 9: Verify if thinking_level, thinking_budget, include_thoughts are new YAML parameters ==="
rg -n "thinking_level|thinking_budget|include_thoughts" massgen --type py -B 2 -A 2 | head -40

Repository: massgen/MassGen

Length of output: 5219


🏁 Script executed:

#!/bin/bash
set -eulo pipefail

echo "=== Step 10: Check if thinking_level/thinking_budget/include_thoughts appear in other handlers ==="
rg -n "thinking_level|thinking_budget" massgen/api_params_handler --type py

echo -e "\n=== Step 11: Check docstring pattern across all API handlers ==="
rg -A 1 "def get_excluded_params" massgen/api_params_handler --type py -B 1

Repository: massgen/MassGen

Length of output: 2879


Add Google-style docstring to get_excluded_params() method.

The method at line 14 is missing a docstring. All other API handlers follow the pattern: """Get parameters to exclude from X API calls."""

Additionally, verify that the new YAML parameters excluded here (thinking_level, thinking_budget, include_thoughts, function_calling_mode, interactions_stream_mode, etc.) are reflected in the base exclusion lists (massgen/backend/base.pyget_base_excluded_config_params() and massgen/api_params_handler/_api_params_handler_base.pyget_base_excluded_params()). These are config parameters handled specially by the backend and may need to be added to the base exclusion lists to prevent accidental API pass-through.

🤖 Prompt for AI Agents
In @massgen/api_params_handler/_gemini_interactions_api_params_handler.py around
lines 11 - 47, Add a Google-style docstring to the
GeminiInteractionsAPIParamsHandler.get_excluded_params() method (e.g., """Get
parameters to exclude from Gemini Interactions API calls.""") and ensure the
newly listed YAML/config keys (thinking_level, thinking_budget,
include_thoughts, function_calling_mode, interactions_stream_mode,
interactions_polling_interval, interactions_store, use_multi_mcp, mcp_sdk_auto,
allowed_tools, exclude_tools, custom_tools, etc.) are present in the centralized
base exclusion lists by updating get_base_excluded_config_params() in
massgen/backend/base.py and get_base_excluded_params() in
massgen/api_params_handler/_api_params_handler_base.py so these config
parameters are handled by the backend and not forwarded to APIs.

Comment on lines +48 to +71
def get_provider_tools(self, all_params: Dict[str, Any]) -> List[Any]:
"""Get provider-specific builtin tools."""
tools: List[Any] = []

if all_params.get("enable_web_search", False):
try:
from google.genai.types import GoogleSearch, Tool

tools.append(Tool(google_search=GoogleSearch()))
except Exception:
pass

if all_params.get("enable_code_execution", False):
try:
from google.genai.types import Tool, ToolCodeExecution

tools.append(Tool(code_execution=ToolCodeExecution()))
except Exception:
pass

if all_params.get("enable_url_context", False):
tools.append({"type": "url_context"})

return tools
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Don’t silently ignore provider-tool import/config errors.

  • Line 53-58 / 61-66: except Exception: pass makes enable_web_search / enable_code_execution failures invisible (matches Ruff S110/BLE001). Prefer catching ImportError (and maybe AttributeError) and logging once.
Proposed diff (narrow exceptions + log)
@@
     def get_provider_tools(self, all_params: Dict[str, Any]) -> List[Any]:
         """Get provider-specific builtin tools."""
         tools: List[Any] = []
 
         if all_params.get("enable_web_search", False):
             try:
                 from google.genai.types import GoogleSearch, Tool
-
                 tools.append(Tool(google_search=GoogleSearch()))
-            except Exception:
-                pass
+            except ImportError:
+                # Keep this non-fatal, but debuggable.
+                from ..logger_config import logger
+                logger.warning("[GeminiInteractions] google.genai.types unavailable; web_search tool disabled")
 
         if all_params.get("enable_code_execution", False):
             try:
                 from google.genai.types import Tool, ToolCodeExecution
-
                 tools.append(Tool(code_execution=ToolCodeExecution()))
-            except Exception:
-                pass
+            except ImportError:
+                from ..logger_config import logger
+                logger.warning("[GeminiInteractions] google.genai.types unavailable; code_execution tool disabled")
🧰 Tools
🪛 Ruff (0.14.10)

57-58: try-except-pass detected, consider logging the exception

(S110)


57-57: Do not catch blind exception: Exception

(BLE001)


65-66: try-except-pass detected, consider logging the exception

(S110)


65-65: Do not catch blind exception: Exception

(BLE001)

🤖 Prompt for AI Agents
In @massgen/api_params_handler/_gemini_interactions_api_params_handler.py around
lines 48 - 71, The get_provider_tools method currently swallows all errors when
importing provider tool classes for enable_web_search and enable_code_execution;
change the broad excepts to catch ImportError and AttributeError only (so
genuine runtime bugs aren't hidden) and emit a single warning/error log that
includes the exception message and context (e.g., mentioning
enable_web_search/enable_code_execution and
google.genai.types.Tool/GoogleSearch/ToolCodeExecution) so failures are visible
while still tolerating missing optional provider dependencies.

Comment on lines +287 to +293
supported_capabilities={
"web_search",
"code_execution",
"mcp",
"image_understanding",
"url_context",
},
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Add "url_context" capability to the Capability enum.

The supported_capabilities set includes "url_context" (line 292), but this capability is not defined in the Capability enum (lines 61-78). This inconsistency could cause validation issues.

Add url_context to Capability enum

Add the following to the Capability enum after line 78:

 class Capability(Enum):
     """Enumeration of all possible backend capabilities."""
 
     WEB_SEARCH = "web_search"
     CODE_EXECUTION = "code_execution"
     BASH = "bash"
     MULTIMODAL = "multimodal"  # Legacy - being phased out
     VISION = "vision"  # Legacy - use image_understanding
     MCP = "mcp"
     FILESYSTEM_NATIVE = "filesystem_native"
     FILESYSTEM_MCP = "filesystem_mcp"
     REASONING = "reasoning"
     IMAGE_GENERATION = "image_generation"
     IMAGE_UNDERSTANDING = "image_understanding"
     AUDIO_GENERATION = "audio_generation"
     AUDIO_UNDERSTANDING = "audio_understanding"
     VIDEO_GENERATION = "video_generation"
     VIDEO_UNDERSTANDING = "video_understanding"
+    URL_CONTEXT = "url_context"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
supported_capabilities={
"web_search",
"code_execution",
"mcp",
"image_understanding",
"url_context",
},
class Capability(Enum):
"""Enumeration of all possible backend capabilities."""
WEB_SEARCH = "web_search"
CODE_EXECUTION = "code_execution"
BASH = "bash"
MULTIMODAL = "multimodal" # Legacy - being phased out
VISION = "vision" # Legacy - use image_understanding
MCP = "mcp"
FILESYSTEM_NATIVE = "filesystem_native"
FILESYSTEM_MCP = "filesystem_mcp"
REASONING = "reasoning"
IMAGE_GENERATION = "image_generation"
IMAGE_UNDERSTANDING = "image_understanding"
AUDIO_GENERATION = "audio_generation"
AUDIO_UNDERSTANDING = "audio_understanding"
VIDEO_GENERATION = "video_generation"
VIDEO_UNDERSTANDING = "video_understanding"
URL_CONTEXT = "url_context"
🤖 Prompt for AI Agents
In @massgen/backend/capabilities.py around lines 287 - 293, The
supported_capabilities set includes "url_context" but the Capability enum lacks
a matching member; add a new enum member named URL_CONTEXT (or url_context
consistent with the enum naming scheme) to the Capability enum definition so
that Capability includes this value and validation against
supported_capabilities succeeds; update any serialization/usage (e.g., when
comparing strings or using Capability.<NAME>) to use the new Capability member.

Comment on lines +296 to +314
models=[
"deep-research-pro-preview-12-2025",
"gemini-3-pro-preview",
"gemini-3-flash-preview",
"gemini-2.5-pro",
"gemini-2.5-flash",
"gemini-2.5-flash-lite",
],
default_model="deep-research-pro-preview-12-2025",
env_var="GEMINI_API_KEY",
notes="Interactions API with stateful conversations, background execution, and agent support (Deep Research).",
model_release_dates={
"deep-research-pro-preview-12-2025": "2025-12",
"gemini-3-pro-preview": "2025-11",
"gemini-3-flash-preview": "2025-11",
"gemini-2.5-pro": "2025-06",
"gemini-2.5-flash": "2025-06",
"gemini-2.5-flash-lite": "2025-09",
},
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🌐 Web query:

Google Gemini official models list 2025 2026 release dates deep-research

💡 Result:

Summary — official Gemini model family and key release dates (2024–2026):

  • Gemini 1.0 / 1.5 family (initial launches and early variants) — 2023–2024; retired/legacy by 2025. (docs.cloud.google.com)
  • Gemini 2.0 family: Gemini 2.0 Flash (GA) — February 5, 2025; Gemini 2.0 Flash‑Lite — Feb 25, 2025; Gemini 2.0 Pro experimental — Feb 5, 2025. (developers.googleblog.com)
  • Gemini 2.5 family (thinking models): Gemini 2.5 Pro / 2.5 Flash — public previews in March–May 2025, GA / stable rollout by June 17, 2025; Gemini‑2.5‑flash‑lite / other 2.5 variants followed (July–Oct 2025 for some image variants). (developers.googleblog.com)
  • Model IDs & Vertex AI lifecycle table (official list with release + retirement dates used by Google Cloud/Vertex AI) — includes: gemini-2.5-pro (Jun 17, 2025), gemini-2.5-flash (Jun 17, 2025), gemini-2.5-flash-lite (Jul 22, 2025), gemini-2.0-flash-001 (Feb 5, 2025), gemini-embedding-001 (May 20, 2025), plus retired/legacy entries. (cloud.google.com)
  • Later / 2025–2026 reporting: press coverage indicates Google continued rolling out Gemini 2.5→Gemini 3 Flash in late‑2025 / early‑2026 (product/AI app integration), but for official model names/GA dates rely on Google’s Developer/Vertex AI pages above. (theverge.com)

If you want, I can extract the full Vertex AI model table (model IDs, exact release and retirement dates) into CSV or a chronological timeline with direct links to each Google page.

Citations:


🌐 Web query:

Google Gemini API models gemini-2.5-flash-lite gemini-3 official release dates

💡 Result:

  • gemini-2.5-flash-lite — GA release date: July 22, 2025. [1][2]
  • Gemini 3 — public launch / product embedding announced: November 18, 2025. [3]

Sources:
[1] Google Cloud Vertex AI model page for Gemini 2.5 Flash-Lite.
[2] Google Developers blog announcement for Gemini 2.5 Flash-Lite (July 22, 2025).
[3] Reuters coverage of Google launching Gemini 3 (Nov 18, 2025).


🌐 Web query:

Google Gemini Interactions API deep-research-pro-preview official model names documentation

💡 Result:

I found Google’s official Interactions API docs listing the supported Gemini model and agent names (including the Deep Research agent). Key names from the documentation:

Models:

  • gemini-2.5-pro. [1]
  • gemini-2.5-flash. [1]
  • gemini-2.5-flash-preview-09-2025. [2]
  • gemini-2.5-flash-lite. [1]
  • gemini-2.5-flash-lite-preview-09-2025. [2]
  • gemini-2.5-flash-preview-native-audio-dialog. [2]
  • gemini-2.5-flash-image-preview. [2]
  • gemini-2.5-pro-preview-tts. [2]
  • gemini-3-pro-preview. [1][2]
  • gemini-3-flash-preview. [1][2]

Agent:

  • deep-research-pro-preview-12-2025 (Gemini Deep Research Agent). [1][3]

References:

  • Google Gemini Interactions API (models & agent examples). [1]
  • Gemini API / Interactions reference (model list and ModelOption values). [2]
  • Gemini Deep Research Agent guide. [3]

Correct the release date for gemini-2.5-flash-lite.

The release date for gemini-2.5-flash-lite should be "2025-07" (July 22, 2025), not "2025-09". The model names are accurate and match official Google Gemini Interactions API documentation; only this date needs to be fixed.

🤖 Prompt for AI Agents
In @massgen/backend/capabilities.py around lines 296 - 314, In the
model_release_dates mapping update the entry for "gemini-2.5-flash-lite" from
"2025-09" to "2025-07"; locate the model_release_dates dict (used alongside
models, default_model, env_var) and change the value for the
"gemini-2.5-flash-lite" key to "2025-07" to reflect the correct July 22, 2025
release date.

Comment on lines +1675 to +1724
def _append_tool_result_message(
self,
updated_messages: List[Dict[str, Any]],
call: Dict[str, Any],
result: Any,
tool_type: str,
) -> None:
"""Append tool result to messages.
For Interactions API, we store results in the active tool result store
for use in continuation requests.
"""
call_id = call.get("call_id", "")
result_str = str(result) if result else "No result"

if self._active_tool_result_store is not None:
self._active_tool_result_store[call_id] = result_str

# Also append to messages for compatibility
updated_messages.append(
{
"role": "tool",
"tool_call_id": call_id,
"name": call.get("name", ""),
"content": result_str,
},
)

def _append_tool_error_message(
self,
updated_messages: List[Dict[str, Any]],
call: Dict[str, Any],
error_msg: str,
tool_type: str,
) -> None:
"""Append tool error to messages."""
call_id = call.get("call_id", "")

if self._active_tool_result_store is not None:
self._active_tool_result_store[call_id] = f"Error: {error_msg}"

updated_messages.append(
{
"role": "tool",
"tool_call_id": call_id,
"name": call.get("name", ""),
"content": f"Error: {error_msg}",
},
)

Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Major correctness: tool results treat falsy values as missing.

  • Line 1688: result_str = str(result) if result else "No result" turns legitimate results like 0, False, and "" into "No result".
Proposed diff
@@
-        result_str = str(result) if result else "No result"
+        result_str = "No result" if result is None else str(result)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
def _append_tool_result_message(
self,
updated_messages: List[Dict[str, Any]],
call: Dict[str, Any],
result: Any,
tool_type: str,
) -> None:
"""Append tool result to messages.
For Interactions API, we store results in the active tool result store
for use in continuation requests.
"""
call_id = call.get("call_id", "")
result_str = str(result) if result else "No result"
if self._active_tool_result_store is not None:
self._active_tool_result_store[call_id] = result_str
# Also append to messages for compatibility
updated_messages.append(
{
"role": "tool",
"tool_call_id": call_id,
"name": call.get("name", ""),
"content": result_str,
},
)
def _append_tool_error_message(
self,
updated_messages: List[Dict[str, Any]],
call: Dict[str, Any],
error_msg: str,
tool_type: str,
) -> None:
"""Append tool error to messages."""
call_id = call.get("call_id", "")
if self._active_tool_result_store is not None:
self._active_tool_result_store[call_id] = f"Error: {error_msg}"
updated_messages.append(
{
"role": "tool",
"tool_call_id": call_id,
"name": call.get("name", ""),
"content": f"Error: {error_msg}",
},
)
def _append_tool_result_message(
self,
updated_messages: List[Dict[str, Any]],
call: Dict[str, Any],
result: Any,
tool_type: str,
) -> None:
"""Append tool result to messages.
For Interactions API, we store results in the active tool result store
for use in continuation requests.
"""
call_id = call.get("call_id", "")
result_str = "No result" if result is None else str(result)
if self._active_tool_result_store is not None:
self._active_tool_result_store[call_id] = result_str
# Also append to messages for compatibility
updated_messages.append(
{
"role": "tool",
"tool_call_id": call_id,
"name": call.get("name", ""),
"content": result_str,
},
)
def _append_tool_error_message(
self,
updated_messages: List[Dict[str, Any]],
call: Dict[str, Any],
error_msg: str,
tool_type: str,
) -> None:
"""Append tool error to messages."""
call_id = call.get("call_id", "")
if self._active_tool_result_store is not None:
self._active_tool_result_store[call_id] = f"Error: {error_msg}"
updated_messages.append(
{
"role": "tool",
"tool_call_id": call_id,
"name": call.get("name", ""),
"content": f"Error: {error_msg}",
},
)
🧰 Tools
🪛 Ruff (0.14.10)

1680-1680: Unused method argument: tool_type

(ARG002)


1708-1708: Unused method argument: tool_type

(ARG002)

🤖 Prompt for AI Agents
In @massgen/backend/gemini_interactions.py around lines 1675 - 1724, In
_append_tool_result_message the code treats any falsy result (0, False, "",
etc.) as missing by using `if result`; change the logic to only treat None as
missing so legitimate falsy values are preserved (i.e., set result_str to "No
result" only when result is None, otherwise use str(result)); update the
assignment in _append_tool_result_message accordingly, keeping the rest of the
behavior (storing in self._active_tool_result_store and appending to
updated_messages) unchanged.

Comment on lines +1774 to +1818
async def _cleanup_genai_resources(self, stream: Any = None, client: Any = None) -> None:
"""Cleanup google-genai resources to avoid unclosed aiohttp sessions.
Cleanup order is critical: stream → session → transport → client → MCP.
Each resource is cleaned independently with error isolation.
"""
# 1. Close stream
await self._try_close_resource(stream, ("aclose", "close"), "Stream")

# 2. Close internal aiohttp session (requires special handling)
if client is not None:
base_client = getattr(client, "_api_client", None)
if base_client is not None:
session = getattr(base_client, "_aiohttp_session", None)
if session is not None and not getattr(session, "closed", True):
try:
await session.close()
log_backend_activity(
"gemini_interactions",
"Closed google-genai aiohttp session",
{},
agent_id=self.agent_id,
)
base_client._aiohttp_session = None
# Yield control to allow connector cleanup
await asyncio.sleep(0)
except Exception as e:
log_backend_activity(
"gemini_interactions",
"Failed to close google-genai aiohttp session",
{"error": str(e)},
agent_id=self.agent_id,
)

# 3. Close internal async transport
if client is not None:
aio_obj = getattr(client, "aio", None)
await self._try_close_resource(aio_obj, ("close", "stop"), "Client AIO")

# 4. Close client
await self._try_close_resource(client, ("aclose", "close"), "Client")

# 5. Cleanup MCP connections
await self.cleanup_mcp()

Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🌐 Web query:

google-genai Python client close cleanup aiohttp session public API

💡 Result:

Short answer: use the client's public close APIs or context managers. For sync use client.close() or with Client() as client; for async use await client.aio.aclose() or async with Client().aio as aclient. This will close the underlying httpx/aiohttp sessions and avoid "Unclosed client session" warnings. [1][2][3]

Notes / pointers:

  • Docs show client.close() (sync) and await client.aio.aclose() (async) and context-manager examples. [1][2]
  • There are GitHub issues reporting aiohttp warnings when the session isn't closed; calling aclose()/using the async context manager is the supported fix. [3][4]

Sources:
[1] python-genai docs — "Close a client" (googleapis.github.io/python-genai).
[2] python-genai GitHub README / examples showing client.close() and await aclient.aclose().
[3] Issue: "Unclosed client session warnings when using google-genai with the aiohttp backend" (google-gemini/cookbook).
[4] Issue: "aiohttp session leakage" (googleapis/python-genai).


🏁 Script executed:

# Check for google-genai version constraints in the project
find . -name "pyproject.toml" -o -name "setup.py" -o -name "requirements*.txt" | head -20

Repository: massgen/MassGen

Length of output: 123


🏁 Script executed:

# Search for how _cleanup_genai_resources is called in the codebase
rg "_cleanup_genai_resources" -A 3 -B 3

Repository: massgen/MassGen

Length of output: 1898


🏁 Script executed:

# Check if cleanup_mcp is a context manager or has guards already
rg "cleanup_mcp" -B 5 -A 5

Repository: massgen/MassGen

Length of output: 10870


🏁 Script executed:

# Check google-genai version constraints
cat pyproject.toml | grep -A 5 -B 5 "google-genai\|genai"

Repository: massgen/MassGen

Length of output: 329


🏁 Script executed:

# Get more context on _cleanup_genai_resources signature in gemini_interactions.py
sed -n '1774,1820p' massgen/backend/gemini_interactions.py

Repository: massgen/MassGen

Length of output: 2181


Use public client.aio.aclose() API instead of accessing private _api_client._aiohttp_session internals.

Lines 1785–1807 access client._api_client._aiohttp_session, which relies on google-genai private implementation details. The library exposes a public async cleanup path: await client.aio.aclose(), which properly closes the underlying aiohttp session. Switch to this public API to avoid future brittleness across google-genai versions.

The defensive getattr checks help, but using the public API eliminates the need for version-guarding internals entirely. Note: cleanup_mcp() is already properly guarded since it's only called during aexit (context manager exit), so no additional flags are needed.

🧰 Tools
🪛 Ruff (0.14.10)

1800-1800: Do not catch blind exception: Exception

(BLE001)

🤖 Prompt for AI Agents
In @massgen/backend/gemini_interactions.py around lines 1774 - 1818, The code in
_cleanup_genai_resources currently reaches into
client._api_client._aiohttp_session to close aiohttp sessions; instead call the
public async API await client.aio.aclose() to close the client's internal
transport/session. Replace the block that inspects base_client/_aiohttp_session
with a try/except that awaits client.aio.aclose(), logs success or failure via
log_backend_activity (using the same messages), and optionally await
asyncio.sleep(0) after success to yield control; retain the surrounding
defensive checks for client and existing _try_close_resource calls for other
parts.

Comment on lines +674 to +679
elif backend_type == "gemini_interactions":
api_key = kwargs.get("api_key") or os.getenv("GOOGLE_API_KEY") or os.getenv("GEMINI_API_KEY")
if not api_key:
raise ConfigurationError(_api_key_error_message("Gemini Interactions", "GOOGLE_API_KEY", config_path))
return GeminiInteractionsBackend(api_key=api_key, **kwargs)

Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Align API-key error messaging + avoid potential api_key kwarg duplication.

  1. The error message currently points only to GOOGLE_API_KEY, but the branch also accepts GEMINI_API_KEY—that’s confusing when users have neither set.
  2. Safer to pop("api_key", None) before calling the backend constructor to avoid TypeError: got multiple values for keyword argument 'api_key' if upstream ever passes api_key in kwargs.
Proposed diff
 elif backend_type == "gemini_interactions":
-    api_key = kwargs.get("api_key") or os.getenv("GOOGLE_API_KEY") or os.getenv("GEMINI_API_KEY")
+    from .backend.gemini_interactions import GeminiInteractionsBackend
+
+    api_key = kwargs.pop("api_key", None) or os.getenv("GOOGLE_API_KEY") or os.getenv("GEMINI_API_KEY")
     if not api_key:
-        raise ConfigurationError(_api_key_error_message("Gemini Interactions", "GOOGLE_API_KEY", config_path))
+        raise ConfigurationError(
+            _api_key_error_message("Gemini Interactions", "GOOGLE_API_KEY (or GEMINI_API_KEY)", config_path)
+        )
     return GeminiInteractionsBackend(api_key=api_key, **kwargs)

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In @massgen/cli.py around lines 674 - 679, The branch handling backend_type ==
"gemini_interactions" should update the API-key error message to reference both
GOOGLE_API_KEY and GEMINI_API_KEY and remove the potential duplicate api_key in
kwargs before constructing the backend; do this by building api_key from
kwargs.get("api_key") or os.getenv("GOOGLE_API_KEY") or
os.getenv("GEMINI_API_KEY"), using kwargs.pop("api_key", None) to remove any
incoming api_key before calling GeminiInteractionsBackend, and call
_api_key_error_message("Gemini Interactions", "GOOGLE_API_KEY",
"GEMINI_API_KEY", config_path) (or otherwise include both env names in the error
text) when raising ConfigurationError.

Comment on lines +1 to +28
# MassGen Configuration: Gemini Interactions with MCP Integration
# Usage: uv run massgen --config massgen/configs/tools/custom_tools/gemini_interactions_custom_tool_with_mcp.yaml "whats the sum of 123 and 456? and whats the weather of Tokyo and london?"

agents:
- id: "gemini_interactions_custom_tool" # Google Gemini Interactions
backend:
type: "gemini_interactions"
model: "gemini-2.5-flash"
custom_tools:
- name: ["two_num_tool"]
category: "math"
path: "massgen/tool/_basic/_two_num_tool.py"
function: ["two_num_tool"]
mcp_servers:
- name: "weather"
type: "stdio"
command: "npx"
args: ["-y", "@fak111/weather-mcp"]
system_message: |
You have access to:
- two_num_tool: Adds two numbers
- Weather MCP: Provides weather information
Use these tools to answer questions. Do not speculate or invent tool capabilities.
ui:
display_type: "rich_terminal"
logging_enabled: true No newline at end of file
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# Verify the config file exists and explore the tool structure
git ls-files | grep -E "(gemini_interactions_custom_tool_with_mcp|_two_num_tool)" || echo "Searching more broadly..."
fd -t f "_two_num_tool" 2>/dev/null || echo "Not found with fd"
fd -t f "gemini_interactions_custom_tool_with_mcp" 2>/dev/null || echo "Not found with fd"

# Check directory structure
ls -la massgen/tool/_basic/ 2>/dev/null || echo "Directory not found"
ls -la massgen/configs/tools/custom_tools/ 2>/dev/null || echo "Directory not found"

Repository: massgen/MassGen

Length of output: 5963


🏁 Script executed:

# Check overall repo structure for massgen/
find massgen -type f -name "*.yaml" | head -20
find massgen -type f -name "*.py" | grep tool | head -20

Repository: massgen/MassGen

Length of output: 1845


🏁 Script executed:

# Read the config file
cat -n massgen/configs/tools/custom_tools/gemini_interactions_custom_tool_with_mcp.yaml

# Read the tool Python file
cat -n massgen/tool/_basic/_two_num_tool.py

# Read TOOL.md
head -50 massgen/tool/_basic/TOOL.md

Repository: massgen/MassGen

Length of output: 3197


Add "What happens" flow comment and pin MCP server version for supply-chain security.

Missing execution flow documentation and unpinned remote code execution dependency. Per coding guidelines, all example configs require "What happens" comments explaining the execution flow. Line 18: @fak111/weather-mcp should be pinned to a specific version to ensure reproducibility and reduce supply-chain risk. Tool compliance verified: massgen/tool/_basic/TOOL.md contains required YAML frontmatter.

Suggested edits
 # MassGen Configuration: Gemini Interactions with MCP Integration
 # Usage: uv run massgen --config massgen/configs/tools/custom_tools/gemini_interactions_custom_tool_with_mcp.yaml "whats the sum of 123 and 456? and whats the weather of Tokyo and london?"
+#
+# What happens:
+# - Agent uses Gemini Interactions backend with gemini-2.5-flash.
+# - Calls `two_num_tool` for arithmetic operations.
+# - Calls Weather MCP server for weather information via stdio MCP.
+# - Combines tool outputs into the final answer.

 agents:
   - id: "gemini_interactions_custom_tool" # Google Gemini Interactions
     backend:
       type: "gemini_interactions"
       model: "gemini-2.5-flash"
       custom_tools:
         - name: ["two_num_tool"]
           category: "math"
           path: "massgen/tool/_basic/_two_num_tool.py"
           function: ["two_num_tool"]
       mcp_servers:
         - name: "weather"
           type: "stdio"
           command: "npx"
-          args: ["-y", "@fak111/weather-mcp"]
+          args: ["-y", "@fak111/[email protected]"]

Comment on lines +55 to +127
def format_tools_for_interactions_api(
self,
custom_tools: Optional[List[Dict[str, Any]]] = None,
mcp_functions: Optional[Dict[str, Any]] = None,
workflow_tools: Optional[List[Dict[str, Any]]] = None,
) -> List[Dict[str, Any]]:
"""Format tools for the Gemini Interactions API.
Args:
custom_tools: Custom tool schemas in OpenAI format
mcp_functions: MCP function objects
workflow_tools: Workflow tools (new_answer, vote) in OpenAI format
Returns:
List of tools in Interactions API format
"""
interactions_tools = []

# Add workflow tools first (new_answer, vote)
if workflow_tools:
for tool in workflow_tools:
if isinstance(tool, dict) and tool.get("type") == "function" and "function" in tool:
func_def = tool["function"]
tool_name = func_def.get("name", "")
# Only include actual workflow tools
if tool_name in ("new_answer", "vote", "ask_others"):
interactions_tools.append(
{
"type": "function",
"name": tool_name,
"description": func_def.get("description", ""),
"parameters": func_def.get("parameters", {}),
},
)

if custom_tools:
for tool in custom_tools:
if isinstance(tool, dict) and tool.get("type") == "function" and "function" in tool:
func_def = tool["function"]
interactions_tools.append(
{
"type": "function",
"name": func_def.get("name", ""),
"description": func_def.get("description", ""),
"parameters": func_def.get("parameters", {}),
},
)
elif isinstance(tool, dict) and "name" in tool and "parameters" in tool:
interactions_tools.append(
{
"type": "function",
"name": tool.get("name", ""),
"description": tool.get("description", ""),
"parameters": tool.get("parameters", {}),
},
)

if mcp_functions:
for mcp_function in mcp_functions.values():
try:
interactions_tools.append(
{
"type": "function",
"name": getattr(mcp_function, "name", ""),
"description": getattr(mcp_function, "description", ""),
"parameters": getattr(mcp_function, "parameters", {}),
},
)
except Exception as e:
logger.error(f"[GeminiFormatter] Failed to convert MCP tool for Interactions API: {e}")
continue

return interactions_tools
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Harden tool normalization: avoid empty names, dedupe, and improve exception logging.

  • Line 78-87 / 94-101 / 103-110 / 116-122: name can become ""; consider skipping empty tool names to prevent API rejections.
  • Line 112-125: prefer logger.exception(...) and (ideally) narrower exception types; current pattern drops stack traces and catches too broadly (matches Ruff BLE001/TRY400).
  • Line 71-127: consider deduping by tool name to avoid sending duplicates when the same tool exists in workflow_tools + custom_tools + mcp_functions.
Proposed diff (dedupe + skip empty names + better logging)
@@
-        interactions_tools = []
+        interactions_tools: List[Dict[str, Any]] = []
+        seen_names: set[str] = set()
@@
-                    tool_name = func_def.get("name", "")
+                    tool_name = (func_def.get("name") or "").strip()
                     # Only include actual workflow tools
                     if tool_name in ("new_answer", "vote", "ask_others"):
+                        if tool_name in seen_names:
+                            continue
                         interactions_tools.append(
@@
                         )
+                        seen_names.add(tool_name)
@@
-                    interactions_tools.append(
+                    tool_name = (func_def.get("name") or "").strip()
+                    if not tool_name or tool_name in seen_names:
+                        continue
+                    interactions_tools.append(
                         {
                             "type": "function",
-                            "name": func_def.get("name", ""),
+                            "name": tool_name,
                             "description": func_def.get("description", ""),
                             "parameters": func_def.get("parameters", {}),
                         },
                     )
+                    seen_names.add(tool_name)
                 elif isinstance(tool, dict) and "name" in tool and "parameters" in tool:
-                    interactions_tools.append(
+                    tool_name = (tool.get("name") or "").strip()
+                    if not tool_name or tool_name in seen_names:
+                        continue
+                    interactions_tools.append(
                         {
                             "type": "function",
-                            "name": tool.get("name", ""),
+                            "name": tool_name,
                             "description": tool.get("description", ""),
                             "parameters": tool.get("parameters", {}),
                         },
                     )
+                    seen_names.add(tool_name)
@@
-                try:
-                    interactions_tools.append(
+                try:
+                    tool_name = (getattr(mcp_function, "name", "") or "").strip()
+                    if not tool_name or tool_name in seen_names:
+                        continue
+                    interactions_tools.append(
                         {
                             "type": "function",
-                            "name": getattr(mcp_function, "name", ""),
+                            "name": tool_name,
                             "description": getattr(mcp_function, "description", ""),
                             "parameters": getattr(mcp_function, "parameters", {}),
                         },
                     )
-                except Exception as e:
-                    logger.error(f"[GeminiFormatter] Failed to convert MCP tool for Interactions API: {e}")
+                    seen_names.add(tool_name)
+                except Exception:
+                    logger.exception("[GeminiFormatter] Failed to convert MCP tool for Interactions API")
                     continue
🧰 Tools
🪛 Ruff (0.14.10)

123-123: Do not catch blind exception: Exception

(BLE001)


124-124: Use logging.exception instead of logging.error

Replace with exception

(TRY400)

🤖 Prompt for AI Agents
In @massgen/formatter/_gemini_formatter.py around lines 55 - 127, In
format_tools_for_interactions_api, avoid adding tools with empty names, dedupe
by tool name, and improve exception logging: maintain a seen_names set and
before appending any tool (in the workflow_tools, custom_tools, and
mcp_functions branches) skip if the resolved name is falsy or already in
seen_names; when converting mcp_functions replace the broad try/except with a
narrower except (e.g., AttributeError, TypeError) and call logger.exception(...)
to preserve stack traces; ensure you use the same name extraction logic
(func_def.get("name", "") or getattr(..., "name", "")) and add the valid name to
seen_names only when you append the tool.

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