Skip to content

feat(amazonq): initialize Q services when credentials arrive - #2840

Merged
ashishrp-aws merged 1 commit into
Amazon-Q-Developer:mainfrom
ashishrp-aws:feat/init-services-on-credentials-update
Aug 17, 2026
Merged

feat(amazonq): initialize Q services when credentials arrive#2840
ashishrp-aws merged 1 commit into
Amazon-Q-Developer:mainfrom
ashishrp-aws:feat/init-services-on-credentials-update

Conversation

@ashishrp-aws

Copy link
Copy Markdown
Collaborator

Depends on @aws/language-server-runtimes 0.3.21 (Amazon-Q-Developer/language-server-runtimes#779), which is published. Dependency floor bumped from ^0.3.19.

Problem

The token service issues its first service call from its constructor, and the service is built lazily by whichever consumer asks first. In practice that consumer is the chat webview finishing boot. From a real session:

08.176  Runtime: Successfully saved bearer credentials
08.838  chat reports ui-is-ready  ->  aws/chat/ready
08.840  "Detected New connection type: builderId"  ->  services built
09.740  first service response

~0.66s in which nothing has contacted the service. For an identity the service rejects, that is 0.66s of a user sitting in front of a chat view that is never going to work, before we can tell them why.

The dead code this replaces was reaching for exactly this event:

if ('onCredentialsUpdated' in credentialsProvider) {
    ;(credentialsProvider as any).onCredentialsUpdated(...)

Added in #2521, guarded by an in check and an any cast, and never fired because the runtime had no such member.

Change

handleOnCredentialsUpdated now calls handleSsoConnectionChange() — the same function the lazy path calls. This changes when initialization happens, not how. It also removes the any cast and the capability check in favour of optional chaining, so a build running on an older runtime simply never receives the event.

Regression analysis

I checked these rather than assuming them:

Concern Finding
Token refresh rebuilding live services createCodewhispererServiceInstances records the connection type, so later calls short-circuit on "Connection type did not change". Without this, every refresh would reset services, dropping in-flight requests and replacing the instance observers are attached to. Test asserts the same instance survives three events
IdC requesting before a profile exists The IdC branch stops at PENDING_Q_PROFILE and builds nothing, so no request is made until a profile arrives. Test asserts this
Opt-out header on an early request shareCodeWhispererContentWithAWS defaults to false, and configuration is read at onInitialized, long before sign-in. An earlier request cannot leak content for a user who opted out
Connection type accuracy The runtime awaits handleBearerCredentialsMetadata before setCredentials, which is where the event fires, so getConnectionType() is already correct
Throwing inside the credentials request Caught and logged. The runtime also guards handler exceptions. The lazy path still runs for whoever asks first, so a failure costs the head start and nothing else
IAM Ignored via a type guard

Behaviour changes: Builder ID and IdC-without-profiles build services ~0.66s earlier; ProfileStatusMonitor.emitAuthSuccess — and therefore MCP registry sync — fires ~0.66s earlier.

Testing

  • 5 new tests: eager init without a consumer, idempotence across three events, IAM ignored, IdC stops at PENDING_Q_PROFILE, no throw without credentials
  • AmazonQTokenServiceManager: 40 passing / 3 failing vs 35 / 3 on main
  • shared group: 342 / 45 vs 337 / 45 on main
  • The 3 and 45 pre-existing failures are unchanged, verified by stashing and re-running
  • tsc and prettier clean, against the published 0.3.21 rather than a locally patched copy

Branched from current main (43e44dc5a).

Known limitation

This removes the ~0.66s wait, not the service round trip, so a rejected identity is discovered in roughly 0.9s rather than 1.5s. Fully eliminating the window means holding the chat reveal until the first call resolves, which would stall every healthy sign-in — a separate product decision.

One thing worth a real-IDE check before merge: the block notification can now arrive while the JetBrains chat webview is still booting rather than after it, so the panel swap may overlap chat panel construction. VS Code is unaffected, since its login view is driven by context keys.

The token service issues its first service call from its constructor, and the service is
built lazily by whichever consumer asks first. That consumer is the chat webview finishing
boot, measured at ~0.66s after the credentials landed. Nothing contacts the service in
that window, so a rejected identity cannot be discovered and the user sits in front of a
chat view that is never going to work.

Uses onCredentialsUpdated, added in language-server-runtimes 0.3.21, to build the services
as soon as bearer credentials arrive. The dead code this replaces -- an `in` check plus an
`any` cast, added in Amazon-Q-Developer#2521 -- was reaching for this event before the runtime had it, so it
never fired.

Reuses handleSsoConnectionChange rather than constructing anything, so this changes only
when initialization happens, not how:

- Idempotent. createCodewhispererServiceInstances records the connection type, so the
  consumer's later call short-circuits instead of resetting live services. This matters
  beyond tidiness: the event fires on every token refresh, and rebuilding would drop
  in-flight requests and replace the service that observers are attached to.
- IdC with developer profiles still stops at PENDING_Q_PROFILE and builds nothing, so no
  request is made before a profile is chosen.
- IAM updates are ignored.
- Failures are logged, not thrown: this runs inside the client's credentials request, and
  the lazy path still runs for whoever asks first, so a failure costs the head start only.

Checked for regressions rather than assumed: the opt-out header defaults to the
conservative value and configuration is read at onInitialized, long before sign-in, so an
earlier request cannot leak content for a user who opted out. getConnectionType is accurate
because the runtime awaits connection metadata before storing credentials.

One behaviour change worth noting: ProfileStatusMonitor.emitAuthSuccess, and therefore MCP
registry sync, now fires ~0.66s earlier.

Tests: AmazonQTokenServiceManager 40 passing/3 failing against 35/3 on main; shared group
342/45 against 337/45. The 3 and 45 are pre-existing and unchanged.
@ashishrp-aws
ashishrp-aws requested a review from a team as a code owner August 17, 2026 21:20
@ashishrp-aws
ashishrp-aws merged commit 4e0d3b0 into Amazon-Q-Developer:main Aug 17, 2026
8 of 9 checks passed
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.

3 participants