From 77404ce08692a98a661e559c3c3bd8c81c484fa3 Mon Sep 17 00:00:00 2001 From: wangyunyou Date: Sun, 2 Aug 2026 02:36:19 +0800 Subject: [PATCH] perf(credential_pool): skip gh subprocess when all copilot sources suppressed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The all-sources suppression gate now runs before resolve_copilot_token(), which shells out to `gh auth token` (~30ms) on every pool load. A user who suppressed every copilot source (hermes auth remove copilot gh_cli suppresses gh_cli + all env variants) still paid the subprocess spawn on every load — model picker open, /model, agent startup. Enumerate the same source space credential_sources._remove_copilot_gh suppresses and bail before any work when all are suppressed. Measured: model.options payload build drops from ~0.46s to ~0.26s cold for an all-suppressed user; resolve_copilot_token() is no longer called at all. --- agent/credential_pool.py | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/agent/credential_pool.py b/agent/credential_pool.py index 4ccf67fe5a4a0..c12cfee279504 100644 --- a/agent/credential_pool.py +++ b/agent/credential_pool.py @@ -2387,17 +2387,33 @@ def _seed_from_singletons(provider: str, entries: List[PooledCredential]) -> Tup # env vars (COPILOT_GITHUB_TOKEN / GH_TOKEN). They don't live in # the auth store or credential pool, so we resolve them here. try: - from hermes_cli.copilot_auth import resolve_copilot_token, get_copilot_api_token + from hermes_cli.copilot_auth import ( + COPILOT_ENV_VARS, + resolve_copilot_token, + get_copilot_api_token, + ) + # All-sources suppression gate BEFORE any work — including the + # `gh auth token` subprocess spawn. resolve_copilot_token() + # shells out (~30ms), and the exchange retries 3x with backoff + # (~13s worst case); a user who suppressed every copilot source + # (hermes auth remove copilot gh_cli) must not pay either on + # every pool load (model picker open, /model, agent startup). + # Enumerating the full source space here matches what + # credential_sources._remove_copilot_gh suppresses, so an + # all-suppressed check is stable. + copilot_sources = ["gh_cli"] + [f"env:{v}" for v in COPILOT_ENV_VARS] + if all(_is_suppressed(provider, s) for s in copilot_sources): + return changed, active_sources token, source = resolve_copilot_token() if token: source_name = "gh_cli" if "gh" in source.lower() else f"env:{source}" - # Suppression gate BEFORE the network exchange. The - # exchange retries 3x with backoff (~13s worst case), so a - # source the user already suppressed (hermes auth remove - # copilot gh_cli) must not burn that dead time on every pool - # load (model picker open, /model, agent startup) just to - # have the entry discarded afterwards. This is the same - # early-gate pattern every other singleton branch uses. + # Per-source suppression gate (a user may suppress only the + # gh CLI path and keep an env var, or vice versa) BEFORE the + # network exchange. The exchange retries 3x with backoff + # (~13s worst case), so a source the user already suppressed + # must not burn that dead time just to have the entry + # discarded afterwards. Same early-gate pattern every other + # singleton branch uses. if _is_suppressed(provider, source_name): return changed, active_sources api_token, enterprise_base_url = get_copilot_api_token(token)