Skip to content

fix(cloud-providers): diff/update model list on re-import (#2346)#2349

Merged
benjaminshafii merged 2 commits into
devfrom
fix/2346-cloud-provider-reimport-diff
Jun 23, 2026
Merged

fix(cloud-providers): diff/update model list on re-import (#2346)#2349
benjaminshafii merged 2 commits into
devfrom
fix/2346-cloud-provider-reimport-diff

Conversation

@benjaminshafii

@benjaminshafii benjaminshafii commented Jun 23, 2026

Copy link
Copy Markdown
Member

Summary

Fixes #2346 — re-importing an org-managed cloud LLM provider did not update the workspace opencode.jsonc model list; it kept the first-import snapshot.

Closes #2346.

Root cause (what was actually failing)

The JSONC writer was not the bug — formatConfigWithCloudProvider uses jsonc-parser modify() which fully replaces the lpr_* provider block. The bug was in the reconcile orchestration / safety guard:

  1. assertCloudProviderImportSafe blocked re-import when the import baseline diverged. The out-of-sync / imported state is tracked in a baseline (cloudImports.providers, keyed by cloud id with modelIds + updatedAt) that lives in a different place than the actual lpr_* block in opencode.jsonc. When that baseline was missing/diverged but the lpr_* 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:

    lpr_… is already connected in this workspace. Disconnect it before importing the cloud-managed version.
    …or …already has a provider block in opencode.jsonc. The error was swallowed during auto-sync, so the block was never updated and the app silently kept model X forever.

  2. performCloudProviderSync used a fragile remove-then-reconnect dance. For an out-of-sync provider it called removeCloudProviderInternal (which removes the block + baseline but does not refresh providerConnectedIds) and then connectCloudProviderInternal, whose assertCloudProviderImportSafe could then throw against the now-stale in-memory connected list — aborting the rewrite after the block was already removed.

Fix

  • Relax assertCloudProviderImportSafe for cloud-managed keys. lpr_* keys and the openwork hosted 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. New isCloudManagedProviderKey() predicate gates the two guards.
  • Replace remove-then-reconnect in performCloudProviderSync with a single idempotent rewrite (connectCloudProviderInternal directly), which fetches the fresh Den model list and fully replaces the block while keeping the baseline — no window where the block is deleted.
  • Extracted the pure config/diff logic into cloud-provider-config.ts so it is unit-testable (and shrinks store.ts).

Before / after opencode.jsonc

Scenario: 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.

"lpr_01kvsfe0h3feyt2cbx50rgfzcr": {
  "models": { "openai/gpt-4o-mini": { "id": "openai/gpt-4o-mini", "name": "GPT-4o mini" } }
}

After (fixed): block has X and Y.

"lpr_01kvsfe0h3feyt2cbx50rgfzcr": {
  "models": {
    "anthropic/claude-3.5-sonnet": { "id": "anthropic/claude-3.5-sonnet", "name": "Claude 3.5 Sonnet" },
    "openai/gpt-4o-mini": { "id": "openai/gpt-4o-mini", "name": "GPT-4o mini" }
  }
}

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.ts asserts the lpr_* models map 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):

pnpm --filter @openwork/app typecheck        # EXIT 0
pnpm --filter @openwork/app exec bun test tests/   # 77 pass / 0 fail
pnpm --filter @openwork/app exec bun test tests/cloud-provider-reimport.test.ts  # 6 pass / 0 fail

Daytona e2e (two-sandbox: Den server + Electron)

  • Den server sandbox openwork-server-20260622-222458; Electron sandbox openwork-test-20260622-223543 (bootstrap confirmed pointing at the Daytona Den URLs, not prod).
  • Seeded demo org (Acme Robotics), created an OpenRouter org provider with model X, signed the desktop in via desktop-handoff.
  • Reproduced the bug on this branch's pre-fix code: clicking Import errored "lpr_… is already connected…", opencode.jsonc kept only X.
  • Applied fix (HMR), re-ran: opencode.jsonc reconciled 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):

Note: Daytona preview URLs are not permanent; sandboxes will be torn down after review. Reproduce with .devcontainer/test-server-on-daytona.sh + .devcontainer/test-on-daytona.sh --den-base-url … --den-api-base-url … per the steps above.

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)

Review in cubic

@vercel

vercel Bot commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
openwork-app Ready Ready Preview, Comment Jun 23, 2026 5:59am
openwork-den Ready Ready Preview, Comment Jun 23, 2026 5:59am
openwork-den-worker-proxy Ready Ready Preview, Comment Jun 23, 2026 5:59am
openwork-landing Ready Ready Preview, Comment, Open in v0 Jun 23, 2026 5:59am

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 4 files

Re-trigger cubic

@benjaminshafii benjaminshafii merged commit 81361ff into dev Jun 23, 2026
11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Cloud provider re-import doesn't update model list (keeps first-import snapshot)

1 participant