OpenRouter: Add control for middle-out transform Closes #3033
| @@ -651,6 +651,19 @@ | ||
| 651 | 651 | <input type="number" id="n_openai" name="n_openai" class="text_pole" min="1" value="1"> |
| 652 | 652 | </div> |
| 653 | 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 | 667 | <div data-source="openrouter"> |
| 655 | 668 | Max prompt cost: <span id="openrouter_max_prompt_cost">Unknown</span> |
| 656 | 669 | </div> |
| @@ -207,6 +207,12 @@ const custom_prompt_post_processing_types = { | ||
| 207 | 207 | STRICT: 'strict', |
| 208 | 208 | }; |
| 209 | 209 | |
| 210 | +const openrouter_middleout_types = { | |
| 211 | + AUTO: 'auto', | |
| 212 | + ON: 'on', | |
| 213 | + OFF: 'off', | |
| 214 | +}; | |
| 215 | + | |
| 210 | 216 | const sensitiveFields = [ |
| 211 | 217 | 'reverse_proxy', |
| 212 | 218 | 'proxy_password', |
| @@ -267,6 +273,7 @@ const default_settings = { | ||
| 267 | 273 | openrouter_sort_models: 'alphabetically', |
| 268 | 274 | openrouter_providers: [], |
| 269 | 275 | openrouter_allow_fallbacks: true, |
| 276 | + openrouter_middleout: openrouter_middleout_types.ON, | |
| 270 | 277 | jailbreak_system: false, |
| 271 | 278 | reverse_proxy: '', |
| 272 | 279 | chat_completion_source: chat_completion_sources.OPENAI, |
| @@ -343,6 +350,7 @@ const oai_settings = { | ||
| 343 | 350 | openrouter_sort_models: 'alphabetically', |
| 344 | 351 | openrouter_providers: [], |
| 345 | 352 | openrouter_allow_fallbacks: true, |
| 353 | + openrouter_middleout: openrouter_middleout_types.ON, | |
| 346 | 354 | jailbreak_system: false, |
| 347 | 355 | reverse_proxy: '', |
| 348 | 356 | chat_completion_source: chat_completion_sources.OPENAI, |
| @@ -1920,6 +1928,7 @@ async function sendOpenAIRequest(type, messages, signal) { | ||
| 1920 | 1928 | generate_data['use_fallback'] = oai_settings.openrouter_use_fallback; |
| 1921 | 1929 | generate_data['provider'] = oai_settings.openrouter_providers; |
| 1922 | 1930 | generate_data['allow_fallbacks'] = oai_settings.openrouter_allow_fallbacks; |
| 1931 | + generate_data['middleout'] = oai_settings.openrouter_middleout; | |
| 1923 | 1932 | |
| 1924 | 1933 | if (isTextCompletion) { |
| 1925 | 1934 | generate_data['stop'] = getStoppingStrings(isImpersonate, isContinue); |
| @@ -3022,6 +3031,7 @@ function loadOpenAISettings(data, settings) { | ||
| 3022 | 3031 | oai_settings.openrouter_sort_models = settings.openrouter_sort_models ?? default_settings.openrouter_sort_models; |
| 3023 | 3032 | oai_settings.openrouter_use_fallback = settings.openrouter_use_fallback ?? default_settings.openrouter_use_fallback; |
| 3024 | 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 | 3035 | oai_settings.ai21_model = settings.ai21_model ?? default_settings.ai21_model; |
| 3026 | 3036 | oai_settings.mistralai_model = settings.mistralai_model ?? default_settings.mistralai_model; |
| 3027 | 3037 | oai_settings.cohere_model = settings.cohere_model ?? default_settings.cohere_model; |
| @@ -3130,6 +3140,7 @@ function loadOpenAISettings(data, settings) { | ||
| 3130 | 3140 | $('#openrouter_group_models').prop('checked', oai_settings.openrouter_group_models); |
| 3131 | 3141 | $('#openrouter_allow_fallbacks').prop('checked', oai_settings.openrouter_allow_fallbacks); |
| 3132 | 3142 | $('#openrouter_providers_chat').val(oai_settings.openrouter_providers).trigger('change'); |
| 3143 | + $('#openrouter_middleout').val(oai_settings.openrouter_middleout); | |
| 3133 | 3144 | $('#squash_system_messages').prop('checked', oai_settings.squash_system_messages); |
| 3134 | 3145 | $('#continue_prefill').prop('checked', oai_settings.continue_prefill); |
| 3135 | 3146 | $('#openai_function_calling').prop('checked', oai_settings.function_calling); |
| @@ -3370,6 +3381,7 @@ async function saveOpenAIPreset(name, settings, triggerUi = true) { | ||
| 3370 | 3381 | openrouter_sort_models: settings.openrouter_sort_models, |
| 3371 | 3382 | openrouter_providers: settings.openrouter_providers, |
| 3372 | 3383 | openrouter_allow_fallbacks: settings.openrouter_allow_fallbacks, |
| 3384 | + openrouter_middleout: settings.openrouter_middleout, | |
| 3373 | 3385 | ai21_model: settings.ai21_model, |
| 3374 | 3386 | mistralai_model: settings.mistralai_model, |
| 3375 | 3387 | cohere_model: settings.cohere_model, |
| @@ -3836,6 +3848,7 @@ function onSettingsPresetChange() { | ||
| 3836 | 3848 | openrouter_sort_models: ['#openrouter_sort_models', 'openrouter_sort_models', false], |
| 3837 | 3849 | openrouter_providers: ['#openrouter_providers_chat', 'openrouter_providers', false], |
| 3838 | 3850 | openrouter_allow_fallbacks: ['#openrouter_allow_fallbacks', 'openrouter_allow_fallbacks', true], |
| 3851 | + openrouter_middleout: ['#openrouter_middleout', 'openrouter_middleout', false], | |
| 3839 | 3852 | ai21_model: ['#model_ai21_select', 'ai21_model', false], |
| 3840 | 3853 | mistralai_model: ['#model_mistralai_select', 'mistralai_model', false], |
| 3841 | 3854 | cohere_model: ['#model_cohere_select', 'cohere_model', false], |
| @@ -5261,6 +5274,11 @@ export function initOpenAI() { | ||
| 5261 | 5274 | saveSettingsDebounced(); |
| 5262 | 5275 | }); |
| 5263 | 5276 | |
| 5277 | + $('#openrouter_middleout').on('input', function () { | |
| 5278 | + oai_settings.openrouter_middleout = String($(this).val()); | |
| 5279 | + saveSettingsDebounced(); | |
| 5280 | + }); | |
| 5281 | + | |
| 5264 | 5282 | $('#squash_system_messages').on('input', function () { |
| 5265 | 5283 | oai_settings.squash_system_messages = !!$(this).prop('checked'); |
| 5266 | 5284 | saveSettingsDebounced(); |
| @@ -72,6 +72,22 @@ function postProcessPrompt(messages, type, names) { | ||
| 72 | 72 | } |
| 73 | 73 | |
| 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 | + */ | |
| 79 | +function 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 | 91 | * Sends a request to Claude API. |
| 76 | 92 | * @param {express.Request} request Express request |
| 77 | 93 | * @param {express.Response} response Express response |
| @@ -834,7 +850,9 @@ router.post('/generate', jsonParser, function (request, response) { | ||
| 834 | 850 | apiKey = readSecret(request.user.directories, SECRET_KEYS.OPENROUTER); |
| 835 | 851 | // OpenRouter needs to pass the Referer and X-Title: https://openrouter.ai/docs#requests |
| 836 | 852 | headers = { ...OPENROUTER_HEADERS }; |
| 837 | - bodyParams = { 'transforms': ['middle-out'] }; | |
| 853 | + bodyParams = { | |
| 854 | + 'transforms': getOpenRouterTransforms(request), | |
| 855 | + }; | |
| 838 | 856 | |
| 839 | 857 | if (request.body.min_p !== undefined) { |
| 840 | 858 | bodyParams['min_p'] = request.body.min_p; |