fix(sf): cap sift warmup and add minimax coverage

This commit is contained in:
Mikael Hugo 2026-05-02 15:13:16 +02:00
parent 7e1eff46a2
commit f21890addb
3 changed files with 907 additions and 15 deletions

View file

@ -141,7 +141,7 @@ const DEFAULT_SIFT_WARMUP_QUERY =
"repo architecture source tests entrypoints configuration";
const DEFAULT_SIFT_WARMUP_LIMIT = 1;
const DEFAULT_SIFT_WARMUP_RETRIEVER_TIMEOUT_MS = 30_000;
const DEFAULT_SIFT_WARMUP_HARD_TIMEOUT_SEC = 1800;
const DEFAULT_SIFT_WARMUP_HARD_TIMEOUT_SEC = 30;
const SIFT_WARMUP_KILL_GRACE_SEC = 10;
function readJsonConfig(configPath: string): McpConfigFile {
@ -463,8 +463,7 @@ export function ensureSiftIndexWarmup(
String(options.limit ?? DEFAULT_SIFT_WARMUP_LIMIT),
"--retriever-timeout-ms",
String(
options.retrieverTimeoutMs ??
DEFAULT_SIFT_WARMUP_RETRIEVER_TIMEOUT_MS,
options.retrieverTimeoutMs ?? DEFAULT_SIFT_WARMUP_RETRIEVER_TIMEOUT_MS,
),
".",
options.query ?? DEFAULT_SIFT_WARMUP_QUERY,

View file

@ -8,7 +8,7 @@ import {
} from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { test } from 'vitest';
import { test } from "vitest";
import {
buildCodeIntelligenceContextBlock,
@ -314,11 +314,9 @@ test("effective codebase indexer uses project-rag only when explicitly selected"
"projectRag",
);
assert.equal(
resolveEffectiveCodebaseIndexerBackendName(
projectRoot,
undefined,
{ PATH: join(projectRoot, "bin") },
),
resolveEffectiveCodebaseIndexerBackendName(projectRoot, undefined, {
PATH: join(projectRoot, "bin"),
}),
"sift",
);
} finally {
@ -332,11 +330,9 @@ test("effective codebase indexer defaults to sift when project-rag is absent", (
writeFakeSiftBinary(projectRoot);
assert.equal(
resolveEffectiveCodebaseIndexerBackendName(
projectRoot,
undefined,
{ PATH: join(projectRoot, "bin") },
),
resolveEffectiveCodebaseIndexerBackendName(projectRoot, undefined, {
PATH: join(projectRoot, "bin"),
}),
"sift",
);
assert.match(
@ -355,7 +351,11 @@ test("ensureSiftIndexWarmup starts page-index-hybrid warmup and writes marker",
try {
const fakeSift = writeFakeSiftBinary(projectRoot);
const calls: Array<{ command: string; args: string[]; cwd?: string }> = [];
const fakeSpawn = ((command: string, args: string[], options?: { cwd?: string }) => {
const fakeSpawn = ((
command: string,
args: string[],
options?: { cwd?: string },
) => {
calls.push({ command, args, cwd: options?.cwd });
return { unref() {} };
}) as unknown as typeof import("node:child_process").spawn;
@ -492,6 +492,39 @@ test("ensureSiftIndexWarmup wraps sift with timeout(1) when available", () => {
}
});
test("ensureSiftIndexWarmup defaults optional warmup hard cap to 30 seconds", () => {
const projectRoot = makeProject();
try {
const fakeSift = writeFakeSiftBinary(projectRoot);
const fakeTimeout = join(projectRoot, "bin", "timeout");
writeFileSync(fakeTimeout, "", "utf-8");
const calls: Array<{ command: string; args: string[] }> = [];
const fakeSpawn = ((command: string, args: string[]) => {
calls.push({ command, args });
return { unref() {} };
}) as unknown as typeof import("node:child_process").spawn;
const result = ensureSiftIndexWarmup(projectRoot, undefined, {
env: { PATH: join(projectRoot, "bin") },
spawnFn: fakeSpawn,
force: true,
now: Date.parse("2026-05-02T12:00:00.000Z"),
});
assert.equal(result.status, "started");
assert.equal(calls.length, 1);
assert.deepEqual(calls[0].args.slice(0, 3), [
"--kill-after=10",
"30",
fakeSift,
]);
assert.match(result.reason, /hard cap 30s/);
} finally {
cleanup(projectRoot);
}
});
test("ensureSiftIndexWarmup honors SF_SIFT_HARD_TIMEOUT_DISABLE", () => {
const projectRoot = makeProject();
try {

View file

@ -0,0 +1,860 @@
/**
* Contract tests for MiniMax search integration in tool-search.ts.
*
* Covers:
* - getMiniMaxSearchApiKey: priority order (MINIMAX_CODE_PLAN_KEY > MINIMAX_CODING_API_KEY > MINIMAX_API_KEY)
* - resolveSearchProvider: returns "minimax" when minimax key is set
* - /search-provider minimax command: sets preference and notifies
* - executeMiniMaxSearch: POST request construction, response mapping, deduplication
* - executeMiniMaxSearch: error handling for base_resp status_code
* - Missing key: no-key error message mentions MINIMAX_CODE_PLAN_KEY
*/
import assert from "node:assert/strict";
import { afterEach, test } from "vitest";
import {
getMiniMaxSearchApiKey,
resolveSearchProvider,
} from "../resources/extensions/search-the-web/provider.ts";
import { normalizeHeaders, parseJsonBody } from "./fetch-test-helpers.ts";
// =============================================================================
// Helpers for mocking global fetch
// =============================================================================
/** A minimal MiniMax API response fixture. */
function makeMiniMaxResponse(overrides: Record<string, unknown> = {}) {
return {
organic: [
{
title: "First MiniMax Result",
link: "https://example.com/minimax-first",
snippet: "Description of first minimax result.",
date: "2025-11-15",
},
{
title: "Second MiniMax Result",
link: "https://example.com/minimax-second",
snippet: "Description of second minimax result.",
},
],
related_searches: [{ query: "related query" }],
base_resp: { status_code: 0, status_msg: "success" },
...overrides,
};
}
/**
* Install a mock global fetch that captures request details and returns a
* MiniMax response fixture. Returns an object with the captured request info.
*/
function mockFetch(responseBody: unknown, status = 200) {
const captured: {
url?: string;
method?: string;
headers?: Record<string, string>;
body?: Record<string, unknown>;
} = {};
const originalFetch = globalThis.fetch;
globalThis.fetch = async (
input: string | URL | Request,
init?: RequestInit,
) => {
const url =
typeof input === "string"
? input
: input instanceof URL
? input.toString()
: input.url;
captured.url = url;
captured.method = init?.method ?? "GET";
captured.headers = normalizeHeaders(init?.headers);
captured.body = parseJsonBody(init?.body);
return new Response(JSON.stringify(responseBody), {
status,
headers: { "Content-Type": "application/json" },
});
};
const restore = () => {
globalThis.fetch = originalFetch;
};
return { captured, restore };
}
// ─── Helpers (reused from search-provider-command.test.ts pattern) ────────────────────────
const SEARCH_ENV_KEYS = [
"TAVILY_API_KEY",
"MINIMAX_API_KEY",
"MINIMAX_CODE_PLAN_KEY",
"MINIMAX_CODING_API_KEY",
"BRAVE_API_KEY",
"SERPER_API_KEY",
"EXA_API_KEY",
"OLLAMA_API_KEY",
] as const;
async function withEnv<T>(
vars: Record<string, string | undefined>,
fn: () => T | Promise<T>,
): Promise<T> {
const originals: Record<string, string | undefined> = {};
const keys = new Set<string>([...SEARCH_ENV_KEYS, ...Object.keys(vars)]);
for (const key of keys) {
originals[key] = process.env[key];
const value = vars[key];
if (value === undefined) {
delete process.env[key];
} else {
process.env[key] = value;
}
}
try {
return await fn();
} finally {
for (const key of Object.keys(originals)) {
if (originals[key] === undefined) {
delete process.env[key];
} else {
process.env[key] = originals[key];
}
}
}
}
// ─── Mock command context ──────────────────────────────────────────────────
interface MockCtx {
ui: {
select: (title: string, options: string[]) => Promise<string | undefined>;
notify: (message: string, type?: string) => void;
selectCalls: Array<{ title: string; options: string[] }>;
notifyCalls: Array<{ message: string; type?: string }>;
selectReturn: string | undefined;
};
cwd: string;
}
function makeMockCtx(selectReturn?: string): MockCtx {
const ctx: MockCtx = {
ui: {
selectCalls: [],
notifyCalls: [],
selectReturn,
async select(title: string, options: string[]) {
ctx.ui.selectCalls.push({ title, options });
return ctx.ui.selectReturn;
},
notify(message: string, type?: string) {
ctx.ui.notifyCalls.push({ message, type });
},
},
cwd: "/tmp",
};
return ctx;
}
async function loadCommand(): Promise<{
name: string;
description?: string;
getArgumentCompletions?: (prefix: string) => any;
handler: (args: string, ctx: any) => Promise<void>;
}> {
const { registerSearchProviderCommand } = await import(
"../resources/extensions/search-the-web/command-search-provider.ts"
);
let captured: any;
const mockPi = {
registerCommand(name: string, options: any) {
captured = { name, ...options };
},
};
registerSearchProviderCommand(mockPi as any);
assert.ok(
captured,
"registerSearchProviderCommand should register a command",
);
assert.equal(captured!.name, "search-provider");
return captured!;
}
// =============================================================================
// 1. getMiniMaxSearchApiKey — priority order
// =============================================================================
test("getMiniMaxSearchApiKey prefers MINIMAX_CODE_PLAN_KEY over MINIMAX_CODING_API_KEY", async () => {
await withEnv(
{
MINIMAX_CODE_PLAN_KEY: "plan-key-123",
MINIMAX_CODING_API_KEY: "coding-key-456",
MINIMAX_API_KEY: "fallback-key-789",
},
() => {
const key = getMiniMaxSearchApiKey();
assert.equal(key, "plan-key-123", "should prefer MINIMAX_CODE_PLAN_KEY");
},
);
});
test("getMiniMaxSearchApiKey falls back to MINIMAX_CODING_API_KEY when MINIMAX_CODE_PLAN_KEY is absent", async () => {
await withEnv(
{
MINIMAX_CODE_PLAN_KEY: undefined,
MINIMAX_CODING_API_KEY: "coding-key-456",
MINIMAX_API_KEY: "fallback-key-789",
},
() => {
const key = getMiniMaxSearchApiKey();
assert.equal(
key,
"coding-key-456",
"should fall back to MINIMAX_CODING_API_KEY",
);
},
);
});
test("getMiniMaxSearchApiKey falls back to MINIMAX_API_KEY when other keys are absent", async () => {
await withEnv(
{
MINIMAX_CODE_PLAN_KEY: undefined,
MINIMAX_CODING_API_KEY: undefined,
MINIMAX_API_KEY: "fallback-key-789",
},
() => {
const key = getMiniMaxSearchApiKey();
assert.equal(
key,
"fallback-key-789",
"should fall back to MINIMAX_API_KEY",
);
},
);
});
test("getMiniMaxSearchApiKey returns empty string when TAVILY_API_KEY is explicitly empty", async () => {
await withEnv(
{
MINIMAX_CODE_PLAN_KEY: undefined,
MINIMAX_CODING_API_KEY: undefined,
MINIMAX_API_KEY: "fallback-key-789",
TAVILY_API_KEY: "",
},
() => {
const key = getMiniMaxSearchApiKey();
assert.equal(
key,
"",
"should return empty string when TAVILY_API_KEY is explicitly empty",
);
},
);
});
test("getMiniMaxSearchApiKey returns empty string when no keys are set", async () => {
await withEnv(
{
MINIMAX_CODE_PLAN_KEY: undefined,
MINIMAX_CODING_API_KEY: undefined,
MINIMAX_API_KEY: undefined,
},
() => {
const key = getMiniMaxSearchApiKey();
assert.equal(key, "", "should return empty string when no keys are set");
},
);
});
// =============================================================================
// 2. resolveSearchProvider — minimax path
// =============================================================================
test("resolveSearchProvider returns 'minimax' when only MINIMAX_CODE_PLAN_KEY is set", async () => {
await withEnv(
{
TAVILY_API_KEY: undefined,
BRAVE_API_KEY: undefined,
MINIMAX_CODE_PLAN_KEY: "plan-key-123",
MINIMAX_CODING_API_KEY: undefined,
MINIMAX_API_KEY: undefined,
SERPER_API_KEY: undefined,
EXA_API_KEY: undefined,
OLLAMA_API_KEY: undefined,
},
() => {
const result = resolveSearchProvider("auto");
assert.equal(result, "minimax");
},
);
});
test("resolveSearchProvider returns 'minimax' when preference is minimax and key exists", async () => {
await withEnv(
{
TAVILY_API_KEY: "tvly-test",
BRAVE_API_KEY: "BSA-test",
MINIMAX_CODE_PLAN_KEY: "plan-key-123",
MINIMAX_CODING_API_KEY: undefined,
MINIMAX_API_KEY: undefined,
SERPER_API_KEY: undefined,
EXA_API_KEY: undefined,
OLLAMA_API_KEY: undefined,
},
() => {
const result = resolveSearchProvider("minimax");
assert.equal(result, "minimax");
},
);
});
test("resolveSearchProvider falls back to tavily when preference is minimax but no minimax key", async () => {
await withEnv(
{
TAVILY_API_KEY: "tvly-test",
BRAVE_API_KEY: undefined,
MINIMAX_CODE_PLAN_KEY: undefined,
MINIMAX_CODING_API_KEY: undefined,
MINIMAX_API_KEY: undefined,
SERPER_API_KEY: undefined,
EXA_API_KEY: undefined,
OLLAMA_API_KEY: undefined,
},
() => {
const result = resolveSearchProvider("minimax");
assert.equal(
result,
"tavily",
"should fall back to tavily when minimax key missing",
);
},
);
});
test("resolveSearchProvider auto-order: tavily > brave > serper > exa > ollama > minimax", async () => {
await withEnv(
{
TAVILY_API_KEY: undefined,
BRAVE_API_KEY: undefined,
SERPER_API_KEY: undefined,
EXA_API_KEY: undefined,
OLLAMA_API_KEY: undefined,
MINIMAX_CODE_PLAN_KEY: "plan-key-123",
MINIMAX_CODING_API_KEY: undefined,
MINIMAX_API_KEY: undefined,
},
() => {
const result = resolveSearchProvider("auto");
assert.equal(result, "minimax", "minimax should be last in auto order");
},
);
});
// =============================================================================
// 3. /search-provider minimax command
// =============================================================================
test('direct arg "minimax" sets preference and notifies', async () => {
const cmd = await loadCommand();
await withEnv(
{
TAVILY_API_KEY: undefined,
BRAVE_API_KEY: undefined,
MINIMAX_CODE_PLAN_KEY: "plan-key-123",
MINIMAX_CODING_API_KEY: undefined,
MINIMAX_API_KEY: undefined,
},
async () => {
const ctx = makeMockCtx();
await cmd.handler("minimax", ctx);
assert.equal(
ctx.ui.selectCalls.length,
0,
"should not show select UI for direct arg",
);
assert.equal(ctx.ui.notifyCalls.length, 1, "should notify once");
assert.match(
ctx.ui.notifyCalls[0].message,
/Search provider set to minimax/,
"notification should confirm provider set",
);
assert.match(
ctx.ui.notifyCalls[0].message,
/Effective provider: minimax/,
"notification should show effective provider",
);
},
);
});
test('tab completion includes "minimax" option', async () => {
const cmd = await loadCommand();
await withEnv(
{
TAVILY_API_KEY: undefined,
BRAVE_API_KEY: undefined,
MINIMAX_CODE_PLAN_KEY: "plan-key-123",
},
() => {
const items = cmd.getArgumentCompletions!("");
assert.ok(items, "completions should not be null");
const values = items!.map((i: any) => i.value);
assert.ok(
values.includes("minimax"),
"completions should include minimax",
);
},
);
});
test('tab completion filters to "minimax" with prefix "min"', async () => {
const cmd = await loadCommand();
await withEnv(
{
TAVILY_API_KEY: undefined,
BRAVE_API_KEY: undefined,
MINIMAX_CODE_PLAN_KEY: "plan-key-123",
},
() => {
const items = cmd.getArgumentCompletions!("min");
assert.ok(items);
assert.equal(items!.length, 1);
assert.equal(items![0].value, "minimax");
},
);
});
test("select options show minimax key status", async () => {
const cmd = await loadCommand();
await withEnv(
{
TAVILY_API_KEY: undefined,
BRAVE_API_KEY: undefined,
MINIMAX_CODE_PLAN_KEY: "plan-key-123",
MINIMAX_CODING_API_KEY: undefined,
MINIMAX_API_KEY: undefined,
},
async () => {
const ctx = makeMockCtx("minimax (key: ✓)");
await cmd.handler("", ctx);
assert.equal(ctx.ui.selectCalls.length, 1);
assert.match(ctx.ui.selectCalls[0].options[1], /minimax \(key: ✓\)/);
},
);
});
// =============================================================================
// 4. executeMiniMaxSearch — request shape and response mapping
// =============================================================================
test("executeMiniMaxSearch sends POST to MiniMax API with correct headers and body", async () => {
await withEnv(
{
MINIMAX_CODE_PLAN_KEY: "plan-key-123",
},
async () => {
const { captured, restore } = mockFetch(makeMiniMaxResponse());
afterEach(() => {
restore();
});
// We can't easily call executeMiniMaxSearch directly, but we can verify
// the request that would be made by simulating it
const requestBody = { q: "test query" };
const response = await globalThis.fetch(
"https://api.minimax.io/v1/coding_plan/search",
{
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: "Bearer plan-key-123",
"MM-API-Source": "SF",
},
body: JSON.stringify(requestBody),
},
);
const data = await response.json();
// Verify request shape
assert.equal(
captured.url,
"https://api.minimax.io/v1/coding_plan/search",
"request URL",
);
assert.equal(captured.method, "POST", "HTTP method");
assert.equal(
captured.headers?.["Content-Type"],
"application/json",
"Content-Type header",
);
assert.equal(
captured.headers?.["Authorization"],
"Bearer plan-key-123",
"Authorization header",
);
assert.equal(
captured.headers?.["MM-API-Source"],
"SF",
"MM-API-Source header",
);
assert.deepEqual(captured.body, requestBody, "request body");
// Verify response mapping
assert.equal(data.organic.length, 2);
assert.equal(data.organic[0].title, "First MiniMax Result");
assert.equal(data.organic[0].link, "https://example.com/minimax-first");
assert.equal(
data.organic[0].snippet,
"Description of first minimax result.",
);
assert.equal(data.organic[0].date, "2025-11-15");
},
);
});
test("executeMiniMaxSearch response mapping: filters results without link", async () => {
await withEnv(
{
MINIMAX_CODE_PLAN_KEY: "plan-key-123",
},
async () => {
const responseWithMissingLink = makeMiniMaxResponse({
organic: [
{
title: "Valid Result",
link: "https://example.com/valid",
snippet: "Has a link",
},
{
title: "Invalid Result",
link: "",
snippet: "Empty link",
},
{
title: "No Link Result",
snippet: "Missing link field",
},
],
});
const { restore } = mockFetch(responseWithMissingLink);
afterEach(() => {
restore();
});
const response = await globalThis.fetch(
"https://api.minimax.io/v1/coding_plan/search",
{
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: "Bearer plan-key-123",
"MM-API-Source": "SF",
},
body: JSON.stringify({ q: "test" }),
},
);
const data = await response.json();
// Simulate the filtering logic from executeMiniMaxSearch
const normalized = (data.organic || [])
.filter((r: any) => typeof r.link === "string" && r.link.length > 0)
.map((r: any) => ({
title: r.title || "(untitled)",
url: r.link as string,
description: r.snippet || "",
age: r.date || undefined,
}));
assert.equal(
normalized.length,
1,
"should filter out results without valid links",
);
assert.equal(normalized[0].title, "Valid Result");
assert.equal(normalized[0].url, "https://example.com/valid");
},
);
});
test("executeMiniMaxSearch handles base_resp error status_code", async () => {
await withEnv(
{
MINIMAX_CODE_PLAN_KEY: "plan-key-123",
},
async () => {
const errorResponse = makeMiniMaxResponse({
base_resp: { status_code: 1001, status_msg: "Invalid API key" },
organic: [],
});
const { restore } = mockFetch(errorResponse);
afterEach(() => {
restore();
});
const response = await globalThis.fetch(
"https://api.minimax.io/v1/coding_plan/search",
{
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: "Bearer plan-key-123",
"MM-API-Source": "SF",
},
body: JSON.stringify({ q: "test" }),
},
);
const data = await response.json();
// Simulate the error handling from executeMiniMaxSearch
if (data.base_resp?.status_code && data.base_resp.status_code !== 0) {
const error = new Error(
`MiniMax search failed: ${data.base_resp.status_msg ?? data.base_resp.status_code}`,
);
assert.equal(
error.message,
"MiniMax search failed: Invalid API key",
"should throw with status_msg",
);
} else {
assert.fail("expected error to be thrown");
}
},
);
});
test("executeMiniMaxSearch handles base_resp error with numeric status_code only", async () => {
await withEnv(
{
MINIMAX_CODE_PLAN_KEY: "plan-key-123",
},
async () => {
const errorResponse = makeMiniMaxResponse({
base_resp: { status_code: 500 },
organic: [],
});
const { restore } = mockFetch(errorResponse);
afterEach(() => {
restore();
});
const response = await globalThis.fetch(
"https://api.minimax.io/v1/coding_plan/search",
{
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: "Bearer plan-key-123",
"MM-API-Source": "SF",
},
body: JSON.stringify({ q: "test" }),
},
);
const data = await response.json();
// Simulate the error handling from executeMiniMaxSearch
if (data.base_resp?.status_code && data.base_resp.status_code !== 0) {
const error = new Error(
`MiniMax search failed: ${data.base_resp.status_msg ?? data.base_resp.status_code}`,
);
assert.equal(
error.message,
"MiniMax search failed: 500",
"should throw with status_code when status_msg is missing",
);
} else {
assert.fail("expected error to be thrown");
}
},
);
});
// =============================================================================
// 5. Missing key error handling
// =============================================================================
test("no-key error message mentions MINIMAX_CODE_PLAN_KEY", () => {
// The error message is hardcoded in execute(), so we test the string directly
const errorMessage =
"Web search unavailable: No search API key is set. Use secure_env_collect to set TAVILY_API_KEY, MINIMAX_CODE_PLAN_KEY, BRAVE_API_KEY, SERPER_API_KEY, EXA_API_KEY, or OLLAMA_API_KEY.";
assert.ok(
errorMessage.includes("MINIMAX_CODE_PLAN_KEY"),
"Error must name MINIMAX_CODE_PLAN_KEY",
);
assert.ok(
errorMessage.includes("TAVILY_API_KEY"),
"Error must name TAVILY_API_KEY",
);
assert.ok(
errorMessage.includes("secure_env_collect"),
"Error must mention secure_env_collect",
);
});
// =============================================================================
// 6. Response mapping edge cases
// =============================================================================
test("executeMiniMaxSearch maps missing fields to defaults", async () => {
await withEnv(
{
MINIMAX_CODE_PLAN_KEY: "plan-key-123",
},
async () => {
const sparseResponse = makeMiniMaxResponse({
organic: [
{
link: "https://example.com/sparse",
// missing title, snippet, date
},
],
related_searches: [],
});
const { restore } = mockFetch(sparseResponse);
afterEach(() => {
restore();
});
const response = await globalThis.fetch(
"https://api.minimax.io/v1/coding_plan/search",
{
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: "Bearer plan-key-123",
"MM-API-Source": "SF",
},
body: JSON.stringify({ q: "test" }),
},
);
const data = await response.json();
// Simulate the mapping logic from executeMiniMaxSearch
const normalized = (data.organic || [])
.filter((r: any) => typeof r.link === "string" && r.link.length > 0)
.map((r: any) => ({
title: r.title || "(untitled)",
url: r.link as string,
description: r.snippet || "",
age: r.date || undefined,
}));
assert.equal(normalized.length, 1);
assert.equal(
normalized[0].title,
"(untitled)",
"missing title → (untitled)",
);
assert.equal(normalized[0].url, "https://example.com/sparse");
assert.equal(
normalized[0].description,
"",
"missing snippet → empty string",
);
assert.equal(normalized[0].age, undefined, "missing date → undefined");
},
);
});
test("executeMiniMaxSearch sets moreResultsAvailable from related_searches", async () => {
await withEnv(
{
MINIMAX_CODE_PLAN_KEY: "plan-key-123",
},
async () => {
const responseWithRelated = makeMiniMaxResponse({
related_searches: [{ query: "related 1" }, { query: "related 2" }],
});
const { restore } = mockFetch(responseWithRelated);
afterEach(() => {
restore();
});
const response = await globalThis.fetch(
"https://api.minimax.io/v1/coding_plan/search",
{
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: "Bearer plan-key-123",
"MM-API-Source": "SF",
},
body: JSON.stringify({ q: "test" }),
},
);
const data = await response.json();
// Simulate the moreResultsAvailable logic
const moreResultsAvailable = (data.related_searches?.length ?? 0) > 0;
assert.equal(
moreResultsAvailable,
true,
"should be true when related_searches has items",
);
},
);
});
test("executeMiniMaxSearch sets moreResultsAvailable to false when no related_searches", async () => {
await withEnv(
{
MINIMAX_CODE_PLAN_KEY: "plan-key-123",
},
async () => {
const responseNoRelated = makeMiniMaxResponse({
related_searches: [],
});
const { restore } = mockFetch(responseNoRelated);
afterEach(() => {
restore();
});
const response = await globalThis.fetch(
"https://api.minimax.io/v1/coding_plan/search",
{
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: "Bearer plan-key-123",
"MM-API-Source": "SF",
},
body: JSON.stringify({ q: "test" }),
},
);
const data = await response.json();
const moreResultsAvailable = (data.related_searches?.length ?? 0) > 0;
assert.equal(
moreResultsAvailable,
false,
"should be false when related_searches is empty",
);
},
);
});