Skip to content

Commit 53cd4dc

Browse files
authored
feat: allow any reverse proxy URLs, add proxy support to model fetching (danny-avila#1192)
* feat: allow any reverse proxy URLs * feat: add proxy support to model fetching
1 parent 015140f commit 53cd4dc

File tree

6 files changed

+17
-19
lines changed

6 files changed

+17
-19
lines changed

app/clients/OpenAIClient.js

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -145,10 +145,6 @@ class OpenAIClient extends BaseClient {
145145
if (reverseProxy) {
146146
this.completionsUrl = reverseProxy;
147147
this.langchainProxy = extractBaseURL(reverseProxy);
148-
!this.langchainProxy &&
149-
console.warn(`The reverse proxy URL ${reverseProxy} is not valid for Plugins.
150-
The url must follow OpenAI specs, for example: https://localhost:8080/v1/chat/completions
151-
If your reverse proxy is compatible to OpenAI specs in every other way, it may still work without plugins enabled.`);
152148
} else if (isChatGptModel) {
153149
this.completionsUrl = 'https://api.openai.com/v1/chat/completions';
154150
} else {

app/clients/PluginsClient.js

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,6 @@ class PluginsClient extends OpenAIClient {
3636

3737
if (this.options.reverseProxyUrl) {
3838
this.langchainProxy = extractBaseURL(this.options.reverseProxyUrl);
39-
!this.langchainProxy &&
40-
console.warn(`The reverse proxy URL ${this.options.reverseProxyUrl} is not valid for Plugins.
41-
The url must follow OpenAI specs, for example: https://localhost:8080/v1/chat/completions
42-
If your reverse proxy is compatible to OpenAI specs in every other way, it may still work without plugins enabled.`);
4339
}
4440
}
4541

app/clients/specs/OpenAIClient.test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ describe('OpenAIClient', () => {
9494

9595
client.setOptions({ reverseProxyUrl: 'https://example.com/completions' });
9696
expect(client.completionsUrl).toBe('https://example.com/completions');
97-
expect(client.langchainProxy).toBe(null);
97+
expect(client.langchainProxy).toBe('https://example.com/completions');
9898
});
9999
});
100100

server/services/ModelService.js

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
const Keyv = require('keyv');
1+
const HttpsProxyAgent = require('https-proxy-agent');
22
const axios = require('axios');
3+
const Keyv = require('keyv');
34
const { isEnabled } = require('../utils');
45
const { extractBaseURL } = require('../../utils');
56
const keyvRedis = require('../../cache/keyvRedis');
@@ -10,7 +11,7 @@ const modelsCache = isEnabled(process.env.USE_REDIS)
1011
? new Keyv({ store: keyvRedis })
1112
: new Keyv({ namespace: 'models' });
1213

13-
const { OPENROUTER_API_KEY, OPENAI_REVERSE_PROXY, CHATGPT_MODELS, ANTHROPIC_MODELS } =
14+
const { OPENROUTER_API_KEY, OPENAI_REVERSE_PROXY, CHATGPT_MODELS, ANTHROPIC_MODELS, PROXY } =
1415
process.env ?? {};
1516

1617
const fetchOpenAIModels = async (opts = { azure: false, plugins: false }, _models = []) => {
@@ -39,13 +40,18 @@ const fetchOpenAIModels = async (opts = { azure: false, plugins: false }, _model
3940
return cachedModels;
4041
}
4142

42-
if (basePath?.includes('v1') || opts.azure) {
43+
if (basePath || opts.azure) {
4344
try {
44-
const res = await axios.get(`${basePath}${opts.azure ? '' : '/models'}`, {
45+
const payload = {
4546
headers: {
4647
Authorization: `Bearer ${apiKey}`,
4748
},
48-
});
49+
};
50+
51+
if (PROXY) {
52+
payload.httpsAgent = new HttpsProxyAgent(PROXY);
53+
}
54+
const res = await axios.get(`${basePath}${opts.azure ? '' : '/models'}`, payload);
4955

5056
models = res.data.data.map((item) => item.id);
5157
// console.log(`Fetched ${models.length} models from ${opts.azure ? 'Azure ' : ''}OpenAI API`);

utils/extractBaseURL.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/**
22
* Extracts a valid OpenAI baseURL from a given string, matching "url/v1," also an added suffix,
33
* ending with "/openai" (to allow the Cloudflare, LiteLLM pattern).
4+
* Returns the original URL if no match is found.
45
*
56
* Examples:
67
* - `https://open.ai/v1/chat` -> `https://open.ai/v1`
@@ -9,12 +10,11 @@
910
* - `https://open.ai/v1/hi/openai` -> `https://open.ai/v1/hi/openai`
1011
*
1112
* @param {string} url - The URL to be processed.
12-
* @returns {string|null} The matched pattern or null if no match is found.
13+
* @returns {string} The matched pattern or input if no match is found.
1314
*/
1415
function extractBaseURL(url) {
15-
// First, let's make sure the URL contains '/v1'.
1616
if (!url.includes('/v1')) {
17-
return null;
17+
return url;
1818
}
1919

2020
// Find the index of '/v1' to use it as a reference point.

utils/extractBaseURL.spec.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,9 @@ describe('extractBaseURL', () => {
2828
);
2929
});
3030

31-
test('should return null if the URL does not match the expected pattern', () => {
31+
test('should return input if the URL does not match the expected pattern', () => {
3232
const url = 'https://someotherdomain.com/notv1';
33-
expect(extractBaseURL(url)).toBeNull();
33+
expect(extractBaseURL(url)).toBe(url);
3434
});
3535

3636
// Test our JSDoc examples.

0 commit comments

Comments
 (0)