fix(cloud-providers): diff/update model list on re-import (#2346)#2349
Merged
Conversation
Contributor
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes #2346 — re-importing an org-managed cloud LLM provider did not update the workspace
opencode.jsoncmodel list; it kept the first-import snapshot.Closes #2346.
Root cause (what was actually failing)
The JSONC writer was not the bug —
formatConfigWithCloudProviderusesjsonc-parsermodify()which fully replaces thelpr_*provider block. The bug was in the reconcile orchestration / safety guard:assertCloudProviderImportSafeblocked re-import when the import baseline diverged. The out-of-sync / imported state is tracked in a baseline (cloudImports.providers, keyed by cloud id withmodelIds+updatedAt) that lives in a different place than the actuallpr_*block inopencode.jsonc. When that baseline was missing/diverged but thelpr_*block still existed (very reproducible: the desktop persists the baseline via the OpenWork server runtime, not the local.opencode/openwork.json), the provider shows as "available" and any Import/auto-sync attempt threw:performCloudProviderSyncused a fragile remove-then-reconnect dance. For an out-of-sync provider it calledremoveCloudProviderInternal(which removes the block + baseline but does not refreshproviderConnectedIds) and thenconnectCloudProviderInternal, whoseassertCloudProviderImportSafecould then throw against the now-stale in-memory connected list — aborting the rewrite after the block was already removed.Fix
assertCloudProviderImportSafefor cloud-managed keys.lpr_*keys and theopenworkhosted provider are owned by the cloud-import system and are never hand-authored, so re-importing over an existing cloud-managed block is a safe reconcile (recovers a lost/diverged baseline), not a clobber of a user's manual provider. NewisCloudManagedProviderKey()predicate gates the two guards.performCloudProviderSyncwith a single idempotent rewrite (connectCloudProviderInternaldirectly), which fetches the fresh Den model list and fully replaces the block while keeping the baseline — no window where the block is deleted.cloud-provider-config.tsso it is unit-testable (and shrinksstore.ts).Before / after
opencode.jsoncScenario: import provider with model X (
openai/gpt-4o-mini); update Den to add Y (anthropic/claude-3.5-sonnet); re-import.Before (bug): block keeps only X.
After (fixed): block has X and Y.
Removal also works — Den updated to drop X → desktop shows "Out of sync" → Sync → block drops X, keeps only Y.
Tests
New unit suite
apps/app/tests/cloud-provider-reimport.test.tsasserts thelpr_*modelsmap is rewritten on re-import (adds new, drops removed), preserves unrelated provider blocks, the cloud-managed-key predicate, and out-of-sync detection.Commands run (from the worktree root):
Daytona e2e (two-sandbox: Den server + Electron)
openwork-server-20260622-222458; Electron sandboxopenwork-test-20260622-223543(bootstrap confirmed pointing at the Daytona Den URLs, not prod).opencode.jsonckept only X.opencode.jsoncreconciled to X + Y; then Den-removed X → Sync → block drops X; the new model Claude 3.5 Sonnet (OpenRouter, LP/cloud badge) is selectable in the composer picker and shows as the active model.Frame-proof / artifacts (Daytona artifacts volume, port 8090):
opencode-before-fix.jsonc,opencode-after-fix.jsonc,opencode-after-remove.jsoncin the same folder.Files changed
apps/app/src/react-app/domains/connections/provider-auth/cloud-provider-config.ts(new, extracted pure helpers +isCloudManagedProviderKey)apps/app/src/react-app/domains/connections/provider-auth/store.ts(use helpers; relax guard; idempotent sync)apps/app/tests/cloud-provider-reimport.test.ts(new tests)evals/cloud-provider-sync-flows.md(Flow 2 expected outcome + regression coverage note)