Skip to content

perf: skip loadCliConfig + refreshAuth in parent for non-sandbox startup#24804

Open
bzqzheng wants to merge 2 commits intogoogle-gemini:mainfrom
bzqzheng:perf/skip-parent-config-auth
Open

perf: skip loadCliConfig + refreshAuth in parent for non-sandbox startup#24804
bzqzheng wants to merge 2 commits intogoogle-gemini:mainfrom
bzqzheng:perf/skip-parent-config-auth

Conversation

@bzqzheng
Copy link
Copy Markdown

@bzqzheng bzqzheng commented Apr 7, 2026

Summary

Skip loadCliConfig and refreshAuth in the parent process for the non-sandbox startup path, eliminating ~500-1000ms of duplicated work on every startup.

Details

In the common non-sandbox case, the parent process previously ran the full loadCliConfig (extension loading, hierarchical memory search, policy engine construction) and refreshAuth (3-5 network calls) before relaunching the child — which then repeated all of the same work from scratch.

This PR restructures gemini.tsx so that:

  • Non-sandbox, no sandbox config → parent skips loadCliConfig/refreshAuth, relaunches immediately. The child handles all initialization.
  • Sandbox path → completely unchanged. Full config + auth still runs before sandbox entry.
  • Inside sandbox or command mode → unchanged. Full config + auth runs normally.

The key insight: the parent only needs settings and memoryArgs to call relaunchAppInChildProcess. The partialConfig, refreshAuth, remoteAdminSettings, and runDeferredCommand are only consumed by the sandbox branch or are re-done by the child.

Closes #24776

How to Validate

  1. npm run build — should pass (verified)
  2. Run gemini interactively — should start normally, no auth issues
  3. Run with --sandbox flag — sandbox path should be unchanged
  4. Run with a prompt command (-p "hello") — non-interactive mode should work
  5. Compare startup time before/after — expect ~500-1000ms improvement

Pre-Merge Checklist

  • Noted breaking changes (if any): None — behavioral change is purely a performance optimization
  • Validated on required platforms/methods:
    • MacOS
      • npm run

@google-cla
Copy link
Copy Markdown

google-cla bot commented Apr 7, 2026

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

@bzqzheng bzqzheng marked this pull request as ready for review April 7, 2026 14:23
@bzqzheng bzqzheng requested a review from a team as a code owner April 7, 2026 14:23
@gemini-code-assist
Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request optimizes the CLI startup sequence by deferring heavy initialization tasks to the child process in non-sandbox environments. By eliminating redundant configuration loading and network-bound authentication calls in the parent process, the application achieves a faster and more efficient launch. The logic remains unchanged for sandbox and command-mode execution paths to ensure compatibility.

Highlights

  • Performance Optimization: Skipped redundant 'loadCliConfig' and 'refreshAuth' calls in the parent process for non-sandbox startup paths, resulting in a 500-1000ms reduction in startup time.
  • Code Restructuring: Refactored 'gemini.tsx' to ensure that configuration and authentication logic only run when necessary, specifically separating the sandbox and non-sandbox initialization flows.
  • Cleanup: Removed unnecessary code comments and streamlined argument handling for stdin processing.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request restructures the CLI startup logic to optimize performance by skipping redundant configuration and authentication during app relaunch. However, the changes introduce significant code duplication and a performance regression where initialization tasks are executed twice when already inside a sandbox. Feedback highlights the need to refactor shared logic into a reusable function to maintain consistency and avoid unnecessary overhead.

