Skip to content

dsh-multiprovider

Verified

dsh-multiprovider ยท v0.1.1 ยท MIT ยท Web UI

Provider-neutral multi-account scheduling, affinity, health, and Settings UI for DeepSeek Harness

Install

dsh plugin add dsh-multiprovider

Confirm the layer applied with dsh --profile default --dump-config โ€” see the install guide.

Source

Tags

Readme

๐Ÿ”€ dsh-multiprovider

Provider-neutral multi-account scheduling for DeepSeek Harness

One provider identity, many credentials, explicit leases, and operator-visible health.

checks npm DeepSeek Harness license


dsh-multiprovider lets concrete provider plugins expose several OAuth, API-key, service-account, or custom credentials behind one stable provider/model identity. It owns account selection, affinity, health, cooldowns, and operator preferences. Provider plugins continue to own authentication, credential storage, transport, and provider-specific error interpretation.

The package is a native Cordis service and DSH bundle, not a second model router. Callers lease one account for a complete operation, settle the outcome exactly once, and explicitly reacquire when provider semantics make failover safe.

Why multiprovider?

Capability What it unlocks
๐Ÿ” Deterministic selection Round-robin, weighted, least-in-flight, and priority policies behind one provider route.
๐Ÿ“Œ Session affinity Stable account reuse for related requests while the selected account remains eligible.
๐Ÿฉบ Visible health Cooldowns, failure classes, and in-flight counts without exposing credential material.
๐Ÿ” Provider-owned secrets Opaque credential references stay on the host and never enter browser snapshots.
๐ŸŽ›๏ธ Live preferences Operators enable, weight, prioritize, and reset accounts from DSH Settings.
๐Ÿงฉ Native composition Cordis lifecycle, DSH settings, and the Web host remain the only runtime authorities.

How it fits

flowchart LR
  Request[Provider operation] --> Pool[ctx.multiprovider]
  Pool --> Policy[Selection + affinity]
  Policy --> Lease[Account lease]
  Lease --> Provider[Concrete provider plugin]
  Provider --> Outcome[Success / failure / cancel]
  Outcome --> Health[Health + cooldown]
  Health --> Pool
  Pool --> Settings[Accounts settings]

The logical provider identity stays unchanged. Internal account IDs and credential references are not model routes and must never be persisted as session provider IDs.

What it provides

  • Dynamic provider and account registration through ctx.multiprovider
  • Opaque, provider-owned credential references that never enter browser snapshots
  • Idempotent account leases with in-flight accounting
  • Round-robin, smooth weighted round-robin, least-in-flight, and priority policies
  • Optional session/workload affinity
  • Per-attempt account exclusions for explicit failover loops
  • Normalized rate-limit, quota, authentication, transient, and fatal failure health
  • Configurable cooldowns with transient exponential backoff
  • Live, durable enable/weight/priority/policy preferences through DSH settings
  • A dedicated Accounts section in DSH's Settings modal
  • Same-origin, loopback-only, secret-free Settings endpoints

The logical provider identity stays unchanged. Internal account IDs and credential references are not model routes and should never be persisted as session provider IDs.

Install

Requirements: Node.js ^22.19.0 || >=24, pnpm 11 for this checkout, and DeepSeek Harness ^0.1.1.

The package is included in the tested DSH distribution. To add it to another profile explicitly:

pnpm dlx @monotykamary/dsh@latest plugin --profile web add dsh-multiprovider

For local development, build this checkout and add its absolute path:

pnpm install --frozen-lockfile
pnpm run check
pnpm dsh plugin --profile web add link:/absolute/path/to/dsh-multiprovider

The bundle patch installs the multiprovider service. Concrete provider integrations inject that service and retain ownership of enrollment, refresh, storage, and transport.

Provider integration

1. Register a provider inventory

Credential references are opaque to this package. They can be DSH CredentialRef values, credential record keys, provider-owned file handles, or another non-secret locator.

import type { Context } from '@monotykamary/cordis'
import type {} from 'dsh-multiprovider'

