feat: add CLI backend fallback
This commit is contained in:
@@ -112,6 +112,7 @@ const FIELD_LABELS: Record<string, string> = {
|
||||
"agents.defaults.humanDelay.mode": "Human Delay Mode",
|
||||
"agents.defaults.humanDelay.minMs": "Human Delay Min (ms)",
|
||||
"agents.defaults.humanDelay.maxMs": "Human Delay Max (ms)",
|
||||
"agents.defaults.cliBackends": "CLI Backends",
|
||||
"commands.native": "Native Commands",
|
||||
"commands.text": "Text Commands",
|
||||
"commands.restart": "Allow Restart",
|
||||
@@ -191,6 +192,8 @@ const FIELD_HELP: Record<string, string> = {
|
||||
"Optional image model (provider/model) used when the primary model lacks image input.",
|
||||
"agents.defaults.imageModel.fallbacks":
|
||||
"Ordered fallback image models (provider/model).",
|
||||
"agents.defaults.cliBackends":
|
||||
"Optional CLI backends for text-only fallback (claude-cli, etc.).",
|
||||
"agents.defaults.humanDelay.mode":
|
||||
'Delay style for block replies ("off", "natural", "custom").',
|
||||
"agents.defaults.humanDelay.minMs":
|
||||
|
||||
@@ -113,6 +113,7 @@ export type SessionEntry = {
|
||||
model?: string;
|
||||
contextTokens?: number;
|
||||
compactionCount?: number;
|
||||
cliSessionIds?: Record<string, string>;
|
||||
claudeCliSessionId?: string;
|
||||
label?: string;
|
||||
displayName?: string;
|
||||
|
||||
@@ -1355,6 +1355,45 @@ export type AgentContextPruningConfig = {
|
||||
};
|
||||
};
|
||||
|
||||
export type CliBackendConfig = {
|
||||
/** CLI command to execute (absolute path or on PATH). */
|
||||
command: string;
|
||||
/** Base args applied to every invocation. */
|
||||
args?: string[];
|
||||
/** Output parsing mode (default: json). */
|
||||
output?: "json" | "text";
|
||||
/** Prompt input mode (default: arg). */
|
||||
input?: "arg" | "stdin";
|
||||
/** Max prompt length for arg mode (if exceeded, stdin is used). */
|
||||
maxPromptArgChars?: number;
|
||||
/** Extra env vars injected for this CLI. */
|
||||
env?: Record<string, string>;
|
||||
/** Env vars to remove before launching this CLI. */
|
||||
clearEnv?: string[];
|
||||
/** Flag used to pass model id (e.g. --model). */
|
||||
modelArg?: string;
|
||||
/** Model aliases mapping (config model id → CLI model id). */
|
||||
modelAliases?: Record<string, string>;
|
||||
/** Flag used to pass session id (e.g. --session-id). */
|
||||
sessionArg?: string;
|
||||
/** When to pass session ids. */
|
||||
sessionMode?: "always" | "existing" | "none";
|
||||
/** JSON fields to read session id from (in order). */
|
||||
sessionIdFields?: string[];
|
||||
/** Flag used to pass system prompt. */
|
||||
systemPromptArg?: string;
|
||||
/** System prompt behavior (append vs replace). */
|
||||
systemPromptMode?: "append" | "replace";
|
||||
/** When to send system prompt. */
|
||||
systemPromptWhen?: "first" | "always" | "never";
|
||||
/** Flag used to pass image paths. */
|
||||
imageArg?: string;
|
||||
/** How to pass multiple images. */
|
||||
imageMode?: "repeat" | "list";
|
||||
/** Serialize runs for this CLI. */
|
||||
serialize?: boolean;
|
||||
};
|
||||
|
||||
export type AgentDefaultsConfig = {
|
||||
/** Primary model and fallbacks (provider/model). */
|
||||
model?: AgentModelListConfig;
|
||||
@@ -1370,6 +1409,8 @@ export type AgentDefaultsConfig = {
|
||||
userTimezone?: string;
|
||||
/** Optional display-only context window override (used for % in status UIs). */
|
||||
contextTokens?: number;
|
||||
/** Optional CLI backends for text-only fallback (claude-cli, etc.). */
|
||||
cliBackends?: Record<string, CliBackendConfig>;
|
||||
/** Opt-in: prune old tool results from the LLM context to reduce token usage. */
|
||||
contextPruning?: AgentContextPruningConfig;
|
||||
/** Default thinking level when no /think directive is present. */
|
||||
|
||||
@@ -124,6 +124,33 @@ const HumanDelaySchema = z.object({
|
||||
maxMs: z.number().int().nonnegative().optional(),
|
||||
});
|
||||
|
||||
const CliBackendSchema = z.object({
|
||||
command: z.string(),
|
||||
args: z.array(z.string()).optional(),
|
||||
output: z.union([z.literal("json"), z.literal("text")]).optional(),
|
||||
input: z.union([z.literal("arg"), z.literal("stdin")]).optional(),
|
||||
maxPromptArgChars: z.number().int().positive().optional(),
|
||||
env: z.record(z.string(), z.string()).optional(),
|
||||
clearEnv: z.array(z.string()).optional(),
|
||||
modelArg: z.string().optional(),
|
||||
modelAliases: z.record(z.string(), z.string()).optional(),
|
||||
sessionArg: z.string().optional(),
|
||||
sessionMode: z
|
||||
.union([z.literal("always"), z.literal("existing"), z.literal("none")])
|
||||
.optional(),
|
||||
sessionIdFields: z.array(z.string()).optional(),
|
||||
systemPromptArg: z.string().optional(),
|
||||
systemPromptMode: z
|
||||
.union([z.literal("append"), z.literal("replace")])
|
||||
.optional(),
|
||||
systemPromptWhen: z
|
||||
.union([z.literal("first"), z.literal("always"), z.literal("never")])
|
||||
.optional(),
|
||||
imageArg: z.string().optional(),
|
||||
imageMode: z.union([z.literal("repeat"), z.literal("list")]).optional(),
|
||||
serialize: z.boolean().optional(),
|
||||
});
|
||||
|
||||
const normalizeAllowFrom = (values?: Array<string | number>): string[] =>
|
||||
(values ?? []).map((v) => String(v).trim()).filter(Boolean);
|
||||
|
||||
@@ -1037,6 +1064,7 @@ const AgentDefaultsSchema = z
|
||||
skipBootstrap: z.boolean().optional(),
|
||||
userTimezone: z.string().optional(),
|
||||
contextTokens: z.number().int().positive().optional(),
|
||||
cliBackends: z.record(z.string(), CliBackendSchema).optional(),
|
||||
contextPruning: z
|
||||
.object({
|
||||
mode: z
|
||||
|
||||
Reference in New Issue
Block a user