test(agents): add comprehensive kimi regressions

This commit is contained in:
Peter Steinberger
2026-02-23 17:37:16 +00:00
parent daaad03593
commit 2fa6aa6ea6
4 changed files with 316 additions and 5 deletions

View File

@@ -62,6 +62,51 @@ function stubMinimaxOkFetch() {
return fetch;
}
function stubOpenAiCompletionsOkFetch(text = "ok") {
const fetch = vi.fn().mockResolvedValue(
new Response(
new ReadableStream<Uint8Array>({
start(controller) {
const encoder = new TextEncoder();
const chunks = [
`data: ${JSON.stringify({
id: "chatcmpl-moonshot-test",
object: "chat.completion.chunk",
created: Math.floor(Date.now() / 1000),
model: "kimi-k2.5",
choices: [
{
index: 0,
delta: { role: "assistant", content: text },
finish_reason: null,
},
],
})}\n\n`,
`data: ${JSON.stringify({
id: "chatcmpl-moonshot-test",
object: "chat.completion.chunk",
created: Math.floor(Date.now() / 1000),
model: "kimi-k2.5",
choices: [{ index: 0, delta: {}, finish_reason: "stop" }],
})}\n\n`,
"data: [DONE]\n\n",
];
for (const chunk of chunks) {
controller.enqueue(encoder.encode(chunk));
}
controller.close();
},
}),
{
status: 200,
headers: { "content-type": "text/event-stream" },
},
),
);
global.fetch = withFetchPreconnect(fetch);
return fetch;
}
function createMinimaxImageConfig(): OpenClawConfig {
return {
agents: {
@@ -270,6 +315,71 @@ describe("image tool implicit imageModel config", () => {
});
});
it("sends moonshot image requests with user+image payloads only", async () => {
await withTempAgentDir(async (agentDir) => {
vi.stubEnv("MOONSHOT_API_KEY", "moonshot-test");
const fetch = stubOpenAiCompletionsOkFetch("ok moonshot");
const cfg: OpenClawConfig = {
agents: {
defaults: {
model: { primary: "moonshot/kimi-k2.5" },
imageModel: { primary: "moonshot/kimi-k2.5" },
},
},
models: {
providers: {
moonshot: {
api: "openai-completions",
baseUrl: "https://api.moonshot.ai/v1",
models: [makeModelDefinition("kimi-k2.5", ["text", "image"])],
},
},
},
};
const tool = requireImageTool(createImageTool({ config: cfg, agentDir }));
const result = await tool.execute("t1", {
prompt: "Describe this image in one word.",
image: `data:image/png;base64,${ONE_PIXEL_PNG_B64}`,
});
expect(fetch).toHaveBeenCalledTimes(1);
const [url, init] = fetch.mock.calls[0] as [unknown, { body?: unknown }];
expect(String(url)).toBe("https://api.moonshot.ai/v1/chat/completions");
expect(typeof init?.body).toBe("string");
const bodyRaw = typeof init?.body === "string" ? init.body : "";
const payload = JSON.parse(bodyRaw) as {
messages?: Array<{
role?: string;
content?: Array<{
type?: string;
text?: string;
image_url?: { url?: string };
}>;
}>;
};
expect(payload.messages?.map((message) => message.role)).toEqual(["user"]);
const userContent = payload.messages?.[0]?.content ?? [];
expect(userContent).toEqual(
expect.arrayContaining([
expect.objectContaining({
type: "text",
text: "Describe this image in one word.",
}),
expect.objectContaining({ type: "image_url" }),
]),
);
expect(userContent.find((block) => block.type === "image_url")?.image_url?.url).toContain(
"data:image/png;base64,",
);
expect(bodyRaw).not.toContain('"role":"developer"');
expect(result.content).toEqual(
expect.arrayContaining([expect.objectContaining({ type: "text", text: "ok moonshot" })]),
);
});
});
it("exposes an Anthropic-safe image schema without union keywords", async () => {
const agentDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-image-"));
try {