Skip to content

v1.5.0: dynamic model list — server-driven, not hardcoded. - #10

Open
boogy777-lgtm wants to merge 2 commits into
lemon07r:masterfrom
boogy777-lgtm:master
Open

v1.5.0: dynamic model list — server-driven, not hardcoded.#10
boogy777-lgtm wants to merge 2 commits into
lemon07r:masterfrom
boogy777-lgtm:master

Conversation

@boogy777-lgtm

@boogy777-lgtm boogy777-lgtm commented Aug 3, 2026

Copy link
Copy Markdown
Mirror kimi-cli refresh_managed_models: GET /coding/v1/models is now the
single source of truth for the model family and metadata.  A new config hook
injects the provider entry + one model entry per discovered model at every
opencode startup (best-effort, static fallback on failure), so newly
released Kimi Code models appear in the picker without a plugin update or
manual config block — same UX as opencode-gemini-auth/antigravity-auth.

• config hook: startup model sync plus provider entry injection
• provider.models: materializes discovered models missing from config
• isKimiModel gates on discovered ids ∪ static fallback, not hardcoded list
• buildConfigBlock generated from discovery (context_length server-reported)
• FALLBACK_MODEL_IDS/FALLBACK_MODELS constants — cold-start only
• MAX_REASONING_MODEL_IDS stays explicit (capability gate, not model list)
• deep per-field merge: user config overrides win, never deleted
• 6 new tests, 85/85 green, tsc clean

Summary by cubic

Makes the Kimi Code model list server‑driven. On startup we sync /coding/v1/models, refresh the token if needed, and inject the provider + discovered models so new Kimi models appear without plugin updates or config edits.

  • New Features

    • Startup config hook: refreshes an expiring token, retries discovery once on 401, injects kimi-for-coding-oauth with one entry per discovered model; falls back to a small static list on failure; user overrides are merged per-field.
    • Runtime: provider.models updates display_name, context_length, and image/video support for all known Kimi Code ids and materializes newly discovered models missing from config; Kimi fields (prompt_cache_key, thinking, reasoning_effort) gate on discovered ∪ fallback ids.
    • Reasoning effort: max is sent for k3; max and xhigh clamp to high for K2.7/unknown models.
    • Wire model rewrite: body model rewrites to the discovered slug only when discovery returned exactly one model; the legacy kimi-for-coding alias remains supported.
    • Generated config: injected models include limit: { context, output: 65536 }, attachment: true, modalities from discovery, and variants including max.
    • Docs/tests: README/AGENTS updated; additional tests added; version bumped to 1.5.0.
  • Migration

    • No action required. The plugin injects the provider and model list at startup; existing config keeps working and user-set fields win over generated defaults.

Written for commit 7e19876. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • New Features

    • Automatically discovers available models and synchronizes configuration at startup.
    • Supports multiple models with model-specific context limits, output limits, media capabilities, and reasoning options.
    • Adds fallback models when discovery is unavailable.
    • Refreshes configuration after authentication or model changes.
  • Bug Fixes

    • Adjusts unsupported reasoning levels according to each model’s capabilities.
    • Preserves custom model settings when applying discovered configuration.
  • Documentation

    • Updated setup, login, troubleshooting, usage, and model configuration guidance.
  • Chores

    • Updated the release version to 1.5.0.

    Mirror kimi-cli refresh_managed_models: GET /coding/v1/models is now the
    single source of truth for the model family and metadata.  A new config hook
    injects the provider entry + one model entry per discovered model at every
    opencode startup (best-effort, static fallback on failure), so newly
    released Kimi Code models appear in the picker without a plugin update or
    manual config block — same UX as opencode-gemini-auth/antigravity-auth.

    • config hook: startup model sync plus provider entry injection
    • provider.models: materializes discovered models missing from config
    • isKimiModel gates on discovered ids ∪ static fallback, not hardcoded list
    • buildConfigBlock generated from discovery (context_length server-reported)
    • FALLBACK_MODEL_IDS/FALLBACK_MODELS constants — cold-start only
    • MAX_REASONING_MODEL_IDS stays explicit (capability gate, not model list)
    • deep per-field merge: user config overrides win, never deleted
    • 6 new tests, 85/85 green, tsc clean
@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The plugin now discovers multiple Kimi models, generates fallback metadata, synchronizes provider configuration at startup, preserves user overrides, and applies model-specific limits and reasoning variants.

Changes

Kimi model discovery and configuration

Layer / File(s) Summary
Model metadata and materialization
src/constants.ts, src/index.ts, test/plugin.test.ts
Fallback and discovered models now include IDs, limits, media capabilities, reasoning variants, and model-specific gating.
Startup configuration synchronization
src/index.ts, test/plugin.test.ts, README.md, AGENTS.md
Startup discovery refreshes authentication, retries 401 responses, falls back when discovery fails, injects provider models, and merges user overrides.
Request model and reasoning integration
src/index.ts, test/plugin.test.ts, README.md
Requests resolve discovered wire IDs, apply Kimi fields, and clamp reasoning effort by model.
Documentation and release metadata
README.md, AGENTS.md, package.json
Documentation describes automatic discovery, startup injection, generated metadata, request fields, verification, and version 1.5.0.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant PluginConfigHook
  participant ModelDiscovery
  participant ProviderConfig
  PluginConfigHook->>ModelDiscovery: discover models before startup loading
  ModelDiscovery-->>PluginConfigHook: discovered or fallback model list
  PluginConfigHook->>ProviderConfig: merge overrides and upsert provider models
