@@ -188,14 +188,14 @@ class TestableCopilotAgent extends CopilotAgent {
188188 }
189189}
190190
191- function createTestAgentContext ( disposables : Pick < DisposableStore , 'add' > , options ?: { sessionDataService ?: ISessionDataService ; copilotClient ?: ICopilotClient ; gitService ?: TestAgentHostGitService ; environmentServiceRegistration ?: 'native' | 'none' } ) : { agent : CopilotAgent ; instantiationService : IInstantiationService } {
191+ function createTestAgentContext ( disposables : Pick < DisposableStore , 'add' > , options ?: { sessionDataService ?: ISessionDataService ; copilotClient ?: ICopilotClient ; gitService ?: TestAgentHostGitService ; environmentServiceRegistration ?: 'native' | 'none' ; pluginManager ?: IAgentPluginManager } ) : { agent : CopilotAgent ; instantiationService : IInstantiationService } {
192192 const services = new ServiceCollection ( ) ;
193193 const logService = new NullLogService ( ) ;
194194 const fileService = disposables . add ( new FileService ( logService ) ) ;
195195 services . set ( ILogService , logService ) ;
196196 services . set ( IFileService , fileService ) ;
197197 services . set ( ISessionDataService , options ?. sessionDataService ?? createNullSessionDataService ( ) ) ;
198- services . set ( IAgentPluginManager , new TestAgentPluginManager ( ) ) ;
198+ services . set ( IAgentPluginManager , options ?. pluginManager ?? new TestAgentPluginManager ( ) ) ;
199199 services . set ( IAgentHostGitService , options ?. gitService ?? new TestAgentHostGitService ( ) ) ;
200200 services . set ( IAgentHostTerminalManager , new TestAgentHostTerminalManager ( ) ) ;
201201 if ( options ?. environmentServiceRegistration !== 'none' ) {
@@ -213,7 +213,7 @@ function createTestAgentContext(disposables: Pick<DisposableStore, 'add'>, optio
213213 return { agent, instantiationService } ;
214214}
215215
216- function createTestAgent ( disposables : Pick < DisposableStore , 'add' > , options ?: { sessionDataService ?: ISessionDataService ; copilotClient ?: ICopilotClient ; gitService ?: TestAgentHostGitService ; environmentServiceRegistration ?: 'native' | 'none' } ) : CopilotAgent {
216+ function createTestAgent ( disposables : Pick < DisposableStore , 'add' > , options ?: { sessionDataService ?: ISessionDataService ; copilotClient ?: ICopilotClient ; gitService ?: TestAgentHostGitService ; environmentServiceRegistration ?: 'native' | 'none' ; pluginManager ?: IAgentPluginManager } ) : CopilotAgent {
217217 return createTestAgentContext ( disposables , options ) . agent ;
218218}
219219
@@ -386,6 +386,75 @@ suite('CopilotAgent', () => {
386386 }
387387 } ) ;
388388
389+ suite ( 'createSession activeClient eager-claim' , ( ) => {
390+
391+ class SpyingPluginManager extends TestAgentPluginManager {
392+ public readonly calls : { clientId : string ; customizations : ICustomizationRef [ ] } [ ] = [ ] ;
393+
394+ override async syncCustomizations ( clientId : string , customizations : ICustomizationRef [ ] , _progress ?: ( status : ISessionCustomization [ ] ) => void ) : Promise < ISyncedCustomization [ ] > {
395+ this . calls . push ( { clientId, customizations : [ ...customizations ] } ) ;
396+ return [ ] ;
397+ }
398+ }
399+
400+ test ( 'createSession seeds activeClient tools and syncs customizations' , async ( ) => {
401+ const sessionDataService = disposables . add ( new TestSessionDataService ( ) ) ;
402+ const client = new TestCopilotClient ( [ ] ) ;
403+ const pluginManager = new SpyingPluginManager ( ) ;
404+ // Fail fast inside the SDK factory so we don't need to wire up a
405+ // real raw session. The seeding of activeClient and the plugin
406+ // sync both happen before `client.createSession` is invoked.
407+ client . createSession = async ( ) => { throw new Error ( 'sentinel' ) ; } ;
408+
409+ const agent = createTestAgent ( disposables , { sessionDataService, copilotClient : client , pluginManager } ) ;
410+ try {
411+ await agent . authenticate ( 'https://api.github.com' , 'token' ) ;
412+
413+ const customizations : ICustomizationRef [ ] = [ { uri : 'file:///plugin-a' , displayName : 'Plugin A' } ] ;
414+ await assert . rejects (
415+ agent . createSession ( {
416+ session : AgentSession . uri ( 'copilot' , 'test-session' ) ,
417+ workingDirectory : URI . file ( '/workspace' ) ,
418+ activeClient : {
419+ clientId : 'client-1' ,
420+ tools : [ { name : 't1' , description : 'd' , inputSchema : { type : 'object' } } ] ,
421+ customizations,
422+ } ,
423+ } ) ,
424+ ( err : Error ) => / s e n t i n e l / . test ( err . message ) ,
425+ ) ;
426+
427+ assert . deepStrictEqual ( pluginManager . calls , [ { clientId : 'client-1' , customizations } ] ) ;
428+ } finally {
429+ await disposeAgent ( agent ) ;
430+ }
431+ } ) ;
432+
433+ test ( 'createSession without activeClient does not sync customizations' , async ( ) => {
434+ const sessionDataService = disposables . add ( new TestSessionDataService ( ) ) ;
435+ const client = new TestCopilotClient ( [ ] ) ;
436+ const pluginManager = new SpyingPluginManager ( ) ;
437+ client . createSession = async ( ) => { throw new Error ( 'sentinel' ) ; } ;
438+
439+ const agent = createTestAgent ( disposables , { sessionDataService, copilotClient : client , pluginManager } ) ;
440+ try {
441+ await agent . authenticate ( 'https://api.github.com' , 'token' ) ;
442+
443+ await assert . rejects (
444+ agent . createSession ( {
445+ session : AgentSession . uri ( 'copilot' , 'test-session-2' ) ,
446+ workingDirectory : URI . file ( '/workspace' ) ,
447+ } ) ,
448+ ( err : Error ) => / s e n t i n e l / . test ( err . message ) ,
449+ ) ;
450+
451+ assert . deepStrictEqual ( pluginManager . calls , [ ] ) ;
452+ } finally {
453+ await disposeAgent ( agent ) ;
454+ }
455+ } ) ;
456+ } ) ;
457+
389458 suite ( 'worktree announcement' , ( ) => {
390459 // Drives a real session through worktree creation (calling the
391460 // agent's _resolveSessionWorkingDirectory via a test seam so we don't
0 commit comments