@@ -5,7 +5,7 @@ import { approveAll } from "../../src/index.js";
55import { createSdkTestContext } from "./harness/sdkTestContext.js" ;
66
77describe ( "Session Configuration" , async ( ) => {
8- const { copilotClient : client , workDir } = await createSdkTestContext ( ) ;
8+ const { copilotClient : client , workDir, openAiEndpoint } = await createSdkTestContext ( ) ;
99
1010 it ( "should use workingDirectory for tool execution" , async ( ) => {
1111 const subDir = join ( workDir , "subproject" ) ;
@@ -75,4 +75,78 @@ describe("Session Configuration", async () => {
7575 // Just verify send doesn't throw — attachment support varies by runtime
7676 await session . disconnect ( ) ;
7777 } ) ;
78+
79+ const PNG_1X1 = Buffer . from (
80+ "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==" ,
81+ "base64" ,
82+ ) ;
83+ const VIEW_IMAGE_PROMPT = "Use the view tool to look at the file test.png and describe what you see" ;
84+
85+ function hasImageUrlContent ( messages : Array < { role : string ; content : unknown } > ) : boolean {
86+ return messages . some (
87+ ( m ) =>
88+ m . role === "user" &&
89+ Array . isArray ( m . content ) &&
90+ m . content . some ( ( p : { type : string } ) => p . type === "image_url" ) ,
91+ ) ;
92+ }
93+
94+ it ( "vision disabled then enabled via setModel" , async ( ) => {
95+ await writeFile ( join ( workDir , "test.png" ) , PNG_1X1 ) ;
96+
97+ const session = await client . createSession ( {
98+ onPermissionRequest : approveAll ,
99+ modelCapabilities : { supports : { vision : false } } ,
100+ } ) ;
101+
102+ // Turn 1: vision off — no image_url expected
103+ await session . sendAndWait ( { prompt : VIEW_IMAGE_PROMPT } ) ;
104+ const trafficAfterT1 = await openAiEndpoint . getExchanges ( ) ;
105+ const t1Messages = trafficAfterT1 . flatMap ( ( e ) => e . request . messages ?? [ ] ) ;
106+ expect ( hasImageUrlContent ( t1Messages ) ) . toBe ( false ) ;
107+
108+ // Switch vision on (re-specify same model with updated capabilities)
109+ await session . setModel ( "claude-sonnet-4.5" , {
110+ modelCapabilities : { supports : { vision : true } } ,
111+ } ) ;
112+
113+ // Turn 2: vision on — image_url expected
114+ await session . sendAndWait ( { prompt : VIEW_IMAGE_PROMPT } ) ;
115+ const trafficAfterT2 = await openAiEndpoint . getExchanges ( ) ;
116+ // Only check exchanges added after turn 1
117+ const newExchanges = trafficAfterT2 . slice ( trafficAfterT1 . length ) ;
118+ const t2Messages = newExchanges . flatMap ( ( e ) => e . request . messages ?? [ ] ) ;
119+ expect ( hasImageUrlContent ( t2Messages ) ) . toBe ( true ) ;
120+
121+ await session . disconnect ( ) ;
122+ } ) ;
123+
124+ it ( "vision enabled then disabled via setModel" , async ( ) => {
125+ await writeFile ( join ( workDir , "test.png" ) , PNG_1X1 ) ;
126+
127+ const session = await client . createSession ( {
128+ onPermissionRequest : approveAll ,
129+ modelCapabilities : { supports : { vision : true } } ,
130+ } ) ;
131+
132+ // Turn 1: vision on — image_url expected
133+ await session . sendAndWait ( { prompt : VIEW_IMAGE_PROMPT } ) ;
134+ const trafficAfterT1 = await openAiEndpoint . getExchanges ( ) ;
135+ const t1Messages = trafficAfterT1 . flatMap ( ( e ) => e . request . messages ?? [ ] ) ;
136+ expect ( hasImageUrlContent ( t1Messages ) ) . toBe ( true ) ;
137+
138+ // Switch vision off
139+ await session . setModel ( "claude-sonnet-4.5" , {
140+ modelCapabilities : { supports : { vision : false } } ,
141+ } ) ;
142+
143+ // Turn 2: vision off — no image_url expected in new exchanges
144+ await session . sendAndWait ( { prompt : VIEW_IMAGE_PROMPT } ) ;
145+ const trafficAfterT2 = await openAiEndpoint . getExchanges ( ) ;
146+ const newExchanges = trafficAfterT2 . slice ( trafficAfterT1 . length ) ;
147+ const t2Messages = newExchanges . flatMap ( ( e ) => e . request . messages ?? [ ] ) ;
148+ expect ( hasImageUrlContent ( t2Messages ) ) . toBe ( false ) ;
149+
150+ await session . disconnect ( ) ;
151+ } ) ;
78152} ) ;
0 commit comments