export function installAccounts(ctx: Context) {
  ctx.inject(['multiprovider'], (mctx) => {
    mctx.effect(() => mctx.multiprovider.registerProvider({
      id: 'anthropic',
      label: 'Anthropic',
      managementHint: 'Add and remove keys in the Anthropic provider settings.',
      accounts: async () => [
        {
          id: 'work',
          label: 'Work key',
          authKind: 'api-key',
          credentialRef: { kind: 'record', key: 'anthropic/work' },
          weight: 3,
          metadata: { organization: 'Work' },
        },
        {
          id: 'personal',
          label: 'Personal key',
          authKind: 'api-key',
          credentialRef: { kind: 'record', key: 'anthropic/personal' },
        },
      ],
      classifyFailure: (error) => {
        const status = (error as { status?: number }).status
        if (status === 429) return { kind: 'rate-limit', retryable: true }
        if (status === 401 || status === 403) return { kind: 'auth', retryable: true }
        if (status !== undefined && status >= 500) return { kind: 'transient', retryable: true }
        return { kind: 'fatal', retryable: false }
      },
    }), 'anthropic: multiprovider accounts')
  })
}

Do not put API keys, access tokens, refresh tokens, or raw provider diagnostics in metadata, labels, account IDs, or credential references. A reference must be a locator, not the secret itself.

2. Lease an account for the complete operation

const attempted = new Set<string>()

for (;;) {
  const lease = await ctx.multiprovider.acquire<MyCredentialRef>({
    providerId: 'anthropic',
    affinityKey: session.id,
    excludeAccountIds: attempted,
  })
  attempted.add(lease.accountId)

  try {
    const credential = await resolveCredential(lease.credentialRef)
    const result = await runCompleteProviderOperation(credential)
    lease.release({ status: 'success' })
    return result
  } catch (error) {
    const disposition = lease.release({ status: 'failure', error })
    if (!disposition?.retryable || !isSafeToReplay(error)) throw error
    // Reacquiring with excludeAccountIds selects another eligible account.
  }
}

For streaming LLM requests, hold the lease until the stream has completed or failedโ€”not merely until an async iterable is created. Never replay automatically after user-visible output has started unless the provider integration can prove replay is safe.

Related search, image, usage, and tool operations should pass the same session/workload affinity key when one is available.

Settings UI

The browser plugin contributes a standalone settings.section named Accounts. It shows:

  • registered provider pools and account auth kinds
  • health, cooldown, failure, and in-flight status
  • pool selection policy and session affinity
  • per-account enablement, weight, and priority
  • provider-supplied account-management guidance
  • an operator action to clear automatic cooldown/failure health

Secrets are never returned by GET /plugins/dsh-multiprovider/state. Mutation endpoints enforce loopback and same-origin checks, capped JSON bodies, method allowlists, no-store responses, and strict field validation.

Ownership boundary

Layer Owns
dsh-multiprovider Account pools, leases, selection, affinity, health, cooldowns, failover primitives, operator policy UI
Provider plugin OAuth/API-key enrollment, credential persistence and refresh, transport, complete stream lifetime, error classification
DSH core Request/session lifecycle, credential and authorization services, provider/model identity

Current scope

Health, leases, and affinity are process-local. Preferences are durable through DSH settings. This version does not queue for account capacity, impose per-account concurrency limits, or perform hidden retries. Those are deliberate future extensions; explicit reacquisition keeps replay safety in the provider integration where protocol semantics are known.

Development and release

pnpm install --frozen-lockfile
pnpm run check
pnpm pack --dry-run

pnpm run check type-checks the host and browser faces, runs the complete Vitest suite, and builds the ESM service plus browser client bundle. prepack repeats that check before npm creates a release payload.

Relationship to the other projects

  • DeepSeek Harness owns provider/model identity, request and session lifecycle, settings persistence, the Web host, and client composition.
  • dsh-codex is a concrete integration: it leases Codex accounts while retaining OAuth, token refresh, and response-stream ownership.
  • dsh-fabric, dsh-fovea, dsh-factory, and dsh-tool-repair are the other external bundles pinned by the tested DSH distribution.

License

MIT ยฉ Tom Nguyen.