mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 11:00:42 +00:00
fix(qa): restore agentic parity tool runtime
This commit is contained in:
@@ -76,7 +76,8 @@ describe("qa docker harness", () => {
|
||||
|
||||
const config = await readFile(path.join(outputDir, "state", "openclaw.json"), "utf8");
|
||||
expect(config).toContain('"allowInsecureAuth": true');
|
||||
expect(config).toContain('"enabled": false');
|
||||
expect(config).toContain('"pluginToolsMcpBridge": true');
|
||||
expect(config).toContain('"openClawToolsMcpBridge": true');
|
||||
expect(config).toContain("/app/dist/control-ui");
|
||||
expect(config).toContain("C-3PO QA");
|
||||
expect(config).toContain('"/tmp/openclaw/workspace"');
|
||||
|
||||
@@ -59,7 +59,13 @@ describe("buildQaGatewayConfig", () => {
|
||||
expect(cfg.models?.providers?.anthropic?.baseUrl).toBe("http://127.0.0.1:44080");
|
||||
expect(cfg.models?.providers?.anthropic?.request).toEqual({ allowPrivateNetwork: true });
|
||||
expect(cfg.plugins?.allow).toEqual(["acpx", "memory-core", "qa-channel"]);
|
||||
expect(cfg.plugins?.entries?.acpx).toEqual({ enabled: false });
|
||||
expect(cfg.plugins?.entries?.acpx).toEqual({
|
||||
enabled: true,
|
||||
config: {
|
||||
pluginToolsMcpBridge: true,
|
||||
openClawToolsMcpBridge: true,
|
||||
},
|
||||
});
|
||||
expect(cfg.plugins?.entries?.["memory-core"]).toEqual({ enabled: true });
|
||||
expect(cfg.plugins?.entries?.["qa-channel"]).toEqual({ enabled: true });
|
||||
expect(cfg.plugins?.entries?.openai).toBeUndefined();
|
||||
|
||||
@@ -118,10 +118,11 @@ export function buildQaGatewayConfig(params: {
|
||||
allow: allowedPlugins,
|
||||
entries: {
|
||||
acpx: {
|
||||
// The parity gateway stages a clean bundled-plugin tree. Keep the
|
||||
// runtime backend plugin in the allowlist so this disabled entry is
|
||||
// not mistaken for stale config when optional bundles are pruned.
|
||||
enabled: false,
|
||||
enabled: true,
|
||||
config: {
|
||||
pluginToolsMcpBridge: true,
|
||||
openClawToolsMcpBridge: true,
|
||||
},
|
||||
},
|
||||
"memory-core": {
|
||||
enabled: true,
|
||||
|
||||
@@ -597,9 +597,13 @@ vi.mock("../thinking.js", () => ({
|
||||
dropThinkingBlocks: <T>(messages: T) => messages,
|
||||
}));
|
||||
|
||||
vi.mock("../tool-name-allowlist.js", () => ({
|
||||
collectAllowedToolNames: () => undefined,
|
||||
}));
|
||||
vi.mock("../tool-name-allowlist.js", async (importOriginal) => {
|
||||
const actual = await importOriginal<typeof import("../tool-name-allowlist.js")>();
|
||||
return {
|
||||
...actual,
|
||||
collectAllowedToolNames: () => undefined,
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock("../tool-split.js", () => ({
|
||||
splitSdkTools: ({ tools }: { tools: unknown[] }) => ({
|
||||
@@ -660,6 +664,7 @@ export type MutableSession = {
|
||||
};
|
||||
};
|
||||
prompt: (prompt: string, options?: { images?: unknown[] }) => Promise<void>;
|
||||
setActiveToolsByName: (toolNames: string[]) => void;
|
||||
abort: () => Promise<void>;
|
||||
dispose: () => void;
|
||||
steer: (text: string) => Promise<void>;
|
||||
@@ -772,6 +777,7 @@ export function createDefaultEmbeddedSession(params?: {
|
||||
},
|
||||
},
|
||||
},
|
||||
setActiveToolsByName: () => {},
|
||||
prompt: async (prompt, options) => {
|
||||
if (params?.prompt) {
|
||||
await params.prompt(session, prompt, options);
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
||||
import {
|
||||
cleanupTempPaths,
|
||||
createContextEngineAttemptRunner,
|
||||
createContextEngineBootstrapAndAssemble,
|
||||
getHoisted,
|
||||
resetEmbeddedAttemptHarness,
|
||||
} from "./attempt.spawn-workspace.test-support.js";
|
||||
|
||||
const hoisted = getHoisted();
|
||||
|
||||
describe("runEmbeddedAttempt tool allowlist", () => {
|
||||
const tempPaths: string[] = [];
|
||||
|
||||
beforeEach(() => {
|
||||
resetEmbeddedAttemptHarness();
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await cleanupTempPaths(tempPaths);
|
||||
});
|
||||
|
||||
it("passes OpenClaw-managed custom tool names to Pi's session allowlist", async () => {
|
||||
await createContextEngineAttemptRunner({
|
||||
sessionKey: "agent:qa:repo-contract",
|
||||
tempPaths,
|
||||
contextEngine: createContextEngineBootstrapAndAssemble(),
|
||||
});
|
||||
|
||||
const options = hoisted.createAgentSessionMock.mock.calls.at(-1)?.[0] as
|
||||
| {
|
||||
customTools?: Array<{ name?: string }>;
|
||||
tools?: string[];
|
||||
}
|
||||
| undefined;
|
||||
expect(options?.customTools?.map((tool) => tool.name)).toContain("sessions_spawn");
|
||||
expect(options?.tools).toContain("sessions_spawn");
|
||||
});
|
||||
});
|
||||
@@ -15,7 +15,9 @@ vi.mock("../provider-runtime.runtime.js", () => ({
|
||||
prepareProviderRuntimeAuth: hoisted.prepareProviderRuntimeAuth,
|
||||
}));
|
||||
|
||||
let getApiKeyForModel: typeof import("./runtime-model-auth.runtime.js").getApiKeyForModel;
|
||||
let getRuntimeAuthForModel: typeof import("./runtime-model-auth.runtime.js").getRuntimeAuthForModel;
|
||||
let resolveApiKeyForProvider: typeof import("./runtime-model-auth.runtime.js").resolveApiKeyForProvider;
|
||||
|
||||
const MODEL = {
|
||||
id: "github-copilot/gpt-4o",
|
||||
@@ -26,7 +28,8 @@ const MODEL = {
|
||||
|
||||
describe("runtime-model-auth.runtime", () => {
|
||||
beforeAll(async () => {
|
||||
({ getRuntimeAuthForModel } = await import("./runtime-model-auth.runtime.js"));
|
||||
({ getApiKeyForModel, getRuntimeAuthForModel, resolveApiKeyForProvider } =
|
||||
await import("./runtime-model-auth.runtime.js"));
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
@@ -115,4 +118,24 @@ describe("runtime-model-auth.runtime", () => {
|
||||
});
|
||||
expect(hoisted.prepareProviderRuntimeAuth).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("keeps direct model auth exports available for bundled runtime facades", async () => {
|
||||
hoisted.getApiKeyForModel.mockResolvedValue({
|
||||
apiKey: "model-key",
|
||||
source: "env:OPENAI_API_KEY",
|
||||
mode: "api-key",
|
||||
});
|
||||
hoisted.resolveApiKeyForProvider.mockResolvedValue({
|
||||
apiKey: "provider-key",
|
||||
source: "env:OPENAI_API_KEY",
|
||||
mode: "api-key",
|
||||
});
|
||||
|
||||
await expect(getApiKeyForModel({ model: MODEL as never })).resolves.toMatchObject({
|
||||
apiKey: "model-key",
|
||||
});
|
||||
await expect(resolveApiKeyForProvider({ provider: "openai" })).resolves.toMatchObject({
|
||||
apiKey: "provider-key",
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,10 +1,23 @@
|
||||
import type { Api, Model } from "@mariozechner/pi-ai";
|
||||
import { getApiKeyForModel, resolveApiKeyForProvider } from "../../agents/model-auth.js";
|
||||
import {
|
||||
getApiKeyForModel as resolveModelApiKey,
|
||||
resolveApiKeyForProvider as resolveProviderApiKey,
|
||||
} from "../../agents/model-auth.js";
|
||||
import type { OpenClawConfig } from "../../config/types.openclaw.js";
|
||||
import { prepareProviderRuntimeAuth } from "../provider-runtime.runtime.js";
|
||||
import type { ResolvedProviderRuntimeAuth } from "./model-auth-types.js";
|
||||
|
||||
export { getApiKeyForModel, resolveApiKeyForProvider };
|
||||
export async function getApiKeyForModel(
|
||||
params: Parameters<typeof resolveModelApiKey>[0],
|
||||
): Promise<Awaited<ReturnType<typeof resolveModelApiKey>>> {
|
||||
return resolveModelApiKey(params);
|
||||
}
|
||||
|
||||
export async function resolveApiKeyForProvider(
|
||||
params: Parameters<typeof resolveProviderApiKey>[0],
|
||||
): Promise<Awaited<ReturnType<typeof resolveProviderApiKey>>> {
|
||||
return resolveProviderApiKey(params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve request-ready auth for a runtime model, applying any provider-owned
|
||||
@@ -15,7 +28,7 @@ export async function getRuntimeAuthForModel(params: {
|
||||
cfg?: OpenClawConfig;
|
||||
workspaceDir?: string;
|
||||
}): Promise<ResolvedProviderRuntimeAuth> {
|
||||
const resolvedAuth = await getApiKeyForModel({
|
||||
const resolvedAuth = await resolveModelApiKey({
|
||||
model: params.model,
|
||||
cfg: params.cfg,
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user