mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-02 16:01:34 +00:00
* feat: add isolated pure-inference completion * fix(google): block ambient system prompt writes * docs: refresh generated map
174 lines
5.2 KiB
TypeScript
174 lines
5.2 KiB
TypeScript
import type { CliBackendPlugin } from "openclaw/plugin-sdk/cli-backend";
|
|
import type { ProviderPlugin } from "openclaw/plugin-sdk/provider-model-shared";
|
|
import { describe, expect, it } from "vitest";
|
|
import { buildGoogleGeminiCliBackend } from "./cli-backend.js";
|
|
import setupEntry from "./setup-api.js";
|
|
|
|
describe("google setup entry", () => {
|
|
it("registers setup runtime providers declared by the manifest", () => {
|
|
const providerIds: string[] = [];
|
|
const cliBackendIds: string[] = [];
|
|
|
|
setupEntry.register({
|
|
registerProvider(provider: ProviderPlugin) {
|
|
providerIds.push(provider.id);
|
|
},
|
|
registerCliBackend(backend: CliBackendPlugin) {
|
|
cliBackendIds.push(backend.id);
|
|
},
|
|
} as never);
|
|
|
|
expect(providerIds).toEqual(["google-vertex"]);
|
|
expect(cliBackendIds).toEqual(["google-gemini-cli"]);
|
|
});
|
|
});
|
|
|
|
describe("google gemini cli backend config", () => {
|
|
it.each([
|
|
{
|
|
phase: "fresh",
|
|
key: "args" as const,
|
|
expected: [
|
|
"--skip-trust",
|
|
"--approval-mode",
|
|
"auto_edit",
|
|
"--output-format",
|
|
"stream-json",
|
|
"--prompt",
|
|
"{prompt}",
|
|
],
|
|
},
|
|
{
|
|
phase: "resume",
|
|
key: "resumeArgs" as const,
|
|
expected: [
|
|
"--skip-trust",
|
|
"--approval-mode",
|
|
"auto_edit",
|
|
"--resume",
|
|
"{sessionId}",
|
|
"--output-format",
|
|
"stream-json",
|
|
"--prompt",
|
|
"{prompt}",
|
|
],
|
|
},
|
|
])("preserves the legacy $phase command bytes in plugin code", ({ key, expected }) => {
|
|
const backend = buildGoogleGeminiCliBackend();
|
|
|
|
expect(backend.config.command).toBe("gemini");
|
|
expect(backend.config[key]).toEqual(expected);
|
|
expect(backend.config.env).toBeUndefined();
|
|
expect(backend.config.clearEnv).toBeUndefined();
|
|
});
|
|
|
|
it("declares its bundled package implementation boundary", () => {
|
|
const backend = buildGoogleGeminiCliBackend();
|
|
expect(backend.runtimeArtifact).toEqual({
|
|
kind: "bundled-package-tree",
|
|
packageName: "@google/gemini-cli",
|
|
entrypoint: "command",
|
|
exactToolAvailabilityVersionPolicy: {
|
|
stableMinimum: "0.39.1",
|
|
prereleaseMinimums: {
|
|
preview: "0.40.0-preview.3",
|
|
nightly: "0.41.0-nightly.20260427.g42587de73",
|
|
},
|
|
},
|
|
});
|
|
expect(backend.nativeToolMode).toBe("selectable");
|
|
expect(backend.toolAvailabilityEnforcement).toBe("prepare-execution");
|
|
});
|
|
|
|
it("enforces exact MCP server availability with a per-run argv override", () => {
|
|
const backend = buildGoogleGeminiCliBackend();
|
|
const baseContext = {
|
|
workspaceDir: "/tmp/openclaw-gemini-test",
|
|
provider: "google-gemini-cli",
|
|
modelId: "gemini-3.1-pro-preview",
|
|
useResume: false,
|
|
baseArgs: [
|
|
"--allowedMcpServerNames",
|
|
"camel-hostile",
|
|
"--allowed_mcp_server_names=snake-hostile",
|
|
"--allowed-mcp-server-names",
|
|
"hostile",
|
|
"--allowed-mcp-server-names=also-hostile",
|
|
"--prompt",
|
|
"{prompt}",
|
|
"--",
|
|
"--allowed-mcp-server-names",
|
|
"positional-hostile",
|
|
],
|
|
};
|
|
|
|
const restrictedArgs = backend.resolveExecutionArgs?.({
|
|
...baseContext,
|
|
toolAvailability: { native: [], openClaw: ["read"], mcp: ["read"] },
|
|
});
|
|
expect(restrictedArgs).toEqual([
|
|
"--prompt",
|
|
"{prompt}",
|
|
"--allowed-mcp-server-names",
|
|
"openclaw",
|
|
"--",
|
|
"--allowed-mcp-server-names",
|
|
"positional-hostile",
|
|
]);
|
|
|
|
const emptyArgs = backend.resolveExecutionArgs?.({
|
|
...baseContext,
|
|
toolAvailability: { native: [], openClaw: [], mcp: [] },
|
|
});
|
|
expect(emptyArgs?.slice(0, -4)).toEqual(["--prompt", "{prompt}", "--allowed-mcp-server-names"]);
|
|
expect(emptyArgs?.at(-4)).toMatch(
|
|
/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/,
|
|
);
|
|
expect(emptyArgs?.slice(-3)).toEqual([
|
|
"--",
|
|
"--allowed-mcp-server-names",
|
|
"positional-hostile",
|
|
]);
|
|
});
|
|
|
|
it("keeps legacy json output overrides on the json parser", () => {
|
|
const backend = buildGoogleGeminiCliBackend();
|
|
const normalized = backend.normalizeConfig?.({
|
|
...backend.config,
|
|
args: ["--skip-trust", "--output-format", "json", "--prompt", "{prompt}"],
|
|
resumeArgs: [
|
|
"--skip-trust",
|
|
"--resume",
|
|
"{sessionId}",
|
|
"--output-format=json",
|
|
"--prompt",
|
|
"{prompt}",
|
|
],
|
|
});
|
|
|
|
expect(normalized?.output).toBe("json");
|
|
expect(normalized?.resumeOutput).toBe("json");
|
|
expect(normalized?.jsonlDialect).toBeUndefined();
|
|
});
|
|
|
|
it("keeps short stream-json output overrides on the jsonl parser", () => {
|
|
const backend = buildGoogleGeminiCliBackend();
|
|
const normalized = backend.normalizeConfig?.({
|
|
...backend.config,
|
|
args: ["--skip-trust", "-o", "stream-json", "--prompt", "{prompt}"],
|
|
resumeArgs: [
|
|
"--skip-trust",
|
|
"--resume",
|
|
"{sessionId}",
|
|
"-o=stream-json",
|
|
"--prompt",
|
|
"{prompt}",
|
|
],
|
|
});
|
|
|
|
expect(normalized?.output).toBe("jsonl");
|
|
expect(normalized?.resumeOutput).toBe("jsonl");
|
|
expect(normalized?.jsonlDialect).toBe("gemini-stream-json");
|
|
});
|
|
});
|