Add ChatGPT subscription LLM support#744
Conversation
Co-authored-by: openhands <openhands@all-hands.dev>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
all-hands-bot
left a comment
There was a problem hiding this comment.
Review Summary
🟡 Acceptable with critical issues - The subscription auth feature is well-structured overall, but has fundamental issues that must be addressed before merging.
[CRITICAL ISSUES]
-
[__tests__/api/llm-subscription-service.test.ts] Test Quality: The core test suite violates repository guidelines by mocking the entire
LLMMetadataClientHTTP client instead of testing real code paths with MSW. This means tests won't catch actual regressions when the HTTP layer, auth headers, or server contract changes. Rewrite to use the MSW handlers already available insettings-handlers.ts. -
[src/components/features/settings/llm-profiles/llm-settings-local-view.tsx:170] Complexity: The
handleSavefunction has >4 levels of nesting (try-catch → rename if → auth type if-else → subscription model if → API key if-else → base_url if → wasActive if), violating the repository's '3 levels max' guideline. Extract helpers:buildLlmConfigForAuthType(),handleProfileRename(),handleProfileReactivation(). -
[src/api/llm-subscription-service.ts:78] Type Safety: Unsafe casting
(client as unknown as LLMMetadataClientWithTransport).clientto access internal transport. If@openhands/typescript-clientchanges its internal structure, this fails at runtime with cryptic errors. Add runtime validation that the transport exists and has the expected methods before using it.
[IMPORTANT ISSUES]
-
[src/components/features/settings/llm-settings/openai-subscription-auth-card.tsx:61] User Experience: When polling returns
connected: false, an error toast is shown with a "PENDING" message. This is misleading—users think something failed when they just need to wait. Use an info/warning toast or inline status text instead. -
[src/components/features/settings/llm-settings/openai-subscription-auth-card.tsx:36] State Management: Users can get stuck in the challenge state if they start device login but close the tab or navigate away. No way to clear the challenge except completing login or logging out (which fails if not connected). Add a "Cancel" button to reset challenge state.
-
[src/routes/llm-settings.tsx:219] Data Flow: Model selection is silently changed when switching auth types. If a user has 'gpt-4o', switches to subscription to explore, then switches back, their original selection is lost forever (replaced with
defaultModel). Store previous models in component state and restore them, or at minimum show a toast explaining the change. -
[src/api/llm-subscription-service.ts:109] Validation: Missing validation for empty strings in
normalizeDeviceChallenge. A buggy server could return empty strings that pass the!deviceCodecheck. Add.trim().length > 0validation fordeviceCode,userCode, andverificationUri. -
[__tests__/api/llm-subscription-service.test.ts] Test Coverage: Missing critical test cases: error handling (401/403, 500, timeouts, malformed responses), validation (incomplete device challenges), end-to-end integration (full device flow), and edge cases (empty strings, null values, concurrent requests).
-
[src/api/llm-subscription-service.ts:87] Error Handling: Network errors from the HTTP client propagate without context. Wrap errors to provide more specific messages about which subscription operation failed.
[SUGGESTIONS]
-
[src/api/agent-server-adapter.ts:820] Documentation: Add docstring to
assertSubscriptionAuthReadynoting that it's NOT called when resuming conversations or sending additional messages, so subscriptions could expire mid-conversation. The agent-server must handle expired tokens gracefully. -
[src/api/llm-subscription-service.ts:136] Data Structure: The
expiresAtfield tries both string and number fallbacks, includingexpires_inwhich is typically a relative duration in seconds, not an absolute timestamp. Mixing relative and absolute time values in the same field could cause confusion. Document the expected behavior or convert relative durations to absolute timestamps. -
[src/hooks/query/use-llm-subscription-status.ts:14] Query Configuration:
staleTimeof 30 seconds seems short for auth status that rarely changes. Consider 5 minutes to reduce unnecessary network requests, especially since mutations properly invalidate this query.
[RISK ASSESSMENT]
🟡 MEDIUM RISK - This PR adds new authentication flows and modifies conversation creation logic. The main risks are:
- Untested error paths could cause poor UX when auth fails
- Complex nested logic increases maintenance burden
- Type safety issues could cause runtime failures with SDK updates
Not blocking auto-merge based on risk alone, but the critical issues above should be addressed.
VERDICT:
❌ Needs rework - Address the critical test quality and complexity issues, then fix the important UX and validation gaps.
KEY INSIGHT:
The subscription auth implementation follows OAuth device flow patterns correctly, and backward compatibility is preserved (API key flows still work). However, the test suite doesn't provide confidence that the integration will work in production, and the complex nested save logic creates maintenance risk. Focus first on rewriting tests to use MSW and refactoring handleSave.
Was this automated review useful? React with 👍 or 👎 to this review to help us measure review quality.
Workflow run: https://github.com/OpenHands/agent-canvas/actions/runs/26336381445
Co-authored-by: openhands <openhands@all-hands.dev>
📸 Snapshot Test ReportWarning Snapshot comparison step crashed (timeout, OOM, or runner error) — diff results below may be incomplete or absent. ✅ 1 snapshot changed — acknowledged via the
✅ Unchanged snapshots (72)
Generated by the Snapshot Tests workflow. This comment was created by an AI agent (OpenHands) on behalf of the repo maintainers. |



Summary
Verification
npm run typechecknpx vitest run __tests__/api/llm-subscription-service.test.ts __tests__/api/agent-server-adapter.test.ts __tests__/routes/llm-settings.test.tsxnpm run check-translation-completenessnpm testnpm run lintnpm run buildNotes
This PR was created by an AI agent (OpenHands) on behalf of the user.
🐳 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.23.0-pythonopenhands-automation==1.0.0a383e343c3bef1e1da25b168af210fc6196d03d569Pull (multi-arch manifest)
# Multi-arch manifest — Docker automatically pulls the correct architecture docker pull ghcr.io/openhands/agent-canvas:sha-83e343cRun
All tags pushed for this build
About Multi-Architecture Support
sha-83e343c) is a multi-arch manifest supporting both amd64 and arm64sha-83e343c-amd64) are also available if neededCompanion PRs / temporary pins
@openhands/typescript-clientpoints atgit+https://github.com/OpenHands/typescript-client.git#add-llm-subscription-clientuntil the client PR is merged and released.OH_AGENT_SERVER_GIT_REF=add-llm-subscription-endpointsfor manual live testing until the SDK PR is merged and released.This PR description update was created by an AI agent (OpenHands) on behalf of the user.