kimi-code / packages /acp-server /src /model-catalog.ts
SaylorTwift's picture
SaylorTwift HF Staff
Add files using upload-large-folder tool
f0634fb verified
Raw History Blame Contribute Delete
3.74 kB
/**
* ACP model catalog β€” projects the engine's model catalog (`IModelCatalog`,
* surfaced through `klient.global.kosong.listModels()`) into a flat list of
* selectable models for the ACP `configOptions` picker.
*
* ACP-specific heuristics (thinking-capability derivation, the toggleable-models
* allow-list) stay scoped to this host. Order mirrors the catalog's
* enumeration order (the engine's model-registry insertion order).
*
* `thinkingSupported` is true if any of:
* 1. the model's declared `capabilities` contains `'thinking'`/`'always_thinking'`, or
* 2. the model id matches `/thinking|reason/i`, or
* 3. the model id is on the {@link TOGGLEABLE_THINKING_MODELS} allow-list.
*/
import type { ModelCatalogItem } from '@moonshot-ai/klient';
/**
* One catalog row per configured model, suitable for an ACP picker.
*/
export interface AcpModelEntry {
readonly id: string;
readonly name: string;
readonly description?: string | undefined;
readonly thinkingSupported: boolean;
/** Declared 'always_thinking' capability β€” thinking cannot be turned off. */
readonly alwaysThinking?: boolean;
/**
* The thinking effort to send when the binary ACP toggle flips on: the
* model's declared `defaultEffort`, else the middle `supportEfforts` entry,
* else `'on'` for boolean models.
*/
readonly defaultThinkingEffort: string;
/**
* The model's declared selectable effort levels (`support_efforts`).
* `undefined` when the model only exposes a boolean thinking toggle.
*/
readonly supportEfforts?: readonly string[];
}
/**
* Models that support thinking by toggle (not by name match or capability
* declaration). ACP-picker-specific UX.
*/
const TOGGLEABLE_THINKING_MODELS = new Set(['kimi-for-coding', 'kimi-code']);
export function deriveThinkingSupported(item: ModelCatalogItem): boolean {
const capabilities = item.capabilities ?? [];
if (capabilities.includes('thinking') || capabilities.includes('always_thinking')) return true;
const lower = item.model.toLowerCase();
if (lower.includes('thinking') || lower.includes('reason')) return true;
if (TOGGLEABLE_THINKING_MODELS.has(item.model)) return true;
return false;
}
/**
* Whether the model declares the 'always_thinking' capability β€” thinking cannot
* be disabled, so the ACP toggle must lock to on. Capability-only by design.
*/
export function deriveAlwaysThinking(item: ModelCatalogItem): boolean {
return (item.capabilities ?? []).includes('always_thinking');
}
/**
* The effort a boolean "thinking on" toggle maps to for this model: declared
* `default_effort`, else the middle `support_efforts` entry, else `'on'`.
*/
export function deriveDefaultThinkingEffort(item: ModelCatalogItem): string {
const efforts = item.support_efforts;
if (efforts !== undefined && efforts.length > 0) {
return item.default_effort ?? efforts[Math.floor(efforts.length / 2)]!;
}
return 'on';
}
/**
* Project the engine's model catalog into a flat ACP catalog. Returns an empty
* array when no models are configured. The catalog item's `model` field is the
* model-registry id β€” the value `agent.setModel()` takes β€” so it doubles as
* the ACP picker value.
*/
export function projectModelCatalog(
items: readonly ModelCatalogItem[],
): readonly AcpModelEntry[] {
return items.map((item) => ({
id: item.model,
name: item.display_name ?? item.model,
thinkingSupported: deriveThinkingSupported(item),
alwaysThinking: deriveAlwaysThinking(item),
defaultThinkingEffort: deriveDefaultThinkingEffort(item),
supportEfforts:
item.support_efforts !== undefined && item.support_efforts.length > 0
? item.support_efforts
: undefined,
}));
}