mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-12 21:53:00 -06:00
refactor(plugin-sdk): remove final test-only facades (#122844)
This commit is contained in:
committed by
GitHub
parent
9ed96868eb
commit
d003e08756
@@ -683,7 +683,6 @@ const config = {
|
|||||||
"browser-control-auth.ts!",
|
"browser-control-auth.ts!",
|
||||||
"browser-config.ts!",
|
"browser-config.ts!",
|
||||||
"browser-doctor.ts!",
|
"browser-doctor.ts!",
|
||||||
"browser-host-inspection.ts!",
|
|
||||||
"browser-maintenance.ts!",
|
"browser-maintenance.ts!",
|
||||||
"browser-profiles.ts!",
|
"browser-profiles.ts!",
|
||||||
// Built by tsdown as the native messaging executable; Chrome launches it by path.
|
// Built by tsdown as the native messaging executable; Chrome launches it by path.
|
||||||
|
|||||||
@@ -1,10 +0,0 @@
|
|||||||
/**
|
|
||||||
* Browser host-inspection API barrel. It exposes Chrome executable discovery
|
|
||||||
* and version parsing helpers.
|
|
||||||
*/
|
|
||||||
export type { BrowserExecutable } from "./src/browser/chrome.executables.js";
|
|
||||||
export {
|
|
||||||
parseBrowserMajorVersion,
|
|
||||||
readBrowserVersion,
|
|
||||||
resolveGoogleChromeExecutableForPlatform,
|
|
||||||
} from "./src/browser/chrome.executables.js";
|
|
||||||
@@ -1,74 +0,0 @@
|
|||||||
// OpenAI model default tests cover provider-specific default model migration helpers.
|
|
||||||
import { describe, expect, it } from "vitest";
|
|
||||||
import type { OpenClawConfig } from "../config/config.js";
|
|
||||||
import {
|
|
||||||
applyOpencodeZenModelDefault,
|
|
||||||
OPENCODE_ZEN_DEFAULT_MODEL,
|
|
||||||
} from "../plugin-sdk/opencode.js";
|
|
||||||
|
|
||||||
function expectPrimaryModelChanged(
|
|
||||||
applied: { changed: boolean; next: OpenClawConfig },
|
|
||||||
primary: string,
|
|
||||||
) {
|
|
||||||
expect(applied.changed).toBe(true);
|
|
||||||
expect(applied.next.agents?.defaults?.model).toEqual({ primary });
|
|
||||||
}
|
|
||||||
|
|
||||||
function expectConfigUnchanged(
|
|
||||||
applied: { changed: boolean; next: OpenClawConfig },
|
|
||||||
cfg: OpenClawConfig,
|
|
||||||
) {
|
|
||||||
expect(applied.changed).toBe(false);
|
|
||||||
expect(applied.next).toEqual(cfg);
|
|
||||||
}
|
|
||||||
|
|
||||||
describe("applyOpencodeZenModelDefault", () => {
|
|
||||||
it("sets defaults when model is unset", () => {
|
|
||||||
const cfg: OpenClawConfig = { agents: { defaults: {} } };
|
|
||||||
const applied = applyOpencodeZenModelDefault(cfg);
|
|
||||||
expectPrimaryModelChanged(applied, OPENCODE_ZEN_DEFAULT_MODEL);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("overrides existing models", () => {
|
|
||||||
const cfg = {
|
|
||||||
agents: { defaults: { model: "anthropic/claude-opus-4-6" } },
|
|
||||||
} as OpenClawConfig;
|
|
||||||
const applied = applyOpencodeZenModelDefault(cfg);
|
|
||||||
expectPrimaryModelChanged(applied, OPENCODE_ZEN_DEFAULT_MODEL);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("no-ops when already legacy opencode-zen default", () => {
|
|
||||||
const cfg = {
|
|
||||||
agents: { defaults: { model: "opencode-zen/claude-opus-4-5" } },
|
|
||||||
} as OpenClawConfig;
|
|
||||||
const applied = applyOpencodeZenModelDefault(cfg);
|
|
||||||
expectConfigUnchanged(applied, cfg);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("preserves fallbacks when setting primary", () => {
|
|
||||||
const cfg: OpenClawConfig = {
|
|
||||||
agents: {
|
|
||||||
defaults: {
|
|
||||||
model: {
|
|
||||||
primary: "anthropic/claude-opus-4-6",
|
|
||||||
fallbacks: ["google/gemini-3-pro"],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
const applied = applyOpencodeZenModelDefault(cfg);
|
|
||||||
expect(applied.changed).toBe(true);
|
|
||||||
expect(applied.next.agents?.defaults?.model).toEqual({
|
|
||||||
primary: OPENCODE_ZEN_DEFAULT_MODEL,
|
|
||||||
fallbacks: ["google/gemini-3.1-pro-preview"],
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("no-ops when already on the current default", () => {
|
|
||||||
const cfg = {
|
|
||||||
agents: { defaults: { model: OPENCODE_ZEN_DEFAULT_MODEL } },
|
|
||||||
} as OpenClawConfig;
|
|
||||||
const applied = applyOpencodeZenModelDefault(cfg);
|
|
||||||
expectConfigUnchanged(applied, cfg);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -72,7 +72,7 @@ import type { ModelsConfig, ModelProviderConfig, OpenClawConfig } from "../confi
|
|||||||
import { isTruthyEnvValue } from "../infra/env.js";
|
import { isTruthyEnvValue } from "../infra/env.js";
|
||||||
import type { ModelRegistry } from "../llm/model-registry.js";
|
import type { ModelRegistry } from "../llm/model-registry.js";
|
||||||
import { redactSecrets } from "../logging/redact.js";
|
import { redactSecrets } from "../logging/redact.js";
|
||||||
import { normalizeGoogleModelId } from "../plugin-sdk/google-model-id.js";
|
import { normalizeGooglePreviewModelId } from "../plugin-sdk/provider-model-shared.js";
|
||||||
import { resolveRuntimeThinkingProfile } from "../plugins/provider-runtime.js";
|
import { resolveRuntimeThinkingProfile } from "../plugins/provider-runtime.js";
|
||||||
import { LEGACY_IMPLICIT_AGENT_ID as DEFAULT_AGENT_ID } from "../routing/session-key.js";
|
import { LEGACY_IMPLICIT_AGENT_ID as DEFAULT_AGENT_ID } from "../routing/session-key.js";
|
||||||
import { stripAssistantInternalScaffolding } from "../shared/text/assistant-visible-text.js";
|
import { stripAssistantInternalScaffolding } from "../shared/text/assistant-visible-text.js";
|
||||||
@@ -723,7 +723,7 @@ function shouldStripAssistantScaffoldingForLiveModel(modelKey?: string): boolean
|
|||||||
if (provider !== "google" || rest.length === 0) {
|
if (provider !== "google" || rest.length === 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const normalizedKey = `${provider}/${normalizeGoogleModelId(modelId)}`;
|
const normalizedKey = `${provider}/${normalizeGooglePreviewModelId(modelId)}`;
|
||||||
return GATEWAY_LIVE_STRIP_SCAFFOLDING_MODEL_KEYS.has(normalizedKey);
|
return GATEWAY_LIVE_STRIP_SCAFFOLDING_MODEL_KEYS.has(normalizedKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -752,7 +752,7 @@ function shouldSkipExecReadNonceMissForLiveModel(modelKey?: string): boolean {
|
|||||||
if (provider !== "google" || rest.length === 0) {
|
if (provider !== "google" || rest.length === 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const normalizedKey = `${provider}/${normalizeGoogleModelId(rest.join("/"))}`;
|
const normalizedKey = `${provider}/${normalizeGooglePreviewModelId(rest.join("/"))}`;
|
||||||
return GATEWAY_LIVE_EXEC_READ_NONCE_MISS_SKIP_MODEL_KEYS.has(normalizedKey);
|
return GATEWAY_LIVE_EXEC_READ_NONCE_MISS_SKIP_MODEL_KEYS.has(normalizedKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2456,7 +2456,7 @@ function shouldSkipToolNonceProbeMissForLiveModel(modelKey?: string): boolean {
|
|||||||
if (provider !== "google" || rest.length === 0) {
|
if (provider !== "google" || rest.length === 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const normalizedKey = `${provider}/${normalizeGoogleModelId(rest.join("/"))}`;
|
const normalizedKey = `${provider}/${normalizeGooglePreviewModelId(rest.join("/"))}`;
|
||||||
return GATEWAY_LIVE_TOOL_NONCE_MISS_SKIP_MODEL_KEYS.has(normalizedKey);
|
return GATEWAY_LIVE_TOOL_NONCE_MISS_SKIP_MODEL_KEYS.has(normalizedKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4223,7 +4223,7 @@ function parseExplicitLiveModelRef(
|
|||||||
const rawModelId = trimmed.slice(slash + 1).trim();
|
const rawModelId = trimmed.slice(slash + 1).trim();
|
||||||
const modelId =
|
const modelId =
|
||||||
provider === "google" || provider === "google-gemini-cli" || provider === "google-vertex"
|
provider === "google" || provider === "google-gemini-cli" || provider === "google-vertex"
|
||||||
? normalizeGoogleModelId(rawModelId)
|
? normalizeGooglePreviewModelId(rawModelId)
|
||||||
: rawModelId;
|
: rawModelId;
|
||||||
return provider && modelId ? { provider, modelId } : null;
|
return provider && modelId ? { provider, modelId } : null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
import { describe, expect, it, vi } from "vitest";
|
import { describe, expect, it, vi } from "vitest";
|
||||||
import { normalizeModelRef } from "./agents/model-ref-shared.js";
|
import { normalizeModelRef } from "./agents/model-ref-shared.js";
|
||||||
import { isStaticallyChannelConfigured } from "./config/channel-configured-shared.js";
|
import { isStaticallyChannelConfigured } from "./config/channel-configured-shared.js";
|
||||||
import { parseBrowserMajorVersion } from "./plugin-sdk/browser-host-inspection.js";
|
|
||||||
|
|
||||||
const testModelIdNormalization = {
|
const testModelIdNormalization = {
|
||||||
providers: {
|
providers: {
|
||||||
@@ -20,21 +19,7 @@ const testModelIdNormalization = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const loadBundledPluginPublicSurfaceModuleSyncCore = vi.hoisted(() =>
|
const loadBundledPluginPublicSurfaceModuleSyncCore = vi.hoisted(() => vi.fn());
|
||||||
vi.fn((params: { artifactBasename: string }) => {
|
|
||||||
if (params.artifactBasename === "browser-host-inspection.js") {
|
|
||||||
return {
|
|
||||||
parseBrowserMajorVersion: (raw: string | null | undefined) => {
|
|
||||||
const match = raw?.match(/\b(\d+)\./u);
|
|
||||||
return match?.[1] ? Number(match[1]) : null;
|
|
||||||
},
|
|
||||||
readBrowserVersion: () => null,
|
|
||||||
resolveGoogleChromeExecutableForPlatform: () => null,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
throw new Error(`unexpected public surface load: ${params.artifactBasename}`);
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
const loadPluginManifestRegistryForPluginRegistry = vi.hoisted(() =>
|
const loadPluginManifestRegistryForPluginRegistry = vi.hoisted(() =>
|
||||||
vi.fn(() => ({
|
vi.fn(() => ({
|
||||||
@@ -122,7 +107,7 @@ vi.mock("./plugin-sdk/facade-runtime.js", () => ({
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
describe("plugin activation boundary", () => {
|
describe("plugin activation boundary", () => {
|
||||||
it("keeps generic boundaries cold and loads only narrow browser helper surfaces on use", () => {
|
it("keeps generic channel and model-normalization boundaries cold", () => {
|
||||||
loadBundledPluginPublicSurfaceModuleSyncCore.mockReset();
|
loadBundledPluginPublicSurfaceModuleSyncCore.mockReset();
|
||||||
|
|
||||||
expect(isStaticallyChannelConfigured({}, "telegram", { TELEGRAM_BOT_TOKEN: "token" })).toBe(
|
expect(isStaticallyChannelConfigured({}, "telegram", { TELEGRAM_BOT_TOKEN: "token" })).toBe(
|
||||||
@@ -154,12 +139,5 @@ describe("plugin activation boundary", () => {
|
|||||||
model: "grok-4-fast",
|
model: "grok-4-fast",
|
||||||
});
|
});
|
||||||
expect(loadBundledPluginPublicSurfaceModuleSyncCore).not.toHaveBeenCalled();
|
expect(loadBundledPluginPublicSurfaceModuleSyncCore).not.toHaveBeenCalled();
|
||||||
|
|
||||||
expect(parseBrowserMajorVersion("Google Chrome 144.0.7534.0")).toBe(144);
|
|
||||||
expect(
|
|
||||||
loadBundledPluginPublicSurfaceModuleSyncCore.mock.calls.map(
|
|
||||||
([params]) => params.artifactBasename,
|
|
||||||
),
|
|
||||||
).toEqual(["browser-host-inspection.js"]);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,65 +0,0 @@
|
|||||||
/**
|
|
||||||
* Shared test helpers for browser facade delegation tests.
|
|
||||||
*/
|
|
||||||
import { expect, vi } from "vitest";
|
|
||||||
|
|
||||||
type FacadeLoaderMock = ReturnType<typeof vi.fn>;
|
|
||||||
|
|
||||||
type ChromeExecutableFixture = {
|
|
||||||
kind: string;
|
|
||||||
path: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
const BROWSER_HOST_INSPECTION_ARTIFACT = {
|
|
||||||
dirName: "browser",
|
|
||||||
artifactBasename: "browser-host-inspection.js",
|
|
||||||
} as const;
|
|
||||||
|
|
||||||
const BROWSER_VERSION = "Google Chrome 144.0.7534.0";
|
|
||||||
|
|
||||||
/** Installs a mocked browser host inspection public surface. */
|
|
||||||
export function mockBrowserHostInspectionFacade(
|
|
||||||
loadBundledPluginPublicSurfaceModuleSync: FacadeLoaderMock,
|
|
||||||
executable: ChromeExecutableFixture,
|
|
||||||
) {
|
|
||||||
const resolveGoogleChromeExecutableForPlatform = vi.fn().mockReturnValue(executable);
|
|
||||||
const readBrowserVersion = vi.fn().mockReturnValue(BROWSER_VERSION);
|
|
||||||
const parseBrowserMajorVersion = vi.fn().mockReturnValue(144);
|
|
||||||
|
|
||||||
loadBundledPluginPublicSurfaceModuleSync.mockReturnValue({
|
|
||||||
resolveGoogleChromeExecutableForPlatform,
|
|
||||||
readBrowserVersion,
|
|
||||||
parseBrowserMajorVersion,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Asserts browser host inspection calls delegate through the browser public facade. */
|
|
||||||
export function expectBrowserHostInspectionDelegation(params: {
|
|
||||||
executable: ChromeExecutableFixture;
|
|
||||||
hostInspection: typeof import("./browser-host-inspection.js");
|
|
||||||
loadBundledPluginPublicSurfaceModuleSync: FacadeLoaderMock;
|
|
||||||
}) {
|
|
||||||
expect(params.hostInspection.resolveGoogleChromeExecutableForPlatform("linux")).toEqual(
|
|
||||||
params.executable,
|
|
||||||
);
|
|
||||||
expect(params.hostInspection.readBrowserVersion(params.executable.path)).toBe(BROWSER_VERSION);
|
|
||||||
expect(params.hostInspection.parseBrowserMajorVersion(BROWSER_VERSION)).toBe(144);
|
|
||||||
expect(params.loadBundledPluginPublicSurfaceModuleSync).toHaveBeenCalledWith(
|
|
||||||
BROWSER_HOST_INSPECTION_ARTIFACT,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Asserts host inspection helpers surface facade load failures to callers. */
|
|
||||||
export async function expectBrowserHostInspectionFacadeUnavailable(
|
|
||||||
loadBundledPluginPublicSurfaceModuleSync: FacadeLoaderMock,
|
|
||||||
) {
|
|
||||||
loadBundledPluginPublicSurfaceModuleSync.mockImplementation(() => {
|
|
||||||
throw new Error("missing browser host inspection facade");
|
|
||||||
});
|
|
||||||
|
|
||||||
const hostInspection = await import("./browser-host-inspection.js");
|
|
||||||
|
|
||||||
expect(() => hostInspection.resolveGoogleChromeExecutableForPlatform("linux")).toThrow(
|
|
||||||
"missing browser host inspection facade",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
// Browser host inspection tests cover browser host discovery and inspection helpers.
|
|
||||||
import { beforeEach, describe, it, vi } from "vitest";
|
|
||||||
import {
|
|
||||||
expectBrowserHostInspectionDelegation,
|
|
||||||
expectBrowserHostInspectionFacadeUnavailable,
|
|
||||||
mockBrowserHostInspectionFacade,
|
|
||||||
} from "./browser-facade-test-helpers.js";
|
|
||||||
|
|
||||||
const loadBundledPluginPublicSurfaceModuleSyncCore = vi.hoisted(() => vi.fn());
|
|
||||||
|
|
||||||
vi.mock("./facade-loader.js", () => ({
|
|
||||||
loadBundledPluginPublicSurfaceModuleSyncCore,
|
|
||||||
}));
|
|
||||||
|
|
||||||
describe("browser host inspection", () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
// Facade wrappers cache successful loads; each case needs a clean wrapper module.
|
|
||||||
vi.resetModules();
|
|
||||||
loadBundledPluginPublicSurfaceModuleSyncCore.mockReset();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("delegates browser host inspection helpers through the browser facade", async () => {
|
|
||||||
const executable: import("./browser-host-inspection.js").BrowserExecutable = {
|
|
||||||
kind: "canary",
|
|
||||||
path: "/usr/bin/google-chrome-beta",
|
|
||||||
};
|
|
||||||
mockBrowserHostInspectionFacade(loadBundledPluginPublicSurfaceModuleSyncCore, executable);
|
|
||||||
|
|
||||||
const hostInspection = await import("./browser-host-inspection.js");
|
|
||||||
|
|
||||||
expectBrowserHostInspectionDelegation({
|
|
||||||
executable,
|
|
||||||
hostInspection,
|
|
||||||
loadBundledPluginPublicSurfaceModuleSync: loadBundledPluginPublicSurfaceModuleSyncCore,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("hard-fails when browser host inspection facade is unavailable", async () => {
|
|
||||||
await expectBrowserHostInspectionFacadeUnavailable(
|
|
||||||
loadBundledPluginPublicSurfaceModuleSyncCore,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
/**
|
|
||||||
* Public SDK facade for browser executable lookup and browser version inspection.
|
|
||||||
*/
|
|
||||||
import { loadBundledPluginPublicSurfaceModuleSyncCore } from "./facade-loader.js";
|
|
||||||
|
|
||||||
/** Browser executable candidate discovered on the host platform. */
|
|
||||||
export type BrowserExecutable = {
|
|
||||||
kind: "brave" | "canary" | "chromium" | "chrome" | "custom" | "edge";
|
|
||||||
path: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
type BrowserHostInspectionSurface = {
|
|
||||||
resolveGoogleChromeExecutableForPlatform: (platform: NodeJS.Platform) => BrowserExecutable | null;
|
|
||||||
readBrowserVersion: (executablePath: string) => string | null;
|
|
||||||
parseBrowserMajorVersion: (rawVersion: string | null | undefined) => number | null;
|
|
||||||
};
|
|
||||||
|
|
||||||
let cachedBrowserHostInspectionSurface: BrowserHostInspectionSurface | undefined;
|
|
||||||
|
|
||||||
function loadBrowserHostInspectionSurface(): BrowserHostInspectionSurface {
|
|
||||||
cachedBrowserHostInspectionSurface ??=
|
|
||||||
loadBundledPluginPublicSurfaceModuleSyncCore<BrowserHostInspectionSurface>({
|
|
||||||
dirName: "browser",
|
|
||||||
artifactBasename: "browser-host-inspection.js",
|
|
||||||
});
|
|
||||||
return cachedBrowserHostInspectionSurface;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Resolves the preferred local Chrome-compatible executable for a platform. */
|
|
||||||
export function resolveGoogleChromeExecutableForPlatform(
|
|
||||||
platform: NodeJS.Platform,
|
|
||||||
): BrowserExecutable | null {
|
|
||||||
return loadBrowserHostInspectionSurface().resolveGoogleChromeExecutableForPlatform(platform);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Reads a browser executable version string through the activated browser facade. */
|
|
||||||
export function readBrowserVersion(executablePath: string): string | null {
|
|
||||||
return loadBrowserHostInspectionSurface().readBrowserVersion(executablePath);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Parses a browser major version from raw command output. */
|
|
||||||
export function parseBrowserMajorVersion(rawVersion: string | null | undefined): number | null {
|
|
||||||
return loadBrowserHostInspectionSurface().parseBrowserMajorVersion(rawVersion);
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
/**
|
|
||||||
* Public SDK subpath for normalizing Google and Antigravity preview model ids.
|
|
||||||
*/
|
|
||||||
export {
|
|
||||||
normalizeAntigravityPreviewModelId as normalizeAntigravityModelId,
|
|
||||||
normalizeGooglePreviewModelId as normalizeGoogleModelId,
|
|
||||||
} from "./provider-model-shared.js";
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
/**
|
|
||||||
* Tests OpenCode SDK helpers and provider-facing OpenCode contracts.
|
|
||||||
*/
|
|
||||||
import { describe, expect, it } from "vitest";
|
|
||||||
import { createOpencodeCatalogApiKeyAuthMethod } from "./opencode.js";
|
|
||||||
|
|
||||||
describe("createOpencodeCatalogApiKeyAuthMethod", () => {
|
|
||||||
it("locks the shared OpenCode auth contract", () => {
|
|
||||||
const method = createOpencodeCatalogApiKeyAuthMethod({
|
|
||||||
providerId: "opencode-go",
|
|
||||||
label: "OpenCode Go catalog",
|
|
||||||
optionKey: "opencodeGoApiKey",
|
|
||||||
flagName: "--opencode-go-api-key",
|
|
||||||
defaultModel: "opencode-go/kimi-k2.6",
|
|
||||||
applyConfig: (cfg) => cfg,
|
|
||||||
noteMessage: "OpenCode uses one API key across the Zen and Go catalogs.",
|
|
||||||
choiceId: "opencode-go",
|
|
||||||
choiceLabel: "OpenCode Go catalog",
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(method.id).toBe("api-key");
|
|
||||||
expect(method.label).toBe("OpenCode Go catalog");
|
|
||||||
expect(method.hint).toBe("Shared API key for Zen + Go catalogs");
|
|
||||||
expect(method.kind).toBe("api_key");
|
|
||||||
if (!method.wizard) {
|
|
||||||
throw new Error("expected OpenCode auth method to include wizard metadata");
|
|
||||||
}
|
|
||||||
expect(method.wizard.choiceId).toBe("opencode-go");
|
|
||||||
expect(method.wizard.choiceLabel).toBe("OpenCode Go catalog");
|
|
||||||
expect(method.wizard.groupId).toBe("opencode");
|
|
||||||
expect(method.wizard.groupLabel).toBe("OpenCode");
|
|
||||||
expect(method.wizard.groupHint).toBe("Shared API key for Zen + Go catalogs");
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
// OpenCode provider helpers expose auth and model defaults for the OpenCode-compatible plugin.
|
|
||||||
import { createProviderApiKeyAuthMethod, type OpenClawConfig } from "./provider-auth-api-key.js";
|
|
||||||
|
|
||||||
export { applyOpencodeZenModelDefault, OPENCODE_ZEN_DEFAULT_MODEL } from "./provider-onboard.js";
|
|
||||||
|
|
||||||
const OPENCODE_SHARED_PROFILE_IDS = ["opencode:default", "opencode-go:default"] as const;
|
|
||||||
const OPENCODE_SHARED_HINT = "Shared API key for Zen + Go catalogs";
|
|
||||||
const OPENCODE_SHARED_WIZARD_GROUP = {
|
|
||||||
groupId: "opencode",
|
|
||||||
groupLabel: "OpenCode",
|
|
||||||
groupHint: OPENCODE_SHARED_HINT,
|
|
||||||
} as const;
|
|
||||||
|
|
||||||
/** Build a shared OpenCode API-key auth method for one OpenCode-compatible catalog. */
|
|
||||||
export function createOpencodeCatalogApiKeyAuthMethod(params: {
|
|
||||||
/** Provider id for the catalog being configured, such as `opencode` or `opencode-go`. */
|
|
||||||
providerId: string;
|
|
||||||
/** Human-facing auth method label for this catalog. */
|
|
||||||
label: string;
|
|
||||||
/** CLI/setup option key that carries the OpenCode API key. */
|
|
||||||
optionKey: string;
|
|
||||||
/** CLI flag name that maps to the option key. */
|
|
||||||
flagName: `--${string}`;
|
|
||||||
/** Default model written when this catalog is selected. */
|
|
||||||
defaultModel: string;
|
|
||||||
/** Provider-specific config patch applied after shared API-key auth succeeds. */
|
|
||||||
applyConfig: (cfg: OpenClawConfig) => OpenClawConfig;
|
|
||||||
/** Setup note explaining how the shared OpenCode key is reused. */
|
|
||||||
noteMessage: string;
|
|
||||||
/** Wizard choice id for this catalog. */
|
|
||||||
choiceId: string;
|
|
||||||
/** Wizard choice label for this catalog. */
|
|
||||||
choiceLabel: string;
|
|
||||||
}) {
|
|
||||||
return createProviderApiKeyAuthMethod({
|
|
||||||
providerId: params.providerId,
|
|
||||||
methodId: "api-key",
|
|
||||||
label: params.label,
|
|
||||||
hint: OPENCODE_SHARED_HINT,
|
|
||||||
optionKey: params.optionKey,
|
|
||||||
flagName: params.flagName,
|
|
||||||
envVar: "OPENCODE_API_KEY",
|
|
||||||
promptMessage: "Enter OpenCode API key",
|
|
||||||
// Zen and Go catalogs intentionally share profile ids so one imported key
|
|
||||||
// satisfies either provider without duplicate credential prompts.
|
|
||||||
profileIds: [...OPENCODE_SHARED_PROFILE_IDS],
|
|
||||||
defaultModel: params.defaultModel,
|
|
||||||
expectedProviders: ["opencode", "opencode-go"],
|
|
||||||
applyConfig: params.applyConfig,
|
|
||||||
noteMessage: params.noteMessage,
|
|
||||||
noteTitle: "OpenCode",
|
|
||||||
wizard: {
|
|
||||||
choiceId: params.choiceId,
|
|
||||||
choiceLabel: params.choiceLabel,
|
|
||||||
...OPENCODE_SHARED_WIZARD_GROUP,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
@@ -1,10 +1,28 @@
|
|||||||
import { describe, expect, it } from "vitest";
|
import { describe, expect, it } from "vitest";
|
||||||
import {
|
import {
|
||||||
|
applyOpencodeZenModelDefault,
|
||||||
createAliasOnlyPresetAppliers,
|
createAliasOnlyPresetAppliers,
|
||||||
|
OPENCODE_ZEN_DEFAULT_MODEL,
|
||||||
resolveAgentModelPrimaryValue,
|
resolveAgentModelPrimaryValue,
|
||||||
type OpenClawConfig,
|
type OpenClawConfig,
|
||||||
} from "./provider-onboard.js";
|
} from "./provider-onboard.js";
|
||||||
|
|
||||||
|
function expectPrimaryModelChanged(
|
||||||
|
applied: { changed: boolean; next: OpenClawConfig },
|
||||||
|
primary: string,
|
||||||
|
) {
|
||||||
|
expect(applied.changed).toBe(true);
|
||||||
|
expect(applied.next.agents?.defaults?.model).toEqual({ primary });
|
||||||
|
}
|
||||||
|
|
||||||
|
function expectConfigUnchanged(
|
||||||
|
applied: { changed: boolean; next: OpenClawConfig },
|
||||||
|
cfg: OpenClawConfig,
|
||||||
|
) {
|
||||||
|
expect(applied.changed).toBe(false);
|
||||||
|
expect(applied.next).toEqual(cfg);
|
||||||
|
}
|
||||||
|
|
||||||
describe("createAliasOnlyPresetAppliers", () => {
|
describe("createAliasOnlyPresetAppliers", () => {
|
||||||
const modelRef = "example/default";
|
const modelRef = "example/default";
|
||||||
const appliers = createAliasOnlyPresetAppliers({ modelRef, alias: "Example" });
|
const appliers = createAliasOnlyPresetAppliers({ modelRef, alias: "Example" });
|
||||||
@@ -48,3 +66,54 @@ describe("createAliasOnlyPresetAppliers", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("applyOpencodeZenModelDefault", () => {
|
||||||
|
it("sets defaults when model is unset", () => {
|
||||||
|
const cfg: OpenClawConfig = { agents: { defaults: {} } };
|
||||||
|
const applied = applyOpencodeZenModelDefault(cfg);
|
||||||
|
expectPrimaryModelChanged(applied, OPENCODE_ZEN_DEFAULT_MODEL);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("overrides existing models", () => {
|
||||||
|
const cfg = {
|
||||||
|
agents: { defaults: { model: "anthropic/claude-opus-4-6" } },
|
||||||
|
} as OpenClawConfig;
|
||||||
|
const applied = applyOpencodeZenModelDefault(cfg);
|
||||||
|
expectPrimaryModelChanged(applied, OPENCODE_ZEN_DEFAULT_MODEL);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("no-ops when already legacy opencode-zen default", () => {
|
||||||
|
const cfg = {
|
||||||
|
agents: { defaults: { model: "opencode-zen/claude-opus-4-5" } },
|
||||||
|
} as OpenClawConfig;
|
||||||
|
const applied = applyOpencodeZenModelDefault(cfg);
|
||||||
|
expectConfigUnchanged(applied, cfg);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("preserves fallbacks when setting primary", () => {
|
||||||
|
const cfg: OpenClawConfig = {
|
||||||
|
agents: {
|
||||||
|
defaults: {
|
||||||
|
model: {
|
||||||
|
primary: "anthropic/claude-opus-4-6",
|
||||||
|
fallbacks: ["google/gemini-3-pro"],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const applied = applyOpencodeZenModelDefault(cfg);
|
||||||
|
expect(applied.changed).toBe(true);
|
||||||
|
expect(applied.next.agents?.defaults?.model).toEqual({
|
||||||
|
primary: OPENCODE_ZEN_DEFAULT_MODEL,
|
||||||
|
fallbacks: ["google/gemini-3.1-pro-preview"],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("no-ops when already on the current default", () => {
|
||||||
|
const cfg = {
|
||||||
|
agents: { defaults: { model: OPENCODE_ZEN_DEFAULT_MODEL } },
|
||||||
|
} as OpenClawConfig;
|
||||||
|
const applied = applyOpencodeZenModelDefault(cfg);
|
||||||
|
expectConfigUnchanged(applied, cfg);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@@ -140,17 +140,6 @@ const BROWSER_FACADE_SOURCE_CONTRACTS: readonly BrowserFacadeSourceContract[] =
|
|||||||
"normalizeHexColor",
|
"normalizeHexColor",
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
|
||||||
subpath: "browser-host-inspection",
|
|
||||||
artifactBasename: "browser-host-inspection.js",
|
|
||||||
mentions: [
|
|
||||||
"loadBundledPluginPublicSurfaceModuleSyncCore",
|
|
||||||
"resolveGoogleChromeExecutableForPlatform",
|
|
||||||
"readBrowserVersion",
|
|
||||||
"parseBrowserMajorVersion",
|
|
||||||
],
|
|
||||||
omits: ["findFirstChromeExecutable", "findGoogleChromeExecutableLinux", "execText"],
|
|
||||||
},
|
|
||||||
];
|
];
|
||||||
|
|
||||||
const BROWSER_HELPER_EXPORT_PARITY_CONTRACTS: readonly BrowserHelperExportParityContract[] = [
|
const BROWSER_HELPER_EXPORT_PARITY_CONTRACTS: readonly BrowserHelperExportParityContract[] = [
|
||||||
@@ -183,16 +172,6 @@ const BROWSER_HELPER_EXPORT_PARITY_CONTRACTS: readonly BrowserHelperExportParity
|
|||||||
"resolveProfile",
|
"resolveProfile",
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
|
||||||
corePath: "src/plugin-sdk/browser-host-inspection.ts",
|
|
||||||
extensionPath: "extensions/browser/browser-host-inspection.ts",
|
|
||||||
expectedExports: [
|
|
||||||
"BrowserExecutable",
|
|
||||||
"parseBrowserMajorVersion",
|
|
||||||
"readBrowserVersion",
|
|
||||||
"resolveGoogleChromeExecutableForPlatform",
|
|
||||||
],
|
|
||||||
},
|
|
||||||
];
|
];
|
||||||
|
|
||||||
function readCachedSource(absolutePath: string): string {
|
function readCachedSource(absolutePath: string): string {
|
||||||
@@ -1278,9 +1257,6 @@ describe("plugin-sdk subpath exports", () => {
|
|||||||
expectSourceOmitsSnippet("agent-runtime", "./sglang.js");
|
expectSourceOmitsSnippet("agent-runtime", "./sglang.js");
|
||||||
expectSourceOmitsSnippet("agent-runtime", "./vllm.js");
|
expectSourceOmitsSnippet("agent-runtime", "./vllm.js");
|
||||||
expectSourceOmitsSnippet("agent-runtime", "../../extensions/");
|
expectSourceOmitsSnippet("agent-runtime", "../../extensions/");
|
||||||
expectSourceOmitsSnippet("google-model-id", "./google.js");
|
|
||||||
expectSourceOmitsSnippet("google-model-id", "./facade-runtime.js");
|
|
||||||
expectSourceOmitsSnippet("google-model-id", "../../extensions/");
|
|
||||||
expectRepoSourceOmitsSnippet("extensions/xai/model-id.ts", "./xai.js");
|
expectRepoSourceOmitsSnippet("extensions/xai/model-id.ts", "./xai.js");
|
||||||
expectRepoSourceOmitsSnippet("extensions/xai/model-id.ts", "./facade-runtime.js");
|
expectRepoSourceOmitsSnippet("extensions/xai/model-id.ts", "./facade-runtime.js");
|
||||||
expectRepoSourceOmitsSnippet("extensions/xai/model-id.ts", "../../extensions/");
|
expectRepoSourceOmitsSnippet("extensions/xai/model-id.ts", "../../extensions/");
|
||||||
|
|||||||
@@ -256,7 +256,6 @@ describe("check-deadcode-exports", () => {
|
|||||||
"browser-control-auth.ts!",
|
"browser-control-auth.ts!",
|
||||||
"browser-config.ts!",
|
"browser-config.ts!",
|
||||||
"browser-doctor.ts!",
|
"browser-doctor.ts!",
|
||||||
"browser-host-inspection.ts!",
|
|
||||||
"browser-maintenance.ts!",
|
"browser-maintenance.ts!",
|
||||||
"browser-profiles.ts!",
|
"browser-profiles.ts!",
|
||||||
]),
|
]),
|
||||||
|
|||||||
Reference in New Issue
Block a user