OpenRouter: Add control for middle-out transform Closes #3033
| @@ -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> |
| @@ -207,6 +207,12 @@ const custom_prompt_post_processing_types = { | |||
| 207 | STRICT: 'strict', | 207 | STRICT: 'strict', |
| 208 | }; | 208 | }; |
| 209 | 209 | ||
| 210 | const openrouter_middleout_types = { | ||
| 211 | AUTO: 'auto', | ||
| 212 | ON: 'on', | ||
| 213 | OFF: 'off', | ||
| 214 | }; | ||
| 215 | |||
| 210 | const sensitiveFields = [ | 216 | const 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; | ||
| 1923 | 1932 | ||
| 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 | }); |
| 5263 | 5276 | ||
| 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(); |
| @@ -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 | * Sends a request to Claude API. | 91 | * Sends a request to Claude API. |
| 76 | * @param {express.Request} request Express request | 92 | * @param {express.Request} request Express request |
| 77 | * @param {express.Response} response Express response | 93 | * @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#requests | 851 | // 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 | }; | ||
| 838 | 856 | ||
| 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; |