@@ -10,6 +10,7 @@ import { ConfigKey, IConfigurationService } from '../../../platform/configuratio
1010import { INativeEnvService } from '../../../platform/env/common/envService' ;
1111import { getGitHubRepoInfoFromContext , IGitService } from '../../../platform/git/common/gitService' ;
1212import { ILogService } from '../../../platform/log/common/logService' ;
13+ import { IChatEndpoint } from '../../../platform/networking/common/networking' ;
1314import { IWorkspaceService } from '../../../platform/workspace/common/workspaceService' ;
1415import { CancellationToken } from '../../../util/vs/base/common/cancellation' ;
1516import { Emitter , Event } from '../../../util/vs/base/common/event' ;
@@ -22,12 +23,12 @@ import { IInstantiationService } from '../../../util/vs/platform/instantiation/c
2223import { ClaudeFolderInfo } from '../claude/common/claudeFolderInfo' ;
2324import { ClaudeSessionUri } from '../claude/common/claudeSessionUri' ;
2425import { ClaudeAgentManager } from '../claude/node/claudeCodeAgent' ;
25- import { CLAUDE_REASONING_EFFORT_PROPERTY , IClaudeCodeModels } from '../claude/node/claudeCodeModels' ;
26+ import { CLAUDE_REASONING_EFFORT_PROPERTY , formatClaudeModelDetails , IClaudeCodeModels , pickReasoningEffort } from '../claude/node/claudeCodeModels' ;
2627import { IClaudeCodeSdkService } from '../claude/node/claudeCodeSdkService' ;
2728import { parseClaudeModelId } from '../claude/node/claudeModelId' ;
2829import { IClaudeSessionStateService } from '../claude/common/claudeSessionStateService' ;
2930import { IClaudeCodeSessionService } from '../claude/node/sessionParser/claudeCodeSessionService' ;
30- import { IClaudeCodeSessionInfo } from '../claude/node/sessionParser/claudeSessionSchema' ;
31+ import { IClaudeCodeSessionInfo , IClaudeCodeSession , SYNTHETIC_MODEL_ID } from '../claude/node/sessionParser/claudeSessionSchema' ;
3132import { IClaudeSlashCommandService } from '../claude/vscode-node/claudeSlashCommandService' ;
3233import { IChatFolderMruService } from '../common/folderRepositoryManager' ;
3334import { builtinSlashCommands } from '../common/builtinSlashCommands' ;
@@ -139,8 +140,13 @@ export class ClaudeChatSessionContentProvider extends Disposable implements vsco
139140 this . sessionStateService . setPermissionModeForSession ( effectiveSessionId , permissionMode ) ;
140141 this . sessionStateService . setFolderInfoForSession ( effectiveSessionId , folderInfo ) ;
141142
143+ // Resolve the endpoint once and reuse it for both reasoning effort
144+ // and the response footer details — they otherwise both call
145+ // `resolveEndpoint` (which hits the cached endpoint list, then
146+ // re-filters), which is wasted work and risks divergence.
147+ const endpoint = await this . _resolveEndpointForRequest ( modelId . toEndpointModelId ( ) ) ;
142148 const rawReasoningEffort = request . modelConfiguration ?. [ CLAUDE_REASONING_EFFORT_PROPERTY ] ;
143- const reasoningEffort = await this . claudeModels . resolveReasoningEffort ( modelId , rawReasoningEffort ) ;
149+ const reasoningEffort = pickReasoningEffort ( endpoint , typeof rawReasoningEffort === 'string' ? rawReasoningEffort : undefined ) ;
144150 this . sessionStateService . setReasoningEffortForSession ( effectiveSessionId , reasoningEffort ) ;
145151
146152 // Set usage handler to report token usage for context window widget
@@ -156,16 +162,21 @@ export class ClaudeChatSessionContentProvider extends Disposable implements vsco
156162 // Clear usage handler after request completes
157163 this . sessionStateService . setUsageHandlerForSession ( effectiveSessionId , undefined ) ;
158164
159- return result . errorDetails ? { errorDetails : result . errorDetails } : { } ;
165+ const details = endpoint ? formatClaudeModelDetails ( endpoint ) : undefined ;
166+ return {
167+ ...( details ? { details } : { } ) ,
168+ ...( result . errorDetails ? { errorDetails : result . errorDetails } : { } ) ,
169+ } ;
160170 } ;
161171 }
162172
163173 // #endregion
164174
165175 async provideChatSessionContent ( sessionResource : vscode . Uri , token : vscode . CancellationToken , context ?: { readonly inputState : vscode . ChatSessionInputState } ) : Promise < vscode . ChatSession > {
166176 const existingSession = await this . sessionService . getSession ( sessionResource , token ) ;
177+ const detailsByModelId = existingSession ? await this . _buildModelDetailsLookup ( existingSession , token ) : undefined ;
167178 const history = existingSession ?
168- buildChatHistory ( existingSession ) :
179+ buildChatHistory ( existingSession , detailsByModelId ? id => detailsByModelId . get ( id ) : undefined ) :
169180 [ ] ;
170181
171182 const options : Record < string , string | vscode . ChatSessionProviderOptionItem > = { } ;
@@ -188,6 +199,57 @@ export class ClaudeChatSessionContentProvider extends Disposable implements vsco
188199 options,
189200 } ;
190201 }
202+
203+ /**
204+ * Resolves a Claude model id to its endpoint. Wraps `resolveEndpoint` in a
205+ * try/catch so transient failures degrade gracefully (return `undefined`)
206+ * instead of breaking the response or session-load path.
207+ */
208+ private async _resolveEndpointForRequest ( modelId : string ) : Promise < IChatEndpoint | undefined > {
209+ try {
210+ return await this . claudeModels . resolveEndpoint ( modelId , undefined ) ;
211+ } catch {
212+ return undefined ;
213+ }
214+ }
215+
216+ /**
217+ * Resolves the display string for each unique non-synthetic model id observed in the
218+ * session's assistant messages. Returns `undefined` (not an empty map) when no model
219+ * ids are present, when the caller has cancelled, or when no ids resolve to known
220+ * endpoints — so callers can skip the per-turn details work entirely.
221+ */
222+ private async _buildModelDetailsLookup ( session : IClaudeCodeSession , token : vscode . CancellationToken ) : Promise < Map < string , string > | undefined > {
223+ if ( token . isCancellationRequested ) {
224+ return undefined ;
225+ }
226+ const modelIds = new Set < string > ( ) ;
227+ for ( const msg of session . messages ) {
228+ if ( msg . type === 'assistant' && msg . message . role === 'assistant' ) {
229+ const model = msg . message . model ;
230+ if ( model && model !== SYNTHETIC_MODEL_ID ) {
231+ modelIds . add ( model ) ;
232+ }
233+ }
234+ }
235+ if ( modelIds . size === 0 ) {
236+ return undefined ;
237+ }
238+ const detailsByModelId = new Map < string , string > ( ) ;
239+ await Promise . all ( [ ...modelIds ] . map ( async modelId => {
240+ if ( token . isCancellationRequested ) {
241+ return ;
242+ }
243+ const endpoint = await this . _resolveEndpointForRequest ( modelId ) ;
244+ if ( endpoint ) {
245+ detailsByModelId . set ( modelId , formatClaudeModelDetails ( endpoint ) ) ;
246+ }
247+ } ) ) ;
248+ if ( token . isCancellationRequested ) {
249+ return undefined ;
250+ }
251+ return detailsByModelId . size > 0 ? detailsByModelId : undefined ;
252+ }
191253}
192254
193255/**
0 commit comments