mirror of https://github.com/openclaw/openclaw.git
fix: keep Kimi anthropic tool payloads native (#60391) (thanks @Eric-Guo)
This commit is contained in:
parent
41e16a883b
commit
d7b8faa7bf
|
|
@ -118,6 +118,7 @@ Docs: https://docs.openclaw.ai
|
|||
- Plugins/media understanding: enable bundled Groq and Deepgram providers by default so configured audio transcription models load without extra plugin activation config. (#59982) Thanks @yxjsxy.
|
||||
- Providers/OpenAI Codex: add forward-compat `openai-codex/gpt-5.4-mini` synthesis across provider runtime, model catalog, and model listing so Codex mini works before bundled Pi catalog updates land.
|
||||
- Plugins/marketplace: block remote marketplace symlink escapes without rewriting ordinary local marketplace install paths. (#60556) Thanks @eleqtrizit.
|
||||
- Plugins/Kimi Coding: keep native Anthropic tool payloads on the Kimi coding endpoint while still parsing tagged tool-call text on the response path, so tool calls execute again instead of echoing raw markup. (#60391) Thanks @Eric-Guo.
|
||||
|
||||
## 2026.4.2
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry";
|
|||
import { createProviderApiKeyAuthMethod } from "openclaw/plugin-sdk/provider-auth-api-key";
|
||||
import { applyKimiCodeConfig, KIMI_CODING_MODEL_REF } from "./onboard.js";
|
||||
import { buildKimiCodingProvider } from "./provider-catalog.js";
|
||||
import { wrapKimiProviderStream } from "./stream.js";
|
||||
import { createKimiToolCallMarkupWrapper } from "./stream.js";
|
||||
|
||||
const PLUGIN_ID = "kimi";
|
||||
const PROVIDER_ID = "kimi";
|
||||
|
|
@ -87,7 +87,7 @@ export default definePluginEntry({
|
|||
},
|
||||
},
|
||||
buildReplayPolicy: () => buildKimiReplayPolicy(),
|
||||
wrapStreamFn: (ctx) => wrapKimiProviderStream(ctx.streamFn),
|
||||
wrapStreamFn: (ctx) => createKimiToolCallMarkupWrapper(ctx.streamFn),
|
||||
});
|
||||
},
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import type { StreamFn } from "@mariozechner/pi-agent-core";
|
||||
import { streamSimple } from "@mariozechner/pi-ai";
|
||||
import { createOpenAIAnthropicToolPayloadCompatibilityWrapper } from "openclaw/plugin-sdk/provider-stream";
|
||||
|
||||
const TOOL_CALLS_SECTION_BEGIN = "<|tool_calls_section_begin|>";
|
||||
const TOOL_CALLS_SECTION_END = "<|tool_calls_section_end|>";
|
||||
|
|
@ -180,9 +179,3 @@ export function createKimiToolCallMarkupWrapper(baseStreamFn: StreamFn | undefin
|
|||
return wrapKimiTaggedToolCalls(maybeStream);
|
||||
};
|
||||
}
|
||||
|
||||
export function wrapKimiProviderStream(baseStreamFn: StreamFn | undefined): StreamFn {
|
||||
return createKimiToolCallMarkupWrapper(
|
||||
createOpenAIAnthropicToolPayloadCompatibilityWrapper(baseStreamFn),
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,10 +54,7 @@ import {
|
|||
resolveExtraParams,
|
||||
resolvePreparedExtraParams,
|
||||
} from "./pi-embedded-runner.js";
|
||||
import {
|
||||
createAnthropicToolPayloadCompatibilityWrapper,
|
||||
createOpenAIAnthropicToolPayloadCompatibilityWrapper,
|
||||
} from "./pi-embedded-runner/anthropic-family-tool-payload-compat.js";
|
||||
import { createAnthropicToolPayloadCompatibilityWrapper } from "./pi-embedded-runner/anthropic-family-tool-payload-compat.js";
|
||||
import {
|
||||
createBedrockNoCacheWrapper,
|
||||
isAnthropicBedrockModel,
|
||||
|
|
@ -164,8 +161,14 @@ beforeEach(() => {
|
|||
params.context.thinkingLevel,
|
||||
);
|
||||
}
|
||||
if (params.provider === "test-anthropic-tool-compat") {
|
||||
return createAnthropicToolPayloadCompatibilityWrapper(params.context.streamFn, {
|
||||
toolSchemaMode: "openai-functions",
|
||||
toolChoiceMode: "openai-string-modes",
|
||||
});
|
||||
}
|
||||
if (params.provider === "kimi") {
|
||||
return createOpenAIAnthropicToolPayloadCompatibilityWrapper(params.context.streamFn);
|
||||
return params.context.streamFn;
|
||||
}
|
||||
if (params.provider === "minimax" || params.provider === "minimax-portal") {
|
||||
return createMinimaxFastModeWrapper(
|
||||
|
|
@ -1222,7 +1225,7 @@ describe("applyExtraParamsToAgent", () => {
|
|||
});
|
||||
});
|
||||
|
||||
it("rewrites anthropic tool payloads for Kimi", () => {
|
||||
it("keeps anthropic tool payloads native for Kimi", () => {
|
||||
const payloads: Record<string, unknown>[] = [];
|
||||
const baseStreamFn: StreamFn = (_model, _context, options) => {
|
||||
const payload: Record<string, unknown> = {
|
||||
|
|
@ -1259,22 +1262,16 @@ describe("applyExtraParamsToAgent", () => {
|
|||
expect(payloads).toHaveLength(1);
|
||||
expect(payloads[0]?.tools).toEqual([
|
||||
{
|
||||
type: "function",
|
||||
function: {
|
||||
name: "read",
|
||||
description: "Read file",
|
||||
parameters: {
|
||||
type: "object",
|
||||
properties: { path: { type: "string" } },
|
||||
required: ["path"],
|
||||
},
|
||||
name: "read",
|
||||
description: "Read file",
|
||||
input_schema: {
|
||||
type: "object",
|
||||
properties: { path: { type: "string" } },
|
||||
required: ["path"],
|
||||
},
|
||||
},
|
||||
]);
|
||||
expect(payloads[0]?.tool_choice).toEqual({
|
||||
type: "function",
|
||||
function: { name: "read" },
|
||||
});
|
||||
expect(payloads[0]?.tool_choice).toEqual({ type: "tool", name: "read" });
|
||||
});
|
||||
|
||||
it("does not rewrite anthropic tool schema for non-kimi endpoints", () => {
|
||||
|
|
@ -1377,11 +1374,18 @@ describe("applyExtraParamsToAgent", () => {
|
|||
};
|
||||
const agent = { streamFn: baseStreamFn };
|
||||
|
||||
applyExtraParamsToAgent(agent, undefined, "kimi", "proxy-model", undefined, "low");
|
||||
applyExtraParamsToAgent(
|
||||
agent,
|
||||
undefined,
|
||||
"test-anthropic-tool-compat",
|
||||
"proxy-model",
|
||||
undefined,
|
||||
"low",
|
||||
);
|
||||
|
||||
const model = {
|
||||
api: "anthropic-messages",
|
||||
provider: "kimi",
|
||||
provider: "test-anthropic-tool-compat",
|
||||
id: "proxy-model",
|
||||
} as Model<"anthropic-messages">;
|
||||
const context: Context = { messages: [] };
|
||||
|
|
|
|||
Loading…
Reference in New Issue