mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-12 21:53:00 -06:00
refactor(deadcode): tighten provider extension roots (#108497)
This commit is contained in:
committed by
GitHub
parent
9e64fbb257
commit
370b80b74d
@@ -52,12 +52,23 @@ const bundledPluginEntries = [
|
||||
"*.ts!",
|
||||
"index.ts!",
|
||||
"setup-entry.ts!",
|
||||
// Core resolves these public plugin artifacts by basename rather than by a
|
||||
// static import from the plugin entry module.
|
||||
"*-api.ts!",
|
||||
"cli-metadata.ts!",
|
||||
"channel-entry.ts!",
|
||||
// Provider catalogs and web tools resolve these manifest/convention-owned
|
||||
// modules from the plugin root at runtime.
|
||||
"provider-discovery.ts!",
|
||||
"{web-search,web-fetch}-provider.ts!",
|
||||
"{api,contract-api,helper-api,runtime-api,light-runtime-api,update-offset-runtime-api,channel-plugin-api,provider-plugin-api,setup-api}.ts!",
|
||||
"subagent-hooks-api.ts!",
|
||||
"src/{api,runtime-api,light-runtime-api,update-offset-runtime-api,channel-plugin-api,provider-plugin-api,doctor-contract,setup-surface,mcp-serve}.ts!",
|
||||
"src/subagent-hooks-api.ts!",
|
||||
] as const;
|
||||
|
||||
const strictBundledPluginEntries = bundledPluginEntries.filter((entry) => entry !== "*.ts!");
|
||||
|
||||
const bundledPluginIgnoredRuntimeDependencies = [
|
||||
"@agentclientprotocol/claude-agent-acp",
|
||||
"@a2ui/lit",
|
||||
@@ -102,6 +113,14 @@ const rootBundledPluginRuntimeDependencies = [
|
||||
"tokenjuice",
|
||||
] as const;
|
||||
|
||||
function strictBundledPluginWorkspace() {
|
||||
return {
|
||||
entry: strictBundledPluginEntries,
|
||||
project: ["*.ts!", "src/**/*.{js,mjs,ts}!"],
|
||||
ignoreDependencies: bundledPluginIgnoredRuntimeDependencies,
|
||||
} as const;
|
||||
}
|
||||
|
||||
// These files are test infrastructure, so their exports are intentionally
|
||||
// available to tests without becoming part of the production dead-code scan.
|
||||
const ignoredTestSupportFiles = [
|
||||
@@ -353,6 +372,19 @@ const config = {
|
||||
entry: ["index.js!", "scripts/postinstall.js!"],
|
||||
project: ["index.js!", "scripts/**/*.js!"],
|
||||
},
|
||||
[`${BUNDLED_PLUGIN_ROOT_DIR}/amazon-bedrock-mantle`]: strictBundledPluginWorkspace(),
|
||||
[`${BUNDLED_PLUGIN_ROOT_DIR}/cohere`]: strictBundledPluginWorkspace(),
|
||||
[`${BUNDLED_PLUGIN_ROOT_DIR}/featherless`]: strictBundledPluginWorkspace(),
|
||||
[`${BUNDLED_PLUGIN_ROOT_DIR}/fireworks`]: strictBundledPluginWorkspace(),
|
||||
[`${BUNDLED_PLUGIN_ROOT_DIR}/huggingface`]: strictBundledPluginWorkspace(),
|
||||
[`${BUNDLED_PLUGIN_ROOT_DIR}/kilocode`]: strictBundledPluginWorkspace(),
|
||||
[`${BUNDLED_PLUGIN_ROOT_DIR}/nvidia`]: strictBundledPluginWorkspace(),
|
||||
[`${BUNDLED_PLUGIN_ROOT_DIR}/qianfan`]: strictBundledPluginWorkspace(),
|
||||
[`${BUNDLED_PLUGIN_ROOT_DIR}/qwen`]: strictBundledPluginWorkspace(),
|
||||
[`${BUNDLED_PLUGIN_ROOT_DIR}/senseaudio`]: strictBundledPluginWorkspace(),
|
||||
[`${BUNDLED_PLUGIN_ROOT_DIR}/tencent`]: strictBundledPluginWorkspace(),
|
||||
[`${BUNDLED_PLUGIN_ROOT_DIR}/vllm`]: strictBundledPluginWorkspace(),
|
||||
[`${BUNDLED_PLUGIN_ROOT_DIR}/xiaomi`]: strictBundledPluginWorkspace(),
|
||||
[`${BUNDLED_PLUGIN_ROOT_DIR}/llama-cpp`]: {
|
||||
entry: bundledPluginEntries,
|
||||
project: ["index.ts!", "src/**/*.{js,mjs,ts}!"],
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
// Amazon Bedrock Mantle tests cover mantle anthropic plugin behavior.
|
||||
import type { Model } from "openclaw/plugin-sdk/llm";
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import {
|
||||
createMantleAnthropicStreamFn,
|
||||
resolveMantleAnthropicBaseUrl,
|
||||
} from "./mantle-anthropic.runtime.js";
|
||||
import { createMantleAnthropicStreamFn } from "./mantle-anthropic.runtime.js";
|
||||
|
||||
function createTestModel(overrides: Partial<Model> = {}): Model {
|
||||
return {
|
||||
@@ -267,13 +264,4 @@ describe("createMantleAnthropicStreamFn", () => {
|
||||
expect(streamOptions).not.toHaveProperty("thinkingBudgetTokens");
|
||||
expect(streamOptions.temperature).toBeUndefined();
|
||||
});
|
||||
|
||||
it("normalizes Mantle provider URLs to the Anthropic endpoint", () => {
|
||||
expect(resolveMantleAnthropicBaseUrl("https://bedrock-mantle.us-east-1.api.aws/v1")).toBe(
|
||||
"https://bedrock-mantle.us-east-1.api.aws/anthropic",
|
||||
);
|
||||
expect(
|
||||
resolveMantleAnthropicBaseUrl("https://bedrock-mantle.us-east-1.api.aws/anthropic/"),
|
||||
).toBe("https://bedrock-mantle.us-east-1.api.aws/anthropic");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -22,7 +22,7 @@ type AnthropicOptions = ConstructorParameters<typeof Anthropic>[0];
|
||||
type MantleAnthropicStream = typeof stream;
|
||||
|
||||
/** Resolve the Anthropic-compatible Mantle base URL from a provider base URL. */
|
||||
export function resolveMantleAnthropicBaseUrl(baseUrl: string): string {
|
||||
function resolveMantleAnthropicBaseUrl(baseUrl: string): string {
|
||||
const trimmed = baseUrl.replace(/\/+$/, "");
|
||||
if (trimmed.endsWith("/anthropic")) {
|
||||
return trimmed;
|
||||
|
||||
@@ -5,15 +5,14 @@ import { registerSingleProviderPlugin } from "openclaw/plugin-sdk/plugin-test-ru
|
||||
import { buildOpenAICompletionsParams } from "openclaw/plugin-sdk/provider-transport-runtime";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import plugin from "./index.js";
|
||||
import {
|
||||
COHERE_COMMAND_A_PLUS_MODEL_ID,
|
||||
COHERE_COMMAND_A_REASONING_MODEL_ID,
|
||||
COHERE_COMMAND_A_VISION_MODEL_ID,
|
||||
COHERE_NORTH_MINI_CODE_MODEL_ID,
|
||||
} from "./models.js";
|
||||
import { COHERE_COMMAND_A_PLUS_MODEL_ID } from "./models.js";
|
||||
import { buildCohereProvider } from "./provider-catalog.js";
|
||||
import { createCohereCompletionsWrapper } from "./stream.js";
|
||||
|
||||
const COHERE_COMMAND_A_REASONING_MODEL_ID = "command-a-reasoning-08-2025";
|
||||
const COHERE_COMMAND_A_VISION_MODEL_ID = "command-a-vision-07-2025";
|
||||
const COHERE_NORTH_MINI_CODE_MODEL_ID = "north-mini-code-1-0";
|
||||
|
||||
function readManifest() {
|
||||
return JSON.parse(readFileSync(new URL("./openclaw.plugin.json", import.meta.url), "utf8")) as {
|
||||
providerAuthChoices?: Array<{ choiceId?: string; optionKey?: string; cliFlag?: string }>;
|
||||
|
||||
@@ -11,9 +11,8 @@ const COHERE_MANIFEST_CATALOG = manifest.modelCatalog.providers.cohere;
|
||||
export const COHERE_BASE_URL = COHERE_MANIFEST_CATALOG.baseUrl;
|
||||
export const COHERE_MODEL_CATALOG = COHERE_MANIFEST_CATALOG.models;
|
||||
export const COHERE_COMMAND_A_PLUS_MODEL_ID = "command-a-plus-05-2026";
|
||||
export const COHERE_COMMAND_A_REASONING_MODEL_ID = "command-a-reasoning-08-2025";
|
||||
export const COHERE_COMMAND_A_VISION_MODEL_ID = "command-a-vision-07-2025";
|
||||
export const COHERE_NORTH_MINI_CODE_MODEL_ID = "north-mini-code-1-0";
|
||||
const COHERE_COMMAND_A_REASONING_MODEL_ID = "command-a-reasoning-08-2025";
|
||||
const COHERE_NORTH_MINI_CODE_MODEL_ID = "north-mini-code-1-0";
|
||||
|
||||
const COHERE_MODERN_MODEL_IDS = new Set([
|
||||
COHERE_COMMAND_A_PLUS_MODEL_ID,
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
import type { OpenClawConfig } from "openclaw/plugin-sdk/config-contracts";
|
||||
import { resolveAgentModelPrimaryValue } from "openclaw/plugin-sdk/provider-onboard";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import {
|
||||
buildCohereCatalogModels,
|
||||
COHERE_BASE_URL,
|
||||
COHERE_COMMAND_A_REASONING_MODEL_ID,
|
||||
COHERE_COMMAND_A_VISION_MODEL_ID,
|
||||
COHERE_MODEL_CATALOG,
|
||||
COHERE_NORTH_MINI_CODE_MODEL_ID,
|
||||
} from "./models.js";
|
||||
import { applyCohereConfig, COHERE_DEFAULT_MODEL_ID, COHERE_DEFAULT_MODEL_REF } from "./onboard.js";
|
||||
import { buildCohereCatalogModels, COHERE_BASE_URL, COHERE_MODEL_CATALOG } from "./models.js";
|
||||
import { applyCohereConfig, COHERE_DEFAULT_MODEL_REF } from "./onboard.js";
|
||||
|
||||
const COHERE_DEFAULT_MODEL_ID = "command-a-plus-05-2026";
|
||||
const COHERE_COMMAND_A_REASONING_MODEL_ID = "command-a-reasoning-08-2025";
|
||||
const COHERE_COMMAND_A_VISION_MODEL_ID = "command-a-vision-07-2025";
|
||||
const COHERE_NORTH_MINI_CODE_MODEL_ID = "north-mini-code-1-0";
|
||||
|
||||
describe("Cohere onboarding", () => {
|
||||
it("registers the manifest catalog through the onboarding preset", () => {
|
||||
|
||||
@@ -9,7 +9,7 @@ import {
|
||||
COHERE_MODEL_CATALOG,
|
||||
} from "./models.js";
|
||||
|
||||
export const COHERE_DEFAULT_MODEL_ID = COHERE_COMMAND_A_PLUS_MODEL_ID;
|
||||
const COHERE_DEFAULT_MODEL_ID = COHERE_COMMAND_A_PLUS_MODEL_ID;
|
||||
export const COHERE_DEFAULT_MODEL_REF = `cohere/${COHERE_DEFAULT_MODEL_ID}`;
|
||||
|
||||
const coherePresetAppliers = createModelCatalogPresetAppliers({
|
||||
|
||||
@@ -5,8 +5,6 @@ import manifest from "./openclaw.plugin.json" with { type: "json" };
|
||||
|
||||
export {
|
||||
FEATHERLESS_BASE_URL,
|
||||
FEATHERLESS_DEFAULT_CONTEXT_WINDOW,
|
||||
FEATHERLESS_DEFAULT_MAX_TOKENS,
|
||||
FEATHERLESS_DEFAULT_MODEL_ID,
|
||||
FEATHERLESS_DYNAMIC_COMPAT,
|
||||
FEATHERLESS_DYNAMIC_CONTEXT_WINDOW,
|
||||
|
||||
@@ -2,10 +2,7 @@
|
||||
import type { StreamFn } from "openclaw/plugin-sdk/agent-core";
|
||||
import type { Context, Model } from "openclaw/plugin-sdk/llm";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import {
|
||||
createFireworksKimiThinkingDisabledWrapper,
|
||||
wrapFireworksProviderStream,
|
||||
} from "./stream.js";
|
||||
import { wrapFireworksProviderStream } from "./stream.js";
|
||||
|
||||
function capturePayload(params: {
|
||||
provider: string;
|
||||
@@ -21,16 +18,21 @@ function capturePayload(params: {
|
||||
return {} as ReturnType<StreamFn>;
|
||||
};
|
||||
|
||||
const wrapped = createFireworksKimiThinkingDisabledWrapper(baseStreamFn);
|
||||
void wrapped(
|
||||
{
|
||||
api: params.api,
|
||||
provider: params.provider,
|
||||
id: params.modelId,
|
||||
} as Model<"openai-completions">,
|
||||
{ messages: [] } as Context,
|
||||
{},
|
||||
);
|
||||
const model = {
|
||||
api: params.api,
|
||||
provider: params.provider,
|
||||
id: params.modelId,
|
||||
} as Model<"openai-completions">;
|
||||
const wrapped = wrapFireworksProviderStream({
|
||||
provider: params.provider,
|
||||
modelId: params.modelId,
|
||||
model,
|
||||
streamFn: baseStreamFn,
|
||||
} as never);
|
||||
if (!wrapped) {
|
||||
throw new Error("expected Fireworks stream wrapper");
|
||||
}
|
||||
void wrapped(model, { messages: [] } as Context, {});
|
||||
|
||||
return captured;
|
||||
}
|
||||
@@ -111,20 +113,25 @@ describe("createFireworksKimiThinkingDisabledWrapper", () => {
|
||||
return {} as ReturnType<StreamFn>;
|
||||
};
|
||||
|
||||
const wrapped = createFireworksKimiThinkingDisabledWrapper(baseStreamFn);
|
||||
void wrapped(
|
||||
{
|
||||
api: "openai-completions",
|
||||
provider: "fireworks",
|
||||
id: "accounts/fireworks/routers/kimi-k2p5-turbo",
|
||||
} as Model<"openai-completions">,
|
||||
{ messages: [] } as Context,
|
||||
{
|
||||
onPayload: (payload) => {
|
||||
callbackPayload = payload as Record<string, unknown>;
|
||||
},
|
||||
const model = {
|
||||
api: "openai-completions",
|
||||
provider: "fireworks",
|
||||
id: "accounts/fireworks/routers/kimi-k2p5-turbo",
|
||||
} as Model<"openai-completions">;
|
||||
const wrapped = wrapFireworksProviderStream({
|
||||
provider: "fireworks",
|
||||
modelId: model.id,
|
||||
model,
|
||||
streamFn: baseStreamFn,
|
||||
} as never);
|
||||
if (!wrapped) {
|
||||
throw new Error("expected Fireworks stream wrapper");
|
||||
}
|
||||
void wrapped(model, { messages: [] } as Context, {
|
||||
onPayload: (payload) => {
|
||||
callbackPayload = payload as Record<string, unknown>;
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
expect(callbackPayload).toEqual({ thinking: { type: "disabled" } });
|
||||
});
|
||||
|
||||
@@ -11,9 +11,7 @@ function isFireworksProviderId(providerId: string): boolean {
|
||||
return normalized === "fireworks" || normalized === "fireworks-ai";
|
||||
}
|
||||
|
||||
export function createFireworksKimiThinkingDisabledWrapper(
|
||||
baseStreamFn: StreamFn | undefined,
|
||||
): StreamFn {
|
||||
function createFireworksKimiThinkingDisabledWrapper(baseStreamFn: StreamFn | undefined): StreamFn {
|
||||
const underlying = baseStreamFn ?? streamSimple;
|
||||
return (model, context, options) =>
|
||||
streamWithPayloadPatch(underlying, model, context, options, (payloadObj) => {
|
||||
|
||||
@@ -8,7 +8,6 @@ import {
|
||||
HUGGINGFACE_MODEL_CATALOG,
|
||||
isHuggingfacePolicyLocked,
|
||||
} from "./api.js";
|
||||
import { HUGGINGFACE_DISCOVERY_TIMEOUT_MS } from "./models.js";
|
||||
|
||||
const ORIGINAL_VITEST = process.env.VITEST;
|
||||
const ORIGINAL_NODE_ENV = process.env.NODE_ENV;
|
||||
@@ -81,7 +80,7 @@ describe("huggingface models", () => {
|
||||
|
||||
await discoverHuggingfaceModels("hf_test_token");
|
||||
|
||||
expect(timeoutSpy).toHaveBeenCalledWith(HUGGINGFACE_DISCOVERY_TIMEOUT_MS);
|
||||
expect(timeoutSpy).toHaveBeenCalledWith(30_000);
|
||||
});
|
||||
|
||||
it("accepts a custom discovery timeout override", async () => {
|
||||
|
||||
@@ -11,7 +11,7 @@ import { isHuggingfaceModelDiscoveryTestEnvironment } from "./model-discovery-en
|
||||
|
||||
export const HUGGINGFACE_BASE_URL = "https://router.huggingface.co/v1";
|
||||
export const HUGGINGFACE_POLICY_SUFFIXES = ["cheapest", "fastest"] as const;
|
||||
export const HUGGINGFACE_DISCOVERY_TIMEOUT_MS = 30_000;
|
||||
const HUGGINGFACE_DISCOVERY_TIMEOUT_MS = 30_000;
|
||||
|
||||
const HUGGINGFACE_DEFAULT_COST = {
|
||||
input: 0,
|
||||
|
||||
@@ -10,7 +10,8 @@ import {
|
||||
KILOCODE_DEFAULT_COST,
|
||||
KILOCODE_DEFAULT_MODEL_ID,
|
||||
} from "./api.js";
|
||||
import { applyKilocodeConfig, KILOCODE_BASE_URL, KILOCODE_DEFAULT_MODEL_REF } from "./onboard.js";
|
||||
import { applyKilocodeConfig, KILOCODE_DEFAULT_MODEL_REF } from "./onboard.js";
|
||||
import { KILOCODE_BASE_URL } from "./provider-models.js";
|
||||
|
||||
const emptyCfg: OpenClawConfig = {};
|
||||
const KILOCODE_MODEL_IDS = ["kilo/auto"];
|
||||
|
||||
@@ -6,7 +6,7 @@ import {
|
||||
import { buildKilocodeProvider } from "./provider-catalog.js";
|
||||
import { KILOCODE_BASE_URL, KILOCODE_DEFAULT_MODEL_REF } from "./provider-models.js";
|
||||
|
||||
export { KILOCODE_BASE_URL, KILOCODE_DEFAULT_MODEL_REF };
|
||||
export { KILOCODE_DEFAULT_MODEL_REF };
|
||||
|
||||
const kilocodePresetAppliers = createModelCatalogPresetAppliers({
|
||||
primaryModelRef: KILOCODE_DEFAULT_MODEL_REF,
|
||||
|
||||
@@ -5,12 +5,12 @@ import {
|
||||
registerSingleProviderPlugin,
|
||||
resolveProviderPluginChoice,
|
||||
} from "openclaw/plugin-sdk/plugin-test-runtime";
|
||||
import { clearLiveCatalogCacheForTests } from "openclaw/plugin-sdk/provider-catalog-live-runtime";
|
||||
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||
import plugin from "./index.js";
|
||||
import {
|
||||
clearNvidiaFeaturedModelCacheForTests,
|
||||
NVIDIA_FEATURED_MODELS_URL,
|
||||
} from "./provider-catalog.js";
|
||||
|
||||
const NVIDIA_FEATURED_MODELS_URL =
|
||||
"https://assets.ngc.nvidia.com/products/api-catalog/featured-models.json";
|
||||
|
||||
const ssrfRuntimeMocks = vi.hoisted(() => ({
|
||||
fetchWithSsrFGuard: vi.fn(),
|
||||
@@ -39,7 +39,7 @@ async function registerNvidiaProvider() {
|
||||
}
|
||||
|
||||
afterEach(() => {
|
||||
clearNvidiaFeaturedModelCacheForTests();
|
||||
clearLiveCatalogCacheForTests();
|
||||
ssrfRuntimeMocks.fetchWithSsrFGuard.mockReset();
|
||||
ssrfRuntimeMocks.ssrfPolicyFromHttpBaseUrlAllowedHostname.mockClear();
|
||||
});
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { clearLiveCatalogCacheForTests } from "openclaw/plugin-sdk/provider-catalog-live-runtime";
|
||||
// Nvidia tests cover provider catalog plugin behavior.
|
||||
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||
import manifest from "./openclaw.plugin.json" with { type: "json" };
|
||||
@@ -6,10 +7,11 @@ import {
|
||||
buildNvidiaProvider,
|
||||
buildSelectableNvidiaProvider,
|
||||
buildSelectableLiveNvidiaProvider,
|
||||
clearNvidiaFeaturedModelCacheForTests,
|
||||
NVIDIA_FEATURED_MODELS_URL,
|
||||
} from "./provider-catalog.js";
|
||||
|
||||
const NVIDIA_FEATURED_MODELS_URL =
|
||||
"https://assets.ngc.nvidia.com/products/api-catalog/featured-models.json";
|
||||
|
||||
const EXPECTED_FEATURED_MODELS = [
|
||||
{
|
||||
id: "nvidia/nemotron-3-ultra-550b-a55b",
|
||||
@@ -94,7 +96,7 @@ vi.mock("openclaw/plugin-sdk/ssrf-runtime", () => ssrfRuntimeMocks);
|
||||
|
||||
afterEach(() => {
|
||||
vi.useRealTimers();
|
||||
clearNvidiaFeaturedModelCacheForTests();
|
||||
clearLiveCatalogCacheForTests();
|
||||
ssrfRuntimeMocks.fetchWithSsrFGuard.mockReset();
|
||||
ssrfRuntimeMocks.ssrfPolicyFromHttpBaseUrlAllowedHostname.mockClear();
|
||||
});
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
// Nvidia provider module implements model/runtime integration.
|
||||
import { lookup as dnsLookup } from "node:dns/promises";
|
||||
import {
|
||||
clearLiveCatalogCacheForTests,
|
||||
getCachedLiveProviderModelRows,
|
||||
} from "openclaw/plugin-sdk/provider-catalog-live-runtime";
|
||||
import { getCachedLiveProviderModelRows } from "openclaw/plugin-sdk/provider-catalog-live-runtime";
|
||||
import { buildManifestModelProviderConfig } from "openclaw/plugin-sdk/provider-catalog-shared";
|
||||
import type {
|
||||
ModelDefinitionConfig,
|
||||
@@ -17,7 +14,7 @@ import { isRecord } from "openclaw/plugin-sdk/string-coerce-runtime";
|
||||
import manifest from "./openclaw.plugin.json" with { type: "json" };
|
||||
|
||||
export const NVIDIA_DEFAULT_MODEL_ID = "nvidia/nemotron-3-ultra-550b-a55b";
|
||||
export const NVIDIA_FEATURED_MODELS_URL =
|
||||
const NVIDIA_FEATURED_MODELS_URL =
|
||||
"https://assets.ngc.nvidia.com/products/api-catalog/featured-models.json";
|
||||
|
||||
const FEATURED_MODEL_CACHE_TTL_MS = 24 * 60 * 60 * 1000;
|
||||
@@ -119,10 +116,6 @@ export async function buildSelectableLiveNvidiaProvider(): Promise<ModelProvider
|
||||
};
|
||||
}
|
||||
|
||||
export function clearNvidiaFeaturedModelCacheForTests() {
|
||||
clearLiveCatalogCacheForTests();
|
||||
}
|
||||
|
||||
async function loadNvidiaFeaturedModels(): Promise<ModelDefinitionConfig[] | null> {
|
||||
try {
|
||||
const rows = await getCachedLiveProviderModelRows({
|
||||
|
||||
@@ -7,11 +7,7 @@ import { resolveAgentModelPrimaryValue } from "openclaw/plugin-sdk/provider-onbo
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { runSingleProviderCatalog } from "../test-support/provider-model-test-helpers.js";
|
||||
import qianfanPlugin from "./index.js";
|
||||
import {
|
||||
applyQianfanConfig,
|
||||
applyQianfanProviderConfig,
|
||||
QIANFAN_DEFAULT_MODEL_REF,
|
||||
} from "./onboard.js";
|
||||
import { applyQianfanConfig, QIANFAN_DEFAULT_MODEL_REF } from "./onboard.js";
|
||||
|
||||
function expectRecord<T>(value: T | null | undefined, label: string): NonNullable<T> {
|
||||
if (!value) {
|
||||
@@ -94,36 +90,6 @@ describe("qianfan provider plugin", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("adds Qianfan provider defaults without changing primary model in provider-only mode", () => {
|
||||
const cfg = applyQianfanProviderConfig({
|
||||
agents: {
|
||||
defaults: {
|
||||
model: { primary: "anthropic/claude-opus-4-6" },
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const modelsConfig = expectRecord(cfg.models, "models config");
|
||||
const providers = expectRecord(modelsConfig.providers, "model providers");
|
||||
const providerConfig = expectRecord(providers.qianfan, "Qianfan provider config");
|
||||
expect(providerConfig.api).toBe("openai-completions");
|
||||
expect(providerConfig.baseUrl).toBe("https://qianfan.baidubce.com/v2");
|
||||
const providerModels = expectRecord(providerConfig.models, "Qianfan provider models");
|
||||
expect(providerModels.map((model) => model.id)).toEqual([
|
||||
"deepseek-v3.2",
|
||||
"ernie-5.0-thinking-preview",
|
||||
]);
|
||||
const agentsConfig = expectRecord(cfg.agents, "agents config");
|
||||
const agentDefaults = expectRecord(agentsConfig.defaults, "agent defaults");
|
||||
const agentModelAliases = expectRecord(agentDefaults.models, "agent model aliases");
|
||||
const qianfanAlias = expectRecord(
|
||||
agentModelAliases[QIANFAN_DEFAULT_MODEL_REF],
|
||||
"Qianfan model alias",
|
||||
);
|
||||
expect(qianfanAlias.alias).toBe("QIANFAN");
|
||||
expect(resolveAgentModelPrimaryValue(agentDefaults.model)).toBe("anthropic/claude-opus-4-6");
|
||||
});
|
||||
|
||||
it("sets Qianfan as the agent primary model in full onboarding mode", () => {
|
||||
const cfg = applyQianfanConfig({});
|
||||
|
||||
|
||||
@@ -53,10 +53,6 @@ const qianfanPresetAppliers = createDefaultModelsPresetAppliers({
|
||||
},
|
||||
});
|
||||
|
||||
export function applyQianfanProviderConfig(cfg: OpenClawConfig): OpenClawConfig {
|
||||
return qianfanPresetAppliers.applyProviderConfig(cfg);
|
||||
}
|
||||
|
||||
export function applyQianfanConfig(cfg: OpenClawConfig): OpenClawConfig {
|
||||
return qianfanPresetAppliers.applyConfig(cfg);
|
||||
}
|
||||
|
||||
@@ -4,10 +4,16 @@ import {
|
||||
installPinnedHostnameTestHooks,
|
||||
} from "openclaw/plugin-sdk/test-env";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { describeQwenVideo } from "./media-understanding-provider.js";
|
||||
import { buildQwenMediaUnderstandingProvider } from "./media-understanding-provider.js";
|
||||
|
||||
installPinnedHostnameTestHooks();
|
||||
|
||||
const qwenProvider = buildQwenMediaUnderstandingProvider();
|
||||
const describeQwenVideo = qwenProvider.describeVideo;
|
||||
if (!describeQwenVideo) {
|
||||
throw new Error("expected Qwen video description capability");
|
||||
}
|
||||
|
||||
function oversizedJsonResponse(params: { chunkCount: number; chunkSize: number }): {
|
||||
response: Response;
|
||||
getReadCount: () => number;
|
||||
|
||||
@@ -21,9 +21,7 @@ import { QWEN_STANDARD_GLOBAL_BASE_URL } from "./models.js";
|
||||
const DEFAULT_QWEN_VIDEO_MODEL = "qwen-vl-max-latest";
|
||||
const DEFAULT_QWEN_VIDEO_PROMPT = "Describe the video in detail.";
|
||||
|
||||
export async function describeQwenVideo(
|
||||
params: VideoDescriptionRequest,
|
||||
): Promise<VideoDescriptionResult> {
|
||||
async function describeQwenVideo(params: VideoDescriptionRequest): Promise<VideoDescriptionResult> {
|
||||
const fetchFn = params.fetchFn ?? fetch;
|
||||
const model = resolveMediaUnderstandingString(params.model, DEFAULT_QWEN_VIDEO_MODEL);
|
||||
const mime = resolveMediaUnderstandingString(params.mime, "video/mp4");
|
||||
|
||||
@@ -10,10 +10,15 @@ import {
|
||||
installPinnedHostnameTestHooks,
|
||||
} from "openclaw/plugin-sdk/test-env";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { transcribeSenseAudioAudio } from "./media-understanding-provider.js";
|
||||
import { senseaudioMediaUnderstandingProvider } from "./media-understanding-provider.js";
|
||||
|
||||
installPinnedHostnameTestHooks();
|
||||
|
||||
const transcribeSenseAudioAudio = senseaudioMediaUnderstandingProvider.transcribeAudio;
|
||||
if (!transcribeSenseAudioAudio) {
|
||||
throw new Error("expected SenseAudio transcription capability");
|
||||
}
|
||||
|
||||
describe("transcribeSenseAudioAudio", () => {
|
||||
it("uses SenseAudio base URL by default", async () => {
|
||||
const { fetchFn, getRequest } = createRequestCaptureJsonFetch({ text: "ok" });
|
||||
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
const DEFAULT_SENSEAUDIO_AUDIO_BASE_URL = "https://api.senseaudio.cn/v1";
|
||||
const DEFAULT_SENSEAUDIO_AUDIO_MODEL = "senseaudio-asr-pro-1.5-260319";
|
||||
|
||||
export async function transcribeSenseAudioAudio(params: AudioTranscriptionRequest) {
|
||||
async function transcribeSenseAudioAudio(params: AudioTranscriptionRequest) {
|
||||
return await transcribeOpenAiCompatibleAudio({
|
||||
...params,
|
||||
provider: "senseaudio",
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
// Tencent tests cover config compatibility repair behavior.
|
||||
import type { OpenClawConfig } from "openclaw/plugin-sdk/config-contracts";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import {
|
||||
migrateTencentTokenHubModelDefaults,
|
||||
TENCENT_TOKENHUB_DEFAULT_MODEL_REF,
|
||||
TENCENT_TOKENHUB_PREVIEW_MODEL_REF,
|
||||
} from "./config-compat.js";
|
||||
import { migrateTencentTokenHubModelDefaults } from "./config-compat.js";
|
||||
|
||||
const TENCENT_TOKENHUB_DEFAULT_MODEL_REF = "tencent-tokenhub/hy3";
|
||||
const TENCENT_TOKENHUB_PREVIEW_MODEL_REF = "tencent-tokenhub/hy3-preview";
|
||||
|
||||
describe("Tencent config compatibility", () => {
|
||||
it("adds the stable TokenHub model and makes it primary for old preview defaults", () => {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
// Tencent config compatibility repairs shipped TokenHub model allowlists.
|
||||
import type { OpenClawConfig } from "openclaw/plugin-sdk/config-contracts";
|
||||
|
||||
export const TENCENT_TOKENHUB_DEFAULT_MODEL_REF = "tencent-tokenhub/hy3";
|
||||
export const TENCENT_TOKENHUB_PREVIEW_MODEL_REF = "tencent-tokenhub/hy3-preview";
|
||||
const TENCENT_TOKENHUB_DEFAULT_MODEL_REF = "tencent-tokenhub/hy3";
|
||||
const TENCENT_TOKENHUB_PREVIEW_MODEL_REF = "tencent-tokenhub/hy3-preview";
|
||||
|
||||
const TOKENHUB_DEFAULT_ALIAS = "Hy3 (TokenHub)";
|
||||
const TOKENHUB_PREVIEW_ALIAS = "Hy3 preview (TokenHub)";
|
||||
@@ -111,10 +111,3 @@ export function migrateTencentTokenHubModelDefaults(cfg: OpenClawConfig): {
|
||||
|
||||
return { config: nextConfig, changes };
|
||||
}
|
||||
|
||||
export function normalizeCompatibilityConfig({ cfg }: { cfg: OpenClawConfig }): {
|
||||
config: OpenClawConfig;
|
||||
changes: string[];
|
||||
} {
|
||||
return migrateTencentTokenHubModelDefaults(cfg);
|
||||
}
|
||||
|
||||
@@ -2,11 +2,7 @@
|
||||
import type { StreamFn } from "openclaw/plugin-sdk/agent-core";
|
||||
import type { Context, Model } from "openclaw/plugin-sdk/llm";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import {
|
||||
createVllmProviderThinkingWrapper,
|
||||
createVllmQwenThinkingWrapper,
|
||||
wrapVllmProviderStream,
|
||||
} from "./stream.js";
|
||||
import { createVllmQwenThinkingWrapper, wrapVllmProviderStream } from "./stream.js";
|
||||
|
||||
function capturePayload(params: {
|
||||
format: "chat-template" | "top-level";
|
||||
@@ -135,21 +131,21 @@ describe("createVllmProviderThinkingWrapper", () => {
|
||||
return {} as ReturnType<StreamFn>;
|
||||
};
|
||||
|
||||
const wrapped = createVllmProviderThinkingWrapper({
|
||||
baseStreamFn,
|
||||
const model = {
|
||||
api: "openai-completions",
|
||||
provider: "vllm",
|
||||
id: "nemotron-3-super",
|
||||
reasoning: true,
|
||||
...params.model,
|
||||
} as Model<"openai-completions">;
|
||||
const wrapped = wrapVllmProviderStream({
|
||||
provider: "vllm",
|
||||
modelId: model.id,
|
||||
model,
|
||||
thinkingLevel: params.thinkingLevel ?? "high",
|
||||
});
|
||||
void wrapped(
|
||||
{
|
||||
api: "openai-completions",
|
||||
provider: "vllm",
|
||||
id: "nemotron-3-super",
|
||||
reasoning: true,
|
||||
...params.model,
|
||||
} as Model<"openai-completions">,
|
||||
{ messages: [] } as Context,
|
||||
{},
|
||||
);
|
||||
streamFn: baseStreamFn,
|
||||
} as never);
|
||||
void wrapped?.(model, { messages: [] } as Context, {});
|
||||
|
||||
return captured;
|
||||
}
|
||||
|
||||
@@ -76,7 +76,7 @@ export function createVllmQwenThinkingWrapper(params: {
|
||||
);
|
||||
}
|
||||
|
||||
export function createVllmProviderThinkingWrapper(params: {
|
||||
function createVllmProviderThinkingWrapper(params: {
|
||||
baseStreamFn: StreamFn | undefined;
|
||||
qwenFormat?: VllmQwenThinkingFormat;
|
||||
thinkingLevel: VllmThinkingLevel;
|
||||
|
||||
@@ -8,7 +8,6 @@ import {
|
||||
applyXiaomiConfig,
|
||||
applyXiaomiProviderConfig,
|
||||
applyXiaomiTokenPlanConfig,
|
||||
applyXiaomiTokenPlanProviderConfig,
|
||||
} from "./onboard.js";
|
||||
import { buildXiaomiProvider, buildXiaomiTokenPlanProvider } from "./provider-catalog.js";
|
||||
|
||||
@@ -68,7 +67,7 @@ describe("xiaomi onboard", () => {
|
||||
|
||||
it("merges Xiaomi Token Plan models and rewrites the selected regional base URL", () => {
|
||||
const provider = expectProviderOnboardMergedLegacyConfig({
|
||||
applyProviderConfig: (config) => applyXiaomiTokenPlanProviderConfig(config, "sgp"),
|
||||
applyProviderConfig: (config) => applyXiaomiTokenPlanConfig(config, "sgp"),
|
||||
providerId: "xiaomi-token-plan",
|
||||
providerApi: "openai-completions",
|
||||
baseUrl: "https://token-plan-sgp.xiaomimimo.com/v1",
|
||||
|
||||
@@ -86,17 +86,6 @@ export function applyXiaomiConfig(cfg: OpenClawConfig): OpenClawConfig {
|
||||
return xiaomiPresetAppliers.applyConfig(cfg);
|
||||
}
|
||||
|
||||
export function applyXiaomiTokenPlanProviderConfig(
|
||||
cfg: OpenClawConfig,
|
||||
region: XiaomiTokenPlanRegion,
|
||||
): OpenClawConfig {
|
||||
return withProviderBaseUrl(
|
||||
xiaomiTokenPlanPresetAppliers.applyProviderConfig(cfg),
|
||||
XIAOMI_TOKEN_PLAN_PROVIDER_ID,
|
||||
resolveXiaomiTokenPlanBaseUrl(region),
|
||||
);
|
||||
}
|
||||
|
||||
export function applyXiaomiTokenPlanConfig(
|
||||
cfg: OpenClawConfig,
|
||||
region: XiaomiTokenPlanRegion,
|
||||
|
||||
@@ -40,6 +40,43 @@ describe("check-deadcode-exports", () => {
|
||||
expect(knipConfig.workspaces["."].entry).toContain("src/mcp/openclaw-tools-serve.ts!");
|
||||
});
|
||||
|
||||
it.each([
|
||||
"amazon-bedrock-mantle",
|
||||
"cohere",
|
||||
"featherless",
|
||||
"fireworks",
|
||||
"huggingface",
|
||||
"kilocode",
|
||||
"nvidia",
|
||||
"qianfan",
|
||||
"qwen",
|
||||
"senseaudio",
|
||||
"tencent",
|
||||
"vllm",
|
||||
"xiaomi",
|
||||
])("removes the bundled-plugin root catch-all from migrated %s workspace", (pluginId) => {
|
||||
const workspace = (
|
||||
knipConfig.workspaces as Record<string, { readonly entry: readonly string[] }>
|
||||
)[`extensions/${pluginId}`];
|
||||
if (!workspace) {
|
||||
throw new Error(`missing Knip workspace for ${pluginId}`);
|
||||
}
|
||||
const entries = workspace.entry;
|
||||
expect(entries).not.toContain("*.ts!");
|
||||
expect(entries).toEqual(
|
||||
expect.arrayContaining([
|
||||
"index.ts!",
|
||||
"setup-entry.ts!",
|
||||
"*-api.ts!",
|
||||
"cli-metadata.ts!",
|
||||
"channel-entry.ts!",
|
||||
"provider-discovery.ts!",
|
||||
"{web-search,web-fetch}-provider.ts!",
|
||||
]),
|
||||
);
|
||||
expect(knipConfig.workspaces["extensions/*"].entry).toContain("*.ts!");
|
||||
});
|
||||
|
||||
it.each([
|
||||
"packages/agent-core",
|
||||
"packages/markdown-core",
|
||||
|
||||
Reference in New Issue
Block a user