@@ -17,6 +17,7 @@ const { createSpeechGenClient, createMusicGenClient } = await import('./media-ge
1717const { createVideoGenClient } = await import ( './media-gen-video-clients.js' )
1818const { createMediaFetch } = await import ( './media-gen-client-support.js' )
1919const { buildImageGenToolProviders } = await import ( './image-gen-tool-provider.js' )
20+ const { buildSpeechGenToolProviders } = await import ( './media-gen-tool-provider.js' )
2021
2122const fakeGeneratedImage = {
2223 // Smallest detectable PNG payload so detectImage() accepts it and the tool
@@ -128,6 +129,95 @@ describe('media generation proxy fetch wiring', () => {
128129 const clientConfig = createImageGenClientMock . mock . calls [ 0 ] [ 0 ] as Record < string , unknown >
129130 expect ( clientConfig ) . not . toHaveProperty ( 'proxyUrl' )
130131 } )
132+
133+ it ( 'falls back to the provider-level proxy for inline image configs without a providerId' , async ( ) => {
134+ const { providers, available } = buildImageGenToolProviders ( {
135+ ...imageGenConfigDefaults ,
136+ enabled : true ,
137+ protocol : 'openai-images' ,
138+ baseUrl : 'https://images.example.test/v1' ,
139+ apiKey : 'sk-inline' ,
140+ model : 'test-model'
141+ } , {
142+ proxyUrl : 'http://proxy.lan:8080'
143+ } )
144+
145+ expect ( available ) . toBe ( true )
146+ const tool = providers [ 0 ] . tools . find ( ( candidate ) => candidate . name === 'generate_image' )
147+ const result = await tool ! . execute ( { prompt : 'a cat' } , minimalContext ( ) )
148+ expect ( result . isError ) . toBeFalsy ( )
149+
150+ const clientConfig = createImageGenClientMock . mock . calls [ 0 ] [ 0 ] as Record < string , unknown >
151+ expect ( clientConfig . proxyUrl ) . toBe ( 'http://proxy.lan:8080' )
152+ expect ( clientConfig . apiKey ) . toBe ( 'sk-inline' )
153+ } )
154+
155+ it ( 'prefers the resolved credential proxy over the provider-level fallback' , async ( ) => {
156+ const { providers } = buildImageGenToolProviders ( {
157+ ...imageGenConfigDefaults ,
158+ enabled : true ,
159+ protocol : 'openai-images' ,
160+ baseUrl : 'https://images.example.test/v1' ,
161+ model : 'test-model' ,
162+ providerId : 'prov-1'
163+ } , {
164+ proxyUrl : 'http://fallback.lan:8080' ,
165+ resolveCredential : async ( ) => ( {
166+ apiKey : 'sk-test' ,
167+ proxyUrl : 'http://proxy.lan:8080'
168+ } )
169+ } )
170+
171+ const tool = providers [ 0 ] . tools . find ( ( candidate ) => candidate . name === 'generate_image' )
172+ await tool ! . execute ( { prompt : 'a cat' } , minimalContext ( ) )
173+
174+ const clientConfig = createImageGenClientMock . mock . calls [ 0 ] [ 0 ] as Record < string , unknown >
175+ expect ( clientConfig . proxyUrl ) . toBe ( 'http://proxy.lan:8080' )
176+ } )
177+
178+ it ( 'honors a connection that explicitly bypasses the proxy instead of falling back' , async ( ) => {
179+ const { providers } = buildImageGenToolProviders ( {
180+ ...imageGenConfigDefaults ,
181+ enabled : true ,
182+ protocol : 'openai-images' ,
183+ baseUrl : 'https://images.example.test/v1' ,
184+ model : 'test-model' ,
185+ providerId : 'prov-direct'
186+ } , {
187+ proxyUrl : 'http://fallback.lan:8080' ,
188+ resolveCredential : async ( ) => ( { apiKey : 'sk-test' } )
189+ } )
190+
191+ const tool = providers [ 0 ] . tools . find ( ( candidate ) => candidate . name === 'generate_image' )
192+ await tool ! . execute ( { prompt : 'a cat' } , minimalContext ( ) )
193+
194+ const clientConfig = createImageGenClientMock . mock . calls [ 0 ] [ 0 ] as Record < string , unknown >
195+ expect ( clientConfig ) . not . toHaveProperty ( 'proxyUrl' )
196+ } )
197+
198+ it ( 'falls back to the provider-level proxy for inline speech configs without a providerId' , async ( ) => {
199+ createProxyFetchMock . mockReturnValue ( async ( ) => {
200+ throw new Error ( 'proxied fetch invoked' )
201+ } )
202+ const { providers, available } = buildSpeechGenToolProviders ( {
203+ enabled : true ,
204+ protocol : 'openai-speech' ,
205+ baseUrl : 'https://speech.example.test/v1' ,
206+ apiKey : 'sk-inline' ,
207+ model : 'tts-test' ,
208+ format : 'mp3' ,
209+ timeoutMs : 30_000
210+ } , {
211+ proxyUrl : 'http://proxy.lan:8080'
212+ } )
213+
214+ expect ( available ) . toBe ( true )
215+ const tool = providers [ 0 ] . tools . find ( ( candidate ) => candidate . name === 'generate_speech' )
216+ const result = await tool ! . execute ( { text : 'hello' } , minimalContext ( ) )
217+ expect ( result . isError ) . toBe ( true )
218+
219+ expect ( createProxyFetchMock ) . toHaveBeenCalledWith ( 'http://proxy.lan:8080' )
220+ } )
131221} )
132222
133223function minimalContext ( ) : Parameters <
0 commit comments