Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/recommended-default-effort.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@moonshot-ai/kimi-code": patch
---

Upgrade the default thinking effort to the recommended level for eligible users.
1 change: 1 addition & 0 deletions apps/kimi-code/src/constant/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ export const KIMI_CODE_INPUT_HISTORY_DIR_NAME = 'user-history';
export const KIMI_CODE_BANNER_DIR_NAME = 'banner';
export const KIMI_CODE_BANNER_STATE_FILE_NAME = 'state.json';
export const KIMI_CODE_SURVEY_STATE_FILE_NAME = 'feedback-survey-state.json';
export const KIMI_CODE_RECOMMENDED_EFFORT_STATE_FILE_NAME = 'recommended-effort-state.json';

// Managed Kimi auth provider key shared with OAuth/SDK config.
export const DEFAULT_OAUTH_PROVIDER_NAME = 'managed:kimi-code';
Expand Down
19 changes: 19 additions & 0 deletions apps/kimi-code/src/tui/kimi-tui.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ import { copyTextToClipboard } from '#/utils/clipboard/clipboard-text';
import { appendInputHistory, loadInputHistory } from '#/utils/history/input-history';
import { openUrl } from '#/utils/open-url';
import { getInputHistoryFile } from '#/utils/paths';
import { applyRecommendedEffort } from '#/utils/recommended-effort';
import { getRecommendedEffortConfig } from '#/utils/recommended-effort-config';
import { detectFdPath, ensureFdPath } from '#/utils/process/fd-detect';
import { quoteShellArg } from '#/utils/shell-quote';
import { restoreTerminalModes } from '#/utils/terminal-restore';
Expand Down Expand Up @@ -728,6 +730,7 @@ export class KimiTUI {
this.state.editorContainer.clear();
this.state.editorContainer.addChild(this.state.editor);
this.state.ui.setFocus(this.state.editor);
this.applyRecommendedEffortInBackground();
return shouldReplayHistory;
}

Expand Down Expand Up @@ -774,6 +777,22 @@ export class KimiTUI {
});
}

private applyRecommendedEffortInBackground(): void {
void this.backgroundRefreshPromise?.then(async () => {
await applyRecommendedEffort({
Comment thread
Grapedge marked this conversation as resolved.
fetchConfig: async () =>
getRecommendedEffortConfig({
accessToken: await this.harness.auth.getCachedAccessToken(),
}),
getConfig: () => this.harness.getConfig(),
setConfig: (patch) => this.harness.setConfig(patch),
track: (event, properties) => {
this.track(event, properties);
},
});
});
Comment thread
Grapedge marked this conversation as resolved.
}

