Skip to content

feat: DB-driven free and default model flags for verified models - #191

Open
juanmichelini wants to merge 2 commits into
mainfrom
free-and-default-verified-models
Open

feat: DB-driven free and default model flags for verified models#191
juanmichelini wants to merge 2 commits into
mainfrom
free-and-default-verified-models

Conversation

@juanmichelini

@juanmichelini juanmichelini commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Summary

Backend (PR 1 of 2) for surfacing Free badges and a configurable default model on the OpenHands provider, driven by the database — extending the existing verified model mechanism rather than hardcoding in the frontend.

Today the "Free" badge is hardcoded in the frontend (format-model-name.tsFREE_OPENHANDS_MODELS). This PR makes free (and a per-provider default) ride the same DB-backed channel that verified already uses, so admins can manage them from the verified-models admin API.

Changes

  • Migration 144: adds is_free and is_default boolean columns to verified_models, plus a partial unique index enforcing at most one default per provider. Seeds the previously-hardcoded free set (glm-5.2, deepseek-v4-flash, minimax-m2.7) and the default (glm-5.2) for the openhands provider so the badge is unchanged the instant the frontend switches over.
  • DTOs (verified_model_models.py): is_free / is_default on create/update models.
  • Service (verified_model_service.py): new columns on StoredVerifiedModel, mapper, and create/update accept the flags. Setting a default clears any existing default for the same provider (write-ordering guard alongside the DB index).
  • Admin API (verified_model_router.py): create/update endpoints pass the new fields through.
  • Model contract (config_models.py, utils/llm.py): LLMModel.free and ModelsResponse.free_models mirror the verified channel; get_supported_llm_models(...) accepts free_models and default_model (defaults preserve existing behavior).
  • SaaS service (litellm_proxy_model_router.py / SaaSLLMModelService): emits DB free models and the openhands default into the models response.

Tests

  • enterprise/tests/unit/test_verified_model/: 44 passed (new free/default flag + default-clearing + per-provider isolation tests).
  • tests/unit/app_server/test_llm_model_service.py: 25 passed (new free propagation tests in _to_llm_models).
  • ruff clean on all touched files (root config for openhands/, enterprise config for enterprise/).

Follow-up

PR 2 (in OpenHands/OpenHands) will replace the hardcoded FREE_OPENHANDS_MODELS with the DB-driven free flag flowing through the same channel as verified, and consume the DB-provided default on onboarding and when creating a new OpenHands model.


This PR was created by an AI agent (OpenHands) on behalf of @juanmichelini.


Enterprise server image for this PR:

ghcr.io/openhands/enterprise-server:sha-d1ab7ce

Add is_free and is_default columns to the verified_models table and thread
them through the admin CRUD API, the LLMModel/ModelsResponse contract, and
SaaSLLMModelService so the OpenHands provider can mark models as free (Free
badge) and designate one default model per provider from the database.

- migration 144: is_free/is_default columns + partial unique index enforcing
  one default per provider; seed previously-hardcoded free set and default
- VerifiedModel DTOs + service create/update accept is_free/is_default with
  default-clearing so only one default survives per provider
- LLMModel.free + ModelsResponse.free_models mirror the verified channel
- get_supported_llm_models accepts free_models/default_model
- SaaSLLMModelService emits DB free models and the openhands default

Co-authored-by: openhands <openhands@all-hands.dev>
@github-actions github-actions Bot added the type: feat A new feature label Aug 17, 2026
@github-actions

github-actions Bot commented Aug 17, 2026

Copy link
Copy Markdown

Coverage report

Click to see where and how coverage changed

FileStatementsMissingCoverageCoverage
(new stmts)
Lines missing
  enterprise/server/verified_models
  verified_model_models.py
  verified_model_service.py 149-150, 161-171, 202-216, 253-263
  openhands/app_server/config_api
  config_models.py
  default_llm_model_service.py 61-64
  openhands/app_server/utils
  llm.py 296-297
Project Total  

This report was generated by python-coverage-comment-action

Mirror the free/verified channel: set LLMModel.default for the model matching
ModelsResponse.default_model so the frontend can read the DB-driven default
from the same models search endpoint used for verified/free.

Co-authored-by: openhands <openhands@all-hands.dev>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

type: feat A new feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants