chore(agent-core): remove experimental micro compaction (#1317)

* chore(agent-core): remove experimental micro compaction

* fix(docs): drop micro compaction row from env-vars table
This commit is contained in:
Kai 2026-07-02 19:50:51 +08:00 committed by GitHub
parent b40649b2ae
commit 78a058acd2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
17 changed files with 170 additions and 150 deletions

View file

@ -0,0 +1,5 @@
---
"@moonshot-ai/kimi-code": patch
---
Remove the experimental micro compaction feature and its toggle from the experiments panel.

View file

@ -1,7 +1,6 @@
import {
effectiveModelAlias,
type ExperimentalFeatureState,
type FlagId,
type ModelAlias,
type PermissionMode,
type Session,
@ -590,7 +589,7 @@ export async function applyExperimentalFeatureChanges(
return;
}
const experimental: Partial<Record<FlagId, boolean>> = {};
const experimental: Record<string, boolean> = {};
for (const change of changes) {
experimental[change.id] = change.enabled;
}

View file

@ -51,8 +51,8 @@ reserved_context_size = 50000
max_running_tasks = 4
keep_alive_on_exit = false
[experimental]
micro_compaction = false
# [experimental]
# micro_compaction = false # disabled: micro compaction has been removed
[[permission.rules]]
decision = "allow"
@ -200,6 +200,7 @@ You can also switch models temporarily without touching the config file — by s
`keep_alive_on_exit` can be overridden by the `KIMI_CODE_BACKGROUND_KEEP_ALIVE_ON_EXIT` environment variable, which takes higher priority than `config.toml`.
<!--
## `experimental`
`experimental` stores persistent overrides for experimental-feature flags. Currently, `micro_compaction` is the only user-facing entry and defaults to `false`; set it to `true` to enable automatic trimming of older large tool results.
@ -207,6 +208,7 @@ You can also switch models temporarily without touching the config file — by s
| Field | Type | Default | Description |
| --- | --- | --- | --- |
| `micro_compaction` | `boolean` | `false` | Trim older large tool results from context while preserving recent conversation |
-->
## `services`

View file

@ -125,7 +125,6 @@ Switches that control the behavior of subsystems such as telemetry, background t
| `KIMI_CODE_PLUGIN_MARKETPLACE_URL` | Override the plugin marketplace JSON loaded by `/plugins`; useful for dev loopback servers, staging CDN files, or alternate marketplace directories | `https://code.kimi.com/kimi-code/plugins/marketplace.json`; also accepts `http://`, `file://` URLs, and local paths |
| `KIMI_CODE_AGENT_SWARM_MAX_CONCURRENCY` | Cap how many AgentSwarm subagents run concurrently during the initial ramp; leave unset for no cap | Positive integer; invalid values fail fast |
| `KIMI_CODE_EXPERIMENTAL_FLAG` | Enable all registered experimental features for this process | `1`, `true`, `yes`, `on` |
| `KIMI_CODE_EXPERIMENTAL_MICRO_COMPACTION` | Override [`[experimental].micro_compaction`](./config-files.md#experimental) for this process | Truthy or falsy |
| `KIMI_SHELL_PATH` | Override the Git Bash path on Windows (used when auto-detection fails) | Absolute path |
| `KIMI_MODEL_MAX_COMPLETION_TOKENS` | Hard cap on `max_completion_tokens` per LLM step; applies to the `kimi` provider only | Positive integer; `0` or negative disables clamping |
| `KIMI_MODEL_TEMPERATURE` | Sampling temperature for every request; applies to the `kimi` provider only (global — independent of `KIMI_MODEL_NAME`) | Number, e.g. `0.3` |

View file

@ -51,8 +51,8 @@ reserved_context_size = 50000
max_running_tasks = 4
keep_alive_on_exit = false
[experimental]
micro_compaction = false
# [experimental]
# micro_compaction = false # disabled: micro compaction has been removed
[[permission.rules]]
decision = "allow"
@ -200,6 +200,7 @@ default_effort = "high"
`keep_alive_on_exit` 可被环境变量 `KIMI_CODE_BACKGROUND_KEEP_ALIVE_ON_EXIT` 覆盖,优先级高于配置文件。
<!--
## `experimental`
`experimental` 存放实验功能 flag 的持久化覆盖。目前 `micro_compaction` 是唯一用户可见的字段,默认值为 `false`;如需自动清理较旧的大型工具结果,把它设为 `true`
@ -207,6 +208,7 @@ default_effort = "high"
| 字段 | 类型 | 默认值 | 说明 |
| --- | --- | --- | --- |
| `micro_compaction` | `boolean` | `false` | 清理较旧的大型工具结果内容,同时保留最近对话 |
-->
## `services`

View file

@ -125,7 +125,6 @@ kimi
| `KIMI_CODE_PLUGIN_MARKETPLACE_URL` | 覆盖 `/plugins` 加载的 plugin marketplace JSON适合 dev loopback server、测试 CDN 文件或替换 marketplace 目录 | `https://code.kimi.com/kimi-code/plugins/marketplace.json`;也接受 `http://``file://` URL 和本地路径 |
| `KIMI_CODE_AGENT_SWARM_MAX_CONCURRENCY` | 限制 AgentSwarm 初始提升并发阶段可同时运行的子 Agent 数量;不设置表示不限制 | 正整数;非法值会立即失败 |
| `KIMI_CODE_EXPERIMENTAL_FLAG` | 在当前进程启用所有已注册的实验功能 | `1``true``yes``on` |
| `KIMI_CODE_EXPERIMENTAL_MICRO_COMPACTION` | 覆盖当前进程的 [`[experimental].micro_compaction`](./config-files.md#experimental) | 真值或假值 |
| `KIMI_SHELL_PATH` | Windows 上覆盖 Git Bash 路径(自动探测失败时使用) | 绝对路径 |
| `KIMI_MODEL_MAX_COMPLETION_TOKENS` | 单步 LLM 请求的 `max_completion_tokens` 硬上限,仅对 `kimi` 供应商生效 | 正整数;`0` 或负数禁用 clamp |
| `KIMI_MODEL_TEMPERATURE` | 每次请求的采样温度,仅对 `kimi` 供应商生效(全局生效,不依赖 `KIMI_MODEL_NAME` | 数字,如 `0.3` |

View file

@ -1,10 +1,11 @@
import type { ContentPart } from '@moonshot-ai/kosong';
// Micro compaction is disabled; ContentPart is no longer referenced here.
// import type { ContentPart } from '@moonshot-ai/kosong';
import type { Agent } from '..';
import type { ContextMessage } from '../context';
import {
estimateTokensForContentParts,
estimateTokensForMessages,
// estimateTokensForMessages, // disabled with micro compaction
} from '../../utils/tokens';
export interface MicroCompactionConfig {
@ -47,83 +48,93 @@ export class MicroCompaction {
}
detect(): void {
if (!this.agent.experimentalFlags.enabled('micro_compaction')) return;
// Micro compaction is disabled: the `micro_compaction` experimental flag has
// been removed from the registry, so detection is intentionally a no-op.
return;
const config = this.config;
const { history, lastAssistantAt } = this.agent.context;
const cacheAgeMs = lastAssistantAt === null ? null : Date.now() - lastAssistantAt;
const cacheMissed = cacheAgeMs !== null && cacheAgeMs >= config.cacheMissedThresholdMs;
if (!cacheMissed) return;
const maxContextTokens = this.agent.config.modelCapabilities.max_context_tokens;
const contextTokens = this.agent.context.tokenCountWithPending;
const contextUsageRatio =
maxContextTokens !== undefined && maxContextTokens > 0
? contextTokens / maxContextTokens
: 1;
if (contextUsageRatio < config.minContextUsageRatio) return;
const previousCutoff = this.cutoff;
const nextCutoff = Math.max(0, history.length - config.keepRecentMessages);
this.apply(nextCutoff);
if (previousCutoff !== nextCutoff) {
const effect = this.measureEffect(history, nextCutoff);
const previousEffect = this.measureEffect(history, previousCutoff);
const rawContextTokens = estimateTokensForMessages(history);
// Whole-context length before/after this cutoff change, mirroring the
// `tokens_before`/`tokens_after` fields on `compaction_finished` so the
// two compaction paths can be compared on the same axis.
const tokensBefore =
rawContextTokens -
previousEffect.truncatedToolResultTokensBefore +
previousEffect.truncatedToolResultTokensAfter;
const tokensAfter =
rawContextTokens -
effect.truncatedToolResultTokensBefore +
effect.truncatedToolResultTokensAfter;
this.agent.telemetry.track('micro_compaction_finished', {
keep_recent_messages: config.keepRecentMessages,
min_content_tokens: config.minContentTokens,
cache_missed_threshold_ms: config.cacheMissedThresholdMs,
truncated_marker: config.truncatedMarker,
min_context_usage_ratio: config.minContextUsageRatio,
truncated_tool_result_count: effect.truncatedToolResultCount,
truncated_tool_result_tokens_before: effect.truncatedToolResultTokensBefore,
truncated_tool_result_tokens_after: effect.truncatedToolResultTokensAfter,
tokens_before: tokensBefore,
tokens_after: tokensAfter,
previous_cutoff: previousCutoff,
cutoff: nextCutoff,
message_count: history.length,
cache_age_ms: cacheAgeMs,
thinking_effort: this.agent.config.thinkingEffort,
});
}
// Original implementation (disabled):
// if (!this.agent.experimentalFlags.enabled('micro_compaction')) return;
//
// const config = this.config;
// const { history, lastAssistantAt } = this.agent.context;
// const cacheAgeMs = lastAssistantAt === null ? null : Date.now() - lastAssistantAt;
// const cacheMissed = cacheAgeMs !== null && cacheAgeMs >= config.cacheMissedThresholdMs;
// if (!cacheMissed) return;
//
// const maxContextTokens = this.agent.config.modelCapabilities.max_context_tokens;
// const contextTokens = this.agent.context.tokenCountWithPending;
// const contextUsageRatio =
// maxContextTokens !== undefined && maxContextTokens > 0
// ? contextTokens / maxContextTokens
// : 1;
// if (contextUsageRatio < config.minContextUsageRatio) return;
//
// const previousCutoff = this.cutoff;
// const nextCutoff = Math.max(0, history.length - config.keepRecentMessages);
// this.apply(nextCutoff);
// if (previousCutoff !== nextCutoff) {
// const effect = this.measureEffect(history, nextCutoff);
// const previousEffect = this.measureEffect(history, previousCutoff);
// const rawContextTokens = estimateTokensForMessages(history);
// // Whole-context length before/after this cutoff change, mirroring the
// // `tokens_before`/`tokens_after` fields on `compaction_finished` so the
// // two compaction paths can be compared on the same axis.
// const tokensBefore =
// rawContextTokens -
// previousEffect.truncatedToolResultTokensBefore +
// previousEffect.truncatedToolResultTokensAfter;
// const tokensAfter =
// rawContextTokens -
// effect.truncatedToolResultTokensBefore +
// effect.truncatedToolResultTokensAfter;
// this.agent.telemetry.track('micro_compaction_finished', {
// keep_recent_messages: config.keepRecentMessages,
// min_content_tokens: config.minContentTokens,
// cache_missed_threshold_ms: config.cacheMissedThresholdMs,
// truncated_marker: config.truncatedMarker,
// min_context_usage_ratio: config.minContextUsageRatio,
// truncated_tool_result_count: effect.truncatedToolResultCount,
// truncated_tool_result_tokens_before: effect.truncatedToolResultTokensBefore,
// truncated_tool_result_tokens_after: effect.truncatedToolResultTokensAfter,
// tokens_before: tokensBefore,
// tokens_after: tokensAfter,
// previous_cutoff: previousCutoff,
// cutoff: nextCutoff,
// message_count: history.length,
// cache_age_ms: cacheAgeMs,
// thinking_effort: this.agent.config.thinkingEffort,
// });
// }
}
compact(messages: readonly ContextMessage[]): readonly ContextMessage[] {
if (!this.agent.experimentalFlags.enabled('micro_compaction')) return messages;
// Micro compaction is disabled: the `micro_compaction` experimental flag has
// been removed from the registry, so messages are always returned unchanged.
return messages;
const config = this.config;
const result: ContextMessage[] = [];
let i = 0;
for (const msg of messages) {
if (
i < this.cutoff &&
msg.role === 'tool' &&
msg.toolCallId !== undefined &&
estimateTokensForContentParts(msg.content) >= config.minContentTokens
) {
result.push({
...msg,
content: [{ type: 'text', text: config.truncatedMarker } satisfies ContentPart],
});
} else {
result.push(msg);
}
i++;
}
return result;
// Original implementation (disabled):
// if (!this.agent.experimentalFlags.enabled('micro_compaction')) return messages;
//
// const config = this.config;
// const result: ContextMessage[] = [];
// let i = 0;
// for (const msg of messages) {
// if (
// i < this.cutoff &&
// msg.role === 'tool' &&
// msg.toolCallId !== undefined &&
// estimateTokensForContentParts(msg.content) >= config.minContentTokens
// ) {
// result.push({
// ...msg,
// content: [{ type: 'text', text: config.truncatedMarker } satisfies ContentPart],
// });
// } else {
// result.push(msg);
// }
// i++;
// }
// return result;
}
private measureEffect(

View file

@ -12,14 +12,17 @@ import type { FlagDefinitionInput } from './types';
* not equal the master switch 'KIMI_CODE_EXPERIMENTAL_FLAG'; `id` must not be 'flag'.
*/
export const FLAG_DEFINITIONS = [
{
id: 'micro_compaction',
title: 'Micro compaction',
description: 'Trim older large tool results from context while keeping recent conversation intact.',
env: 'KIMI_CODE_EXPERIMENTAL_MICRO_COMPACTION',
default: false,
surface: 'core',
},
// Micro compaction has been disabled and removed: the capability cannot be
// enabled via env, config, or the master experimental switch. The entry is
// kept here commented out so it can be restored if the feature is revived.
// {
// id: 'micro_compaction',
// title: 'Micro compaction',
// description: 'Trim older large tool results from context while keeping recent conversation intact.',
// env: 'KIMI_CODE_EXPERIMENTAL_MICRO_COMPACTION',
// default: false,
// surface: 'core',
// },
] as const satisfies readonly FlagDefinitionInput[];
/** Literal union of registered flag ids. */

View file

@ -26,7 +26,10 @@ export type ExperimentalFlagConfig = Partial<Record<FlagId, boolean>>;
export type ExperimentalFlagSource = 'master-env' | 'env' | 'config' | 'default';
export interface ExperimentalFeatureState {
readonly id: FlagId;
/** Feature id. Typed as `string` because this is a runtime snapshot that
* crosses the SDK/RPC boundary and must remain usable even when no flags are
* registered (in which case the internal `FlagId` union collapses to `never`). */
readonly id: string;
readonly title: string;
readonly description: string;
readonly surface: FlagSurface;

View file

@ -9,7 +9,9 @@ it('creates an independent agent with a scoped experimental flag resolver', () =
experimentalFlags: new FlagResolver({}, FLAG_DEFINITIONS),
});
expect(ctx.agent.experimentalFlags.enabled('micro_compaction')).toBe(false);
// No experimental flags are currently registered, so the scoped resolver
// reports none enabled.
expect(ctx.agent.experimentalFlags.enabledIds()).toEqual([]);
});
it('runs a text-only agent turn from prompt to completion', async () => {

View file

@ -354,7 +354,9 @@ describe('compaction — probe tests (high-risk scenarios)', () => {
// to a recent suffix but still projected through MicroCompaction.compact()
// with the cutoff computed for the FULL history. The absolute cutoff applied
// to the shifted suffix can clear recent tool results the summary needs.
it.fails('does not clear recent tool results when projecting a shrunk suffix under an active micro-compaction cutoff', () => {
// SKIPPED: micro-compaction has been disabled and its flag removed, so this
// defect no longer exists.
it.skip('does not clear recent tool results when projecting a shrunk suffix under an active micro-compaction cutoff', () => {
// This defect only exists when micro-compaction is active, so enable the
// flag explicitly rather than inheriting the ambient KIMI_CODE_EXPERIMENTAL
// master switch — otherwise the probe's pass/fail flips with the runner's

View file

@ -324,7 +324,9 @@ describe('FullCompaction', () => {
).toBe(false);
});
it('micro-compacts old tool results before sending the summary request', async () => {
// Micro compaction is disabled; this scenario is skipped because the feature
// can no longer be enabled.
it.skip('micro-compacts old tool results before sending the summary request', async () => {
vi.useFakeTimers();
enableMicroCompactionFlag();
const ctx = testAgent({
@ -2227,11 +2229,9 @@ function enableMicroCompactionFlag(): void {
}
function getMicroCompactionFlagEnv(): string {
const flag = FLAG_DEFINITIONS.find((definition) => definition.id === 'micro_compaction');
if (flag === undefined) {
throw new Error('Missing micro_compaction flag definition.');
}
return flag.env;
// Micro compaction is disabled and its flag has been removed from the registry;
// the env var name is kept so the (skipped) test still type-checks.
return 'KIMI_CODE_EXPERIMENTAL_MICRO_COMPACTION';
}
function deferred<T>() {

View file

@ -29,15 +29,18 @@ const MINUTE = 60 * 1000;
const DEFAULT_MARKER = '[Old tool result content cleared]';
const MICRO_COMPACTION_FLAG_ENV = getMicroCompactionFlagEnv();
describe('MicroCompaction', () => {
// Micro compaction is disabled and its flag has been removed; the suite is
// skipped because the feature can no longer be enabled.
describe.skip('MicroCompaction', () => {
beforeEach(() => {
vi.stubEnv(MASTER_ENV, '0');
vi.stubEnv(MICRO_COMPACTION_FLAG_ENV, '1');
});
it('defaults the micro_compaction flag off', () => {
expect(new FlagResolver({}, FLAG_DEFINITIONS).enabled('micro_compaction')).toBe(false);
});
// The micro_compaction flag no longer exists, so there is no default to assert.
// it('defaults the micro_compaction flag off', () => {
// expect(new FlagResolver({}, FLAG_DEFINITIONS).enabled('micro_compaction')).toBe(false);
// });
it('truncates old tool results after cache miss', () => {
vi.useFakeTimers();
@ -966,11 +969,9 @@ function hasMarker(messages: readonly Message[]): boolean {
}
function getMicroCompactionFlagEnv(): string {
const flag = FLAG_DEFINITIONS.find((definition) => definition.id === 'micro_compaction');
if (flag === undefined) {
throw new Error('Missing micro_compaction flag definition.');
}
return flag.env;
// Micro compaction is disabled and its flag has been removed from the registry;
// the env var name is kept so the (skipped) suite still type-checks.
return 'KIMI_CODE_EXPERIMENTAL_MICRO_COMPACTION';
}
function singleTelemetryEvent(

View file

@ -26,16 +26,15 @@ import type { OAuthTokenProviderResolver } from '../../src/session/provider-mana
import { testKaos } from '../fixtures/test-kaos';
function requiredFlagEnv(id: string): string {
const def = FLAG_DEFINITIONS.find((item) => item.id === id);
if (def === undefined) throw new Error(`Missing flag definition: ${id}`);
return def.env;
// Micro compaction was the only registered flag and has been removed, so the
// env var name is derived directly; the (skipped) tests still type-check.
return `KIMI_CODE_EXPERIMENTAL_${id.toUpperCase()}`;
}
function clearExperimentalEnv(): void {
vi.stubEnv(MASTER_ENV, '0');
for (const def of FLAG_DEFINITIONS) {
vi.stubEnv(def.env, '');
}
// No experimental flags are currently registered, so there are no per-flag
// env vars to clear.
}
function experimentalFeatureEnabled(core: KimiCore, id: string): boolean | undefined {
@ -94,16 +93,19 @@ describe('KimiCore runtime config', () => {
vi.unstubAllGlobals();
});
it('logs all enabled experimental flags once on core startup', async () => {
// Micro compaction was the only experimental flag and has been removed; this
// test is skipped because there is no flag to enable.
it.skip('logs all enabled experimental flags once on core startup', async () => {
tmp = await mkdtemp(join(tmpdir(), 'kimi-core-runtime-'));
const homeDir = join(tmp, 'home');
await mkdir(homeDir, { recursive: true });
await getRootLogger().configure(resolveLoggingConfig({ homeDir }));
vi.stubEnv(MASTER_ENV, '0');
for (const def of FLAG_DEFINITIONS) {
vi.stubEnv(def.env, '0');
}
// No experimental flags are currently registered, so there is nothing to clear.
// for (const def of FLAG_DEFINITIONS) {
// vi.stubEnv(def.env, '0');
// }
vi.stubEnv(requiredFlagEnv('micro_compaction'), '1');
void new KimiCore(async () => ({}) as never, { homeDir });
@ -115,7 +117,9 @@ describe('KimiCore runtime config', () => {
expect(text.match(/experimental flags enabled/g)).toHaveLength(1);
});
it('resolves experimental flags from each core config independently', async () => {
// Micro compaction was the only experimental flag and has been removed; this
// test is skipped because there is no flag to resolve.
it.skip('resolves experimental flags from each core config independently', async () => {
tmp = await mkdtemp(join(tmpdir(), 'kimi-core-runtime-'));
const firstHome = join(tmp, 'first-home');
const secondHome = join(tmp, 'second-home');
@ -144,7 +148,9 @@ micro_compaction = false
expect(experimentalFeatureEnabled(second, 'micro_compaction')).toBe(false);
});
it('updates the scoped experimental resolver after setKimiConfig', async () => {
// Micro compaction was the only experimental flag and has been removed; this
// test is skipped because there is no flag to update.
it.skip('updates the scoped experimental resolver after setKimiConfig', async () => {
tmp = await mkdtemp(join(tmpdir(), 'kimi-core-runtime-'));
const homeDir = join(tmp, 'home');
await mkdir(homeDir, { recursive: true });
@ -169,7 +175,9 @@ micro_compaction = false
expect(experimentalFeatureEnabled(core, 'micro_compaction')).toBe(true);
});
it('updates the shared experimental resolver while goal tools stay available', async () => {
// Micro compaction was the only experimental flag and has been removed; this
// test is skipped because there is no flag to update.
it.skip('updates the shared experimental resolver while goal tools stay available', async () => {
tmp = await mkdtemp(join(tmpdir(), 'kimi-core-runtime-'));
const homeDir = join(tmp, 'home');
const workDir = join(tmp, 'work');
@ -201,8 +209,8 @@ micro_compaction = false
const session = core.sessions.get(created.id);
const mainAgent = session?.getReadyAgent('main');
expect(session?.experimentalFlags.enabled('micro_compaction')).toBe(false);
expect(mainAgent?.experimentalFlags.enabled('micro_compaction')).toBe(false);
// expect(session?.experimentalFlags.enabled('micro_compaction')).toBe(false);
// expect(mainAgent?.experimentalFlags.enabled('micro_compaction')).toBe(false);
expect(mainAgent?.tools.data().some((tool) => tool.name === 'CreateGoal')).toBe(true);
await core.setKimiConfig({
@ -211,8 +219,8 @@ micro_compaction = false
},
});
expect(session?.experimentalFlags.enabled('micro_compaction')).toBe(true);
expect(mainAgent?.experimentalFlags.enabled('micro_compaction')).toBe(true);
// expect(session?.experimentalFlags.enabled('micro_compaction')).toBe(true);
// expect(mainAgent?.experimentalFlags.enabled('micro_compaction')).toBe(true);
expect(mainAgent?.tools.data().some((tool) => tool.name === 'CreateGoal')).toBe(true);
await rpc.reloadSession({ sessionId: created.id });

View file

@ -30,7 +30,7 @@ const BACKGROUND_FIELDS_TO_KEEP = new Set([
'keep_alive_on_exit',
]);
const REGISTERED_EXPERIMENTAL_FLAGS: ReadonlySet<string> = new Set(
FLAG_DEFINITIONS.map((definition) => definition.id),
(FLAG_DEFINITIONS as ReadonlyArray<{ readonly id: string }>).map((definition) => definition.id),
);
// kimi-code's tui.toml `theme` enum (mirrors apps/kimi-code TuiThemeSchema).

View file

@ -458,8 +458,11 @@ base_url = "https://target.example/v1"
expect(r.migrated).toBe(true);
const cfg = await readFile(join(tgt, 'config.toml'), 'utf-8');
expect(cfg).toContain('[experimental]');
expect(cfg).toContain('micro_compaction = false');
// No experimental flags are currently registered, so the whole
// `[experimental]` section (including the former `micro_compaction`) is
// dropped along with unknown flags during migration.
expect(cfg).not.toContain('[experimental]');
expect(cfg).not.toContain('micro_compaction');
expect(cfg).not.toContain('unknown_flag');
expect(cfg).toContain('[loop_control]');
expect(cfg).toContain('max_retries_per_step = 2');

View file

@ -329,32 +329,13 @@ describe('KimiHarness config API', () => {
it('returns experimental feature metadata through the harness', async () => {
vi.stubEnv('KIMI_CODE_EXPERIMENTAL_FLAG', '0');
vi.stubEnv('KIMI_CODE_EXPERIMENTAL_MICRO_COMPACTION', '');
const homeDir = await makeTempDir();
await writeFile(
join(homeDir, 'config.toml'),
`
[experimental]
micro_compaction = false
`,
'utf-8',
);
const harness = createKimiHarness({ homeDir, identity: TEST_IDENTITY });
// No experimental features are currently registered, so the harness exposes
// an empty list.
const features = await harness.getExperimentalFeatures();
const microCompaction = features.find((feature) => feature.id === 'micro_compaction');
expect(microCompaction).toMatchObject({
id: 'micro_compaction',
title: 'Micro compaction',
enabled: false,
source: 'config',
configValue: false,
env: 'KIMI_CODE_EXPERIMENTAL_MICRO_COMPACTION',
});
expect(features).toEqual([
expect.objectContaining({ id: 'micro_compaction', enabled: false }),
]);
expect(features).toEqual([]);
});
it('can create the default config scaffold without selecting a model', async () => {