feat(gemini): Add manual project_id input when auto-discovery fails#152
feat(gemini): Add manual project_id input when auto-discovery fails#152mirrobot-agent[bot] wants to merge 1 commit intodevfrom
Conversation
- Add _prompt_for_manual_setup() method to prompt for project_id and tier - Display link to manual setup documentation (docs/gemini-cli-manual-code-assist-setup.md) - Allow manual tier selection from known tiers list - Persist manually provided project_id and tier to credential file - Only triggers in interactive mode when auto-discovery fails after onboarding - Create placeholder documentation file for manual Code Assist setup instructions Resolves: #151
Implementation SummaryThis PR addresses issue #151 by adding manual project_id input capability for Gemini CLI OAuth setup. What Was Done
Testing Recommendations
Notes for Reviewer
This comment was automatically generated by mirrobot-agent. |
There was a problem hiding this comment.
Overall Assessment
This PR introduces a helpful fallback mechanism for manual project_id input when auto-discovery fails. The interactive prompt using Rich is a nice touch, and the tier selection flow is user-friendly. However, there are a few issues that should be addressed before merging.
Architectural Feedback
The approach of falling back to manual input is sound and follows good UX principles. The separation into _prompt_for_manual_setup and _persist_project_metadata methods is clean.
Key Suggestions
-
Incomplete Documentation (Critical): The documentation file is a placeholder but is actively referenced by the code at line 872.
-
Exception Handling: The broad
except Exceptionat line 822 could hide real bugs. -
Hard-coded Path: The documentation path at line 872 should be resolved relative to the module.
-
Persistence Failures: Silent failures in metadata persistence at line 819 could lead to re-prompting.
-
Tier Constant: The "unknown" fallback should be documented or added to known tiers (line 35).
Questions for the Author
- Is the documentation intentionally incomplete for this PR?
- Are there tests planned for the new manual input flow?
This review was generated by an AI assistant.
|
|
||
| ## Overview | ||
|
|
||
| Some Gemini accounts require manual creation of a Google Cloud Console project with the Code Assist API enabled. This guide will walk you through the process. |
There was a problem hiding this comment.
This documentation file is marked as a placeholder with incomplete steps. However, the code in gemini_auth_base.py:872 directs users to read this file during manual setup.
Consider completing the documentation before merging, or remove this file from the PR and add it in a follow-up once the steps are documented.
| await self._persist_project_metadata(credential_path, project_id, tier) | ||
|
|
||
| return project_id | ||
| except Exception as e: |
There was a problem hiding this comment.
The try-except block catches all Exception types, which is too broad and could hide bugs during development. Consider catching specific exceptions like EOFError, KeyboardInterrupt, or ValueError that are expected from user input.
| self.project_tier_cache[credential_path] = tier | ||
|
|
||
| # Persist to credential file | ||
| await self._persist_project_metadata(credential_path, project_id, tier) |
There was a problem hiding this comment.
If _persist_project_metadata fails, the project_id is still returned on line 821. This could cause the user to be prompted again on the next run since the metadata wasn't saved.
Consider adding explicit warning logging if persistence fails.
| "1. The Cloud AI Companion API is not enabled in your Google Cloud project\n" | ||
| "2. You need to manually create a project\n\n" | ||
| "[bold]Please follow the manual setup instructions:[/bold]\n" | ||
| "[cyan]docs/gemini-cli-manual-code-assist-setup.md[/cyan]\n\n" |
There was a problem hiding this comment.
This hard-coded relative path assumes the user is running from the repository root. Consider using a path relative to the module using Path(__file__) for a more robust solution.
| SERVICE_USAGE_API = "https://serviceusage.googleapis.com/v1" | ||
|
|
||
| # Known Gemini CLI tiers for manual selection | ||
| KNOWN_GEMINI_TIERS = [ |
There was a problem hiding this comment.
The KNOWN_GEMINI_TIERS list doesn't include "unknown", but the code uses "unknown" as a fallback (around line 912). Consider either adding "unknown" to the list or documenting it as a special sentinel value.
|
| Filename | Overview |
|---|---|
| src/rotator_library/providers/gemini_auth_base.py | Core Gemini auth class with critical bugs: _persist_project_metadata called with 4 args but only accepts 3 (TypeError at runtime), and triple-duplicated post-auth log block emitting the same message 3 times per credential init. |
| src/rotator_library/providers/utilities/gemini_credential_manager.py | Duplicate except Exception as e: block (second is unreachable dead code) and success log accidentally placed inside the error handler, causing misleading log output on discovery failure. |
| src/rotator_library/providers/utilities/gemini_shared_utils.py | New tier normalization utilities (normalize_tier_name, is_free_tier, is_paid_tier, get_tier_full_name, extract_project_id_from_response, load_persisted_project_metadata, build_project_tier_env_lines) are well-structured and cleanly centralize previously duplicated tier logic. |
| src/rotator_library/providers/gemini_cli_provider.py | Updated to use centralized TIER_PRIORITIES and DEFAULT_TIER_PRIORITY, adds gemini-3.1-pro-preview model, bumps user-agent to 0.28.0. Stale comments still describe old concurrency multiplier values (5x/3x) while actuals are now 2x/1x. |
| src/rotator_library/providers/google_oauth_base.py | Re-auth queue replaced with a simpler _permanently_expired_credentials set; credentials with invalid refresh tokens are now removed from rotation immediately and require manual re-authentication. |
| docs/gemini-cli-manual-code-assist-setup.md | New placeholder documentation file with no actual content, but actively referenced from the interactive _prompt_for_manual_setup flow shown to users when auto-discovery fails. |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[OAuth Token Acquired] --> B[load_persisted_project_metadata]
B -- "project_id cached" --> C[Return cached project_id]
B -- "no cache" --> D[loadCodeAssist API call]
D -- "server returns project" --> E[Use server project]
D -- "no server project, tier detected" --> F[_scan_gcp_projects_for_code_assist]
D -- "no tier / new user" --> G[onboardUser LRO]
F -- "project found" --> E
F -- "not found" --> G
G -- "LRO success" --> E
G -- "failed" --> H[_prompt_for_manual_setup]
H -- "interactive mode, user enters ID" --> I[Use manual project_id]
H -- "non-interactive / skipped" --> J[Raise ValueError]
E --> K[Cache tier + tier_full]
I --> K
K --> L[_persist_project_metadata\ncredential_path, project_id, tier\n❌ tier_full arg dropped - TypeError!]
L --> M[Return project_id]
Comments Outside Diff (3)
-
src/rotator_library/providers/gemini_auth_base.py, line 285-307 (link)Triple-duplicated post-auth discovery log block
The same three lines that extract
tier_fulland log the post-auth discovery result are copy-pasted three times in a row (visible at lines 285–307 in the new file). This causes the sameINFOmessage to be emitted three times for every credential initialization:# Use full tier name for post-auth log (one-time display) tier_full = self.tier_full_cache.get(credential_path) tier = tier_full or self.project_tier_cache.get(credential_path, "unknown") lib_logger.info( f"Post-auth discovery complete for {Path(credential_path).name}: " f"tier={tier}, project={project_id}" ) # EXACT DUPLICATE ↓ tier_full = self.tier_full_cache.get(credential_path) ... # EXACT DUPLICATE ↓ tier_full = self.tier_full_cache.get(credential_path) ...
This should be deduplicated to a single block. The duplicate
self.tier_full_cache: Dict[str, str] = {}declaration in__init__(lines 104–105) is a related artifact of the same sloppy merge. -
src/rotator_library/providers/gemini_cli_provider.py, line 183-195 (link)Stale comments contradict actual concurrency multiplier values
The comments above
default_priority_multipliersstill describe the old values, but the actual values were reduced:# Priority 1 (paid ultra): 5x concurrent requests ← stale (was {1: 5}) # Priority 2 (standard paid): 3x concurrent requests ← stale (was {2: 3}) # Others: Use sequential fallback (2x) or balanced default (1x) ← stale (was 2x) default_priority_multipliers = {1: 2, 2: 1} # actual: 2x / 1x default_sequential_fallback_multiplier = 1 # actual: 1x, not 2x
The comments should be updated to reflect the new multipliers to avoid confusion.
-
src/rotator_library/providers/utilities/gemini_credential_manager.py, line 167-198 (link)Unreachable duplicate
exceptblock and misleading success-log inside error handlerThe
try/exceptblock ininitialize_credentials_with_tier_discoverynow has twoexcept Exception as e:clauses for the sametryblock. Python only enters the first matching handler; the secondexceptblock is entirely unreachable dead code.Additionally, the tier-full name lookup and
lib_logger.info(f"Discovered tier ...")success message were accidentally placed inside the first (error-handling)exceptblock instead of in thetryblock. As a result:- When discovery succeeds, the success info log is never emitted.
- When discovery fails, the code still attempts to look up
tier_fulland emits a misleading "Discovered tier 'unknown'" message inside the error handler.
The tier_full lookup and
lib_logger.infosuccess log should be moved back into thetryblock (after_discover_project_idreturns), and the duplicate secondexcept Exceptionclause should be removed entirely.
Last reviewed commit: "feat(gemini): add ma..."
| async def _persist_project_metadata( | ||
| self, credential_path: str, project_id: str, tier: Optional[str] | ||
| ): |
There was a problem hiding this comment.
TypeError:
_persist_project_metadata() called with too many arguments
_persist_project_metadata is defined with the signature (self, credential_path: str, project_id: str, tier: Optional[str]) (3 parameters), but is called at lines 520–524 and 700–702 with 4 positional arguments — passing discovered_tier_full as a fourth argument:
await self._persist_project_metadata(
credential_path,
project_id,
discovered_tier,
discovered_tier_full, # ← 4th arg, no matching parameter
)This will raise TypeError: _persist_project_metadata() takes 4 positional arguments but 5 were given at runtime every time a credential successfully completes loadCodeAssist or onboarding discovery, completely breaking project metadata persistence for those credentials. The function signature needs to be updated to accept and store the tier_full value, e.g.:
async def _persist_project_metadata(
self, credential_path: str, project_id: str, tier: Optional[str], tier_full: Optional[str] = None
):
...
if tier_full:
creds["_proxy_metadata"]["tier_full"] = tier_full| # Manual Google Cloud Code Assist Setup for Gemini CLI | ||
|
|
||
| > **⚠️ PLACEHOLDER - To Be Completed by Mirrowel** | ||
| > | ||
| > This document will contain step-by-step instructions for manually enabling the Code Assist API in Google Cloud Console. | ||
|
|
||
| ## Overview | ||
|
|
||
| Some Gemini accounts require manual creation of a Google Cloud Console project with the Code Assist API enabled. This guide will walk you through the process. | ||
|
|
There was a problem hiding this comment.
Placeholder document shipped with no content and referenced at runtime
This documentation file is incomplete — every section contains a [Instructions to be added...] or [To be added...] placeholder. However, it is actively referenced in the interactive prompt shown to users when auto-discovery fails in _prompt_for_manual_setup (in gemini_auth_base.py):
"[bold]Please follow the manual setup instructions:[/bold]\n"
"[cyan]docs/gemini-cli-manual-code-assist-setup.md[/cyan]\n\n"
"After following the instructions, enter your Project ID below."A user whose auto-discovery fails will be directed to this file for help and find it completely empty. Either the document should be completed before merging, or the prompt should reference the ⚠️ PLACEHOLDER note more clearly so the user isn't left stranded.
|
hmm, not super complete. not everything was done. |
Summary
This PR implements manual input capability for the
project_idvariable during Gemini CLI OAuth credential setup, addressing the issue where some Gemini accounts require manual Google Cloud Console project creation.Related Issue
Closes #151
Changes Made
1. Manual Project ID Prompt (
src/rotator_library/providers/gemini_auth_base.py)Added
_prompt_for_manual_setup()method (lines 835-915):project_idandtierModified
_discover_project_id()method (lines 795-813):Added
_persist_project_metadata()method (lines 917-950):Added
KNOWN_GEMINI_TIERSconstant (lines 35-41):2. Documentation (
docs/gemini-cli-manual-code-assist-setup.md)Why These Changes Were Needed
Problem
Some Gemini accounts don't have automatic tier assignment and require:
Previously, users had to:
GEMINI_CLI_PROJECT_IDenvironment variable BEFORE running OAuthSolution
The new flow:
Implementation Details
Integration Points
sys.stdin.isatty()checkUser Experience Flow
Tier Selection
Known tiers presented in order:
Testing
Manual Verification Steps
Test Scenarios
Additional Notes
Documentation Placeholder
The documentation file (
docs/gemini-cli-manual-code-assist-setup.md) is intentionally left as a placeholder. @Mirrowel will need to add:Future Enhancements
This pull request was automatically generated by mirrobot-agent in response to @Mirrowel's request.