mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 07:30:43 +00:00
fix(qa): preserve image generation plugin allowlist
This commit is contained in:
@@ -14,6 +14,23 @@ describe("QA provider image generation config", () => {
|
||||
expect(patch.models?.providers["mock-openai"]?.baseUrl).toBe("http://127.0.0.1:44080/v1");
|
||||
});
|
||||
|
||||
it("preserves already-allowed plugins when configuring image generation", () => {
|
||||
const patch = buildQaImageGenerationConfigPatch({
|
||||
providerMode: "mock-openai",
|
||||
providerBaseUrl: "http://127.0.0.1:44080/v1",
|
||||
requiredPluginIds: ["qa-channel"],
|
||||
existingPluginIds: ["openai", "anthropic", "qa-channel"],
|
||||
});
|
||||
|
||||
expect(patch.plugins.allow).toEqual([
|
||||
"acpx",
|
||||
"memory-core",
|
||||
"openai",
|
||||
"anthropic",
|
||||
"qa-channel",
|
||||
]);
|
||||
});
|
||||
|
||||
it("uses the selected mock provider for AIMock image generation", () => {
|
||||
const patch = buildQaImageGenerationConfigPatch({
|
||||
providerMode: "aimock",
|
||||
|
||||
@@ -6,6 +6,7 @@ type QaImageGenerationPatchInput = {
|
||||
providerMode: QaProviderMode;
|
||||
providerBaseUrl?: string;
|
||||
requiredPluginIds: readonly string[];
|
||||
existingPluginIds?: readonly string[];
|
||||
};
|
||||
|
||||
function splitModelProviderId(modelRef: string) {
|
||||
@@ -48,6 +49,7 @@ export function buildQaImageGenerationConfigPatch(input: QaImageGenerationPatchI
|
||||
plugins: {
|
||||
allow: uniqueNonEmpty([
|
||||
...QA_BASE_RUNTIME_PLUGIN_IDS,
|
||||
...(input.existingPluginIds ?? []),
|
||||
...enabledPluginIds,
|
||||
...input.requiredPluginIds,
|
||||
]),
|
||||
|
||||
@@ -4,12 +4,16 @@ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
const fetchJsonMock = vi.hoisted(() => vi.fn());
|
||||
const patchConfigMock = vi.hoisted(() => vi.fn(async () => undefined));
|
||||
const readConfigSnapshotMock = vi.hoisted(() =>
|
||||
vi.fn(async () => ({ hash: "hash", config: { plugins: { allow: [] as string[] } } })),
|
||||
);
|
||||
const waitForGatewayHealthyMock = vi.hoisted(() => vi.fn(async () => undefined));
|
||||
const waitForTransportReadyMock = vi.hoisted(() => vi.fn(async () => undefined));
|
||||
|
||||
vi.mock("./suite-runtime-gateway.js", () => ({
|
||||
fetchJson: fetchJsonMock,
|
||||
patchConfig: patchConfigMock,
|
||||
readConfigSnapshot: readConfigSnapshotMock,
|
||||
waitForGatewayHealthy: waitForGatewayHealthyMock,
|
||||
waitForTransportReady: waitForTransportReadyMock,
|
||||
}));
|
||||
@@ -29,6 +33,8 @@ describe("qa suite runtime agent media helpers", () => {
|
||||
beforeEach(() => {
|
||||
fetchJsonMock.mockReset();
|
||||
patchConfigMock.mockClear();
|
||||
readConfigSnapshotMock.mockReset();
|
||||
readConfigSnapshotMock.mockResolvedValue({ hash: "hash", config: { plugins: { allow: [] } } });
|
||||
waitForGatewayHealthyMock.mockClear();
|
||||
waitForTransportReadyMock.mockClear();
|
||||
});
|
||||
@@ -102,4 +108,27 @@ describe("qa suite runtime agent media helpers", () => {
|
||||
expect(waitForGatewayHealthyMock).toHaveBeenCalled();
|
||||
expect(waitForTransportReadyMock).toHaveBeenCalledWith(expect.anything(), 60_000);
|
||||
});
|
||||
|
||||
it("preserves plugins already allowed by the gateway when configuring media", async () => {
|
||||
readConfigSnapshotMock.mockResolvedValue({
|
||||
hash: "hash",
|
||||
config: { plugins: { allow: ["openai", "anthropic", "qa-channel"] } },
|
||||
});
|
||||
|
||||
await ensureImageGenerationConfigured({
|
||||
providerMode: "mock-openai",
|
||||
mock: { baseUrl: "http://127.0.0.1:9999" },
|
||||
transport: { requiredPluginIds: ["qa-channel"] },
|
||||
} as never);
|
||||
|
||||
expect(patchConfigMock).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
patch: expect.objectContaining({
|
||||
plugins: expect.objectContaining({
|
||||
allow: ["acpx", "memory-core", "openai", "anthropic", "qa-channel"],
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -4,6 +4,7 @@ import { buildQaImageGenerationConfigPatch } from "./providers/image-generation.
|
||||
import {
|
||||
fetchJson,
|
||||
patchConfig,
|
||||
readConfigSnapshot,
|
||||
waitForGatewayHealthy,
|
||||
waitForTransportReady,
|
||||
} from "./suite-runtime-gateway.js";
|
||||
@@ -13,6 +14,19 @@ function extractMediaPathFromText(text: string | undefined): string | undefined
|
||||
return /MEDIA:([^\n]+)/.exec(text ?? "")?.[1]?.trim();
|
||||
}
|
||||
|
||||
function readPluginAllow(config: Record<string, unknown>) {
|
||||
const plugins = config.plugins;
|
||||
if (typeof plugins !== "object" || plugins === null || Array.isArray(plugins)) {
|
||||
return [];
|
||||
}
|
||||
const allow = (plugins as { allow?: unknown }).allow;
|
||||
return Array.isArray(allow)
|
||||
? allow.filter(
|
||||
(pluginId): pluginId is string => typeof pluginId === "string" && pluginId.length > 0,
|
||||
)
|
||||
: [];
|
||||
}
|
||||
|
||||
async function resolveGeneratedImagePath(params: {
|
||||
env: Pick<QaSuiteRuntimeEnv, "mock" | "gateway">;
|
||||
promptSnippet: string;
|
||||
@@ -71,12 +85,14 @@ async function resolveGeneratedImagePath(params: {
|
||||
}
|
||||
|
||||
async function ensureImageGenerationConfigured(env: QaSuiteRuntimeEnv) {
|
||||
const snapshot = await readConfigSnapshot(env);
|
||||
await patchConfig({
|
||||
env,
|
||||
patch: buildQaImageGenerationConfigPatch({
|
||||
providerMode: env.providerMode,
|
||||
providerBaseUrl: env.mock ? `${env.mock.baseUrl}/v1` : undefined,
|
||||
requiredPluginIds: env.transport.requiredPluginIds,
|
||||
existingPluginIds: readPluginAllow(snapshot.config),
|
||||
}),
|
||||
});
|
||||
await waitForGatewayHealthy(env);
|
||||
|
||||
Reference in New Issue
Block a user