OpenRouter: Add control for middle-out transform Closes #3033

7adc6d38e29672ac27acebf1d588f61be97d68d1

Cohee <18619528+Cohee1207@users.noreply.github.com>

3 files changed, +50 -1Showing whitespace changes
public/index.html+13 -0
@@ -651,6 +651,19 @@
651 <input type="number" id="n_openai" name="n_openai" class="text_pole" min="1" value="1">651 <input type="number" id="n_openai" name="n_openai" class="text_pole" min="1" value="1">
652 </div>652 </div>
653 </div>653 </div>
654 <div data-source="openrouter" class="range-block">
655 <div class="range-block-title" title="Allow compressing requests by removing messages from the middle of the prompt.">
656 <span data-i18n="Middle-out Transform">Middle-out Transform</span>
657 <a href="https://openrouter.ai/docs/transforms" target="_blank" rel="noreferrer noopener" class="note-link-span fa-solid fa-circle-question"></a>
658 </div>
659 <div class="wide100p">
660 <select id="openrouter_middleout" class="text_pole">
661 <option value="auto" data-i18n="Auto">Auto</option>
662 <option value="on" data-i18n="Allow">Allow</option>
663 <option value="off" data-i18n="Forbid">Forbid</option>
664 </select>
665 </div>
666 </div>
654 <div data-source="openrouter">667 <div data-source="openrouter">
655 Max prompt cost: <span id="openrouter_max_prompt_cost">Unknown</span>668 Max prompt cost: <span id="openrouter_max_prompt_cost">Unknown</span>
656 </div>669 </div>
public/scripts/openai.js+18 -0
@@ -207,6 +207,12 @@ const custom_prompt_post_processing_types = {
207 STRICT: 'strict',207 STRICT: 'strict',
208};208};
209209
210const openrouter_middleout_types = {
211 AUTO: 'auto',
212 ON: 'on',
213 OFF: 'off',
214};
215
210const sensitiveFields = [216const sensitiveFields = [
211 'reverse_proxy',217 'reverse_proxy',
212 'proxy_password',218 'proxy_password',
@@ -267,6 +273,7 @@ const default_settings = {
267 openrouter_sort_models: 'alphabetically',273 openrouter_sort_models: 'alphabetically',
268 openrouter_providers: [],274 openrouter_providers: [],
269 openrouter_allow_fallbacks: true,275 openrouter_allow_fallbacks: true,
276 openrouter_middleout: openrouter_middleout_types.ON,
270 jailbreak_system: false,277 jailbreak_system: false,
271 reverse_proxy: '',278 reverse_proxy: '',
272 chat_completion_source: chat_completion_sources.OPENAI,279 chat_completion_source: chat_completion_sources.OPENAI,
@@ -343,6 +350,7 @@ const oai_settings = {
343 openrouter_sort_models: 'alphabetically',350 openrouter_sort_models: 'alphabetically',
344 openrouter_providers: [],351 openrouter_providers: [],
345 openrouter_allow_fallbacks: true,352 openrouter_allow_fallbacks: true,
353 openrouter_middleout: openrouter_middleout_types.ON,
346 jailbreak_system: false,354 jailbreak_system: false,
347 reverse_proxy: '',355 reverse_proxy: '',
348 chat_completion_source: chat_completion_sources.OPENAI,356 chat_completion_source: chat_completion_sources.OPENAI,
@@ -1920,6 +1928,7 @@ async function sendOpenAIRequest(type, messages, signal) {
1920 generate_data['use_fallback'] = oai_settings.openrouter_use_fallback;1928 generate_data['use_fallback'] = oai_settings.openrouter_use_fallback;
1921 generate_data['provider'] = oai_settings.openrouter_providers;1929 generate_data['provider'] = oai_settings.openrouter_providers;
1922 generate_data['allow_fallbacks'] = oai_settings.openrouter_allow_fallbacks;1930 generate_data['allow_fallbacks'] = oai_settings.openrouter_allow_fallbacks;
1931 generate_data['middleout'] = oai_settings.openrouter_middleout;
19231932
1924 if (isTextCompletion) {1933 if (isTextCompletion) {
1925 generate_data['stop'] = getStoppingStrings(isImpersonate, isContinue);1934 generate_data['stop'] = getStoppingStrings(isImpersonate, isContinue);
@@ -3022,6 +3031,7 @@ function loadOpenAISettings(data, settings) {
3022 oai_settings.openrouter_sort_models = settings.openrouter_sort_models ?? default_settings.openrouter_sort_models;3031 oai_settings.openrouter_sort_models = settings.openrouter_sort_models ?? default_settings.openrouter_sort_models;
3023 oai_settings.openrouter_use_fallback = settings.openrouter_use_fallback ?? default_settings.openrouter_use_fallback;3032 oai_settings.openrouter_use_fallback = settings.openrouter_use_fallback ?? default_settings.openrouter_use_fallback;
3024 oai_settings.openrouter_allow_fallbacks = settings.openrouter_allow_fallbacks ?? default_settings.openrouter_allow_fallbacks;3033 oai_settings.openrouter_allow_fallbacks = settings.openrouter_allow_fallbacks ?? default_settings.openrouter_allow_fallbacks;
3034 oai_settings.openrouter_middleout = settings.openrouter_middleout ?? default_settings.openrouter_middleout;
3025 oai_settings.ai21_model = settings.ai21_model ?? default_settings.ai21_model;3035 oai_settings.ai21_model = settings.ai21_model ?? default_settings.ai21_model;
3026 oai_settings.mistralai_model = settings.mistralai_model ?? default_settings.mistralai_model;3036 oai_settings.mistralai_model = settings.mistralai_model ?? default_settings.mistralai_model;
3027 oai_settings.cohere_model = settings.cohere_model ?? default_settings.cohere_model;3037 oai_settings.cohere_model = settings.cohere_model ?? default_settings.cohere_model;
@@ -3130,6 +3140,7 @@ function loadOpenAISettings(data, settings) {
3130 $('#openrouter_group_models').prop('checked', oai_settings.openrouter_group_models);3140 $('#openrouter_group_models').prop('checked', oai_settings.openrouter_group_models);
3131 $('#openrouter_allow_fallbacks').prop('checked', oai_settings.openrouter_allow_fallbacks);3141 $('#openrouter_allow_fallbacks').prop('checked', oai_settings.openrouter_allow_fallbacks);
3132 $('#openrouter_providers_chat').val(oai_settings.openrouter_providers).trigger('change');3142 $('#openrouter_providers_chat').val(oai_settings.openrouter_providers).trigger('change');
3143 $('#openrouter_middleout').val(oai_settings.openrouter_middleout);
3133 $('#squash_system_messages').prop('checked', oai_settings.squash_system_messages);3144 $('#squash_system_messages').prop('checked', oai_settings.squash_system_messages);
3134 $('#continue_prefill').prop('checked', oai_settings.continue_prefill);3145 $('#continue_prefill').prop('checked', oai_settings.continue_prefill);
3135 $('#openai_function_calling').prop('checked', oai_settings.function_calling);3146 $('#openai_function_calling').prop('checked', oai_settings.function_calling);
@@ -3370,6 +3381,7 @@ async function saveOpenAIPreset(name, settings, triggerUi = true) {
3370 openrouter_sort_models: settings.openrouter_sort_models,3381 openrouter_sort_models: settings.openrouter_sort_models,
3371 openrouter_providers: settings.openrouter_providers,3382 openrouter_providers: settings.openrouter_providers,
3372 openrouter_allow_fallbacks: settings.openrouter_allow_fallbacks,3383 openrouter_allow_fallbacks: settings.openrouter_allow_fallbacks,
3384 openrouter_middleout: settings.openrouter_middleout,
3373 ai21_model: settings.ai21_model,3385 ai21_model: settings.ai21_model,
3374 mistralai_model: settings.mistralai_model,3386 mistralai_model: settings.mistralai_model,
3375 cohere_model: settings.cohere_model,3387 cohere_model: settings.cohere_model,
@@ -3836,6 +3848,7 @@ function onSettingsPresetChange() {
3836 openrouter_sort_models: ['#openrouter_sort_models', 'openrouter_sort_models', false],3848 openrouter_sort_models: ['#openrouter_sort_models', 'openrouter_sort_models', false],
3837 openrouter_providers: ['#openrouter_providers_chat', 'openrouter_providers', false],3849 openrouter_providers: ['#openrouter_providers_chat', 'openrouter_providers', false],
3838 openrouter_allow_fallbacks: ['#openrouter_allow_fallbacks', 'openrouter_allow_fallbacks', true],3850 openrouter_allow_fallbacks: ['#openrouter_allow_fallbacks', 'openrouter_allow_fallbacks', true],
3851 openrouter_middleout: ['#openrouter_middleout', 'openrouter_middleout', false],
3839 ai21_model: ['#model_ai21_select', 'ai21_model', false],3852 ai21_model: ['#model_ai21_select', 'ai21_model', false],
3840 mistralai_model: ['#model_mistralai_select', 'mistralai_model', false],3853 mistralai_model: ['#model_mistralai_select', 'mistralai_model', false],
3841 cohere_model: ['#model_cohere_select', 'cohere_model', false],3854 cohere_model: ['#model_cohere_select', 'cohere_model', false],
@@ -5261,6 +5274,11 @@ export function initOpenAI() {
5261 saveSettingsDebounced();5274 saveSettingsDebounced();
5262 });5275 });
52635276
5277 $('#openrouter_middleout').on('input', function () {
5278 oai_settings.openrouter_middleout = String($(this).val());
5279 saveSettingsDebounced();
5280 });
5281
5264 $('#squash_system_messages').on('input', function () {5282 $('#squash_system_messages').on('input', function () {
5265 oai_settings.squash_system_messages = !!$(this).prop('checked');5283 oai_settings.squash_system_messages = !!$(this).prop('checked');
5266 saveSettingsDebounced();5284 saveSettingsDebounced();
src/endpoints/backends/chat-completions.js+19 -1
@@ -72,6 +72,22 @@ function postProcessPrompt(messages, type, names) {
72}72}
7373
74/**74/**
75 * Gets OpenRouter transforms based on the request.
76 * @param {import('express').Request} request Express request
77 * @returns {string[] | undefined} OpenRouter transforms
78 */
79function getOpenRouterTransforms(request) {
80 switch (request.body.middleout) {
81 case 'on':
82 return ['middle-out'];
83 case 'off':
84 return [];
85 case 'auto':
86 return undefined;
87 }
88}
89
90/**
75 * Sends a request to Claude API.91 * Sends a request to Claude API.
76 * @param {express.Request} request Express request92 * @param {express.Request} request Express request
77 * @param {express.Response} response Express response93 * @param {express.Response} response Express response
@@ -834,7 +850,9 @@ router.post('/generate', jsonParser, function (request, response) {
834 apiKey = readSecret(request.user.directories, SECRET_KEYS.OPENROUTER);850 apiKey = readSecret(request.user.directories, SECRET_KEYS.OPENROUTER);
835 // OpenRouter needs to pass the Referer and X-Title: https://openrouter.ai/docs#requests851 // OpenRouter needs to pass the Referer and X-Title: https://openrouter.ai/docs#requests
836 headers = { ...OPENROUTER_HEADERS };852 headers = { ...OPENROUTER_HEADERS };
837 bodyParams = { 'transforms': ['middle-out'] };853 bodyParams = {
854 'transforms': getOpenRouterTransforms(request),
855 };
838856
839 if (request.body.min_p !== undefined) {857 if (request.body.min_p !== undefined) {
840 bodyParams['min_p'] = request.body.min_p;858 bodyParams['min_p'] = request.body.min_p;