Loading

Suggested reviewers: lemon07r

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: replacing hardcoded model configuration with a server-driven dynamic model list.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
src/constants.ts (1)

35-61: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider deriving FALLBACK_MODEL_IDS from FALLBACK_MODELS.

The two constants list the same three ids. A future edit to one list can leave the other stale, which silently changes the cold-start known-model gate.

♻️ Proposed refactor
-export const FALLBACK_MODEL_IDS = ["k3", "kimi-for-coding", "kimi-for-coding-highspeed"] as const
-
-// Fallback per-model metadata for the same cold-start path. Server-reported
+// Fallback per-model metadata for the cold-start path. Server-reported
 // `display_name` / `context_length` / `supports_*` flags always win over these.
 export const FALLBACK_MODELS: ReadonlyArray<{
   id: string
   display_name: string
   context_length: number
   supports_image_in: boolean
   supports_video_in: boolean
 }> = [

Then declare the id list after the table:

export const FALLBACK_MODEL_IDS: ReadonlyArray<string> = FALLBACK_MODELS.map((m) => m.id)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/constants.ts` around lines 35 - 61, Derive FALLBACK_MODEL_IDS from
FALLBACK_MODELS instead of maintaining a duplicate literal list. Move its
declaration after the FALLBACK_MODELS table and map each model’s id, preserving
the existing exported read-only string-array contract.
test/plugin.test.ts (1)

227-258: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider adding a clamp test for a model outside MAX_REASONING_MODEL_IDS that is known only from discovery.

The new tests cover k3 and kimi-for-coding. The documented rule also clamps max to high for any newly discovered model until it is verified. A test for a discovered id such as k4 with reasoning_effort: "max" would lock that safe default in.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/plugin.test.ts` around lines 227 - 258, Add a chat.params test for a
discovered model ID outside MAX_REASONING_MODEL_IDS, such as k4, using
reasoning_effort "max"; assert the output clamps reasoning_effort to "high" and
enables thinking, matching the existing kimi-for-coding coverage.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/index.ts`:
- Around line 748-761: Restrict the legacy MODEL_ID fallback in the discovered
model lookup to cases where auth.models contains exactly one model. When
discovery has zero or multiple models and does not contain MODEL_ID, leave
requestedModelId unchanged so the server handles the entitlement error; preserve
direct matches and the existing single-model fallback behavior.

---

Nitpick comments:
In `@src/constants.ts`:
- Around line 35-61: Derive FALLBACK_MODEL_IDS from FALLBACK_MODELS instead of
maintaining a duplicate literal list. Move its declaration after the
FALLBACK_MODELS table and map each model’s id, preserving the existing exported
read-only string-array contract.

In `@test/plugin.test.ts`:
- Around line 227-258: Add a chat.params test for a discovered model ID outside
MAX_REASONING_MODEL_IDS, such as k4, using reasoning_effort "max"; assert the
output clamps reasoning_effort to "high" and enables thinking, matching the
existing kimi-for-coding coverage.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: eaad6917-2ff8-489a-87d5-f190408c31ca

📥 Commits

Reviewing files that changed from the base of the PR and between 86a3d32 and b40fb81.

📒 Files selected for processing (6)
  • AGENTS.md
  • README.md
  • package.json
  • src/constants.ts
  • src/index.ts
  • test/plugin.test.ts

Comment thread src/index.ts

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 6 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="src/constants.ts">

<violation number="1" location="src/constants.ts:35">
P2: After `/coding/v1/models` succeeds, a model omitted by the account can still be treated as a Kimi model because this fallback ID remains in the permanent gate. Restrict the post-discovery gate to discovered IDs and use the fallback IDs only while no discovery list exists, so removed or unauthorized models are not sent through Kimi-specific request handling.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread src/index.ts Outdated
Comment thread src/constants.ts Outdated
// model list at all. The entries below are only the cold-start fallback used
// when discovery has not produced a list yet in this process (offline start,
// not logged in, or the chat hooks firing before the first discovery).
export const FALLBACK_MODEL_IDS = ["k3", "kimi-for-coding", "kimi-for-coding-highspeed"] as const

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: After /coding/v1/models succeeds, a model omitted by the account can still be treated as a Kimi model because this fallback ID remains in the permanent gate. Restrict the post-discovery gate to discovered IDs and use the fallback IDs only while no discovery list exists, so removed or unauthorized models are not sent through Kimi-specific request handling.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/constants.ts, line 35:

<comment>After `/coding/v1/models` succeeds, a model omitted by the account can still be treated as a Kimi model because this fallback ID remains in the permanent gate. Restrict the post-discovery gate to discovered IDs and use the fallback IDs only while no discovery list exists, so removed or unauthorized models are not sent through Kimi-specific request handling.</comment>

<file context>
@@ -22,8 +22,55 @@ export const OAUTH_DEVICE_GRANT = "urn:ietf:params:oauth:grant-type:device_code"
+// model list at all. The entries below are only the cold-start fallback used
+// when discovery has not produced a list yet in this process (offline start,
+// not logged in, or the chat hooks firing before the first discovery).
+export const FALLBACK_MODEL_IDS = ["k3", "kimi-for-coding", "kimi-for-coding-highspeed"] as const
+
+// Fallback per-model metadata for the same cold-start path. Server-reported
</file context>

Comment thread src/index.ts Outdated
Comment thread src/index.ts Outdated
Comment thread AGENTS.md Outdated
Comment thread test/plugin.test.ts Outdated
…ambiguous slug fallback

    • config hook refreshes an expiring stored token before startup discovery
      (Kimi access tokens live ~15 min — without this, cold starts always
      401'd and degraded to the static fallback) + one forced-refresh retry on 401
    • chat-hook gate is the discovered id set once discovery succeeded;
      fallback-id models the server omits drop out (fail loud server-side)
    • rememberDiscovery overwrites even on empty list — a successful response
      is authoritative, stale entitlements must not survive it
    • MODEL_ID wire-slug fallback only when discovery returned exactly one
      model; multi-model discovery leaves the id untouched so the server
      answers with a visible entitlement error instead of silently running a
      different model
    • FALLBACK_MODEL_IDS derived from FALLBACK_MODELS (no duplicate literal)
    • tests: max→high clamp for discovered-only model, gate drop-out after
      discovery, refresh-before-discovery, 401 retry, fixed dead mock in the
      network-down test
    • 89/89 green, tsc clean

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/index.ts`:
- Around line 105-113: Update knownModelIds to use the presence of
discovery.models, not its length, so an authoritative empty array returns an
empty set while undefined still uses FALLBACK_MODEL_IDS. Apply the same
undefined-versus-defined check to the config fallback near config and
FALLBACK_MODELS, preserving the existing cachedDiscovery consumers in
chat.headers and chat.params through the corrected knownModelIds behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: b951ad4e-59f7-49cd-b5dc-a03c66710731

📥 Commits

Reviewing files that changed from the base of the PR and between b40fb81 and 7e19876.

📒 Files selected for processing (4)
  • AGENTS.md
  • src/constants.ts
  • src/index.ts
  • test/plugin.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/constants.ts

Comment thread src/index.ts
Comment on lines +105 to +113
// The known set is the server-discovered list once discovery has succeeded in
// this process (kimi-cli keeps no static list at all — removed/entitled-out
// models drop out of the gate, so their requests fail loud server-side
// instead of carrying Kimi-specific fields). The static fallback only covers
// the window before the first discovery.
function knownModelIds(discovery: ModelDiscovery): ReadonlySet<string> {
if (discovery.models?.length) return new Set(discovery.models.map((m) => m.id))
return new Set(FALLBACK_MODEL_IDS)
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

knownModelIds cannot distinguish "not yet discovered" from "discovered, zero models".

ModelDiscovery.models is optional, and rememberDiscovery (Line 537) deliberately sets cachedDiscovery = { models } even for an empty array, because a successful /models response is treated as authoritative. However, knownModelIds checks discovery.models?.length (Line 111), which is falsy both when discovery has never run and when discovery legitimately returned zero models. In the latter case, the function still returns FALLBACK_MODEL_IDS (Line 112), contradicting its own comment that "the static fallback only covers the window before the first discovery."

Practical effect: if an account's entitlement drops to zero models, a successful (authoritative) empty response should stop treating any id as Kimi-capable, but this code silently re-enables gating for the stale fallback ids instead. The same .length ambiguity is inherited at:

  • Line 612, where config falls back to FALLBACK_MODELS for the same authoritative-empty case.
  • Line 862 and Line 884, where chat.headers/chat.params call knownModelIds(cachedDiscovery) and therefore inherit the same misclassification.

Distinguish "undefined" from "defined-but-empty" instead of using .length.

🐛 Proposed fix for the discovery-state check
 function knownModelIds(discovery: ModelDiscovery): ReadonlySet<string> {
-  if (discovery.models?.length) return new Set(discovery.models.map((m) => m.id))
-  return new Set(FALLBACK_MODEL_IDS)
+  if (discovery.models) return new Set(discovery.models.map((m) => m.id))
+  return new Set(FALLBACK_MODEL_IDS)
 }

Also applies to: 612-612, 862-862, 884-884

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/index.ts` around lines 105 - 113, Update knownModelIds to use the
presence of discovery.models, not its length, so an authoritative empty array
returns an empty set while undefined still uses FALLBACK_MODEL_IDS. Apply the
same undefined-versus-defined check to the config fallback near config and
FALLBACK_MODELS, preserving the existing cachedDiscovery consumers in
chat.headers and chat.params through the corrected knownModelIds behavior.

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