🤖 fix: load app and providers config into the VS Code webview with host-side redaction - #4813
Conversation
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
f7d0c86 to
20e79b8
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 20e79b8966
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…fore a policy fallback
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 66ae26908c
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Summary
The VS Code webview now loads the user's app config (model routing and per-model minimum thinking levels) and the providers config, so the thinking selector shows the level the turn actually uses and the model list reflects the configured providers. It connects the shared
ProvidersConfigStoreandAppConfigStoreto its bridge client, as the desktopAppLoaderdoes. The extension host narrows both results before they reach the webview.Background
The webview never connected these stores (#4766, split out of #4755). The thinking selector raised the level to the model's built-in minimum (MED) instead of the user's configured one, and the model list ignored which providers are configured. #4765 stopped clamping sends in the webview for this reason; the send path is unchanged here.
Webview allowlist and data exposure
oRPC paths added:
config.getConfigandconfig.onConfigChanged. Every otherconfig.*procedure (saveConfig,update*, …) stays blocked.providers.getConfig/providers.onConfigChangedwere already allowed; this PR adds redaction toproviders.getConfig.What reaches the webview (all narrowing happens in the extension host, in
redactWebviewOrpcResult, a pure function with unit tests, applied inhandleOrpcCalllike the #4807forcedBaseUrlredaction):config.getConfigroutePriority(route names),routeOverrides(model → route name) andminThinkingLevelByModel(model → thinking level): the three fieldsAppConfigStorereadsheartbeatDefaultPrompt),muxGovernorUrl, user preferences, task and runtime settings, advisor/agent defaults. Fields added to the config later stay in the host because the projection is an allow-list.config.onConfigChangedeventIterator(z.void()))providers.getConfigapiKeySet/codexOauthSet/couponCodeSet-style booleans, model lists, gateway/discovered model IDs, provider type and display namebaseUrl,baseUrlResolved,deploymentUrl(URLs that can embed credentials or tokens) andapiKeyFile(a local path). No webview code reads them.No secrets: the providers config schema never carries API keys or OAuth tokens, only booleans saying whether they are set; the fields that could still embed a credential are removed.
Why this is safe for a less-trusted webview: both new paths are read-only and have no input. The data is model routing preferences, thinking floors and model availability, which the webview needs to render the same model list and thinking level the backend uses; the backend still enforces routing, policy and floors on every send.
Implementation
vscode/src/orpcAllowlist.ts:config: getConfig, onConfigChanged;redactWebviewOrpcResultdispatches to an allow-list projection forconfig.getConfigand a field denylist for eachproviders.getConfigentry. Inputs are not mutated.vscode/src/webview/App.tsx: connects both stores while the connection is in API mode, keyed by the server URL, and disconnects them otherwise, so a recovery from file mode (where the host rejects calls) or a switch to another server fetches again (review round 1).vscode/src/webview/ChatComposer.tsx: the 🤖 fix: fall back to an allowed model when admin policy excludes the VS Code webview's selection #4811 policy fallback now waits for the providers config, because before it arrives the model list is not filtered by provider availability (review round 1).Validation
orpcAllowlist.test.ts: the two paths are allowed andconfig.saveConfig/config.updateRoutePreferencesare not;config.getConfigis projected to the three fields (governor URL, prompt, preferences, task settings dropped);providers.getConfigloses the URL and key-file fields and keeps everything else; the input is not mutated. All three fail onmain.App.test.tsx(TestBridge): with the stored thinking levellowandminThinkingLevelByModelfor Opus 5.5 set tohigh, the selector shows HIGH, not MED (fails onmain: noconfig.getConfigcall). A file-mode start posts neither config call; recovery posts both (fails onmain).apimode, new URL) refetches both configs while a same-server refresh does not; withproviders.getConfigstill pending, a policy-excluded model is not substituted. Both fail on the round-0 head.anthropic:claude-fable-5-1).config.getConfiganswered with the Opus floorhigh,providers.getConfigwith only Anthropic configured, stored thinkinglow):providers.getConfig,providers.onConfigChanged,config.getConfigandconfig.onConfigChanged.Thinking floor loaded, 800px:
Model list limited to the configured provider, 800px:
Thinking floor loaded, 390px:
Risks
Low to medium, webview only. With the providers config loaded, the model list now hides models of unconfigured providers, matching the desktop. The stores are app-wide singletons; the webview has one
App, and the effect disconnects them on unmount and in file mode. The host-side redaction is the security boundary: a new URL-like provider field would pass through until added to the denylist, while the app config uses an allow-list.Fixes #4766
Generated with
xum• Model:anthropic:claude-opus-5-5• Thinking:high• Cost:$4.48