-
Notifications
You must be signed in to change notification settings - Fork 106
feat: add gemini interactions api as new backend( Experimental) #662
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
…ate backend creation logic
…rch, code execution, and image understanding
…ded parameters, provider tools, and API parameter construction.
…ith MCP integration
📝 WalkthroughWalkthroughAdds 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
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
Estimated code review effort🎯 4 (Complex) | ⏱️ ~75 minutes Possibly related issues
🚥 Pre-merge checks | ✅ 3 | ❌ 3❌ Failed checks (3 warnings)
✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
Comment |
There was a problem hiding this 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 acceptsGEMINI_API_KEYtoo.The supported-backend list says
gemini_interactions ... requires GOOGLE_API_KEY, but the implementation also acceptsGEMINI_API_KEY. Update the docstring (and ideally the CLI help text) to match actual behavior.
6298-6314: Addgemini_interactionsto CLI--backendchoices.
create_backend()supportsgemini_interactions(documented in its docstring and fully implemented), but theargparse--backendargument choices don't include it. This prevents users from usingmassgen --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_interactionsis optional/experimental, importing it at module import time can breakmassgeneven when users never select that backend (e.g., missing optional deps). A local import inside thegemini_interactionsbranch keeps failures scoped.Proposed diff
-from .backend.gemini_interactions import GeminiInteractionsBackendmassgen/api_params_handler/_gemini_interactions_api_params_handler.py (1)
73-115: API field names and ToolConfig usage are correct; unusedmessages/toolsare intentional per interface contract.The Interactions API parameter mapping is sound:
max_tokens→max_output_tokensis correct, model exclusion is correct, andToolConfig(function_calling_config=FunctionCallingConfig(mode=...))with valid modes{"AUTO", "ANY", "NONE"}matches the google-genai SDK.The unused
messagesandtoolsparameters exist becausebuild_api_params()inherits its signature fromAPIParamsHandlerBase(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 intoinputelsewhere before the API call. While renaming to_messages/_toolswould clarify intent, it would require breaking the ABC interface contract.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (11)
massgen/agent_config.pymassgen/api_params_handler/__init__.pymassgen/api_params_handler/_gemini_interactions_api_params_handler.pymassgen/backend/__init__.pymassgen/backend/capabilities.pymassgen/backend/gemini_interactions.pymassgen/cli.pymassgen/configs/tools/custom_tools/gemini_interactions_custom_tool_with_mcp.yamlmassgen/formatter/_gemini_formatter.pypyproject.tomlrequirements.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.pymassgen/agent_config.pymassgen/backend/capabilities.pymassgen/api_params_handler/_gemini_interactions_api_params_handler.pymassgen/cli.pymassgen/backend/gemini_interactions.pymassgen/api_params_handler/__init__.pymassgen/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.pymassgen/agent_config.pymassgen/backend/capabilities.pymassgen/api_params_handler/_gemini_interactions_api_params_handler.pymassgen/cli.pymassgen/backend/gemini_interactions.pymassgen/api_params_handler/__init__.pymassgen/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.pymassgen/backend/gemini_interactions.pymassgen/backend/__init__.py
massgen/backend/**/*.py
⚙️ CodeRabbit configuration file
massgen/backend/**/*.py: Backend code review - CHECK FOR THESE UPDATES:
- If adding new model support → ensure massgen/backend/capabilities.py is updated
- If adding new capabilities → update supported_capabilities in capabilities.py
- Verify inheritance from base classes is correct
- Check streaming buffer usage where applicable
- Ensure error handling follows existing patterns
Files:
massgen/backend/capabilities.pymassgen/backend/gemini_interactions.pymassgen/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:
- Property placement: cwd at BACKEND-level, context_paths at ORCHESTRATOR-level
- Prefer cost-effective models (gpt-5-nano, gpt-5-mini, gemini-2.5-flash)
- All agents should have identical system_message for multi-agent setups
- Never reference legacy paths or massgen v1
- 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.pymassgen/cli.pymassgen/backend/gemini_interactions.pymassgen/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.pymassgen/cli.pymassgen/backend/gemini_interactions.pymassgen/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.pymassgen/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.pymassgen/cli.pymassgen/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.pymassgen/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.pymassgen/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.yamlmassgen/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.pymassgen/backend/gemini_interactions.pymassgen/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_interactionsbackend 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_handlerand 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_interactionsand 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:
GeminiInteractionsBackendis imported and exported in__init__.py, fully defined inbackend/capabilities.pywith all model mappings and support details, and properly handled incli.py. The backend registration follows the codebase pattern where capabilities and model mappings are managed throughbackend/capabilities.pyrather 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: Thenameandfunctionfields incustom_toolscorrectly use list format forgemini_interactionsbackend. 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 likegemini_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 ingemini_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.
| @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) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
| 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 | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 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.pyRepository: 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 -25Repository: 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 -40Repository: 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 1Repository: 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.py → get_base_excluded_config_params() and massgen/api_params_handler/_api_params_handler_base.py → get_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.
| 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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don’t silently ignore provider-tool import/config errors.
- Line 53-58 / 61-66:
except Exception: passmakesenable_web_search/enable_code_executionfailures invisible (matches Ruff S110/BLE001). Prefer catchingImportError(and maybeAttributeError) 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.
| supported_capabilities={ | ||
| "web_search", | ||
| "code_execution", | ||
| "mcp", | ||
| "image_understanding", | ||
| "url_context", | ||
| }, |
There was a problem hiding this comment.
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.
| 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.
| 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", | ||
| }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 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:
- 1: https://docs.cloud.google.com/vertex-ai/generative-ai/docs/learn/model-versions?utm_source=openai
- 2: https://developers.googleblog.com/en/gemini-2-family-expands/?utm_source=openai
- 3: https://developers.googleblog.com/en/gemini-2-5-thinking-model-updates/?utm_source=openai
- 4: https://cloud.google.com/vertex-ai/generative-ai/docs/deprecations/gemini-1.0-pro?utm_source=openai
- 5: https://www.theverge.com/news/845741/gemini-3-flash-google-ai-mode-launch?utm_source=openai
🌐 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.
| 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}", | ||
| }, | ||
| ) | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Major correctness: tool results treat falsy values as missing.
- Line 1688:
result_str = str(result) if result else "No result"turns legitimate results like0,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.
| 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.
| 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() | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 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 -20Repository: 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 3Repository: 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 5Repository: 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.pyRepository: 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.
| 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) | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Align API-key error messaging + avoid potential api_key kwarg duplication.
- The error message currently points only to
GOOGLE_API_KEY, but the branch also acceptsGEMINI_API_KEY—that’s confusing when users have neither set. - Safer to
pop("api_key", None)before calling the backend constructor to avoidTypeError: got multiple values for keyword argument 'api_key'if upstream ever passesapi_keyin 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.
| # 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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 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 -20Repository: 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.mdRepository: 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]"]| 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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Harden tool normalization: avoid empty names, dedupe, and improve exception logging.
- Line 78-87 / 94-101 / 103-110 / 116-122:
namecan 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.
Description
Adding the gemini interactions api as new backend, this is experimental feature
Type of change
feat:) - Non-breaking change which adds functionalityChecklist
Pre-commit status
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
Chores
✏️ Tip: You can customize this high-level summary in your review settings.