feat: define model via KIMI_MODEL_* environment variables - #212
Conversation
Add a KIMI_MODEL_* environment-variable channel that synthesizes a provider (__kimi_env__) and model alias (__kimi_env_model__) in memory and selects it as the default model, without editing config.toml. Supports provider type (kimi/anthropic/openai), base URL, API key, context size, capabilities, anthropic max_output_size, openai reasoning_key, and full thinking settings. Runtime config reads go through a new loadRuntimeConfig wrapper; the config.toml write-back paths keep using readConfigFile so the synthesized model is never persisted back to disk.
🦋 Changeset detectedLatest commit: 3719ec0 The changes in this PR will be included in the next version bump. This PR includes changesets to release 3 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
commit: |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 57507ed18d
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| this.telemetry = options.telemetry ?? noopTelemetryClient; | ||
| ensureKimiHome(this.homeDir); | ||
| this.config = readConfigFile(this.configPath); | ||
| this.config = loadRuntimeConfig(this.configPath); |
There was a problem hiding this comment.
Keep env-only model entries out of persisted config
When KIMI_MODEL_NAME is set, storing the loadRuntimeConfig result in this.config makes getConfig() expose the synthetic __kimi_env__ provider and its apiKey. The existing /login and /connect flows read that config and pass config.providers / config.models back to setConfig (apps/kimi-code/src/tui/commands/auth.ts lines 164-178 and 266-282), after which setKimiConfig merges the patch into the raw file and writes it. In that scenario the supposedly in-memory env model, including the shell API key, is persisted to config.toml, so the public config returned here needs to strip runtime-only entries or the write path must reject them.
Useful? React with 👍 / 👎.
| ...(thinkingEffort !== undefined ? { effort: thinkingEffort } : {}), | ||
| } | ||
| : config.thinking; | ||
| const defaultThinking = parseBooleanEnv(env['KIMI_MODEL_DEFAULT_THINKING']); |
There was a problem hiding this comment.
Reject invalid default-thinking values
When KIMI_MODEL_DEFAULT_THINKING is set to a non-empty typo such as flase, parseBooleanEnv returns undefined, so the merge silently keeps any existing default_thinking from config.toml instead of reporting the bad env value. In a config that already has default_thinking = true, a user trying to disable Thinking for the env model would still start new sessions with Thinking enabled, unlike the other invalid KIMI_MODEL_* values that fail fast; please treat unrecognized non-empty values as config errors here.
Useful? React with 👍 / 👎.
- KIMI_MODEL_MAX_CONTEXT_SIZE defaults to 262144 (256K) when unset - KIMI_MODEL_CAPABILITIES defaults to image_in,thinking when unset - TUI welcome banner shows the model display name / id instead of the internal __kimi_env_model__ alias key
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c9a3b831b4
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| ...(thinkingEffort !== undefined ? { effort: thinkingEffort } : {}), | ||
| } | ||
| : config.thinking; | ||
| const defaultThinking = parseBooleanEnv(env['KIMI_MODEL_DEFAULT_THINKING']); |
There was a problem hiding this comment.
Default env-model thinking to off
When KIMI_MODEL_NAME is set but KIMI_MODEL_DEFAULT_THINKING is unset, this stays undefined, so the merged runtime config omits defaultThinking and new sessions fall through resolveThinkingLevel(undefined, {}) to high. On a clean env-only launch this contradicts the new env-var docs/table that say the default is Off, and because the synthesized alias also defaults to the thinking capability, requests may be sent with thinking enabled unless the user explicitly sets KIMI_MODEL_DEFAULT_THINKING=0.
Useful? React with 👍 / 👎.
| maxOutputRaw !== undefined | ||
| ? parsePositiveInt(maxOutputRaw, 'KIMI_MODEL_MAX_OUTPUT_SIZE') | ||
| : undefined; | ||
| const capabilities = parseCapabilities(env['KIMI_MODEL_CAPABILITIES']) ?? DEFAULT_CAPABILITIES; |
There was a problem hiding this comment.
Do not force Kimi capabilities onto non-Kimi env models
When KIMI_MODEL_PROVIDER_TYPE is openai or anthropic and KIMI_MODEL_CAPABILITIES is left unset, this still declares image_in and thinking instead of relying on the provider capability registry. For models such as gpt-3.5-turbo (detected in capability-registry.ts as text/tool only), the UI will allow image input and Thinking, and enabling either can send unsupported request fields/content to the provider; the Kimi defaults should only be applied for the default kimi provider or made provider-specific.
Useful? React with 👍 / 👎.
- Strip the synthesized __kimi_env__ provider / __kimi_env_model__ model (and a default_model pointing at it) in writeConfigFile, so the env model and its shell API key cannot be persisted via a getConfig -> setConfig patch round-trip (e.g. running /login or /connect in env-model mode). - Reject a non-empty but unparseable KIMI_MODEL_DEFAULT_THINKING value (fail-fast) instead of silently keeping config.toml's existing default.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 6eeef4f3ea
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| ...config, | ||
| providers, | ||
| ...(models !== undefined ? { models } : {}), | ||
| ...(defaultIsEnv ? { defaultModel: undefined } : {}), |
There was a problem hiding this comment.
Preserve default_model when stripping env aliases
When KIMI_MODEL_NAME is set and the runtime config is written back with defaultModel: '__kimi_env_model__' (for example via a getConfig()/setConfig() round trip or selecting the env model in /model), this branch turns the persisted defaultModel into undefined. Because writeConfigFile then serializes from the stripped config, any real default_model that was already in config.toml is deleted even though the env model is supposed to be in-memory only; please drop/reject the env default in the write patch without erasing the on-disk default.
Useful? React with 👍 / 👎.
| // for enum validation (auto/on/off). The cast avoids a TS compile error | ||
| // without skipping runtime validation. | ||
| ...(thinkingMode !== undefined ? { mode: thinkingMode as ThinkingConfig['mode'] } : {}), | ||
| ...(thinkingEffort !== undefined ? { effort: thinkingEffort } : {}), |
There was a problem hiding this comment.
Reject invalid env thinking efforts
When KIMI_MODEL_THINKING_EFFORT contains a typo such as meduim, this copies the raw string into config.thinking.effort and validateConfig only checks that it is a string. Later resolveThinkingEffort ignores unrecognized efforts and falls back to the default high, so a user trying to lower or otherwise set the env model's Thinking effort silently runs with the wrong effort instead of getting the same fail-fast behavior as the other invalid KIMI_MODEL_* values.
Useful? React with 👍 / 👎.
| ...(thinking !== undefined ? { thinking } : {}), | ||
| ...(defaultThinking !== undefined ? { defaultThinking } : {}), |
There was a problem hiding this comment.
Scope env thinking overrides to the env model
When KIMI_MODEL_NAME is set but the user launches with -m <existing-alias>, these KIMI_MODEL_* thinking values still overwrite the top-level runtime thinking / defaultThinking config. createSession resolves Thinking from this global config before applying the selected model, so an env-only override such as KIMI_MODEL_THINKING_MODE=off or KIMI_MODEL_DEFAULT_THINKING=0 also disables Thinking for the explicitly selected non-env model, even though the env channel is documented as synthesizing a separate model and -m wins for that launch.
Useful? React with 👍 / 👎.
…nking docs - stripEnvModelConfig restores config.toml's default_model from raw instead of erasing it when the runtime default points at the env alias, so a real default_model survives a getConfig -> setConfig round-trip. - Correct KIMI_MODEL_DEFAULT_THINKING docs: unset follows the global default (Thinking on), not Off.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 18a86297a2
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| ...(thinking !== undefined ? { thinking } : {}), | ||
| ...(defaultThinking !== undefined ? { defaultThinking } : {}), |
There was a problem hiding this comment.
Strip env thinking before config writes
When KIMI_MODEL_DEFAULT_THINKING or KIMI_MODEL_THINKING_* is set, these lines put the env-only thinking values into the top-level runtime config returned by getConfig(). A getConfig() → setConfig(config) round trip (the same write-back class guarded by stripEnvModelConfig) still deep-merges these fields into the raw readConfigFile() result, and stripEnvModelConfig only removes the synthetic provider/model/default alias, so the shell-only thinking override is serialized to config.toml. This violates the new “in memory only / nothing is written back” contract even after the provider/API-key guard.
Useful? React with 👍 / 👎.
…nfig; update tests for thinking behavior
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 3719ec031d
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| // values; an unset raw field restores to undefined (i.e. drops it). | ||
| ...(defaultIsEnv ? { defaultModel: rawDefaultModel(config) } : {}), | ||
| thinking: rawThinking(config), | ||
| defaultThinking: rawDefaultThinking(config), |
There was a problem hiding this comment.
Preserve explicit default-thinking writes
When KIMI_MODEL_NAME is set and the user runs /login or /connect, those handlers mutate the runtime config and then call setConfig with the newly selected defaultThinking value (apps/kimi-code/src/tui/commands/auth.ts lines 173-177 and 277-281). Because that patch also carries the env provider/model, stripEnvModelConfig runs and this line unconditionally replaces the just-selected value with config.raw's old default_thinking, so the login/connect flow can save the new provider/default model while silently losing the Thinking default the user chose. Restore the raw value only for env-derived writes, not for explicit config patches that also contain env entries.
Useful? React with 👍 / 👎.
Summary
KIMI_MODEL_*环境变量通道:设置KIMI_MODEL_NAME即在内存中合成一个 provider(__kimi_env__)+ model alias(__kimi_env_model__)并设为默认模型,完全不修改config.toml。kimi/anthropic/openai)、base URL、API key、max_context_size、capabilities、anthropic 的max_output_size、openai 的reasoning_key,以及完整 thinking(默认开关 / mode / effort)。loadRuntimeConfig;config.toml的写回路径保持裸readConfigFile,确保合成模型永不被写回磁盘。config.toml的default_model;-m <alias>仍为单次启动最高优先级。KIMI_MODEL_*例外)。Test Plan
env-model.ts单测 18 例:触发开关、必填校验(API_KEY / MAX_CONTEXT_SIZE)、正整数解析、type 白名单、按 type 的 base_url 默认、capabilities 解析、thinking 逐字段合并、写回隔离writeConfigFile仅源自 rawreadConfigFile,合成模型无路径写回config.tomlmake typecheck/make lint均 exit 0