diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 487ccd6..d0d6137 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -1978,7 +1978,7 @@ dependencies = [ [[package]] name = "kimiswitch" -version = "0.7.14" +version = "0.7.15" dependencies = [ "anyhow", "chrono", diff --git a/src-tauri/src/commands.rs b/src-tauri/src/commands.rs index b66c434..f99c0b7 100644 --- a/src-tauri/src/commands.rs +++ b/src-tauri/src/commands.rs @@ -1335,7 +1335,7 @@ pub async fn kimi_oauth_poll( } // --------------------------------------------------------------------------- -// Experimental feature env-var probe (Kimi Code secondary model etc.) +// Experimental feature env-var probe (Kimi Code experimental flags) // --------------------------------------------------------------------------- /// Read the Kimi Code environment variables that are currently set (non-empty) @@ -1348,6 +1348,11 @@ pub async fn kimi_oauth_poll( /// are probed too — the latter lets AgentSettingsPanel decide whether to /// dual-write the v1 engine's loop_control keys. /// +/// As of Kimi Code 0.42.0 the upstream registry holds 6 experimental flags; +/// `secondary-model`, `persistence_minidb_readmodel`, `remote-control` and +/// `search_worker` have been promoted or removed upstream and are no longer +/// probed here. +/// /// The flag id → env var mapping mirrors `EXPERIMENTAL_FLAGS` in /// src/lib/subagent-settings.ts; keep both lists in sync. /// @@ -1355,19 +1360,13 @@ pub async fn kimi_oauth_poll( /// the raw values are returned and the truthy check happens on the frontend. #[tauri::command] pub fn get_experimental_env_status() -> HashMap { - const VARS: [(&str, &str); 11] = [ - ("secondary-model", "KIMI_CODE_EXPERIMENTAL_SECONDARY_MODEL"), + const VARS: [(&str, &str); 8] = [ ("tool-select", "KIMI_CODE_EXPERIMENTAL_TOOL_SELECT"), - ( - "persistence_minidb_readmodel", - "KIMI_CODE_EXPERIMENTAL_PERSISTENCE_MINIDB_READMODEL", - ), ("tower", "KIMI_CODE_EXPERIMENTAL_TOWER"), ("subagent_fork", "KIMI_CODE_EXPERIMENTAL_SUBAGENT_FORK"), ("wait_for", "KIMI_CODE_EXPERIMENTAL_WAIT_FOR"), ("auto_session_title", "KIMI_CODE_EXPERIMENTAL_AUTO_SESSION_TITLE"), - ("remote-control", "KIMI_CODE_EXPERIMENTAL_REMOTE_CONTROL"), - ("search_worker", "KIMI_CODE_EXPERIMENTAL_SEARCH_WORKER"), + ("notify_user", "KIMI_CODE_EXPERIMENTAL_NOTIFY_USER"), // Non-flag probes consumed by the frontend: ("master", "KIMI_CODE_EXPERIMENTAL_FLAG"), ("legacy", "KIMI_CODE_LEGACY_FLAG"), diff --git a/src/components/SubagentSettingsPage.tsx b/src/components/SubagentSettingsPage.tsx index 7457b6f..e388923 100644 --- a/src/components/SubagentSettingsPage.tsx +++ b/src/components/SubagentSettingsPage.tsx @@ -43,21 +43,15 @@ const EFFORT_LABELS: Record<(typeof EFFORTS)[number], TranslationKey> = { }; const FLAG_LABELS: Record = { - "secondary-model": { name: "flagSecondaryModel", desc: "flagSecondaryModelDesc" }, + wait_for: { name: "flagWaitFor", desc: "flagWaitForDesc" }, "tool-select": { name: "flagToolSelect", desc: "flagToolSelectDesc" }, - persistence_minidb_readmodel: { - name: "flagMinidbReadmodel", - desc: "flagMinidbReadmodelDesc", - }, + notify_user: { name: "flagNotifyUser", desc: "flagNotifyUserDesc" }, tower: { name: "flagTower", desc: "flagTowerDesc" }, subagent_fork: { name: "flagSubagentFork", desc: "flagSubagentForkDesc" }, - wait_for: { name: "flagWaitFor", desc: "flagWaitForDesc" }, auto_session_title: { name: "flagAutoSessionTitle", desc: "flagAutoSessionTitleDesc", }, - "remote-control": { name: "flagRemoteControl", desc: "flagRemoteControlDesc" }, - search_worker: { name: "flagSearchWorker", desc: "flagSearchWorkerDesc" }, }; /** Validation-error i18n key per engine rule, for the pre-write self-check. */ @@ -185,21 +179,6 @@ export function SubagentSettingsPage({ // off — upgrading with force would create an invalid force+pool-table combo. const canUpgrade = !!pool && !isPoolView && pool.model !== undefined && !pool.force; const masterOn = isMasterEnvOn(env); - const secondaryFlag = EXPERIMENTAL_FLAGS[0]; // "secondary-model" - const otherFlags = EXPERIMENTAL_FLAGS.slice(1); - - /** Effective state of the secondary-model flag. Mirrors the kimi-code - * 0.40.1 priority: single-flag env > explicit [experimental] value > - * master env (force-on only) > upstream default. The master env no - * longer locks the toggle — only the flag's own env var does. */ - const secondaryEnabled = isFlagLockedByEnv(env, secondaryFlag) - ? forcedEnvValue(env, secondaryFlag) - : isExperimentalFlagSet(rawOther, secondaryFlag.id) - ? flags["secondary-model"] === true - : masterOn - ? true - : (secondaryFlag.defaultEnabled ?? false); - const secondaryLocked = isFlagLockedByEnv(env, secondaryFlag); const aliasList = Object.keys(models).sort(); @@ -573,41 +552,6 @@ export function SubagentSettingsPage({ )}
-
-
-
- {t(FLAG_LABELS[secondaryFlag.id].name)} - {!secondaryLocked && - !isExperimentalFlagSet(rawOther, secondaryFlag.id) && - secondaryFlag.defaultEnabled && ( - - {t("flagDefaultOn")} - - )} -
-
- {t(FLAG_LABELS[secondaryFlag.id].desc)} - {secondaryFlag.envVar} -
-
- {secondaryLocked && ( - - 🔒 {t("lockedByEnv")} - - )} - - onChange( - setExperimentalFlag(rawOther, secondaryFlag.id, checked, { - explicitFalse: masterOn || secondaryFlag.defaultEnabled === true, - }) - ) - } - /> -
{effectiveDefault !== undefined && (
@@ -636,9 +580,9 @@ export function SubagentSettingsPage({

{t("secondaryModelPriorityHint")}

- {/* Other experimental features (not subagent-related) */} - - {otherFlags.map(renderFlagRow)} + {/* Experimental feature flags — one unified list */} + + {EXPERIMENTAL_FLAGS.map(renderFlagRow)}

{t("experimentalFlagsHint")}

diff --git a/src/i18n/en.ts b/src/i18n/en.ts index a176791..2f4acf4 100644 --- a/src/i18n/en.ts +++ b/src/i18n/en.ts @@ -463,15 +463,10 @@ export const enTranslations: Record = { // Advanced settings page (WebUI quick open + experimental flags + secondary model) subagentSettings: "Advanced Settings", experimentalFlags: "Experimental Features", - otherExperimentalFlags: "Other Experimental Features", experimentalFlagsHint: "Toggles are written to the [experimental] section of config.toml; env vars take precedence and locked toggles cannot be changed here", - flagSecondaryModel: "Subagent Secondary Model", - flagSecondaryModelDesc: "Newly spawned subagents bind a second (usually cheaper) model config", flagToolSelect: "Tool Select", flagToolSelectDesc: "Enable the experimental tool selection feature", - flagMinidbReadmodel: "MiniDB Read Model", - flagMinidbReadmodelDesc: "Enable the v2 engine MiniDB read-model backend", flagTower: "Tower Mode", flagTowerDesc: "Enable tower mode: coordinate multiple agents on a shared objective (/tower command)", flagSubagentFork: "Subagent Fork Context", @@ -480,17 +475,13 @@ export const enTranslations: Record = { flagWaitForDesc: "The agent can wait for background tasks to finish within the current turn", flagAutoSessionTitle: "Auto Session Title", flagAutoSessionTitleDesc: "Generate session titles automatically via the managed chat_title tool", - flagRemoteControl: "Remote Control", - flagRemoteControlDesc: "Enable the experimental remote control feature", - flagSearchWorker: "Search Worker", - flagSearchWorkerDesc: "Run the kap-server global search backend in a background worker host", + flagNotifyUser: "NotifyUser tool", + flagNotifyUserDesc: "Experimental Updates panel: paginated progress messages from the main agent and subagents (off by default)", flagDefaultOn: "On by default", lockedByEnv: "Locked by env var", masterEnvOnHint: "KIMI_CODE_EXPERIMENTAL_FLAG is set: flags without an explicit [experimental] entry are forced on; explicit entries in config.toml still win", secondaryModelSection: "Subagent Model (Secondary Model)", - secondaryModelDisabledHint: - "The experimental flag \"Subagent Secondary Model\" is off and this config will not take effect — enable the toggle above first", secondaryModelLabel: "Secondary model", secondaryModelUnset: "Not configured", secondaryModelInheritedContext: "Inherited context", diff --git a/src/i18n/zh.ts b/src/i18n/zh.ts index b883aeb..1595f9e 100644 --- a/src/i18n/zh.ts +++ b/src/i18n/zh.ts @@ -458,15 +458,10 @@ export const zhTranslations = { // Advanced settings page (WebUI quick open + experimental flags + secondary model) subagentSettings: "高级设置", experimentalFlags: "实验功能开关", - otherExperimentalFlags: "其他实验功能", experimentalFlagsHint: "开关写入 config.toml 的 [experimental] 节;环境变量优先级更高,被锁定的开关无法在此修改", - flagSecondaryModel: "子代理次主力模型", - flagSecondaryModelDesc: "子代理派发时绑定第二份(通常更便宜的)模型配置", flagToolSelect: "工具选择", flagToolSelectDesc: "启用实验性工具选择功能", - flagMinidbReadmodel: "MiniDB 读模型", - flagMinidbReadmodelDesc: "启用 v2 引擎 MiniDB 读模型后端", flagTower: "Tower 模式", flagTowerDesc: "启用 Tower 多智能体协同模式(/tower 命令切换)", flagSubagentFork: "子代理 Fork 上下文", @@ -475,17 +470,13 @@ export const zhTranslations = { flagWaitForDesc: "代理可在当前回合内等待后台任务完成,而无需结束回合再被唤醒", flagAutoSessionTitle: "自动会话标题", flagAutoSessionTitleDesc: "通过托管 chat_title 工具自动生成会话标题", - flagRemoteControl: "远程控制", - flagRemoteControlDesc: "启用实验性远程控制功能", - flagSearchWorker: "搜索 Worker", - flagSearchWorkerDesc: "kap-server 全局搜索的后台 worker 宿主服务", + flagNotifyUser: "NotifyUser 工具", + flagNotifyUserDesc: "实验性 Updates 面板:分页展示主代理与子代理的进度消息(默认关闭)", flagDefaultOn: "默认开启", lockedByEnv: "被环境变量锁定", masterEnvOnHint: "KIMI_CODE_EXPERIMENTAL_FLAG 已设置:未显式配置的实验项将被强制开启;config.toml 中的显式配置优先生效", secondaryModelSection: "子代理模型(次主力模型)", - secondaryModelDisabledHint: - "实验开关「子代理次主力模型」未启用,本配置不会生效——请先在上方打开对应开关", secondaryModelLabel: "次主力模型", secondaryModelUnset: "未配置", secondaryModelInheritedContext: "继承上下文长度", diff --git a/src/lib/subagent-settings.test.ts b/src/lib/subagent-settings.test.ts index 1c09ef8..74d5ed7 100644 --- a/src/lib/subagent-settings.test.ts +++ b/src/lib/subagent-settings.test.ts @@ -1,10 +1,12 @@ import { describe, expect, it } from "vitest"; import { EXPERIMENTAL_FLAGS, + forcedEnvValue, getExperimentalFlags, getSecondaryModel, getSubagentModelPool, isExperimentalFlagSet, + isFlagLockedByEnv, removeSubagentPoolEntry, setExperimentalFlag, setSecondaryModelOnly, @@ -163,13 +165,13 @@ describe("setSecondaryModelOnly", () => { it("preserves other top-level raw_other sections", () => { const raw = { - experimental: { "secondary-model": true }, + experimental: { wait_for: true }, secondary_model: { model: "kimi-k1" }, }; const next = setSecondaryModelOnly(raw, "kimi-k2") as { experimental?: unknown; }; - expect(next.experimental).toEqual({ "secondary-model": true }); + expect(next.experimental).toEqual({ wait_for: true }); }); }); @@ -455,31 +457,49 @@ describe("validateSubagentPool", () => { }); // --------------------------------------------------------------------------- -// [experimental] — flag registry (kimi-code 0.41.0) + write semantics +// [experimental] — flag registry (kimi-code 0.42.0) + write semantics // --------------------------------------------------------------------------- describe("experimental flag registry", () => { - it("mirrors the 0.41.0 v2 registry (9 flags, file_history removed)", () => { + it("mirrors the 0.42.0 v2 registry (6 flags)", () => { expect(EXPERIMENTAL_FLAGS.map((f) => f.id)).toEqual([ - "secondary-model", + "wait_for", "tool-select", - "persistence_minidb_readmodel", + "notify_user", "tower", "subagent_fork", - "wait_for", "auto_session_title", + ]); + // Removed upstream: file_history (0.41.0, turn-level file history is + // always on) plus secondary-model / persistence_minidb_readmodel / + // remote-control / search_worker (0.42.0 — promoted or moved to + // dedicated config, the minidb read-model now lives under [database]), + // so the adapter must not mirror them either. + for (const id of [ + "file_history", + "secondary-model", + "persistence_minidb_readmodel", "remote-control", "search_worker", - ]); - // Upstream removed the flag in 0.41.0 (turn-level file history is - // always on), so the adapter must not mirror it either. - expect(EXPERIMENTAL_FLAGS.some((f) => f.id === "file_history")).toBe(false); + ]) { + expect(EXPERIMENTAL_FLAGS.some((f) => f.id === id)).toBe(false); + } }); - it("secondary-model is on by default since 0.40.1", () => { - expect( - EXPERIMENTAL_FLAGS.find((f) => f.id === "secondary-model")?.defaultEnabled - ).toBe(true); + it("notify_user is opt-in: no upstream default, own env var", () => { + const flag = EXPERIMENTAL_FLAGS.find((f) => f.id === "notify_user"); + expect(flag?.envVar).toBe("KIMI_CODE_EXPERIMENTAL_NOTIFY_USER"); + expect(flag?.defaultEnabled).toBeUndefined(); + }); + + it("notify_user is locked by its env var and forced to the env value", () => { + const flag = EXPERIMENTAL_FLAGS.find((f) => f.id === "notify_user")!; + expect(isFlagLockedByEnv({}, flag)).toBe(false); + // A set env var locks the toggle even when it is falsy — it can force + // the flag on *or* off. + expect(isFlagLockedByEnv({ [flag.envVar]: "0" }, flag)).toBe(true); + expect(forcedEnvValue({ [flag.envVar]: "0" }, flag)).toBe(false); + expect(forcedEnvValue({ [flag.envVar]: "true" }, flag)).toBe(true); }); }); @@ -514,13 +534,13 @@ describe("setExperimentalFlag", () => { it("an explicit false coexists with other flags and keeps the section", () => { const next = setExperimentalFlag( - rawExp({ "secondary-model": false }), + rawExp({ wait_for: false }), "tower", true, { explicitFalse: true } ) as { experimental: Record }; expect(next.experimental).toEqual({ - "secondary-model": false, + wait_for: false, tower: true, }); }); diff --git a/src/lib/subagent-settings.ts b/src/lib/subagent-settings.ts index d4be5e1..a7b305e 100644 --- a/src/lib/subagent-settings.ts +++ b/src/lib/subagent-settings.ts @@ -24,7 +24,7 @@ function isTruthyEnv(value: string | undefined): boolean { // --------------------------------------------------------------------------- export interface ExperimentalFlagDef { - /** Flag id as stored in config.toml `[experimental]` (e.g. "secondary-model"). */ + /** Flag id as stored in config.toml `[experimental]` (e.g. "wait_for"). */ id: string; /** Single-feature env var that can force the flag (locks the UI toggle). */ envVar: string; @@ -33,43 +33,30 @@ export interface ExperimentalFlagDef { defaultEnabled?: boolean; } -/** Known experimental flags — mirrors the kimi-code v2 flag registry - * (the per-feature flag.ts files under packages/agent-core-v2/src: - * secondary-model, tool-select, persistence_minidb_readmodel, tower, - * subagent_fork, wait_for, auto_session_title, remote-control, - * search_worker). `acp-v2` was removed upstream and is dropped here; - * `file_history` was removed in kimi-code 0.41.0 (turn-level file - * history is always on, no flag). Keep the env-var list in sync with - * `get_experimental_env_status` in src-tauri/src/commands.rs. */ +/** Known experimental flags — mirrors the kimi-code 0.42.0 v2 flag registry + * (the per-feature flag.ts files under packages/agent-core-v2/src): + * wait_for, tool-select, notify_user, tower, subagent_fork, + * auto_session_title. Removed in 0.42.0: secondary-model, remote-control + * and search_worker (promoted or dropped upstream — no flag left), and + * persistence_minidb_readmodel (now controlled by the `[database]` config + * section). `acp-v2` was removed upstream earlier; `file_history` was + * removed in kimi-code 0.41.0 (turn-level file history is always on, no + * flag). Keep the env-var list in sync with `get_experimental_env_status` + * in src-tauri/src/commands.rs. */ export const EXPERIMENTAL_FLAGS: ExperimentalFlagDef[] = [ - { - id: "secondary-model", - envVar: "KIMI_CODE_EXPERIMENTAL_SECONDARY_MODEL", - defaultEnabled: true, // on by default since kimi-code 0.40.1 - }, - { id: "tool-select", envVar: "KIMI_CODE_EXPERIMENTAL_TOOL_SELECT" }, - { - id: "persistence_minidb_readmodel", - envVar: "KIMI_CODE_EXPERIMENTAL_PERSISTENCE_MINIDB_READMODEL", - defaultEnabled: true, - }, - { id: "tower", envVar: "KIMI_CODE_EXPERIMENTAL_TOWER" }, - { id: "subagent_fork", envVar: "KIMI_CODE_EXPERIMENTAL_SUBAGENT_FORK" }, { id: "wait_for", envVar: "KIMI_CODE_EXPERIMENTAL_WAIT_FOR", defaultEnabled: true, }, + { id: "tool-select", envVar: "KIMI_CODE_EXPERIMENTAL_TOOL_SELECT" }, + { id: "notify_user", envVar: "KIMI_CODE_EXPERIMENTAL_NOTIFY_USER" }, + { id: "tower", envVar: "KIMI_CODE_EXPERIMENTAL_TOWER" }, + { id: "subagent_fork", envVar: "KIMI_CODE_EXPERIMENTAL_SUBAGENT_FORK" }, { id: "auto_session_title", envVar: "KIMI_CODE_EXPERIMENTAL_AUTO_SESSION_TITLE", }, - { id: "remote-control", envVar: "KIMI_CODE_EXPERIMENTAL_REMOTE_CONTROL" }, - { - id: "search_worker", - envVar: "KIMI_CODE_EXPERIMENTAL_SEARCH_WORKER", - defaultEnabled: true, - }, ]; export const EXPERIMENTAL_MASTER_ENV = "KIMI_CODE_EXPERIMENTAL_FLAG";