Skip to content

Self-host: switch the model provider at any time, and check a release's models before updating - #318

Merged
nambok merged 1 commit into
mainfrom
feat/selfhost-models-runtime
Oct 26, 2026
Merged

nambok merged 1 commit into
mainfrom
feat/selfhost-models-runtime

Conversation

@nambok

@nambok nambok commented Oct 26, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Self-hosted installs can switch how they call Claude (Amazon Bedrock or Anthropic API keys) at any time in Settings, System, Models, with no redeploy. Every model the release calls must answer a test call before a switch is saved. Before any update is applied, the updater checks every model the new release calls through the install's current provider. A refused model holds the update with the exact fix and console link. Nothing ever accepts AWS or Anthropic terms for anyone.

Changes

  • Runtime provider (common::model_provider): the provider, inference profile prefix and model id overrides are stored on the settings table (SYSTEM/MODELS). The deploy config is only the first-boot default. Gateway (middleware), worker (each event and each model loop) and the log analyzer re-read it at most every 30 s. A broken record falls back to the deploy config. A model call under way finishes on its provider. A run that started on Bedrock without a team key stays on Bedrock.

  • Anthropic keys stay per team. Each key already lives on its team's settings item, every service reads it there, and usage stays on each team's Anthropic bill. An install-wide key would add a second place to read it and pool everyone's usage.

  • Switch routes (routes/system_models.rs, capability system.models, admins who are also install admins, never in custom roles):

    • GET /api/system/models
    • POST /api/system/models/check
    • PUT /api/system/models

    A switch probes every model in the release manifest through the target provider. Bedrock uses the candidate prefix and ids; Anthropic uses the admin's team key. Any failure means 409 with per-model detail, fix and link, and nothing is written. Otherwise the audit entry (model_provider_switched in the team audit log) is written first. If it can't be written, nothing changes. Then the setting is saved.

  • Shared refusal mapping (common::model_access): access off, use case form, Marketplace terms or subscription pending, IAM, model not in region, transient, key refused and no key. Each kind has one fix sentence and a console link. Setup's bedrock_code now uses it.

  • Release model manifest: services/common/release_models.json is built into the services and is what teams can pick (replaces ALLOWED_MODELS). A test fails when any non-test Rust, Python or infra source names a model id that isn't listed. selfhost/launch/release-models.mjs turns it into models.json with Bedrock ids for every prefix. The build job of release.yml writes it before SHA256SUMS, so the signed checksums cover it, and it is attested.

  • Update preflight (lambda/updater): the updater never downloads models.json. A new read-only CodeBuild project, <prefix>-release-check, runs the same VERIFY_SUMS as the update build. It reads models.json only when the signed SHA256SUMS lists it and the checksum matches, then reports models_verified. Its role can only invoke the updater. Until the release is verified the check is pending and the update is held. The worker's new model_check direct call makes one-token test calls (metered on the setup meter) through the install's provider and role.

    • The check runs when a release is first seen, daily while a model is refused, and again right before applying.
    • On refusal: no update, one admin notice (email and webhook), and model_check in status. Settings, System and Setup show "Update to vX needs your action".
    • Once the check passes, the update applies by itself in the maintenance window if auto-update is on.
    • Update now has no override for a model the release calls. skip_check passes only a failure on a model it doesn't call.
  • IAM: every self-hosted install's gateway, worker, streaming and log analyzer roles get bedrock:InvokeModel (which also covers Converse) and bedrock:InvokeModelWithResponseStream, limited to Anthropic foundation models and inference profiles. This lets an install that started on keys switch without a redeploy. Nothing gets aws-marketplace:* or the agreement and use case APIs. The updater may invoke the worker and start the release check, and calls no model itself.

  • Docs: model-providers.md covers switching, Bedrock model access (model access, use case form, Marketplace terms, always a person's action), and updates and new models. updates.md covers the model check. The CLI wizard's Models step and the Launch Stack parameter now say "You can change this later in Settings, System."

Verification

  • cargo fmt --check; cargo clippy --workspace --all-targets -D warnings; cargo test --workspace. New tests cover setting resolution and fallback, the refusal mapping for every kind, switch refused or audited-then-saved, no audit entry means no switch, a switch to keys without a key, the manifest drift test, the worker's id choice, and preflight blockers including the pending state.
  • python3 -m unittest discover -s lambda/tests. New tests: a refused model holds the update and notifies once; the daily retry applies after a pass; a refusal found right before applying stops it; Update now has no override; skip only for a model the release doesn't call; the manifest is read only after the signature check; the source never downloads models.json; the only AWS call is the worker invoke. All model calls are faked, with no AWS writes.
  • infra npm test: Bedrock access on an Anthropic-first self-host, no Marketplace or agreement actions anywhere, the release check reads models.json only after VERIFY_SUMS and its role can only report back, and the hosted deployment gets no Bedrock access.
  • node --test selfhost/launch/*.test.mjs, which includes the release manifest test and checks that the workflow writes models.json into SHA256SUMS. .github/scripts/check_workflows.py passes (no new actions). Installer npm test passes.

Dashboard: CoderHelm/coderhelm#230

…'s models before updating

- Settings, System, Models: Claude on Amazon Bedrock or Anthropic API keys,
  stored at runtime (SYSTEM/MODELS); the deploy config is the first-boot
  default. Every model the release calls answers a test call first; the
  switch is audited, then saved, and reaches every service within 30 s.
- Release model manifest (services/common/release_models.json), built into
  the services, held to the code by a test, published as models.json in the
  signed SHA256SUMS.
- The updater reads models.json only through a read-only release check
  build after the signature check, then has the worker test each model
  through the install's provider. A refused model holds the update with its
  fix; checked daily; applies once it passes. No terms are ever accepted.
- Every self-hosted install may call Claude on Bedrock (Anthropic models and
  inference profiles only); no Marketplace or agreement permissions.
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.

1 participant