Skip to content

Enable provider onboarding and model selection through OpenCode provider APIs #78

Description

@khodam666

Context

OpenKhodam currently consumes OpenCode models only after a provider is already connected. The current flow is:

Chat UI -> useOpenCodeModels -> client.provider.list({ directory }) -> connected providers only -> model picker -> session.promptAsync/create

This means users have no OpenKhodam-native path to connect a provider, understand disconnected providers, or recover when no connected model exists.

OpenCode already has a generic provider/auth system that tells the app which providers exist and how each provider authenticates. We should build OpenKhodam's provider UX on top of that instead of implementing provider-specific auth ourselves.

Important OpenCode reference behavior

OpenCode desktop uses:

  • client.provider.list({ directory })
    • returns all available providers
    • returns connected provider IDs
    • returns default model IDs
  • client.provider.auth()
    • returns auth methods per provider
    • methods can be api or oauth
    • methods can include extra prompts
  • client.auth.set({ providerID, auth })
    • stores API-key auth in OpenCode
  • client.provider.oauth.authorize(...)
    • starts OAuth flow
  • client.provider.oauth.callback(...)
    • completes OAuth flow
  • client.auth.remove({ providerID })
    • disconnects provider auth
  • client.global.dispose()
    • refreshes runtime/provider state after auth changes

Relevant OpenCode files:

  • packages/app/src/components/settings-providers.tsx
  • packages/app/src/components/dialog-connect-provider.tsx
  • packages/app/src/components/dialog-select-provider.tsx
  • packages/app/src/components/dialog-select-model.tsx
  • packages/app/src/hooks/use-providers.ts
  • packages/opencode/src/server/routes/instance/httpapi/handlers/provider.ts
  • packages/opencode/src/provider/auth.ts

Local OpenKhodam files to inspect

  • packages/desktop/src/renderer/src/hooks/useOpenCodeModels.ts
  • packages/desktop/src/renderer/src/hooks/opencode/client.tsx
  • packages/desktop/src/renderer/src/pages/SettingsPage.tsx
  • packages/desktop/src/renderer/src/components/chat/ChatHomePage.tsx
  • packages/desktop/src/renderer/src/hooks/useOpenCodeChatInterface.ts
  • packages/desktop/src/renderer/src/hooks/useOpenCodeChat.ts

Direction

OpenKhodam should own the desktop UX around providers.

OpenCode should remain the source of truth for:

  • provider catalog
  • auth method schema
  • OAuth/API-key storage
  • connected state
  • available models

OpenKhodam should not build a parallel credential store.

MVP 1: Provider visibility and connection entry points

Goal

Users can see provider status and have an obvious path to connect a provider.

Build

  • Add a Providers section to Settings.
  • Show connected providers.
  • Show popular disconnected providers.
  • Add "View all providers" / searchable provider list.
  • Use OpenCode provider catalog, not hardcoded provider details.

Suggested popular providers:

  • OpenCode
  • Anthropic
  • OpenAI
  • Google
  • OpenRouter
  • GitHub Copilot
  • Vercel

Calls

client.provider.list({ directory })
client.provider.auth()

Acceptance criteria

  • Settings shows connected providers.
  • Settings shows popular disconnected providers.
  • User can open a provider connect flow.
  • If no models are connected, chat/model picker points user toward connecting a provider.

MVP 2: Generic connect/disconnect flow

Goal

Users can connect providers without OpenKhodam implementing provider-specific logic.

Build

Create a generic provider connect dialog driven by OpenCode auth methods.

Auth method shape:

type ProviderAuthMethod = {
  type: 'api' | 'oauth'
  label: string
  prompts?: Array<
    | { type: 'text'; key: string; message: string; placeholder?: string }
    | { type: 'select'; key: string; message: string; options: Array<{ label: string; value: string }> }
  >
}

Flow:

  1. Load auth methods with client.provider.auth().
  2. If one method exists, auto-select it.
  3. If multiple methods exist, show method picker.
  4. If method is api, show API key input.
  5. If method has prompts, render prompts generically.
  6. If method is oauth, call authorize, open returned URL, then call callback.
  7. After success, call client.global.dispose() and invalidate provider/model queries.

Calls

API key:

client.auth.set({
  providerID,
  auth: {
    type: 'api',
    key,
    metadata: promptInputs
  }
})

OAuth:

client.provider.oauth.authorize({
  providerID,
  method,
  inputs
})

client.provider.oauth.callback({
  providerID,
  method,
  code
})

