Purpose: document the actual settings used by the OpenHands-Tab VS Code extension today. This is grounded in the TypeScript agent SDK (@openhands/agent-sdk-ts) and the extension implementation as the source of truth.
openhands.serverUrl(string, default: empty)- Empty → local mode (SDK runs in-process).
- Non-empty → remote mode (agent-server over HTTP/WebSocket).
- Normalization: if the user omits a scheme, the extension coerces it to
http://…and canonicalizes the URL.
openhands.servers(array of{ url, label? })- Stored globally.
- Deduplicated by canonical URL; invalid entries are dropped.
- If
serverUrlis set, it is always injected into the saved server list.
openhands.cloudApiKey.server.<hash>(VS Code SecretStorage; per-server)- Used only for OpenHands Cloud/SaaS servers (e.g.
https://app.all-hands.dev). - HTTP header:
Authorization: Bearer <cloudApiKey>
- Used only for OpenHands Cloud/SaaS servers (e.g.
openhands.runtimeSessionApiKey.server.<hash>(VS Code SecretStorage; per-server)- Used for direct/non-cloud agent-server endpoints (e.g. a local python agent-server or self-hosted agent-server).
- HTTP header:
X-Session-API-Key: <runtimeSessionApiKey> - WebSocket: prefer handshake header auth (no URL secrets):
X-Session-API-Key: <runtimeSessionApiKey>(orAuthorization: Bearer ...).- Legacy (browser-only):
?session_api_key=<runtimeSessionApiKey>query param.- This query-param path is deprecated for non-browser clients and is being removed from the extension’s WS URL construction (see
oh-tab-h3g/ PR #873).
- This query-param path is deprecated for non-browser clients and is being removed from the extension’s WS URL construction (see
- Downstream change (draft): enyst#873 removes
session_api_keyfrom WS URLs; merge is blocked until upstream OpenHands/software-agent-sdk#1786 is merged/deployed.
- Legacy (browser-only):
- Note (OpenHands Cloud): the nested runtime
session_api_keyis obtained via SaaS V1 bootstrap (/api/v1/app-conversations*) and is not persisted; it is injected into in-memorysettings.secrets.runtimeSessionApiKeyonly for the lifetime of the running conversation.
Cloud/SaaS servers (e.g. app.all-hands.dev):
- Use OpenHands: Login to Remote Server (Device Flow) to obtain and store a cloud API key.
- Storage:
openhands.cloudApiKey.server.<hash>in VS Code SecretStorage. - The runtime session API key is fetched per-conversation from SaaS
/api/v1/app-conversations*and kept in-memory only (not persisted). - Auth headers:
- SaaS/app-server:
Authorization: Bearer <cloudApiKey> - Nested runtime:
X-Session-API-Key: <runtimeSessionApiKey>(orAuthorization: Bearer ...when supported)
- SaaS/app-server:
Direct/self-hosted agent-servers (non-cloud):
- Use OpenHands: Set Runtime Session API Key to store a per-server runtime key.
- Storage:
openhands.runtimeSessionApiKey.server.<hash>in VS Code SecretStorage. - Auth header:
X-Session-API-Key: <runtimeSessionApiKey>
Troubleshooting quick checks:
- 401/403 on cloud: re-run device flow login, confirm
serverUrlis a cloud host, and ensure you are not using a runtime session key as a cloud key. - 401/403 on non-cloud: set the runtime session API key (must match the server’s
SESSION_API_KEY), and verify the selected server URL. - Keys are per-server: switching servers requires separate login/key entry.
- To clear cloud auth, use OpenHands: Logout of Remote Server; to clear runtime auth, run OpenHands: Set Runtime Session API Key and choose “Clear”.
- Stored in workspace state:
openhands.conversationId.localopenhands.conversationId.remote
openhands.conversation.storeRoot(string, optional)- When set, treated as a path relative to the user’s home directory unless absolute.
- If empty, the extension falls back to
~/.openhands/conversations-vscode/. - If that fails (e.g., permission), it tries VS Code global storage, then OS temp.
openhands.conversation.maxIterations(number, default: 50)- Applied to new conversations via the SDK.
openhands.llm.profileId(string, machine scope)- A local alias that points to
~/.openhands/llm-profiles/<profileId>.json. - If unset/invalid, the extension auto-selects a default profile ID and persists it globally. The selection order is:
- A profile that already has a per-profile API key stored in SecretStorage.
- A profile suggested by provider-specific API keys (
OPENAI_API_KEY,ANTHROPIC_API_KEY,GEMINI_API_KEY). - The fallback profile ID
sonnet-45.
- A local alias that points to
openhands.oracle.profileId(string, machine scope)- Optional. Selects the LLM profile used by the local-only
ask_oracletool. - If unset,
ask_oraclereturns an instructive error prompting you to configure it.
- Optional. Selects the LLM profile used by the local-only
- The agent-server schema is strict; it does not accept
profile_idfields. - The extension loads the profile locally and expands it into
agent.llmfields before sending remote requests.
The extension reads these fields from the profile and passes them to the SDK:
provider,model,openaiApiMode,baseUrl,apiVersiontimeoutSeconds,temperature,topP,topKmaxInputTokens,maxOutputTokensreasoningEffort,reasoningSummaryinputCostPerToken,outputCostPerToken
- Stored in SecretStorage as
openhands.llmProfileApiKey.<profileId>.
openhands.agent.enableSecurityAnalyzer(bool, default: true)openhands.agent.debug(bool, default: false)- Enables local-mode debug events (e.g.,
llm_request/tool_call_raw).
- Enables local-mode debug events (e.g.,
openhands.agent.summarizeToolCalls(bool, default: false)- Local-only. Generates Gemini summaries for tool calls.
- Auto-disabled if no Gemini API key is available.
openhands.devBridge.enabled(bool, default: false)- Enables the webview → extension debug logging bridge.
openhands.confirmation.policy=never | always | riskyopenhands.confirmation.risky.threshold=LOW | MEDIUM | HIGHopenhands.confirmation.risky.confirmUnknown= boolean
These values map directly to the SDK confirmation policy and drive the confirmation UI.
openhands.hal.enabled(bool, default: false)openhands.hal.mode=bundled | tts_only | voice_confirmopenhands.hal.userName(string, default:Engel)openhands.hal.llmProfileId(string, default:gemini-flash-hal)openhands.hal.voiceAId,openhands.hal.voiceUserId,openhands.hal.modelIdopenhands.hal.volume(0.0–1.0)openhands.hal.cache(bool)
Secrets are stored in VS Code SecretStorage and never in settings.json:
Extension-scoped secrets (SecretStorage keys)
openhands.cloudApiKey.server.<hash>openhands.runtimeSessionApiKey.server.<hash>openhands.llmApiKey(global fallback LLM API key)openhands.awsAccessKeyId,openhands.awsSecretAccessKey(plumbed but no dedicated UI)openhands.githubTokenopenhands.hal.ttsApiKeyopenhands.customSecret1,openhands.customSecret2,openhands.customSecret3openhands.llmProfileApiKey.<profileId>
Provider keys stored in SecretStorage
OPENAI_API_KEY,ANTHROPIC_API_KEY,OPENROUTER_API_KEY,LITELLM_API_KEY,GEMINI_API_KEY
Important: “secrets” settings are status indicators only The following VS Code settings exist only to display ✓/blank status in the Settings UI:
openhands.secrets.*(cloudApiKey,runtimeSessionApiKey,githubToken, provider keys, custom secrets)
These do not store secrets; they are updated automatically when SecretStorage changes.
- OpenHands: Configure → opens the extension Settings page.
- Secret commands prompt for values and store them securely:
OpenHands: Set API Key(global fallback key:openhands.llmApiKey)- Provider-specific keys: OpenAI, Anthropic, OpenRouter, LiteLLM, Gemini
- Cloud API key, Runtime Session API key, GitHub token, HAL TTS key, Custom secrets 1–3
- LLM Profiles view (webview slide-over) for profile CRUD and per-profile keys.
- Local mode (no
serverUrl):- SDK runs in-process with local tools +
AgentContext(skills enabled).
- SDK runs in-process with local tools +
- Remote mode (with
serverUrl):- SDK connects to agent-server;
agent.llmis populated from the selected profile andllmApiKeyfallback.
- SDK connects to agent-server;
- WebSocket URL:
ws(s)://{serverUrl}/sockets/events/{conversation_id}with optionalsession_api_key.
Server deployment settings such as CORS, server-side persistence paths, session key lists, and VNC/port management are server concerns and not exposed in the extension UI.