mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-03-20 02:51:55 -07:00
feat(core, cli): Add support for agents in settings.json. (#16433)
This commit is contained in:
@@ -557,6 +557,14 @@ their corresponding top-level category object in your `settings.json` file.
|
||||
used.
|
||||
- **Default:** `[]`
|
||||
|
||||
#### `agents`
|
||||
|
||||
- **`agents.overrides`** (object):
|
||||
- **Description:** Override settings for specific agents, e.g. to disable the
|
||||
agent, set a custom model config, or run config.
|
||||
- **Default:** `{}`
|
||||
- **Requires restart:** Yes
|
||||
|
||||
#### `context`
|
||||
|
||||
- **`context.fileName`** (string | string[]):
|
||||
|
||||
@@ -660,6 +660,7 @@ export async function loadCliConfig(
|
||||
mcpServers: mcpEnabled ? settings.mcpServers : {},
|
||||
mcpEnabled,
|
||||
extensionsEnabled,
|
||||
agents: settings.agents,
|
||||
allowedMcpServers: mcpEnabled
|
||||
? (argv.allowedMcpServerNames ?? settings.mcp?.allowed)
|
||||
: undefined,
|
||||
|
||||
@@ -785,6 +785,32 @@ const SETTINGS_SCHEMA = {
|
||||
},
|
||||
},
|
||||
|
||||
agents: {
|
||||
type: 'object',
|
||||
label: 'Agents',
|
||||
category: 'Advanced',
|
||||
requiresRestart: true,
|
||||
default: {},
|
||||
description: 'Settings for subagents.',
|
||||
showInDialog: false,
|
||||
properties: {
|
||||
overrides: {
|
||||
type: 'object',
|
||||
label: 'Agent Overrides',
|
||||
category: 'Advanced',
|
||||
requiresRestart: true,
|
||||
default: {},
|
||||
description:
|
||||
'Override settings for specific agents, e.g. to disable the agent, set a custom model config, or run config.',
|
||||
showInDialog: false,
|
||||
additionalProperties: {
|
||||
type: 'object',
|
||||
ref: 'AgentOverride',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
context: {
|
||||
type: 'object',
|
||||
label: 'Context',
|
||||
@@ -2002,6 +2028,36 @@ export const SETTINGS_SCHEMA_DEFINITIONS: Record<
|
||||
},
|
||||
},
|
||||
},
|
||||
AgentOverride: {
|
||||
type: 'object',
|
||||
description: 'Override settings for a specific agent.',
|
||||
additionalProperties: false,
|
||||
properties: {
|
||||
modelConfig: {
|
||||
type: 'object',
|
||||
additionalProperties: true,
|
||||
},
|
||||
runConfig: {
|
||||
type: 'object',
|
||||
description: 'Run configuration for an agent.',
|
||||
additionalProperties: false,
|
||||
properties: {
|
||||
maxTimeMinutes: {
|
||||
type: 'number',
|
||||
description: 'The maximum execution time for the agent in minutes.',
|
||||
},
|
||||
maxTurns: {
|
||||
type: 'number',
|
||||
description: 'The maximum number of conversational turns.',
|
||||
},
|
||||
},
|
||||
},
|
||||
disabled: {
|
||||
type: 'boolean',
|
||||
description: 'Whether to disable the agent.',
|
||||
},
|
||||
},
|
||||
},
|
||||
CustomTheme: {
|
||||
type: 'object',
|
||||
description:
|
||||
|
||||
@@ -619,6 +619,127 @@ describe('AgentRegistry', () => {
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('overrides', () => {
|
||||
it('should skip registration if agent is disabled in settings', async () => {
|
||||
const config = makeFakeConfig({
|
||||
agents: {
|
||||
overrides: {
|
||||
MockAgent: { disabled: true },
|
||||
},
|
||||
},
|
||||
});
|
||||
const registry = new TestableAgentRegistry(config);
|
||||
|
||||
await registry.testRegisterAgent(MOCK_AGENT_V1);
|
||||
|
||||
expect(registry.getDefinition('MockAgent')).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should skip remote agent registration if disabled in settings', async () => {
|
||||
const config = makeFakeConfig({
|
||||
agents: {
|
||||
overrides: {
|
||||
RemoteAgent: { disabled: true },
|
||||
},
|
||||
},
|
||||
});
|
||||
const registry = new TestableAgentRegistry(config);
|
||||
|
||||
const remoteAgent: AgentDefinition = {
|
||||
kind: 'remote',
|
||||
name: 'RemoteAgent',
|
||||
description: 'A remote agent',
|
||||
agentCardUrl: 'https://example.com/card',
|
||||
inputConfig: { inputs: {} },
|
||||
};
|
||||
|
||||
await registry.testRegisterAgent(remoteAgent);
|
||||
|
||||
expect(registry.getDefinition('RemoteAgent')).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should merge runConfig overrides', async () => {
|
||||
const config = makeFakeConfig({
|
||||
agents: {
|
||||
overrides: {
|
||||
MockAgent: {
|
||||
runConfig: { maxTurns: 50 },
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
const registry = new TestableAgentRegistry(config);
|
||||
|
||||
await registry.testRegisterAgent(MOCK_AGENT_V1);
|
||||
|
||||
const def = registry.getDefinition('MockAgent') as LocalAgentDefinition;
|
||||
expect(def.runConfig.max_turns).toBe(50);
|
||||
expect(def.runConfig.max_time_minutes).toBe(
|
||||
MOCK_AGENT_V1.runConfig.max_time_minutes,
|
||||
);
|
||||
});
|
||||
|
||||
it('should apply modelConfig overrides', async () => {
|
||||
const config = makeFakeConfig({
|
||||
agents: {
|
||||
overrides: {
|
||||
MockAgent: {
|
||||
modelConfig: {
|
||||
model: 'overridden-model',
|
||||
generateContentConfig: {
|
||||
temperature: 0.5,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
const registry = new TestableAgentRegistry(config);
|
||||
|
||||
await registry.testRegisterAgent(MOCK_AGENT_V1);
|
||||
|
||||
const resolved = config.modelConfigService.getResolvedConfig({
|
||||
model: getModelConfigAlias(MOCK_AGENT_V1),
|
||||
});
|
||||
|
||||
expect(resolved.model).toBe('overridden-model');
|
||||
expect(resolved.generateContentConfig.temperature).toBe(0.5);
|
||||
// topP should still be MOCK_AGENT_V1.modelConfig.top_p (1) because we merged
|
||||
expect(resolved.generateContentConfig.topP).toBe(1);
|
||||
});
|
||||
|
||||
it('should deep merge generateContentConfig (e.g. thinkingConfig)', async () => {
|
||||
const config = makeFakeConfig({
|
||||
agents: {
|
||||
overrides: {
|
||||
MockAgent: {
|
||||
modelConfig: {
|
||||
generateContentConfig: {
|
||||
thinkingConfig: {
|
||||
thinkingBudget: 16384,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
const registry = new TestableAgentRegistry(config);
|
||||
|
||||
await registry.testRegisterAgent(MOCK_AGENT_V1);
|
||||
|
||||
const resolved = config.modelConfigService.getResolvedConfig({
|
||||
model: getModelConfigAlias(MOCK_AGENT_V1),
|
||||
});
|
||||
|
||||
expect(resolved.generateContentConfig.thinkingConfig).toEqual({
|
||||
includeThoughts: true, // Preserved from default
|
||||
thinkingBudget: 16384, // Overridden
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('getToolDescription', () => {
|
||||
it('should return default message when no agents are registered', () => {
|
||||
expect(registry.getToolDescription()).toContain(
|
||||
|
||||
@@ -14,7 +14,6 @@ import { CliHelpAgent } from './cli-help-agent.js';
|
||||
import { A2AClientManager } from './a2a-client-manager.js';
|
||||
import { ADCHandler } from './remote-invocation.js';
|
||||
import { type z } from 'zod';
|
||||
import type { GenerateContentConfig } from '@google/genai';
|
||||
import { debugLogger } from '../utils/debugLogger.js';
|
||||
import {
|
||||
DEFAULT_GEMINI_MODEL,
|
||||
@@ -23,6 +22,10 @@ import {
|
||||
isPreviewModel,
|
||||
isAutoModel,
|
||||
} from '../config/models.js';
|
||||
import {
|
||||
type ModelConfig,
|
||||
ModelConfigService,
|
||||
} from '../services/modelConfigService.js';
|
||||
|
||||
/**
|
||||
* Returns the model config alias for a given agent definition.
|
||||
@@ -226,49 +229,83 @@ export class AgentRegistry {
|
||||
return;
|
||||
}
|
||||
|
||||
const overrides =
|
||||
this.config.getAgentsSettings().overrides?.[definition.name];
|
||||
if (overrides?.disabled) {
|
||||
if (this.config.getDebugMode()) {
|
||||
debugLogger.log(
|
||||
`[AgentRegistry] Skipping disabled agent '${definition.name}'`,
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.agents.has(definition.name) && this.config.getDebugMode()) {
|
||||
debugLogger.log(`[AgentRegistry] Overriding agent '${definition.name}'`);
|
||||
}
|
||||
|
||||
this.agents.set(definition.name, definition);
|
||||
// TODO(16443): Refactor definition merging logic into a helper.
|
||||
// To do this, we need to align the definition of the internal `Definition`
|
||||
// type with the one exported in settings.json.
|
||||
const mergedDefinition = {
|
||||
...definition,
|
||||
runConfig: {
|
||||
...definition.runConfig,
|
||||
max_time_minutes:
|
||||
overrides?.runConfig?.maxTimeMinutes ??
|
||||
definition.runConfig.max_time_minutes,
|
||||
max_turns:
|
||||
overrides?.runConfig?.maxTurns ?? definition.runConfig.max_turns,
|
||||
},
|
||||
};
|
||||
|
||||
this.agents.set(mergedDefinition.name, mergedDefinition);
|
||||
|
||||
// Register model config. We always create a runtime alias. However,
|
||||
// if the user is using `auto` as a model string then we also create
|
||||
// runtime overrides to ensure the subagent generation settings are
|
||||
// respected regardless of the final model string from routing.
|
||||
// TODO(12916): Migrate sub-agents where possible to static configs.
|
||||
const modelConfig = definition.modelConfig;
|
||||
const modelConfig = mergedDefinition.modelConfig;
|
||||
let model = modelConfig.model;
|
||||
if (model === 'inherit') {
|
||||
model = this.config.getModel();
|
||||
}
|
||||
|
||||
const generateContentConfig: GenerateContentConfig = {
|
||||
temperature: modelConfig.temp,
|
||||
topP: modelConfig.top_p,
|
||||
thinkingConfig: {
|
||||
includeThoughts: true,
|
||||
thinkingBudget: modelConfig.thinkingBudget ?? -1,
|
||||
let agentModelConfig: ModelConfig = {
|
||||
model,
|
||||
generateContentConfig: {
|
||||
temperature: modelConfig.temp,
|
||||
topP: modelConfig.top_p,
|
||||
thinkingConfig: {
|
||||
includeThoughts: true,
|
||||
thinkingBudget: modelConfig.thinkingBudget ?? -1,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
// Apply standardized modelConfig overrides if present.
|
||||
if (overrides?.modelConfig) {
|
||||
agentModelConfig = ModelConfigService.merge(
|
||||
agentModelConfig,
|
||||
overrides.modelConfig,
|
||||
);
|
||||
}
|
||||
|
||||
this.config.modelConfigService.registerRuntimeModelConfig(
|
||||
getModelConfigAlias(definition),
|
||||
getModelConfigAlias(mergedDefinition),
|
||||
{
|
||||
modelConfig: {
|
||||
model,
|
||||
generateContentConfig,
|
||||
},
|
||||
modelConfig: agentModelConfig,
|
||||
},
|
||||
);
|
||||
|
||||
if (isAutoModel(model)) {
|
||||
if (agentModelConfig.model && isAutoModel(agentModelConfig.model)) {
|
||||
this.config.modelConfigService.registerRuntimeModelOverride({
|
||||
match: {
|
||||
overrideScope: definition.name,
|
||||
overrideScope: mergedDefinition.name,
|
||||
},
|
||||
modelConfig: {
|
||||
generateContentConfig,
|
||||
generateContentConfig: agentModelConfig.generateContentConfig,
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -292,6 +329,17 @@ export class AgentRegistry {
|
||||
return;
|
||||
}
|
||||
|
||||
const overrides =
|
||||
this.config.getAgentsSettings().overrides?.[definition.name];
|
||||
if (overrides?.disabled) {
|
||||
if (this.config.getDebugMode()) {
|
||||
debugLogger.log(
|
||||
`[AgentRegistry] Skipping disabled remote agent '${definition.name}'`,
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.agents.has(definition.name) && this.config.getDebugMode()) {
|
||||
debugLogger.log(`[AgentRegistry] Overriding agent '${definition.name}'`);
|
||||
}
|
||||
|
||||
@@ -69,7 +69,10 @@ import type { FallbackModelHandler } from '../fallback/types.js';
|
||||
import { ModelAvailabilityService } from '../availability/modelAvailabilityService.js';
|
||||
import { ModelRouterService } from '../routing/modelRouterService.js';
|
||||
import { OutputFormat } from '../output/types.js';
|
||||
import type { ModelConfigServiceConfig } from '../services/modelConfigService.js';
|
||||
import type {
|
||||
ModelConfig,
|
||||
ModelConfigServiceConfig,
|
||||
} from '../services/modelConfigService.js';
|
||||
import { ModelConfigService } from '../services/modelConfigService.js';
|
||||
import { DEFAULT_MODEL_CONFIGS } from './defaultModelConfigs.js';
|
||||
import { ContextManager } from '../services/contextManager.js';
|
||||
@@ -159,6 +162,21 @@ export interface CliHelpAgentSettings {
|
||||
enabled?: boolean;
|
||||
}
|
||||
|
||||
export interface AgentRunConfig {
|
||||
maxTimeMinutes?: number;
|
||||
maxTurns?: number;
|
||||
}
|
||||
|
||||
export interface AgentOverride {
|
||||
modelConfig?: ModelConfig;
|
||||
runConfig?: AgentRunConfig;
|
||||
disabled?: boolean;
|
||||
}
|
||||
|
||||
export interface AgentSettings {
|
||||
overrides?: Record<string, AgentOverride>;
|
||||
}
|
||||
|
||||
/**
|
||||
* All information required in CLI to handle an extension. Defined in Core so
|
||||
* that the collection of loaded, active, and inactive extensions can be passed
|
||||
@@ -364,6 +382,7 @@ export interface ConfigParameters {
|
||||
onModelChange?: (model: string) => void;
|
||||
mcpEnabled?: boolean;
|
||||
extensionsEnabled?: boolean;
|
||||
agents?: AgentSettings;
|
||||
onReload?: () => Promise<{ disabledSkills?: string[] }>;
|
||||
}
|
||||
|
||||
@@ -496,6 +515,7 @@ export class Config {
|
||||
| undefined;
|
||||
|
||||
private readonly enableAgents: boolean;
|
||||
private readonly agents: AgentSettings;
|
||||
private readonly skillsSupport: boolean;
|
||||
private disabledSkills: string[];
|
||||
|
||||
@@ -570,6 +590,7 @@ export class Config {
|
||||
this.model = params.model;
|
||||
this._activeModel = params.model;
|
||||
this.enableAgents = params.enableAgents ?? false;
|
||||
this.agents = params.agents ?? {};
|
||||
this.disableLLMCorrection = params.disableLLMCorrection ?? false;
|
||||
this.skillsSupport = params.skillsSupport ?? false;
|
||||
this.disabledSkills = params.disabledSkills ?? [];
|
||||
@@ -1443,6 +1464,10 @@ export class Config {
|
||||
return this.noBrowser;
|
||||
}
|
||||
|
||||
getAgentsSettings(): AgentSettings {
|
||||
return this.agents;
|
||||
}
|
||||
|
||||
isBrowserLaunchSuppressed(): boolean {
|
||||
return this.getNoBrowser() || !shouldAttemptBrowserLaunch();
|
||||
}
|
||||
|
||||
@@ -119,14 +119,10 @@ export class ModelConfigService {
|
||||
...this.runtimeAliases,
|
||||
};
|
||||
|
||||
const {
|
||||
aliasChain,
|
||||
baseModel: initialBaseModel,
|
||||
resolvedConfig: initialResolvedConfig,
|
||||
} = this.resolveAliasChain(context.model, allAliases);
|
||||
|
||||
let baseModel = initialBaseModel;
|
||||
let resolvedConfig = initialResolvedConfig;
|
||||
const { aliasChain, baseModel, resolvedConfig } = this.resolveAliasChain(
|
||||
context.model,
|
||||
allAliases,
|
||||
);
|
||||
|
||||
const modelToLevel = this.buildModelLevelMap(aliasChain, baseModel);
|
||||
const allOverrides = [
|
||||
@@ -142,19 +138,22 @@ export class ModelConfigService {
|
||||
|
||||
this.sortOverrides(matches);
|
||||
|
||||
let currentConfig: ModelConfig = {
|
||||
model: baseModel,
|
||||
generateContentConfig: resolvedConfig,
|
||||
};
|
||||
|
||||
for (const match of matches) {
|
||||
if (match.modelConfig.model) {
|
||||
baseModel = match.modelConfig.model;
|
||||
}
|
||||
if (match.modelConfig.generateContentConfig) {
|
||||
resolvedConfig = this.deepMerge(
|
||||
resolvedConfig,
|
||||
match.modelConfig.generateContentConfig,
|
||||
);
|
||||
}
|
||||
currentConfig = ModelConfigService.merge(
|
||||
currentConfig,
|
||||
match.modelConfig,
|
||||
);
|
||||
}
|
||||
|
||||
return { model: baseModel, generateContentConfig: resolvedConfig };
|
||||
return {
|
||||
model: currentConfig.model,
|
||||
generateContentConfig: currentConfig.generateContentConfig ?? {},
|
||||
};
|
||||
}
|
||||
|
||||
private resolveAliasChain(
|
||||
@@ -165,8 +164,6 @@ export class ModelConfigService {
|
||||
baseModel: string | undefined;
|
||||
resolvedConfig: GenerateContentConfig;
|
||||
} {
|
||||
let baseModel: string | undefined = undefined;
|
||||
let resolvedConfig: GenerateContentConfig = {};
|
||||
const aliasChain: string[] = [];
|
||||
|
||||
if (allAliases[requestedModel]) {
|
||||
@@ -194,17 +191,19 @@ export class ModelConfigService {
|
||||
|
||||
// Root-to-Leaf chain for merging and level assignment.
|
||||
const reversedChain = [...aliasChain].reverse();
|
||||
let resolvedConfig: ModelConfig = {};
|
||||
for (const aliasName of reversedChain) {
|
||||
const alias = allAliases[aliasName];
|
||||
if (alias.modelConfig.model) {
|
||||
baseModel = alias.modelConfig.model;
|
||||
}
|
||||
resolvedConfig = this.deepMerge(
|
||||
resolvedConfig = ModelConfigService.merge(
|
||||
resolvedConfig,
|
||||
alias.modelConfig.generateContentConfig,
|
||||
alias.modelConfig,
|
||||
);
|
||||
}
|
||||
return { aliasChain: reversedChain, baseModel, resolvedConfig };
|
||||
return {
|
||||
aliasChain: reversedChain,
|
||||
baseModel: resolvedConfig.model,
|
||||
resolvedConfig: resolvedConfig.generateContentConfig ?? {},
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
@@ -298,21 +297,36 @@ export class ModelConfigService {
|
||||
} as ResolvedModelConfig;
|
||||
}
|
||||
|
||||
private isObject(item: unknown): item is Record<string, unknown> {
|
||||
static isObject(item: unknown): item is Record<string, unknown> {
|
||||
return !!item && typeof item === 'object' && !Array.isArray(item);
|
||||
}
|
||||
|
||||
private deepMerge(
|
||||
config1: GenerateContentConfig | undefined,
|
||||
config2: GenerateContentConfig | undefined,
|
||||
): Record<string, unknown> {
|
||||
return this.genericDeepMerge(
|
||||
config1 as Record<string, unknown> | undefined,
|
||||
config2 as Record<string, unknown> | undefined,
|
||||
);
|
||||
/**
|
||||
* Merges an override `ModelConfig` into a base `ModelConfig`.
|
||||
* The override's model name takes precedence if provided.
|
||||
* The `generateContentConfig` properties are deeply merged.
|
||||
*/
|
||||
static merge(base: ModelConfig, override: ModelConfig): ModelConfig {
|
||||
return {
|
||||
model: override.model ?? base.model,
|
||||
generateContentConfig: ModelConfigService.deepMerge(
|
||||
base.generateContentConfig,
|
||||
override.generateContentConfig,
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
private genericDeepMerge(
|
||||
static deepMerge(
|
||||
config1: GenerateContentConfig | undefined,
|
||||
config2: GenerateContentConfig | undefined,
|
||||
): GenerateContentConfig {
|
||||
return ModelConfigService.genericDeepMerge(
|
||||
config1 as Record<string, unknown> | undefined,
|
||||
config2 as Record<string, unknown> | undefined,
|
||||
) as GenerateContentConfig;
|
||||
}
|
||||
|
||||
private static genericDeepMerge(
|
||||
...objects: Array<Record<string, unknown> | undefined>
|
||||
): Record<string, unknown> {
|
||||
return objects.reduce((acc: Record<string, unknown>, obj) => {
|
||||
@@ -329,8 +343,11 @@ export class ModelConfigService {
|
||||
// override the base array.
|
||||
// TODO(joshualitt): Consider knobs here, i.e. opt-in to deep merging
|
||||
// arrays on a case-by-case basis.
|
||||
if (this.isObject(accValue) && this.isObject(objValue)) {
|
||||
acc[key] = this.deepMerge(accValue, objValue);
|
||||
if (
|
||||
ModelConfigService.isObject(accValue) &&
|
||||
ModelConfigService.isObject(objValue)
|
||||
) {
|
||||
acc[key] = ModelConfigService.genericDeepMerge(accValue, objValue);
|
||||
} else {
|
||||
acc[key] = objValue;
|
||||
}
|
||||
|
||||
@@ -926,6 +926,26 @@
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"agents": {
|
||||
"title": "Agents",
|
||||
"description": "Settings for subagents.",
|
||||
"markdownDescription": "Settings for subagents.\n\n- Category: `Advanced`\n- Requires restart: `yes`\n- Default: `{}`",
|
||||
"default": {},
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"overrides": {
|
||||
"title": "Agent Overrides",
|
||||
"description": "Override settings for specific agents, e.g. to disable the agent, set a custom model config, or run config.",
|
||||
"markdownDescription": "Override settings for specific agents, e.g. to disable the agent, set a custom model config, or run config.\n\n- Category: `Advanced`\n- Requires restart: `yes`\n- Default: `{}`",
|
||||
"default": {},
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"$ref": "#/$defs/AgentOverride"
|
||||
}
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"context": {
|
||||
"title": "Context",
|
||||
"description": "Settings for managing context provided to the model.",
|
||||
@@ -1854,6 +1874,36 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"AgentOverride": {
|
||||
"type": "object",
|
||||
"description": "Override settings for a specific agent.",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"modelConfig": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
},
|
||||
"runConfig": {
|
||||
"type": "object",
|
||||
"description": "Run configuration for an agent.",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"maxTimeMinutes": {
|
||||
"type": "number",
|
||||
"description": "The maximum execution time for the agent in minutes."
|
||||
},
|
||||
"maxTurns": {
|
||||
"type": "number",
|
||||
"description": "The maximum number of conversational turns."
|
||||
}
|
||||
}
|
||||
},
|
||||
"disabled": {
|
||||
"type": "boolean",
|
||||
"description": "Whether to disable the agent."
|
||||
}
|
||||
}
|
||||
},
|
||||
"CustomTheme": {
|
||||
"type": "object",
|
||||
"description": "Custom theme definition used for styling Gemini CLI output. Colors are provided as hex strings or named ANSI colors.",
|
||||
|
||||
Reference in New Issue
Block a user