@@ -1703,10 +1703,10 @@ function releaseRetryAttachmentPayload(retryId) {
17031703
17041704function releaseRetryAttachmentsInTree ( root ) {
17051705 if ( ! root ) return ;
1706- if ( root . matches ?. ( '.error-retry-btn[data-retry-id], .cost-allowance-retry-btn[data-retry-id]' ) ) {
1706+ if ( root . matches ?. ( '.error-retry-btn[data-retry-id], .cost-allowance-retry-btn[data-retry-id], .planner-request-failure-retry-btn[data-retry-id] ' ) ) {
17071707 releaseRetryAttachmentPayload ( root . dataset . retryId ) ;
17081708 }
1709- root . querySelectorAll ?. ( '.error-retry-btn[data-retry-id], .cost-allowance-retry-btn[data-retry-id]' ) . forEach ( ( btn ) => {
1709+ root . querySelectorAll ?. ( '.error-retry-btn[data-retry-id], .cost-allowance-retry-btn[data-retry-id], .planner-request-failure-retry-btn[data-retry-id] ' ) . forEach ( ( btn ) => {
17101710 releaseRetryAttachmentPayload ( btn . dataset . retryId ) ;
17111711 } ) ;
17121712}
@@ -3738,6 +3738,15 @@ async function adoptRestoredRunState(tabId, state) {
37383738 probeFirst : true ,
37393739 requireDurableSubmittedTurn : runUi . kind !== 'continue' ,
37403740 } ) ;
3741+ const returnedPlannerFailure = plannerRequestFailureUpdate ( res ?. updates ) ;
3742+ if ( returnedPlannerFailure && sameTabId ( currentTabId , tabId ) && ! isTabAbortRequested ( tabId ) ) {
3743+ const targetAssistantEl = assistantEl || currentAssistantEl ;
3744+ renderPlannerRequestFailure (
3745+ targetAssistantEl ,
3746+ returnedPlannerFailure . data ,
3747+ retryPayloadForRunAssistant ( targetAssistantEl ) ,
3748+ ) ;
3749+ }
37413750 const returnedErrorUpdate = Array . isArray ( res ?. updates )
37423751 ? res . updates . find ( update => update ?. type === 'error' )
37433752 : null ;
@@ -5165,7 +5174,7 @@ function bindErrorRetryButton(btn) {
51655174}
51665175
51675176function rebindRetryButtons ( ) {
5168- document . querySelectorAll ( '.error-retry-btn' ) . forEach ( bindErrorRetryButton ) ;
5177+ document . querySelectorAll ( '.error-retry-btn, .planner-request-failure-retry-btn ' ) . forEach ( bindErrorRetryButton ) ;
51695178}
51705179
51715180function createActiveChatPayloadState ( retryPayload , requestId = '' ) {
@@ -5204,6 +5213,81 @@ function retryPayloadForRunAssistant(assistantEl) {
52045213 } ;
52055214}
52065215
5216+ function plannerRequestFailureUpdate ( updates = [ ] ) {
5217+ if ( ! Array . isArray ( updates ) ) return null ;
5218+ return updates . find ( update => (
5219+ update ?. type === 'warning'
5220+ && update ?. data ?. code === 'planner_request_failed'
5221+ ) ) || null ;
5222+ }
5223+
5224+ function bindPlannerProviderSettingsButton ( btn ) {
5225+ if ( ! btn || btn . dataset . bound ) return ;
5226+ btn . dataset . bound = 'true' ;
5227+ btn . addEventListener ( 'click' , async ( event ) => {
5228+ event . preventDefault ( ) ;
5229+ event . stopPropagation ( ) ;
5230+ btn . disabled = true ;
5231+ try {
5232+ await openProvidersSettingsPage ( ) ;
5233+ } finally {
5234+ btn . disabled = false ;
5235+ }
5236+ } ) ;
5237+ }
5238+
5239+ function rebindPlannerRequestFailureControls ( ) {
5240+ document . querySelectorAll ( '.planner-request-failure-provider-btn' )
5241+ . forEach ( bindPlannerProviderSettingsButton ) ;
5242+ }
5243+
5244+ function renderPlannerRequestFailure ( assistantEl , data , retryPayload = null ) {
5245+ if ( ! assistantEl || data ?. code !== 'planner_request_failed' ) return false ;
5246+ const textEl = assistantEl . querySelector ( '.message-text' ) ;
5247+ if ( ! textEl ) return false ;
5248+ if ( textEl . querySelector ( '.planner-request-failure-actions' ) ) return true ;
5249+
5250+ clearAssistantTextStreamState ( assistantEl ) ;
5251+ assistantEl . classList . add ( 'planner-request-failure' ) ;
5252+ textEl . classList . add ( 'planner-request-failure-content' ) ;
5253+ textEl . replaceChildren ( ) ;
5254+
5255+ const message = document . createElement ( 'div' ) ;
5256+ message . className = 'planner-request-failure-message' ;
5257+ message . textContent = data . message || 'Planner request failed before a valid response was available.' ;
5258+
5259+ const actions = document . createElement ( 'div' ) ;
5260+ actions . className = 'planner-request-failure-actions' ;
5261+
5262+ const retryBtn = document . createElement ( 'button' ) ;
5263+ retryBtn . type = 'button' ;
5264+ retryBtn . className = 'planner-request-failure-action planner-request-failure-retry-btn' ;
5265+ retryBtn . textContent = t ( 'sp.retry' ) ;
5266+ retryBtn . title = t ( 'sp.retry' ) ;
5267+ retryBtn . setAttribute ( 'aria-label' , t ( 'sp.retry' ) ) ;
5268+ const retryReady = configureRetryButton ( retryBtn , retryPayload ) ;
5269+
5270+ const providerBtn = document . createElement ( 'button' ) ;
5271+ providerBtn . type = 'button' ;
5272+ providerBtn . className = 'planner-request-failure-action planner-request-failure-provider-btn' ;
5273+ providerBtn . textContent = t ( 'st.tab.providers' ) ;
5274+ providerBtn . title = `${ t ( 'sp.btn.settings' ) } : ${ t ( 'st.tab.providers' ) } ` ;
5275+ providerBtn . setAttribute ( 'aria-label' , providerBtn . title ) ;
5276+ bindPlannerProviderSettingsButton ( providerBtn ) ;
5277+
5278+ const orderedActions = data . failureKind === 'auth'
5279+ ? [ providerBtn , retryReady ? retryBtn : null ]
5280+ : [ retryReady ? retryBtn : null , providerBtn ] ;
5281+ const visibleActions = orderedActions . filter ( Boolean ) ;
5282+ visibleActions [ 0 ] ?. classList . add ( 'primary' ) ;
5283+ visibleActions . forEach ( btn => actions . appendChild ( btn ) ) ;
5284+
5285+ textEl . append ( message , actions ) ;
5286+ addMessageCopyButton ( assistantEl ) ;
5287+ scrollToBottom ( ) ;
5288+ return true ;
5289+ }
5290+
52075291function clearActiveChatPayloadForTab ( tabId ) {
52085292 if ( tabId != null ) activeChatPayloadsByTab . delete ( tabId ) ;
52095293}
@@ -5262,6 +5346,7 @@ function rebindRestoredMessageControls() {
52625346 rebindCopyButtons ( ) ;
52635347 rebindScreenshotSaveButtons ( ) ;
52645348 rebindRetryButtons ( ) ;
5349+ rebindPlannerRequestFailureControls ( ) ;
52655350 rebindContinueButtons ( ) ;
52665351 rebindClarifyCards ( ) ;
52675352 rebindPlanReviewCards ( ) ;
@@ -6989,6 +7074,14 @@ async function sendMessage(extraChatParams = {}) {
69897074 accepted = true ;
69907075 completedSuccessfully = res ?. successfulDone === true || updatesContainSuccessfulDone ( res ?. updates ) ;
69917076 promptEligibleCompletion = completedSuccessfully || isSuccessfulAskCompletion ( modeForSend , res ) ;
7077+ const returnedPlannerFailure = plannerRequestFailureUpdate ( res ?. updates ) ;
7078+ if ( returnedPlannerFailure
7079+ && renderToCurrentTab
7080+ && currentTabId === tabId
7081+ && ! isTabAbortRequested ( tabId )
7082+ && ! clearedConversationRunRequestIds . has ( requestId ) ) {
7083+ renderPlannerRequestFailure ( assistantEl , returnedPlannerFailure . data , retryPayload ) ;
7084+ }
69927085 const returnedErrorUpdate = Array . isArray ( res ?. updates )
69937086 ? res . updates . find ( u => u ?. type === 'error' )
69947087 : null ;
@@ -7539,7 +7632,12 @@ function handleAgentUpdateMessage(msg) {
75397632
75407633 case 'warning' :
75417634 hideActivity ( ) ;
7542- if ( data ?. code === 'ask_stream_fallback' ) {
7635+ if ( data ?. code === 'planner_request_failed' ) {
7636+ const targetAssistantEl = eventAssistantEl || currentAssistantEl ;
7637+ const retryPayload = activeRetryPayloadForRequest ( eventTabId , msg . requestId )
7638+ || retryPayloadForRunAssistant ( targetAssistantEl ) ;
7639+ renderPlannerRequestFailure ( targetAssistantEl , data , retryPayload ) ;
7640+ } else if ( data ?. code === 'ask_stream_fallback' ) {
75437641 showComposerToast ( t ( 'sp.streaming.fallback' ) , { duration : 6000 } ) ;
75447642 }
75457643 break ;
0 commit comments