Disconnect:

client.auth.remove({ providerID })
client.global.dispose()

Acceptance criteria

  • API-key providers can be connected.
  • OAuth providers can be connected if OpenCode exposes OAuth methods.
  • Providers with extra prompt fields can be handled generically.
  • Connected provider models appear after refresh.
  • Disconnect removes the provider from connected state.
  • No provider secret is stored in OpenKhodam project/session artifacts.

MVP 3: Model picker integration

Goal

The chat model picker should guide users through provider setup instead of only showing connected models.

Build

  • Keep showing connected models as selectable.
  • Add "Connect provider" action in the model picker.
  • If no connected models exist, show an empty state with connect CTA.
  • After connecting, refresh model list and allow selection.

Current path:

ChatPromptComposer -> ModelPickerCombobox -> useOpenCodeModels -> prompt model

Desired path:

ChatPromptComposer -> ModelPickerCombobox -> ConnectProviderDialog -> OpenCode auth -> refresh models -> select model -> prompt

Acceptance criteria

  • User can connect a provider from the chat/model picker path.
  • Chat send remains blocked until a connected model is selected.
  • Helper text explains missing provider/model state.
  • Prompt submission still sends:
model: {
  providerID,
  modelID
}

MVP 4: Local default provider/model selection

Goal

OpenKhodam remembers the user's last selected model.

Build

  • Persist last selected provider/model locally.
  • Resolve selection in this order:
    1. current explicit selection
    2. saved local selection if still connected
    3. OpenCode default model
    4. first connected model

Acceptance criteria

  • User does not need to reselect model every time.
  • If saved provider disconnects, UI falls back safely.
  • No secret material is persisted.

Maturity 1: Project/session-level defaults

Goal

Users can have provider/model defaults per project or session.

Build

  • Add project-level default provider/model.
  • Optionally snapshot selected provider/model when creating a session.
  • Selection resolution becomes:
    1. session selected/snapshotted model
    2. project default
    3. app default
    4. OpenCode default
    5. first connected model

Acceptance criteria

  • Project default affects new sessions in that project.
  • Existing sessions do not unexpectedly change unless explicitly selected.
  • Disconnected project default shows a recoverable warning.

Maturity 2: Provider management polish

Goal

Provider setup feels like a first-class part of OpenKhodam.

Build

  • Better provider cards:
    • connected source: api/oauth/env/config/custom if available
    • provider notes
    • recommended badges
    • environment-managed providers cannot be disconnected from UI
  • Search all OpenCode providers.
  • Support custom provider only if we intentionally decide to expose OpenCode's custom provider flow.

Acceptance criteria

  • Users can understand why a provider is connected.
  • Users can distinguish app-managed vs environment/config-managed providers.
  • Provider list scales beyond popular providers.

Maturity 3: Robust auth/callback handling

Goal

OAuth/API-key flows are reliable in desktop contexts.

Build

  • Handle OAuth code vs auto callback methods.
  • Open auth URLs through Electron shell.
  • Surface provider auth errors clearly.
  • Ensure query invalidation and sidecar refresh happen after auth changes.
  • Consider deep-link callback support only if OpenCode/provider flow requires it.

Acceptance criteria

  • OAuth failure shows actionable error.
  • Auth cancellation does not leave stale pending UI.
  • Successful auth refreshes connected provider/model state.

Explicit non-goals

  • Do not build OpenKhodam's own provider credential store.
  • Do not hardcode Anthropic/OpenAI/Google-specific auth behavior.
  • Do not store provider secrets in project artifacts, session memory, or renderer durable state.
  • Do not implement custom providers in MVP unless required by product scope.

Testing

Use repo commands through Nix:

nix develop -c pnpm lint
nix develop -c pnpm typecheck

Add focused tests where feasible:

  • provider list normalization
  • connected vs disconnected provider display
  • auth method rendering:
    • API key
    • OAuth
    • prompts
  • model picker empty state
  • model picker connect CTA
  • selected model fallback when provider disconnects

If e2e provider auth is difficult, use fixture-backed provider API responses for e2e and cover actual auth method handling with lower-level tests.

Review focus

  • Reuse OpenCode provider/auth APIs instead of duplicating provider logic.
  • Keep provider secrets out of OpenKhodam-owned project/session storage.
  • Keep code footprint small in MVP: hooks + settings section + generic dialog.
  • Make model picker recovery path obvious when no connected provider exists.
  • Preserve existing prompt send flow through providerID/modelID.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions