mirror of
https://github.com/MoonshotAI/kimi-code.git
synced 2026-07-10 01:39:25 +00:00
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:
parent
b40649b2ae
commit
78a058acd2
17 changed files with 170 additions and 150 deletions
5
.changeset/remove-micro-compaction.md
Normal file
5
.changeset/remove-micro-compaction.md
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
"@moonshot-ai/kimi-code": patch
|
||||
---
|
||||
|
||||
Remove the experimental micro compaction feature and its toggle from the experiments panel.
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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`
|
||||
|
||||
|
|
|
|||
|
|
@ -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` |
|
||||
|
|
|
|||
|
|
@ -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`
|
||||
|
||||
|
|
|
|||
|
|
@ -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` |
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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. */
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 () => {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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>() {
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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 });
|
||||
|
|
|
|||
|
|
@ -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).
|
||||
|
|
|
|||
|
|
@ -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');
|
||||
|
|
|
|||
|
|
@ -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 () => {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue