fix(models): add kimi-coding implicit provider template (openclaw#22526) thanks @lailoo

Verified:
- pnpm build
- pnpm check
- pnpm test:macmini

Co-authored-by: lailoo <20536249+lailoo@users.noreply.github.com>
Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
This commit is contained in:
大猫子
2026-02-21 21:35:09 +08:00
committed by GitHub
parent 14b3743228
commit c62a6e7040
4 changed files with 95 additions and 11 deletions

View File

@@ -47,6 +47,7 @@ Docs: https://docs.openclaw.ai
- Security/Browser: block non-network browser navigation protocols (including `file:`, `data:`, and `javascript:`) while preserving `about:blank`, preventing local file reads via browser tool navigation. This ships in the next npm release. Thanks @q1uf3ng for reporting.
- Security/Exec: block shell startup-file env injection (`BASH_ENV`, `ENV`, `BASH_FUNC_*`, `LD_*`, `DYLD_*`) across config env ingestion, node-host inherited environment sanitization, and macOS exec host runtime to prevent pre-command execution from attacker-controlled environment variables. This ships in the next npm release. Thanks @tdjackey.
- Security/Exec (Windows): canonicalize `cmd.exe /c` command text across validation, approval binding, and audit/event rendering to prevent trailing-argument approval mismatches in `system.run`. This ships in the next npm release. Thanks @tdjackey for reporting.
- Models/Kimi-Coding: add missing implicit provider template for `kimi-coding` with correct `anthropic-messages` API type and base URL, fixing 403 errors when using Kimi for Coding. (#22409)
- Security/Gateway/Hooks: block `__proto__`, `constructor`, and `prototype` traversal in webhook template path resolution to prevent prototype-chain payload data leakage in `messageTemplate` rendering. (#22213) Thanks @SleuthCo.
- Security/OpenClawKit/UI: prevent injected inbound user context metadata blocks from leaking into chat history in TUI, webchat, and macOS surfaces by stripping all untrusted metadata prefixes at display boundaries. (#22142) Thanks @Mellowambience, @vincentkoc.
- Security/OpenClawKit/UI: strip inbound metadata blocks from user messages in TUI rendering while preserving user-authored content. (#22345) Thanks @kansodata, @vincentkoc.

View File

@@ -0,0 +1,45 @@
import { mkdtempSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { describe, expect, it } from "vitest";
import { captureEnv } from "../test-utils/env.js";
import { buildKimiCodingProvider, resolveImplicitProviders } from "./models-config.providers.js";
describe("kimi-coding implicit provider (#22409)", () => {
it("should include kimi-coding when KIMI_API_KEY is configured", async () => {
const agentDir = mkdtempSync(join(tmpdir(), "openclaw-test-"));
const envSnapshot = captureEnv(["KIMI_API_KEY"]);
process.env.KIMI_API_KEY = "test-key";
try {
const providers = await resolveImplicitProviders({ agentDir });
expect(providers?.["kimi-coding"]).toBeDefined();
expect(providers?.["kimi-coding"]?.api).toBe("anthropic-messages");
expect(providers?.["kimi-coding"]?.baseUrl).toBe("https://api.kimi.com/coding/");
} finally {
envSnapshot.restore();
}
});
it("should build kimi-coding provider with anthropic-messages API", () => {
const provider = buildKimiCodingProvider();
expect(provider.api).toBe("anthropic-messages");
expect(provider.baseUrl).toBe("https://api.kimi.com/coding/");
expect(provider.models).toBeDefined();
expect(provider.models.length).toBeGreaterThan(0);
expect(provider.models[0].id).toBe("k2p5");
});
it("should not include kimi-coding when no API key is configured", async () => {
const agentDir = mkdtempSync(join(tmpdir(), "openclaw-test-"));
const envSnapshot = captureEnv(["KIMI_API_KEY"]);
delete process.env.KIMI_API_KEY;
try {
const providers = await resolveImplicitProviders({ agentDir });
expect(providers?.["kimi-coding"]).toBeUndefined();
} finally {
envSnapshot.restore();
}
});
});

View File

@@ -96,6 +96,17 @@ const MOONSHOT_DEFAULT_COST = {
cacheWrite: 0,
};
const KIMI_CODING_BASE_URL = "https://api.kimi.com/coding/";
const KIMI_CODING_DEFAULT_MODEL_ID = "k2p5";
const KIMI_CODING_DEFAULT_CONTEXT_WINDOW = 262144;
const KIMI_CODING_DEFAULT_MAX_TOKENS = 32768;
const KIMI_CODING_DEFAULT_COST = {
input: 0,
output: 0,
cacheRead: 0,
cacheWrite: 0,
};
const QWEN_PORTAL_BASE_URL = "https://portal.qwen.ai/v1";
const QWEN_PORTAL_OAUTH_PLACEHOLDER = "qwen-oauth";
const QWEN_PORTAL_DEFAULT_CONTEXT_WINDOW = 128000;
@@ -483,6 +494,24 @@ function buildMoonshotProvider(): ProviderConfig {
};
}
export function buildKimiCodingProvider(): ProviderConfig {
return {
baseUrl: KIMI_CODING_BASE_URL,
api: "anthropic-messages",
models: [
{
id: KIMI_CODING_DEFAULT_MODEL_ID,
name: "Kimi for Coding",
reasoning: true,
input: ["text", "image"],
cost: KIMI_CODING_DEFAULT_COST,
contextWindow: KIMI_CODING_DEFAULT_CONTEXT_WINDOW,
maxTokens: KIMI_CODING_DEFAULT_MAX_TOKENS,
},
],
};
}
function buildQwenPortalProvider(): ProviderConfig {
return {
baseUrl: QWEN_PORTAL_BASE_URL,
@@ -687,6 +716,13 @@ export async function resolveImplicitProviders(params: {
providers.moonshot = { ...buildMoonshotProvider(), apiKey: moonshotKey };
}
const kimiCodingKey =
resolveEnvApiKeyVarName("kimi-coding") ??
resolveApiKeyFromProfiles({ provider: "kimi-coding", store: authStore });
if (kimiCodingKey) {
providers["kimi-coding"] = { ...buildKimiCodingProvider(), apiKey: kimiCodingKey };
}
const syntheticKey =
resolveEnvApiKeyVarName("synthetic") ??
resolveApiKeyFromProfiles({ provider: "synthetic", store: authStore });

View File

@@ -4,6 +4,7 @@ import {
HUGGINGFACE_MODEL_CATALOG,
} from "../agents/huggingface-models.js";
import {
buildKimiCodingProvider,
buildQianfanProvider,
buildXiaomiProvider,
QIANFAN_DEFAULT_MODEL_ID,
@@ -61,6 +62,7 @@ import {
buildXaiModelDefinition,
QIANFAN_BASE_URL,
QIANFAN_DEFAULT_MODEL_REF,
KIMI_CODING_MODEL_ID,
KIMI_CODING_MODEL_REF,
MOONSHOT_BASE_URL,
MOONSHOT_CN_BASE_URL,
@@ -206,19 +208,19 @@ export function applyKimiCodeProviderConfig(cfg: OpenClawConfig): OpenClawConfig
const models = { ...cfg.agents?.defaults?.models };
models[KIMI_CODING_MODEL_REF] = {
...models[KIMI_CODING_MODEL_REF],
alias: models[KIMI_CODING_MODEL_REF]?.alias ?? "Kimi K2.5",
alias: models[KIMI_CODING_MODEL_REF]?.alias ?? "Kimi for Coding",
};
return {
...cfg,
agents: {
...cfg.agents,
defaults: {
...cfg.agents?.defaults,
models,
},
},
};
const defaultModel = buildKimiCodingProvider().models[0];
return applyProviderConfigWithDefaultModel(cfg, {
agentModels: models,
providerId: "kimi-coding",
api: "anthropic-messages",
baseUrl: "https://api.kimi.com/coding/",
defaultModel,
defaultModelId: KIMI_CODING_MODEL_ID,
});
}
export function applyKimiCodeConfig(cfg: OpenClawConfig): OpenClawConfig {