Skip to content
Open
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/deepseek-anthropic-capabilities.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@moonshot-ai/kimi-code": patch
---

Recognize DeepSeek Anthropic-compatible chat model capabilities.
5 changes: 5 additions & 0 deletions .changeset/env-model-provider-capabilities.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@moonshot-ai/kimi-code": patch
---

Avoid defaulting OpenAI and Anthropic environment models to Kimi-only capabilities.
5 changes: 5 additions & 0 deletions .changeset/kimi-model-capabilities.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@moonshot-ai/kimi-code": patch
---

Recognize current Kimi Open Platform model capabilities.
5 changes: 5 additions & 0 deletions .changeset/mimo-anthropic-capabilities.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@moonshot-ai/kimi-code": patch
---

Recognize MiMo Anthropic-compatible chat model capabilities.
5 changes: 5 additions & 0 deletions .changeset/minimax-anthropic-capabilities.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@moonshot-ai/kimi-code": patch
---

Recognize MiniMax Anthropic-compatible chat model capabilities.
2 changes: 1 addition & 1 deletion docs/en/configuration/env-vars.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ Complete variable list:
| `KIMI_MODEL_PROVIDER_TYPE` | No | Provider type: `kimi`, `anthropic`, `openai` | `kimi` |
| `KIMI_MODEL_BASE_URL` | No | API base URL | Each type has its own default |
| `KIMI_MODEL_MAX_CONTEXT_SIZE` | No | Maximum context length (tokens) | `262144` (256 K) |
| `KIMI_MODEL_CAPABILITIES` | No | Comma-separated capability tags, unioned with auto-detected capabilities | `image_in,thinking` |
| `KIMI_MODEL_CAPABILITIES` | No | Comma-separated capability tags, unioned with auto-detected capabilities | `kimi` → `image_in,thinking`; `openai` / `anthropic` → unset |
| `KIMI_MODEL_DISPLAY_NAME` | No | Name shown in `/model` | Falls back to `KIMI_MODEL_NAME` |
| `KIMI_MODEL_MAX_OUTPUT_SIZE` | No | Per-request output cap (`anthropic` only) | Model default |
| `KIMI_MODEL_REASONING_KEY` | No | Reasoning field name override (`openai` only) | Auto-detected |
Expand Down
2 changes: 1 addition & 1 deletion docs/zh/configuration/env-vars.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ kimi
| `KIMI_MODEL_PROVIDER_TYPE` | 否 | 供应商类型:`kimi`、`anthropic`、`openai` | `kimi` |
| `KIMI_MODEL_BASE_URL` | 否 | API 基础 URL | 各类型有各自默认值 |
| `KIMI_MODEL_MAX_CONTEXT_SIZE` | 否 | 最大上下文长度(token 数) | `262144`(256K) |
| `KIMI_MODEL_CAPABILITIES` | 否 | 逗号分隔的能力标签,与自动探测的能力取并集 | `image_in,thinking` |
| `KIMI_MODEL_CAPABILITIES` | 否 | 逗号分隔的能力标签,与自动探测的能力取并集 | `kimi` → `image_in,thinking`;`openai` / `anthropic` → 未设置 |
| `KIMI_MODEL_DISPLAY_NAME` | 否 | 在 `/model` 中显示的名称 | 回退到 `KIMI_MODEL_NAME` |
| `KIMI_MODEL_MAX_OUTPUT_SIZE` | 否 | 单次输出上限(仅 `anthropic`) | 模型默认值 |
| `KIMI_MODEL_REASONING_KEY` | 否 | 推理字段名覆盖(仅 `openai`) | 自动探测 |
Expand Down
10 changes: 7 additions & 3 deletions packages/agent-core/src/config/env-model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,10 @@ const DEFAULT_BASE_URL: Partial<Record<ProviderType, string>> = {
/** Default context window (256K) used when KIMI_MODEL_MAX_CONTEXT_SIZE is unset. */
const DEFAULT_MAX_CONTEXT_SIZE = 262144;

/** Default capabilities when KIMI_MODEL_CAPABILITIES is unset (kimi models support both). */
const DEFAULT_CAPABILITIES = ['image_in', 'thinking'];
/** Default capabilities when KIMI_MODEL_CAPABILITIES is unset. */
const DEFAULT_CAPABILITIES_BY_TYPE: Partial<Record<ProviderType, readonly string[]>> = {
kimi: ['image_in', 'thinking'],
};

type Env = Readonly<Record<string, string | undefined>>;

Expand Down Expand Up @@ -119,7 +121,9 @@ export function applyEnvModelConfig(config: KimiConfig, env: Env = process.env):
maxOutputRaw !== undefined
? parsePositiveInt(maxOutputRaw, 'KIMI_MODEL_MAX_OUTPUT_SIZE')
: undefined;
const capabilities = parseCapabilities(env['KIMI_MODEL_CAPABILITIES']) ?? DEFAULT_CAPABILITIES;
const capabilities =
parseCapabilities(env['KIMI_MODEL_CAPABILITIES']) ??
DEFAULT_CAPABILITIES_BY_TYPE[type]?.slice();
const displayName = trimmed(env['KIMI_MODEL_DISPLAY_NAME']);
const reasoningKey = trimmed(env['KIMI_MODEL_REASONING_KEY']);
const adaptiveThinking = parseBooleanVar(
Expand Down
11 changes: 11 additions & 0 deletions packages/agent-core/test/config/env-model.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,17 @@ describe('applyEnvModelConfig', () => {
expect(anthropic?.baseUrl).toBeUndefined();
});

it('does not apply Kimi default capabilities to non-Kimi providers', () => {
expect(
apply({ ...MIN, KIMI_MODEL_PROVIDER_TYPE: 'openai' })
.models?.[ENV_MODEL_ALIAS_KEY]?.capabilities,
).toBeUndefined();
expect(
apply({ ...MIN, KIMI_MODEL_PROVIDER_TYPE: 'anthropic' })
.models?.[ENV_MODEL_ALIAS_KEY]?.capabilities,
).toBeUndefined();
});

it('rejects unsupported provider types', () => {
expectConfigInvalid(() =>
apply({ ...MIN, KIMI_MODEL_PROVIDER_TYPE: 'google-genai' }),
Expand Down
91 changes: 91 additions & 0 deletions packages/kosong/src/providers/capability-registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,28 @@ const GEMINI_CATALOGUED_PREFIXES = [
'gemini-2.5-flash',
] as const;

const MIMO_THINKING_TOOL_MODELS = [
'mimo-v2.5-pro',
'mimo-v2-pro',
'mimo-v2-flash',
] as const;

const MIMO_THINKING_VISION_TOOL_MODELS = ['mimo-v2.5', 'mimo-v2-omni'] as const;

const MINIMAX_THINKING_VISION_TOOL_MODELS = ['minimax-m3'] as const;

const MINIMAX_TEXT_TOOL_MODELS = [
'minimax-m2.7',
'minimax-m2.7-highspeed',
'minimax-m2.5',
'minimax-m2.5-highspeed',
'minimax-m2.1',
'minimax-m2.1-highspeed',
'minimax-m2',
] as const;

const DEEPSEEK_THINKING_TOOL_MODELS = ['deepseek-v4-pro', 'deepseek-v4-flash'] as const;

const OPENAI_REASONING_CAPABILITY: ModelCapability = Object.freeze({
image_in: false,
video_in: false,
Expand Down Expand Up @@ -90,6 +112,51 @@ const ANTHROPIC_THINKING_VISION_TOOL_CAPABILITY: ModelCapability = Object.freeze
max_context_tokens: 0,
});

const MIMO_THINKING_TOOL_CAPABILITY: ModelCapability = Object.freeze({
image_in: false,
video_in: false,
audio_in: false,
thinking: true,
tool_use: true,
max_context_tokens: 0,
});

const MIMO_THINKING_VISION_TOOL_CAPABILITY: ModelCapability = Object.freeze({
image_in: true,
video_in: false,
audio_in: false,
thinking: true,
tool_use: true,
max_context_tokens: 0,
});

const MINIMAX_THINKING_VISION_TOOL_CAPABILITY: ModelCapability = Object.freeze({
image_in: true,
video_in: false,
audio_in: false,
thinking: true,
tool_use: true,
max_context_tokens: 0,
});

const MINIMAX_TEXT_TOOL_CAPABILITY: ModelCapability = Object.freeze({
image_in: false,
video_in: false,
audio_in: false,
thinking: false,
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Mark MiniMax M2.7 as thinking-capable

This shared capability object makes MiniMax-M2.7 and MiniMax-M2.7-highspeed report thinking: false, even though the Anthropic-compatible M2.7 API emits thinking blocks as part of its interleaved-thinking tool flow. Any caller relying on getCapability() will under-report those models and can hide or avoid thinking support for a model whose tool-loop responses include reasoning blocks; split M2.7 out or mark the M2.x entries that support interleaved thinking as thinking-capable.

Useful? React with 👍 / 👎.

tool_use: true,
max_context_tokens: 0,
});

const DEEPSEEK_THINKING_TOOL_CAPABILITY: ModelCapability = Object.freeze({
image_in: false,
video_in: false,
audio_in: false,
thinking: true,
tool_use: true,
max_context_tokens: 0,
});

const GEMINI_MULTIMODAL_TOOL_CAPABILITY: ModelCapability = Object.freeze({
image_in: true,
video_in: true,
Expand Down Expand Up @@ -135,6 +202,26 @@ const OPENAI_RESPONSES_CAPABILITY_CATALOG: readonly CapabilityCatalogEntry[] = [
];

const ANTHROPIC_CAPABILITY_CATALOG: readonly CapabilityCatalogEntry[] = [
{
matches: (name) => hasExactModel(name, MIMO_THINKING_TOOL_MODELS),
capability: MIMO_THINKING_TOOL_CAPABILITY,
},
{
matches: (name) => hasExactModel(name, MIMO_THINKING_VISION_TOOL_MODELS),
capability: MIMO_THINKING_VISION_TOOL_CAPABILITY,
},
{
matches: (name) => hasExactModel(name, MINIMAX_THINKING_VISION_TOOL_MODELS),
capability: MINIMAX_THINKING_VISION_TOOL_CAPABILITY,
},
{
matches: (name) => hasExactModel(name, MINIMAX_TEXT_TOOL_MODELS),
capability: MINIMAX_TEXT_TOOL_CAPABILITY,
},
{
matches: (name) => hasExactModel(name, DEEPSEEK_THINKING_TOOL_MODELS),
capability: DEEPSEEK_THINKING_TOOL_CAPABILITY,
},
{
matches: (name) => hasPrefix(name, CLAUDE_3_PREFIXES),
capability: ANTHROPIC_VISION_TOOL_CAPABILITY,
Expand All @@ -153,6 +240,10 @@ function hasPrefix(modelName: string, prefixes: readonly string[]): boolean {
return prefixes.some((prefix) => modelName.startsWith(prefix));
}

function hasExactModel(modelName: string, models: readonly string[]): boolean {
return models.some((model) => modelName === model);
}

function isOpenAIReasoningModel(modelName: string): boolean {
return /^o\d/.test(modelName);
}
Expand Down
46 changes: 46 additions & 0 deletions packages/kosong/src/providers/kimi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,43 @@ import {
sanitizeToolCallId,
type ToolCallIdPolicy,
} from './tool-call-id';

const KIMI_K2_6_CAPABILITY: ModelCapability = Object.freeze({
image_in: true,
video_in: true,
audio_in: false,
thinking: true,
tool_use: true,
max_context_tokens: 0,
});

const KIMI_K2_5_CAPABILITY: ModelCapability = Object.freeze({
image_in: true,
video_in: false,
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Enable video input for Kimi K2.5

For kimi-k2.5, leaving video_in false under-detects a supported modality: the Kimi K2.5 API accepts video input, but ToolManager.initializeBuiltinTools only exposes ReadMediaFile for video when modelCapabilities.video_in is true. In sessions using the catalogued kimi-k2.5 model, users will be told the current model does not support video and cannot attach videos even though the provider can send/upload them; this should be true like K2.6.

Useful? React with 👍 / 👎.

audio_in: false,
thinking: true,
tool_use: true,
max_context_tokens: 0,
});

const KIMI_VISION_TOOL_CAPABILITY: ModelCapability = Object.freeze({
image_in: true,
video_in: false,
audio_in: false,
thinking: false,
tool_use: true,
max_context_tokens: 0,
});

const KIMI_TEXT_TOOL_CAPABILITY: ModelCapability = Object.freeze({
image_in: false,
video_in: false,
audio_in: false,
thinking: false,
tool_use: true,
max_context_tokens: 0,
});

export interface KimiOptions {
apiKey?: string | undefined;
baseUrl?: string | undefined;
Expand Down Expand Up @@ -499,6 +536,15 @@ export class KimiChatProvider implements ChatProvider {
}

getCapability(_model?: string): ModelCapability {
const model = (_model ?? this._model).toLowerCase();
if (model === 'kimi-k2.6') return KIMI_K2_6_CAPABILITY;
if (model === 'kimi-k2.5') return KIMI_K2_5_CAPABILITY;
if (/^moonshot-v1-(?:8k|32k|128k)-vision-preview$/.test(model)) {
return KIMI_VISION_TOOL_CAPABILITY;
}
if (/^moonshot-v1-(?:8k|32k|128k)$/.test(model)) {
return KIMI_TEXT_TOOL_CAPABILITY;
}
return UNKNOWN_CAPABILITY;
}

Expand Down
Loading