@@ -29,6 +29,7 @@ import {
2929 InlineChatResultParams ,
3030 PromptInputOptionChangeParams ,
3131 TextDocument ,
32+ ChatUpdateParams ,
3233} from '@aws/language-server-runtimes/protocol'
3334import {
3435 ApplyWorkspaceEditParams ,
@@ -73,7 +74,14 @@ import { ChatSessionManagementService } from '../chat/chatSessionManagementServi
7374import { ChatTelemetryController } from '../chat/telemetry/chatTelemetryController'
7475import { QuickAction } from '../chat/quickActions'
7576import { Metric } from '../../shared/telemetry/metric'
76- import { getErrorMessage , getHttpStatusCode , getRequestID , isAwsError , isNullish , isObject } from '../../shared/utils'
77+ import {
78+ getErrorMessage ,
79+ getHttpStatusCode ,
80+ getRequestID ,
81+ getSsoConnectionType ,
82+ isFreeTierLimitError ,
83+ isNullish ,
84+ } from '../../shared/utils'
7785import { HELP_MESSAGE , loadingMessage } from '../chat/constants'
7886import { TelemetryService } from '../../shared/telemetry/telemetryService'
7987import {
@@ -147,6 +155,7 @@ export class AgenticChatController implements ChatHandlers {
147155 #additionalContextProvider: AdditionalContextProvider
148156 #contextCommandsProvider: ContextCommandsProvider
149157 #stoppedToolUses = new Set < string > ( )
158+ #freeTierLimit = false
150159
151160 /**
152161 * Determines the appropriate message ID for a tool use based on tool type and name
@@ -239,7 +248,15 @@ export class AgenticChatController implements ChatHandlers {
239248 await this . #renderStoppedShellCommand( params . tabId , params . messageId )
240249 return { success : true }
241250 } else if ( params . buttonId === 'upgrade-q' ) {
242- this . #features. logging . warn ( 'clicked upgrade-to-pro-button' )
251+ const awsAccountId = ( params as any ) . awsAccountId
252+ if ( typeof awsAccountId !== 'string' ) {
253+ this . #log( `invalid awsAccountId: ${ awsAccountId } ` )
254+ return {
255+ success : false ,
256+ failureReason : 'invalid awsAccountId' ,
257+ }
258+ }
259+ this . setUpgradeQMode ( params . tabId , 'paidtier' )
243260 return { success : true }
244261 } else {
245262 return {
@@ -1574,6 +1591,12 @@ export class AgenticChatController implements ChatHandlers {
15741591 metric . setDimension ( 'cwsprChatResponseCode' , getHttpStatusCode ( err ) ?? 0 )
15751592 metric . setDimension ( 'languageServerVersion' , this . #features. runtime . serverInfo . version )
15761593
1594+ // TODO handle free tier limit exceeded
1595+ if ( isFreeTierLimitError ( err ) ) {
1596+ this . setUpgradeQMode ( tabId , 'freetier-limit' )
1597+ // throw new AmazonQFreeTierLimitError()
1598+ }
1599+
15771600 // use custom error message for unactionable errors (user-dependent errors like PromptCharacterLimit)
15781601 if ( err . code && err . code in unactionableErrorCodes ) {
15791602 const customErrMessage = unactionableErrorCodes [ err . code as keyof typeof unactionableErrorCodes ]
@@ -1604,7 +1627,7 @@ export class AgenticChatController implements ChatHandlers {
16041627 return createAuthFollowUpResult ( authFollowType )
16051628 }
16061629
1607- if ( customerFacingErrorCodes . includes ( err . code ) ) {
1630+ if ( isFreeTierLimitError ( err ) || customerFacingErrorCodes . includes ( err . code ) ) {
16081631 this . #features. logging . error ( `${ loggingUtils . formatErr ( err ) } ` )
16091632 if ( err . code === 'InputTooLong' ) {
16101633 // Clear the chat history in the database for this tab
@@ -1813,6 +1836,12 @@ export class AgenticChatController implements ChatHandlers {
18131836
18141837 async onReady ( ) {
18151838 await this . #tabBarController. loadChats ( )
1839+ try {
1840+ this . setUpgradeQMode ( )
1841+ } catch ( err ) {
1842+ this . #log( 'Error initializing Free Tier state: ' + ( err as Error ) . message )
1843+ }
1844+
18161845 try {
18171846 const localProjectContextController = await LocalProjectContextController . getInstance ( )
18181847 const contextItems = await localProjectContextController . getContextCommandItems ( )
@@ -1846,6 +1875,8 @@ export class AgenticChatController implements ChatHandlers {
18461875 this . #telemetryController. activeTabId = params . tabId
18471876
18481877 this . #chatSessionManagementService. createSession ( params . tabId )
1878+
1879+ this . setUpgradeQMode ( params . tabId )
18491880 }
18501881
18511882 onTabChange ( params : TabChangeParams ) {
@@ -1860,6 +1891,8 @@ export class AgenticChatController implements ChatHandlers {
18601891 name : ChatTelemetryEventName . EnterFocusConversation ,
18611892 data : { } ,
18621893 } )
1894+
1895+ this . setUpgradeQMode ( params . tabId )
18631896 }
18641897
18651898 onTabRemove ( params : TabRemoveParams ) {
@@ -2004,6 +2037,43 @@ export class AgenticChatController implements ChatHandlers {
20042037 }
20052038 }
20062039
2040+ /**
2041+ * Enables or disables the "Upgrade Q" UI in the chat component.
2042+ *
2043+ * `mode` behavior:
2044+ * - 'freetier': always show "Upgrade Q" button.
2045+ * - 'freetier-limit': also show "Free Tier limit reached" card in chat.
2046+ * - This mode is "sticky" until 'paidtier' is passed to override it.
2047+ * - 'paidtier': don't show "Upgrade Q" button.
2048+ */
2049+ async setUpgradeQMode (
2050+ tabId ?: string ,
2051+ mode ?: 'paidtier' | 'freetier' | 'freetier-limit' /*, session: ChatSessionService*/
2052+ ) {
2053+ if ( mode === 'freetier-limit' ) {
2054+ this . #freeTierLimit = true // Sticky until 'paidtier' is sent.
2055+ } else if ( mode === 'paidtier' ) {
2056+ this . #freeTierLimit = false
2057+ } else if ( this . #freeTierLimit && ( ! mode || mode === 'freetier' ) ) {
2058+ mode = 'freetier-limit'
2059+ } else if ( ! mode ) {
2060+ const isFreeTierUser = getSsoConnectionType ( this . #features. credentialsProvider ) === 'builderId'
2061+ mode = isFreeTierUser ? 'freetier' : 'paidtier'
2062+ }
2063+
2064+ const o : ChatUpdateParams = {
2065+ tabId : tabId ?? 'xxx' ,
2066+ state : { inProgress : false } ,
2067+ data : {
2068+ // Special flag recognized by `chat-client/src/client/mynahUi.ts`.
2069+ placeholderText : 'upgrade-q' ,
2070+ messages : [ ] ,
2071+ } ,
2072+ }
2073+ ; ( o as any ) . upgradeQMode = mode
2074+ this . #features. chat . sendChatUpdate ( o )
2075+ }
2076+
20072077 async #processGenerateAssistantResponseResponseWithTimeout(
20082078 response : GenerateAssistantResponseCommandOutput ,
20092079 metric : Metric < AddMessageEvent > ,
0 commit comments