mirror of
https://github.com/lemon07r/opencode-kimi-full.git
synced 2026-07-18 08:05:52 +02:00
Fix invalid login config hint
This commit is contained in:
@@ -70,6 +70,7 @@ These are the invariants that, if broken, silently degrade K2.6 → K2.5 or prod
|
||||
7. **Auth store is opencode's, not kimi-cli's.** We use opencode's auth store for tokens under the `kimi-for-coding-oauth` provider id. Do not read/write `~/.kimi/credentials/kimi-code.json`; that's kimi-cli's file and sharing it across independent apps causes token-race bugs. Also note that opencode's SDK auth schema only persists the standard oauth fields, so model discovery metadata cannot be stored there durably.
|
||||
8. **Provider id must not collide with any id in the [models.dev](https://models.dev) catalog.** models.dev publishes `kimi-for-coding` (static `KIMI_API_KEY` → `@ai-sdk/anthropic` → K2.5). If we registered under that same id, `opencode auth login kimi-for-coding` would surface two methods under one entry and users picking the API-key one would silently land on K2.5. We deliberately use `kimi-for-coding-oauth` instead; `MODEL_ID` on the wire stays `kimi-for-coding` (rule 6).
|
||||
9. **`src/index.ts` must have exactly one export — the default plugin function.** opencode's plugin loader (`research/opencode/packages/opencode/src/plugin/index.ts` → `getLegacyPlugins`) iterates every export of the plugin module and throws `Plugin export is not a function` if any named export is not callable. The failure mode is silent in the CLI (the provider just doesn't appear in `opencode auth login`); the error only surfaces in `~/.local/share/opencode/log/*.log`. Keep constants in `src/constants.ts` and import them in `src/index.ts` rather than re-exporting. `test/exports.test.ts` guards this.
|
||||
10. **The post-login config hint must not emit a partial `limit` object.** opencode's live config schema at `https://opencode.ai/config.json` requires both `limit.context` and `limit.output` whenever `limit` is present, while Kimi's `GET /coding/v1/models` only gives us `context_length`. Therefore `buildConfigBlock()` omits `limit` entirely and leaves `provider.models` to backfill `limit.context` at runtime. Do not invent `output` or set `input` heuristically; opencode's overflow logic treats `limit.input` as authoritative (`research/opencode/packages/opencode/src/session/overflow.ts`).
|
||||
|
||||
### Working on this repo
|
||||
|
||||
|
||||
@@ -100,7 +100,7 @@ Two identifiers are load-bearing:
|
||||
opencode auth login -p kimi-for-coding-oauth
|
||||
```
|
||||
|
||||
The plugin returns a verification URL and user code. After browser approval it polls the device-auth endpoint, queries `/coding/v1/models` to discover the current model id and context length for your account, prints a config snippet with that context length filled in, and stores the token in opencode's auth store. Model discovery runs again on every token refresh, and a fresh loader instance will re-query `/coding/v1/models` on first use if it needs the current wire model id. Access tokens refresh automatically, and the loader retries once after a `401`.
|
||||
The plugin returns a verification URL and user code. After browser approval it polls the device-auth endpoint, queries `/coding/v1/models` to discover the current model id and context length for your account, prints a ready-to-paste config snippet, and stores the token in opencode's auth store. The authorization message still includes the discovered context length; the snippet intentionally omits `limit` because opencode's schema requires `limit.output` too, and Kimi's models endpoint only exposes `context_length`. Model discovery runs again on every token refresh, and a fresh loader instance will re-query `/coding/v1/models` on first use if it needs the current wire model id. Access tokens refresh automatically, and the loader retries once after a `401`.
|
||||
|
||||
### Use
|
||||
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "opencode-kimi-full",
|
||||
"version": "1.2.2",
|
||||
"version": "1.2.3",
|
||||
"description": "OpenCode plugin that adds first-class support for Kimi K2.6 (kimi-for-coding) via the official Kimi OAuth device flow, matching the upstream kimi-cli 1:1.",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
|
||||
+6
-4
@@ -174,13 +174,17 @@ function applyDiscoveryToModels<T extends Record<string, ModelWithContextLimit>>
|
||||
}
|
||||
}
|
||||
|
||||
function buildConfigBlock(info: { model_id: string; context_length?: number; display?: string }) {
|
||||
function buildConfigBlock(info: { model_id: string; display?: string }) {
|
||||
const name = info.display ?? "Kimi For Coding"
|
||||
const ctx = info.context_length ?? 0
|
||||
// The opencode-side model key is always MODEL_ID ("kimi-for-coding"); the
|
||||
// plugin rewrites the wire `model` body field to `info.model_id` inside
|
||||
// `loader.fetch`. This way both K2.5 and K2.6 users paste identical
|
||||
// config — only the wire request differs.
|
||||
//
|
||||
// Intentionally omit `limit`: opencode's config schema requires
|
||||
// `limit.output` whenever a `limit` object is present, but Kimi's
|
||||
// `/coding/v1/models` discovery only tells us `context_length`. The
|
||||
// provider.models hook backfills `limit.context` at runtime.
|
||||
return JSON.stringify(
|
||||
{
|
||||
provider: {
|
||||
@@ -193,7 +197,6 @@ function buildConfigBlock(info: { model_id: string; context_length?: number; dis
|
||||
name,
|
||||
reasoning: true,
|
||||
options: {},
|
||||
...(ctx > 0 ? { limit: { context: ctx } } : {}),
|
||||
variants: {
|
||||
off: { reasoning_effort: "off" },
|
||||
auto: { reasoning_effort: "auto" },
|
||||
@@ -462,7 +465,6 @@ const plugin: Plugin = async ({ client }) => {
|
||||
// this next to the "Authorized" message.
|
||||
const block = buildConfigBlock({
|
||||
model_id: discovered.model_id,
|
||||
context_length: discovered.context_length,
|
||||
display: discovered.model_display,
|
||||
})
|
||||
console.log(
|
||||
|
||||
+3
-2
@@ -692,7 +692,7 @@ test("auth.methods[0].authorize returns URL + instructions + async callback", as
|
||||
expect(typeof cb.expires).toBe("number")
|
||||
})
|
||||
|
||||
test("auth callback prints a config snippet with top-level model variants", async () => {
|
||||
test("auth callback prints a schema-valid config snippet with top-level model variants", async () => {
|
||||
mock = installFetchMock((call) => {
|
||||
if (call.url.includes("device_authorization")) {
|
||||
return {
|
||||
@@ -744,7 +744,8 @@ test("auth callback prints a config snippet with top-level model variants", asyn
|
||||
}
|
||||
}
|
||||
const model = parsed.provider[PROVIDER_ID]!.models[MODEL_ID]!
|
||||
expect(model.limit?.context).toBe(262144)
|
||||
expect(text).toContain("context 262144")
|
||||
expect(model.limit).toBeUndefined()
|
||||
expect(model.options).toEqual({})
|
||||
expect(model.variants?.off).toEqual({ reasoning_effort: "off" })
|
||||
expect(model.variants?.auto).toEqual({ reasoning_effort: "auto" })
|
||||
|
||||
Reference in New Issue
Block a user