private async refreshProviderModelsInBackground(): Promise<void> {
try {
const result = await this.authFlow.refreshProviderModels();
Expand Down
5 changes: 5 additions & 0 deletions apps/kimi-code/src/utils/paths.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {
KIMI_CODE_NATIVE_STAGED_STATE_FILE_NAME,
KIMI_CODE_NATIVE_STAGING_DIR_NAME,
KIMI_CODE_PLUGIN_UPDATE_NOTICE_STATE_FILE_NAME,
KIMI_CODE_RECOMMENDED_EFFORT_STATE_FILE_NAME,
KIMI_CODE_SURVEY_STATE_FILE_NAME,
KIMI_CODE_UPDATE_INSTALL_LOCK_FILE_NAME,
KIMI_CODE_UPDATE_INSTALL_STATE_FILE_NAME,
Expand Down Expand Up @@ -131,6 +132,10 @@ export function getSurveyStateFile(): string {
return join(getDataDir(), KIMI_CODE_SURVEY_STATE_FILE_NAME);
}

export function getRecommendedEffortStateFile(): string {
return join(getDataDir(), KIMI_CODE_RECOMMENDED_EFFORT_STATE_FILE_NAME);
}

/**
* Return the user input history file for a given working directory.
* Layout: `<share_dir>/user-history/<md5(cwd)>.jsonl`.
Expand Down
47 changes: 47 additions & 0 deletions apps/kimi-code/src/utils/recommended-effort-config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { z } from 'zod';

import {
getClientConfig,
peekClientConfig,
resetClientConfigCache,
type ClientConfigFetchOptions,
} from '#/utils/client-configs';

const CONFIG_NAME = 'recommended_effort';

export interface RecommendedEffortEntry {
version: number;
recommended_default_effort: string;
}

export type RecommendedEffortConfig = Record<string, RecommendedEffortEntry>;

const recommendedEffortEntrySchema = z.object({
version: z.number().int().min(0),
recommended_default_effort: z.string(),
});

const recommendedEffortConfigSchema = z
.record(z.string(), z.unknown())
.transform((record): RecommendedEffortConfig => {
const config: RecommendedEffortConfig = {};
for (const [model, rawEntry] of Object.entries(record)) {
const parsed = recommendedEffortEntrySchema.safeParse(rawEntry);
if (parsed.success) config[model] = parsed.data;
}
return config;
});

export async function getRecommendedEffortConfig(
options: ClientConfigFetchOptions = {},
): Promise<RecommendedEffortConfig | undefined> {
return getClientConfig(CONFIG_NAME, recommendedEffortConfigSchema, options);
Comment thread
Grapedge marked this conversation as resolved.
}

export function peekRecommendedEffortConfig(now?: number): RecommendedEffortConfig | undefined {
return peekClientConfig(CONFIG_NAME, recommendedEffortConfigSchema, now);
}

export function resetRecommendedEffortConfigCache(): void {
resetClientConfigCache(CONFIG_NAME);
}
31 changes: 31 additions & 0 deletions apps/kimi-code/src/utils/recommended-effort-state-store.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { z } from 'zod';

import { getRecommendedEffortStateFile } from '#/utils/paths';
import { readJsonFile, writeJsonFileSync } from '#/utils/persistence';

const RecommendedEffortStateSchema = z.record(
z.string(),
z.object({
version: z.number().int().min(0),
applied_at: z.string(),
}),
);

export type RecommendedEffortState = z.infer<typeof RecommendedEffortStateSchema>;

export async function readRecommendedEffortState(
filePath: string = getRecommendedEffortStateFile(),
): Promise<RecommendedEffortState> {
try {
return await readJsonFile(filePath, RecommendedEffortStateSchema, {});
} catch {
return {};
}
}

export function writeRecommendedEffortState(
state: RecommendedEffortState,
filePath: string = getRecommendedEffortStateFile(),
): void {
writeJsonFileSync(filePath, RecommendedEffortStateSchema, state);
}
72 changes: 72 additions & 0 deletions apps/kimi-code/src/utils/recommended-effort.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { isManagedKimiCodeBaseUrl } from '@moonshot-ai/kimi-code-oauth';
import type { KimiConfig, KimiConfigPatch, ModelAlias } from '@moonshot-ai/kimi-code-sdk';
import type { TelemetryProperties } from '@moonshot-ai/kimi-telemetry';

import { getRecommendedEffortStateFile } from '#/utils/paths';
import type { RecommendedEffortConfig } from '#/utils/recommended-effort-config';
import {
readRecommendedEffortState,
writeRecommendedEffortState,
} from '#/utils/recommended-effort-state-store';

export interface ApplyRecommendedEffortDeps {
fetchConfig: () => Promise<RecommendedEffortConfig | undefined>;
getConfig: () => Promise<KimiConfig>;
setConfig: (patch: KimiConfigPatch) => Promise<unknown>;
track: (event: string, properties?: TelemetryProperties) => void;
stateFile?: string;
now?: () => Date;
}

function eligibleModelEntry(config: KimiConfig): ModelAlias | undefined {
if (config.thinking?.enabled === false) return undefined;
const alias = config.defaultModel;
if (alias === undefined) return undefined;
const entry = config.models?.[alias];
if (entry === undefined) return undefined;
const baseUrl = entry.baseUrl ?? config.providers[entry.provider]?.baseUrl;
return isManagedKimiCodeBaseUrl(baseUrl) ? entry : undefined;
}

export async function applyRecommendedEffort(deps: ApplyRecommendedEffortDeps): Promise<void> {
try {
if (eligibleModelEntry(await deps.getConfig()) === undefined) return;
const cloud = await deps.fetchConfig();
if (cloud === undefined) return;

const config = await deps.getConfig();
const modelEntry = eligibleModelEntry(config);
if (modelEntry === undefined) return;
const campaign = cloud[modelEntry.model];
if (campaign === undefined) return;
const supportEfforts = modelEntry.overrides?.supportEfforts ?? modelEntry.supportEfforts;
if (!supportEfforts?.includes(campaign.recommended_default_effort)) return;

const stateFile = deps.stateFile ?? getRecommendedEffortStateFile();
const state = await readRecommendedEffortState(stateFile);
const applied = state[modelEntry.model];
if (applied !== undefined && campaign.version <= applied.version) return;

const previousEffort = config.thinking?.effort;
if (previousEffort !== campaign.recommended_default_effort) {
await deps.setConfig({ thinking: { effort: campaign.recommended_default_effort } });
}
writeRecommendedEffortState(
{
...state,
[modelEntry.model]: {
version: campaign.version,
applied_at: (deps.now?.() ?? new Date()).toISOString(),
},
},
stateFile,
);
deps.track('recommended_effort_applied', {
model: modelEntry.model,
version: campaign.version,
effort: campaign.recommended_default_effort,
previous_effort: previousEffort,
});
} catch {
}
}
Loading
Loading