Skip to content

Define a structured API contract for synchronized model favorites #4466

Description

@marius-kilocode

Problem

modelPreferences persists favorites as opaque string[]. That leaves each client to choose its own identifier encoding. Gateway options use catalog ids such as anthropic/claude-sonnet-4, while mobile remote catalog options use remote:${providerID}:${modelID} because their displayed ids are unstable. The CLI and VS Code extension already represent a favorite as { providerID, modelID }.

The result is that the same model can have different favorite keys across surfaces. A delimited string is also not safely reversible because a provider-local model id can itself contain delimiters. Favorites cannot therefore synchronize reliably across web, mobile, CLI, and the extension.

Required API Contract

Introduce a versioned structured favorites contract rather than changing the existing string-based procedures in place:

type FavoriteModelRef = {
  providerID: string
  modelID: string
}

get(): {
  favorites: FavoriteModelRef[]
  lastSelected: { model: string; variant?: string } | null
}

addFavorite({ favorite: FavoriteModelRef })
removeFavorite({ favorite: FavoriteModelRef })
setFavorites({ favorites: FavoriteModelRef[] })

The structured API must:

  • Treat the pair of providerID and modelID as the unique favorite identity.
  • Preserve the current per-user scope, 500-item limit, idempotent add/remove behavior, and atomic concurrent mutations.
  • Return and accept structured values without requiring clients to serialize or parse a delimited string.
  • Apply organization availability filtering through an explicit mapping from available catalog models to FavoriteModelRef. Do not split arbitrary model strings to derive a reference.
  • Retain unavailable references in storage. Clients can hide models absent from their current catalog, but one device must not delete another device's favorite merely because it cannot resolve it.

Migration And Compatibility

The existing string API is already consumed by released web and mobile clients, so the structured contract must be introduced as a new versioned API or an equivalent backward-compatible transition. Do not generically parse existing strings as provider/model. Existing values include client-specific encodings and provider-local model ids can contain delimiters.

Define an explicit, non-lossy migration path for existing records. Known values may be mapped through an authoritative catalog mapping; values without an unambiguous mapping must not be silently misidentified or discarded. Retire the legacy string contract only after web and mobile have migrated.

App Follow-Up

  • Web and mobile must send and consume FavoriteModelRef values.
  • Mobile must remove the remote:${providerID}:${modelID} favorite-key convention and use the structured remote catalog reference directly.
  • The gateway model adapter must provide a canonical FavoriteModelRef rather than leaking a UI row id.
  • All surfaces must use the same structured identity before cloud synchronization is enabled for CLI and VS Code.

Acceptance Criteria

  • The API has a documented structured favorite type shared by all clients.
  • A favorite written by one surface can be matched by another without client-specific string parsing.
  • Existing favorite records have a defined compatibility and migration behavior.
  • Organization filtering does not remove stored favorites merely because they are temporarily unavailable.
  • Legacy and structured clients can coexist for the migration period.

Client Implementation

CLI and VS Code integration is tracked in Kilo-Org/kilocode#12069. The client work is blocked on the structured API and keeps cloud authentication and synchronization in the CLI service layer.

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