Merge branch 'main' of github.com:getpaseo/paseo
This commit is contained in:
@@ -0,0 +1,89 @@
|
|||||||
|
import { describe, it, expect } from "vitest";
|
||||||
|
import { buildLoopRunInput } from "./run.js";
|
||||||
|
import type { LoopRunOptions } from "./types.js";
|
||||||
|
|
||||||
|
describe("buildLoopRunInput", () => {
|
||||||
|
it("should parse provider/model from provider string", () => {
|
||||||
|
const options: LoopRunOptions = {
|
||||||
|
provider: "opencode/hy3-preview-free",
|
||||||
|
model: undefined,
|
||||||
|
verifyProvider: undefined,
|
||||||
|
verifyModel: undefined,
|
||||||
|
verify: undefined,
|
||||||
|
verifyCheck: [],
|
||||||
|
archive: false,
|
||||||
|
name: undefined,
|
||||||
|
sleep: undefined,
|
||||||
|
maxIterations: undefined,
|
||||||
|
maxTime: undefined,
|
||||||
|
} as LoopRunOptions;
|
||||||
|
|
||||||
|
const result = buildLoopRunInput("test prompt", options);
|
||||||
|
|
||||||
|
expect(result.provider).toBe("opencode");
|
||||||
|
expect(result.model).toBe("hy3-preview-free");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should use provider only when no model in string", () => {
|
||||||
|
const options = {
|
||||||
|
provider: "opencode",
|
||||||
|
model: undefined,
|
||||||
|
verifyProvider: undefined,
|
||||||
|
verifyModel: undefined,
|
||||||
|
verify: undefined,
|
||||||
|
verifyCheck: [],
|
||||||
|
archive: false,
|
||||||
|
name: undefined,
|
||||||
|
sleep: undefined,
|
||||||
|
maxIterations: undefined,
|
||||||
|
maxTime: undefined,
|
||||||
|
} as LoopRunOptions;
|
||||||
|
|
||||||
|
const result = buildLoopRunInput("test prompt", options);
|
||||||
|
|
||||||
|
expect(result.provider).toBe("opencode");
|
||||||
|
expect(result.model).toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should pass verifierProvider with model parsing", () => {
|
||||||
|
const options = {
|
||||||
|
provider: undefined,
|
||||||
|
model: undefined,
|
||||||
|
verifyProvider: "codex/gpt-5.4",
|
||||||
|
verifyModel: undefined,
|
||||||
|
verify: undefined,
|
||||||
|
verifyCheck: [],
|
||||||
|
archive: false,
|
||||||
|
name: undefined,
|
||||||
|
sleep: undefined,
|
||||||
|
maxIterations: undefined,
|
||||||
|
maxTime: undefined,
|
||||||
|
} as LoopRunOptions;
|
||||||
|
|
||||||
|
const result = buildLoopRunInput("test prompt", options);
|
||||||
|
|
||||||
|
expect(result.verifierProvider).toBe("codex");
|
||||||
|
expect(result.verifierModel).toBe("gpt-5.4");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should prefer explicit model over parsed model", () => {
|
||||||
|
const options = {
|
||||||
|
provider: "opencode/hy3-preview-free",
|
||||||
|
model: "other-model",
|
||||||
|
verifyProvider: undefined,
|
||||||
|
verifyModel: undefined,
|
||||||
|
verify: undefined,
|
||||||
|
verifyCheck: [],
|
||||||
|
archive: false,
|
||||||
|
name: undefined,
|
||||||
|
sleep: undefined,
|
||||||
|
maxIterations: undefined,
|
||||||
|
maxTime: undefined,
|
||||||
|
} as LoopRunOptions;
|
||||||
|
|
||||||
|
const result = buildLoopRunInput("test prompt", options);
|
||||||
|
|
||||||
|
expect(result.provider).toBe("opencode");
|
||||||
|
expect(result.model).toBe("other-model");
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -8,6 +8,7 @@ import type {
|
|||||||
} from "../../output/index.js";
|
} from "../../output/index.js";
|
||||||
import { collectMultiple } from "../../utils/command-options.js";
|
import { collectMultiple } from "../../utils/command-options.js";
|
||||||
import { parseDuration } from "../../utils/duration.js";
|
import { parseDuration } from "../../utils/duration.js";
|
||||||
|
import { resolveProviderAndModel } from "../../utils/provider-model.js";
|
||||||
import type { LoopDaemonClient, LoopRecord, LoopRunInput } from "./types.js";
|
import type { LoopDaemonClient, LoopRecord, LoopRunInput } from "./types.js";
|
||||||
|
|
||||||
export interface LoopRunRow {
|
export interface LoopRunRow {
|
||||||
@@ -86,7 +87,8 @@ function parseMaxIterations(value: string | undefined): number | undefined {
|
|||||||
return parsed;
|
return parsed;
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildLoopRunInput(prompt: string, options: LoopRunOptions): LoopRunInput {
|
// oxlint-disable complexity
|
||||||
|
export function buildLoopRunInput(prompt: string, options: LoopRunOptions): LoopRunInput {
|
||||||
const verifyPrompt = options.verify?.trim();
|
const verifyPrompt = options.verify?.trim();
|
||||||
if (options.verify !== undefined && !verifyPrompt) {
|
if (options.verify !== undefined && !verifyPrompt) {
|
||||||
throw {
|
throw {
|
||||||
@@ -95,24 +97,54 @@ function buildLoopRunInput(prompt: string, options: LoopRunOptions): LoopRunInpu
|
|||||||
} satisfies CommandError;
|
} satisfies CommandError;
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
const result: LoopRunInput = {
|
||||||
prompt,
|
prompt,
|
||||||
cwd: process.cwd(),
|
cwd: process.cwd(),
|
||||||
...(options.provider ? { provider: options.provider } : {}),
|
|
||||||
...(options.model?.trim() ? { model: options.model.trim() } : {}),
|
|
||||||
...(options.verifyProvider ? { verifierProvider: options.verifyProvider } : {}),
|
|
||||||
...(options.verifyModel?.trim() ? { verifierModel: options.verifyModel.trim() } : {}),
|
|
||||||
...(verifyPrompt ? { verifyPrompt } : {}),
|
|
||||||
...(options.verifyCheck && options.verifyCheck.length > 0
|
|
||||||
? { verifyChecks: options.verifyCheck }
|
|
||||||
: {}),
|
|
||||||
...(options.archive ? { archive: true } : {}),
|
|
||||||
...(options.name?.trim() ? { name: options.name.trim() } : {}),
|
|
||||||
...(options.sleep ? { sleepMs: parseDuration(options.sleep) } : {}),
|
|
||||||
...(options.maxIterations ? { maxIterations: parseMaxIterations(options.maxIterations) } : {}),
|
|
||||||
...(options.maxTime ? { maxTimeMs: parseDuration(options.maxTime) } : {}),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Resolve provider/model
|
||||||
|
if (options.provider) {
|
||||||
|
const { provider, model } = resolveProviderAndModel({ provider: options.provider });
|
||||||
|
if (provider) result.provider = provider;
|
||||||
|
// Explicit --model takes precedence over parsed model
|
||||||
|
if (options.model?.trim()) {
|
||||||
|
result.model = options.model.trim();
|
||||||
|
} else if (model) {
|
||||||
|
result.model = model;
|
||||||
|
}
|
||||||
|
} else if (options.model?.trim()) {
|
||||||
|
result.model = options.model.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resolve verifier provider/model
|
||||||
|
if (options.verifyProvider) {
|
||||||
|
const { provider, model } = resolveProviderAndModel({ provider: options.verifyProvider });
|
||||||
|
if (provider) result.verifierProvider = provider;
|
||||||
|
// Explicit --verify-model takes precedence over parsed model
|
||||||
|
if (options.verifyModel?.trim()) {
|
||||||
|
result.verifierModel = options.verifyModel.trim();
|
||||||
|
} else if (model) {
|
||||||
|
result.verifierModel = model;
|
||||||
|
}
|
||||||
|
} else if (options.verifyModel?.trim()) {
|
||||||
|
result.verifierModel = options.verifyModel.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (verifyPrompt) result.verifyPrompt = verifyPrompt;
|
||||||
|
if (options.verifyCheck && options.verifyCheck.length > 0) {
|
||||||
|
result.verifyChecks = options.verifyCheck;
|
||||||
|
}
|
||||||
|
if (options.archive) result.archive = true;
|
||||||
|
if (options.name?.trim()) result.name = options.name.trim();
|
||||||
|
if (options.sleep) result.sleepMs = parseDuration(options.sleep);
|
||||||
|
if (options.maxIterations) {
|
||||||
|
result.maxIterations = parseMaxIterations(options.maxIterations);
|
||||||
|
}
|
||||||
|
if (options.maxTime) result.maxTimeMs = parseDuration(options.maxTime);
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
// oxlint-enable complexity
|
||||||
|
|
||||||
export type LoopRunResult = SingleResult<LoopRunRow>;
|
export type LoopRunResult = SingleResult<LoopRunRow>;
|
||||||
|
|
||||||
|
|||||||
@@ -451,6 +451,10 @@ export interface WaitForChatMessagesOptions {
|
|||||||
export interface RunLoopOptions {
|
export interface RunLoopOptions {
|
||||||
prompt: string;
|
prompt: string;
|
||||||
cwd: string;
|
cwd: string;
|
||||||
|
provider?: string;
|
||||||
|
model?: string;
|
||||||
|
verifierProvider?: string;
|
||||||
|
verifierModel?: string;
|
||||||
verifyPrompt?: string | null;
|
verifyPrompt?: string | null;
|
||||||
verifyChecks?: string[];
|
verifyChecks?: string[];
|
||||||
name?: string | null;
|
name?: string | null;
|
||||||
@@ -3589,6 +3593,10 @@ export class DaemonClient {
|
|||||||
type: "loop/run",
|
type: "loop/run",
|
||||||
prompt: options.prompt,
|
prompt: options.prompt,
|
||||||
cwd: options.cwd,
|
cwd: options.cwd,
|
||||||
|
...(options.provider ? { provider: options.provider } : {}),
|
||||||
|
...(options.model ? { model: options.model } : {}),
|
||||||
|
...(options.verifierProvider ? { verifierProvider: options.verifierProvider } : {}),
|
||||||
|
...(options.verifierModel ? { verifierModel: options.verifierModel } : {}),
|
||||||
...(options.verifyPrompt ? { verifyPrompt: options.verifyPrompt } : {}),
|
...(options.verifyPrompt ? { verifyPrompt: options.verifyPrompt } : {}),
|
||||||
...(options.verifyChecks && options.verifyChecks.length > 0
|
...(options.verifyChecks && options.verifyChecks.length > 0
|
||||||
? { verifyChecks: options.verifyChecks }
|
? { verifyChecks: options.verifyChecks }
|
||||||
|
|||||||
Reference in New Issue
Block a user