Skip to content

feat(onboarding): auto-detect ACP subscription/login via /api/acp/auth-status#971

Open
simonrosenberg wants to merge 2 commits into
mainfrom
feat-acp-auth-status-wire
Open

feat(onboarding): auto-detect ACP subscription/login via /api/acp/auth-status#971
simonrosenberg wants to merge 2 commits into
mainfrom
feat-acp-auth-status-wire

Conversation

@simonrosenberg
Copy link
Copy Markdown
Member

@simonrosenberg simonrosenberg commented Jun 1, 2026

Summary

Phase 1 canvas side of #964. During ACP onboarding (Claude Code / Codex / Gemini), the credentials step now detects whether the chosen provider's CLI is already authenticated — by a subscription login (Claude Pro/Max, ChatGPT, Google) or a pre-set API key — and shows a "✓ you're already logged in" banner instead of unconditionally asking for an API key.

Detection rides the agent-server's purpose-built endpoint from software-agent-sdk#3452, which drives the ACP initialize + session/new handshake server-side. No prompt is sent, so it spends no model tokens, and because the probe runs inside the agent-server it reports the truth for wherever the agent actually runs.

Onboarding credentials step
  │  useAcpAuthStatus(providerKey)
  ▼
AcpService.getAuthStatus(server)            ← new canvas service
  │  AcpClient (typescript-client #196)
  ▼
GET /api/acp/auth-status?server=<key>       ← agent-server (sdk #3452)
  → { status: authenticated | unauthenticated | unknown, ... }

Changes

  • AcpService (src/api/acp-service/acp-service.api.ts) — wraps the new AcpClient from @openhands/typescript-client, constructed from the active backend's client options, so all agent-server access stays typed (the no-direct-agent-server-calls guard stays satisfied).
  • useAcpAuthStatus now calls GET /api/acp/auth-status instead of the canvas-only "Phase 0" throwaway-conversation probe (closed PR feat(onboarding): detect existing ACP subscription/login (Phase 0, canvas-only) #968, which was a false positive — conversation-create doesn't run the handshake). A failed/unreachable probe falls back to "unknown", so we never falsely claim "not logged in". The hook's public shape is unchanged.
  • Onboarding banner UI (credentials step) carried over from feat(onboarding): detect existing ACP subscription/login (Phase 0, canvas-only) #968: green "✓ logged in" banner when authenticated, spinner while checking, API-key fields otherwise. Gated to local backends with credential fields; cached per provider per backend; never blocks the (skippable) step.

Temporary SHA pin

@openhands/typescript-client is pinned by SHA to the AcpClient commit (OpenHands/typescript-client#196) so this can be validated end-to-end before that PR is released. Swap to the released version once published.

Validation

  • npm run typecheck, eslint, prettier --check: clean.
  • vitest run for use-acp-auth-status, the two onboarding step/modal tests, and the no-direct-agent-server-calls guard: green.
  • Manual end-to-end against a local agent-server running the sdk#3452 branch (see PR thread).

Dependencies

Refs #964

🤖 Generated with Claude Code


🐳 Docker images for this PR

GHCR package: https://github.com/OpenHands/agent-canvas/pkgs/container/agent-canvas

Component Value
Image ghcr.io/openhands/agent-canvas
Architectures amd64, arm64
Agent Server ghcr.io/openhands/agent-server:1.24.0-python
Automation openhands-automation==1.0.0a5
Commit f76d648195cf1c51f27af830427c2a406e4b4e66

Pull (multi-arch manifest)

# Multi-arch manifest — Docker automatically pulls the correct architecture
docker pull ghcr.io/openhands/agent-canvas:sha-f76d648

Run

docker run -it --rm \
  -p 8000:8000 \
  ghcr.io/openhands/agent-canvas:sha-f76d648

All tags pushed for this build

ghcr.io/openhands/agent-canvas:sha-f76d648-amd64
ghcr.io/openhands/agent-canvas:feat-acp-auth-status-wire-amd64
ghcr.io/openhands/agent-canvas:pr-971-amd64
ghcr.io/openhands/agent-canvas:sha-f76d648-arm64
ghcr.io/openhands/agent-canvas:feat-acp-auth-status-wire-arm64
ghcr.io/openhands/agent-canvas:pr-971-arm64
ghcr.io/openhands/agent-canvas:sha-f76d648
ghcr.io/openhands/agent-canvas:feat-acp-auth-status-wire
ghcr.io/openhands/agent-canvas:pr-971

About Multi-Architecture Support

  • Each tag (e.g., sha-f76d648) is a multi-arch manifest supporting both amd64 and arm64
  • Docker automatically pulls the correct architecture for your platform
  • Individual architecture tags (e.g., sha-f76d648-amd64) are also available if needed

…h-status

Onboarding now probes whether the chosen ACP provider's CLI is already
authenticated (Claude Pro/Max, ChatGPT, Google subscription — or a pre-set
API key) and shows a "✓ you're already logged in" banner instead of
unconditionally asking for an API key. Refs #964.

Detection rides the agent-server's purpose-built endpoint added in
software-agent-sdk#3452, which drives the ACP initialize + session/new
handshake server-side (no prompt → no model tokens) and returns
authenticated / unauthenticated / unknown.

- `AcpService.getAuthStatus(server)` wraps the new `AcpClient` from
  `@openhands/typescript-client`, keeping all agent-server access typed (the
  no-direct-agent-server-calls guard stays satisfied).
- `useAcpAuthStatus` now calls `GET /api/acp/auth-status` instead of the
  canvas-only "Phase 0" throwaway-conversation probe (closed PR #968). A
  failed/unreachable probe falls back to "unknown" so we never falsely claim
  "not logged in". The hook's public shape is unchanged, so the onboarding
  banner UI carried over from #968 did not change.
- Gated to local backends with credential fields; cached per provider per
  backend; never blocks the (skippable) step.

The `@openhands/typescript-client` dependency is temporarily pinned to the
`AcpClient` commit (OpenHands/typescript-client#196) by SHA so this can be
validated end-to-end before that PR is released; swap to the released version
once published.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@vercel
Copy link
Copy Markdown

vercel Bot commented Jun 1, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
agent-canvas Ready Ready Preview, Comment Jun 1, 2026 3:17pm

Request Review

…roviders)

Gemini was the one provider the feature most benefits — it logs in via Google
OAuth, so a user with no API key is exactly who should see "✓ you're already
signed in" — yet it was never probed. The probe was gated on "does this provider
have API-key fields" (`getAcpProviderSecrets(...).length > 0`), and the
onboarding flow skipped the whole credentials slide for Gemini. The agent-server
can detect Gemini fine (the handshake returns authenticated / auth_required).

- `useAcpAuthStatus`: drop the `hasCredentials` gate — eligibility is now just
  "local backend". The server returns `unknown` (422 → caught) for anything it
  can't probe, so coupling to key-fields was both wrong (excluded Gemini) and
  unnecessary. `AcpAuthStatus` now aliases the client's `ACPAuthStatusValue`
  instead of a hand-redefined union.
- Onboarding modal: every non-OpenHands provider now shows slide 2, so the
  `skipStep2` machinery (nav deltas + progress-bar remapping) is deleted — the
  flow is a plain 4-step sequence again.
- Credentials step: for providers with no key fields it renders a login-status
  screen — "Sign in to {provider}" + a browser-OAuth subtitle, the "you're
  already signed in" banner when authenticated, and no inputs. Claude Code /
  Codex are unchanged (key fields + banner).
- New i18n: ACP_LOGIN_TITLE, ACP_LOGIN_SUBTITLE, ACP_AUTH_DETECTED_NO_KEY.

Tests: hook now asserts Gemini IS probed; modal asserts slide 2 renders as a
key-less login screen (no skip, 4 segments); step asserts the login-only render.

Refs #964

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 1, 2026

📸 Snapshot Test Report

✅ All snapshots match the main branch baselines.

Category Count
🔴 Changed 0
🆕 New 0
✅ Unchanged 73
Total 73
✅ Unchanged snapshots (73)

archived-conversation

  • conversation-panel-with-archived-badges
  • conversation-view-archived
  • conversation-view-sandbox-error

automations

  • automations-delete-modal
  • automations-list-active-inactive
  • automations-no-automations
  • automations-search-no-results

backends-extended

  • backend-add-blank-disabled
  • backend-add-cloud-advanced-open
  • backend-add-cloud-no-key-disabled
  • backend-add-cloud-with-key-enabled
  • backend-add-form-partially-filled
  • backend-add-invalid-url-disabled
  • backend-add-local-ready
  • backend-add-name-only-disabled
  • backend-add-two-column-layout
  • backend-add-whitespace-host-disabled
  • backend-after-switch
  • backend-cancel-nothing-saved
  • backend-dropdown-two-backends
  • backend-edit-prefilled
  • backend-manage-after-removal
  • backend-manage-two-listed
  • backend-remove-cancelled
  • backend-remove-confirmation
  • backend-switch-overlay

backends

  • backend-add-modal
  • backend-manage-modal
  • backend-selector-open

changes-tab

  • changes-deleted-file
  • changes-diff-viewer
  • changes-empty

collapsible-thinking

  • reasoning-content-collapsed
  • reasoning-content-expanded
  • think-action-collapsed
  • think-action-expanded

mcp-page

  • mcp-custom-server-1-editor-open
  • mcp-custom-server-2-url-filled
  • mcp-custom-server-3-all-filled
  • mcp-custom-server-4-installed
  • mcp-custom-server-editor
  • mcp-empty-installed
  • mcp-search-filtered
  • mcp-slack-install-1-marketplace
  • mcp-slack-install-2-modal
  • mcp-slack-install-3-filled
  • mcp-slack-install-4-installed

onboarding

  • onboarding-step-0-choose-agent
  • onboarding-step-1-check-backend
  • onboarding-step-2-setup-llm
  • onboarding-step-3-say-hello

projects-workspace-browser

  • projects-workspace-browser

settings-page

  • add-backend-modal
  • analytics-consent-modal
  • home-screen
  • settings-app-page
  • settings-page

settings-secrets

  • secrets-add-form-filled
  • secrets-add-form
  • secrets-after-save
  • secrets-delete-confirm
  • secrets-list

settings-verification

  • condenser-settings
  • verification-settings-off
  • verification-settings-on

sidebar

  • sidebar-collapsed
  • sidebar-conversation-panel
  • sidebar-filter-menu

skills-page

  • skills-empty
  • skills-loaded
  • skills-no-match
  • skills-search-filtered
  • skills-type-filter

Generated by the Snapshot Tests workflow. This comment was created by an AI agent (OpenHands) on behalf of the repo maintainers.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant