settings: expose SDK settings schema to OpenHands#13306
Conversation
Co-authored-by: openhands <openhands@all-hands.dev>
all-hands-bot
left a comment
There was a problem hiding this comment.
🟡 Acceptable - Clean implementation that solves a real problem, but testing needs strengthening.
The core logic is sound: graceful SDK detection with clean try/except, proper type definitions, and backward-compatible API extension. However, the test coverage is too shallow for a feature explicitly designed to handle SDK presence/absence.
Key Issues:
- Only one field (model_name) is verified in the test - schema structure is not validated
- Missing test for the None case when SDK is not installed (contradicts the graceful degradation design)
- Missing docstring on the helper function
Suggested Addition:
Add a test case for when SDK is missing (e.g., mock the import to raise ModuleNotFoundError and verify sdk_settings_schema is None).
Co-authored-by: openhands <openhands@all-hands.dev>
Co-authored-by: openhands <openhands@all-hands.dev>
d87179d to
11a0803
Compare
Co-authored-by: openhands <openhands@all-hands.dev>
11a0803 to
9dab5b1
Compare
Co-authored-by: openhands <openhands@all-hands.dev>
Co-authored-by: openhands <openhands@all-hands.dev>
Co-authored-by: openhands <openhands@all-hands.dev>
Add methods to OpenHandsCloudWorkspace that call the new SaaS API endpoints to retrieve the user's LLM configuration and custom secrets: - get_llm(**llm_kwargs): Fetches LLM settings from the user's SaaS account and returns a configured LLM instance. User kwargs override SaaS defaults. - get_secrets(names=None): Fetches custom secrets and returns a dict[str, str] compatible with conversation.update_secrets(). These methods enable SDK users to inherit their SaaS credentials while retaining full control over agent customization. Depends on OpenHands/OpenHands#13306 for the server-side API endpoints. Related: OpenHands/OpenHands#13268 Co-authored-by: openhands <openhands@all-hands.dev>
|
@OpenHands merge main and fix conflicts then update the code in this PR to reflect the most recent changes here: OpenHands/software-agent-sdk#2361 respond with instructions about how I can test this locally |
|
I'm on it! neubig can track my progress at all-hands.dev |
Co-authored-by: openhands <openhands@all-hands.dev>
|
Merged Local verification steps:
|
|
Final update: Checklist
New/final changes since the last summary
Final resultThe PR branch is now updated, pushed, and includes the requested merge-from-main plus the SDK-settings-schema adaptations, along with local verification instructions for the reviewer. |
|
@OpenHands merge main and fix failing CI |
|
I'm on it! neubig can track my progress at all-hands.dev |
Co-authored-by: openhands <openhands@all-hands.dev>
|
Merged current Local verification completed:
Pushed in |
|
@OpenHands merge main and fix any issues. make sure that this runs appropriately. |
|
I'm on it! neubig can track my progress at all-hands.dev |
Co-authored-by: openhands <openhands@all-hands.dev>
|
Hello @neubig, I encountered a few issues while running the pull request locally in OSS mode. I’ve outlined them below for your reference. Issue 1 (Blocking): The width of the input elements is inconsistent. Please see the image below for further details.
Issue 2 (Blocking): The Basic View of the "Verification" page is currently empty. You can refer to the image below for clarification.
Issue 3 (Blocking): After adding MCP, I’m unable to delete the added data. A video has been included below for additional context. issue3.movIssue 4 (Blocking): The agent dropdown is appearing empty. Kindly refer to the image below for further information.
Issue 5 (Blocking): Is the link supposed to be https://docs.openhands.dev? Please see the image below for further details.
Issue 6 (Blocking): When attempting to set the value "99999" in the Top P field and clicking the Save Settings button, I receive the backend error message 'Something went wrong storing settings.' If users input values across multiple fields, it may lead to confusion, as it will not be clear which fields are invalid. For further details, please refer to the image below.
Issue 7 (Blocking): While most new fields are accompanied by helpful explanatory texts placed below the input elements, some fields are missing these descriptions. A video has been included below for further clarification. issue7.movIssue 8 (Blocking): It seems that multiple languages are not currently supported for the new fields. You can refer to the video below for additional context. issue8.movThank you very much! 🙏 |
| secret_store = secret_store.model_copy( | ||
| update={'custom_secrets': converted_store.custom_secrets} | ||
| ) | ||
| data['secret_store'] = secret_store |
There was a problem hiding this comment.
suggestion (blocking):
data['secret_store'] = secret_store # the field is actually named 'secrets_store' (plural).
It appears that the field in question is secrets_store (as seen on line 106). However, the validator is attempting to write to a key that does not exist.
Thank you! 🙏
… in settings round-trip The SDK's AgentSettings.model_validate automatically transforms 'openhands/X' to 'litellm_proxy/X' and sets the proxy base_url. This caused three issues: 1. is_openhands_model() only recognized 'openhands/' prefix, so _post_merge_llm_fixups and the V1 load_settings base_url clearing logic failed for SDK-transformed model names. 2. get_agent_settings_display() converted the model name back but didn't clear the proxy base_url, so the frontend received the raw proxy URL and could not display 'basic' mode. 3. The V1 load_settings endpoint didn't convert the model name back to 'openhands/' and had a trailing-slash mismatch when comparing base_url to LITE_LLM_API_URL. Fixes: - is_openhands_model() now recognizes both 'openhands/' and 'litellm_proxy/' prefixes - get_agent_settings_display() clears the proxy base_url for managed models - V1 load_settings converts litellm_proxy/ → openhands/ and normalizes trailing slashes in the base_url comparison Co-authored-by: openhands <openhands@all-hands.dev>
|
Pushed 0caab0a to address the valid settings review regressions. Added/expanded regression coverage in:
These tests cover the review issues around schema-driven labels/descriptions/constraints, basic-view LLM + verification behavior, MCP deletion/replacement, and preserving current agent selections. Validation summary:
No SDK-side changes were required for these fixes. This comment was created by an AI assistant (OpenHands) on behalf of the user. |
Implements Rails-style i18n conventions for schema-driven UI fields: - Add toSchemaTranslationKey() to generate conventional keys (e.g., llm.api_key -> SCHEMA$LLM$API_KEY$LABEL) - Add resolver functions with fallback chain: - resolveSchemaFieldLabel() - resolveSchemaFieldDescription() - resolveSchemaFieldSectionLabel() - resolveSchemaChoiceLabel() - Update schema-field.tsx to use new resolver functions - Add ~18 SCHEMA translation keys for common fields with all 15 languages - Add 20 unit tests for resolver functions The fallback chain: 1. Use explicit translation key if schema provides one (contains $) 2. Try conventional key (SCHEMA$<PATH>$<ATTR>) 3. Fall back to schema-provided value (untranslated) Co-authored-by: openhands <openhands@all-hands.dev>
…a fields Add 154 SCHEMA translation keys covering: - All fields from /agent-schema endpoint (general, llm, condenser, verification) - All fields from /conversation-schema endpoint - Section labels (General, LLM, Condenser, Verification) - Choice labels for select fields (reasoning_effort, reasoning_summary, critic_mode, security_analyzer) Keys follow the convention: SCHEMA$<PATH>$<ATTR> Examples: - SCHEMA$LLM$REASONING_EFFORT$LABEL - SCHEMA$VERIFICATION$CRITIC_MODE$DESCRIPTION - SCHEMA$LLM$REASONING_EFFORT$CHOICE$HIGH English values are populated; other languages have empty strings for future translation contributions. Co-authored-by: openhands <openhands@all-hands.dev>
Add translations for the most commonly used schema fields including: - Core LLM fields (model, API key, base URL, temperature, etc.) - AWS credential fields - OpenRouter fields - Retry/timeout fields - Condenser fields - Verification fields - Section labels - Choice labels Languages: English, Japanese, Chinese (Simplified/Traditional), Korean, Norwegian, Italian, Portuguese, Spanish, Arabic, French, Turkish, German, Ukrainian, Catalan Some lesser-used fields retain English-only text for future translation contributions. Co-authored-by: openhands <openhands@all-hands.dev>
- Create common resolveSchemaFieldText() function used by: - resolveSchemaFieldLabel() - resolveSchemaFieldDescription() - resolveSchemaFieldSectionLabel() - Add warning logging when falling back to untranslated schema values (logs to console.warn with key and fallback value) - Update resolveSchemaChoiceLabel to also log warnings on fallback - Add tests for warning logging behavior (5 new tests) Note: i18next already logs missing keys in debug mode (development), but this explicit warning helps identify untranslated schema fields in production environments as well. Co-authored-by: openhands <openhands@all-hands.dev>
Fill in translations for all 64 SCHEMA keys across all 15 supported languages (ja, zh-CN, zh-TW, ko-KR, no, it, pt, es, ar, fr, tr, de, uk, ca). This includes: - LLM configuration labels/descriptions (extra headers, force string serializer, input/output costs, token limits, temperature, top_k, top_p, streaming, seed, reasoning effort/summary, etc.) - Verification/Critic settings (confirmation mode, critic enable, critic mode choices, thresholds, iterative refinement, security analyzer, etc.) Co-authored-by: openhands <openhands@all-hands.dev>
Restore _create_condenser, _create_security_analyzer_from_string, _select_confirmation_policy, and _set_security_analyzer_from_settings methods that were accidentally removed during merge conflict resolution. Also restore necessary imports: AgentType, LLMSummarizingCondenser, LLM, and security-related classes. Co-authored-by: openhands <openhands@all-hands.dev>
Co-authored-by: openhands <openhands@all-hands.dev> Co-authored-by: hieptl <hieptl.developer@gmail.com> Co-authored-by: tofarr <tofarr@gmail.com>






What
Integrates the SDK-owned
AgentSettingsschema into the OpenHands GUI and backend. The frontend now fetches the schema from/api/settings/schema(served by the SDK) and dynamically renders settings pages from it, instead of hard-coding field definitions.The most important points are:
Fixes #13788 · Upstream: software-agent-sdk#2228
NOTE: This PR also modifies v0 code, as this was the easiest way to ensure that the entire codebase was consistent. Feel free to skip review of the v0 code, as it will be removed soon anyway.
Why
The SDK defines the
AgentSettingsmodel, so it should own the schema contract. This eliminates manual duplication of settings fields in the frontend and ensures new SDK settings appear in the GUI automatically.Key changes
Backend — Settings model (
openhands/storage/data_models/settings.py)Settingsnow embedsAgentSettings(from SDK) andConversationSettingsas nested objectsllm_model,llm_api_key,llm_base_url,agent, etc.) are migrated intoagent_settings/conversation_settingson loadagent_settingscolumn (migration 107)Backend — MCP config (
openhands/core/config/mcp_config.py,openhands/mcp/)MCPConfigandMCPStdioServerConfignow come from the SDKinclude_stdio/use_stdioparameters fromcreate_mcp_clientsandfetch_mcp_tools_from_config— all configured servers are always connectedBackend — Conversation startup
live_status_app_conversation_service.py: Reads agent/conversation settings fromAgentSettings; renamed_create_condenser→_create_llm_summarizing_condensersession.py,conversation_service.py: Adapted to passAgentSettingsthrough startup flowFrontend — Schema-driven settings UI
sdk-section-page.tsx,schema-field.tsx— generic components that render any SDK settings section from schema JSONuse-agent-settings-schema.tshook fetches/api/settings/schemasdk-settings-schema.ts— utilities to parse schema sections, extract field metadata, build value pickers/settings/condenser,/settings/verification, plus org-default variantsllm-settings.tsx: Rewritten to render from schema with custom overrides for model selectormcp-settings.tsx: Adapted to useMCPConfigfrom SDK typesuse-settings.ts: Now loads/savesagent_settingsandconversation_settingsas nested objectsuse-save-settings.ts: Handles JSON-patch merging of nested settingsEnterprise
saas_settings_store.py,org_store.py,org_member_store.py,user_store.py: Adapted toAgentSettings-based modelorg_models.py: Simplified — org defaults useAgentSettingsdirectlyagent_settingsJSON column to enterprise settings tableSDK dependency
software-agent-sdk@5aef1b2(includes schema route +AgentSettings/ConversationSettingsmodels)AGENT_SETTINGS_SCHEMA_VERSIONconstant from SDK instead of hardcoded valuesHow to review
This is a large PR (~20k lines across 137 files). Suggested review order:
openhands/storage/data_models/settings.py(the core change)openhands/server/routes/settings.pyandopenhands/app_server/settings/settings_router.pyfrontend/src/utils/sdk-settings-schema.tsfrontend/src/routes/llm-settings.tsx,sdk-section-page.tsxopenhands/core/config/mcp_config.py,openhands/mcp/utils.pyenterprise/storage/saas_settings_store.py,enterprise/storage/org_store.pyThis PR description was written by an AI assistant (OpenHands) on behalf of the user.
To run this PR locally, use the following command:
GUI with Docker: