feat: LLM profiles route integration (PR C)#393
Conversation
- Add LlmSettingsLocalView component for integrated profile management - Extend SdkSectionSaveControl to expose form values for custom save flows - Update LLM settings route to render profile list with create/edit views - Add i18n keys for profile create/edit UI (CREATE_PROFILE, EDIT_PROFILE, PROFILE_CREATED, PROFILE_UPDATED, MODEL_REQUIRED, STATUS, BUTTON) - Add test coverage for LlmSettingsLocalView The integrated view shows: - Profile list with active badge and action menu - Add Profile button that opens create form - Edit button that loads profile config and opens edit form - Back/Cancel buttons to return to list view 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.
The route integration works and the component structure is reasonable, but there are a few areas that need attention around test quality, component complexity, and evidence of the working UI.
Key concerns:
- Tests only verify mocked hook calls, not actual save flow behavior
- Main component has high complexity with multiple responsibilities
- API key preservation logic could be more robust
- Missing visual evidence of the working UI flow
- Improve mock typing with properly typed helper functions that provide all required React Query fields, eliminating incomplete 'as unknown as' casts - Add integration test that verifies the save flow (fills in profile name, clicks save, verifies UI state transitions) - Add component documentation noting future refactoring opportunity (extract useProfileForm, useProfileSave hooks for better testability) - Document API key preservation behavior: currently preserves existing encrypted key in edit mode with no new key; note about potential 'Clear API Key' UX enhancement for future - Document auto-derive name race condition: client-side uniqueness check uses render-time state, so concurrent profile creation by another client would result in server conflict error (handled gracefully) - Document default export change in route file: LlmSettingsLocalView is now the default export; named export LlmSettingsScreen remains for embedded use Co-authored-by: openhands <openhands@all-hands.dev>
|
Addressed all feedback in 545fdfa. Ready for another look. Changes made:
All 8 tests passing. |
The default export of llm-settings.tsx changed to render LlmSettingsLocalView (the profiles manager). The test needs to import the named export LlmSettingsScreen to test the form component directly. Co-authored-by: openhands <openhands@all-hands.dev>
|
Fixed CI failure in e41dc5d - the llm-settings test needed to use the named export |
all-hands-bot
left a comment
There was a problem hiding this comment.
🟢 Good taste - Clean, incremental feature addition with appropriate separation of concerns.
All previous review feedback has been addressed. The component complexity and API key preservation concerns are well-documented for future iteration.
[RISK ASSESSMENT]
🟢 LOW - Frontend-only UI changes for LLM profile management. No impact on agent behavior, tool execution, or evaluation paths.
VERDICT:
✅ Worth merging - Solid route integration that completes the LLM profiles feature.
KEY INSIGHT:
The architecture appropriately delegates form complexity to the existing LlmSettingsScreen while keeping profile-specific concerns (naming, validation, save orchestration) at the view layer.
…0.6.0 - BrandButton: Change padding from p-2 to px-3 py-2 for better text display - ProfileRow: Increase active badge vertical padding from py-0.5 to py-1 - Update @openhands/typescript-client from commit SHA to v0.6.0 tag Co-authored-by: openhands <openhands@all-hands.dev>
… create mode - LlmSettingsRoute: Render LlmSettingsScreen (standard form) for cloud backends and LlmSettingsLocalView (profile manager) for local backends only - LlmSettingsLocalView: Pass empty initial values in create mode to ensure fresh form fields, add key prop to force form remount between profiles - Add unit tests for cloud vs local backend rendering - Add unit tests for create mode empty form initialization Co-authored-by: openhands <openhands@all-hands.dev>
- Fix initialValueOverrides logic to properly check for edit mode AND existing initialValues before using them - Add prefix to edit mode key for clearer remount semantics - Add unit tests verifying edit mode populates profile name correctly - Add unit tests verifying getProfile is called with encrypted mode Co-authored-by: openhands <openhands@all-hands.dev>
Co-authored-by: openhands <openhands@all-hands.dev>
…g.llm The API returns profile config with llm settings at the top level (config.model, config.api_key, config.base_url), not nested under config.llm. Fixed the parsing to read directly from detail.config. Co-authored-by: openhands <openhands@all-hands.dev>
When editing a profile and changing its name: 1. Rename the profile first using ProfilesService.renameProfile 2. Then save the profile config to the new name 3. If the renamed profile was the active profile, re-activate it after the rename (since rename doesn't update active_profile) This prevents creating duplicate profiles when just changing the name. Co-authored-by: openhands <openhands@all-hands.dev>
all-hands-bot
left a comment
There was a problem hiding this comment.
The route integration is well-implemented and all previous review feedback has been properly addressed. However, there's one blocking issue with the dependency update that needs to be fixed before merge.
The lock file was using git+ssh:// protocol which causes Vercel build failures since Vercel doesn't have SSH keys configured. Changed to git+https:// and removed the integrity hash (git deps don't have one). Co-authored-by: openhands <openhands@all-hands.dev>
|
QA went well! |
|
Issues:
startup.mov
profile_name_modify.mov
|
VascoSch92
left a comment
There was a problem hiding this comment.
A lot of the points that I mentioned can be copy/paste from this PR: OpenHands/OpenHands#14149
…#417) * fix(profiles): Available Profiles heading translation * fix(profiles): use brand badge for active profile indicator * feat(profiles): replace form heading with "Back to LLM profiles list" * fix(profiles): unify profile-name validation and reject any whitespace * fix(onboarding): persist onboarding LLM choice as an active profile * refactor(profiles): drop redundant trim/wrapper after validator change
all-hands-bot
left a comment
There was a problem hiding this comment.
🟢 Good taste - Clean feature completion with solid testing and documentation.
This PR successfully completes the LLM profiles route integration (final part of the 3-PR series). The implementation is well-structured with comprehensive test coverage, proper error handling, and good inline documentation of design decisions and known limitations.
[RISK ASSESSMENT]
🟢 LOW - Frontend-only UI changes for profile management. No impact on agent behavior, tool execution, or backend evaluation paths. Built on top of existing profile APIs from merged PRs A & B.
VERDICT:
✅ Worth merging - Solid implementation that completes the profiles feature with appropriate testing and documentation.
- translation.json: merge LLM profile keys (branch) with THINKING/MCP/NAV/SKILLS keys (main) - file-service-handlers.ts: take main's Docker-aware mock implementation - mock-file-handlers.test.ts: update expectations to match main's mock data Co-authored-by: openhands <openhands@all-hands.dev>
neubig
left a comment
There was a problem hiding this comment.
This looks good and I tried it out and seems to be working!
Vasco's not here today and asked me to review instead
* feat: integrate LLM profiles into settings route (PR C) - Add LlmSettingsLocalView component for integrated profile management - Extend SdkSectionSaveControl to expose form values for custom save flows - Update LLM settings route to render profile list with create/edit views - Add i18n keys for profile create/edit UI (CREATE_PROFILE, EDIT_PROFILE, PROFILE_CREATED, PROFILE_UPDATED, MODEL_REQUIRED, STATUS, BUTTON) - Add test coverage for LlmSettingsLocalView The integrated view shows: - Profile list with active badge and action menu - Add Profile button that opens create form - Edit button that loads profile config and opens edit form - Back/Cancel buttons to return to list view Co-authored-by: openhands <openhands@all-hands.dev> * chore: address PR review feedback (#393) - Improve mock typing with properly typed helper functions that provide all required React Query fields, eliminating incomplete 'as unknown as' casts - Add integration test that verifies the save flow (fills in profile name, clicks save, verifies UI state transitions) - Add component documentation noting future refactoring opportunity (extract useProfileForm, useProfileSave hooks for better testability) - Document API key preservation behavior: currently preserves existing encrypted key in edit mode with no new key; note about potential 'Clear API Key' UX enhancement for future - Document auto-derive name race condition: client-side uniqueness check uses render-time state, so concurrent profile creation by another client would result in server conflict error (handled gracefully) - Document default export change in route file: LlmSettingsLocalView is now the default export; named export LlmSettingsScreen remains for embedded use Co-authored-by: openhands <openhands@all-hands.dev> * fix: update llm-settings test to use named export The default export of llm-settings.tsx changed to render LlmSettingsLocalView (the profiles manager). The test needs to import the named export LlmSettingsScreen to test the form component directly. Co-authored-by: openhands <openhands@all-hands.dev> * Fix LLM profile button/badge sizing and update typescript-client to v0.6.0 - BrandButton: Change padding from p-2 to px-3 py-2 for better text display - ProfileRow: Increase active badge vertical padding from py-0.5 to py-1 - Update @openhands/typescript-client from commit SHA to v0.6.0 tag Co-authored-by: openhands <openhands@all-hands.dev> * Fix LLM settings to show regular form in cloud mode and empty form in create mode - LlmSettingsRoute: Render LlmSettingsScreen (standard form) for cloud backends and LlmSettingsLocalView (profile manager) for local backends only - LlmSettingsLocalView: Pass empty initial values in create mode to ensure fresh form fields, add key prop to force form remount between profiles - Add unit tests for cloud vs local backend rendering - Add unit tests for create mode empty form initialization Co-authored-by: openhands <openhands@all-hands.dev> * Fix edit mode form initialization to display profile values - Fix initialValueOverrides logic to properly check for edit mode AND existing initialValues before using them - Add prefix to edit mode key for clearer remount semantics - Add unit tests verifying edit mode populates profile name correctly - Add unit tests verifying getProfile is called with encrypted mode Co-authored-by: openhands <openhands@all-hands.dev> * Add debug logging to trace edit profile data flow Co-authored-by: openhands <openhands@all-hands.dev> * Fix edit profile config parsing - read from config directly not config.llm The API returns profile config with llm settings at the top level (config.model, config.api_key, config.base_url), not nested under config.llm. Fixed the parsing to read directly from detail.config. Co-authored-by: openhands <openhands@all-hands.dev> * Handle profile rename during edit and update active profile When editing a profile and changing its name: 1. Rename the profile first using ProfilesService.renameProfile 2. Then save the profile config to the new name 3. If the renamed profile was the active profile, re-activate it after the rename (since rename doesn't update active_profile) This prevents creating duplicate profiles when just changing the name. Co-authored-by: openhands <openhands@all-hands.dev> * Fix package-lock.json to use https protocol for typescript-client The lock file was using git+ssh:// protocol which causes Vercel build failures since Vercel doesn't have SSH keys configured. Changed to git+https:// and removed the integrity hash (git deps don't have one). Co-authored-by: openhands <openhands@all-hands.dev> * fix(profiles): Available Profiles heading translation * fix(profiles): use brand badge for active profile indicator * feat(profiles): replace form heading with "Back to LLM profiles list" * fix(profiles): unify profile-name validation and reject any whitespace * fix(onboarding): persist onboarding LLM choice as an active profile * refactor(profiles): drop redundant trim/wrapper after validator change * feat(chat): add /model slash command for LLM profiles * Add model profile slash completions * chore: address model command review feedback (#418) Co-authored-by: openhands <openhands@all-hands.dev> * chore: address model command follow-up review (#418) Co-authored-by: openhands <openhands@all-hands.dev> --------- Co-authored-by: openhands <openhands@all-hands.dev> Co-authored-by: Graham Neubig <neubig@gmail.com>


Summary
This is Part C of the LLM profiles feature split (from #210).
Depends on:
What's included
Route Integration:
LlmSettingsLocalView- Integrated view that combines profile list with create/edit forms/settingsroute (LLM tab) to render the integrated viewSdkSectionSaveControlto expose form values for custom save flowsView Modes:
User Flow:
i18n keys added:
SETTINGS$CREATE_PROFILESETTINGS$EDIT_PROFILESETTINGS$PROFILE_CREATEDSETTINGS$PROFILE_UPDATEDSETTINGS$MODEL_REQUIREDSTATUS$SAVINGBUTTON$BACKFiles changed
src/components/features/settings/llm-profiles/llm-settings-local-view.tsx(new)src/components/features/settings/llm-profiles/index.tssrc/components/features/settings/sdk-settings/sdk-section-page.tsxsrc/routes/llm-settings.tsxsrc/i18n/translation.json__tests__/components/settings/llm-profiles/llm-settings-local-view.test.tsx(new)Testing
npm run typecheckpassesnpm run buildpassesThis PR was created by an AI agent (OpenHands) as part of splitting #210 into smaller incremental PRs.
@malhotra5 can click here to continue refining the PR