Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions packages/coding-agent/src/cli/args.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,14 @@ export interface Args {
themes?: string[];
noThemes?: boolean;
noContextFiles?: boolean;
autonomous?: boolean;
autonomousGates?: string[];
autonomousGateRetries?: number;
autonomousGateTimeoutMs?: number;
autonomousMaxContinuations?: number;
autonomousMaxTurns?: number;
autonomousMaxTokens?: number;
autonomousTimeoutMs?: number;
listModels?: string | true;
offline?: boolean;
verbose?: boolean;
Expand Down Expand Up @@ -166,6 +174,23 @@ export function parseArgs(args: string[]): Args {
result.noThemes = true;
} else if (arg === "--no-context-files" || arg === "-nc") {
result.noContextFiles = true;
} else if (arg === "--autonomous") {
result.autonomous = true;
} else if (arg === "--autonomous-gate" && i + 1 < args.length) {
result.autonomousGates = result.autonomousGates ?? [];
result.autonomousGates.push(args[++i]);
} else if (arg === "--autonomous-gate-retries" && i + 1 < args.length) {
result.autonomousGateRetries = parsePositiveInt(args[++i], "--autonomous-gate-retries", result);
} else if (arg === "--autonomous-gate-timeout-ms" && i + 1 < args.length) {
result.autonomousGateTimeoutMs = parsePositiveInt(args[++i], "--autonomous-gate-timeout-ms", result);
} else if (arg === "--autonomous-max-continuations" && i + 1 < args.length) {
result.autonomousMaxContinuations = parsePositiveInt(args[++i], "--autonomous-max-continuations", result);
} else if (arg === "--autonomous-max-turns" && i + 1 < args.length) {
result.autonomousMaxTurns = parsePositiveInt(args[++i], "--autonomous-max-turns", result);
} else if (arg === "--autonomous-max-tokens" && i + 1 < args.length) {
result.autonomousMaxTokens = parsePositiveInt(args[++i], "--autonomous-max-tokens", result);
} else if (arg === "--autonomous-timeout-ms" && i + 1 < args.length) {
result.autonomousTimeoutMs = parsePositiveInt(args[++i], "--autonomous-timeout-ms", result);
} else if (arg === "--list-models") {
// Check if next arg is a search pattern (not a flag or file arg)
if (i + 1 < args.length && !args[i + 1].startsWith("-") && !args[i + 1].startsWith("@")) {
Expand Down Expand Up @@ -262,6 +287,14 @@ ${chalk.bold("Options:")}
--theme <path> Load a theme file or directory (can be used multiple times)
--no-themes Disable theme discovery and loading
--no-context-files, -nc Disable AGENTS.md and CLAUDE.md discovery and loading
--autonomous Continue autonomously until host-observable terminal evidence exists
--autonomous-gate <command> Run a command before autonomous mode may finish (repeatable)
--autonomous-gate-retries <n> Max autonomous retries per failed gate (default: 3)
--autonomous-gate-timeout-ms <n> Timeout per autonomous gate command in milliseconds
--autonomous-max-continuations <n> Max autonomous follow-up messages (default: 3)
--autonomous-max-turns <n> Max assistant turns while autonomous mode is active (default: 12)
--autonomous-max-tokens <n> Max tokens while autonomous mode is active (default: 80000)
--autonomous-timeout-ms <n> Max autonomous wall-clock time in milliseconds (default: 1800000)
--export <file> Export session file to HTML and exit
--list-models [search] List available models (with optional fuzzy search)
--verbose Force verbose startup (overrides quietStartup setting)
Expand Down Expand Up @@ -372,3 +405,12 @@ ${chalk.bold("Built-in Tool Names:")}
edit - Edit files with find/replace (off by default)
`);
}

function parsePositiveInt(value: string, flag: string, result: Args): number | undefined {
const parsed = Number(value);
if (!Number.isInteger(parsed) || parsed <= 0) {
result.diagnostics.push({ type: "error", message: `${flag} must be a positive integer` });
return undefined;
}
return parsed;
}
17 changes: 17 additions & 0 deletions packages/coding-agent/src/core/agent-session-config.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { ThinkingLevel } from "@earendil-works/pi-agent-core";
import type { AgentAutonomousConfig } from "./autonomous.js";

export interface AgentSessionRuntimeConfig {
cwd?: string;
Expand All @@ -23,6 +24,7 @@ export interface AgentSessionRuntimeConfig {
themes?: string[];
noThemes?: boolean;
noContextFiles?: boolean;
autonomous?: AgentAutonomousConfig;
extensionFlagValues?: Record<string, boolean | string>;
}

Expand Down Expand Up @@ -56,6 +58,7 @@ export function mergeAgentSessionRuntimeConfig(
themes: cloneArray(override.themes ?? base.themes),
noThemes: override.noThemes ?? base.noThemes,
noContextFiles: override.noContextFiles ?? base.noContextFiles,
autonomous: mergeAutonomousConfig(base.autonomous, override.autonomous),
extensionFlagValues:
base.extensionFlagValues || override.extensionFlagValues
? { ...(base.extensionFlagValues ?? {}), ...(override.extensionFlagValues ?? {}) }
Expand All @@ -73,10 +76,24 @@ function cloneAgentSessionRuntimeConfig(config: AgentSessionRuntimeConfig): Agen
skills: cloneArray(config.skills),
promptTemplates: cloneArray(config.promptTemplates),
themes: cloneArray(config.themes),
autonomous: config.autonomous ? { ...config.autonomous } : undefined,
extensionFlagValues: config.extensionFlagValues ? { ...config.extensionFlagValues } : undefined,
};
}

function mergeAutonomousConfig(
base: AgentAutonomousConfig | undefined,
override: AgentAutonomousConfig | undefined,
): AgentAutonomousConfig | undefined {
if (!base && !override) {
return undefined;
}
return {
...(base ?? {}),
...(override ?? {}),
};
}

function cloneArray<T>(value: T[] | undefined): T[] | undefined {
return value ? [...value] : undefined;
}
3 changes: 3 additions & 0 deletions packages/coding-agent/src/core/agent-session-services.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type { Model } from "@earendil-works/pi-ai";
import { getAgentDir } from "../config.js";
import { installAgentTraceUpload } from "./agent-traces.js";
import { AuthStorage } from "./auth-storage.js";
import type { AgentAutonomousConfig } from "./autonomous.js";
import type { AgentRlmHeartbeatController } from "./cron-jobs.js";
import type { SessionStartEvent, ToolDefinition } from "./extensions/index.js";
import { ModelRegistry } from "./model-registry.js";
Expand Down Expand Up @@ -59,6 +60,7 @@ export interface AgentSessionCreationOptions {
subagentRuntimeHost?: SubagentRuntimeHost;
rlmHeartbeatController?: AgentRlmHeartbeatController;
prewarmIpythonKernel?: boolean;
autonomous?: AgentAutonomousConfig;
}

/**
Expand Down Expand Up @@ -224,5 +226,6 @@ export async function createAgentSessionFromServices(
rlmHeartbeatController: options.rlmHeartbeatController,
sessionStartEvent: options.sessionStartEvent,
prewarmIpythonKernel: options.prewarmIpythonKernel,
autonomous: options.autonomous,
});
}
Loading