test: tighten mistral media and onboarding coverage

This commit is contained in:
Peter Steinberger
2026-02-23 00:18:49 +00:00
parent 8a8faf066e
commit 60c494c024
5 changed files with 153 additions and 36 deletions

View File

@@ -5,7 +5,9 @@ import { resolveMemorySearchConfig } from "./memory-search.js";
const asConfig = (cfg: OpenClawConfig): OpenClawConfig => cfg;
describe("memory search config", () => {
function configWithDefaultProvider(provider: "openai" | "local" | "gemini"): OpenClawConfig {
function configWithDefaultProvider(
provider: "openai" | "local" | "gemini" | "mistral",
): OpenClawConfig {
return asConfig({
agents: {
defaults: {
@@ -147,6 +149,13 @@ describe("memory search config", () => {
expectDefaultRemoteBatch(resolved);
});
it("includes remote defaults and model default for mistral without overrides", () => {
const cfg = configWithDefaultProvider("mistral");
const resolved = resolveMemorySearchConfig(cfg, "main");
expectDefaultRemoteBatch(resolved);
expect(resolved?.model).toBe("mistral-embed");
});
it("defaults session delta thresholds", () => {
const cfg = asConfig({
agents: {

View File

@@ -14,7 +14,12 @@ vi.mock("../../commands/auth-choice-options.js", () => ({
}));
vi.mock("../../commands/onboard-provider-auth-flags.js", () => ({
ONBOARD_PROVIDER_AUTH_FLAGS: [] as Array<{ cliOption: string; description: string }>,
ONBOARD_PROVIDER_AUTH_FLAGS: [
{
cliOption: "--mistral-api-key <key>",
description: "Mistral API key",
},
] as Array<{ cliOption: string; description: string }>,
}));
vi.mock("../../commands/onboard.js", () => ({
@@ -103,6 +108,16 @@ describe("registerOnboardCommand", () => {
);
});
it("parses --mistral-api-key and forwards mistralApiKey", async () => {
await runCli(["onboard", "--mistral-api-key", "sk-mistral-test"]);
expect(onboardCommandMock).toHaveBeenCalledWith(
expect.objectContaining({
mistralApiKey: "sk-mistral-test",
}),
runtime,
);
});
it("reports errors via runtime on onboard command failures", async () => {
onboardCommandMock.mockRejectedValueOnce(new Error("onboard failed"));

View File

@@ -45,4 +45,56 @@ describe("live tool probe utils", () => {
}),
).toBe(false);
});
it("retries when tool output is empty and attempts remain", () => {
expect(
shouldRetryToolReadProbe({
text: " ",
nonceA: "nonce-a",
nonceB: "nonce-b",
provider: "openai",
attempt: 0,
maxAttempts: 3,
}),
).toBe(true);
});
it("retries when output still looks like tool/function scaffolding", () => {
expect(
shouldRetryToolReadProbe({
text: "Use tool function read[] now.",
nonceA: "nonce-a",
nonceB: "nonce-b",
provider: "openai",
attempt: 0,
maxAttempts: 3,
}),
).toBe(true);
});
it("retries mistral nonce marker echoes without parsed nonce values", () => {
expect(
shouldRetryToolReadProbe({
text: "nonceA= nonceB=",
nonceA: "nonce-a",
nonceB: "nonce-b",
provider: "mistral",
attempt: 0,
maxAttempts: 3,
}),
).toBe(true);
});
it("does not retry nonce marker echoes for non-mistral providers", () => {
expect(
shouldRetryToolReadProbe({
text: "nonceA= nonceB=",
nonceA: "nonce-a",
nonceB: "nonce-b",
provider: "openai",
attempt: 0,
maxAttempts: 3,
}),
).toBe(false);
});
});

View File

@@ -109,47 +109,69 @@ describe("runCapability auto audio entries", () => {
});
it("uses mistral when only mistral key is configured", async () => {
const priorEnv: Record<string, string | undefined> = {
OPENAI_API_KEY: process.env.OPENAI_API_KEY,
GROQ_API_KEY: process.env.GROQ_API_KEY,
DEEPGRAM_API_KEY: process.env.DEEPGRAM_API_KEY,
GEMINI_API_KEY: process.env.GEMINI_API_KEY,
MISTRAL_API_KEY: process.env.MISTRAL_API_KEY,
};
delete process.env.OPENAI_API_KEY;
delete process.env.GROQ_API_KEY;
delete process.env.DEEPGRAM_API_KEY;
delete process.env.GEMINI_API_KEY;
process.env.MISTRAL_API_KEY = "mistral-test-key";
let runResult: Awaited<ReturnType<typeof runCapability>> | undefined;
await withAudioFixture("openclaw-auto-audio-mistral", async ({ ctx, media, cache }) => {
const providerRegistry = buildProviderRegistry({
openai: {
id: "openai",
capabilities: ["audio"],
transcribeAudio: async () => ({ text: "openai", model: "gpt-4o-mini-transcribe" }),
},
mistral: {
id: "mistral",
capabilities: ["audio"],
transcribeAudio: async (req) => ({ text: "mistral", model: req.model ?? "unknown" }),
},
});
const cfg = {
models: {
providers: {
mistral: {
apiKey: "mistral-test-key",
models: [],
try {
await withAudioFixture("openclaw-auto-audio-mistral", async ({ ctx, media, cache }) => {
const providerRegistry = buildProviderRegistry({
openai: {
id: "openai",
capabilities: ["audio"],
transcribeAudio: async () => ({ text: "openai", model: "gpt-4o-mini-transcribe" }),
},
mistral: {
id: "mistral",
capabilities: ["audio"],
transcribeAudio: async (req) => ({ text: "mistral", model: req.model ?? "unknown" }),
},
});
const cfg = {
models: {
providers: {
mistral: {
apiKey: "mistral-test-key",
models: [],
},
},
},
},
tools: {
media: {
audio: {
enabled: true,
tools: {
media: {
audio: {
enabled: true,
},
},
},
},
} as unknown as OpenClawConfig;
} as unknown as OpenClawConfig;
runResult = await runCapability({
capability: "audio",
cfg,
ctx,
attachments: cache,
media,
providerRegistry,
runResult = await runCapability({
capability: "audio",
cfg,
ctx,
attachments: cache,
media,
providerRegistry,
});
});
});
} finally {
for (const [key, value] of Object.entries(priorEnv)) {
if (value === undefined) {
delete process.env[key];
} else {
process.env[key] = value;
}
}
}
if (!runResult) {
throw new Error("Expected auto audio mistral result");
}

View File

@@ -0,0 +1,19 @@
import { describe, expect, it } from "vitest";
import { DEFAULT_MISTRAL_EMBEDDING_MODEL, normalizeMistralModel } from "./embeddings-mistral.js";
describe("normalizeMistralModel", () => {
it("returns the default model for empty values", () => {
expect(normalizeMistralModel("")).toBe(DEFAULT_MISTRAL_EMBEDDING_MODEL);
expect(normalizeMistralModel(" ")).toBe(DEFAULT_MISTRAL_EMBEDDING_MODEL);
});
it("strips the mistral/ prefix", () => {
expect(normalizeMistralModel("mistral/mistral-embed")).toBe("mistral-embed");
expect(normalizeMistralModel(" mistral/custom-embed ")).toBe("custom-embed");
});
it("keeps explicit non-prefixed models", () => {
expect(normalizeMistralModel("mistral-embed")).toBe("mistral-embed");
expect(normalizeMistralModel("custom-embed-v2")).toBe("custom-embed-v2");
});
});