2025-04-19 19:45:42 +01:00
/**
* @license
2026-02-09 21:53:10 -05:00
* Copyright 2026 Google LLC
2025-04-19 19:45:42 +01:00
* SPDX-License-Identifier: Apache-2.0
*/
2026-01-26 16:57:27 -05:00
import * as fs from 'node:fs' ;
2025-04-19 19:45:42 +01:00
import * as path from 'node:path' ;
2026-01-27 13:17:40 -08:00
import * as os from 'node:os' ;
2025-11-10 23:15:38 -05:00
import { inspect } from 'node:util' ;
2025-04-19 19:45:42 +01:00
import process from 'node:process' ;
2025-09-07 13:00:03 -07:00
import type {
ContentGenerator ,
ContentGeneratorConfig ,
} from '../core/contentGenerator.js' ;
2025-06-19 16:52:22 -07:00
import {
AuthType ,
2025-09-07 13:00:03 -07:00
createContentGenerator ,
2025-06-19 16:52:22 -07:00
createContentGeneratorConfig ,
} from '../core/contentGenerator.js' ;
2025-07-25 20:56:33 +00:00
import { PromptRegistry } from '../prompts/prompt-registry.js' ;
2025-12-09 03:43:12 +01:00
import { ResourceRegistry } from '../resources/resource-registry.js' ;
2025-04-21 12:59:31 -07:00
import { ToolRegistry } from '../tools/tool-registry.js' ;
import { LSTool } from '../tools/ls.js' ;
import { ReadFileTool } from '../tools/read-file.js' ;
import { GrepTool } from '../tools/grep.js' ;
2025-09-08 14:44:56 -07:00
import { canUseRipgrep , RipGrepTool } from '../tools/ripGrep.js' ;
2025-04-21 12:59:31 -07:00
import { GlobTool } from '../tools/glob.js' ;
2026-01-02 11:15:06 -08:00
import { ActivateSkillTool } from '../tools/activate-skill.js' ;
2026-01-05 15:25:54 -05:00
import { EditTool } from '../tools/edit.js' ;
2025-04-24 18:03:33 -07:00
import { ShellTool } from '../tools/shell.js' ;
2025-06-08 16:20:43 -07:00
import { WriteFileTool } from '../tools/write-file.js' ;
2025-04-21 12:59:31 -07:00
import { WebFetchTool } from '../tools/web-fetch.js' ;
2025-08-20 10:55:47 +09:00
import { MemoryTool , setGeminiMdFilename } from '../tools/memoryTool.js' ;
2025-05-20 11:36:21 -07:00
import { WebSearchTool } from '../tools/web-search.js' ;
2026-01-27 13:30:44 -05:00
import { AskUserTool } from '../tools/ask-user.js' ;
2026-02-02 22:30:03 -05:00
import { ExitPlanModeTool } from '../tools/exit-plan-mode.js' ;
2026-02-04 13:57:41 -05:00
import { EnterPlanModeTool } from '../tools/enter-plan-mode.js' ;
2025-06-02 14:55:51 -07:00
import { GeminiClient } from '../core/client.js' ;
2025-09-09 01:14:15 -04:00
import { BaseLlmClient } from '../core/baseLlmClient.js' ;
2025-11-03 18:47:23 -08:00
import type { HookDefinition , HookEventName } from '../hooks/types.js' ;
2025-06-03 21:40:46 -07:00
import { FileDiscoveryService } from '../services/fileDiscoveryService.js' ;
2025-06-11 15:33:09 -04:00
import { GitService } from '../services/gitService.js' ;
2025-08-26 00:04:53 +02:00
import type { TelemetryTarget } from '../telemetry/index.js' ;
2025-06-15 00:47:32 -04:00
import {
initializeTelemetry ,
DEFAULT_TELEMETRY_TARGET ,
DEFAULT_OTLP_ENDPOINT ,
2025-09-12 15:11:41 -07:00
uiTelemetryService ,
2025-06-15 00:47:32 -04:00
} from '../telemetry/index.js' ;
2026-01-12 12:11:24 -05:00
import { coreEvents , CoreEvent } from '../utils/events.js' ;
2025-09-12 15:11:41 -07:00
import { tokenLimit } from '../core/tokenLimits.js' ;
2025-06-24 18:48:55 -04:00
import {
DEFAULT_GEMINI_EMBEDDING_MODEL ,
DEFAULT_GEMINI_FLASH_MODEL ,
2026-02-09 21:53:10 -05:00
DEFAULT_GEMINI_MODEL ,
2025-12-17 09:43:21 -08:00
DEFAULT_GEMINI_MODEL_AUTO ,
2026-02-09 21:53:10 -05:00
isAutoModel ,
2025-12-17 09:43:21 -08:00
isPreviewModel ,
2026-02-09 21:53:10 -05:00
PREVIEW_GEMINI_FLASH_MODEL ,
2025-12-17 09:43:21 -08:00
PREVIEW_GEMINI_MODEL ,
2026-02-09 21:53:10 -05:00
PREVIEW_GEMINI_MODEL_AUTO ,
resolveModel ,
2025-06-24 18:48:55 -04:00
} from './models.js' ;
2025-07-21 16:23:28 -07:00
import { shouldAttemptBrowserLaunch } from '../utils/browser.js' ;
2025-08-26 00:04:53 +02:00
import type { MCPOAuthConfig } from '../mcp/oauth-provider.js' ;
2025-09-11 11:22:20 -07:00
import { ideContextStore } from '../ide/ideContext.js' ;
2025-09-20 06:01:02 -07:00
import { WriteTodosTool } from '../tools/write-todos.js' ;
2025-08-26 00:04:53 +02:00
import type { FileSystemService } from '../services/fileSystemService.js' ;
import { StandardFileSystemService } from '../services/fileSystemService.js' ;
2026-02-21 13:33:25 -05:00
import {
logRipgrepFallback ,
logFlashFallback ,
logApprovalModeSwitch ,
logApprovalModeDuration ,
} from '../telemetry/loggers.js' ;
2026-01-02 13:19:43 -05:00
import {
RipgrepFallbackEvent ,
FlashFallbackEvent ,
2026-01-20 13:57:34 -05:00
ApprovalModeSwitchEvent ,
ApprovalModeDurationEvent ,
2026-01-02 13:19:43 -05:00
} from '../telemetry/types.js' ;
2026-01-20 16:23:01 -08:00
import type {
FallbackModelHandler ,
ValidationHandler ,
} from '../fallback/types.js' ;
2025-11-26 12:36:42 -08:00
import { ModelAvailabilityService } from '../availability/modelAvailabilityService.js' ;
2025-09-11 13:38:50 -04:00
import { ModelRouterService } from '../routing/modelRouterService.js' ;
2025-09-11 05:19:47 +09:00
import { OutputFormat } from '../output/types.js' ;
2026-01-13 12:16:02 -08:00
import type {
ModelConfig ,
ModelConfigServiceConfig ,
} from '../services/modelConfigService.js' ;
2025-11-05 17:18:42 -08:00
import { ModelConfigService } from '../services/modelConfigService.js' ;
import { DEFAULT_MODEL_CONFIGS } from './defaultModelConfigs.js' ;
2025-12-03 04:09:46 +08:00
import { ContextManager } from '../services/contextManager.js' ;
2026-01-11 14:11:06 -05:00
import type { GenerateContentParameters } from '@google/genai' ;
2025-07-22 09:34:56 -04:00
// Re-export OAuth config type
2026-02-09 21:53:10 -05:00
export type { MCPOAuthConfig , AnyToolInvocation , AnyDeclarativeTool } ;
import type { AnyToolInvocation , AnyDeclarativeTool } from '../tools/tools.js' ;
2025-07-31 05:38:20 +09:00
import { WorkspaceContext } from '../utils/workspaceContext.js' ;
2025-08-20 10:55:47 +09:00
import { Storage } from './storage.js' ;
2025-09-11 13:27:27 -07:00
import type { ShellExecutionConfig } from '../services/shellExecutionService.js' ;
2025-08-23 13:35:00 +09:00
import { FileExclusions } from '../utils/ignorePatterns.js' ;
2025-09-11 09:39:17 -07:00
import { MessageBus } from '../confirmation-bus/message-bus.js' ;
2026-02-09 21:53:10 -05:00
import type { EventEmitter } from 'node:events' ;
2025-09-11 09:39:17 -07:00
import { PolicyEngine } from '../policy/policy-engine.js' ;
2026-01-06 23:28:06 -05:00
import { ApprovalMode , type PolicyEngineConfig } from '../policy/types.js' ;
2025-11-24 14:31:48 -08:00
import { HookSystem } from '../hooks/index.js' ;
2026-02-21 13:33:25 -05:00
import type {
UserTierId ,
RetrieveUserQuotaResponse ,
AdminControlsSettings ,
} from '../code_assist/types.js' ;
2026-02-09 18:01:59 -08:00
import type { HierarchicalMemory } from './memory.js' ;
2025-11-04 15:09:53 -08:00
import { getCodeAssistServer } from '../code_assist/codeAssist.js' ;
import type { Experiments } from '../code_assist/experiments/experiments.js' ;
2025-10-01 16:54:00 -04:00
import { AgentRegistry } from '../agents/registry.js' ;
2026-01-26 19:49:32 +00:00
import { AcknowledgedAgentsService } from '../agents/acknowledgedAgents.js' ;
2025-10-21 12:43:37 -07:00
import { setGlobalProxy } from '../utils/fetch.js' ;
2026-01-23 02:18:31 +00:00
import { SubagentTool } from '../agents/subagent-tool.js' ;
2025-11-04 15:09:53 -08:00
import { getExperiments } from '../code_assist/experiments/experiments.js' ;
2025-11-10 23:15:38 -05:00
import { ExperimentFlags } from '../code_assist/experiments/flagNames.js' ;
2025-11-04 15:09:53 -08:00
import { debugLogger } from '../utils/debugLogger.js' ;
2026-01-04 14:45:07 -08:00
import { SkillManager , type SkillDefinition } from '../skills/skillManager.js' ;
2025-12-01 10:06:13 -08:00
import { startupProfiler } from '../telemetry/startupProfiler.js' ;
2026-01-13 19:09:22 +00:00
import type { AgentDefinition } from '../agents/types.js' ;
2026-01-16 15:24:53 -05:00
import { fetchAdminControls } from '../code_assist/admin/admin_controls.js' ;
2026-01-27 13:17:40 -08:00
import { isSubpath } from '../utils/paths.js' ;
2026-02-18 14:05:50 -08:00
import { UserHintService } from './userHintService.js' ;
2026-02-19 16:16:03 -08:00
import { WORKSPACE_POLICY_TIER } from '../policy/config.js' ;
import { loadPoliciesFromToml } from '../policy/toml-loader.js' ;
2025-10-01 16:54:00 -04:00
2026-02-23 18:44:28 -08:00
import { CheckerRunner } from '../safety/checker-runner.js' ;
import { ContextBuilder } from '../safety/context-builder.js' ;
import { CheckerRegistry } from '../safety/registry.js' ;
import { ConsecaSafetyChecker } from '../safety/conseca/conseca.js' ;
2025-06-04 00:46:57 -07:00
export interface AccessibilitySettings {
2026-02-19 13:43:12 -05:00
/** @deprecated Use ui.loadingPhrases instead. */
2026-01-16 23:33:49 +01:00
enableLoadingPhrases? : boolean ;
2025-08-21 22:29:15 +00:00
screenReader? : boolean ;
2025-06-04 00:46:57 -07:00
}
2025-06-14 00:00:24 -07:00
export interface BugCommandSettings {
urlTemplate : string ;
}
2025-07-15 10:22:31 -07:00
export interface SummarizeToolOutputSettings {
tokenBudget? : number ;
}
2026-02-19 17:47:08 -05:00
export interface PlanSettings {
directory? : string ;
2026-02-24 19:15:14 -05:00
modelRouting? : boolean ;
2026-02-19 17:47:08 -05:00
}
2025-06-15 00:47:32 -04:00
export interface TelemetrySettings {
enabled? : boolean ;
target? : TelemetryTarget ;
otlpEndpoint? : string ;
2025-08-15 18:10:21 -07:00
otlpProtocol ? : 'grpc' | 'http' ;
2025-06-15 00:47:32 -04:00
logPrompts? : boolean ;
2025-07-23 17:48:24 -04:00
outfile? : string ;
2025-09-17 04:13:57 +09:00
useCollector? : boolean ;
2025-12-02 21:27:37 -08:00
useCliAuth? : boolean ;
2025-06-15 00:47:32 -04:00
}
2025-09-11 05:19:47 +09:00
export interface OutputSettings {
format? : OutputFormat ;
}
2026-02-05 20:53:11 -05:00
export interface ToolOutputMaskingConfig {
enabled : boolean ;
toolProtectionThreshold : number ;
minPrunableTokensThreshold : number ;
protectLatestTurn : boolean ;
}
2025-12-30 16:09:48 -05:00
export interface ExtensionSetting {
name : string ;
description : string ;
envVar : string ;
sensitive? : boolean ;
}
export interface ResolvedExtensionSetting {
name : string ;
envVar : string ;
2026-02-03 15:39:20 -05:00
value? : string ;
2025-12-30 16:09:48 -05:00
sensitive : boolean ;
2026-01-09 12:04:53 -05:00
scope ? : 'user' | 'workspace' ;
source? : string ;
2025-12-30 16:09:48 -05:00
}
2026-01-13 12:16:02 -08:00
export interface AgentRunConfig {
maxTimeMinutes? : number ;
maxTurns? : number ;
}
2026-02-24 09:22:09 -08:00
/**
* Override configuration for a specific agent.
* Generic fields (modelConfig, runConfig, enabled) are standard across all agents.
*/
2026-01-13 12:16:02 -08:00
export interface AgentOverride {
modelConfig? : ModelConfig ;
runConfig? : AgentRunConfig ;
2026-01-16 09:21:13 -08:00
enabled? : boolean ;
2026-01-13 12:16:02 -08:00
}
export interface AgentSettings {
overrides? : Record < string , AgentOverride > ;
2026-02-24 09:22:09 -08:00
browser? : BrowserAgentCustomConfig ;
2026-01-13 12:16:02 -08:00
}
2026-01-28 13:58:35 -05:00
export interface CustomTheme {
type : 'custom' ;
name : string ;
text ? : {
primary? : string ;
secondary? : string ;
link? : string ;
accent? : string ;
response? : string ;
} ;
background ? : {
primary? : string ;
diff ? : {
added? : string ;
removed? : string ;
} ;
} ;
border ? : {
default ? : string ;
focused? : string ;
} ;
ui ? : {
comment? : string ;
symbol ? : string ;
gradient? : string [ ] ;
} ;
status ? : {
error? : string ;
success? : string ;
warning? : string ;
} ;
// Legacy properties (all optional)
Background? : string ;
Foreground? : string ;
LightBlue? : string ;
AccentBlue? : string ;
AccentPurple? : string ;
AccentCyan? : string ;
AccentGreen? : string ;
AccentYellow? : string ;
AccentRed? : string ;
DiffAdded? : string ;
DiffRemoved? : string ;
Comment? : string ;
Gray? : string ;
DarkGray? : string ;
GradientColors? : string [ ] ;
}
2026-02-24 09:22:09 -08:00
/**
* Browser agent custom configuration.
* Used in agents.browser
*
* IMPORTANT: Keep in sync with the browser settings schema in
* packages/cli/src/config/settingsSchema.ts (agents.browser.properties).
*/
export interface BrowserAgentCustomConfig {
/**
* Session mode:
* - 'persistent': Launch Chrome with a persistent profile at ~/.cache/chrome-devtools-mcp/ (default)
* - 'isolated': Launch Chrome with a temporary profile, cleaned up after session
* - 'existing': Attach to an already-running Chrome instance (requires remote debugging
* enabled at chrome://inspect/#remote-debugging)
*/
sessionMode ? : 'isolated' | 'persistent' | 'existing' ;
/** Run browser in headless mode. Default: false */
headless? : boolean ;
/** Path to Chrome profile directory for session persistence. */
profilePath? : string ;
/** Model override for the visual agent. */
visualModel? : string ;
}
2025-10-08 07:31:41 -07:00
/**
* 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
* around on the config object though Core does not use this information
* directly.
*/
2025-07-18 20:45:00 +02:00
export interface GeminiCLIExtension {
2025-07-08 12:57:34 -04:00
name : string ;
version : string ;
2025-07-18 20:45:00 +02:00
isActive : boolean ;
2025-07-28 18:40:47 -07:00
path : string ;
2025-09-17 18:14:01 -04:00
installMetadata? : ExtensionInstallMetadata ;
2025-10-08 07:31:41 -07:00
mcpServers? : Record < string , MCPServerConfig > ;
contextFiles : string [ ] ;
excludeTools? : string [ ] ;
2025-10-21 16:55:16 -04:00
id : string ;
2025-11-02 11:49:16 -08:00
hooks ? : { [ K in HookEventName ] ? : HookDefinition [ ] } ;
2025-12-30 16:09:48 -05:00
settings? : ExtensionSetting [ ] ;
resolvedSettings? : ResolvedExtensionSetting [ ] ;
2026-01-04 14:45:07 -08:00
skills? : SkillDefinition [ ] ;
2026-01-13 19:09:22 +00:00
agents? : AgentDefinition [ ] ;
2026-01-28 13:58:35 -05:00
/**
* Custom themes contributed by this extension.
* These themes will be registered when the extension is activated.
*/
themes? : CustomTheme [ ] ;
2025-09-17 18:14:01 -04:00
}
export interface ExtensionInstallMetadata {
source : string ;
type : 'git' | 'local' | 'link' | 'github-release' ;
2025-09-22 09:42:35 -07:00
releaseTag? : string ; // Only present for github-release installs.
2025-09-12 09:20:04 -07:00
ref? : string ;
2025-09-18 14:49:47 -07:00
autoUpdate? : boolean ;
2025-10-08 14:26:12 -07:00
allowPreRelease? : boolean ;
2025-07-08 12:57:34 -04:00
}
2025-09-12 09:20:04 -07:00
2026-02-23 15:57:16 -08:00
import { DEFAULT_MAX_ATTEMPTS } from '../utils/retry.js' ;
2025-09-26 13:37:00 -04:00
import type { FileFilteringOptions } from './constants.js' ;
import {
DEFAULT_FILE_FILTERING_OPTIONS ,
2025-10-10 12:04:15 -04:00
DEFAULT_MEMORY_FILE_FILTERING_OPTIONS ,
2025-09-26 13:37:00 -04:00
} from './constants.js' ;
2026-02-05 20:53:11 -05:00
import {
DEFAULT_TOOL_PROTECTION_THRESHOLD ,
DEFAULT_MIN_PRUNABLE_TOKENS_THRESHOLD ,
DEFAULT_PROTECT_LATEST_TURN ,
} from '../services/toolOutputMaskingService.js' ;
2025-11-03 15:41:00 -08:00
2025-10-28 09:04:30 -07:00
import {
type ExtensionLoader ,
SimpleExtensionLoader ,
} from '../utils/extensionLoader.js' ;
2025-11-04 07:51:18 -08:00
import { McpClientManager } from '../tools/mcp-client-manager.js' ;
2025-12-22 19:18:27 -08:00
import type { EnvironmentSanitizationConfig } from '../services/environmentSanitization.js' ;
2026-01-23 02:18:31 +00:00
import { getErrorMessage } from '../utils/errors.js' ;
2026-02-05 15:04:03 -05:00
import {
ENTER_PLAN_MODE_TOOL_NAME ,
EXIT_PLAN_MODE_TOOL_NAME ,
} from '../tools/tool-names.js' ;
2025-09-26 13:37:00 -04:00
export type { FileFilteringOptions } ;
export {
DEFAULT_FILE_FILTERING_OPTIONS ,
2025-10-10 12:04:15 -04:00
DEFAULT_MEMORY_FILE_FILTERING_OPTIONS ,
2025-07-20 00:55:33 -07:00
} ;
2025-09-05 15:37:29 -07:00
2026-02-06 13:41:19 -08:00
export const DEFAULT_TRUNCATE_TOOL_OUTPUT_THRESHOLD = 40 _000 ;
2025-09-05 15:37:29 -07:00
2025-05-17 16:53:22 -07:00
export class MCPServerConfig {
constructor (
2025-05-23 17:19:30 -04:00
// For stdio transport
readonly command? : string ,
2025-05-17 16:53:22 -07:00
readonly args? : string [ ] ,
readonly env? : Record < string , string > ,
readonly cwd? : string ,
2025-05-23 17:19:30 -04:00
// For sse transport
readonly url? : string ,
2025-06-13 20:18:06 +00:00
// For streamable http transport
readonly httpUrl? : string ,
2025-06-30 01:09:08 +01:00
readonly headers? : Record < string , string > ,
2025-06-13 13:30:44 +00:00
// For websocket transport
readonly tcp? : string ,
2025-12-02 20:01:33 -05:00
// Transport type (optional, for use with 'url' field)
// When set to 'http', uses StreamableHTTPClientTransport
// When set to 'sse', uses SSEClientTransport
// When omitted, auto-detects transport type
// Note: 'httpUrl' is deprecated in favor of 'url' + 'type'
readonly type ? : 'sse' | 'http' ,
2025-05-23 17:19:30 -04:00
// Common
2025-05-17 16:53:22 -07:00
readonly timeout? : number ,
2025-05-30 15:32:21 -07:00
readonly trust? : boolean ,
2025-06-07 18:30:56 -04:00
// Metadata
readonly description? : string ,
2025-07-07 18:34:26 +02:00
readonly includeTools? : string [ ] ,
readonly excludeTools? : string [ ] ,
2025-10-20 16:15:23 -07:00
readonly extension? : GeminiCLIExtension ,
2025-07-22 09:34:56 -04:00
// OAuth configuration
readonly oauth? : MCPOAuthConfig ,
2025-07-24 10:37:39 -07:00
readonly authProviderType? : AuthProviderType ,
2025-09-27 10:12:24 +02:00
// Service Account Configuration
/* targetAudience format: CLIENT_ID.apps.googleusercontent.com */
readonly targetAudience? : string ,
/* targetServiceAccount format: <service-account-name>@<project-num>.iam.gserviceaccount.com */
readonly targetServiceAccount? : string ,
2025-05-17 16:53:22 -07:00
) { }
}
2025-04-19 19:45:42 +01:00
2025-07-24 10:37:39 -07:00
export enum AuthProviderType {
DYNAMIC_DISCOVERY = 'dynamic_discovery' ,
GOOGLE_CREDENTIALS = 'google_credentials' ,
2025-09-27 10:12:24 +02:00
SERVICE_ACCOUNT_IMPERSONATION = 'service_account_impersonation' ,
2025-07-24 10:37:39 -07:00
}
2025-06-18 10:01:00 -07:00
export interface SandboxConfig {
command : 'docker' | 'podman' | 'sandbox-exec' ;
image : string ;
}
2026-01-22 15:38:06 -08:00
/**
* Callbacks for checking MCP server enablement status.
* These callbacks are provided by the CLI package to bridge
* the enablement state to the core package.
*/
export interface McpEnablementCallbacks {
/** Check if a server is disabled for the current session only */
isSessionDisabled : ( serverId : string ) = > boolean ;
/** Check if a server is enabled in the file-based configuration */
isFileEnabled : ( serverId : string ) = > Promise < boolean > ;
}
2026-02-19 16:16:03 -08:00
export interface PolicyUpdateConfirmationRequest {
scope : string ;
identifier : string ;
policyDir : string ;
newHash : string ;
}
2025-05-29 20:51:17 +00:00
export interface ConfigParameters {
2025-06-11 04:46:39 +00:00
sessionId : string ;
2026-01-20 22:01:18 +00:00
clientVersion? : string ;
2025-06-13 01:25:42 -07:00
embeddingModel? : string ;
2025-06-18 10:01:00 -07:00
sandbox? : SandboxConfig ;
2025-05-29 20:51:17 +00:00
targetDir : string ;
debugMode : boolean ;
question? : string ;
2025-10-16 12:09:21 -07:00
2025-05-29 20:51:17 +00:00
coreTools? : string [ ] ;
2026-02-11 16:49:48 -08:00
/** @deprecated Use Policy Engine instead */
2025-08-27 02:17:43 +10:00
allowedTools? : string [ ] ;
2026-02-11 16:49:48 -08:00
/** @deprecated Use Policy Engine instead */
2025-06-11 14:32:23 -07:00
excludeTools? : string [ ] ;
2025-05-29 20:51:17 +00:00
toolDiscoveryCommand? : string ;
toolCallCommand? : string ;
mcpServerCommand? : string ;
mcpServers? : Record < string , MCPServerConfig > ;
2026-01-22 15:38:06 -08:00
mcpEnablementCallbacks? : McpEnablementCallbacks ;
2026-02-09 18:01:59 -08:00
userMemory? : string | HierarchicalMemory ;
2025-05-29 20:51:17 +00:00
geminiMdFileCount? : number ;
2025-10-02 17:46:54 -04:00
geminiMdFilePaths? : string [ ] ;
2025-06-02 22:05:45 +02:00
approvalMode? : ApprovalMode ;
2025-05-30 22:18:01 +00:00
showMemoryUsage? : boolean ;
2025-06-13 09:19:08 -07:00
contextFileName? : string | string [ ] ;
2025-06-04 00:46:57 -07:00
accessibility? : AccessibilitySettings ;
2025-06-15 00:47:32 -04:00
telemetry? : TelemetrySettings ;
2025-06-23 20:29:31 -04:00
usageStatisticsEnabled? : boolean ;
2025-06-21 18:23:35 -07:00
fileFiltering ? : {
respectGitIgnore? : boolean ;
2025-07-20 00:55:33 -07:00
respectGeminiIgnore? : boolean ;
2025-06-21 18:23:35 -07:00
enableRecursiveFileSearch? : boolean ;
2026-01-16 23:33:49 +01:00
enableFuzzySearch? : boolean ;
2026-01-15 12:04:22 -08:00
maxFileCount? : number ;
searchTimeout? : number ;
2026-01-27 17:19:13 -08:00
customIgnoreFilePaths? : string [ ] ;
2025-06-21 18:23:35 -07:00
} ;
2025-06-20 00:39:15 -04:00
checkpointing? : boolean ;
2025-06-12 17:17:29 -07:00
proxy? : string ;
cwd : string ;
2025-06-13 20:25:59 -04:00
fileDiscoveryService? : FileDiscoveryService ;
2025-07-31 05:38:20 +09:00
includeDirectories? : string [ ] ;
2025-06-14 00:00:24 -07:00
bugCommand? : BugCommandSettings ;
2025-06-19 16:52:22 -07:00
model : string ;
2026-02-02 10:13:20 -08:00
disableLoopDetection? : boolean ;
2025-07-11 07:55:03 -07:00
maxSessionTurns? : number ;
2025-08-13 12:58:26 -03:00
experimentalZedIntegration? : boolean ;
2025-11-10 18:31:00 -07:00
listSessions? : boolean ;
deleteSession? : string ;
2025-07-08 12:57:34 -04:00
listExtensions? : boolean ;
2025-10-28 09:04:30 -07:00
extensionLoader? : ExtensionLoader ;
2025-10-20 16:15:23 -07:00
enabledExtensions? : string [ ] ;
2025-10-30 11:05:49 -07:00
enableExtensionReloading? : boolean ;
2025-11-04 07:51:18 -08:00
allowedMcpServers? : string [ ] ;
blockedMcpServers? : string [ ] ;
2025-12-22 19:18:27 -08:00
allowedEnvironmentVariables? : string [ ] ;
blockedEnvironmentVariables? : string [ ] ;
enableEnvironmentVariableRedaction? : boolean ;
2025-07-10 18:59:02 -07:00
noBrowser? : boolean ;
2025-07-15 10:22:31 -07:00
summarizeToolOutput? : Record < string , SummarizeToolOutputSettings > ;
2025-08-07 14:06:17 -07:00
folderTrust? : boolean ;
2025-07-14 12:04:08 -04:00
ideMode? : boolean ;
2025-08-06 02:01:01 +09:00
loadMemoryFromIncludeDirectories? : boolean ;
2026-02-17 11:19:26 -08:00
includeDirectoryTree? : boolean ;
2025-11-07 09:07:25 -08:00
importFormat ? : 'tree' | 'flat' ;
discoveryMaxDirs? : number ;
2025-10-30 16:03:58 -07:00
compressionThreshold? : number ;
2025-08-07 14:19:06 -07:00
interactive? : boolean ;
2025-08-13 11:06:31 -07:00
trustedFolder? : boolean ;
2026-01-26 15:23:54 -08:00
useBackgroundColor? : boolean ;
2025-08-22 14:10:45 +08:00
useRipgrep? : boolean ;
2025-10-08 13:28:19 -07:00
enableInteractiveShell? : boolean ;
2025-08-19 16:45:13 -07:00
skipNextSpeakerCheck? : boolean ;
2025-09-11 13:27:27 -07:00
shellExecutionConfig? : ShellExecutionConfig ;
2025-08-25 17:02:10 +00:00
extensionManagement? : boolean ;
2025-09-05 15:37:29 -07:00
truncateToolOutputThreshold? : number ;
2025-08-28 21:53:56 +02:00
eventEmitter? : EventEmitter ;
2025-09-20 06:01:02 -07:00
useWriteTodos? : boolean ;
2025-09-11 09:39:17 -07:00
policyEngineConfig? : PolicyEngineConfig ;
2026-02-23 11:50:14 -08:00
directWebFetch? : boolean ;
2026-02-19 16:16:03 -08:00
policyUpdateConfirmationRequest? : PolicyUpdateConfirmationRequest ;
2025-09-11 05:19:47 +09:00
output? : OutputSettings ;
2025-10-28 18:25:53 -04:00
disableModelRouterForAuth? : AuthType [ ] ;
2025-10-09 18:04:08 -04:00
continueOnFailedApiCall? : boolean ;
2025-10-14 09:17:31 -07:00
retryFetchErrors? : boolean ;
2026-02-23 15:57:16 -08:00
maxAttempts? : number ;
2025-10-13 21:31:45 -07:00
enableShellOutputEfficiency? : boolean ;
2025-11-26 13:43:33 -08:00
shellToolInactivityTimeout? : number ;
2025-10-23 16:10:43 -07:00
fakeResponses? : string ;
2025-10-28 12:13:45 -07:00
recordResponses? : string ;
2025-10-17 09:07:18 -07:00
ptyInfo? : string ;
2025-10-22 11:57:10 -07:00
disableYoloMode? : boolean ;
2026-01-20 23:58:37 -05:00
rawOutput? : boolean ;
acceptRawOutputRisk? : boolean ;
2025-11-05 17:18:42 -08:00
modelConfigServiceConfig? : ModelConfigServiceConfig ;
2025-11-02 11:49:16 -08:00
enableHooks? : boolean ;
2026-01-07 12:34:33 -08:00
enableHooksUI? : boolean ;
2025-11-04 15:09:53 -08:00
experiments? : Experiments ;
2026-01-20 14:47:31 -08:00
hooks ? : { [ K in HookEventName ] ? : HookDefinition [ ] } ;
disabledHooks? : string [ ] ;
projectHooks ? : { [ K in HookEventName ] ? : HookDefinition [ ] } ;
2025-12-03 12:53:06 -08:00
enableAgents? : boolean ;
2026-01-19 22:59:30 -05:00
enableEventDrivenScheduler? : boolean ;
2025-12-30 13:35:52 -08:00
skillsSupport? : boolean ;
disabledSkills? : string [ ] ;
2026-01-13 23:40:23 -08:00
adminSkillsEnabled? : boolean ;
2025-12-03 04:09:46 +08:00
experimentalJitContext? : boolean ;
2026-02-05 20:53:11 -05:00
toolOutputMasking? : Partial < ToolOutputMaskingConfig > ;
2026-01-13 09:26:53 +08:00
disableLLMCorrection? : boolean ;
2026-01-14 19:55:10 -05:00
plan? : boolean ;
2026-02-19 17:47:08 -05:00
planSettings? : PlanSettings ;
2026-02-18 14:05:50 -08:00
modelSteering? : boolean ;
2025-12-23 19:53:43 +05:30
onModelChange ? : ( model : string ) = > void ;
2026-01-06 16:38:07 -05:00
mcpEnabled? : boolean ;
2026-01-08 12:59:30 -05:00
extensionsEnabled? : boolean ;
2026-01-13 12:16:02 -08:00
agents? : AgentSettings ;
2026-01-13 23:40:23 -08:00
onReload ? : ( ) = > Promise < {
disabledSkills? : string [ ] ;
adminSkillsEnabled? : boolean ;
2026-01-14 19:30:17 -05:00
agents? : AgentSettings ;
2026-01-13 23:40:23 -08:00
} > ;
2026-02-23 18:44:28 -08:00
enableConseca? : boolean ;
2025-05-29 20:51:17 +00:00
}
2025-04-19 19:45:42 +01:00
export class Config {
2025-06-19 19:54:36 -07:00
private toolRegistry ! : ToolRegistry ;
2025-11-04 07:51:18 -08:00
private mcpClientManager? : McpClientManager ;
private allowedMcpServers : string [ ] ;
private blockedMcpServers : string [ ] ;
2025-12-22 19:18:27 -08:00
private allowedEnvironmentVariables : string [ ] ;
private blockedEnvironmentVariables : string [ ] ;
private readonly enableEnvironmentVariableRedaction : boolean ;
2025-07-25 20:56:33 +00:00
private promptRegistry ! : PromptRegistry ;
2025-12-09 03:43:12 +01:00
private resourceRegistry ! : ResourceRegistry ;
2025-10-01 16:54:00 -04:00
private agentRegistry ! : AgentRegistry ;
2026-01-26 19:49:32 +00:00
private readonly acknowledgedAgentsService : AcknowledgedAgentsService ;
2025-12-30 13:35:52 -08:00
private skillManager ! : SkillManager ;
2025-11-10 18:31:00 -07:00
private sessionId : string ;
2026-01-20 22:01:18 +00:00
private clientVersion : string ;
2025-08-18 16:29:45 -06:00
private fileSystemService : FileSystemService ;
2025-06-19 16:52:22 -07:00
private contentGeneratorConfig ! : ContentGeneratorConfig ;
2025-09-07 13:00:03 -07:00
private contentGenerator ! : ContentGenerator ;
2025-11-05 17:18:42 -08:00
readonly modelConfigService : ModelConfigService ;
2025-07-28 11:13:46 -07:00
private readonly embeddingModel : string ;
private readonly sandbox : SandboxConfig | undefined ;
private readonly targetDir : string ;
2025-08-01 04:02:08 +09:00
private workspaceContext : WorkspaceContext ;
2025-07-28 11:13:46 -07:00
private readonly debugMode : boolean ;
private readonly question : string | undefined ;
2026-02-23 18:44:28 -08:00
readonly enableConseca : boolean ;
2025-10-16 12:09:21 -07:00
2025-07-28 11:13:46 -07:00
private readonly coreTools : string [ ] | undefined ;
2026-02-11 16:49:48 -08:00
/** @deprecated Use Policy Engine instead */
2025-08-27 02:17:43 +10:00
private readonly allowedTools : string [ ] | undefined ;
2026-02-11 16:49:48 -08:00
/** @deprecated Use Policy Engine instead */
2025-07-28 11:13:46 -07:00
private readonly excludeTools : string [ ] | undefined ;
private readonly toolDiscoveryCommand : string | undefined ;
private readonly toolCallCommand : string | undefined ;
private readonly mcpServerCommand : string | undefined ;
2026-01-06 16:38:07 -05:00
private readonly mcpEnabled : boolean ;
2026-01-08 12:59:30 -05:00
private readonly extensionsEnabled : boolean ;
2025-10-30 11:05:49 -07:00
private mcpServers : Record < string , MCPServerConfig > | undefined ;
2026-01-22 15:38:06 -08:00
private readonly mcpEnablementCallbacks? : McpEnablementCallbacks ;
2026-02-09 18:01:59 -08:00
private userMemory : string | HierarchicalMemory ;
2025-05-29 20:51:17 +00:00
private geminiMdFileCount : number ;
2025-10-02 17:46:54 -04:00
private geminiMdFilePaths : string [ ] ;
2025-07-28 11:13:46 -07:00
private readonly showMemoryUsage : boolean ;
private readonly accessibility : AccessibilitySettings ;
private readonly telemetrySettings : TelemetrySettings ;
private readonly usageStatisticsEnabled : boolean ;
2025-06-19 16:52:22 -07:00
private geminiClient ! : GeminiClient ;
2025-09-09 01:14:15 -04:00
private baseLlmClient ! : BaseLlmClient ;
2025-09-11 13:38:50 -04:00
private modelRouterService : ModelRouterService ;
2025-11-26 12:36:42 -08:00
private readonly modelAvailabilityService : ModelAvailabilityService ;
2025-07-28 11:13:46 -07:00
private readonly fileFiltering : {
2025-06-21 18:23:35 -07:00
respectGitIgnore : boolean ;
2025-07-20 00:55:33 -07:00
respectGeminiIgnore : boolean ;
2025-06-21 18:23:35 -07:00
enableRecursiveFileSearch : boolean ;
2026-01-16 23:33:49 +01:00
enableFuzzySearch : boolean ;
2026-01-15 12:04:22 -08:00
maxFileCount : number ;
searchTimeout : number ;
2026-01-27 17:19:13 -08:00
customIgnoreFilePaths : string [ ] ;
2025-06-21 18:23:35 -07:00
} ;
2025-06-03 21:40:46 -07:00
private fileDiscoveryService : FileDiscoveryService | null = null ;
2025-06-11 15:33:09 -04:00
private gitService : GitService | undefined = undefined ;
2025-07-28 11:13:46 -07:00
private readonly checkpointing : boolean ;
private readonly proxy : string | undefined ;
private readonly cwd : string ;
private readonly bugCommand : BugCommandSettings | undefined ;
2025-09-11 13:38:50 -04:00
private model : string ;
2026-02-02 10:13:20 -08:00
private readonly disableLoopDetection : boolean ;
2026-02-23 09:14:00 +05:30
// null = unknown (quota not fetched); true = has access; false = definitively no access
private hasAccessToPreviewModel : boolean | null = null ;
2025-07-28 11:13:46 -07:00
private readonly noBrowser : boolean ;
2025-08-07 14:06:17 -07:00
private readonly folderTrust : boolean ;
2025-07-30 22:36:24 +00:00
private ideMode : boolean ;
2025-09-04 09:32:09 -07:00
2025-12-08 06:44:34 -08:00
private _activeModel : string ;
2025-07-28 11:13:46 -07:00
private readonly maxSessionTurns : number ;
2025-11-10 18:31:00 -07:00
private readonly listSessions : boolean ;
private readonly deleteSession : string | undefined ;
2025-07-28 11:13:46 -07:00
private readonly listExtensions : boolean ;
2025-10-28 09:04:30 -07:00
private readonly _extensionLoader : ExtensionLoader ;
2025-10-20 16:15:23 -07:00
private readonly _enabledExtensions : string [ ] ;
2025-10-30 11:05:49 -07:00
private readonly enableExtensionReloading : boolean ;
2025-09-08 16:19:52 -04:00
fallbackModelHandler? : FallbackModelHandler ;
2026-01-20 16:23:01 -08:00
validationHandler? : ValidationHandler ;
2025-07-09 13:55:56 -04:00
private quotaErrorOccurred : boolean = false ;
2026-02-09 21:53:10 -05:00
private modelQuotas : Map <
string ,
{ remaining : number ; limit : number ; resetTime? : string }
> = new Map ( ) ;
private lastRetrievedQuota? : RetrieveUserQuotaResponse ;
private lastQuotaFetchTime = 0 ;
private lastEmittedQuotaRemaining : number | undefined ;
private lastEmittedQuotaLimit : number | undefined ;
private emitQuotaChangedEvent ( ) : void {
const pooled = this . getPooledQuota ( ) ;
if (
this . lastEmittedQuotaRemaining !== pooled . remaining ||
this . lastEmittedQuotaLimit !== pooled . limit
) {
this . lastEmittedQuotaRemaining = pooled . remaining ;
this . lastEmittedQuotaLimit = pooled . limit ;
coreEvents . emitQuotaChanged (
pooled . remaining ,
pooled . limit ,
pooled . resetTime ,
) ;
}
}
2025-07-28 11:13:46 -07:00
private readonly summarizeToolOutput :
2025-07-15 10:22:31 -07:00
| Record < string , SummarizeToolOutputSettings >
| undefined ;
2025-08-13 12:58:26 -03:00
private readonly experimentalZedIntegration : boolean = false ;
2025-08-06 02:01:01 +09:00
private readonly loadMemoryFromIncludeDirectories : boolean = false ;
2026-02-17 11:19:26 -08:00
private readonly includeDirectoryTree : boolean = true ;
2025-11-07 09:07:25 -08:00
private readonly importFormat : 'tree' | 'flat' ;
private readonly discoveryMaxDirs : number ;
2025-10-30 16:03:58 -07:00
private readonly compressionThreshold : number | undefined ;
2026-01-27 13:17:40 -08:00
/** Public for testing only */
readonly interactive : boolean ;
2025-10-17 09:07:18 -07:00
private readonly ptyInfo : string ;
2025-08-13 11:06:31 -07:00
private readonly trustedFolder : boolean | undefined ;
2026-02-23 11:50:14 -08:00
private readonly directWebFetch : boolean ;
2025-08-22 14:10:45 +08:00
private readonly useRipgrep : boolean ;
2025-10-08 13:28:19 -07:00
private readonly enableInteractiveShell : boolean ;
2025-08-19 16:45:13 -07:00
private readonly skipNextSpeakerCheck : boolean ;
2026-01-26 15:23:54 -08:00
private readonly useBackgroundColor : boolean ;
2025-09-11 13:27:27 -07:00
private shellExecutionConfig : ShellExecutionConfig ;
2025-09-05 11:44:41 -07:00
private readonly extensionManagement : boolean = true ;
2025-09-05 15:37:29 -07:00
private readonly truncateToolOutputThreshold : number ;
2026-01-18 22:40:07 -08:00
private compressionTruncationCounter = 0 ;
2026-02-17 14:59:33 -08:00
private initialized = false ;
private initPromise : Promise < void > | undefined ;
2025-08-20 10:55:47 +09:00
readonly storage : Storage ;
2025-08-23 13:35:00 +09:00
private readonly fileExclusions : FileExclusions ;
2025-08-28 21:53:56 +02:00
private readonly eventEmitter? : EventEmitter ;
2025-09-20 06:01:02 -07:00
private readonly useWriteTodos : boolean ;
2025-09-11 09:39:17 -07:00
private readonly messageBus : MessageBus ;
private readonly policyEngine : PolicyEngine ;
2026-02-19 16:16:03 -08:00
private policyUpdateConfirmationRequest :
| PolicyUpdateConfirmationRequest
| undefined ;
2025-09-11 05:19:47 +09:00
private readonly outputSettings : OutputSettings ;
2025-10-09 18:04:08 -04:00
private readonly continueOnFailedApiCall : boolean ;
2025-10-14 09:17:31 -07:00
private readonly retryFetchErrors : boolean ;
2026-02-23 15:57:16 -08:00
private readonly maxAttempts : number ;
2025-10-13 21:31:45 -07:00
private readonly enableShellOutputEfficiency : boolean ;
2025-11-26 13:43:33 -08:00
private readonly shellToolInactivityTimeout : number ;
2025-10-23 16:10:43 -07:00
readonly fakeResponses? : string ;
2025-10-28 12:13:45 -07:00
readonly recordResponses? : string ;
2025-10-22 11:57:10 -07:00
private readonly disableYoloMode : boolean ;
2026-01-20 23:58:37 -05:00
private readonly rawOutput : boolean ;
private readonly acceptRawOutputRisk : boolean ;
2025-11-14 19:06:30 -08:00
private pendingIncludeDirectories : string [ ] ;
2025-11-02 11:49:16 -08:00
private readonly enableHooks : boolean ;
2026-01-07 12:34:33 -08:00
private readonly enableHooksUI : boolean ;
2026-02-05 20:53:11 -05:00
private readonly toolOutputMasking : ToolOutputMaskingConfig ;
2026-01-16 19:28:36 -05:00
private hooks : { [ K in HookEventName ] ? : HookDefinition [ ] } | undefined ;
private projectHooks :
2025-12-23 16:10:46 -05:00
| ( { [ K in HookEventName ] ? : HookDefinition [ ] } & { disabled? : string [ ] } )
| undefined ;
2026-01-16 19:28:36 -05:00
private disabledHooks : string [ ] ;
2025-11-04 15:09:53 -08:00
private experiments : Experiments | undefined ;
private experimentsPromise : Promise < void > | undefined ;
2025-11-24 14:31:48 -08:00
private hookSystem? : HookSystem ;
2025-12-23 19:53:43 +05:30
private readonly onModelChange : ( ( model : string ) = > void ) | undefined ;
2026-01-05 15:12:51 -08:00
private readonly onReload :
2026-01-13 23:40:23 -08:00
| ( ( ) = > Promise < {
disabledSkills? : string [ ] ;
adminSkillsEnabled? : boolean ;
2026-01-14 19:30:17 -05:00
agents? : AgentSettings ;
2026-01-13 23:40:23 -08:00
} > )
2026-01-05 15:12:51 -08:00
| undefined ;
2025-05-29 20:51:17 +00:00
2025-12-03 12:53:06 -08:00
private readonly enableAgents : boolean ;
2026-01-14 19:30:17 -05:00
private agents : AgentSettings ;
2026-01-19 22:59:30 -05:00
private readonly enableEventDrivenScheduler : boolean ;
2025-12-30 13:35:52 -08:00
private readonly skillsSupport : boolean ;
2026-01-05 15:12:51 -08:00
private disabledSkills : string [ ] ;
2026-01-13 23:40:23 -08:00
private readonly adminSkillsEnabled : boolean ;
2025-11-18 12:01:16 -05:00
2025-12-03 04:09:46 +08:00
private readonly experimentalJitContext : boolean ;
2026-01-13 09:26:53 +08:00
private readonly disableLLMCorrection : boolean ;
2026-01-14 19:55:10 -05:00
private readonly planEnabled : boolean ;
2026-02-24 19:15:14 -05:00
private readonly planModeRoutingEnabled : boolean ;
2026-02-18 14:05:50 -08:00
private readonly modelSteering : boolean ;
2025-12-03 04:09:46 +08:00
private contextManager? : ContextManager ;
2025-12-18 10:36:48 -08:00
private terminalBackground : string | undefined = undefined ;
2026-02-03 16:19:14 -05:00
private remoteAdminSettings : AdminControlsSettings | undefined ;
2026-01-11 14:11:06 -05:00
private latestApiRequest : GenerateContentParameters | undefined ;
2026-02-21 19:32:57 -05:00
private lastModeSwitchTime : number = performance . now ( ) ;
2026-02-18 14:05:50 -08:00
readonly userHintService : UserHintService ;
2026-02-04 12:01:43 -05:00
private approvedPlanPath : string | undefined ;
2025-05-29 20:51:17 +00:00
constructor ( params : ConfigParameters ) {
2025-06-11 04:46:39 +00:00
this . sessionId = params . sessionId ;
2026-01-20 22:01:18 +00:00
this . clientVersion = params . clientVersion ? ? 'unknown' ;
2026-02-04 12:01:43 -05:00
this . approvedPlanPath = undefined ;
2025-06-13 01:25:42 -07:00
this . embeddingModel =
params . embeddingModel ? ? DEFAULT_GEMINI_EMBEDDING_MODEL ;
2025-08-18 16:29:45 -06:00
this . fileSystemService = new StandardFileSystemService ( ) ;
2025-05-29 20:51:17 +00:00
this . sandbox = params . sandbox ;
this . targetDir = path . resolve ( params . targetDir ) ;
2025-11-14 19:06:30 -08:00
this . folderTrust = params . folderTrust ? ? false ;
this . workspaceContext = new WorkspaceContext ( this . targetDir , [ ] ) ;
this . pendingIncludeDirectories = params . includeDirectories ? ? [ ] ;
2025-05-29 20:51:17 +00:00
this . debugMode = params . debugMode ;
this . question = params . question ;
2025-10-16 12:09:21 -07:00
2025-05-29 20:51:17 +00:00
this . coreTools = params . coreTools ;
2025-08-27 02:17:43 +10:00
this . allowedTools = params . allowedTools ;
2025-06-11 14:32:23 -07:00
this . excludeTools = params . excludeTools ;
2025-05-29 20:51:17 +00:00
this . toolDiscoveryCommand = params . toolDiscoveryCommand ;
this . toolCallCommand = params . toolCallCommand ;
this . mcpServerCommand = params . mcpServerCommand ;
this . mcpServers = params . mcpServers ;
2026-01-22 15:38:06 -08:00
this . mcpEnablementCallbacks = params . mcpEnablementCallbacks ;
2026-01-06 16:38:07 -05:00
this . mcpEnabled = params . mcpEnabled ? ? true ;
2026-01-08 12:59:30 -05:00
this . extensionsEnabled = params . extensionsEnabled ? ? true ;
2025-11-04 07:51:18 -08:00
this . allowedMcpServers = params . allowedMcpServers ? ? [ ] ;
this . blockedMcpServers = params . blockedMcpServers ? ? [ ] ;
2025-12-22 19:18:27 -08:00
this . allowedEnvironmentVariables = params . allowedEnvironmentVariables ? ? [ ] ;
this . blockedEnvironmentVariables = params . blockedEnvironmentVariables ? ? [ ] ;
this . enableEnvironmentVariableRedaction =
params . enableEnvironmentVariableRedaction ? ? false ;
2025-05-29 20:51:17 +00:00
this . userMemory = params . userMemory ? ? '' ;
this . geminiMdFileCount = params . geminiMdFileCount ? ? 0 ;
2025-10-02 17:46:54 -04:00
this . geminiMdFilePaths = params . geminiMdFilePaths ? ? [ ] ;
2025-05-30 22:18:01 +00:00
this . showMemoryUsage = params . showMemoryUsage ? ? false ;
2025-06-04 00:46:57 -07:00
this . accessibility = params . accessibility ? ? { } ;
2025-06-15 00:47:32 -04:00
this . telemetrySettings = {
enabled : params.telemetry?.enabled ? ? false ,
target : params.telemetry?.target ? ? DEFAULT_TELEMETRY_TARGET ,
otlpEndpoint : params.telemetry?.otlpEndpoint ? ? DEFAULT_OTLP_ENDPOINT ,
2025-08-15 18:10:21 -07:00
otlpProtocol : params.telemetry?.otlpProtocol ,
2025-06-15 00:47:32 -04:00
logPrompts : params.telemetry?.logPrompts ? ? true ,
2025-07-23 17:48:24 -04:00
outfile : params.telemetry?.outfile ,
2025-09-17 04:13:57 +09:00
useCollector : params.telemetry?.useCollector ,
2025-12-02 21:27:37 -08:00
useCliAuth : params.telemetry?.useCliAuth ,
2025-06-15 00:47:32 -04:00
} ;
2025-06-23 20:29:31 -04:00
this . usageStatisticsEnabled = params . usageStatisticsEnabled ? ? true ;
2025-06-15 00:47:32 -04:00
2025-06-21 18:23:35 -07:00
this . fileFiltering = {
2025-10-10 12:04:15 -04:00
respectGitIgnore :
params.fileFiltering?.respectGitIgnore ? ?
DEFAULT_FILE_FILTERING_OPTIONS . respectGitIgnore ,
respectGeminiIgnore :
params.fileFiltering?.respectGeminiIgnore ? ?
DEFAULT_FILE_FILTERING_OPTIONS . respectGeminiIgnore ,
2025-06-21 18:23:35 -07:00
enableRecursiveFileSearch :
params.fileFiltering?.enableRecursiveFileSearch ? ? true ,
2026-01-16 23:33:49 +01:00
enableFuzzySearch : params.fileFiltering?.enableFuzzySearch ? ? true ,
2026-01-15 12:04:22 -08:00
maxFileCount :
params.fileFiltering?.maxFileCount ? ?
DEFAULT_FILE_FILTERING_OPTIONS . maxFileCount ? ?
20000 ,
searchTimeout :
params.fileFiltering?.searchTimeout ? ?
DEFAULT_FILE_FILTERING_OPTIONS . searchTimeout ? ?
5000 ,
2026-01-27 17:19:13 -08:00
customIgnoreFilePaths : params.fileFiltering?.customIgnoreFilePaths ? ? [ ] ,
2025-06-21 18:23:35 -07:00
} ;
2025-06-20 00:39:15 -04:00
this . checkpointing = params . checkpointing ? ? false ;
2025-06-12 17:17:29 -07:00
this . proxy = params . proxy ;
this . cwd = params . cwd ? ? process . cwd ( ) ;
2025-06-13 20:25:59 -04:00
this . fileDiscoveryService = params . fileDiscoveryService ? ? null ;
2025-06-14 00:00:24 -07:00
this . bugCommand = params . bugCommand ;
2025-09-12 15:57:07 -04:00
this . model = params . model ;
2026-02-02 10:13:20 -08:00
this . disableLoopDetection = params . disableLoopDetection ? ? false ;
2025-12-08 06:44:34 -08:00
this . _activeModel = params . model ;
2025-12-03 12:53:06 -08:00
this . enableAgents = params . enableAgents ? ? false ;
2026-01-13 12:16:02 -08:00
this . agents = params . agents ? ? { } ;
2026-01-21 10:53:41 -08:00
this . disableLLMCorrection = params . disableLLMCorrection ? ? true ;
2026-01-14 19:55:10 -05:00
this . planEnabled = params . plan ? ? false ;
2026-02-24 19:15:14 -05:00
this . planModeRoutingEnabled = params . planSettings ? . modelRouting ? ? true ;
2026-01-21 17:40:19 -05:00
this . enableEventDrivenScheduler = params . enableEventDrivenScheduler ? ? true ;
2026-01-27 19:09:52 -05:00
this . skillsSupport = params . skillsSupport ? ? true ;
2025-12-30 13:35:52 -08:00
this . disabledSkills = params . disabledSkills ? ? [ ] ;
2026-01-13 23:40:23 -08:00
this . adminSkillsEnabled = params . adminSkillsEnabled ? ? true ;
2025-11-26 12:36:42 -08:00
this . modelAvailabilityService = new ModelAvailabilityService ( ) ;
2025-12-30 13:35:52 -08:00
this . experimentalJitContext = params . experimentalJitContext ? ? false ;
2026-02-18 14:05:50 -08:00
this . modelSteering = params . modelSteering ? ? false ;
this . userHintService = new UserHintService ( ( ) = >
this . isModelSteeringEnabled ( ) ,
) ;
2026-02-05 20:53:11 -05:00
this . toolOutputMasking = {
2026-02-11 01:21:55 -05:00
enabled : params.toolOutputMasking?.enabled ? ? true ,
2026-02-05 20:53:11 -05:00
toolProtectionThreshold :
params.toolOutputMasking?.toolProtectionThreshold ? ?
DEFAULT_TOOL_PROTECTION_THRESHOLD ,
minPrunableTokensThreshold :
params.toolOutputMasking?.minPrunableTokensThreshold ? ?
DEFAULT_MIN_PRUNABLE_TOKENS_THRESHOLD ,
protectLatestTurn :
params.toolOutputMasking?.protectLatestTurn ? ?
DEFAULT_PROTECT_LATEST_TURN ,
} ;
2025-07-11 07:55:03 -07:00
this . maxSessionTurns = params . maxSessionTurns ? ? - 1 ;
2025-08-13 12:58:26 -03:00
this . experimentalZedIntegration =
params . experimentalZedIntegration ? ? false ;
2025-11-10 18:31:00 -07:00
this . listSessions = params . listSessions ? ? false ;
this . deleteSession = params . deleteSession ;
2025-07-08 12:57:34 -04:00
this . listExtensions = params . listExtensions ? ? false ;
2025-10-28 09:04:30 -07:00
this . _extensionLoader =
params . extensionLoader ? ? new SimpleExtensionLoader ( [ ] ) ;
2025-10-20 16:15:23 -07:00
this . _enabledExtensions = params . enabledExtensions ? ? [ ] ;
2025-07-10 18:59:02 -07:00
this . noBrowser = params . noBrowser ? ? false ;
2025-07-15 10:22:31 -07:00
this . summarizeToolOutput = params . summarizeToolOutput ;
2025-08-07 14:06:17 -07:00
this . folderTrust = params . folderTrust ? ? false ;
2025-08-04 17:06:50 -04:00
this . ideMode = params . ideMode ? ? false ;
2026-02-17 11:19:26 -08:00
this . includeDirectoryTree = params . includeDirectoryTree ? ? true ;
2025-08-06 02:01:01 +09:00
this . loadMemoryFromIncludeDirectories =
params . loadMemoryFromIncludeDirectories ? ? false ;
2025-11-07 09:07:25 -08:00
this . importFormat = params . importFormat ? ? 'tree' ;
this . discoveryMaxDirs = params . discoveryMaxDirs ? ? 200 ;
2025-10-30 16:03:58 -07:00
this . compressionThreshold = params . compressionThreshold ;
2025-08-07 14:19:06 -07:00
this . interactive = params . interactive ? ? false ;
2025-10-17 09:07:18 -07:00
this . ptyInfo = params . ptyInfo ? ? 'child_process' ;
2025-08-13 11:06:31 -07:00
this . trustedFolder = params . trustedFolder ;
2026-02-23 11:50:14 -08:00
this . directWebFetch = params . directWebFetch ? ? false ;
2025-09-11 16:46:07 -07:00
this . useRipgrep = params . useRipgrep ? ? true ;
2026-01-26 15:23:54 -08:00
this . useBackgroundColor = params . useBackgroundColor ? ? true ;
2025-10-08 13:28:19 -07:00
this . enableInteractiveShell = params . enableInteractiveShell ? ? false ;
2025-09-11 14:11:06 -07:00
this . skipNextSpeakerCheck = params . skipNextSpeakerCheck ? ? true ;
2025-09-11 13:27:27 -07:00
this . shellExecutionConfig = {
terminalWidth : params.shellExecutionConfig?.terminalWidth ? ? 80 ,
terminalHeight : params.shellExecutionConfig?.terminalHeight ? ? 24 ,
showColor : params.shellExecutionConfig?.showColor ? ? false ,
pager : params.shellExecutionConfig?.pager ? ? 'cat' ,
2025-12-22 19:18:27 -08:00
sanitizationConfig : this.sanitizationConfig ,
2025-09-11 13:27:27 -07:00
} ;
2025-09-05 15:37:29 -07:00
this . truncateToolOutputThreshold =
params . truncateToolOutputThreshold ? ?
DEFAULT_TRUNCATE_TOOL_OUTPUT_THRESHOLD ;
2025-12-17 09:43:21 -08:00
// // TODO(joshualitt): Re-evaluate the todo tool for 3 family.
this . useWriteTodos = isPreviewModel ( this . model )
? false
: ( params . useWriteTodos ? ? true ) ;
2026-01-07 12:34:33 -08:00
this . enableHooksUI = params . enableHooksUI ? ? true ;
2026-01-21 17:40:31 -05:00
this . enableHooks = params . enableHooks ? ? true ;
2026-01-20 14:47:31 -08:00
this . disabledHooks = params . disabledHooks ? ? [ ] ;
2025-11-02 11:49:16 -08:00
2025-10-09 18:04:08 -04:00
this . continueOnFailedApiCall = params . continueOnFailedApiCall ? ? true ;
2025-10-13 21:31:45 -07:00
this . enableShellOutputEfficiency =
params . enableShellOutputEfficiency ? ? true ;
2025-11-26 13:43:33 -08:00
this . shellToolInactivityTimeout =
( params . shellToolInactivityTimeout ? ? 300 ) * 1000 ; // 5 minutes
2025-09-05 11:44:41 -07:00
this . extensionManagement = params . extensionManagement ? ? true ;
2025-10-30 11:05:49 -07:00
this . enableExtensionReloading = params . enableExtensionReloading ? ? false ;
2026-02-12 14:02:59 -05:00
this . storage = new Storage ( this . targetDir , this . sessionId ) ;
2026-02-19 17:47:08 -05:00
this . storage . setCustomPlansDir ( params . planSettings ? . directory ) ;
2026-01-26 16:57:27 -05:00
2025-10-23 16:10:43 -07:00
this . fakeResponses = params . fakeResponses ;
2025-10-28 12:13:45 -07:00
this . recordResponses = params . recordResponses ;
2025-08-23 13:35:00 +09:00
this . fileExclusions = new FileExclusions ( this ) ;
2025-08-28 21:53:56 +02:00
this . eventEmitter = params . eventEmitter ;
2026-02-23 18:44:28 -08:00
this . enableConseca = params . enableConseca ? ? false ;
// Initialize Safety Infrastructure
const contextBuilder = new ContextBuilder ( this ) ;
const checkersPath = this . targetDir ;
// The checkersPath is used to resolve external checkers. Since we do not have any external checkers currently, it is set to the targetDir.
const checkerRegistry = new CheckerRegistry ( checkersPath ) ;
const checkerRunner = new CheckerRunner ( contextBuilder , checkerRegistry , {
checkersPath ,
timeout : 30000 , // 30 seconds to allow for LLM-based checkers
2025-12-22 15:25:07 -05:00
} ) ;
2026-02-19 16:16:03 -08:00
this . policyUpdateConfirmationRequest =
params . policyUpdateConfirmationRequest ;
2026-02-23 18:44:28 -08:00
this . policyEngine = new PolicyEngine (
{
. . . params . policyEngineConfig ,
approvalMode :
params.approvalMode ? ? params . policyEngineConfig ? . approvalMode ,
} ,
checkerRunner ,
) ;
// Register Conseca if enabled
if ( this . enableConseca ) {
debugLogger . log ( '[SAFETY] Registering Conseca Safety Checker' ) ;
ConsecaSafetyChecker . getInstance ( ) . setConfig ( this ) ;
}
2025-10-21 11:45:33 -07:00
this . messageBus = new MessageBus ( this . policyEngine , this . debugMode ) ;
2026-01-26 19:49:32 +00:00
this . acknowledgedAgentsService = new AcknowledgedAgentsService ( ) ;
2025-12-30 13:35:52 -08:00
this . skillManager = new SkillManager ( ) ;
2025-09-11 05:19:47 +09:00
this . outputSettings = {
format : params.output?.format ? ? OutputFormat . TEXT ,
} ;
2025-10-14 09:17:31 -07:00
this . retryFetchErrors = params . retryFetchErrors ? ? false ;
2026-02-23 15:57:16 -08:00
this . maxAttempts = Math . min (
params . maxAttempts ? ? DEFAULT_MAX_ATTEMPTS ,
DEFAULT_MAX_ATTEMPTS ,
) ;
2025-10-22 11:57:10 -07:00
this . disableYoloMode = params . disableYoloMode ? ? false ;
2026-01-20 23:58:37 -05:00
this . rawOutput = params . rawOutput ? ? false ;
this . acceptRawOutputRisk = params . acceptRawOutputRisk ? ? false ;
2026-01-16 19:28:36 -05:00
if ( params . hooks ) {
2026-01-20 14:47:31 -08:00
this . hooks = params . hooks ;
2026-01-16 19:28:36 -05:00
}
if ( params . projectHooks ) {
this . projectHooks = params . projectHooks ;
}
2025-11-04 15:09:53 -08:00
this . experiments = params . experiments ;
2025-12-23 19:53:43 +05:30
this . onModelChange = params . onModelChange ;
2026-01-05 15:12:51 -08:00
this . onReload = params . onReload ;
2025-04-19 19:45:42 +01:00
2025-05-31 12:49:28 -07:00
if ( params . contextFileName ) {
setGeminiMdFilename ( params . contextFileName ) ;
}
2025-06-15 00:47:32 -04:00
if ( this . telemetrySettings . enabled ) {
2025-12-05 16:12:49 -08:00
// eslint-disable-next-line @typescript-eslint/no-floating-promises
2025-06-05 16:04:25 -04:00
initializeTelemetry ( this ) ;
}
2025-09-07 13:00:03 -07:00
2025-11-03 10:13:52 -08:00
const proxy = this . getProxy ( ) ;
if ( proxy ) {
try {
setGlobalProxy ( proxy ) ;
} catch ( error ) {
coreEvents . emitFeedback (
'error' ,
'Invalid proxy configuration detected. Check debug drawer for more details (F12)' ,
error ,
) ;
}
2025-09-07 13:00:03 -07:00
}
this . geminiClient = new GeminiClient ( this ) ;
2025-09-11 13:38:50 -04:00
this . modelRouterService = new ModelRouterService ( this ) ;
2025-11-05 17:18:42 -08:00
// HACK: The settings loading logic doesn't currently merge the default
// generation config with the user's settings. This means if a user provides
// any `generation` settings (e.g., just `overrides`), the default `aliases`
// are lost. This hack manually merges the default aliases back in if they
// are missing from the user's config.
// TODO(12593): Fix the settings loading logic to properly merge defaults and
// remove this hack.
let modelConfigServiceConfig = params . modelConfigServiceConfig ;
2025-12-10 09:36:27 -08:00
if ( modelConfigServiceConfig ) {
if ( ! modelConfigServiceConfig . aliases ) {
modelConfigServiceConfig = {
. . . modelConfigServiceConfig ,
aliases : DEFAULT_MODEL_CONFIGS.aliases ,
} ;
}
if ( ! modelConfigServiceConfig . overrides ) {
modelConfigServiceConfig = {
. . . modelConfigServiceConfig ,
overrides : DEFAULT_MODEL_CONFIGS.overrides ,
} ;
}
2025-11-05 17:18:42 -08:00
}
this . modelConfigService = new ModelConfigService (
modelConfigServiceConfig ? ? DEFAULT_MODEL_CONFIGS ,
) ;
2025-04-19 19:45:42 +01:00
}
2026-02-11 09:29:18 -08:00
isInitialized ( ) : boolean {
return this . initialized ;
}
2025-08-07 14:19:06 -07:00
/**
2026-02-17 14:59:33 -08:00
* Dedups initialization requests using a shared promise that is only resolved
* once.
2025-08-07 14:19:06 -07:00
*/
2025-07-07 15:01:59 -07:00
async initialize ( ) : Promise < void > {
2026-02-17 14:59:33 -08:00
if ( this . initPromise ) {
return this . initPromise ;
2025-08-07 14:19:06 -07:00
}
2025-09-04 09:32:09 -07:00
2026-02-17 14:59:33 -08:00
this . initPromise = this . _initialize ( ) ;
return this . initPromise ;
}
private async _initialize ( ) : Promise < void > {
2026-02-06 08:10:17 -08:00
await this . storage . initialize ( ) ;
2026-01-21 09:58:23 -08:00
// Add pending directories to workspace context
for ( const dir of this . pendingIncludeDirectories ) {
this . workspaceContext . addDirectory ( dir ) ;
}
2026-01-26 16:57:27 -05:00
// Add plans directory to workspace context for plan file storage
if ( this . planEnabled ) {
2026-02-19 17:47:08 -05:00
const plansDir = this . storage . getPlansDir ( ) ;
2026-01-26 16:57:27 -05:00
await fs . promises . mkdir ( plansDir , { recursive : true } ) ;
this . workspaceContext . addDirectory ( plansDir ) ;
}
2025-07-07 15:01:59 -07:00
// Initialize centralized FileDiscoveryService
2025-12-01 10:06:13 -08:00
const discoverToolsHandle = startupProfiler . start ( 'discover_tools' ) ;
2025-07-07 15:01:59 -07:00
this . getFileService ( ) ;
if ( this . getCheckpointingEnabled ( ) ) {
2025-07-14 13:23:51 -04:00
await this . getGitService ( ) ;
2025-07-07 15:01:59 -07:00
}
2025-07-25 20:56:33 +00:00
this . promptRegistry = new PromptRegistry ( ) ;
2025-12-09 03:43:12 +01:00
this . resourceRegistry = new ResourceRegistry ( ) ;
2025-10-01 16:54:00 -04:00
this . agentRegistry = new AgentRegistry ( this ) ;
await this . agentRegistry . initialize ( ) ;
2026-01-12 12:11:24 -05:00
coreEvents . on ( CoreEvent . AgentsRefreshed , this . onAgentsRefreshed ) ;
2025-07-07 15:01:59 -07:00
this . toolRegistry = await this . createToolRegistry ( ) ;
2025-12-01 10:06:13 -08:00
discoverToolsHandle ? . end ( ) ;
2025-11-04 07:51:18 -08:00
this . mcpClientManager = new McpClientManager (
2026-01-20 22:01:18 +00:00
this . clientVersion ,
2025-11-04 07:51:18 -08:00
this . toolRegistry ,
this ,
this . eventEmitter ,
) ;
2026-01-15 15:33:16 -05:00
// We do not await this promise so that the CLI can start up even if
// MCP servers are slow to connect.
2026-01-23 22:51:47 +05:30
const mcpInitialization = Promise . allSettled ( [
2026-01-15 15:33:16 -05:00
this . mcpClientManager . startConfiguredMcpServers ( ) ,
this . getExtensionLoader ( ) . start ( this ) ,
2026-01-23 22:51:47 +05:30
] ) . then ( ( results ) = > {
for ( const result of results ) {
if ( result . status === 'rejected' ) {
debugLogger . error ( 'Error initializing MCP clients:' , result . reason ) ;
}
}
2026-01-15 15:33:16 -05:00
} ) ;
2025-09-07 13:00:03 -07:00
2026-02-17 20:39:14 +01:00
if ( ! this . interactive || this . experimentalZedIntegration ) {
2026-01-23 22:51:47 +05:30
await mcpInitialization ;
}
2025-12-30 13:35:52 -08:00
if ( this . skillsSupport ) {
2026-01-13 23:40:23 -08:00
this . getSkillManager ( ) . setAdminSettings ( this . adminSkillsEnabled ) ;
if ( this . adminSkillsEnabled ) {
await this . getSkillManager ( ) . discoverSkills (
this . storage ,
this . getExtensions ( ) ,
2026-02-03 14:53:31 -08:00
this . isTrustedFolder ( ) ,
2026-01-02 11:15:06 -08:00
) ;
2026-01-13 23:40:23 -08:00
this . getSkillManager ( ) . setDisabledSkills ( this . disabledSkills ) ;
// Re-register ActivateSkillTool to update its schema with the discovered enabled skill enums
if ( this . getSkillManager ( ) . getSkills ( ) . length > 0 ) {
this . getToolRegistry ( ) . unregisterTool ( ActivateSkillTool . Name ) ;
this . getToolRegistry ( ) . registerTool (
new ActivateSkillTool ( this , this . messageBus ) ,
) ;
}
2026-01-02 11:15:06 -08:00
}
2025-12-30 13:35:52 -08:00
}
2025-11-24 14:31:48 -08:00
// Initialize hook system if enabled
2026-01-06 13:33:37 -08:00
if ( this . getEnableHooks ( ) ) {
2025-11-24 14:31:48 -08:00
this . hookSystem = new HookSystem ( this ) ;
await this . hookSystem . initialize ( ) ;
}
2025-12-03 04:09:46 +08:00
if ( this . experimentalJitContext ) {
this . contextManager = new ContextManager ( this ) ;
2025-12-19 07:04:03 -10:00
await this . contextManager . refresh ( ) ;
2025-12-03 04:09:46 +08:00
}
2025-09-07 13:00:03 -07:00
await this . geminiClient . initialize ( ) ;
2026-02-05 15:04:03 -05:00
this . syncPlanModeTools ( ) ;
2026-02-17 14:59:33 -08:00
this . initialized = true ;
2025-09-07 13:00:03 -07:00
}
getContentGenerator ( ) : ContentGenerator {
return this . contentGenerator ;
2025-07-07 15:01:59 -07:00
}
2025-06-24 18:48:55 -04:00
2026-02-25 10:04:42 -05:00
async refreshAuth ( authMethod : AuthType , apiKey? : string ) {
2025-12-10 13:53:12 -08:00
// Reset availability service when switching auth
this . modelAvailabilityService . reset ( ) ;
2025-09-07 13:00:03 -07:00
// Vertex and Genai have incompatible encryption and sending history with
2025-10-20 16:15:23 -07:00
// thoughtSignature from Genai to Vertex will fail, we need to strip them
2025-09-07 13:00:03 -07:00
if (
this . contentGeneratorConfig ? . authType === AuthType . USE_GEMINI &&
2025-11-18 12:01:16 -05:00
authMethod !== AuthType . USE_GEMINI
2025-09-07 13:00:03 -07:00
) {
// Restore the conversation history to the new client
this . geminiClient . stripThoughtsFromHistory ( ) ;
2025-08-04 03:33:01 +05:30
}
2025-12-17 09:43:21 -08:00
// Reset availability status when switching auth (e.g. from limited key to OAuth)
this . modelAvailabilityService . reset ( ) ;
2026-02-20 14:19:21 -05:00
// Clear stale authType to ensure getGemini31LaunchedSync doesn't return stale results
// during the transition.
if ( this . contentGeneratorConfig ) {
this . contentGeneratorConfig . authType = undefined ;
}
2025-10-29 18:58:08 -07:00
const newContentGeneratorConfig = await createContentGeneratorConfig (
2025-07-15 21:13:30 -07:00
this ,
2025-06-19 16:52:22 -07:00
authMethod ,
2026-02-25 10:04:42 -05:00
apiKey ,
2025-06-19 16:52:22 -07:00
) ;
2025-09-07 13:00:03 -07:00
this . contentGenerator = await createContentGenerator (
newContentGeneratorConfig ,
this ,
this . getSessionId ( ) ,
) ;
2025-08-04 03:33:01 +05:30
// Only assign to instance properties after successful initialization
this . contentGeneratorConfig = newContentGeneratorConfig ;
2025-06-24 18:48:55 -04:00
2025-09-09 01:14:15 -04:00
// Initialize BaseLlmClient now that the ContentGenerator is available
this . baseLlmClient = new BaseLlmClient ( this . contentGenerator , this ) ;
2025-11-04 15:09:53 -08:00
const codeAssistServer = getCodeAssistServer ( this ) ;
2026-01-09 10:47:05 -08:00
if ( codeAssistServer ? . projectId ) {
await this . refreshUserQuota ( ) ;
}
this . experimentsPromise = getExperiments ( codeAssistServer )
. then ( ( experiments ) = > {
this . setExperiments ( experiments ) ;
} )
. catch ( ( e ) = > {
debugLogger . error ( 'Failed to fetch experiments' , e ) ;
} ) ;
2025-11-04 15:09:53 -08:00
2025-12-17 09:43:21 -08:00
const authType = this . contentGeneratorConfig . authType ;
if (
authType === AuthType . USE_GEMINI ||
authType === AuthType . USE_VERTEX_AI
) {
this . setHasAccessToPreviewModel ( true ) ;
}
2026-02-23 09:14:00 +05:30
// Only reset when we have explicit "no access" (hasAccessToPreviewModel === false).
// When null (quota not fetched) or true, we preserve the saved model.
if ( isPreviewModel ( this . model ) && this . hasAccessToPreviewModel === false ) {
2025-12-17 09:43:21 -08:00
this . setModel ( DEFAULT_GEMINI_MODEL_AUTO ) ;
}
2026-01-16 15:24:53 -05:00
// Fetch admin controls
await this . ensureExperimentsLoaded ( ) ;
const adminControlsEnabled =
this . experiments ? . flags [ ExperimentFlags . ENABLE_ADMIN_CONTROLS ]
? . boolValue ? ? false ;
const adminControls = await fetchAdminControls (
codeAssistServer ,
this . getRemoteAdminSettings ( ) ,
adminControlsEnabled ,
2026-02-03 16:19:14 -05:00
( newSettings : AdminControlsSettings ) = > {
2026-01-16 15:24:53 -05:00
this . setRemoteAdminSettings ( newSettings ) ;
coreEvents . emitAdminSettingsChanged ( ) ;
} ,
) ;
this . setRemoteAdminSettings ( adminControls ) ;
2025-06-19 16:52:22 -07:00
}
2025-11-21 14:44:50 -06:00
async getExperimentsAsync ( ) : Promise < Experiments | undefined > {
if ( this . experiments ) {
return this . experiments ;
}
const codeAssistServer = getCodeAssistServer ( this ) ;
2026-01-09 10:47:05 -08:00
return getExperiments ( codeAssistServer ) ;
2025-11-21 14:44:50 -06:00
}
2025-09-07 13:00:03 -07:00
getUserTier ( ) : UserTierId | undefined {
return this . contentGenerator ? . userTier ;
}
2026-01-23 16:03:53 -05:00
getUserTierName ( ) : string | undefined {
2026-02-03 22:28:58 -05:00
return this . contentGenerator ? . userTierName ;
2026-01-23 16:03:53 -05:00
}
2025-09-09 01:14:15 -04:00
/**
* Provides access to the BaseLlmClient for stateless LLM operations.
*/
getBaseLlmClient ( ) : BaseLlmClient {
if ( ! this . baseLlmClient ) {
// Handle cases where initialization might be deferred or authentication failed
if ( this . contentGenerator ) {
this . baseLlmClient = new BaseLlmClient (
this . getContentGenerator ( ) ,
this ,
) ;
} else {
throw new Error (
'BaseLlmClient not initialized. Ensure authentication has occurred and ContentGenerator is ready.' ,
) ;
}
}
return this . baseLlmClient ;
}
2025-06-11 04:46:39 +00:00
getSessionId ( ) : string {
return this . sessionId ;
}
2025-11-10 18:31:00 -07:00
setSessionId ( sessionId : string ) : void {
this . sessionId = sessionId ;
}
2025-12-18 10:36:48 -08:00
setTerminalBackground ( terminalBackground : string | undefined ) : void {
this . terminalBackground = terminalBackground ;
}
getTerminalBackground ( ) : string | undefined {
return this . terminalBackground ;
}
2026-01-11 14:11:06 -05:00
getLatestApiRequest ( ) : GenerateContentParameters | undefined {
return this . latestApiRequest ;
}
setLatestApiRequest ( req : GenerateContentParameters ) : void {
this . latestApiRequest = req ;
}
2026-02-03 16:19:14 -05:00
getRemoteAdminSettings ( ) : AdminControlsSettings | undefined {
2026-01-06 16:38:07 -05:00
return this . remoteAdminSettings ;
}
2026-02-18 17:54:07 -05:00
setRemoteAdminSettings ( settings : AdminControlsSettings | undefined ) : void {
2026-01-06 16:38:07 -05:00
this . remoteAdminSettings = settings ;
}
2025-08-06 02:01:01 +09:00
shouldLoadMemoryFromIncludeDirectories ( ) : boolean {
return this . loadMemoryFromIncludeDirectories ;
}
2026-02-17 11:19:26 -08:00
getIncludeDirectoryTree ( ) : boolean {
return this . includeDirectoryTree ;
}
2025-11-07 09:07:25 -08:00
getImportFormat ( ) : 'tree' | 'flat' {
return this . importFormat ;
}
getDiscoveryMaxDirs ( ) : number {
return this . discoveryMaxDirs ;
}
2025-06-07 16:17:27 -07:00
getContentGeneratorConfig ( ) : ContentGeneratorConfig {
return this . contentGeneratorConfig ;
2025-04-19 19:45:42 +01:00
}
getModel ( ) : string {
2025-09-11 13:38:50 -04:00
return this . model ;
2025-04-19 19:45:42 +01:00
}
2026-02-02 10:13:20 -08:00
getDisableLoopDetection ( ) : boolean {
return this . disableLoopDetection ? ? false ;
}
2026-01-05 15:31:13 -05:00
setModel ( newModel : string , isTemporary : boolean = true ) : void {
2025-12-17 17:14:33 -05:00
if ( this . model !== newModel || this . _activeModel !== newModel ) {
2025-11-03 14:59:51 -05:00
this . model = newModel ;
2025-12-08 06:44:34 -08:00
// When the user explicitly sets a model, that becomes the active model.
this . _activeModel = newModel ;
2025-11-03 14:59:51 -05:00
coreEvents . emitModelChanged ( newModel ) ;
2026-01-05 15:31:13 -05:00
if ( this . onModelChange && ! isTemporary ) {
2025-12-23 19:53:43 +05:30
this . onModelChange ( newModel ) ;
}
2025-11-03 14:59:51 -05:00
}
2025-12-10 13:53:12 -08:00
this . modelAvailabilityService . reset ( ) ;
2025-06-24 18:48:55 -04:00
}
2026-01-02 13:19:43 -05:00
activateFallbackMode ( model : string ) : void {
2026-01-12 12:23:06 -05:00
this . setModel ( model , true ) ;
2026-01-02 13:19:43 -05:00
const authType = this . getContentGeneratorConfig ( ) ? . authType ;
if ( authType ) {
logFlashFallback ( this , new FlashFallbackEvent ( authType ) ) ;
}
}
2025-12-08 06:44:34 -08:00
getActiveModel ( ) : string {
return this . _activeModel ? ? this . model ;
}
setActiveModel ( model : string ) : void {
if ( this . _activeModel !== model ) {
this . _activeModel = model ;
}
}
2025-09-08 16:19:52 -04:00
setFallbackModelHandler ( handler : FallbackModelHandler ) : void {
this . fallbackModelHandler = handler ;
2025-06-24 18:48:55 -04:00
}
2025-11-18 12:01:16 -05:00
getFallbackModelHandler ( ) : FallbackModelHandler | undefined {
return this . fallbackModelHandler ;
}
2026-01-20 16:23:01 -08:00
setValidationHandler ( handler : ValidationHandler ) : void {
this . validationHandler = handler ;
}
getValidationHandler ( ) : ValidationHandler | undefined {
return this . validationHandler ;
}
2025-12-17 17:14:33 -05:00
resetTurn ( ) : void {
this . modelAvailabilityService . resetTurn ( ) ;
2025-11-18 12:01:16 -05:00
}
2025-07-11 07:55:03 -07:00
getMaxSessionTurns ( ) : number {
return this . maxSessionTurns ;
}
2025-07-09 13:55:56 -04:00
setQuotaErrorOccurred ( value : boolean ) : void {
this . quotaErrorOccurred = value ;
}
getQuotaErrorOccurred ( ) : boolean {
return this . quotaErrorOccurred ;
}
2026-02-09 21:53:10 -05:00
setQuota (
remaining : number | undefined ,
limit : number | undefined ,
modelId? : string ,
) : void {
const activeModel = modelId ? ? this . getActiveModel ( ) ;
if ( remaining !== undefined && limit !== undefined ) {
const current = this . modelQuotas . get ( activeModel ) ;
if (
! current ||
current . remaining !== remaining ||
current . limit !== limit
) {
this . modelQuotas . set ( activeModel , { remaining , limit } ) ;
this . emitQuotaChangedEvent ( ) ;
}
}
}
private getPooledQuota ( ) : {
remaining? : number ;
limit? : number ;
resetTime? : string ;
} {
const model = this . getModel ( ) ;
if ( ! isAutoModel ( model ) ) {
return { } ;
}
const isPreview =
model === PREVIEW_GEMINI_MODEL_AUTO ||
isPreviewModel ( this . getActiveModel ( ) ) ;
const proModel = isPreview ? PREVIEW_GEMINI_MODEL : DEFAULT_GEMINI_MODEL ;
const flashModel = isPreview
? PREVIEW_GEMINI_FLASH_MODEL
: DEFAULT_GEMINI_FLASH_MODEL ;
const proQuota = this . modelQuotas . get ( proModel ) ;
const flashQuota = this . modelQuotas . get ( flashModel ) ;
if ( proQuota || flashQuota ) {
// For reset time, take the one that is furthest in the future (most conservative)
const resetTime = [ proQuota ? . resetTime , flashQuota ? . resetTime ]
. filter ( ( t ) : t is string = > ! ! t )
. sort ( )
. reverse ( ) [ 0 ] ;
return {
remaining : ( proQuota ? . remaining ? ? 0 ) + ( flashQuota ? . remaining ? ? 0 ) ,
limit : ( proQuota ? . limit ? ? 0 ) + ( flashQuota ? . limit ? ? 0 ) ,
resetTime ,
} ;
}
return { } ;
}
getQuotaRemaining ( ) : number | undefined {
const pooled = this . getPooledQuota ( ) ;
if ( pooled . remaining !== undefined ) {
return pooled . remaining ;
}
2026-02-20 14:19:21 -05:00
const primaryModel = resolveModel (
this . getModel ( ) ,
this . getGemini31LaunchedSync ( ) ,
) ;
2026-02-09 21:53:10 -05:00
return this . modelQuotas . get ( primaryModel ) ? . remaining ;
}
getQuotaLimit ( ) : number | undefined {
const pooled = this . getPooledQuota ( ) ;
if ( pooled . limit !== undefined ) {
return pooled . limit ;
}
2026-02-20 14:19:21 -05:00
const primaryModel = resolveModel (
this . getModel ( ) ,
this . getGemini31LaunchedSync ( ) ,
) ;
2026-02-09 21:53:10 -05:00
return this . modelQuotas . get ( primaryModel ) ? . limit ;
}
getQuotaResetTime ( ) : string | undefined {
const pooled = this . getPooledQuota ( ) ;
if ( pooled . resetTime !== undefined ) {
return pooled . resetTime ;
}
2026-02-20 14:19:21 -05:00
const primaryModel = resolveModel (
this . getModel ( ) ,
this . getGemini31LaunchedSync ( ) ,
) ;
2026-02-09 21:53:10 -05:00
return this . modelQuotas . get ( primaryModel ) ? . resetTime ;
}
2025-06-07 13:38:05 -07:00
getEmbeddingModel ( ) : string {
return this . embeddingModel ;
}
2025-06-18 10:01:00 -07:00
getSandbox ( ) : SandboxConfig | undefined {
2025-05-02 08:15:46 -07:00
return this . sandbox ;
}
2025-08-01 04:02:08 +09:00
isRestrictiveSandbox ( ) : boolean {
const sandboxConfig = this . getSandbox ( ) ;
2025-08-17 12:43:21 -04:00
const seatbeltProfile = process . env [ 'SEATBELT_PROFILE' ] ;
2025-08-01 04:02:08 +09:00
return (
! ! sandboxConfig &&
sandboxConfig . command === 'sandbox-exec' &&
! ! seatbeltProfile &&
2026-02-12 10:33:54 -08:00
( seatbeltProfile . startsWith ( 'restrictive-' ) ||
seatbeltProfile . startsWith ( 'strict-' ) )
2025-08-01 04:02:08 +09:00
) ;
}
2025-04-19 19:45:42 +01:00
getTargetDir ( ) : string {
return this . targetDir ;
}
2025-04-20 20:20:40 +01:00
2025-06-11 15:33:09 -04:00
getProjectRoot ( ) : string {
return this . targetDir ;
}
2025-07-31 05:38:20 +09:00
getWorkspaceContext ( ) : WorkspaceContext {
return this . workspaceContext ;
}
2025-10-01 16:54:00 -04:00
getAgentRegistry ( ) : AgentRegistry {
return this . agentRegistry ;
}
2026-01-26 19:49:32 +00:00
getAcknowledgedAgentsService ( ) : AcknowledgedAgentsService {
return this . acknowledgedAgentsService ;
}
2025-08-19 15:31:02 -07:00
getToolRegistry ( ) : ToolRegistry {
return this . toolRegistry ;
2025-04-21 12:59:31 -07:00
}
2025-07-25 20:56:33 +00:00
getPromptRegistry ( ) : PromptRegistry {
return this . promptRegistry ;
}
2025-12-30 13:35:52 -08:00
getSkillManager ( ) : SkillManager {
return this . skillManager ;
}
2025-12-09 03:43:12 +01:00
getResourceRegistry ( ) : ResourceRegistry {
return this . resourceRegistry ;
}
2025-04-20 20:20:40 +01:00
getDebugMode ( ) : boolean {
return this . debugMode ;
}
2025-04-22 18:32:03 -07:00
getQuestion ( ) : string | undefined {
return this . question ;
}
2025-04-20 21:06:22 +01:00
2025-12-17 09:43:21 -08:00
getHasAccessToPreviewModel ( ) : boolean {
2026-02-23 09:14:00 +05:30
return this . hasAccessToPreviewModel !== false ;
2025-12-17 09:43:21 -08:00
}
2026-02-23 09:14:00 +05:30
setHasAccessToPreviewModel ( hasAccess : boolean | null ) : void {
2025-12-17 09:43:21 -08:00
this . hasAccessToPreviewModel = hasAccess ;
}
async refreshUserQuota ( ) : Promise < RetrieveUserQuotaResponse | undefined > {
const codeAssistServer = getCodeAssistServer ( this ) ;
if ( ! codeAssistServer || ! codeAssistServer . projectId ) {
return undefined ;
}
try {
const quota = await codeAssistServer . retrieveUserQuota ( {
project : codeAssistServer.projectId ,
} ) ;
2026-02-09 21:53:10 -05:00
if ( quota . buckets ) {
this . lastRetrievedQuota = quota ;
this . lastQuotaFetchTime = Date . now ( ) ;
for ( const bucket of quota . buckets ) {
if (
bucket . modelId &&
bucket . remainingAmount &&
bucket . remainingFraction != null
) {
const remaining = parseInt ( bucket . remainingAmount , 10 ) ;
const limit =
bucket . remainingFraction > 0
? Math . round ( remaining / bucket . remainingFraction )
: ( this . modelQuotas . get ( bucket . modelId ) ? . limit ? ? 0 ) ;
if ( ! isNaN ( remaining ) && Number . isFinite ( limit ) && limit > 0 ) {
this . modelQuotas . set ( bucket . modelId , {
remaining ,
limit ,
resetTime : bucket.resetTime ,
} ) ;
}
}
}
this . emitQuotaChangedEvent ( ) ;
}
2025-12-17 09:43:21 -08:00
const hasAccess =
2026-02-22 07:53:24 -05:00
quota . buckets ? . some ( ( b ) = > b . modelId && isPreviewModel ( b . modelId ) ) ? ?
false ;
2025-12-17 09:43:21 -08:00
this . setHasAccessToPreviewModel ( hasAccess ) ;
return quota ;
} catch ( e ) {
debugLogger . debug ( 'Failed to retrieve user quota' , e ) ;
return undefined ;
}
}
2026-02-09 21:53:10 -05:00
async refreshUserQuotaIfStale (
staleMs = 30 _000 ,
) : Promise < RetrieveUserQuotaResponse | undefined > {
const now = Date . now ( ) ;
if ( now - this . lastQuotaFetchTime > staleMs ) {
return this . refreshUserQuota ( ) ;
}
return this . lastRetrievedQuota ;
}
getLastRetrievedQuota ( ) : RetrieveUserQuotaResponse | undefined {
return this . lastRetrievedQuota ;
}
getRemainingQuotaForModel ( modelId : string ) :
| {
remainingAmount? : number ;
remainingFraction? : number ;
resetTime? : string ;
}
| undefined {
const bucket = this . lastRetrievedQuota ? . buckets ? . find (
( b ) = > b . modelId === modelId ,
) ;
if ( ! bucket ) return undefined ;
return {
remainingAmount : bucket.remainingAmount
? parseInt ( bucket . remainingAmount , 10 )
: undefined ,
remainingFraction : bucket.remainingFraction ,
resetTime : bucket.resetTime ,
} ;
}
2025-05-17 19:45:16 -07:00
getCoreTools ( ) : string [ ] | undefined {
return this . coreTools ;
}
2025-08-27 02:17:43 +10:00
getAllowedTools ( ) : string [ ] | undefined {
return this . allowedTools ;
}
2025-11-04 07:51:18 -08:00
/**
* All the excluded tools from static configuration, loaded extensions, or
2026-02-11 16:49:48 -08:00
* other sources (like the Policy Engine).
2025-11-04 07:51:18 -08:00
*
* May change over time.
*/
2026-02-24 09:20:11 -05:00
getExcludeTools (
toolMetadata? : Map < string , Record < string , unknown > > ,
2026-02-24 12:17:43 -05:00
allToolNames? : Set < string > ,
2026-02-24 09:20:11 -05:00
) : Set < string > | undefined {
2026-02-11 16:49:48 -08:00
// Right now this is present for backward compatibility with settings.json exclude
2025-11-04 07:51:18 -08:00
const excludeToolsSet = new Set ( [ . . . ( this . excludeTools ? ? [ ] ) ] ) ;
for ( const extension of this . getExtensionLoader ( ) . getExtensions ( ) ) {
if ( ! extension . isActive ) {
continue ;
}
for ( const tool of extension . excludeTools || [ ] ) {
excludeToolsSet . add ( tool ) ;
}
}
2026-02-11 16:49:48 -08:00
2026-02-24 12:17:43 -05:00
const policyExclusions = this . policyEngine . getExcludedTools (
toolMetadata ,
allToolNames ,
) ;
2026-02-11 16:49:48 -08:00
for ( const tool of policyExclusions ) {
excludeToolsSet . add ( tool ) ;
}
2025-11-07 12:18:35 -08:00
return excludeToolsSet ;
2025-06-11 14:32:23 -07:00
}
2025-05-03 19:57:28 -07:00
getToolDiscoveryCommand ( ) : string | undefined {
return this . toolDiscoveryCommand ;
}
getToolCallCommand ( ) : string | undefined {
return this . toolCallCommand ;
}
2025-05-04 12:11:19 -07:00
getMcpServerCommand ( ) : string | undefined {
return this . mcpServerCommand ;
}
2025-05-11 14:28:21 -07:00
2025-11-04 07:51:18 -08:00
/**
* The user configured MCP servers (via gemini settings files).
*
* Does NOT include mcp servers configured by extensions.
*/
2025-05-17 16:53:22 -07:00
getMcpServers ( ) : Record < string , MCPServerConfig > | undefined {
2025-05-16 16:29:03 -07:00
return this . mcpServers ;
}
2026-01-06 16:38:07 -05:00
getMcpEnabled ( ) : boolean {
return this . mcpEnabled ;
}
2026-01-22 15:38:06 -08:00
getMcpEnablementCallbacks ( ) : McpEnablementCallbacks | undefined {
return this . mcpEnablementCallbacks ;
}
2026-01-08 12:59:30 -05:00
getExtensionsEnabled ( ) : boolean {
return this . extensionsEnabled ;
}
2025-11-04 07:51:18 -08:00
getMcpClientManager ( ) : McpClientManager | undefined {
return this . mcpClientManager ;
}
getAllowedMcpServers ( ) : string [ ] | undefined {
return this . allowedMcpServers ;
}
getBlockedMcpServers ( ) : string [ ] | undefined {
return this . blockedMcpServers ;
}
2025-12-22 19:18:27 -08:00
get sanitizationConfig ( ) : EnvironmentSanitizationConfig {
return {
allowedEnvironmentVariables : this.allowedEnvironmentVariables ,
blockedEnvironmentVariables : this.blockedEnvironmentVariables ,
enableEnvironmentVariableRedaction :
this.enableEnvironmentVariableRedaction ,
} ;
}
2025-10-30 11:05:49 -07:00
setMcpServers ( mcpServers : Record < string , MCPServerConfig > ) : void {
this . mcpServers = mcpServers ;
}
2026-02-09 18:01:59 -08:00
getUserMemory ( ) : string | HierarchicalMemory {
2025-12-19 07:04:03 -10:00
if ( this . experimentalJitContext && this . contextManager ) {
2026-02-09 18:01:59 -08:00
return {
global : this . contextManager . getGlobalMemory ( ) ,
extension : this.contextManager.getExtensionMemory ( ) ,
project : this.contextManager.getEnvironmentMemory ( ) ,
} ;
2025-12-19 07:04:03 -10:00
}
2025-05-14 12:37:17 -07:00
return this . userMemory ;
}
2026-01-20 11:10:21 -05:00
/**
* Refreshes the MCP context, including memory, tools, and system instructions.
*/
async refreshMcpContext ( ) : Promise < void > {
if ( this . experimentalJitContext && this . contextManager ) {
await this . contextManager . refresh ( ) ;
} else {
const { refreshServerHierarchicalMemory } = await import (
'../utils/memoryDiscovery.js'
) ;
await refreshServerHierarchicalMemory ( this ) ;
}
if ( this . geminiClient ? . isInitialized ( ) ) {
await this . geminiClient . setTools ( ) ;
2026-01-26 18:45:24 -05:00
this . geminiClient . updateSystemInstruction ( ) ;
2026-01-20 11:10:21 -05:00
}
}
2026-02-09 18:01:59 -08:00
setUserMemory ( newUserMemory : string | HierarchicalMemory ) : void {
2025-05-14 12:37:17 -07:00
this . userMemory = newUserMemory ;
}
2025-05-14 15:19:45 -07:00
2025-12-03 04:09:46 +08:00
getGlobalMemory ( ) : string {
return this . contextManager ? . getGlobalMemory ( ) ? ? '' ;
}
getEnvironmentMemory ( ) : string {
return this . contextManager ? . getEnvironmentMemory ( ) ? ? '' ;
}
getContextManager ( ) : ContextManager | undefined {
return this . contextManager ;
}
isJitContextEnabled ( ) : boolean {
return this . experimentalJitContext ;
}
2026-02-18 14:05:50 -08:00
isModelSteeringEnabled ( ) : boolean {
return this . modelSteering ;
}
2026-02-05 20:53:11 -05:00
getToolOutputMaskingEnabled ( ) : boolean {
return this . toolOutputMasking . enabled ;
}
2026-02-07 22:04:46 -05:00
async getToolOutputMaskingConfig ( ) : Promise < ToolOutputMaskingConfig > {
await this . ensureExperimentsLoaded ( ) ;
const remoteProtection =
this . experiments ? . flags [ ExperimentFlags . MASKING_PROTECTION_THRESHOLD ]
? . intValue ;
const remotePrunable =
this . experiments ? . flags [ ExperimentFlags . MASKING_PRUNABLE_THRESHOLD ]
? . intValue ;
const remoteProtectLatest =
this . experiments ? . flags [ ExperimentFlags . MASKING_PROTECT_LATEST_TURN ]
? . boolValue ;
const parsedProtection = remoteProtection
? parseInt ( remoteProtection , 10 )
: undefined ;
const parsedPrunable = remotePrunable
? parseInt ( remotePrunable , 10 )
: undefined ;
return {
enabled : this.toolOutputMasking.enabled ,
toolProtectionThreshold :
parsedProtection !== undefined && ! isNaN ( parsedProtection )
? parsedProtection
: this.toolOutputMasking.toolProtectionThreshold ,
minPrunableTokensThreshold :
parsedPrunable !== undefined && ! isNaN ( parsedPrunable )
? parsedPrunable
: this.toolOutputMasking.minPrunableTokensThreshold ,
protectLatestTurn :
remoteProtectLatest ? ? this . toolOutputMasking . protectLatestTurn ,
} ;
2026-02-05 20:53:11 -05:00
}
2025-05-14 15:19:45 -07:00
getGeminiMdFileCount ( ) : number {
2025-12-19 07:04:03 -10:00
if ( this . experimentalJitContext && this . contextManager ) {
return this . contextManager . getLoadedPaths ( ) . size ;
}
2025-05-14 15:19:45 -07:00
return this . geminiMdFileCount ;
}
setGeminiMdFileCount ( count : number ) : void {
this . geminiMdFileCount = count ;
}
2025-05-16 23:33:12 -07:00
2025-10-02 17:46:54 -04:00
getGeminiMdFilePaths ( ) : string [ ] {
2025-12-19 07:04:03 -10:00
if ( this . experimentalJitContext && this . contextManager ) {
return Array . from ( this . contextManager . getLoadedPaths ( ) ) ;
}
2025-10-02 17:46:54 -04:00
return this . geminiMdFilePaths ;
}
setGeminiMdFilePaths ( paths : string [ ] ) : void {
this . geminiMdFilePaths = paths ;
}
2025-06-02 22:05:45 +02:00
getApprovalMode ( ) : ApprovalMode {
2025-12-22 15:25:07 -05:00
return this . policyEngine . getApprovalMode ( ) ;
2025-05-16 23:33:12 -07:00
}
2026-02-19 16:16:03 -08:00
getPolicyUpdateConfirmationRequest ( ) :
| PolicyUpdateConfirmationRequest
| undefined {
return this . policyUpdateConfirmationRequest ;
}
/**
* Hot-loads workspace policies from the specified directory into the active policy engine.
* This allows applying newly accepted policies without requiring an application restart.
*
* @param policyDir The directory containing the workspace policy TOML files.
*/
async loadWorkspacePolicies ( policyDir : string ) : Promise < void > {
const { rules , checkers } = await loadPoliciesFromToml (
[ policyDir ] ,
( ) = > WORKSPACE_POLICY_TIER ,
) ;
// Clear existing workspace policies to prevent duplicates/stale rules
this . policyEngine . removeRulesByTier ( WORKSPACE_POLICY_TIER ) ;
this . policyEngine . removeCheckersByTier ( WORKSPACE_POLICY_TIER ) ;
for ( const rule of rules ) {
this . policyEngine . addRule ( rule ) ;
}
for ( const checker of checkers ) {
this . policyEngine . addChecker ( checker ) ;
}
this . policyUpdateConfirmationRequest = undefined ;
debugLogger . debug ( ` Workspace policies loaded from: ${ policyDir } ` ) ;
}
2025-06-02 22:05:45 +02:00
setApprovalMode ( mode : ApprovalMode ) : void {
2025-08-28 19:41:33 -07:00
if ( ! this . isTrustedFolder ( ) && mode !== ApprovalMode . DEFAULT ) {
2025-08-25 17:30:04 -07:00
throw new Error (
'Cannot enable privileged approval modes in an untrusted folder.' ,
) ;
}
2026-01-20 13:57:34 -05:00
const currentMode = this . getApprovalMode ( ) ;
if ( currentMode !== mode ) {
2026-02-21 19:32:57 -05:00
this . logCurrentModeDuration ( currentMode ) ;
2026-01-20 13:57:34 -05:00
logApprovalModeSwitch (
this ,
new ApprovalModeSwitchEvent ( currentMode , mode ) ,
) ;
}
2025-12-22 15:25:07 -05:00
this . policyEngine . setApprovalMode ( mode ) ;
2026-01-26 18:45:24 -05:00
const isPlanModeTransition =
currentMode !== mode &&
( currentMode === ApprovalMode . PLAN || mode === ApprovalMode . PLAN ) ;
2026-02-19 20:53:12 -05:00
const isYoloModeTransition =
currentMode !== mode &&
( currentMode === ApprovalMode . YOLO || mode === ApprovalMode . YOLO ) ;
if ( isPlanModeTransition || isYoloModeTransition ) {
2026-02-05 15:04:03 -05:00
this . syncPlanModeTools ( ) ;
2026-01-26 18:45:24 -05:00
this . updateSystemInstructionIfInitialized ( ) ;
}
2025-05-16 23:33:12 -07:00
}
2025-05-27 10:00:07 -07:00
2026-02-05 15:04:03 -05:00
/**
* Synchronizes enter/exit plan mode tools based on current mode.
*/
syncPlanModeTools ( ) : void {
const registry = this . getToolRegistry ( ) ;
2026-02-19 20:53:12 -05:00
if ( ! registry ) {
return ;
}
const approvalMode = this . getApprovalMode ( ) ;
const isPlanMode = approvalMode === ApprovalMode . PLAN ;
const isYoloMode = approvalMode === ApprovalMode . YOLO ;
2026-02-05 15:04:03 -05:00
if ( isPlanMode ) {
if ( registry . getTool ( ENTER_PLAN_MODE_TOOL_NAME ) ) {
registry . unregisterTool ( ENTER_PLAN_MODE_TOOL_NAME ) ;
}
if ( ! registry . getTool ( EXIT_PLAN_MODE_TOOL_NAME ) ) {
registry . registerTool ( new ExitPlanModeTool ( this , this . messageBus ) ) ;
}
} else {
if ( registry . getTool ( EXIT_PLAN_MODE_TOOL_NAME ) ) {
registry . unregisterTool ( EXIT_PLAN_MODE_TOOL_NAME ) ;
}
2026-02-19 20:53:12 -05:00
if ( this . planEnabled && ! isYoloMode ) {
2026-02-08 20:57:01 -05:00
if ( ! registry . getTool ( ENTER_PLAN_MODE_TOOL_NAME ) ) {
registry . registerTool ( new EnterPlanModeTool ( this , this . messageBus ) ) ;
}
} else {
if ( registry . getTool ( ENTER_PLAN_MODE_TOOL_NAME ) ) {
registry . unregisterTool ( ENTER_PLAN_MODE_TOOL_NAME ) ;
}
2026-02-05 15:04:03 -05:00
}
}
if ( this . geminiClient ? . isInitialized ( ) ) {
this . geminiClient . setTools ( ) . catch ( ( err ) = > {
debugLogger . error ( 'Failed to update tools' , err ) ;
} ) ;
}
}
2026-01-20 13:57:34 -05:00
/**
* Logs the duration of the current approval mode.
*/
logCurrentModeDuration ( mode : ApprovalMode ) : void {
2026-02-21 19:32:57 -05:00
const now = performance . now ( ) ;
2026-01-20 13:57:34 -05:00
const duration = now - this . lastModeSwitchTime ;
2026-02-21 19:32:57 -05:00
if ( duration > 0 ) {
logApprovalModeDuration (
this ,
new ApprovalModeDurationEvent ( mode , duration ) ,
) ;
}
this . lastModeSwitchTime = now ;
2026-01-20 13:57:34 -05:00
}
2025-10-22 11:57:10 -07:00
isYoloModeDisabled ( ) : boolean {
return this . disableYoloMode || ! this . isTrustedFolder ( ) ;
}
2026-01-20 23:58:37 -05:00
getRawOutput ( ) : boolean {
return this . rawOutput ;
}
getAcceptRawOutputRisk ( ) : boolean {
return this . acceptRawOutputRisk ;
}
2025-11-14 19:06:30 -08:00
getPendingIncludeDirectories ( ) : string [ ] {
return this . pendingIncludeDirectories ;
}
clearPendingIncludeDirectories ( ) : void {
this . pendingIncludeDirectories = [ ] ;
}
2025-05-30 22:18:01 +00:00
getShowMemoryUsage ( ) : boolean {
return this . showMemoryUsage ;
}
2025-06-02 14:55:51 -07:00
2025-06-04 00:46:57 -07:00
getAccessibility ( ) : AccessibilitySettings {
return this . accessibility ;
}
2025-06-05 16:04:25 -04:00
getTelemetryEnabled ( ) : boolean {
2025-06-15 00:47:32 -04:00
return this . telemetrySettings . enabled ? ? false ;
2025-06-05 16:04:25 -04:00
}
2025-06-15 00:47:32 -04:00
getTelemetryLogPromptsEnabled ( ) : boolean {
return this . telemetrySettings . logPrompts ? ? true ;
2025-06-05 16:04:25 -04:00
}
getTelemetryOtlpEndpoint ( ) : string {
2025-06-15 00:47:32 -04:00
return this . telemetrySettings . otlpEndpoint ? ? DEFAULT_OTLP_ENDPOINT ;
}
2025-08-15 18:10:21 -07:00
getTelemetryOtlpProtocol ( ) : 'grpc' | 'http' {
return this . telemetrySettings . otlpProtocol ? ? 'grpc' ;
}
2025-06-15 00:47:32 -04:00
getTelemetryTarget ( ) : TelemetryTarget {
return this . telemetrySettings . target ? ? DEFAULT_TELEMETRY_TARGET ;
2025-06-05 16:04:25 -04:00
}
2025-07-23 17:48:24 -04:00
getTelemetryOutfile ( ) : string | undefined {
return this . telemetrySettings . outfile ;
}
2025-09-17 04:13:57 +09:00
getTelemetryUseCollector ( ) : boolean {
return this . telemetrySettings . useCollector ? ? false ;
}
2025-12-02 21:27:37 -08:00
getTelemetryUseCliAuth ( ) : boolean {
return this . telemetrySettings . useCliAuth ? ? false ;
}
2025-06-02 14:55:51 -07:00
getGeminiClient ( ) : GeminiClient {
return this . geminiClient ;
}
2025-06-03 21:40:46 -07:00
2025-11-20 21:22:06 +08:00
/**
* Updates the system instruction with the latest user memory.
* Whenever the user memory (GEMINI.md files) is updated.
*/
2026-01-26 18:45:24 -05:00
updateSystemInstructionIfInitialized ( ) : void {
2025-11-20 21:22:06 +08:00
const geminiClient = this . getGeminiClient ( ) ;
if ( geminiClient ? . isInitialized ( ) ) {
2026-01-26 18:45:24 -05:00
geminiClient . updateSystemInstruction ( ) ;
2025-11-20 21:22:06 +08:00
}
}
2025-09-11 13:38:50 -04:00
getModelRouterService ( ) : ModelRouterService {
return this . modelRouterService ;
}
2025-11-26 12:36:42 -08:00
getModelAvailabilityService ( ) : ModelAvailabilityService {
return this . modelAvailabilityService ;
}
2025-06-21 18:23:35 -07:00
getEnableRecursiveFileSearch ( ) : boolean {
return this . fileFiltering . enableRecursiveFileSearch ;
}
2026-01-16 23:33:49 +01:00
getFileFilteringEnableFuzzySearch ( ) : boolean {
return this . fileFiltering . enableFuzzySearch ;
2025-08-21 23:31:39 -07:00
}
2025-06-03 21:40:46 -07:00
getFileFilteringRespectGitIgnore ( ) : boolean {
2025-06-21 18:23:35 -07:00
return this . fileFiltering . respectGitIgnore ;
2025-06-03 21:40:46 -07:00
}
2026-01-27 17:19:13 -08:00
2025-07-20 00:55:33 -07:00
getFileFilteringRespectGeminiIgnore ( ) : boolean {
return this . fileFiltering . respectGeminiIgnore ;
}
2026-01-27 17:19:13 -08:00
getCustomIgnoreFilePaths ( ) : string [ ] {
return this . fileFiltering . customIgnoreFilePaths ;
}
2025-07-20 00:55:33 -07:00
getFileFilteringOptions ( ) : FileFilteringOptions {
return {
respectGitIgnore : this.fileFiltering.respectGitIgnore ,
respectGeminiIgnore : this.fileFiltering.respectGeminiIgnore ,
2026-01-15 12:04:22 -08:00
maxFileCount : this.fileFiltering.maxFileCount ,
searchTimeout : this.fileFiltering.searchTimeout ,
2026-01-27 17:19:13 -08:00
customIgnoreFilePaths : this.fileFiltering.customIgnoreFilePaths ,
2025-07-20 00:55:33 -07:00
} ;
}
2025-06-03 21:40:46 -07:00
2025-08-23 13:35:00 +09:00
/**
* Gets custom file exclusion patterns from configuration.
* TODO: This is a placeholder implementation. In the future, this could
* read from settings files, CLI arguments, or environment variables.
*/
getCustomExcludes ( ) : string [ ] {
// Placeholder implementation - returns empty array for now
// Future implementation could read from:
// - User settings file
// - Project-specific configuration
// - Environment variables
// - CLI arguments
return [ ] ;
}
2025-06-20 00:39:15 -04:00
getCheckpointingEnabled ( ) : boolean {
return this . checkpointing ;
2025-06-11 15:33:09 -04:00
}
2025-06-12 17:17:29 -07:00
getProxy ( ) : string | undefined {
return this . proxy ;
}
getWorkingDir ( ) : string {
return this . cwd ;
}
2025-06-14 00:00:24 -07:00
getBugCommand ( ) : BugCommandSettings | undefined {
return this . bugCommand ;
}
2025-06-14 10:25:34 -04:00
getFileService ( ) : FileDiscoveryService {
2025-06-03 21:40:46 -07:00
if ( ! this . fileDiscoveryService ) {
2026-01-27 17:19:13 -08:00
this . fileDiscoveryService = new FileDiscoveryService ( this . targetDir , {
respectGitIgnore : this.fileFiltering.respectGitIgnore ,
respectGeminiIgnore : this.fileFiltering.respectGeminiIgnore ,
customIgnoreFilePaths : this.fileFiltering.customIgnoreFilePaths ,
} ) ;
2025-06-03 21:40:46 -07:00
}
return this . fileDiscoveryService ;
}
2025-06-11 15:33:09 -04:00
2025-06-23 17:19:40 -04:00
getUsageStatisticsEnabled ( ) : boolean {
2025-06-23 20:29:31 -04:00
return this . usageStatisticsEnabled ;
2025-06-22 09:26:48 -05:00
}
2025-08-13 12:58:26 -03:00
getExperimentalZedIntegration ( ) : boolean {
return this . experimentalZedIntegration ;
2025-07-17 16:25:23 -06:00
}
2025-07-08 12:57:34 -04:00
getListExtensions ( ) : boolean {
return this . listExtensions ;
}
2025-11-10 18:31:00 -07:00
getListSessions ( ) : boolean {
return this . listSessions ;
}
getDeleteSession ( ) : string | undefined {
return this . deleteSession ;
}
2025-08-25 17:02:10 +00:00
getExtensionManagement ( ) : boolean {
return this . extensionManagement ;
}
2025-07-18 20:45:00 +02:00
getExtensions ( ) : GeminiCLIExtension [ ] {
2025-10-28 09:04:30 -07:00
return this . _extensionLoader . getExtensions ( ) ;
}
getExtensionLoader ( ) : ExtensionLoader {
return this . _extensionLoader ;
2025-07-18 20:45:00 +02:00
}
2025-10-20 16:15:23 -07:00
// The list of explicitly enabled extensions, if any were given, may contain
// the string "none".
getEnabledExtensions ( ) : string [ ] {
return this . _enabledExtensions ;
}
2025-10-30 11:05:49 -07:00
getEnableExtensionReloading ( ) : boolean {
return this . enableExtensionReloading ;
}
2026-01-13 09:26:53 +08:00
getDisableLLMCorrection ( ) : boolean {
return this . disableLLMCorrection ;
}
2026-01-14 19:55:10 -05:00
isPlanEnabled ( ) : boolean {
return this . planEnabled ;
}
2026-02-04 12:01:43 -05:00
getApprovedPlanPath ( ) : string | undefined {
return this . approvedPlanPath ;
}
2026-02-23 11:50:14 -08:00
getDirectWebFetch ( ) : boolean {
return this . directWebFetch ;
}
2026-02-04 12:01:43 -05:00
setApprovedPlanPath ( path : string | undefined ) : void {
this . approvedPlanPath = path ;
}
2025-12-03 12:53:06 -08:00
isAgentsEnabled ( ) : boolean {
return this . enableAgents ;
}
2026-01-19 22:59:30 -05:00
isEventDrivenSchedulerEnabled ( ) : boolean {
return this . enableEventDrivenScheduler ;
}
2025-07-10 18:59:02 -07:00
getNoBrowser ( ) : boolean {
return this . noBrowser ;
}
2026-01-13 12:16:02 -08:00
getAgentsSettings ( ) : AgentSettings {
return this . agents ;
}
2025-07-21 16:23:28 -07:00
isBrowserLaunchSuppressed ( ) : boolean {
return this . getNoBrowser ( ) || ! shouldAttemptBrowserLaunch ( ) ;
}
2025-07-15 10:22:31 -07:00
getSummarizeToolOutputConfig ( ) :
| Record < string , SummarizeToolOutputSettings >
| undefined {
return this . summarizeToolOutput ;
}
2025-08-07 14:06:17 -07:00
getIdeMode ( ) : boolean {
return this . ideMode ;
}
2025-10-10 11:07:40 -07:00
/**
* Returns 'true' if the folder trust feature is enabled.
2025-10-10 12:04:15 -04:00
*/
2025-10-10 11:07:40 -07:00
getFolderTrust ( ) : boolean {
return this . folderTrust ;
2025-08-06 15:27:21 -07:00
}
2025-08-29 14:12:36 -04:00
/**
* Returns 'true' if the workspace is considered "trusted".
* 'false' for untrusted.
*/
2025-08-28 19:41:33 -07:00
isTrustedFolder ( ) : boolean {
2025-09-11 11:22:20 -07:00
const context = ideContextStore . get ( ) ;
2025-09-03 11:44:26 -07:00
if ( context ? . workspaceState ? . isTrusted !== undefined ) {
return context . workspaceState . isTrusted ;
}
2026-01-06 10:09:09 -08:00
// Default to untrusted if folder trust is enabled and no explicit value is set.
return this . folderTrust ? ( this . trustedFolder ? ? false ) : true ;
2025-08-13 11:06:31 -07:00
}
2025-07-30 22:36:24 +00:00
setIdeMode ( value : boolean ) : void {
this . ideMode = value ;
}
2025-08-18 16:29:45 -06:00
/**
* Get the current FileSystemService
*/
getFileSystemService ( ) : FileSystemService {
return this . fileSystemService ;
}
2026-01-27 13:17:40 -08:00
/**
* Checks if a given absolute path is allowed for file system operations.
* A path is allowed if it's within the workspace context or the project's temporary directory.
*
* @param absolutePath The absolute path to check.
* @returns true if the path is allowed, false otherwise.
*/
isPathAllowed ( absolutePath : string ) : boolean {
const realpath = ( p : string ) = > {
let resolved : string ;
try {
resolved = fs . realpathSync ( p ) ;
} catch {
resolved = path . resolve ( p ) ;
}
return os . platform ( ) === 'win32' ? resolved . toLowerCase ( ) : resolved ;
} ;
const resolvedPath = realpath ( absolutePath ) ;
const workspaceContext = this . getWorkspaceContext ( ) ;
if ( workspaceContext . isPathWithinWorkspace ( resolvedPath ) ) {
return true ;
}
const projectTempDir = this . storage . getProjectTempDir ( ) ;
const resolvedTempDir = realpath ( projectTempDir ) ;
return isSubpath ( resolvedTempDir , resolvedPath ) ;
}
/**
* Validates if a path is allowed and returns a detailed error message if not.
*
* @param absolutePath The absolute path to validate.
2026-02-09 12:24:28 -08:00
* @param checkType The type of access to check ('read' or 'write'). Defaults to 'write' for safety.
2026-01-27 13:17:40 -08:00
* @returns An error message string if the path is disallowed, null otherwise.
*/
2026-02-09 12:24:28 -08:00
validatePathAccess (
absolutePath : string ,
checkType : 'read' | 'write' = 'write' ,
) : string | null {
// For read operations, check read-only paths first
if ( checkType === 'read' ) {
if ( this . getWorkspaceContext ( ) . isPathReadable ( absolutePath ) ) {
return null ;
}
}
// Then check standard allowed paths (Workspace + Temp)
// This covers 'write' checks and acts as a fallback/temp-dir check for 'read'
2026-01-27 13:17:40 -08:00
if ( this . isPathAllowed ( absolutePath ) ) {
return null ;
}
const workspaceDirs = this . getWorkspaceContext ( ) . getDirectories ( ) ;
const projectTempDir = this . storage . getProjectTempDir ( ) ;
return ` Path not in workspace: Attempted path " ${ absolutePath } " resolves outside the allowed workspace directories: ${ workspaceDirs . join ( ', ' ) } or the project temp directory: ${ projectTempDir } ` ;
}
2025-08-18 16:29:45 -06:00
/**
* Set a custom FileSystemService
*/
setFileSystemService ( fileSystemService : FileSystemService ) : void {
this . fileSystemService = fileSystemService ;
}
2025-11-04 15:09:53 -08:00
async getCompressionThreshold ( ) : Promise < number | undefined > {
if ( this . compressionThreshold ) {
return this . compressionThreshold ;
}
2026-01-18 22:40:07 -08:00
await this . ensureExperimentsLoaded ( ) ;
2025-11-04 15:09:53 -08:00
const remoteThreshold =
2025-11-10 23:15:38 -05:00
this . experiments ? . flags [ ExperimentFlags . CONTEXT_COMPRESSION_THRESHOLD ]
2025-11-04 15:09:53 -08:00
? . floatValue ;
if ( remoteThreshold === 0 ) {
return undefined ;
}
return remoteThreshold ;
2025-08-07 07:34:40 -07:00
}
2025-11-10 23:15:38 -05:00
async getUserCaching ( ) : Promise < boolean | undefined > {
await this . ensureExperimentsLoaded ( ) ;
return this . experiments ? . flags [ ExperimentFlags . USER_CACHING ] ? . boolValue ;
}
2026-02-24 19:15:14 -05:00
async getPlanModeRoutingEnabled ( ) : Promise < boolean > {
return this . planModeRoutingEnabled ;
}
2026-01-22 16:12:07 -06:00
async getNumericalRoutingEnabled ( ) : Promise < boolean > {
await this . ensureExperimentsLoaded ( ) ;
return ! ! this . experiments ? . flags [ ExperimentFlags . ENABLE_NUMERICAL_ROUTING ]
? . boolValue ;
}
async getClassifierThreshold ( ) : Promise < number | undefined > {
await this . ensureExperimentsLoaded ( ) ;
const flag = this . experiments ? . flags [ ExperimentFlags . CLASSIFIER_THRESHOLD ] ;
if ( flag ? . intValue !== undefined ) {
return parseInt ( flag . intValue , 10 ) ;
}
return flag ? . floatValue ;
}
2025-11-18 12:01:16 -05:00
async getBannerTextNoCapacityIssues ( ) : Promise < string > {
await this . ensureExperimentsLoaded ( ) ;
return (
this . experiments ? . flags [ ExperimentFlags . BANNER_TEXT_NO_CAPACITY_ISSUES ]
? . stringValue ? ? ''
) ;
}
async getBannerTextCapacityIssues ( ) : Promise < string > {
await this . ensureExperimentsLoaded ( ) ;
return (
this . experiments ? . flags [ ExperimentFlags . BANNER_TEXT_CAPACITY_ISSUES ]
? . stringValue ? ? ''
) ;
}
2026-02-20 14:19:21 -05:00
/**
* Returns whether Gemini 3.1 has been launched.
* This method is async and ensures that experiments are loaded before returning the result.
*/
async getGemini31Launched ( ) : Promise < boolean > {
await this . ensureExperimentsLoaded ( ) ;
return this . getGemini31LaunchedSync ( ) ;
}
/**
* Returns whether Gemini 3.1 has been launched.
*
* Note: This method should only be called after startup, once experiments have been loaded.
* If you need to call this during startup or from an async context, use
* getGemini31Launched instead.
*/
getGemini31LaunchedSync ( ) : boolean {
const authType = this . contentGeneratorConfig ? . authType ;
if (
authType === AuthType . USE_GEMINI ||
authType === AuthType . USE_VERTEX_AI
) {
return true ;
}
return (
this . experiments ? . flags [ ExperimentFlags . GEMINI_3_1_PRO_LAUNCHED ]
? . boolValue ? ? false
) ;
}
2025-11-10 23:15:38 -05:00
private async ensureExperimentsLoaded ( ) : Promise < void > {
if ( ! this . experimentsPromise ) {
return ;
}
try {
await this . experimentsPromise ;
} catch ( e ) {
debugLogger . debug ( 'Failed to fetch experiments' , e ) ;
}
}
2025-10-17 09:07:18 -07:00
isInteractiveShellEnabled ( ) : boolean {
return (
this . interactive &&
this . ptyInfo !== 'child_process' &&
this . enableInteractiveShell
) ;
}
2025-12-30 13:35:52 -08:00
isSkillsSupportEnabled ( ) : boolean {
return this . skillsSupport ;
}
2026-01-05 15:12:51 -08:00
/**
* Reloads skills by re-discovering them from extensions and local directories.
*/
async reloadSkills ( ) : Promise < void > {
if ( ! this . skillsSupport ) {
return ;
}
if ( this . onReload ) {
const refreshed = await this . onReload ( ) ;
this . disabledSkills = refreshed . disabledSkills ? ? [ ] ;
2026-01-13 23:40:23 -08:00
this . getSkillManager ( ) . setAdminSettings (
refreshed . adminSkillsEnabled ? ? this . adminSkillsEnabled ,
) ;
2026-01-05 15:12:51 -08:00
}
2026-01-13 23:40:23 -08:00
if ( this . getSkillManager ( ) . isAdminEnabled ( ) ) {
await this . getSkillManager ( ) . discoverSkills (
this . storage ,
this . getExtensions ( ) ,
2026-02-03 14:53:31 -08:00
this . isTrustedFolder ( ) ,
2026-01-05 15:12:51 -08:00
) ;
2026-01-13 23:40:23 -08:00
this . getSkillManager ( ) . setDisabledSkills ( this . disabledSkills ) ;
// Re-register ActivateSkillTool to update its schema with the newly discovered skills
if ( this . getSkillManager ( ) . getSkills ( ) . length > 0 ) {
this . getToolRegistry ( ) . unregisterTool ( ActivateSkillTool . Name ) ;
this . getToolRegistry ( ) . registerTool (
new ActivateSkillTool ( this , this . messageBus ) ,
) ;
} else {
this . getToolRegistry ( ) . unregisterTool ( ActivateSkillTool . Name ) ;
}
2026-01-05 15:12:51 -08:00
} else {
2026-01-13 23:40:23 -08:00
this . getSkillManager ( ) . clearSkills ( ) ;
2026-01-05 15:12:51 -08:00
this . getToolRegistry ( ) . unregisterTool ( ActivateSkillTool . Name ) ;
}
// Notify the client that system instructions might need updating
2026-01-26 18:45:24 -05:00
this . updateSystemInstructionIfInitialized ( ) ;
2026-01-05 15:12:51 -08:00
}
2026-01-14 19:30:17 -05:00
/**
* Reloads agent settings.
*/
async reloadAgents ( ) : Promise < void > {
if ( this . onReload ) {
const refreshed = await this . onReload ( ) ;
if ( refreshed . agents ) {
this . agents = refreshed . agents ;
}
}
}
2025-08-07 14:19:06 -07:00
isInteractive ( ) : boolean {
return this . interactive ;
}
2025-08-22 14:10:45 +08:00
getUseRipgrep ( ) : boolean {
return this . useRipgrep ;
}
2026-01-26 15:23:54 -08:00
getUseBackgroundColor ( ) : boolean {
return this . useBackgroundColor ;
}
2025-10-08 13:28:19 -07:00
getEnableInteractiveShell ( ) : boolean {
return this . enableInteractiveShell ;
2025-08-19 16:03:51 -07:00
}
2025-08-19 16:45:13 -07:00
getSkipNextSpeakerCheck ( ) : boolean {
return this . skipNextSpeakerCheck ;
}
2025-10-09 18:04:08 -04:00
getContinueOnFailedApiCall ( ) : boolean {
return this . continueOnFailedApiCall ;
}
2025-10-14 09:17:31 -07:00
getRetryFetchErrors ( ) : boolean {
return this . retryFetchErrors ;
}
2026-02-23 15:57:16 -08:00
getMaxAttempts ( ) : number {
return this . maxAttempts ;
}
2025-10-13 21:31:45 -07:00
getEnableShellOutputEfficiency ( ) : boolean {
return this . enableShellOutputEfficiency ;
}
2025-11-26 13:43:33 -08:00
getShellToolInactivityTimeout ( ) : number {
return this . shellToolInactivityTimeout ;
}
2025-09-11 13:27:27 -07:00
getShellExecutionConfig ( ) : ShellExecutionConfig {
return this . shellExecutionConfig ;
}
setShellExecutionConfig ( config : ShellExecutionConfig ) : void {
this . shellExecutionConfig = {
terminalWidth :
config.terminalWidth ? ? this . shellExecutionConfig . terminalWidth ,
terminalHeight :
config.terminalHeight ? ? this . shellExecutionConfig . terminalHeight ,
showColor : config.showColor ? ? this . shellExecutionConfig . showColor ,
pager : config.pager ? ? this . shellExecutionConfig . pager ,
2025-12-22 19:18:27 -08:00
sanitizationConfig :
config.sanitizationConfig ? ?
this . shellExecutionConfig . sanitizationConfig ,
2025-09-11 13:27:27 -07:00
} ;
}
2025-08-21 22:29:15 +00:00
getScreenReader ( ) : boolean {
return this . accessibility . screenReader ? ? false ;
}
2025-09-05 15:37:29 -07:00
getTruncateToolOutputThreshold ( ) : number {
2025-09-12 15:11:41 -07:00
return Math . min (
// Estimate remaining context window in characters (1 token ~= 4 chars).
4 *
( tokenLimit ( this . model ) - uiTelemetryService . getLastPromptTokenCount ( ) ) ,
this . truncateToolOutputThreshold ,
) ;
2025-09-05 15:37:29 -07:00
}
2026-01-18 22:40:07 -08:00
getNextCompressionTruncationId ( ) : number {
return ++ this . compressionTruncationCounter ;
}
2025-09-20 06:01:02 -07:00
getUseWriteTodos ( ) : boolean {
return this . useWriteTodos ;
}
2025-09-11 05:19:47 +09:00
getOutputFormat ( ) : OutputFormat {
return this . outputSettings ? . format
? this . outputSettings.format
: OutputFormat.TEXT ;
}
2025-06-11 15:33:09 -04:00
async getGitService ( ) : Promise < GitService > {
if ( ! this . gitService ) {
2025-08-20 10:55:47 +09:00
this . gitService = new GitService ( this . targetDir , this . storage ) ;
2025-06-11 15:33:09 -04:00
await this . gitService . initialize ( ) ;
}
return this . gitService ;
}
2025-07-07 16:45:44 -04:00
2025-08-23 13:35:00 +09:00
getFileExclusions ( ) : FileExclusions {
return this . fileExclusions ;
}
2025-09-11 09:39:17 -07:00
getMessageBus ( ) : MessageBus {
return this . messageBus ;
}
getPolicyEngine ( ) : PolicyEngine {
return this . policyEngine ;
}
2025-11-02 11:49:16 -08:00
getEnableHooks ( ) : boolean {
return this . enableHooks ;
}
2026-01-07 12:34:33 -08:00
getEnableHooksUI ( ) : boolean {
return this . enableHooksUI ;
}
2026-02-24 09:22:09 -08:00
/**
* Get override settings for a specific agent.
* Reads from agents.overrides.<agentName>.
*/
getAgentOverride ( agentName : string ) : AgentOverride | undefined {
return this . getAgentsSettings ( ) ? . overrides ? . [ agentName ] ;
}
/**
* Get browser agent configuration.
* Combines generic AgentOverride fields with browser-specific customConfig.
* This is the canonical way to access browser agent settings.
*/
getBrowserAgentConfig ( ) : {
enabled : boolean ;
model? : string ;
customConfig : BrowserAgentCustomConfig ;
} {
const override = this . getAgentOverride ( 'browser_agent' ) ;
const customConfig = this . getAgentsSettings ( ) ? . browser ? ? { } ;
return {
enabled : override?.enabled ? ? false ,
model : override?.modelConfig?.model ,
customConfig : {
sessionMode : customConfig.sessionMode ? ? 'persistent' ,
headless : customConfig.headless ? ? false ,
profilePath : customConfig.profilePath ,
visualModel : customConfig.visualModel ,
} ,
} ;
}
2025-07-07 15:01:59 -07:00
async createToolRegistry ( ) : Promise < ToolRegistry > {
2026-01-04 17:11:43 -05:00
const registry = new ToolRegistry ( this , this . messageBus ) ;
2025-10-28 09:20:57 -07:00
2025-07-07 15:01:59 -07:00
// helper to create & register core tools that are enabled
2026-02-09 21:53:10 -05:00
const maybeRegister = (
toolClass : { name : string ; Name? : string } ,
registerFn : ( ) = > void ,
) = > {
const className = toolClass . name ;
const toolName = toolClass . Name || className ;
2025-07-07 15:01:59 -07:00
const coreTools = this . getCoreTools ( ) ;
2025-09-03 19:23:25 -07:00
// On some platforms, the className can be minified to _ClassName.
const normalizedClassName = className . replace ( /^_+/ , '' ) ;
2025-07-07 15:01:59 -07:00
2025-08-27 02:17:43 +10:00
let isEnabled = true ; // Enabled by default if coreTools is not set.
if ( coreTools ) {
2025-07-07 15:01:59 -07:00
isEnabled = coreTools . some (
( tool ) = >
tool === toolName ||
2025-09-03 19:23:25 -07:00
tool === normalizedClassName ||
tool . startsWith ( ` ${ toolName } ( ` ) ||
tool . startsWith ( ` ${ normalizedClassName } ( ` ) ,
2025-07-07 15:01:59 -07:00
) ;
}
if ( isEnabled ) {
2026-02-09 21:53:10 -05:00
registerFn ( ) ;
2025-07-07 15:01:59 -07:00
}
} ;
2025-06-29 15:32:26 -04:00
2026-02-09 21:53:10 -05:00
maybeRegister ( LSTool , ( ) = >
registry . registerTool ( new LSTool ( this , this . messageBus ) ) ,
) ;
maybeRegister ( ReadFileTool , ( ) = >
registry . registerTool ( new ReadFileTool ( this , this . messageBus ) ) ,
) ;
2025-08-22 14:10:45 +08:00
if ( this . getUseRipgrep ( ) ) {
2025-09-08 14:44:56 -07:00
let useRipgrep = false ;
let errorString : undefined | string = undefined ;
try {
useRipgrep = await canUseRipgrep ( ) ;
} catch ( error : unknown ) {
errorString = String ( error ) ;
}
if ( useRipgrep ) {
2026-02-09 21:53:10 -05:00
maybeRegister ( RipGrepTool , ( ) = >
registry . registerTool ( new RipGrepTool ( this , this . messageBus ) ) ,
) ;
2025-09-08 14:44:56 -07:00
} else {
logRipgrepFallback ( this , new RipgrepFallbackEvent ( errorString ) ) ;
2026-02-09 21:53:10 -05:00
maybeRegister ( GrepTool , ( ) = >
registry . registerTool ( new GrepTool ( this , this . messageBus ) ) ,
) ;
2025-09-08 14:44:56 -07:00
}
2025-08-22 14:10:45 +08:00
} else {
2026-02-09 21:53:10 -05:00
maybeRegister ( GrepTool , ( ) = >
registry . registerTool ( new GrepTool ( this , this . messageBus ) ) ,
) ;
2025-08-22 14:10:45 +08:00
}
2026-02-09 21:53:10 -05:00
maybeRegister ( GlobTool , ( ) = >
registry . registerTool ( new GlobTool ( this , this . messageBus ) ) ,
) ;
maybeRegister ( ActivateSkillTool , ( ) = >
registry . registerTool ( new ActivateSkillTool ( this , this . messageBus ) ) ,
) ;
maybeRegister ( EditTool , ( ) = >
registry . registerTool ( new EditTool ( this , this . messageBus ) ) ,
) ;
maybeRegister ( WriteFileTool , ( ) = >
registry . registerTool ( new WriteFileTool ( this , this . messageBus ) ) ,
) ;
maybeRegister ( WebFetchTool , ( ) = >
registry . registerTool ( new WebFetchTool ( this , this . messageBus ) ) ,
) ;
maybeRegister ( ShellTool , ( ) = >
registry . registerTool ( new ShellTool ( this , this . messageBus ) ) ,
) ;
maybeRegister ( MemoryTool , ( ) = >
registry . registerTool ( new MemoryTool ( this . messageBus ) ) ,
) ;
maybeRegister ( WebSearchTool , ( ) = >
registry . registerTool ( new WebSearchTool ( this , this . messageBus ) ) ,
) ;
maybeRegister ( AskUserTool , ( ) = >
registry . registerTool ( new AskUserTool ( this . messageBus ) ) ,
) ;
2025-09-20 06:01:02 -07:00
if ( this . getUseWriteTodos ( ) ) {
2026-02-09 21:53:10 -05:00
maybeRegister ( WriteTodosTool , ( ) = >
registry . registerTool ( new WriteTodosTool ( this . messageBus ) ) ,
) ;
2025-09-20 06:01:02 -07:00
}
2026-02-02 22:30:03 -05:00
if ( this . isPlanEnabled ( ) ) {
2026-02-09 21:53:10 -05:00
maybeRegister ( ExitPlanModeTool , ( ) = >
registry . registerTool ( new ExitPlanModeTool ( this , this . messageBus ) ) ,
) ;
maybeRegister ( EnterPlanModeTool , ( ) = >
registry . registerTool ( new EnterPlanModeTool ( this , this . messageBus ) ) ,
) ;
2026-02-02 22:30:03 -05:00
}
2025-05-17 19:45:16 -07:00
2025-10-01 16:54:00 -04:00
// Register Subagents as Tools
2026-01-23 02:18:31 +00:00
this . registerSubAgentTools ( registry ) ;
2026-01-12 12:11:24 -05:00
await registry . discoverAllTools ( ) ;
registry . sortTools ( ) ;
return registry ;
}
/**
2026-01-23 02:18:31 +00:00
* Registers SubAgentTools for all available agents.
2026-01-12 12:11:24 -05:00
*/
2026-01-23 02:18:31 +00:00
private registerSubAgentTools ( registry : ToolRegistry ) : void {
2026-01-22 12:59:47 -08:00
const agentsOverrides = this . getAgentsSettings ( ) . overrides ? ? { } ;
2025-12-10 16:14:13 -05:00
if (
this . isAgentsEnabled ( ) ||
2026-01-22 12:59:47 -08:00
agentsOverrides [ 'codebase_investigator' ] ? . enabled !== false ||
agentsOverrides [ 'cli_help' ] ? . enabled !== false
2025-12-10 16:14:13 -05:00
) {
2026-01-23 02:18:31 +00:00
const definitions = this . agentRegistry . getAllDefinitions ( ) ;
for ( const definition of definitions ) {
2026-02-11 20:12:01 -06:00
try {
const tool = new SubagentTool ( definition , this , this . getMessageBus ( ) ) ;
registry . registerTool ( tool ) ;
} catch ( e : unknown ) {
debugLogger . warn (
` Failed to register tool for agent ${ definition . name } : ${ getErrorMessage ( e ) } ` ,
) ;
2026-01-23 02:18:31 +00:00
}
2025-10-01 16:54:00 -04:00
}
}
2025-07-07 15:01:59 -07:00
}
2025-11-02 11:49:16 -08:00
2025-11-24 14:31:48 -08:00
/**
* Get the hook system instance
*/
getHookSystem ( ) : HookSystem | undefined {
return this . hookSystem ;
}
2025-11-02 11:49:16 -08:00
/**
* Get hooks configuration
*/
getHooks ( ) : { [ K in HookEventName ] ? : HookDefinition [ ] } | undefined {
return this . hooks ;
}
2025-11-04 15:09:53 -08:00
2025-12-23 16:10:46 -05:00
/**
* Get project-specific hooks configuration
*/
2026-01-20 14:47:31 -08:00
getProjectHooks ( ) : { [ K in HookEventName ] ? : HookDefinition [ ] } | undefined {
2025-12-23 16:10:46 -05:00
return this . projectHooks ;
}
2026-01-16 19:28:36 -05:00
/**
* Update the list of disabled hooks dynamically.
* This is used to keep the running system in sync with settings changes
* without risk of loading new hook definitions into memory.
*/
updateDisabledHooks ( disabledHooks : string [ ] ) : void {
this . disabledHooks = disabledHooks ;
}
2025-12-03 10:01:57 -08:00
/**
* Get disabled hooks list
*/
getDisabledHooks ( ) : string [ ] {
return this . disabledHooks ;
}
2025-11-04 15:09:53 -08:00
/**
* Get experiments configuration
*/
getExperiments ( ) : Experiments | undefined {
return this . experiments ;
}
/**
* Set experiments configuration
*/
setExperiments ( experiments : Experiments ) : void {
this . experiments = experiments ;
2025-11-10 23:15:38 -05:00
const flagSummaries = Object . entries ( experiments . flags ? ? { } )
. sort ( ( [ a ] , [ b ] ) = > a . localeCompare ( b ) )
2025-11-14 13:34:54 -08:00
. map ( ( [ flagId , flag ] ) = > {
const summary : Record < string , unknown > = { flagId } ;
2025-11-10 23:15:38 -05:00
if ( flag . boolValue !== undefined ) {
summary [ 'boolValue' ] = flag . boolValue ;
}
if ( flag . floatValue !== undefined ) {
summary [ 'floatValue' ] = flag . floatValue ;
}
if ( flag . intValue !== undefined ) {
summary [ 'intValue' ] = flag . intValue ;
}
if ( flag . stringValue !== undefined ) {
summary [ 'stringValue' ] = flag . stringValue ;
}
const int32Length = flag . int32ListValue ? . values ? . length ? ? 0 ;
if ( int32Length > 0 ) {
summary [ 'int32ListLength' ] = int32Length ;
}
const stringListLength = flag . stringListValue ? . values ? . length ? ? 0 ;
if ( stringListLength > 0 ) {
summary [ 'stringListLength' ] = stringListLength ;
}
return summary ;
} ) ;
const summary = {
experimentIds : experiments.experimentIds ? ? [ ] ,
flags : flagSummaries ,
} ;
const summaryString = inspect ( summary , {
depth : null ,
maxArrayLength : null ,
maxStringLength : null ,
breakLength : 80 ,
compact : false ,
} ) ;
debugLogger . debug ( 'Experiments loaded' , summaryString ) ;
2025-11-04 15:09:53 -08:00
}
2026-01-12 12:11:24 -05:00
private onAgentsRefreshed = async ( ) = > {
if ( this . toolRegistry ) {
2026-01-23 02:18:31 +00:00
this . registerSubAgentTools ( this . toolRegistry ) ;
2026-01-12 12:11:24 -05:00
}
// Propagate updates to the active chat session
const client = this . getGeminiClient ( ) ;
if ( client ? . isInitialized ( ) ) {
await client . setTools ( ) ;
2026-01-26 18:45:24 -05:00
client . updateSystemInstruction ( ) ;
2026-01-12 12:11:24 -05:00
} else {
debugLogger . debug (
'[Config] GeminiClient not initialized; skipping live prompt/tool refresh.' ,
) ;
}
} ;
/**
* Disposes of resources and removes event listeners.
*/
async dispose ( ) : Promise < void > {
2026-01-20 13:57:34 -05:00
this . logCurrentModeDuration ( this . getApprovalMode ( ) ) ;
2026-01-12 12:11:24 -05:00
coreEvents . off ( CoreEvent . AgentsRefreshed , this . onAgentsRefreshed ) ;
2026-01-20 01:25:15 -05:00
this . agentRegistry ? . dispose ( ) ;
this . geminiClient ? . dispose ( ) ;
2026-01-12 12:11:24 -05:00
if ( this . mcpClientManager ) {
await this . mcpClientManager . stop ( ) ;
}
}
2025-04-21 12:59:31 -07:00
}
2025-06-24 18:48:55 -04:00
// Export model constants for use in CLI
export { DEFAULT_GEMINI_FLASH_MODEL } ;