Skip to content

feat: define model via KIMI_MODEL_* environment variables - #212

Merged
RealKai42 merged 5 commits into
mainfrom
kaiyi/osaka
May 29, 2026
Merged

feat: define model via KIMI_MODEL_* environment variables#212
RealKai42 merged 5 commits into
mainfrom
kaiyi/osaka

Conversation

@RealKai42

Copy link
Copy Markdown
Collaborator

Summary

  • 新增 KIMI_MODEL_* 环境变量通道:设置 KIMI_MODEL_NAME 即在内存中合成一个 provider(__kimi_env__)+ model alias(__kimi_env_model__)并设为默认模型,完全不修改 config.toml
  • 支持 provider type(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.tomldefault_model;-m <alias> 仍为单次启动最高优先级。
  • 同步更新 en/zh 文档,并修正"shell 环境变量不参与模型/凭据"的绝对化表述(标注 KIMI_MODEL_* 例外)。

Test Plan

  • env-model.ts 单测 18 例:触发开关、必填校验(API_KEY / MAX_CONTEXT_SIZE)、正整数解析、type 白名单、按 type 的 base_url 默认、capabilities 解析、thinking 逐字段合并、写回隔离
  • 写回防污染回归测试 + 独立 grep 追踪:writeConfigFile 仅源自 raw readConfigFile,合成模型无路径写回 config.toml
  • 全量 make typecheck / make lint 均 exit 0
  • 全量测试 5020 通过

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-bot

changeset-bot Bot commented May 29, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 3719ec0

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 3 packages
Name Type
@moonshot-ai/agent-core Minor
@moonshot-ai/kimi-code Minor
@moonshot-ai/migration-legacy Patch

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

@pkg-pr-new

pkg-pr-new Bot commented May 29, 2026

Copy link
Copy Markdown
pnpm dlx https://pkg.pr.new/@moonshot-ai/kimi-code@3719ec0
npx https://pkg.pr.new/@moonshot-ai/kimi-code@3719ec0

commit: 3719ec0

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 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);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge 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']);

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 Badge 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

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 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']);

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 Badge 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;

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 Badge 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.

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 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 } : {}),

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 Badge 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 } : {}),

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 Badge 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 👍 / 👎.

Comment on lines +158 to +159
...(thinking !== undefined ? { thinking } : {}),
...(defaultThinking !== undefined ? { defaultThinking } : {}),

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 Badge 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.

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 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".

Comment on lines +158 to +159
...(thinking !== undefined ? { thinking } : {}),
...(defaultThinking !== undefined ? { defaultThinking } : {}),

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 Badge 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 👍 / 👎.

@RealKai42
RealKai42 merged commit 2bbea75 into main May 29, 2026
6 checks passed
@RealKai42
RealKai42 deleted the kaiyi/osaka branch May 29, 2026 13:40

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 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),

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 Badge 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 👍 / 👎.

@github-actions github-actions Bot mentioned this pull request May 29, 2026
@RealKai42
RealKai42 restored the kaiyi/osaka branch May 29, 2026 13:44
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