Files
openclaw/extensions/fireworks/index.test.ts
Evgeni Obuchowski 9d9389bc6b fix(fireworks): resolve catalog model params from manifest (#90326)
Resolve bundled Fireworks manifest models through core's static catalog so Kimi K2.6 keeps its 262,144-token context limit and nested model compatibility metadata.

Keep the existing dynamic fallback for uncataloged Fireworks IDs and align bundled Kimi reasoning metadata with existing runtime behavior.

Verified with focused tests, extension/core type checks, lint/format, full build, fresh autoreview, required CI, and a live Fireworks Kimi K2.6 embedded run using a real key.

Co-authored-by: Evgeni Obuchowski <evgeni@obukhovski.com>
2026-06-12 22:48:46 -07:00

200 lines
7.2 KiB
TypeScript

// Fireworks tests cover index plugin behavior.
import type { ProviderRuntimeModel } from "openclaw/plugin-sdk/plugin-entry";
import {
registerSingleProviderPlugin,
resolveProviderPluginChoice,
} from "openclaw/plugin-sdk/plugin-test-runtime";
import { describe, expect, it } from "vitest";
import {
createProviderDynamicModelContext,
runSingleProviderCatalog,
} from "../test-support/provider-model-test-helpers.js";
import fireworksPlugin from "./index.js";
import {
FIREWORKS_BASE_URL,
FIREWORKS_DEFAULT_CONTEXT_WINDOW,
FIREWORKS_DEFAULT_MAX_TOKENS,
FIREWORKS_DEFAULT_MODEL_ID,
FIREWORKS_K2_6_CONTEXT_WINDOW,
FIREWORKS_K2_6_MAX_TOKENS,
FIREWORKS_K2_6_MODEL_ID,
} from "./provider-catalog.js";
import { resolveThinkingProfile } from "./provider-policy-api.js";
function createFireworksDefaultRuntimeModel(params: { reasoning: boolean }): ProviderRuntimeModel {
return {
id: FIREWORKS_DEFAULT_MODEL_ID,
name: FIREWORKS_DEFAULT_MODEL_ID,
provider: "fireworks",
api: "openai-completions",
baseUrl: FIREWORKS_BASE_URL,
reasoning: params.reasoning,
input: ["text", "image"],
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
contextWindow: FIREWORKS_DEFAULT_CONTEXT_WINDOW,
maxTokens: FIREWORKS_DEFAULT_MAX_TOKENS,
};
}
describe("fireworks provider plugin", () => {
it("registers Fireworks with api-key auth wizard metadata", async () => {
const provider = await registerSingleProviderPlugin(fireworksPlugin);
const resolved = resolveProviderPluginChoice({
providers: [provider],
choice: "fireworks-api-key",
});
expect(provider.id).toBe("fireworks");
expect(provider.label).toBe("Fireworks");
expect(provider.aliases).toEqual(["fireworks-ai"]);
expect(provider.envVars).toEqual(["FIREWORKS_API_KEY"]);
expect(provider.auth).toHaveLength(1);
if (!resolved) {
throw new Error("expected Fireworks api-key auth choice");
}
expect(resolved.provider.id).toBe("fireworks");
expect(resolved.method.id).toBe("api-key");
});
it("builds the Fireworks catalog", async () => {
const provider = await registerSingleProviderPlugin(fireworksPlugin);
const catalogProvider = await runSingleProviderCatalog(provider);
expect(catalogProvider.api).toBe("openai-completions");
expect(catalogProvider.baseUrl).toBe(FIREWORKS_BASE_URL);
const models = catalogProvider.models;
if (!models) {
throw new Error("expected Fireworks catalog models");
}
expect(models.map((model) => model.id)).toEqual([
FIREWORKS_K2_6_MODEL_ID,
FIREWORKS_DEFAULT_MODEL_ID,
]);
expect(models[0]?.reasoning).toBe(false);
expect(models[0]?.input).toEqual(["text", "image"]);
expect(models[0]?.contextWindow).toBe(FIREWORKS_K2_6_CONTEXT_WINDOW);
expect(models[0]?.maxTokens).toBe(FIREWORKS_K2_6_MAX_TOKENS);
expect(models[1]?.reasoning).toBe(false);
expect(models[1]?.input).toEqual(["text", "image"]);
expect(models[1]?.contextWindow).toBe(FIREWORKS_DEFAULT_CONTEXT_WINDOW);
expect(models[1]?.maxTokens).toBe(FIREWORKS_DEFAULT_MAX_TOKENS);
});
it("resolves forward-compat Fireworks model ids from the default template", async () => {
const provider = await registerSingleProviderPlugin(fireworksPlugin);
const resolved = provider.resolveDynamicModel?.(
createProviderDynamicModelContext({
provider: "fireworks",
modelId: "accounts/fireworks/models/qwen3.6-plus",
models: [createFireworksDefaultRuntimeModel({ reasoning: true })],
}),
);
expect(resolved?.provider).toBe("fireworks");
expect(resolved?.id).toBe("accounts/fireworks/models/qwen3.6-plus");
expect(resolved?.api).toBe("openai-completions");
expect(resolved?.baseUrl).toBe(FIREWORKS_BASE_URL);
expect(resolved?.reasoning).toBe(true);
expect(resolved?.input).toEqual(["text", "image"]);
});
it("disables reasoning metadata for Fireworks Kimi dynamic models", async () => {
const provider = await registerSingleProviderPlugin(fireworksPlugin);
const resolved = provider.resolveDynamicModel?.(
createProviderDynamicModelContext({
provider: "fireworks",
modelId: "accounts/fireworks/models/kimi-k2p5",
models: [createFireworksDefaultRuntimeModel({ reasoning: false })],
}),
);
expect(resolved?.provider).toBe("fireworks");
expect(resolved?.id).toBe("accounts/fireworks/models/kimi-k2p5");
expect(resolved?.reasoning).toBe(false);
expect(resolved?.input).toEqual(["text", "image"]);
});
it("keeps Fireworks GLM dynamic models text-only", async () => {
const provider = await registerSingleProviderPlugin(fireworksPlugin);
const resolved = provider.resolveDynamicModel?.(
createProviderDynamicModelContext({
provider: "fireworks",
modelId: "accounts/fireworks/models/glm-5p1",
models: [createFireworksDefaultRuntimeModel({ reasoning: false })],
}),
);
expect(resolved?.provider).toBe("fireworks");
expect(resolved?.id).toBe("accounts/fireworks/models/glm-5p1");
expect(resolved?.input).toEqual(["text"]);
});
it("disables reasoning metadata for Fireworks Kimi k2.5 aliases", async () => {
const provider = await registerSingleProviderPlugin(fireworksPlugin);
const resolved = provider.resolveDynamicModel?.(
createProviderDynamicModelContext({
provider: "fireworks",
modelId: "accounts/fireworks/routers/kimi-k2.5-turbo",
models: [createFireworksDefaultRuntimeModel({ reasoning: false })],
}),
);
expect(resolved?.provider).toBe("fireworks");
expect(resolved?.id).toBe("accounts/fireworks/routers/kimi-k2.5-turbo");
expect(resolved?.reasoning).toBe(false);
});
it("defers manifest catalog models to core static-catalog resolution", async () => {
const provider = await registerSingleProviderPlugin(fireworksPlugin);
for (const modelId of [FIREWORKS_K2_6_MODEL_ID, FIREWORKS_DEFAULT_MODEL_ID]) {
const resolved = provider.resolveDynamicModel?.(
createProviderDynamicModelContext({
provider: "fireworks",
modelId,
models: [createFireworksDefaultRuntimeModel({ reasoning: false })],
}),
);
expect(resolved).toBeUndefined();
}
});
it("exposes off-only thinking policy for Fireworks Kimi models", async () => {
const provider = await registerSingleProviderPlugin(fireworksPlugin);
expect(
provider.resolveThinkingProfile?.({
provider: "fireworks",
modelId: "accounts/fireworks/routers/kimi-k2p5-turbo",
}),
).toEqual({
levels: [{ id: "off" }],
defaultLevel: "off",
});
expect(
provider.resolveThinkingProfile?.({
provider: "fireworks",
modelId: FIREWORKS_K2_6_MODEL_ID,
}),
).toEqual({
levels: [{ id: "off" }],
defaultLevel: "off",
});
expect(
provider.resolveThinkingProfile?.({
provider: "fireworks",
modelId: "accounts/fireworks/models/qwen3.6-plus",
}),
).toBeUndefined();
expect(resolveThinkingProfile({ modelId: FIREWORKS_K2_6_MODEL_ID })).toEqual({
levels: [{ id: "off" }],
defaultLevel: "off",
});
expect(
resolveThinkingProfile({
modelId: "accounts/fireworks/models/qwen3.6-plus",
}),
).toBeUndefined();
});
});