pi-provider-kimi-code 0.6.3 → 0.6.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +35 -21
- package/index.ts +129 -23
- package/package.json +1 -1
- package/src/config.ts +5 -2
- package/src/constants.ts +3 -3
- package/src/device.ts +41 -0
- package/src/models.ts +157 -29
- package/src/oauth.ts +168 -39
- package/src/payload.ts +60 -25
- package/src/stream.ts +25 -6
- package/src/tools/common.ts +6 -4
- package/src/tools/moonshot.ts +13 -35
- package/src/usage.ts +133 -13
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
Pi already has a basic `kimi-coding` provider. This extension is for the parts that start to matter once Kimi Code becomes part of your real Pi workflow: account login reuse, file uploads, tool schema compatibility, live model metadata, measured cache behavior, and API-tested parameter handling.
|
|
9
9
|
|
|
10
|
-
> **Kimi
|
|
10
|
+
> **Kimi K3 supported.** The provider combines Kimi's live `/v1/models` catalog with your membership level from `/usages`, exposing only eligible models and advertising the correct K3 context limit. It refreshes this metadata at startup and through `/kimi-settings`; OAuth login and token refresh also update the model catalog.
|
|
11
11
|
|
|
12
12
|
## Why this exists
|
|
13
13
|
|
|
@@ -19,20 +19,20 @@ Kimi's API surface goes beyond the LLM itself. It includes file uploads, web sea
|
|
|
19
19
|
- **Send files the Kimi way.** Large inline images go through Kimi's Files API and become `ms://` references instead of huge base64 payloads.
|
|
20
20
|
- **Know what the cache is doing.** Kimi caches by content prefix. This repo measures that behavior instead of pretending `prompt_cache_key` controls it.
|
|
21
21
|
- **Keep Pi's tools working.** Moonshot's API rejects tool schemas over 15 KB — a limit that Pi's extension ecosystem regularly hits ([#16](https://github.com/Leechael/pi-provider-kimi-code/issues/16), [#21](https://github.com/Leechael/pi-provider-kimi-code/issues/21)). This extension automatically deduplicates schemas with `$ref`/`$defs` before sending, so subagents and other extensions don't break.
|
|
22
|
-
- **Tested against the live API.** Thinking config, parameter constraints, protocol compatibility, and streaming behavior are all verified against Kimi's Coding endpoint — not assumed from docs. When the API rejects something (wrong `temperature`, unsupported `tool_choice`), the provider
|
|
22
|
+
- **Tested against the live API.** Thinking config, parameter constraints, protocol compatibility, and streaming behavior are all verified against Kimi's Coding endpoint — not assumed from docs. When the API rejects something (wrong `temperature`, unsupported `tool_choice`), the provider normalizes the request before you see a 400.
|
|
23
23
|
- **Turn on Kimi-native tools when you want them.** `moonshot_search`, `moonshot_fetch`, and `kimi_datasource` are opt-in, configurable per user or per project.
|
|
24
24
|
- **Embed in your own build.** `KimiCode()` factory lets you ship Kimi Code support inside a custom Pi agent with programmatic config overrides — no file-based extension path needed.
|
|
25
25
|
|
|
26
26
|
## What this package adds
|
|
27
27
|
|
|
28
28
|
- Kimi account login in Pi, plus `KIMI_API_KEY` for CI or pay-per-token use.
|
|
29
|
-
- `kimi-code` credential reuse from `~/.kimi/credentials/kimi-code.json
|
|
29
|
+
- `kimi-code` credential reuse from `~/.kimi-code/credentials/kimi-code.json`, with read-only support for the legacy `~/.kimi` path.
|
|
30
30
|
- Kimi Files API uploads for large inline images.
|
|
31
|
-
- Live model metadata
|
|
31
|
+
- Live model metadata combined with membership-aware K3 and HighSpeed availability.
|
|
32
32
|
- OpenAI-compatible mode by default, Anthropic-compatible mode on request.
|
|
33
|
-
-
|
|
33
|
+
- K2.7 and K3 reasoning level mapping for Pi's reasoning controls.
|
|
34
34
|
- Tool schema dedup to stay under Moonshot's 15 KB per-tool-schema limit.
|
|
35
|
-
- K2.7 parameter guard:
|
|
35
|
+
- K2.7 parameter guard: removes rejected `temperature` and `top_p` values and rewrites unsupported `tool_choice` values to `auto`.
|
|
36
36
|
- Stream cleanup for Kimi's thinking-only placeholder text.
|
|
37
37
|
- Optional `moonshot_search`, `moonshot_fetch`, and unified datasource `kimi_datasource` tools via `/kimi-settings`.
|
|
38
38
|
- Programmatic `KimiCode()` factory for embedding in custom Pi builds.
|
|
@@ -84,15 +84,21 @@ Inside Pi, run:
|
|
|
84
84
|
/login kimi-coding
|
|
85
85
|
```
|
|
86
86
|
|
|
87
|
-
A browser tab opens, you sign into your Kimi account, and Pi stores the credential at `~/.pi/agent/auth.json`. Tokens refresh automatically.
|
|
87
|
+
A browser tab opens, you sign into your Kimi account, and Pi stores the credential at `~/.pi/agent/auth.json`. Tokens refresh automatically. The extension also syncs refreshed credentials to the current `kimi-code` credential file:
|
|
88
88
|
|
|
89
|
-
|
|
89
|
+
```text
|
|
90
|
+
~/.kimi-code/credentials/kimi-code.json
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
If you already use `kimi-code`, the extension can reuse that session. Set `KIMI_CODE_HOME` if its home directory lives somewhere else.
|
|
94
|
+
|
|
95
|
+
The legacy credential path is also supported:
|
|
90
96
|
|
|
91
97
|
```text
|
|
92
98
|
~/.kimi/credentials/kimi-code.json
|
|
93
99
|
```
|
|
94
100
|
|
|
95
|
-
|
|
101
|
+
Legacy credentials are read-only. Set `KIMI_SHARE_DIR` to override the legacy `~/.kimi` directory.
|
|
96
102
|
|
|
97
103
|
For CI or pay-per-token use, set `KIMI_API_KEY` instead:
|
|
98
104
|
|
|
@@ -100,18 +106,24 @@ For CI or pay-per-token use, set `KIMI_API_KEY` instead:
|
|
|
100
106
|
KIMI_API_KEY=sk-... pi
|
|
101
107
|
```
|
|
102
108
|
|
|
103
|
-
##
|
|
109
|
+
## Models
|
|
104
110
|
|
|
105
|
-
This provider publishes
|
|
111
|
+
This provider publishes three Pi model IDs:
|
|
106
112
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
113
|
+
| Pi model ID | Upstream model | Access |
|
|
114
|
+
| --------------------------------------- | ------------------------ | ------------------------------------------------------ |
|
|
115
|
+
| `kimi-coding/kimi-for-coding` | Kimi K2.7 Code | All Kimi Code members |
|
|
116
|
+
| `kimi-coding/kimi-for-coding-highspeed` | Kimi K2.7 Code HighSpeed | Allegretto and above |
|
|
117
|
+
| `kimi-coding/k3` | Kimi K3 | Moderato: 256K context; Allegretto and above: up to 1M |
|
|
110
118
|
|
|
111
|
-
|
|
119
|
+
Plans below Moderato cannot use K3. The provider reads the current membership level from `/usages` and combines it with `/models`: server catalog availability remains authoritative, while known plan limits can only hide unavailable selections or lower K3's advertised context window. Unknown or unavailable membership data falls back to the server catalog instead of guessing.
|
|
120
|
+
|
|
121
|
+
Select a model inside Pi:
|
|
112
122
|
|
|
113
123
|
```text
|
|
114
124
|
/model kimi-coding/kimi-for-coding
|
|
125
|
+
/model kimi-coding/kimi-for-coding-highspeed
|
|
126
|
+
/model kimi-coding/k3
|
|
115
127
|
```
|
|
116
128
|
|
|
117
129
|
Kimi keeps Coding models behind aliases. Rather than hardcoding a stale model list, this extension asks Kimi for the current model info when you log in or refresh. If your account is on a newer rollout (e.g., Kimi K2.7) or internal test, Pi can pick up the latest model name and context size without waiting for a package release.
|
|
@@ -123,7 +135,9 @@ Fallback values:
|
|
|
123
135
|
- Input: text and image
|
|
124
136
|
- Reasoning: enabled
|
|
125
137
|
|
|
126
|
-
The provider maps Pi's reasoning levels to Kimi's `
|
|
138
|
+
The provider maps Pi's reasoning levels to Kimi's top-level `thinking` parameter. K3 currently advertises only `max`; `max` and `xhigh` map to `max`, `high` and `medium` map to `high`, and `low` and `minimal` map to `low`. It sends `thinking.effort` only when `/models` advertises the mapped value. The mapping refreshes automatically on credential refresh. Opening `/kimi-settings` also re-discovers the latest model and membership metadata.
|
|
139
|
+
|
|
140
|
+
Switching models or thinking effort invalidates Kimi's existing context cache. Start a new session when switching to avoid re-prefilling a long conversation and consuming extra quota.
|
|
127
141
|
|
|
128
142
|
## Optional tools
|
|
129
143
|
|
|
@@ -135,14 +149,14 @@ Inside Pi, run:
|
|
|
135
149
|
/kimi-settings
|
|
136
150
|
```
|
|
137
151
|
|
|
138
|
-
That command shows the current server-side model name (e.g. "K2.7 Code High Speed"), your Kimi
|
|
152
|
+
That command shows the current server-side model name (e.g. "K2.7 Code High Speed"), your Kimi quota and Extra Usage balance, and lets you edit the home or project config. Changes apply to the active session tool set.
|
|
139
153
|
|
|
140
154
|
Configurable settings include protocol mode, upload threshold, and per-tool enable/collapse.
|
|
141
155
|
|
|
142
156
|
Config files are JSON:
|
|
143
157
|
|
|
144
|
-
- Home: `~/.pi/
|
|
145
|
-
- Project override: `<cwd>/.pi/
|
|
158
|
+
- Home: `~/.pi/providers/kimi-coding/config.json`
|
|
159
|
+
- Project override: `<cwd>/.pi/providers/kimi-coding/config.json`
|
|
146
160
|
|
|
147
161
|
Project config overrides home config with a deep merge. Missing files or missing keys mean all tools stay off.
|
|
148
162
|
|
|
@@ -277,7 +291,7 @@ Kimi's cache is **content-based**: it fires automatically when your prompt prefi
|
|
|
277
291
|
- A timestamp, request ID, or randomized header is being interpolated into the prompt.
|
|
278
292
|
- The first ~256 tokens of the prompt differ between turns.
|
|
279
293
|
|
|
280
|
-
`PI_CACHE_RETENTION=none` skips `prompt_cache_key` injection but **does not** disable Kimi's caching (the cache is unconditional). For deterministic measurement, run `scripts/
|
|
294
|
+
`PI_CACHE_RETENTION=none` skips `prompt_cache_key` injection but **does not** disable Kimi's caching (the cache is unconditional). For deterministic measurement, run a focused suite under `scripts/e2e/cache/`, starting with `scripts/e2e/cache/ttl.sh`. See [docs/caching.md](docs/caching.md) for full mechanics.
|
|
281
295
|
|
|
282
296
|
### OpenAI-compatible tools complain about a `developer` role
|
|
283
297
|
|
|
@@ -294,7 +308,7 @@ In OpenAI mode this extension maps the `developer` role to `system` (Kimi's Codi
|
|
|
294
308
|
|
|
295
309
|
## Credits
|
|
296
310
|
|
|
297
|
-
Based on the login implementation from Kimi Code by Moonshot AI.
|
|
311
|
+
Based on the login implementation from Kimi Code by Moonshot AI. Pi was originally created by [@badlogic](https://github.com/badlogic).
|
|
298
312
|
|
|
299
313
|
## License
|
|
300
314
|
|
package/index.ts
CHANGED
|
@@ -42,12 +42,19 @@ import { PROVIDER_ID, PROVIDER_VERSION, getBaseUrl, getKimiApiType } from "./src
|
|
|
42
42
|
import {
|
|
43
43
|
type KimiOAuthCredentials,
|
|
44
44
|
type KimiOAuthExtras,
|
|
45
|
+
applyKimiMembershipLimitsToModel,
|
|
45
46
|
buildKimiModelFromConfig,
|
|
46
47
|
applyKimiOAuthExtrasToModel,
|
|
48
|
+
KIMI_CODING_HIGHSPEED_MODEL_ID,
|
|
49
|
+
KIMI_CODING_MODEL_ID,
|
|
50
|
+
KIMI_K3_MODEL_ID,
|
|
51
|
+
KIMI_MODEL_CATALOG_VERSION,
|
|
47
52
|
discoverKimiModelMetadata,
|
|
53
|
+
getKimiModelMetadata,
|
|
54
|
+
isKimiModelAvailableForMembership,
|
|
48
55
|
resolveKimiModelConfig,
|
|
49
56
|
} from "./src/models.ts";
|
|
50
|
-
import { loginKimiCode, refreshKimiCodeToken } from "./src/oauth.ts";
|
|
57
|
+
import { getKimiApiKey, loginKimiCode, refreshKimiCodeToken } from "./src/oauth.ts";
|
|
51
58
|
import { isKimiProjectConfigApproved } from "./src/project-trust.ts";
|
|
52
59
|
import {
|
|
53
60
|
type KimiConfigScope,
|
|
@@ -57,13 +64,14 @@ import {
|
|
|
57
64
|
parseByteSizeInput,
|
|
58
65
|
} from "./src/settings-ui.ts";
|
|
59
66
|
import { setStoreResolvedKimiConfig, streamSimpleKimi } from "./src/stream.ts";
|
|
60
|
-
import {
|
|
67
|
+
import { fetchKimiUsageSnapshot, getKimiUsageToken } from "./src/usage.ts";
|
|
61
68
|
import { buildMoonshotFetchTool, buildMoonshotSearchTool } from "./src/tools/moonshot.ts";
|
|
62
69
|
import { buildKimiDatasourceTool } from "./src/tools/datasource.ts";
|
|
63
70
|
interface KimiRuntimeState {
|
|
64
71
|
cwd: string;
|
|
65
72
|
config: KimiCodeConfig;
|
|
66
73
|
modelExtras: KimiOAuthExtras;
|
|
74
|
+
membershipLevel: string | null;
|
|
67
75
|
projectTrusted: boolean;
|
|
68
76
|
overrides?: KimiCodeConfigPatch;
|
|
69
77
|
}
|
|
@@ -114,7 +122,10 @@ function reloadEffectiveKimiRuntimeConfig(
|
|
|
114
122
|
state.config = config;
|
|
115
123
|
state.projectTrusted = projectTrusted;
|
|
116
124
|
setStoreResolvedKimiConfig({
|
|
117
|
-
model: resolveKimiModelConfig(
|
|
125
|
+
model: resolveKimiModelConfig(
|
|
126
|
+
config.model,
|
|
127
|
+
getKimiModelMetadata(state.modelExtras, KIMI_CODING_MODEL_ID),
|
|
128
|
+
),
|
|
118
129
|
protocol: config.protocol,
|
|
119
130
|
uploads: config.uploads,
|
|
120
131
|
});
|
|
@@ -132,13 +143,13 @@ function applyEffectiveKimiRuntimeConfig(
|
|
|
132
143
|
return config;
|
|
133
144
|
}
|
|
134
145
|
|
|
135
|
-
async function refreshModelExtras(state: KimiRuntimeState): Promise<
|
|
146
|
+
async function refreshModelExtras(state: KimiRuntimeState): Promise<boolean> {
|
|
136
147
|
const token = getKimiUsageToken();
|
|
137
|
-
if (!token) return;
|
|
148
|
+
if (!token) return false;
|
|
138
149
|
const extras = await discoverKimiModelMetadata(token, state.config.protocol);
|
|
139
|
-
if (Object.keys(extras).length
|
|
140
|
-
|
|
141
|
-
|
|
150
|
+
if (Object.keys(extras).length === 0) return false;
|
|
151
|
+
Object.assign(state.modelExtras, extras);
|
|
152
|
+
return true;
|
|
142
153
|
}
|
|
143
154
|
|
|
144
155
|
async function openSettingsMenu(
|
|
@@ -146,7 +157,21 @@ async function openSettingsMenu(
|
|
|
146
157
|
ctx: ExtensionCommandContext,
|
|
147
158
|
state: KimiRuntimeState,
|
|
148
159
|
): Promise<void> {
|
|
149
|
-
const
|
|
160
|
+
const modelDiscoveryToken = getKimiUsageToken();
|
|
161
|
+
const [usageSnapshot, initialModelsRefreshed] = await Promise.all([
|
|
162
|
+
fetchKimiUsageSnapshot(),
|
|
163
|
+
refreshModelExtras(state),
|
|
164
|
+
]);
|
|
165
|
+
let modelsRefreshed = initialModelsRefreshed;
|
|
166
|
+
const refreshedToken = getKimiUsageToken();
|
|
167
|
+
if (!modelsRefreshed && refreshedToken && refreshedToken !== modelDiscoveryToken) {
|
|
168
|
+
modelsRefreshed = await refreshModelExtras(state);
|
|
169
|
+
}
|
|
170
|
+
const refreshedMembershipLevel = usageSnapshot.membershipLevel ?? state.membershipLevel;
|
|
171
|
+
const membershipChanged = state.membershipLevel !== refreshedMembershipLevel;
|
|
172
|
+
state.membershipLevel = refreshedMembershipLevel;
|
|
173
|
+
if (modelsRefreshed || membershipChanged) registerKimiProvider(pi, state);
|
|
174
|
+
const usage = usageSnapshot.summary;
|
|
150
175
|
|
|
151
176
|
const projectTrusted = await isKimiProjectConfigApproved(ctx, ctx.cwd);
|
|
152
177
|
const homeDraft = loadHomeKimiCodeConfig(os.homedir());
|
|
@@ -354,10 +379,43 @@ function saveScopeKimiCodeConfig(
|
|
|
354
379
|
}
|
|
355
380
|
}
|
|
356
381
|
|
|
382
|
+
function filterAvailableKimiModels<T extends { id: string }>(
|
|
383
|
+
models: T[],
|
|
384
|
+
extras: KimiOAuthExtras,
|
|
385
|
+
membershipLevel: string | null,
|
|
386
|
+
): T[] {
|
|
387
|
+
const available =
|
|
388
|
+
extras.modelCatalogVersion === KIMI_MODEL_CATALOG_VERSION && extras.modelCatalog
|
|
389
|
+
? new Set(Object.keys(extras.modelCatalog))
|
|
390
|
+
: null;
|
|
391
|
+
return models.filter(
|
|
392
|
+
(model) =>
|
|
393
|
+
(!available || available.has(model.id)) &&
|
|
394
|
+
isKimiModelAvailableForMembership(model.id, membershipLevel) !== false,
|
|
395
|
+
);
|
|
396
|
+
}
|
|
397
|
+
|
|
357
398
|
function registerKimiProvider(pi: ExtensionAPI, state: KimiRuntimeState): void {
|
|
358
|
-
const
|
|
359
|
-
|
|
360
|
-
|
|
399
|
+
const standardModel = applyKimiMembershipLimitsToModel(
|
|
400
|
+
applyKimiOAuthExtrasToModel(
|
|
401
|
+
buildKimiModelFromConfig(state.config.model),
|
|
402
|
+
getKimiModelMetadata(state.modelExtras, KIMI_CODING_MODEL_ID),
|
|
403
|
+
),
|
|
404
|
+
state.membershipLevel,
|
|
405
|
+
);
|
|
406
|
+
const highSpeedModel = applyKimiMembershipLimitsToModel(
|
|
407
|
+
applyKimiOAuthExtrasToModel(
|
|
408
|
+
buildKimiModelFromConfig(state.config.model, KIMI_CODING_HIGHSPEED_MODEL_ID),
|
|
409
|
+
getKimiModelMetadata(state.modelExtras, KIMI_CODING_HIGHSPEED_MODEL_ID),
|
|
410
|
+
),
|
|
411
|
+
state.membershipLevel,
|
|
412
|
+
);
|
|
413
|
+
const k3Model = applyKimiMembershipLimitsToModel(
|
|
414
|
+
applyKimiOAuthExtrasToModel(
|
|
415
|
+
buildKimiModelFromConfig(state.config.model, KIMI_K3_MODEL_ID),
|
|
416
|
+
getKimiModelMetadata(state.modelExtras, KIMI_K3_MODEL_ID),
|
|
417
|
+
),
|
|
418
|
+
state.membershipLevel,
|
|
361
419
|
);
|
|
362
420
|
|
|
363
421
|
pi.registerProvider(PROVIDER_ID, {
|
|
@@ -366,13 +424,35 @@ function registerKimiProvider(pi: ExtensionAPI, state: KimiRuntimeState): void {
|
|
|
366
424
|
api: getKimiApiType(state.config.protocol),
|
|
367
425
|
streamSimple: streamSimpleKimi,
|
|
368
426
|
|
|
369
|
-
models:
|
|
427
|
+
models: filterAvailableKimiModels(
|
|
428
|
+
[standardModel, highSpeedModel, k3Model],
|
|
429
|
+
state.modelExtras,
|
|
430
|
+
state.membershipLevel,
|
|
431
|
+
),
|
|
370
432
|
|
|
371
433
|
oauth: {
|
|
372
434
|
name: "Kimi Code (OAuth)",
|
|
373
|
-
login:
|
|
374
|
-
|
|
375
|
-
|
|
435
|
+
login: async (callbacks) => {
|
|
436
|
+
const credentials = await loginKimiCode(callbacks);
|
|
437
|
+
const usage = await fetchKimiUsageSnapshot({
|
|
438
|
+
timeoutMs: 2500,
|
|
439
|
+
token: credentials.access,
|
|
440
|
+
refreshOnUnauthorized: false,
|
|
441
|
+
});
|
|
442
|
+
state.membershipLevel = usage.membershipLevel;
|
|
443
|
+
return credentials;
|
|
444
|
+
},
|
|
445
|
+
refreshToken: async (credentials) => {
|
|
446
|
+
const refreshed = await refreshKimiCodeToken(credentials);
|
|
447
|
+
const usage = await fetchKimiUsageSnapshot({
|
|
448
|
+
timeoutMs: 2500,
|
|
449
|
+
token: refreshed.access,
|
|
450
|
+
refreshOnUnauthorized: false,
|
|
451
|
+
});
|
|
452
|
+
state.membershipLevel = usage.membershipLevel;
|
|
453
|
+
return refreshed;
|
|
454
|
+
},
|
|
455
|
+
getApiKey: getKimiApiKey,
|
|
376
456
|
// Reflect server-side model identity on the registered model after login
|
|
377
457
|
// / refresh. We never rewrite the model id (pi-side `/model` selections
|
|
378
458
|
// and persisted sessions reference it); only the human-facing name, the
|
|
@@ -382,10 +462,25 @@ function registerKimiProvider(pi: ExtensionAPI, state: KimiRuntimeState): void {
|
|
|
382
462
|
const extras = cred as KimiOAuthCredentials;
|
|
383
463
|
state.modelExtras = extras;
|
|
384
464
|
reloadEffectiveKimiRuntimeConfig(state, state.cwd, state.projectTrusted);
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
465
|
+
const available =
|
|
466
|
+
extras.modelCatalogVersion === KIMI_MODEL_CATALOG_VERSION && extras.modelCatalog
|
|
467
|
+
? new Set(Object.keys(extras.modelCatalog))
|
|
468
|
+
: null;
|
|
469
|
+
return models
|
|
470
|
+
.filter(
|
|
471
|
+
(model) =>
|
|
472
|
+
model.provider !== PROVIDER_ID ||
|
|
473
|
+
((!available || available.has(model.id)) &&
|
|
474
|
+
isKimiModelAvailableForMembership(model.id, state.membershipLevel) !== false),
|
|
475
|
+
)
|
|
476
|
+
.map((model) =>
|
|
477
|
+
model.provider === PROVIDER_ID
|
|
478
|
+
? applyKimiMembershipLimitsToModel(
|
|
479
|
+
applyKimiOAuthExtrasToModel(model, getKimiModelMetadata(extras, model.id)),
|
|
480
|
+
state.membershipLevel,
|
|
481
|
+
)
|
|
482
|
+
: model,
|
|
483
|
+
);
|
|
389
484
|
},
|
|
390
485
|
},
|
|
391
486
|
});
|
|
@@ -399,13 +494,24 @@ export function KimiCode(overrides?: KimiCodeConfigPatch): ExtensionFactory {
|
|
|
399
494
|
overrides,
|
|
400
495
|
);
|
|
401
496
|
const discoveryToken = getKimiUsageToken();
|
|
402
|
-
const
|
|
403
|
-
?
|
|
404
|
-
:
|
|
497
|
+
const [initialDiscovery, usageSnapshot] = await Promise.all([
|
|
498
|
+
discoveryToken ? discoverKimiModelMetadata(discoveryToken, config.protocol) : {},
|
|
499
|
+
fetchKimiUsageSnapshot({ timeoutMs: 2500 }),
|
|
500
|
+
]);
|
|
501
|
+
let discovered = initialDiscovery;
|
|
502
|
+
const refreshedToken = getKimiUsageToken();
|
|
503
|
+
if (
|
|
504
|
+
Object.keys(discovered).length === 0 &&
|
|
505
|
+
refreshedToken &&
|
|
506
|
+
refreshedToken !== discoveryToken
|
|
507
|
+
) {
|
|
508
|
+
discovered = await discoverKimiModelMetadata(refreshedToken, config.protocol);
|
|
509
|
+
}
|
|
405
510
|
const state: KimiRuntimeState = {
|
|
406
511
|
cwd,
|
|
407
512
|
config,
|
|
408
513
|
modelExtras: discovered,
|
|
514
|
+
membershipLevel: usageSnapshot.membershipLevel,
|
|
409
515
|
projectTrusted: false,
|
|
410
516
|
overrides,
|
|
411
517
|
};
|
package/package.json
CHANGED
package/src/config.ts
CHANGED
|
@@ -38,6 +38,8 @@ export interface ModelConfig {
|
|
|
38
38
|
|
|
39
39
|
export interface KimiResolvedModelConfig extends ModelConfig {
|
|
40
40
|
supportsThinkingType?: "only" | "no" | "both";
|
|
41
|
+
supportEfforts?: string[];
|
|
42
|
+
defaultEffort?: string;
|
|
41
43
|
}
|
|
42
44
|
|
|
43
45
|
export interface KimiCodeConfig {
|
|
@@ -119,9 +121,10 @@ export const DEFAULT_KIMI_CODE_CONFIG: KimiCodeConfig = {
|
|
|
119
121
|
off: { effort: null, enabled: false },
|
|
120
122
|
minimal: { effort: "low", enabled: true },
|
|
121
123
|
low: { effort: "low", enabled: true },
|
|
122
|
-
medium: { effort: "
|
|
124
|
+
medium: { effort: "high", enabled: true },
|
|
123
125
|
high: { effort: "high", enabled: true },
|
|
124
|
-
xhigh: { effort: "
|
|
126
|
+
xhigh: { effort: "max", enabled: true },
|
|
127
|
+
max: { effort: "max", enabled: true },
|
|
125
128
|
},
|
|
126
129
|
thinkingKeep: "all",
|
|
127
130
|
generation: {},
|
package/src/constants.ts
CHANGED
|
@@ -41,12 +41,12 @@ export function getDefaultBaseUrl(protocol: KimiWireProtocol): string {
|
|
|
41
41
|
|
|
42
42
|
export const DEFAULT_BASE_URL = getDefaultBaseUrl(ENV_KIMI_CODE_PROTOCOL);
|
|
43
43
|
|
|
44
|
-
export const PROVIDER_VERSION = "0.6.
|
|
44
|
+
export const PROVIDER_VERSION = "0.6.6";
|
|
45
45
|
|
|
46
46
|
// Upstream kimi-code CLI version — used in User-Agent and X-Msh-Version
|
|
47
47
|
// headers to match the official client's identity. Update this when
|
|
48
|
-
// syncing with https://github.com/
|
|
49
|
-
export const KIMI_UPSTREAM_VERSION = "0.
|
|
48
|
+
// syncing with https://github.com/MoonshotAI/kimi-code.
|
|
49
|
+
export const KIMI_UPSTREAM_VERSION = "0.26.0";
|
|
50
50
|
export const KIMI_CODE_USER_AGENT = `kimi-code-cli/${KIMI_UPSTREAM_VERSION}`;
|
|
51
51
|
export const KIMI_PLATFORM = "kimi_code_cli";
|
|
52
52
|
|
package/src/device.ts
CHANGED
|
@@ -152,6 +152,22 @@ function getStableDeviceId(): string {
|
|
|
152
152
|
return DEVICE_ID;
|
|
153
153
|
}
|
|
154
154
|
|
|
155
|
+
export function parseKimiCodeCustomHeaders(
|
|
156
|
+
env: NodeJS.ProcessEnv = process.env,
|
|
157
|
+
): Record<string, string> {
|
|
158
|
+
const raw = env.KIMI_CODE_CUSTOM_HEADERS?.trim();
|
|
159
|
+
if (!raw) return {};
|
|
160
|
+
const headers: Record<string, string> = {};
|
|
161
|
+
for (const line of raw.split("\n")) {
|
|
162
|
+
const colon = line.indexOf(":");
|
|
163
|
+
if (colon < 0) continue;
|
|
164
|
+
const name = line.slice(0, colon).trim();
|
|
165
|
+
if (!/^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/.test(name)) continue;
|
|
166
|
+
headers[name] = asciiHeaderValue(line.slice(colon + 1));
|
|
167
|
+
}
|
|
168
|
+
return headers;
|
|
169
|
+
}
|
|
170
|
+
|
|
155
171
|
export function getCommonHeaders(): Record<string, string> {
|
|
156
172
|
const headers = {
|
|
157
173
|
"User-Agent": KIMI_CODE_USER_AGENT,
|
|
@@ -166,3 +182,28 @@ export function getCommonHeaders(): Record<string, string> {
|
|
|
166
182
|
Object.entries(headers).map(([key, value]) => [key, asciiHeaderValue(value)]),
|
|
167
183
|
) as Record<string, string>;
|
|
168
184
|
}
|
|
185
|
+
|
|
186
|
+
const RESERVED_PROVIDER_HEADERS = new Set([
|
|
187
|
+
"accept",
|
|
188
|
+
"anthropic-version",
|
|
189
|
+
"authorization",
|
|
190
|
+
"content-type",
|
|
191
|
+
"user-agent",
|
|
192
|
+
"x-api-key",
|
|
193
|
+
]);
|
|
194
|
+
|
|
195
|
+
function isReservedProviderHeader(name: string): boolean {
|
|
196
|
+
const normalized = name.toLowerCase();
|
|
197
|
+
return RESERVED_PROVIDER_HEADERS.has(normalized) || normalized.startsWith("x-msh-");
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
export function getKimiProviderHeaders(
|
|
201
|
+
env: NodeJS.ProcessEnv = process.env,
|
|
202
|
+
): Record<string, string> {
|
|
203
|
+
const customHeaders = Object.fromEntries(
|
|
204
|
+
Object.entries(parseKimiCodeCustomHeaders(env)).filter(
|
|
205
|
+
([name]) => !isReservedProviderHeader(name),
|
|
206
|
+
),
|
|
207
|
+
);
|
|
208
|
+
return { ...customHeaders, ...getCommonHeaders() };
|
|
209
|
+
}
|