Add --mode to schedule and loop CLI, default background runs to unattended mode

Plumb --mode/--verify-mode through paseo schedule create and paseo loop run.
Mark each provider's unattended mode (claude bypassPermissions, codex/opencode
full-access, copilot autopilot) so loop and schedule services pick it by
default when no explicit modeId is given.
This commit is contained in:
Mohamed Boudra
2026-05-05 19:56:26 +07:00
parent 5feaa7a101
commit 0775f59a6f
13 changed files with 191 additions and 11 deletions
+15
View File
@@ -21,8 +21,10 @@ export interface LoopRunRow {
export interface LoopRunOptions extends CommandOptions {
provider?: string;
model?: string;
mode?: string;
verifyProvider?: string;
verifyModel?: string;
verifyMode?: string;
verify?: string;
verifyCheck?: string[];
archive?: boolean;
@@ -48,8 +50,13 @@ export function addLoopRunOptions(command: Command): Command {
.argument("<prompt>", "Prompt for each fresh worker iteration")
.option("--provider <provider>", "Default provider for worker and verifier agents")
.option("--model <model>", "Default model for worker and verifier agents")
.option(
"--mode <mode>",
"Provider-specific mode for the worker agent (e.g. claude bypassPermissions, opencode build)",
)
.option("--verify-provider <provider>", "Provider for the verifier agent")
.option("--verify-model <model>", "Model for the verifier agent")
.option("--verify-mode <mode>", "Provider-specific mode for the verifier agent")
.option("--verify <prompt>", "Verifier agent prompt")
.option(
"--verify-check <command>",
@@ -116,6 +123,10 @@ export function buildLoopRunInput(prompt: string, options: LoopRunOptions): Loop
result.model = options.model.trim();
}
if (options.mode?.trim()) {
result.modeId = options.mode.trim();
}
// Resolve verifier provider/model
if (options.verifyProvider) {
const { provider, model } = resolveProviderAndModel({ provider: options.verifyProvider });
@@ -130,6 +141,10 @@ export function buildLoopRunInput(prompt: string, options: LoopRunOptions): Loop
result.verifierModel = options.verifyModel.trim();
}
if (options.verifyMode?.trim()) {
result.verifierModeId = options.verifyMode.trim();
}
if (verifyPrompt) result.verifyPrompt = verifyPrompt;
if (options.verifyCheck && options.verifyCheck.length > 0) {
result.verifyChecks = options.verifyCheck;
+4
View File
@@ -47,10 +47,12 @@ export interface LoopRecord {
cwd: string;
provider: string;
model: string | null;
modeId: string | null;
workerProvider: string | null;
workerModel: string | null;
verifierProvider: string | null;
verifierModel: string | null;
verifierModeId: string | null;
verifyPrompt: string | null;
verifyChecks: string[];
archive: boolean;
@@ -124,10 +126,12 @@ export interface LoopRunInput {
cwd: string;
provider?: string;
model?: string;
modeId?: string;
workerProvider?: string;
workerModel?: string;
verifierProvider?: string;
verifierModel?: string;
verifierModeId?: string;
verifyPrompt?: string;
verifyChecks?: string[];
archive?: boolean;
@@ -16,6 +16,7 @@ export interface ScheduleCreateOptions extends ScheduleCommandOptions {
name?: string;
target?: string;
provider?: string;
mode?: string;
maxRuns?: string;
expiresIn?: string;
}
@@ -32,6 +33,7 @@ export async function runCreateCommand(
name: options.name,
target: options.target,
provider: options.provider,
mode: options.mode,
maxRuns: options.maxRuns,
expiresIn: options.expiresIn,
});
@@ -25,6 +25,10 @@ export function createScheduleCommand(): Command {
"--provider <provider>",
"Agent provider, or provider/model (e.g. codex or codex/gpt-5.4)",
)
.option(
"--mode <mode>",
"Provider-specific mode (e.g. claude bypassPermissions, opencode build)",
)
.option("--max-runs <n>", "Maximum number of runs")
.option("--expires-in <duration>", "Time to live for the schedule"),
).action(withOutput(runCreateCommand));
+10 -7
View File
@@ -85,14 +85,14 @@ export function formatDurationMs(durationMs: number): string {
function resolveScheduleTarget(args: {
targetValue: string | undefined;
hasExplicitProviderSelection: boolean;
hasExplicitNewAgentOption: boolean;
createNewAgentTarget: () => ScheduleTarget;
}): ScheduleTarget {
const { targetValue, hasExplicitProviderSelection, createNewAgentTarget } = args;
const { targetValue, hasExplicitNewAgentOption, createNewAgentTarget } = args;
const currentAgentId = process.env.PASEO_AGENT_ID?.trim();
if (!targetValue) {
if (currentAgentId && !hasExplicitProviderSelection) {
if (currentAgentId && !hasExplicitNewAgentOption) {
return { type: "self", agentId: currentAgentId };
}
return createNewAgentTarget();
@@ -102,10 +102,10 @@ function resolveScheduleTarget(args: {
return createNewAgentTarget();
}
if (hasExplicitProviderSelection) {
if (hasExplicitNewAgentOption) {
throw {
code: "INVALID_TARGET",
message: "--provider can only be used with a new-agent target",
message: "--provider/--mode can only be used with a new-agent target",
details: "Use --target new-agent or omit --target to create a new agent schedule",
} satisfies CommandError;
}
@@ -130,6 +130,7 @@ export function parseScheduleCreateInput(options: {
name?: string;
target?: string;
provider?: string;
mode?: string;
maxRuns?: string;
expiresIn?: string;
}): CreateScheduleInput {
@@ -154,7 +155,8 @@ export function parseScheduleCreateInput(options: {
: { type: "cron", expression: options.cron!.trim() };
const targetValue = options.target?.trim();
const hasExplicitProviderSelection = options.provider !== undefined;
const modeId = options.mode?.trim();
const hasExplicitNewAgentOption = options.provider !== undefined || options.mode !== undefined;
const createNewAgentTarget = (): ScheduleTarget => {
const resolvedProviderModel = resolveProviderAndModel({
provider: options.provider,
@@ -165,12 +167,13 @@ export function parseScheduleCreateInput(options: {
provider: resolvedProviderModel.provider,
cwd: process.cwd(),
...(resolvedProviderModel.model ? { model: resolvedProviderModel.model } : {}),
...(modeId ? { modeId } : {}),
},
};
};
const target = resolveScheduleTarget({
targetValue,
hasExplicitProviderSelection,
hasExplicitNewAgentOption,
createNewAgentTarget,
});