33 * Licensed under the MIT License. See License.txt in the project root for license information.
44 *--------------------------------------------------------------------------------------------*/
55
6- import type { ModelMetadata , Session , internal } from '@github/copilot/sdk' ;
6+ import type { Session , internal } from '@github/copilot/sdk' ;
77import { ChatCompletionMessageParam } from 'openai/resources/chat/completions' ;
88import type { CancellationToken , ChatRequest } from 'vscode' ;
99import { INativeEnvService } from '../../../../platform/env/common/envService' ;
@@ -19,7 +19,7 @@ import { Disposable, DisposableMap, DisposableStore, IDisposable, toDisposable }
1919import { joinPath } from '../../../../util/vs/base/common/resources' ;
2020import { IInstantiationService } from '../../../../util/vs/platform/instantiation/common/instantiation' ;
2121import { ChatSessionStatus } from '../../../../vscodeTypes' ;
22- import { CopilotCLISessionOptions , ICopilotCLISDK , ICopilotCLISessionOptionsService } from './copilotCli' ;
22+ import { CopilotCLISessionOptions , ICopilotCLISDK } from './copilotCli' ;
2323import { CopilotCLISession , ICopilotCLISession } from './copilotcliSession' ;
2424import { stripReminders } from './copilotcliToolInvocationFormatter' ;
2525import { getCopilotLogger } from './logger' ;
@@ -45,13 +45,13 @@ export interface ICopilotCLISessionService {
4545 deleteSession ( sessionId : string ) : Promise < void > ;
4646
4747 // Session wrapper tracking
48- getSession ( sessionId : string , model : string | undefined , workingDirectory : string | undefined , readonly : boolean , token : CancellationToken ) : Promise < ICopilotCLISession | undefined > ;
49- createSession ( prompt : string , model : string | undefined , workingDirectory : string | undefined , isolationEnabled : boolean | undefined , token : CancellationToken ) : Promise < ICopilotCLISession > ;
48+ getSession ( sessionId : string , options : { model ? : string ; workingDirectory ? : string ; isolationEnabled ?: boolean ; readonly : boolean } , token : CancellationToken ) : Promise < ICopilotCLISession | undefined > ;
49+ createSession ( prompt : string , options : { model ? : string ; workingDirectory ? : string ; isolationEnabled ? : boolean } , token : CancellationToken ) : Promise < ICopilotCLISession > ;
5050}
5151
5252export const ICopilotCLISessionService = createServiceIdentifier < ICopilotCLISessionService > ( 'ICopilotCLISessionService' ) ;
5353
54- const SESSION_SHUTDOWN_TIMEOUT_MS = 30 * 1000 ;
54+ const SESSION_SHUTDOWN_TIMEOUT_MS = 300 * 1000 ;
5555
5656export class CopilotCLISessionService extends Disposable implements ICopilotCLISessionService {
5757 declare _serviceBrand : undefined ;
@@ -70,7 +70,6 @@ export class CopilotCLISessionService extends Disposable implements ICopilotCLIS
7070 @ILogService private readonly logService : ILogService ,
7171 @ICopilotCLISDK private readonly copilotCLISDK : ICopilotCLISDK ,
7272 @IInstantiationService private readonly instantiationService : IInstantiationService ,
73- @ICopilotCLISessionOptionsService private readonly optionsService : ICopilotCLISessionOptionsService ,
7473 @INativeEnvService private readonly nativeEnv : INativeEnvService ,
7574 @IFileSystemService private readonly fileSystem : IFileSystemService ,
7675 ) {
@@ -119,16 +118,7 @@ export class CopilotCLISessionService extends Disposable implements ICopilotCLIS
119118 // This is a new session not yet persisted to disk by SDK
120119 return undefined ;
121120 }
122- const timestamp = metadata . startTime ;
123121 const id = metadata . sessionId ;
124- const label = metadata . summary ? labelFromPrompt ( metadata . summary ) : undefined ;
125- if ( label ) {
126- return {
127- id,
128- label,
129- timestamp,
130- } satisfies ICopilotCLISessionItem ;
131- }
132122 let dispose : ( ( ) => Promise < void > ) | undefined = undefined ;
133123 let session : Session | undefined = undefined ;
134124 try {
@@ -144,6 +134,18 @@ export class CopilotCLISessionService extends Disposable implements ICopilotCLIS
144134 return undefined ;
145135 }
146136 const label = this . _generateSessionLabel ( session . sessionId , chatMessages , undefined ) ;
137+
138+ // Get timestamp from last SDK event, or fallback to metadata.startTime
139+ const sdkEvents = session . getEvents ( ) ;
140+ const lastEventWithTimestamp = [ ...sdkEvents ] . reverse ( ) . find ( event =>
141+ event . type !== 'session.import_legacy'
142+ && event . type !== 'session.start'
143+ && 'timestamp' in event
144+ ) ;
145+ const timestamp = lastEventWithTimestamp && 'timestamp' in lastEventWithTimestamp
146+ ? new Date ( lastEventWithTimestamp . timestamp )
147+ : metadata . startTime ;
148+
147149 return {
148150 id,
149151 label,
@@ -183,14 +185,10 @@ export class CopilotCLISessionService extends Disposable implements ICopilotCLIS
183185 return { session, dispose : ( ) => Promise . resolve ( ) } ;
184186 }
185187
186- public async createSession ( prompt : string , model : string | undefined , workingDirectory : string | undefined , isolationEnabled : boolean | undefined , token : CancellationToken ) : Promise < CopilotCLISession > {
188+ public async createSession ( prompt : string , { model, workingDirectory , isolationEnabled } : { model ?: string ; workingDirectory ? : string ; isolationEnabled ? : boolean } , token : CancellationToken ) : Promise < CopilotCLISession > {
187189 const sessionDisposables = this . _register ( new DisposableStore ( ) ) ;
188190 try {
189- const options = await raceCancellationError ( this . optionsService . createOptions ( {
190- model : model as unknown as ModelMetadata [ 'model' ] ,
191- workingDirectory
192- } ) , token ) ;
193- options . isolationEnabled = isolationEnabled === true ;
191+ const options = new CopilotCLISessionOptions ( { model, workingDirectory, isolationEnabled } , this . logService ) ;
194192 const sessionManager = await raceCancellationError ( this . getSessionManager ( ) , token ) ;
195193 const sdkSession = await sessionManager . createSession ( options . toSessionOptions ( ) ) ;
196194 const chatMessages = await sdkSession . getChatContextMessages ( ) ;
@@ -220,7 +218,7 @@ export class CopilotCLISessionService extends Disposable implements ICopilotCLIS
220218 }
221219 }
222220
223- public async getSession ( sessionId : string , model : string | undefined , workingDirectory : string | undefined , readonly : boolean , token : CancellationToken ) : Promise < CopilotCLISession | undefined > {
221+ public async getSession ( sessionId : string , { model, workingDirectory , isolationEnabled , readonly } : { model ?: string ; workingDirectory ? : string ; isolationEnabled ?: boolean ; readonly : boolean } , token : CancellationToken ) : Promise < CopilotCLISession | undefined > {
224222 const session = this . _sessionWrappers . get ( sessionId ) ;
225223
226224 if ( session ) {
@@ -231,10 +229,7 @@ export class CopilotCLISessionService extends Disposable implements ICopilotCLIS
231229 const sessionDisposables = this . _register ( new DisposableStore ( ) ) ;
232230 try {
233231 const sessionManager = await raceCancellationError ( this . getSessionManager ( ) , token ) ;
234- const options = await raceCancellationError ( this . optionsService . createOptions ( {
235- model : model as unknown as ModelMetadata [ 'model' ] ,
236- workingDirectory
237- } ) , token ) ;
232+ const options = new CopilotCLISessionOptions ( { model, workingDirectory, isolationEnabled } , this . logService ) ;
238233
239234 const sdkSession = await sessionManager . getSession ( { ...options . toSessionOptions ( ) , sessionId } , ! readonly ) ;
240235 if ( ! sdkSession ) {
0 commit comments