Comment on lines 445 to 501
} else {
// Non-relaunch path (sandbox env or command mode): auth is needed here
// because we won't be relaunching.
const partialConfig = await loadCliConfig(
settings.merged,
sessionId,
argv,
{
projectHooks: settings.workspace.settings.hooks,
},
);
adminControlsListner.setConfig(partialConfig);

if (!settings.merged.security.auth.useExternal && !argv.isCommand) {
try {
if (
partialConfig.isInteractive() &&
settings.merged.security.auth.selectedType
) {
const err = validateAuthMethod(
settings.merged.security.auth.selectedType,
);
if (err) {
throw new Error(err);
}

await partialConfig.refreshAuth(
settings.merged.security.auth.selectedType,
);
} else if (!partialConfig.isInteractive()) {
const authType = await validateNonInteractiveAuth(
settings.merged.security.auth.selectedType,
settings.merged.security.auth.useExternal,
partialConfig,
settings,
);
await partialConfig.refreshAuth(authType);
}
} catch (err) {
if (err instanceof ValidationCancelledError) {
await runExitCleanup();
process.exit(ExitCodes.SUCCESS);
}

if (!(err instanceof ValidationRequiredError)) {
debugLogger.error('Error authenticating:', err);
}
}
}

const remoteAdminSettings = partialConfig.getRemoteAdminSettings();
if (remoteAdminSettings) {
settings.setRemoteAdminSettings(remoteAdminSettings);
}

await runDeferredCommand(settings.merged);
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

This else block introduces a performance regression for the sandbox environment. When process.env['SANDBOX'] is true (meaning we are already executing inside the sandbox), this block performs a full loadCliConfig and refreshAuth. However, the execution then continues to line 508, where loadCliConfig is called a second time, and later to initializeApp (line 602) which performs authentication again. Since this PR's objective is to optimize startup time, performing these expensive operations twice inside the sandbox is counterproductive. This block should be skipped if process.env['SANDBOX'] is true, as the main initialization starting at line 507 handles this correctly.

References
  1. When the application relaunches into a sandbox, it re-executes the main function. This re-execution includes the logic for fetching and applying remote admin settings, making it unnecessary to perform these steps manually before the main initialization.

Copy link
Copy Markdown
Author

@bzqzheng bzqzheng Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not a new regression. The double load when SANDBOX=true is pre-existing behavior. The old code ran loadCliConfig unconditionally at line ~327 (before the sandbox branch), then again at line ~507. Both old and new code execute it twice in this path. Skipping the else block would break things: it also calls getRemoteAdminSettings() and runDeferredCommand() which are needed before the main init at line 507.

Comment on lines +448 to +500
const partialConfig = await loadCliConfig(
settings.merged,
sessionId,
argv,
{
projectHooks: settings.workspace.settings.hooks,
},
);
adminControlsListner.setConfig(partialConfig);

if (!settings.merged.security.auth.useExternal && !argv.isCommand) {
try {
if (
partialConfig.isInteractive() &&
settings.merged.security.auth.selectedType
) {
const err = validateAuthMethod(
settings.merged.security.auth.selectedType,
);
if (err) {
throw new Error(err);
}

await partialConfig.refreshAuth(
settings.merged.security.auth.selectedType,
);
} else if (!partialConfig.isInteractive()) {
const authType = await validateNonInteractiveAuth(
settings.merged.security.auth.selectedType,
settings.merged.security.auth.useExternal,
partialConfig,
settings,
);
await partialConfig.refreshAuth(authType);
}
} catch (err) {
if (err instanceof ValidationCancelledError) {
await runExitCleanup();
process.exit(ExitCodes.SUCCESS);
}

if (!(err instanceof ValidationRequiredError)) {
debugLogger.error('Error authenticating:', err);
}
}
}

const remoteAdminSettings = partialConfig.getRemoteAdminSettings();
if (remoteAdminSettings) {
settings.setRemoteAdminSettings(remoteAdminSettings);
}

await runDeferredCommand(settings.merged);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The logic for loading configuration, refreshing authentication, and handling remote admin settings is now duplicated between the if (sandboxConfig) block (lines 345-400) and this else block. This duplication increases maintenance overhead and has already introduced inconsistencies, such as the missing initialAuthFailed check in this second block. Please refactor this shared initialization logic into a reusable function or restructure the control flow to avoid duplication.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch on the duplication — addressing in a follow-up commit by extracting a performEarlyInit() function. Re: the missing initialAuthFailed: this is intentional, not a bug. The sandbox path needs a hard exit (FATAL_AUTHENTICATION_ERROR) before entering the sandbox because it blocks OAuth redirects. The else path falls through to the full init at line ~507 which handles auth independently, so an early fatal exit would be wrong.

bzqzheng added 2 commits April 8, 2026 12:50
In the common non-sandbox case, the parent process now skips expensive
initialization (loadCliConfig, refreshAuth) and relaunches immediately.
The child process handles all initialization on its own.

Previously, the parent loaded full config (extensions, hierarchical
memory search, policy engine) and made 3-5 network calls (OAuth,
quota, experiments, admin controls) only to discard everything when
spawning the child — which then repeated the same work.

This eliminates ~500-1000ms of duplicated work on every startup.

The sandbox path is completely unchanged.

Closes google-gemini#24776
The sandbox and non-relaunch code paths had identical ~40-line blocks
for loadCliConfig, refreshAuth, getRemoteAdminSettings, and
runDeferredCommand. Extract into performEarlyInit() which returns
{ partialConfig, authFailed } so callers can choose their error
handling strategy.

Behavioral change: the else block (SANDBOX env / command mode) now
tracks authFailed (previously it silently swallowed auth errors).
This is safe because the fallback path at line ~507 handles auth
independently — the early failure just means the pre-init attempt
didn't succeed.
@bzqzheng bzqzheng force-pushed the perf/skip-parent-config-auth branch from 2b9a365 to 51865fd Compare April 8, 2026 16:51
@bzqzheng
Copy link
Copy Markdown
Author

bzqzheng commented Apr 8, 2026

@jacob314 @scidomino — PTAL. This is a perf optimization that skips loadCliConfig + refreshAuth in the parent process for the non-sandbox startup path (~500-1000ms improvement). Addresses the duplication concern from automated review in a follow-up commit (extracted performEarlyInit()).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

perf: skip loadCliConfig + refreshAuth in parent process for non-sandbox startup

1 participant