Skip to content

enhancement: model allowed-list / admin policy for the LLM picker #56

Description

@AhmadHammad21

Context

The LLM picker (Settings → Agent config → LLM, shipped in feat/llm-model-picker) lets any
admin pick any model from any configured provider, plus arbitrary custom strings via the
"Custom — type a model name…" option. Good for personal / small-team OSS use.

For production / multi-tenant SaaS, an org admin will eventually want to restrict
which models the picker offers. Reasons:

  • Cost control — block Opus 4.8 because it's 5× Sonnet at scale.
  • Compliance / SOC2 — pin to a list of vetted models (e.g. only EU-hosted Gemini, only
    on-prem Ollama). Block external providers entirely.
  • Reduce support surface — fewer model variants in flight → fewer "why is my chat
    weird?" tickets.

Today

  • The curated catalog (_PROVIDER_CATALOG in apps/core/src/opendevops_core/agent/llm/backend.py)
    is convenience, not policy — users can still type any string in the Custom field, and
    the backend's PUT validation only checks that the provider has credentials.
  • No org / global allowed-list exists.

Proposed shape

  1. Global allow-list (OSS): new env var ALLOWED_LLM_MODELS (comma-separated). When
    set, the picker only offers models that match; the custom field is hidden; PUT rejects
    anything not on the list. Empty/unset = current behavior (everything allowed).
  2. Per-org allow-list (Product): small admin UI on the org settings page; persisted in
    app_config[\"llm_allowed_models_{org_id}\"]. Falls back to the global list when unset.
  3. Glob support so admins can write `anthropic/` or `-haiku-*` without listing every
    model individually.
  4. Catalog filtering: available_providers() filters its models[] against the
    allowed list before returning; UI doesn't need to know about the policy.

Where it lives in the code

  • apps/core/src/opendevops_core/agent/llm/backend.pyavailable_providers() filter +
    a is_model_allowed(model: str) -> bool helper.
  • apps/backend/src/api/routers/settings.py — PUT endpoint rejects with 400 when out of
    policy.
  • Product repo, mirrored — per-org override read from app_config.

Out of scope (for the first cut)

  • Per-user picks (deferred — not currently supported anywhere).
  • Model-by-model cost caps (separate feature; bigger conversation).

Filed from chat discussion 2026-05-30 while merging feat/llm-model-picker.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions