diff --git a/packages/core/src/core/openaiContentGenerator/provider/dashscope.test.ts b/packages/core/src/core/openaiContentGenerator/provider/dashscope.test.ts index 03761133a64..3becf07f18e 100644 --- a/packages/core/src/core/openaiContentGenerator/provider/dashscope.test.ts +++ b/packages/core/src/core/openaiContentGenerator/provider/dashscope.test.ts @@ -164,6 +164,92 @@ describe('DashScopeOpenAICompatibleProvider', () => { expect(result).toBe(true); }); + it('should return true for internal alibaba-inc.com subdomain', () => { + const config = { + authType: AuthType.USE_OPENAI, + baseUrl: 'https://gateway.alibaba-inc.com/dashscope/v1', + } as ContentGeneratorConfig; + + const result = + DashScopeOpenAICompatibleProvider.isDashScopeProvider(config); + expect(result).toBe(true); + expect(mockDebugLogger.debug).toHaveBeenCalledWith( + 'DashScope provider activated via internal origin: gateway.alibaba-inc.com', + ); + }); + + it('should return true for internal aliyun-inc.com subdomain', () => { + const config = { + authType: AuthType.USE_OPENAI, + baseUrl: 'https://model-gateway.aliyun-inc.com/dashscope/v1', + } as ContentGeneratorConfig; + + const result = + DashScopeOpenAICompatibleProvider.isDashScopeProvider(config); + expect(result).toBe(true); + }); + + it('should return true for multi-level internal subdomain', () => { + const config = { + authType: AuthType.USE_OPENAI, + baseUrl: 'https://a.b.alibaba-inc.com/dashscope/v1', + } as ContentGeneratorConfig; + + const result = + DashScopeOpenAICompatibleProvider.isDashScopeProvider(config); + expect(result).toBe(true); + }); + + it('should return true for port-bearing internal URL', () => { + const config = { + authType: AuthType.USE_OPENAI, + baseUrl: 'https://gateway.alibaba-inc.com:8443/dashscope/v1', + } as ContentGeneratorConfig; + + const result = + DashScopeOpenAICompatibleProvider.isDashScopeProvider(config); + expect(result).toBe(true); + }); + + it('should return false for bare alibaba-inc.com domain', () => { + const config = { + authType: AuthType.USE_OPENAI, + baseUrl: 'https://alibaba-inc.com/v1', + } as ContentGeneratorConfig; + + const result = + DashScopeOpenAICompatibleProvider.isDashScopeProvider(config); + expect(result).toBe(false); + }); + + it('should return false for bare aliyun-inc.com domain', () => { + const config = { + authType: AuthType.USE_OPENAI, + baseUrl: 'https://aliyun-inc.com/v1', + } as ContentGeneratorConfig; + + const result = + DashScopeOpenAICompatibleProvider.isDashScopeProvider(config); + expect(result).toBe(false); + }); + + it('should return false for lookalike internal domains without dot boundary', () => { + const configs = [ + 'https://notalibaba-inc.com/v1', + 'https://notaliyun-inc.com/v1', + 'https://alibaba-inc.com.evil.com/v1', + 'https://aliyun-inc.com.evil.com/v1', + ]; + + configs.forEach((baseUrl) => { + const result = DashScopeOpenAICompatibleProvider.isDashScopeProvider({ + authType: AuthType.USE_OPENAI, + baseUrl, + } as ContentGeneratorConfig); + expect(result).toBe(false); + }); + }); + it('should return false for non-DashScope configurations', () => { const configs = [ { @@ -275,6 +361,31 @@ describe('DashScopeOpenAICompatibleProvider', () => { ); }); + it('should log internal-origin activation instead of proxy mismatch for internal domains', () => { + vi.stubEnv( + 'DASHSCOPE_PROXY_BASE_URL', + 'https://your-proxy.com/dashscope', + ); + + const config = { + authType: AuthType.USE_OPENAI, + baseUrl: 'https://gateway.alibaba-inc.com/dashscope/v1', + } as ContentGeneratorConfig; + + const result = + DashScopeOpenAICompatibleProvider.isDashScopeProvider(config); + + expect(result).toBe(true); + expect(mockDebugLogger.debug).toHaveBeenCalledWith( + 'DashScope provider activated via internal origin: gateway.alibaba-inc.com', + ); + expect(mockDebugLogger.debug).not.toHaveBeenCalledWith( + expect.stringContaining( + 'DASHSCOPE_PROXY_BASE_URL is configured but the request baseUrl does not match', + ), + ); + }); + it('should return true when baseUrl matches DASHSCOPE_PROXY_BASE_URL with trailing slash', () => { vi.stubEnv( 'DASHSCOPE_PROXY_BASE_URL', diff --git a/packages/core/src/core/openaiContentGenerator/provider/dashscope.ts b/packages/core/src/core/openaiContentGenerator/provider/dashscope.ts index 8f0e2dfe2da..644232b58b5 100644 --- a/packages/core/src/core/openaiContentGenerator/provider/dashscope.ts +++ b/packages/core/src/core/openaiContentGenerator/provider/dashscope.ts @@ -29,6 +29,16 @@ export class DashScopeOpenAICompatibleProvider extends DefaultOpenAICompatiblePr super(contentGeneratorConfig, cliConfig); } + /** + * Determines whether to use the DashScope-compatible provider. + * Covers dashscope.aliyuncs.com, dashscope-intl.aliyuncs.com, + * internal Alibaba domains (*.alibaba-inc.com, *.aliyun-inc.com), + * and proxy matches. + * + * Note: any *.alibaba-inc.com / *.aliyun-inc.com host is treated as a + * DashScope-compatible endpoint by design. Keep this generic and avoid + * embedding individual private gateway hostnames in provider detection. + */ static isDashScopeProvider( contentGeneratorConfig: ContentGeneratorConfig, ): boolean { @@ -60,6 +70,13 @@ export class DashScopeOpenAICompatibleProvider extends DefaultOpenAICompatiblePr hostname.endsWith('.dashscope.aliyuncs.com') || hostname.endsWith('.dashscope-intl.aliyuncs.com')); + // Internal Alibaba domains proxying to DashScope-compatible APIs. + // Covers *.alibaba-inc.com and *.aliyun-inc.com. + const isInternalOrigin = + hostname !== null && + (hostname.endsWith('.alibaba-inc.com') || + hostname.endsWith('.aliyun-inc.com')); + // Check if proxy is configured and matches const normalizedProxyUrl = DASHSCOPE_PROXY_BASE_URL?.endsWith('/') ? DASHSCOPE_PROXY_BASE_URL.slice(0, -1) @@ -70,13 +87,24 @@ export class DashScopeOpenAICompatibleProvider extends DefaultOpenAICompatiblePr normalizedBaseUrl.toLowerCase() === normalizedProxyUrl.toLowerCase(), ); - if (normalizedProxyUrl && !isDashscopeOrigin && !isProxyMatch) { + if ( + normalizedProxyUrl && + !isDashscopeOrigin && + !isInternalOrigin && + !isProxyMatch + ) { debugLogger.debug( `DASHSCOPE_PROXY_BASE_URL is configured but the request baseUrl does not match. DashScope headers/cache control will be skipped.`, ); } - return isDashscopeOrigin || isProxyMatch; + if (isInternalOrigin) { + debugLogger.debug( + `DashScope provider activated via internal origin: ${hostname}`, + ); + } + + return isDashscopeOrigin || isInternalOrigin || isProxyMatch; } override buildHeaders(): Record {