fix(settings): 适配 kimi-code 近期变更 — [watch] 默认值修正为开启(上游 #4015 翻回默认开);新增顶层开关 auto_session_title(#3962)与 repeat_breaker(#3995,默认开、false 显式写入/true 删键);最大输出 Token 文案修正为「留空则不发送输出上限」(上游 #4091 未配置即省略 max_tokens)

This commit is contained in:
KimiSwitch Dev committed 2026-10-04 00:26:05 +08:00
1 parent 3c3c18925d
commit 977f433bb2
6 files changed
+124 -18

No files matched your search

+24 -6
View File
@@ -236,19 +236,37 @@ export function AgentSettingsPanel({ rawOther, onChange, models, defaultModel }:
</Card>
<Card title={t("watchSettings")}>
{/* Top-level `[watch] enabled` (kimi-code 2.0.1+; off by default since
2.0.2). KIMI_CODE_WATCH outranks this config at runtime — the env
var is probed by get_experimental_env_status as a non-flag entry
but deliberately locks nothing here, the toggle just documents the
config value that applies when the env var is unset. */}
{/* Top-level `[watch] enabled` (kimi-code 2.0.1+; 2.0.2 flipped the
default off, #4015 flipped it back on). KIMI_CODE_WATCH outranks
this config at runtime — the env var is probed by
get_experimental_env_status as a non-flag entry but deliberately
locks nothing here, the toggle just documents the config value
that applies when the env var is unset. */}
<Checkbox
label={t("watchEnabled")}
checked={settings.watch?.enabled ?? false}
checked={settings.watch?.enabled ?? true}
onChange={(checked) => updateWatch({ enabled: checked })}
/>
<p className="text-xs text-content-muted">{t("watchEnabledDesc")}</p>
</Card>
<Card title={t("behaviorSettings")}>
{/* Top-level booleans, both default true upstream: false is written
explicitly, true removes the key (see setAgentSettings). */}
<Checkbox
label={t("autoSessionTitle")}
checked={settings.auto_session_title ?? true}
onChange={(checked) => update({ auto_session_title: checked })}
/>
<p className="text-xs text-content-muted">{t("autoSessionTitleDesc")}</p>
<Checkbox
label={t("repeatBreaker")}
checked={settings.repeat_breaker ?? true}
onChange={(checked) => update({ repeat_breaker: checked })}
/>
<p className="text-xs text-content-muted">{t("repeatBreakerDesc")}</p>
</Card>
<Card title={t("permissionRules")}>
{/* kimi-code `[permission] dangerous_command_guard`. The env
var KIMI_CODE_DANGEROUS_COMMAND_GUARD (literal "true"/"false")
+9 -2
View File
@@ -112,7 +112,7 @@ export const enTranslations: Record<TranslationKey, string> = {
envPairs: "Env pairs",
addEnv: "+ Add",
modelMappingDesc: "Display name only affects the /model menu.",
maxOutputSizeDesc: "Max output tokens writes max_output_size — leave blank to use the upstream default.",
maxOutputSizeDesc: "Max output tokens writes max_output_size — leave blank to send no output cap upstream.",
oneClickSetup: "One-click setup",
fetchModels: "Fetch models",
fetchingModels: "Fetching...",
@@ -188,7 +188,14 @@ export const enTranslations: Record<TranslationKey, string> = {
watchSettings: "File Watching",
watchEnabled: "Enable file watching",
watchEnabledDesc:
"Watch config files and the workspace for changes (configurable since kimi-code 2.0.1, off by default since 2.0.2). The KIMI_CODE_WATCH environment variable overrides this setting.",
"Watch config files and the workspace for changes (configurable since kimi-code 2.0.1, on by default). The KIMI_CODE_WATCH environment variable overrides this setting.",
behaviorSettings: "Behavior",
autoSessionTitle: "Auto session title",
autoSessionTitleDesc:
"Let clients auto-generate session titles (on by default; turning it off writes false).",
repeatBreaker: "Repeat breaker",
repeatBreakerDesc:
"Remind and force-stop on consecutively repeated identical tool calls (on by default). The KIMI_CODE_REPEAT_BREAKER environment variable overrides this setting.",
permissionRules: "Permission Rules",
permissionDecision: "Decision",
permissionPattern: "Pattern",
+9 -2
View File
@@ -109,7 +109,7 @@ export const zhTranslations = {
envPairs: "Env 键值对",
addEnv: "+ 添加",
modelMappingDesc: "显示名称只影响 /model 菜单。",
maxOutputSizeDesc: "「最大输出 Token」写入 max_output_size,留空则用上游默认值。",
maxOutputSizeDesc: "「最大输出 Token」写入 max_output_size,留空则不发送输出上限。",
oneClickSetup: "一键设置",
fetchModels: "获取模型列表",
fetchingModels: "获取中...",
@@ -181,7 +181,14 @@ export const zhTranslations = {
watchSettings: "文件监听",
watchEnabled: "启用文件监听",
watchEnabledDesc:
"监听配置文件与工作目录变化(kimi-code 2.0.1 起可配置,2.0.2 起默认关闭)。环境变量 KIMI_CODE_WATCH 会覆盖本配置。",
"监听配置文件与工作目录变化(kimi-code 2.0.1 起可配置,默认开启)。环境变量 KIMI_CODE_WATCH 会覆盖本配置。",
behaviorSettings: "行为开关",
autoSessionTitle: "自动生成会话标题",
autoSessionTitleDesc:
"允许客户端自动生成会话标题(默认开启;关闭后写入 false)。",
repeatBreaker: "重复调用拦截",
repeatBreakerDesc:
"连续重复相同工具调用时提醒并强制停止(默认开启)。环境变量 KIMI_CODE_REPEAT_BREAKER 会覆盖本配置。",
permissionRules: "权限规则",
permissionDecision: "处置",
permissionPattern: "模式",
+48 -5
View File
@@ -201,8 +201,8 @@ describe("loop_control.compaction_max_attempts", () => {
});
// ---------------------------------------------------------------------------
// [watch] enabled (kimi-code 2.0.1+) — top-level section, off by default since
// 2.0.2; mirrors the [background] handling
// [watch] enabled (kimi-code 2.0.1+) — top-level section; 2.0.2 flipped the
// default off, #4015 flipped it back on. Mirrors the [background] handling.
// ---------------------------------------------------------------------------
function watchOf(raw: unknown): Record<string, unknown> {
@@ -213,9 +213,9 @@ function watchOf(raw: unknown): Record<string, unknown> {
}
describe("[watch] enabled", () => {
it("reads as false when the section or key is absent (2.0.2 default)", () => {
expect(getAgentSettings({}).watch?.enabled).toBe(false);
expect(getAgentSettings({ watch: {} }).watch?.enabled).toBe(false);
it("reads as true when the section or key is absent (#4015 default)", () => {
expect(getAgentSettings({}).watch?.enabled).toBe(true);
expect(getAgentSettings({ watch: {} }).watch?.enabled).toBe(true);
});
it("reads an explicit value", () => {
@@ -248,6 +248,49 @@ describe("[watch] enabled", () => {
});
});
// ---------------------------------------------------------------------------
// Top-level booleans (auto_session_title #3962 / repeat_breaker #3995):
// upstream default true — false is written explicitly, true removes the key.
// ---------------------------------------------------------------------------
describe("top-level boolean switches", () => {
it("reads as undefined when the key is absent (default true)", () => {
const s = getAgentSettings({});
expect(s.auto_session_title).toBeUndefined();
expect(s.repeat_breaker).toBeUndefined();
});
it("reads explicit false values", () => {
const s = getAgentSettings({
auto_session_title: false,
repeat_breaker: false,
});
expect(s.auto_session_title).toBe(false);
expect(s.repeat_breaker).toBe(false);
});
it("writes false explicitly and removes the key on true", () => {
const off = setAgentSettings({}, { repeat_breaker: false }) as Record<
string,
unknown
>;
expect(off.repeat_breaker).toBe(false);
const on = setAgentSettings(
{ repeat_breaker: false },
{ repeat_breaker: true }
) as Record<string, unknown>;
expect("repeat_breaker" in on).toBe(false);
});
it("keeps an explicit false on saves that do not touch it", () => {
const next = setAgentSettings(
{ auto_session_title: false },
{ thinking: { effort: "high" } }
) as Record<string, unknown>;
expect(next.auto_session_title).toBe(false);
});
});
describe("permission.dangerous_command_guard", () => {
it("reads as undefined when the key is absent (default on)", () => {
+27 -3
View File
@@ -13,10 +13,11 @@ const DEFAULT_SETTINGS: AgentSettings = {
background: {
keep_alive_on_exit: false,
},
// `[watch] enabled` — kimi-code 2.0.1 added the key, 2.0.2 flipped the
// default to off, so an absent key reads as "off".
// `[watch] enabled` — kimi-code 2.0.1 added the key; 2.0.2 flipped the
// default to off, then #4015 flipped it back on, so an absent key reads
// as "on".
watch: {
enabled: false,
enabled: true,
},
permission: { rules: [] },
hooks: [],
@@ -37,6 +38,7 @@ function getSection<T>(rawOther: unknown, key: string): T | undefined {
}
export function getAgentSettings(rawOther: unknown): AgentSettings {
const root = asRecord(rawOther);
const sectionLoop = getSection<AgentSettings["loop_control"]>(
rawOther,
"loop_control"
@@ -92,6 +94,16 @@ export function getAgentSettings(rawOther: unknown): AgentSettings {
: {}),
},
hooks: getSection<AgentSettings["hooks"]>(rawOther, "hooks") ?? [],
// Top-level booleans (upstream default true): keep only explicit values,
// an absent key means "on" — the UI shows `?? true`.
auto_session_title:
typeof root.auto_session_title === "boolean"
? root.auto_session_title
: undefined,
repeat_breaker:
typeof root.repeat_breaker === "boolean"
? root.repeat_breaker
: undefined,
};
}
@@ -166,5 +178,17 @@ export function setAgentSettings(
delete root.hooks;
}
// Top-level booleans with an upstream default of true: an explicit false
// is written; true/undefined removes the key so the config tracks the
// upstream default instead of pinning it.
for (const key of ["auto_session_title", "repeat_breaker"] as const) {
const value = patch[key] ?? current[key];
if (value === false) {
root[key] = false;
} else {
delete root[key];
}
}
return root;
}
+7
View File
@@ -172,6 +172,13 @@ export interface AgentSettings {
background?: BackgroundConfig;
/** Top-level `[watch]` section (kimi-code 2.0.1+). */
watch?: WatchConfig;
/** Top-level config.toml key (kimi-code #3962): let clients auto-generate
* session titles. Default true; only an explicit false disables. */
auto_session_title?: boolean;
/** Top-level config.toml key (kimi-code #3995): repeat-breaker for
* consecutively repeated identical tool calls. Default true; env
* KIMI_CODE_REPEAT_BREAKER outranks this config. */
repeat_breaker?: boolean;
permission?: {
rules?: PermissionRule[];
/** kimi-code `[permission]` key. Default true when the key is