144 lines
4.3 KiB
TypeScript
144 lines
4.3 KiB
TypeScript
import { describe, it } from "vitest";
|
|
import fc from "fast-check";
|
|
import { PiBackend } from "../../src/backends/pi-backend.js";
|
|
import type { BackendAdapterConfig } from "../../src/backends/types.js";
|
|
|
|
// Feature: multi-cli-backend, Property: Pi backend required flags
|
|
// Validates Pi-specific CLI argument construction
|
|
|
|
/**
|
|
* Arbitrary for non-empty strings that won't break CLI arg parsing.
|
|
*/
|
|
const nonEmptyString = fc.string({ minLength: 1, maxLength: 200 });
|
|
|
|
/**
|
|
* Arbitrary for model strings (provider/model format).
|
|
*/
|
|
const modelString = fc.stringMatching(/^[a-z]{1,20}\/[a-z0-9-]{1,40}$/);
|
|
|
|
function createBackend(model?: string): PiBackend {
|
|
const config: BackendAdapterConfig = {
|
|
cliPath: "pi",
|
|
workingDir: "/tmp",
|
|
queryTimeoutMs: 60000,
|
|
allowedTools: [],
|
|
maxTurns: 25,
|
|
model,
|
|
};
|
|
return new PiBackend(config);
|
|
}
|
|
|
|
describe("Pi backend required flags", () => {
|
|
it("generated args always contain -p for print mode", () => {
|
|
fc.assert(
|
|
fc.property(
|
|
nonEmptyString,
|
|
(prompt) => {
|
|
const backend = createBackend();
|
|
const args = backend.buildArgs(prompt);
|
|
|
|
return args.includes("-p");
|
|
},
|
|
),
|
|
{ numRuns: 100 },
|
|
);
|
|
});
|
|
|
|
it("generated args always contain --mode json", () => {
|
|
fc.assert(
|
|
fc.property(
|
|
nonEmptyString,
|
|
(prompt) => {
|
|
const backend = createBackend();
|
|
const args = backend.buildArgs(prompt);
|
|
|
|
const modeIndex = args.indexOf("--mode");
|
|
return modeIndex !== -1 && args[modeIndex + 1] === "json";
|
|
},
|
|
),
|
|
{ numRuns: 100 },
|
|
);
|
|
});
|
|
|
|
it("generated args contain --model when a model is configured", () => {
|
|
fc.assert(
|
|
fc.property(
|
|
nonEmptyString,
|
|
modelString,
|
|
(prompt, model) => {
|
|
const backend = createBackend(model);
|
|
const args = backend.buildArgs(prompt);
|
|
|
|
const modelIndex = args.indexOf("--model");
|
|
return modelIndex !== -1 && args[modelIndex + 1] === model;
|
|
},
|
|
),
|
|
{ numRuns: 100 },
|
|
);
|
|
});
|
|
|
|
it("generated args do not contain --model when no model is configured", () => {
|
|
fc.assert(
|
|
fc.property(
|
|
nonEmptyString,
|
|
(prompt) => {
|
|
const backend = createBackend(undefined);
|
|
const args = backend.buildArgs(prompt);
|
|
|
|
return !args.includes("--model");
|
|
},
|
|
),
|
|
{ numRuns: 100 },
|
|
);
|
|
});
|
|
|
|
it("generated args contain --no-session for headless usage", () => {
|
|
fc.assert(
|
|
fc.property(
|
|
nonEmptyString,
|
|
(prompt) => {
|
|
const backend = createBackend();
|
|
const args = backend.buildArgs(prompt);
|
|
|
|
return args.includes("--no-session");
|
|
},
|
|
),
|
|
{ numRuns: 100 },
|
|
);
|
|
});
|
|
|
|
it("generated args contain --no-extensions, --no-skills, --no-themes for deterministic runs", () => {
|
|
fc.assert(
|
|
fc.property(
|
|
nonEmptyString,
|
|
(prompt) => {
|
|
const backend = createBackend();
|
|
const args = backend.buildArgs(prompt);
|
|
|
|
return (
|
|
args.includes("--no-extensions") &&
|
|
args.includes("--no-skills") &&
|
|
args.includes("--no-themes")
|
|
);
|
|
},
|
|
),
|
|
{ numRuns: 100 },
|
|
);
|
|
});
|
|
|
|
it("prompt is always the last argument", () => {
|
|
fc.assert(
|
|
fc.property(
|
|
nonEmptyString,
|
|
(prompt) => {
|
|
const backend = createBackend();
|
|
const args = backend.buildArgs(prompt);
|
|
|
|
return args[args.length - 1] === prompt;
|
|
},
|
|
),
|
|
{ numRuns: 100 },
|
|
);
|
|
});
|
|
});
|