feat(onboarding): collect Gemini ACP credentials + ACP agents docs#972
feat(onboarding): collect Gemini ACP credentials + ACP agents docs#972simonrosenberg wants to merge 12 commits into
Conversation
Agent Canvas fully supports external ACP agents (Claude Code, Codex, Gemini CLI) — onboarding wizard, per-provider credentials, and the Settings → Agent picker — but the flow was only explained in code comments and i18n strings, with nothing for users. Add docs/ACP_AGENTS.md covering what ACP agents are, the four-step onboarding flow, how credentials map to global secrets/env vars, switching agent or model later, custom ACP servers, and troubleshooting. Link it from the docs index. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
ACP agents authenticate either via a subscription login or an API key, and a cached subscription login on the local machine is auto-detected and preferred over a key — a behavior that was easy to miss. Add an Authentication section spelling out the precedence, the per-provider login files (~/.codex/auth.json, ~/.gemini/oauth_creds.json, CLAUDE_CONFIG_DIR → ~/.claude), and that auto-detection only works when the Agent Server runs on the machine you logged in on. Call out Gemini explicitly: onboarding collects no key; it just works off your local Google login. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
✅ Review complete. This review was performed through OpenHands Cloud Automation. You can log in and view the conversation here. |
all-hands-bot
left a comment
There was a problem hiding this comment.
Solid documentation addition — the structure is clear, the Mermaid diagram effectively communicates the delegation model, and the callouts for the @zed-industries/codex-acp vs @openai/codex acp footgun and the subscription-login-wins precedence rule are exactly the kind of gotcha that users would hit silently. Two small suggestions below on authentication discoverability.
This review was generated by an AI agent (OpenHands) on behalf of the user through OpenHands Automation. View conversation
…MINI_BASE_URL) Gemini CLI was the only built-in ACP provider whose onboarding skipped the credentials step, on the premise that it "authenticates via OAuth, not an env-var key." But the SDK has supported gemini-api-key auth since #2619 and GEMINI_BASE_URL routing since the registry centralization (#3022) — so the omission left no in-UI way to give a headless Gemini backend a key. Add a gemini-cli entry to ACP_PROVIDER_SECRETS (GEMINI_API_KEY masked + optional GEMINI_BASE_URL), reusing the existing generic hint keys. The fields flow through the same global-secret path as Claude Code / Codex, so they reach the subprocess env the SDK already reads. Gemini's Google OAuth login still takes precedence at runtime, and the fields stay optional/skippable. No SDK or typescript-client change needed — both already support these env vars end to end. The generic skip-slide-2 path in the modal is retained for any future OAuth-only provider but is no longer hit by a built-in. Tests: convert the Gemini "skips slide 2" modal test into a "renders the credentials step (no longer skipped)" regression test, and add a Gemini field render case to setup-acp-secrets-step. Stale comments updated. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Now that onboarding collects GEMINI_API_KEY + GEMINI_BASE_URL like the other providers, drop the "Gemini skips the credentials step / uses only OAuth" framing: the providers table lists the same optional credentials for all three, and the onboarding steps no longer carve out Gemini. The auth-precedence section (subscription login preferred, key fallback) stays — it still applies to all three — and keeps the two real Gemini specifics: its Google login is the common no-key local path, and GEMINI_BASE_URL only routes on the API-key/gateway path. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…cted Address review: the auth table marked Codex/Gemini logins "auto-detected" but left Claude Code's row ambiguous, even though CLAUDE_CONFIG_DIR must be set on the backend explicitly. Note the asymmetry inline in the table row. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
✅ Review complete. This review was performed through OpenHands Cloud Automation. You can log in and view the conversation here. |
all-hands-bot
left a comment
There was a problem hiding this comment.
Review: feat(onboarding): collect Gemini ACP credentials + ACP agents docs
Summary: Clean, minimal, and well-motivated. This closes a real gap — Gemini CLI was the only built-in ACP provider that skipped credentials in onboarding, leaving no in-UI path to supply a key in headless/cloud deployments. The implementation change is a single new entry in ACP_PROVIDER_SECRETS; the existing generic logic in onboarding-modal.tsx propagates the rest automatically without any modal code changes.
Strengths
- Minimal blast radius. The only functional change is the new
"gemini-cli"block inACP_PROVIDER_SECRETS.showAcpSecretsStepandskipStep2were already provider-agnostic; they just work. - Structural consistency. The Gemini entry mirrors the Codex entry exactly —
secret: trueon the key, nosecretflag on the base URL. - Test quality. Both updated test files are accurate. The
setup-acp-secrets-stepaddition correctly asserts field types (passwordfor the key,textfor the URL). The refactored modal test is cleaner — the removed intermediatewaitForfordata-current-step="1"was redundant (it is implied by the subsequentwaitFor(onboarding-backend-next)). - Documentation quality.
docs/ACP_AGENTS.mdis thorough and honest: theGEMINI_BASE_URLrouting caveat (API-key path only, not OAuth), theCLAUDE_CONFIG_DIRauto-detection difference, and the Codex wrapper trap are all called out. The Mermaid diagram gives a good overview. - Comment updates. All three source comments that referenced the old "Gemini skips credentials" behaviour are updated consistently, including the JSDoc in
setup-acp-secrets-step.tsxand thegetAcpProviderSecretsdescription.
Minor observations
-
skipStep2dead-code comment — the updated comment reads "No built-in provider hits this today — all three collect a key". True right now, but it could confuse a future contributor who adds a provider without credentials and doesn't spot the mismatch. The phrase "kept for future OAuth-only providers" already appears later in the same comment and conveys the intent better on its own. Not a blocker. -
Generic hint for
GEMINI_BASE_URL— see inline comment.
This review was generated by an AI agent (OpenHands) on behalf of the user through OpenHands Automation. View conversation
|
✅ Review complete. This review was performed through OpenHands Cloud Automation. You can log in and view the conversation here. |
all-hands-bot
left a comment
There was a problem hiding this comment.
Review: feat(onboarding): collect Gemini ACP credentials + ACP agents docs
🟢 Good taste — Clean, minimal, and well-motivated. The functional change is a single new entry in ACP_PROVIDER_SECRETS at src/constants/acp-providers.ts; the existing showAcpSecretsStep / skipStep2 logic in the modal was already provider-agnostic and propagates automatically. No modal code changes were needed.
Note: Prior reviews by
all-hands-botalready addressed the main suggestions (theCLAUDE_CONFIG_DIRdiscoverability wording and theGEMINI_BASE_URLgeneric hint key). Those threads are resolved or explicitly accepted as non-blocking by the author. The observations below are additive and independent of those.
Strengths
- Blast radius is minimal. All three comment blocks that referenced the old "Gemini skips credentials" behaviour are updated consistently across
onboarding-modal.tsx,setup-acp-secrets-step.tsx, andacp-providers.ts. No stale documentation anywhere. - Structural parity with Codex. The new
"gemini-cli"block mirrors the"codex"block exactly —secret: trueon the key, plain text on the base URL — which is the right call given identical semantics. - Documentation honesty.
docs/ACP_AGENTS.mdcalls out the two real Gemini gotchas (OAuth login takes precedence,GEMINI_BASE_URLis API-key-path-only) rather than glossing over them. The Mermaid diagram gives a clear mental model up front. skipStep2is correctly preserved. Keeping the skip path generic for future OAuth-only providers is the right design; the alternative (hardcoding Gemini as the only skip case) would have been worse.
Minor observations
1. Test: progress step state coverage reduced
See inline comment on onboarding-modal.test.tsx line 329.
2. Docs: npx -y without version pinning
See inline comment on docs/ACP_AGENTS.md line 45.
[RISK ASSESSMENT]
- [Overall PR]
⚠️ Risk Assessment: 🟢 LOW
Purely additive: a new constant entry and docs. No existing credential flows, modal logic, or test coverage is removed. The refactored Gemini modal test replaces a test for behaviour that is now intentionally obsolete, so there is no regression risk there.
VERDICT:
✅ Worth merging. Core change is sound and closes a real gap (no in-UI path to supply a Gemini key in headless/cloud deployments). Minor suggestions are non-blocking.
KEY INSIGHT: The design already handled optional providers generically; this PR simply fills in the missing constant entry, which is exactly the right scope for this change.
This review was generated by an AI agent (OpenHands) on behalf of the user through OpenHands Automation. View conversation
Improve this review? If any feedback above seems incorrect or irrelevant to this repository, you can teach the reviewer to do better:
- Add a
.agents/skills/custom-codereview-guide.mdfile to your branch (or edit it if one already exists) with the/codereviewtrigger and the context the reviewer is missing. See the customization docs for the required frontmatter format.- Re-request a review — the reviewer reads guidelines from the PR branch, so your changes take effect immediately.
Was this review helpful? React with 👍 or 👎 to give feedback.
- onboarding-modal test: restore the progress-bar state-machine assertions (slide 2 = current, earlier segments = completed) the Gemini test dropped in the refactor, so it guards data-state and not just segment count. - docs(acp): note the default ACP commands are unpinned (`npx -y` = latest) and how to pin a version via Settings → Agent for production. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
✅ Review complete. This review was performed through OpenHands Cloud Automation. You can log in and view the conversation here. |
all-hands-bot
left a comment
There was a problem hiding this comment.
Review: feat(onboarding): collect Gemini ACP credentials + ACP agents docs
Context: Prior
all-hands-botreviews (10:07, 10:27, 11:56 UTC) covered the main observations — genericGEMINI_BASE_URLhint,CLAUDE_CONFIG_DIRdiscoverability,npx -yversion-pinning awareness, and progress-bar state assertions. The author addressed all of them in commits101bf7fdand8e24ff8c. This review evaluates the PR at its current HEAD.
Summary
Clean, minimal, well-motivated. Gemini CLI was the only built-in ACP provider that skipped credentials in onboarding — leaving no in-UI path to supply an API key for headless/cloud backends. The fix is a single constant entry; the existing provider-agnostic modal logic picks it up automatically. No modal, routing, or SDK changes were needed.
What's in the current HEAD
Functional change (src/constants/acp-providers.ts): New "gemini-cli" entry in ACP_PROVIDER_SECRETS with GEMINI_API_KEY (masked) and GEMINI_BASE_URL (plain text), mirroring the Codex entry structurally. The getAcpProviderSecrets JSDoc is updated to remove Gemini from the "returns empty" list. All comment blocks referencing the old "Gemini skips credentials" behaviour are updated consistently across the three source files.
Tests: The Gemini modal test is converted from asserting a skip-to-step-3 path to asserting slide-2 active + both credential fields rendered + 4 progress segments + slide 2 data-state=current. This is stronger coverage than the test it replaces. The setup-acp-secrets-step addition confirms field types (password/text). Both changes are accurate.
Docs (docs/ACP_AGENTS.md): Comprehensive and honest — the two real Gemini gotchas (GEMINI_BASE_URL routes on API-key path only; Google OAuth login auto-detected and preferred) are prominently documented. The CLAUDE_CONFIG_DIR auto-detection difference is correctly flagged as the exception. The npx -y behaviour is noted with a pinning override example. The Mermaid diagram gives a clear mental model.
Remaining observations (non-blocking)
1. GEMINI_BASE_URL hint text still generic
The hint_key reuses ONBOARDING$ACP_SECRET_BASE_URL_HINT (same as Claude Code / Codex). If that string says something like "optional base URL override" it is accurate for Gemini too, but it does not surface the OAuth-vs-API-key caveat in-UI. The caveat is documented in the ACP_PROVIDER_SECRETS block comment and in docs/ACP_AGENTS.md, so this is an acceptable v1 trade-off — the prior thread on this was closed as non-blocking. A follow-up could add a Gemini-specific hint key that surfaces the routing caveat inline.
2. skipStep2 comment minor tension
The comment now says "No built-in provider hits this today — all three collect a key" followed by "kept generic for any future OAuth-only provider". These two statements are logically consistent, but the first sentence could mislead a future contributor into thinking the skip path is dead code. Consider trimming it to just the intent: "Kept for future OAuth-only providers; no built-in provider triggers this today." — not a blocker.
Risk
🟢 LOW. Purely additive constant entry + docs. No existing credential flows, modal logic, or routing are removed. The only test that changed was already testing behaviour that is now intentionally obsolete.
Verdict
✅ Ready to merge. The functional change is exactly the right scope, all prior feedback has been addressed, and the documentation is among the clearest in the project.
This review was generated by an AI agent (OpenHands) on behalf of the user through OpenHands Automation. View conversation
Address review: lead the skipStep2 comment with its intent (generic path kept for a future OAuth-only provider) rather than "no built-in hits this today", which could read as dead code to a future contributor. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Addressed the two non-blocking observations from the latest review in
|
|
✅ Review complete. This review was performed through OpenHands Cloud Automation. You can log in and view the conversation here. |
all-hands-bot
left a comment
There was a problem hiding this comment.
Review: feat(onboarding): collect Gemini ACP credentials + ACP agents docs
Context: This is the fifth review pass. Prior
all-hands-botreviews thoroughly covered the main observations — genericGEMINI_BASE_URLhint,CLAUDE_CONFIG_DIRdiscoverability,npx -yversion-pinning awareness, and progress-bar state assertions. All were addressed by the author in101bf7fdand8e24ff8c. This review evaluates the PR at its current HEAD (ef039a3f).
Summary
Clean, minimal, and fully addressed. Gemini CLI was the only built-in ACP provider with no onboarding credentials step, leaving headless/cloud users with no in-UI path to supply a key. The fix is a single new entry in ACP_PROVIDER_SECRETS; the existing provider-agnostic modal logic (showAcpSecretsStep, skipStep2) picks it up automatically — no conditional changes needed.
Code Review
src/constants/acp-providers.ts — The "gemini-cli" block is structurally identical to "codex": secret: true on the API key, no secret flag on the base URL (plain text). Correct. The block comment has been updated to accurately describe all three providers and clearly notes the GEMINI_BASE_URL routing caveat (API-key path only, ignored under OAuth). The getAcpProviderSecrets JSDoc correctly removes Gemini from the "returns empty" list. ✅
src/components/features/onboarding/onboarding-modal.tsx — Comment-only changes updating the slide-2 documentation. The skipStep2 comment now reads "Kept for future OAuth-only providers; no built-in provider triggers this today", which is appropriately forward-looking without implying dead code. ✅
src/components/features/onboarding/steps/setup-acp-secrets-step.tsx — JSDoc and inline comment updated consistently with the new Gemini behavior. ✅
__tests__/components/onboarding/onboarding-modal.test.tsx — The refactored test is stronger than what it replaces: it now asserts slide-2 is active, both Gemini credential fields are rendered, 4 progress segments are in the DOM, and segment 2 carries data-state=current with segment 1 completed. This accurately captures the intended post-change behavior and is a regression-safe baseline. The removed waitFor for data-current-step="1" was redundant (implied by the subsequent waitFor(onboarding-backend-next) check). ✅
__tests__/components/onboarding/setup-acp-secrets-step.test.tsx — The new Gemini case confirms field input types (password for key, text for base URL), consistent with other provider tests. ✅
docs/ACP_AGENTS.md — Comprehensive and honest. The two Gemini gotchas (OAuth login preferred over API key; GEMINI_BASE_URL only routes on API-key path) are prominently documented. The CLAUDE_CONFIG_DIR non-auto-detection exception is correctly flagged as the outlier. The npx -y behavior is noted with a pinning override example. The Mermaid diagram and troubleshooting section add real value. ✅
Remaining (pre-existing, accepted as non-blocking)
GEMINI_BASE_URLhint still reuses the genericONBOARDING$ACP_SECRET_BASE_URL_HINT— accepted by the author as a follow-up; the routing caveat is covered in the block comment and docs.
Risk
🟢 LOW. Purely additive: one new constant entry + one new docs file. No modal routing, credential flows, or existing tests removed. The refactored Gemini modal test replaces an assertion for intentionally obsolete behavior.
Verdict
✅ Ready to merge. Functional change is exactly the right scope, all prior feedback has been addressed across multiple commits, and the documentation is among the clearest in the project.
This review was generated by an AI agent (OpenHands) on behalf of the user through OpenHands Automation. View conversation
…needed In the ACP "Add your API keys" step, add a concise line under the subtitle: "Already signed in with a subscription or login? Leave these blank — no API key needed." This reassures users on a subscription/OAuth path (e.g. Gemini's Google login, a Claude/ChatGPT login) that the optional fields can be skipped, instead of relying only on the per-field "leave blank" hint. New ONBOARDING$ACP_SECRETS_SUBSCRIPTION_NOTE key added across all 15 locales. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Added a concise subscription-auth note to the onboarding Add your API keys step in |
|
✅ Review complete. This review was performed through OpenHands Cloud Automation. You can log in and view the conversation here. |
all-hands-bot
left a comment
There was a problem hiding this comment.
Review: feat(onboarding): collect Gemini ACP credentials + ACP agents docs
Context: Previous
all-hands-botreviews (×5) thoroughly covered the main observations — genericGEMINI_BASE_URLhint text,CLAUDE_CONFIG_DIRdiscoverability,npx -yversion-pinning awareness, and progress-bar state assertions. All were addressed in101bf7fd,8e24ff8c, andef039a3f. This review evaluates the one new commit at the current HEAD (b1c1af4b) and confirms the full PR is clean.
New in b1c1af4b
src/components/features/onboarding/steps/setup-acp-secrets-step.tsx / src/i18n/translation.json — Adds a subtitle line: "Already signed in with a subscription or login? Leave these blank — no API key needed." This is a well-targeted UX improvement. The per-field hint_key only surfaces in each field's placeholder/tooltip; a step-level note makes the skip-intent visible before a user even focuses a field. The new ONBOARDING$ACP_SECRETS_SUBSCRIPTION_NOTE key ships with 15 locale translations (matching the project's locale coverage) and uses zero dynamic interpolation, so there's no risk of a missing-variable runtime error.
The text-[var(--oh-muted)] class is consistent with how other de-emphasized help text is styled in the onboarding flow.
Full-PR assessment (current HEAD)
🟢 Good taste — Clean, minimal, and fully addressed. The functional change is a single new entry in ACP_PROVIDER_SECRETS; the modal's existing showAcpSecretsStep / skipStep2 logic picks it up automatically with no conditional changes. The test suite was correctly updated to replace assertions for now-obsolete behavior with positive assertions confirming the new credential fields and 4-segment progress bar. The docs are among the clearest in the project.
[RISK ASSESSMENT]
- [Overall PR]
⚠️ Risk Assessment: 🟢 LOW
Purely additive: one new constant entry, one new docs file, one UX hint, and updated tests. No routing logic or credential flow changed. No existing tests removed; the refactored Gemini modal test replaces an assertion for intentionally obsolete behavior.
VERDICT:
✅ Worth merging — All prior feedback has been addressed across multiple commits. The latest commit adds a clear, well-localised UX hint with no risk.
KEY INSIGHT: Making all three built-in ACP providers structurally uniform (same constant shape, same onboarding path) is the right move — it eliminates the special-case skipStep2 branch for Gemini and makes the modal logic a simple acpSecretFields.length > 0 gate.
This review was generated by an AI agent (OpenHands) on behalf of the user through OpenHands Automation. View conversation
/simplify: ACP_PROVIDER_SECRETS hand-maintained three structurally-identical per-provider entries (API key + base URL) whose env-var names already live in the SDK registry (api_key_env_var / base_url_env_var, mirrored via @openhands/typescript-client). Replace the parallel list with a derivation in getAcpProviderSecrets: read the env vars off getAcpProvider(key) and attach the Canvas-only bits (masked API key, plain base URL, hint keys). Behavior-preserving — the registry names match the removed literals exactly (ANTHROPIC_/OPENAI_/GEMINI_ _API_KEY/_BASE_URL), verified by the onboarding + secrets-step tests and a live run. Removes drift risk and the silent "provider in ACP_PROVIDERS but missing from the secrets list shows no step" failure mode; a future provider with an api_key_env_var now gets a credentials step for free. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
✅ Review complete. This review was performed through OpenHands Cloud Automation. You can log in and view the conversation here. |
all-hands-bot
left a comment
There was a problem hiding this comment.
Review: feat(onboarding): collect Gemini ACP credentials + ACP agents docs
Context: This review targets the current HEAD (
5dabfe4b) — the most recent commit — and gives an overall PR assessment. Priorall-hands-botreviews (×6) coveredCLAUDE_CONFIG_DIRdiscoverability,GEMINI_BASE_URLhint caveat,npx -yversion-pinning, and progress-bar assertions; all were addressed in101bf7fd,8e24ff8c,ef039a3f, andb1c1af4b.
New in 5dabfe4b — Registry-derived credential fields
This commit replaces the hand-maintained ACP_PROVIDER_SECRETS map with a dynamic derivation from getClientAcpProvider(), pulling api_key_env_var and base_url_env_var directly out of the SDK registry (mirrored by @openhands/typescript-client). It's a clean architectural improvement with two concrete wins:
- No drift. The env-var names previously lived in two places (the registry and the Canvas constant). A registry rename would leave Canvas silently showing stale field names until someone noticed. With derivation, the TypeScript client propagates any rename at compile time.
- Future providers are free. Any new provider added to the SDK registry with an
api_key_env_vargets a credentials step in Canvas automatically, with no parallel Canvas update required.
The implementation handles edge cases correctly: null / undefined key → []; missing api_key_env_var → no password field; missing base_url_env_var → no text field. The secret: true on API keys is hardcoded and correct — API keys must always be masked regardless of provider.
The trade-off (SDK renames now propagate automatically) is the right one: renaming a provider's env var in the SDK is already a breaking change for anyone depending on the subprocess environment, so Canvas should track it.
Full-PR assessment (current HEAD 5dabfe4b)
🟢 Good taste — Each commit in this series is focused and well-motivated. The functional change (Gemini CLI gets GEMINI_API_KEY + GEMINI_BASE_URL in onboarding) is small; the rest is documentation, test corrections, UX polish, and a clean architectural refactor. The modal's existing showAcpSecretsStep / skipStep2 logic required zero conditional changes because the gate was already acpSecretFields.length > 0. Making all three built-in ACP providers structurally uniform was the right call.
Risk: 🟢 LOW. Purely additive at the feature level. The refactor in 5dabfe4b is behavior-preserving (env-var names match the removed literals exactly, confirmed by the tests). No routing logic changed; no secrets handling changed.
VERDICT: ✅ Ready to merge.
This review was generated by an AI agent (OpenHands) on behalf of the user through OpenHands Automation. View conversation
…ected The previous text claimed Claude Code's login is "via CLAUDE_CONFIG_DIR pointing at your ~/.claude credentials" and "must be set on the backend — not auto-detected." That's wrong. Verified on macOS: the OAuth token lives in the **system Keychain** (item "Claude Code-credentials"), ~/.claude holds only config/state (no token), and CLAUDE_CONFIG_DIR was unset while Claude Code was logged in. claude-agent-acp confirms CLAUDE_CONFIG_DIR merely defaults to ~/.claude and points at settings + session history, not credentials. Corrected: Claude Code's login is auto-detected from its own store (macOS Keychain, or ~/.claude/.credentials.json on Linux); CLAUDE_CONFIG_DIR is not required and only relocates the config dir (containers/multi-account). Kept the real nuance: if ANTHROPIC_API_KEY is set Claude Code uses it instead of the login, and a headless setup can set CLAUDE_CONFIG_DIR to make the SDK strip a conflicting key so the OAuth token wins. Also generalized the intro (a login is a file *or* the macOS Keychain) and dropped the inaccurate blanket "subscription login always wins" (true for Codex/Gemini; Claude prefers an env API key). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
✅ Review complete. This review was performed through OpenHands Cloud Automation. You can log in and view the conversation here. |
all-hands-bot
left a comment
There was a problem hiding this comment.
Review: feat(onboarding): collect Gemini ACP credentials + ACP agents docs
Context: This is the eighth review pass on this PR. Prior
all-hands-botreviews (×7) covered the full feature and refactor —GEMINI_BASE_URLcaveat,npx -yversion-pinning,CLAUDE_CONFIG_DIRdiscoverability, registry-derived credential fields, and the UX note about subscription / OAuth logins. All prior observations were addressed across the commit series (101bf7fd,8e24ff8c,ef039a3f,b1c1af4b,5dabfe4b). The previous review at5dabfe4bdeclared this Ready to merge.
This review covers only the new commit 849663e0.
849663e0 — docs(acp): correct Claude Code subscription login detection
A targeted documentation correction to docs/ACP_AGENTS.md. The prior text incorrectly claimed:
- Claude Code's login requires
CLAUDE_CONFIG_DIRto be set and is not auto-detected. - A subscription login always wins over an API key (false for Claude Code — it's actually the opposite).
The correction is factually accurate:
- Claude Code stores its OAuth token in the macOS Keychain (or
~/.claude/.credentials.jsonon Linux) and auto-detects it with noCLAUDE_CONFIG_DIRneeded. CLAUDE_CONFIG_DIRonly relocates the config/session-history directory (settings, session history), not the credential store. Its real use case is containers or multi-account setups.- Claude Code's actual precedence is the reverse of Codex and Gemini: if
ANTHROPIC_API_KEYis present it wins; the OAuth token is the fallback. The corrected text captures this nuance correctly. - The
CLAUDE_CONFIG_DIR+ SDK key-stripping behaviour for headless OAuth-forced setups is a genuine (if uncommon) edge case and is correctly retained.
The table reformulation ("Subscription login (auto-detected)" / "API key") and the rewritten callout are clear improvements. No code changes; no test changes needed.
Full-PR assessment (current HEAD 849663e0)
🟢 Good taste — Two related, well-scoped changes (Gemini CLI credentials parity + ACP docs) with a clean refactor (registry-derived fields) layered in. Each commit is focused. The functional gap (no in-UI path for a headless Gemini backend to receive a key) is real and the fix is minimal. The latest commit closes a factual inaccuracy in the docs about Claude Code's authentication flow.
[RISK ASSESSMENT]
- [Overall PR]
⚠️ Risk Assessment: 🟢 LOW — Additive feature on a previously skipped onboarding slide; registry-derived fields are behavior-preserving (confirmed by tests); latest commit is documentation-only.
VERDICT: ✅ Ready to merge.
This review was generated by an AI agent (OpenHands) on behalf of the user through OpenHands Automation. View conversation
- Drop the Troubleshooting section. - Remove the "Onboarding asks for" column from the providers table (identical for all three; authentication is covered in its own section). - Remove the npx version-pinning note and the vendor-wrapper [!NOTE]. - Remove the secret-name-pattern / "key is only a fallback" paragraph. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
✅ Review complete. This review was performed through OpenHands Cloud Automation. You can log in and view the conversation here. |
all-hands-bot
left a comment
There was a problem hiding this comment.
Review: feat(onboarding): collect Gemini ACP credentials + ACP agents docs
Context: All five prior inline review threads are resolved, and prior
all-hands-botreviews coveredGEMINI_BASE_URLhint specificity,CLAUDE_CONFIG_DIRdiscoverability,npx -yversion-pinning, and progress-bar state assertions. This is an independent review of the PR at current HEAD (849663e0).
Core architectural change — registry-derived credential fields (src/constants/acp-providers.ts)
The replacement of the hardcoded ACP_PROVIDER_SECRETS map with dynamic derivation from getClientAcpProvider() is the standout architectural improvement. The previous design required a parallel Canvas update every time the SDK registry added or renamed a provider — a silent drift risk. The new implementation propagates env-var names at compile time: a registry rename becomes a TypeScript error rather than a stale field name in the UI.
Edge cases are handled correctly:
null/undefinedkey →[](no credentials step)api_key_env_varabsent → no password fieldbase_url_env_varabsent → no URL fieldsecret: truehardcoded for all API keys — correct, independent of provider
The trade-off (SDK renames now auto-propagate to the form) is the right one: any such rename is already a breaking change for the subprocess environment.
Gemini credential parity (src/constants/acp-providers.ts, onboarding-modal.tsx)
The gap is cleanly closed. getAcpProviderSecrets("gemini-cli") now returns [GEMINI_API_KEY (masked), GEMINI_BASE_URL (text)] via registry derivation, requiring zero changes to the modal's showAcpSecretsStep / skipStep2 logic — the existing acpSecretFields.length > 0 check handles it automatically.
The retained skipStep2 path remains correct for any future OAuth-only provider whose registry entry carries no api_key_env_var.
UX — subscription note (setup-acp-secrets-step.tsx, translation.json)
The new ONBOARDING$ACP_SECRETS_SUBSCRIPTION_NOTE paragraph is well-placed (after the per-provider description, before the form fields) and appropriately styled (text-[var(--oh-muted)] matches existing help text). It correctly applies to all three built-in providers — Claude Code and Codex users with subscription logins equally benefit from knowing the fields are optional.
The 15-locale coverage matches the project's existing i18n breadth. Zero dynamic interpolation means no runtime variable-missing risk.
Minor nuance (non-blocking, for awareness): Claude Code's auth precedence is inverted from the others (ANTHROPIC_API_KEY wins over the OAuth login if both are present), whereas the note says "Already signed in? Leave these blank." This is fine for the onboarding context — the note advises users not to enter a key, not making claims about precedence when both exist simultaneously. The precedence detail is already accurately captured in docs/ACP_AGENTS.md. No change needed.
Documentation (docs/ACP_AGENTS.md)
Strong addition. Highlights:
- Mermaid architecture diagram communicates the Canvas → Server → ACP subprocess boundary effectively
- The explicit
@openai/codex acpanti-pattern callout is genuinely useful — this footgun causes silent handshake deadlocks - The Claude Code credential detection correction (
849663e0) is factually accurate: Keychain /~/.claude/.credentials.jsonauto-detected with noCLAUDE_CONFIG_DIRneeded;CLAUDE_CONFIG_DIRonly relocates config/session-history - The
CLAUDE_CONFIG_DIR+ SDK key-stripping edge case for forced-OAuth headless setups is correctly retained npx -yversion-pinning awareness note added to the providers table ✓- Troubleshooting section covers the main real-world failure modes (deadlocked handshake, auth errors, model not found, per-backend agent choice)
Tests
onboarding-modal.test.tsx: correctly converted from "skips slide 2" to "renders credential step", with positive assertions ononboarding-acp-secret-GEMINI_API_KEY,onboarding-acp-secret-GEMINI_BASE_URL, slide-2 active, and the 4-segment progress-bar state machine (step 2 current, step 1 completed)setup-acp-secrets-step.test.tsx: new Gemini case confirmsGEMINI_API_KEYrenders astype="password"andGEMINI_BASE_URLastype="text"✓
Summary
🟢 Ready to merge. The functional change is minimal and well-motivated: one registry-derived field list replaces a hand-maintained map, closing the Gemini credential gap with no downstream code changes required. All prior feedback has been addressed. Tests guard both the new behavior and the state machine.
[RISK ASSESSMENT]
- [Overall PR]
⚠️ Risk Assessment: 🟢 LOW — purely additive (new doc, new i18n key, one new registry-derived lookup). No routing logic, credential flow, or auth path changed.
This review was generated by an AI agent (OpenHands) on behalf of the user through OpenHands Automation. View conversation
📸 Snapshot Test Report✅ All snapshots match the main branch baselines.
✅ Unchanged snapshots (73)
Generated by the Snapshot Tests workflow. This comment was created by an AI agent (OpenHands) on behalf of the repo maintainers. |
What
Two related changes for ACP agents:
docs/ACP_AGENTS.mdguide explaining what ACP agents are, how to onboard them, how authentication works (subscription login vs API key, and the local auto-detection precedence), and how to switch agent/model later. Linked from the docs index.GEMINI_API_KEY+GEMINI_BASE_URLfor Gemini CLI, the same way it already does for Claude Code and Codex.Why the Gemini change
Gemini CLI was the only built-in ACP provider whose onboarding skipped the credentials step, on the premise that it "authenticates via OAuth, not an env-var key." But the SDK has supported
gemini-api-keyauth since software-agent-sdk #2619 andGEMINI_BASE_URLrouting since the registry centralization (#3022) — so the omission left no in-UI way to give a headless/cloud Gemini backend a key (you'd have to hand-create the secret). This closes that gap and brings Gemini to parity.ACP_PROVIDER_SECRETSgains agemini-clientry (GEMINI_API_KEYmasked + optionalGEMINI_BASE_URL), reusing the existing generic hint keys.GEMINI_BASE_URLonly routes on the API-key path (it's passed as the ACPgatewayendpoint), not under the OAuth login.Docs simplification
Since Gemini is no longer special in onboarding, the guide drops the "Gemini skips the credentials step" framing — the providers table and onboarding steps now treat all three uniformly, while the auth-precedence section (subscription preferred, key fallback) and the two genuine Gemini specifics (Google login is the common no-key local path; base-URL gateway caveat) are retained.
Tests
setup-acp-secrets-step.test.tsx.react-router typegen && tsc,eslint,prettier --check, and the onboarding + constants suites (37 tests) pass locally; pre-commit (typecheck:staged + lint-staged) green.Notes
🤖 Generated with Claude Code
🐳 Docker images for this PR
• GHCR package: https://github.com/OpenHands/agent-canvas/pkgs/container/agent-canvas
ghcr.io/openhands/agent-canvasghcr.io/openhands/agent-server:1.24.0-pythonopenhands-automation==1.0.0a5438bdcc708d2263f9cade37708fe8ae5c60358c4Pull (multi-arch manifest)
# Multi-arch manifest — Docker automatically pulls the correct architecture docker pull ghcr.io/openhands/agent-canvas:sha-438bdccRun
All tags pushed for this build
About Multi-Architecture Support
sha-438bdcc) is a multi-arch manifest supporting both amd64 and arm64sha-438bdcc-amd64) are also available if needed