Add xAI as chat completion source
| @@ -685,7 +685,7 @@ | |||
| 685 | </span> | 685 | </span> |
| 686 | </div> | 686 | </div> |
| 687 | </div> | 687 | </div> |
| 688 | <div class="range-block" data-source="openai,claude,windowai,openrouter,ai21,scale,makersuite,mistralai,custom,cohere,perplexity,groq,01ai,nanogpt,deepseek"> | 688 | <div class="range-block" data-source="openai,claude,windowai,openrouter,ai21,scale,makersuite,mistralai,custom,cohere,perplexity,groq,01ai,nanogpt,deepseek,xai"> |
| 689 | <div class="range-block-title" data-i18n="Temperature"> | 689 | <div class="range-block-title" data-i18n="Temperature"> |
| 690 | Temperature | 690 | Temperature |
| 691 | </div> | 691 | </div> |
| @@ -698,7 +698,7 @@ | |||
| 698 | </div> | 698 | </div> |
| 699 | </div> | 699 | </div> |
| 700 | </div> | 700 | </div> |
| 701 | <div class="range-block" data-source="openai,openrouter,custom,cohere,perplexity,groq,mistralai,nanogpt,deepseek"> | 701 | <div class="range-block" data-source="openai,openrouter,custom,cohere,perplexity,groq,mistralai,nanogpt,deepseek,xai"> |
| 702 | <div class="range-block-title" data-i18n="Frequency Penalty"> | 702 | <div class="range-block-title" data-i18n="Frequency Penalty"> |
| 703 | Frequency Penalty | 703 | Frequency Penalty |
| 704 | </div> | 704 | </div> |
| @@ -711,7 +711,7 @@ | |||
| 711 | </div> | 711 | </div> |
| 712 | </div> | 712 | </div> |
| 713 | </div> | 713 | </div> |
| 714 | <div class="range-block" data-source="openai,openrouter,custom,cohere,perplexity,groq,mistralai,nanogpt,deepseek"> | 714 | <div class="range-block" data-source="openai,openrouter,custom,cohere,perplexity,groq,mistralai,nanogpt,deepseek,xai"> |
| 715 | <div class="range-block-title" data-i18n="Presence Penalty"> | 715 | <div class="range-block-title" data-i18n="Presence Penalty"> |
| 716 | Presence Penalty | 716 | Presence Penalty |
| 717 | </div> | 717 | </div> |
| @@ -737,7 +737,7 @@ | |||
| 737 | </div> | 737 | </div> |
| 738 | </div> | 738 | </div> |
| 739 | </div> | 739 | </div> |
| 740 | <div class="range-block" data-source="openai,claude,openrouter,ai21,scale,makersuite,mistralai,custom,cohere,perplexity,groq,01ai,nanogpt,deepseek"> | 740 | <div class="range-block" data-source="openai,claude,openrouter,ai21,scale,makersuite,mistralai,custom,cohere,perplexity,groq,01ai,nanogpt,deepseek,xai"> |
| 741 | <div class="range-block-title" data-i18n="Top P"> | 741 | <div class="range-block-title" data-i18n="Top P"> |
| 742 | Top P | 742 | Top P |
| 743 | </div> | 743 | </div> |
| @@ -974,7 +974,7 @@ | |||
| 974 | </div> | 974 | </div> |
| 975 | </div> | 975 | </div> |
| 976 | </div> | 976 | </div> |
| 977 | <div class="range-block" data-source="openai,openrouter,mistralai,custom,cohere,groq,nanogpt"> | 977 | <div class="range-block" data-source="openai,openrouter,mistralai,custom,cohere,groq,nanogpt,xai"> |
| 978 | <div class="range-block-title justifyLeft" data-i18n="Seed"> | 978 | <div class="range-block-title justifyLeft" data-i18n="Seed"> |
| 979 | Seed | 979 | Seed |
| 980 | </div> | 980 | </div> |
| @@ -1965,7 +1965,7 @@ | |||
| 1965 | </span> | 1965 | </span> |
| 1966 | </div> | 1966 | </div> |
| 1967 | </div> | 1967 | </div> |
| 1968 | <div class="range-block" data-source="openai,cohere,mistralai,custom,claude,openrouter,groq,deepseek,makersuite,ai21"> | 1968 | <div class="range-block" data-source="openai,cohere,mistralai,custom,claude,openrouter,groq,deepseek,makersuite,ai21,xai"> |
| 1969 | <label for="openai_function_calling" class="checkbox_label flexWrap widthFreeExpand"> | 1969 | <label for="openai_function_calling" class="checkbox_label flexWrap widthFreeExpand"> |
| 1970 | <input id="openai_function_calling" type="checkbox" /> | 1970 | <input id="openai_function_calling" type="checkbox" /> |
| 1971 | <span data-i18n="Enable function calling">Enable function calling</span> | 1971 | <span data-i18n="Enable function calling">Enable function calling</span> |
| @@ -1975,7 +1975,7 @@ | |||
| 1975 | <span data-i18n="enable_functions_desc_3">Can be utilized by various extensions to provide additional functionality.</span> | 1975 | <span data-i18n="enable_functions_desc_3">Can be utilized by various extensions to provide additional functionality.</span> |
| 1976 | </div> | 1976 | </div> |
| 1977 | </div> | 1977 | </div> |
| 1978 | <div class="range-block" data-source="openai,openrouter,makersuite,claude,custom,01ai"> | 1978 | <div class="range-block" data-source="openai,openrouter,makersuite,claude,custom,01ai,xai"> |
| 1979 | <label for="openai_image_inlining" class="checkbox_label flexWrap widthFreeExpand"> | 1979 | <label for="openai_image_inlining" class="checkbox_label flexWrap widthFreeExpand"> |
| 1980 | <input id="openai_image_inlining" type="checkbox" /> | 1980 | <input id="openai_image_inlining" type="checkbox" /> |
| 1981 | <span data-i18n="Send inline images">Send inline images</span> | 1981 | <span data-i18n="Send inline images">Send inline images</span> |
| @@ -2031,7 +2031,7 @@ | |||
| 2031 | </span> | 2031 | </span> |
| 2032 | </div> | 2032 | </div> |
| 2033 | </div> | 2033 | </div> |
| 2034 | <div class="range-block" data-source="deepseek,openrouter,custom,claude"> | 2034 | <div class="range-block" data-source="deepseek,openrouter,custom,claude,xai"> |
| 2035 | <label for="openai_show_thoughts" class="checkbox_label widthFreeExpand"> | 2035 | <label for="openai_show_thoughts" class="checkbox_label widthFreeExpand"> |
| 2036 | <input id="openai_show_thoughts" type="checkbox" /> | 2036 | <input id="openai_show_thoughts" type="checkbox" /> |
| 2037 | <span> | 2037 | <span> |
| @@ -2045,7 +2045,7 @@ | |||
| 2045 | </span> | 2045 | </span> |
| 2046 | </div> | 2046 | </div> |
| 2047 | </div> | 2047 | </div> |
| 2048 | <div class="flex-container flexFlowColumn wide100p textAlignCenter marginTop10" data-source="openai,custom,claude"> | 2048 | <div class="flex-container flexFlowColumn wide100p textAlignCenter marginTop10" data-source="openai,custom,claude,xai"> |
| 2049 | <div class="flex-container oneline-dropdown" title="Constrains effort on reasoning for reasoning models. Currently supported values are low, medium, and high. Reducing reasoning effort can result in faster responses and fewer tokens used on reasoning in a response." data-i18n="[title]Constrains effort on reasoning for reasoning models."> | 2049 | <div class="flex-container oneline-dropdown" title="Constrains effort on reasoning for reasoning models. Currently supported values are low, medium, and high. Reducing reasoning effort can result in faster responses and fewer tokens used on reasoning in a response." data-i18n="[title]Constrains effort on reasoning for reasoning models."> |
| 2050 | <label for="openai_reasoning_effort"> | 2050 | <label for="openai_reasoning_effort"> |
| 2051 | <span data-i18n="Reasoning Effort">Reasoning Effort</span> | 2051 | <span data-i18n="Reasoning Effort">Reasoning Effort</span> |
| @@ -2756,6 +2756,7 @@ | |||
| 2756 | <option value="perplexity">Perplexity</option> | 2756 | <option value="perplexity">Perplexity</option> |
| 2757 | <option value="scale">Scale</option> | 2757 | <option value="scale">Scale</option> |
| 2758 | <option value="windowai">Window AI</option> | 2758 | <option value="windowai">Window AI</option> |
| 2759 | <option value="xai">xAI (Grok)</option> | ||
| 2759 | </optgroup> | 2760 | </optgroup> |
| 2760 | </select> | 2761 | </select> |
| 2761 | <div class="inline-drawer wide100p" data-source="openai,claude,mistralai,makersuite,deepseek"> | 2762 | <div class="inline-drawer wide100p" data-source="openai,claude,mistralai,makersuite,deepseek"> |
| @@ -3424,6 +3425,31 @@ | |||
| 3424 | <select id="model_01ai_select"> | 3425 | <select id="model_01ai_select"> |
| 3425 | </select> | 3426 | </select> |
| 3426 | </div> | 3427 | </div> |
| 3428 | <div id="xai_form" data-source="xai"> | ||
| 3429 | <h4> | ||
| 3430 | <a data-i18n="xAI API Key" href="https://console.x.ai/" target="_blank" rel="noopener noreferrer"> | ||
| 3431 | xAI API Key | ||
| 3432 | </a> | ||
| 3433 | </h4> | ||
| 3434 | <div class="flex-container"> | ||
| 3435 | <input id="api_key_xai" name="api_key_xai" class="text_pole flex1" value="" type="text" autocomplete="off"> | ||
| 3436 | <div title="Clear your API key" data-i18n="[title]Clear your API key" class="menu_button fa-solid fa-circle-xmark clear-api-key" data-key="api_key_xai"></div> | ||
| 3437 | </div> | ||
| 3438 | <div data-for="api_key_01ai" class="neutral_warning" data-i18n="For privacy reasons, your API key will be hidden after you reload the page."> | ||
| 3439 | For privacy reasons, your API key will be hidden after you reload the page. | ||
| 3440 | </div> | ||
| 3441 | <h4 data-i18n="xAI Model">xAI Model</h4> | ||
| 3442 | <select id="model_xai_select"> | ||
| 3443 | <option value="grok-3-beta">grok-3-beta</option> | ||
| 3444 | <option value="grok-3-fast-beta">grok-3-fast-beta</option> | ||
| 3445 | <option value="grok-3-mini-beta">grok-3-mini-beta</option> | ||
| 3446 | <option value="grok-3-mini-fast-beta">grok-3-mini-fast-beta</option> | ||
| 3447 | <option value="grok-2-vision-1212">grok-2-vision-1212</option> | ||
| 3448 | <option value="grok-2-1212">grok-2-1212</option> | ||
| 3449 | <option value="grok-vision-beta">grok-vision-beta</option> | ||
| 3450 | <option value="grok-beta">grok-beta</option> | ||
| 3451 | </select> | ||
| 3452 | </div> | ||
| 3427 | <div id="prompt_post_porcessing_form" data-source="custom,openrouter"> | 3453 | <div id="prompt_post_porcessing_form" data-source="custom,openrouter"> |
| 3428 | <h4 data-i18n="Prompt Post-Processing">Prompt Post-Processing</h4> | 3454 | <h4 data-i18n="Prompt Post-Processing">Prompt Post-Processing</h4> |
| 3429 | <select id="custom_prompt_post_processing" class="text_pole" title="Applies additional processing to the prompt before sending it to the API." data-i18n="[title]Applies additional processing to the prompt before sending it to the API."> | 3455 | <select id="custom_prompt_post_processing" class="text_pole" title="Applies additional processing to the prompt before sending it to the API." data-i18n="[title]Applies additional processing to the prompt before sending it to the API."> |
| @@ -409,6 +409,7 @@ function RA_autoconnect(PrevApi) { | |||
| 409 | || (secret_state[SECRET_KEYS.ZEROONEAI] && oai_settings.chat_completion_source == chat_completion_sources.ZEROONEAI) | 409 | || (secret_state[SECRET_KEYS.ZEROONEAI] && oai_settings.chat_completion_source == chat_completion_sources.ZEROONEAI) |
| 410 | || (secret_state[SECRET_KEYS.NANOGPT] && oai_settings.chat_completion_source == chat_completion_sources.NANOGPT) | 410 | || (secret_state[SECRET_KEYS.NANOGPT] && oai_settings.chat_completion_source == chat_completion_sources.NANOGPT) |
| 411 | || (secret_state[SECRET_KEYS.DEEPSEEK] && oai_settings.chat_completion_source == chat_completion_sources.DEEPSEEK) | 411 | || (secret_state[SECRET_KEYS.DEEPSEEK] && oai_settings.chat_completion_source == chat_completion_sources.DEEPSEEK) |
| 412 | || (secret_state[SECRET_KEYS.XAI] && oai_settings.chat_completion_source == chat_completion_sources.XAI) | ||
| 412 | || (isValidUrl(oai_settings.custom_url) && oai_settings.chat_completion_source == chat_completion_sources.CUSTOM) | 413 | || (isValidUrl(oai_settings.custom_url) && oai_settings.chat_completion_source == chat_completion_sources.CUSTOM) |
| 413 | ) { | 414 | ) { |
| 414 | $('#api_button_openai').trigger('click'); | 415 | $('#api_button_openai').trigger('click'); |
| @@ -184,6 +184,7 @@ export const chat_completion_sources = { | |||
| 184 | ZEROONEAI: '01ai', | 184 | ZEROONEAI: '01ai', |
| 185 | NANOGPT: 'nanogpt', | 185 | NANOGPT: 'nanogpt', |
| 186 | DEEPSEEK: 'deepseek', | 186 | DEEPSEEK: 'deepseek', |
| 187 | XAI: 'xai', | ||
| 187 | }; | 188 | }; |
| 188 | 189 | ||
| 189 | const character_names_behavior = { | 190 | const character_names_behavior = { |
| @@ -257,6 +258,7 @@ export const settingsToUpdate = { | |||
| 257 | nanogpt_model: ['#model_nanogpt_select', 'nanogpt_model', false], | 258 | nanogpt_model: ['#model_nanogpt_select', 'nanogpt_model', false], |
| 258 | deepseek_model: ['#model_deepseek_select', 'deepseek_model', false], | 259 | deepseek_model: ['#model_deepseek_select', 'deepseek_model', false], |
| 259 | zerooneai_model: ['#model_01ai_select', 'zerooneai_model', false], | 260 | zerooneai_model: ['#model_01ai_select', 'zerooneai_model', false], |
| 261 | xai_model: ['#model_xai_select', 'xai_model', false], | ||
| 260 | custom_model: ['#custom_model_id', 'custom_model', false], | 262 | custom_model: ['#custom_model_id', 'custom_model', false], |
| 261 | custom_url: ['#custom_api_url_text', 'custom_url', false], | 263 | custom_url: ['#custom_api_url_text', 'custom_url', false], |
| 262 | custom_include_body: ['#custom_include_body', 'custom_include_body', false], | 264 | custom_include_body: ['#custom_include_body', 'custom_include_body', false], |
| @@ -345,6 +347,7 @@ const default_settings = { | |||
| 345 | nanogpt_model: 'gpt-4o-mini', | 347 | nanogpt_model: 'gpt-4o-mini', |
| 346 | zerooneai_model: 'yi-large', | 348 | zerooneai_model: 'yi-large', |
| 347 | deepseek_model: 'deepseek-chat', | 349 | deepseek_model: 'deepseek-chat', |
| 350 | xai_model: 'grok-3-beta', | ||
| 348 | custom_model: '', | 351 | custom_model: '', |
| 349 | custom_url: '', | 352 | custom_url: '', |
| 350 | custom_include_body: '', | 353 | custom_include_body: '', |
| @@ -425,6 +428,7 @@ const oai_settings = { | |||
| 425 | nanogpt_model: 'gpt-4o-mini', | 428 | nanogpt_model: 'gpt-4o-mini', |
| 426 | zerooneai_model: 'yi-large', | 429 | zerooneai_model: 'yi-large', |
| 427 | deepseek_model: 'deepseek-chat', | 430 | deepseek_model: 'deepseek-chat', |
| 431 | xai_model: 'grok-3-beta', | ||
| 428 | custom_model: '', | 432 | custom_model: '', |
| 429 | custom_url: '', | 433 | custom_url: '', |
| 430 | custom_include_body: '', | 434 | custom_include_body: '', |
| @@ -1644,6 +1648,8 @@ export function getChatCompletionModel(source = null) { | |||
| 1644 | return oai_settings.nanogpt_model; | 1648 | return oai_settings.nanogpt_model; |
| 1645 | case chat_completion_sources.DEEPSEEK: | 1649 | case chat_completion_sources.DEEPSEEK: |
| 1646 | return oai_settings.deepseek_model; | 1650 | return oai_settings.deepseek_model; |
| 1651 | case chat_completion_sources.XAI: | ||
| 1652 | return oai_settings.xai_model; | ||
| 1647 | default: | 1653 | default: |
| 1648 | throw new Error(`Unknown chat completion source: ${activeSource}`); | 1654 | throw new Error(`Unknown chat completion source: ${activeSource}`); |
| 1649 | } | 1655 | } |
| @@ -1961,6 +1967,7 @@ async function sendOpenAIRequest(type, messages, signal) { | |||
| 1961 | const is01AI = oai_settings.chat_completion_source == chat_completion_sources.ZEROONEAI; | 1967 | const is01AI = oai_settings.chat_completion_source == chat_completion_sources.ZEROONEAI; |
| 1962 | const isNano = oai_settings.chat_completion_source == chat_completion_sources.NANOGPT; | 1968 | const isNano = oai_settings.chat_completion_source == chat_completion_sources.NANOGPT; |
| 1963 | const isDeepSeek = oai_settings.chat_completion_source == chat_completion_sources.DEEPSEEK; | 1969 | const isDeepSeek = oai_settings.chat_completion_source == chat_completion_sources.DEEPSEEK; |
| 1970 | const isXAI = oai_settings.chat_completion_source == chat_completion_sources.XAI; | ||
| 1964 | const isTextCompletion = isOAI && textCompletionModels.includes(oai_settings.openai_model); | 1971 | const isTextCompletion = isOAI && textCompletionModels.includes(oai_settings.openai_model); |
| 1965 | const isQuiet = type === 'quiet'; | 1972 | const isQuiet = type === 'quiet'; |
| 1966 | const isImpersonate = type === 'impersonate'; | 1973 | const isImpersonate = type === 'impersonate'; |
| @@ -2033,7 +2040,7 @@ async function sendOpenAIRequest(type, messages, signal) { | |||
| 2033 | } | 2040 | } |
| 2034 | 2041 | ||
| 2035 | // Add logprobs request (currently OpenAI only, max 5 on their side) | 2042 | // Add logprobs request (currently OpenAI only, max 5 on their side) |
| 2036 | if (useLogprobs && (isOAI || isCustom || isDeepSeek)) { | 2043 | if (useLogprobs && (isOAI || isCustom || isDeepSeek || isXAI)) { |
| 2037 | generate_data['logprobs'] = 5; | 2044 | generate_data['logprobs'] = 5; |
| 2038 | } | 2045 | } |
| 2039 | 2046 | ||
| @@ -2152,7 +2159,7 @@ async function sendOpenAIRequest(type, messages, signal) { | |||
| 2152 | } | 2159 | } |
| 2153 | } | 2160 | } |
| 2154 | 2161 | ||
| 2155 | if ((isOAI || isOpenRouter || isMistral || isCustom || isCohere || isNano) && oai_settings.seed >= 0) { | 2162 | if ((isOAI || isOpenRouter || isMistral || isCustom || isCohere || isNano || isXAI) && oai_settings.seed >= 0) { |
| 2156 | generate_data['seed'] = oai_settings.seed; | 2163 | generate_data['seed'] = oai_settings.seed; |
| 2157 | } | 2164 | } |
| 2158 | 2165 | ||
| @@ -2278,6 +2285,11 @@ export function getStreamingReply(data, state, { chatCompletionSource = null, ov | |||
| 2278 | state.reasoning += (data.choices?.filter(x => x?.delta?.reasoning_content)?.[0]?.delta?.reasoning_content || ''); | 2285 | state.reasoning += (data.choices?.filter(x => x?.delta?.reasoning_content)?.[0]?.delta?.reasoning_content || ''); |
| 2279 | } | 2286 | } |
| 2280 | return data.choices?.[0]?.delta?.content || ''; | 2287 | return data.choices?.[0]?.delta?.content || ''; |
| 2288 | } else if (chat_completion_source === chat_completion_sources.XAI) { | ||
| 2289 | if (show_thoughts) { | ||
| 2290 | state.reasoning += (data.choices?.filter(x => x?.delta?.reasoning_content)?.[0]?.delta?.reasoning_content || ''); | ||
| 2291 | } | ||
| 2292 | return data.choices?.[0]?.delta?.content || ''; | ||
| 2281 | } else if (chat_completion_source === chat_completion_sources.OPENROUTER) { | 2293 | } else if (chat_completion_source === chat_completion_sources.OPENROUTER) { |
| 2282 | if (show_thoughts) { | 2294 | if (show_thoughts) { |
| 2283 | state.reasoning += (data.choices?.filter(x => x?.delta?.reasoning)?.[0]?.delta?.reasoning || ''); | 2295 | state.reasoning += (data.choices?.filter(x => x?.delta?.reasoning)?.[0]?.delta?.reasoning || ''); |
| @@ -2310,6 +2322,7 @@ function parseChatCompletionLogprobs(data) { | |||
| 2310 | switch (oai_settings.chat_completion_source) { | 2322 | switch (oai_settings.chat_completion_source) { |
| 2311 | case chat_completion_sources.OPENAI: | 2323 | case chat_completion_sources.OPENAI: |
| 2312 | case chat_completion_sources.DEEPSEEK: | 2324 | case chat_completion_sources.DEEPSEEK: |
| 2325 | case chat_completion_sources.XAI: | ||
| 2313 | case chat_completion_sources.CUSTOM: | 2326 | case chat_completion_sources.CUSTOM: |
| 2314 | if (!data.choices?.length) { | 2327 | if (!data.choices?.length) { |
| 2315 | return null; | 2328 | return null; |
| @@ -3231,6 +3244,7 @@ function loadOpenAISettings(data, settings) { | |||
| 3231 | oai_settings.nanogpt_model = settings.nanogpt_model ?? default_settings.nanogpt_model; | 3244 | oai_settings.nanogpt_model = settings.nanogpt_model ?? default_settings.nanogpt_model; |
| 3232 | oai_settings.deepseek_model = settings.deepseek_model ?? default_settings.deepseek_model; | 3245 | oai_settings.deepseek_model = settings.deepseek_model ?? default_settings.deepseek_model; |
| 3233 | oai_settings.zerooneai_model = settings.zerooneai_model ?? default_settings.zerooneai_model; | 3246 | oai_settings.zerooneai_model = settings.zerooneai_model ?? default_settings.zerooneai_model; |
| 3247 | oai_settings.xai_model = settings.xai_model ?? default_settings.xai_model; | ||
| 3234 | oai_settings.custom_model = settings.custom_model ?? default_settings.custom_model; | 3248 | oai_settings.custom_model = settings.custom_model ?? default_settings.custom_model; |
| 3235 | oai_settings.custom_url = settings.custom_url ?? default_settings.custom_url; | 3249 | oai_settings.custom_url = settings.custom_url ?? default_settings.custom_url; |
| 3236 | oai_settings.custom_include_body = settings.custom_include_body ?? default_settings.custom_include_body; | 3250 | oai_settings.custom_include_body = settings.custom_include_body ?? default_settings.custom_include_body; |
| @@ -3316,6 +3330,8 @@ function loadOpenAISettings(data, settings) { | |||
| 3316 | $('#model_deepseek_select').val(oai_settings.deepseek_model); | 3330 | $('#model_deepseek_select').val(oai_settings.deepseek_model); |
| 3317 | $(`#model_deepseek_select option[value="${oai_settings.deepseek_model}"`).prop('selected', true); | 3331 | $(`#model_deepseek_select option[value="${oai_settings.deepseek_model}"`).prop('selected', true); |
| 3318 | $('#model_01ai_select').val(oai_settings.zerooneai_model); | 3332 | $('#model_01ai_select').val(oai_settings.zerooneai_model); |
| 3333 | $('#model_xai_select').val(oai_settings.xai_model); | ||
| 3334 | $(`#model_xai_select option[value="${oai_settings.xai_model}"`).attr('selected', true); | ||
| 3319 | $('#custom_model_id').val(oai_settings.custom_model); | 3335 | $('#custom_model_id').val(oai_settings.custom_model); |
| 3320 | $('#custom_api_url_text').val(oai_settings.custom_url); | 3336 | $('#custom_api_url_text').val(oai_settings.custom_url); |
| 3321 | $('#openai_max_context').val(oai_settings.openai_max_context); | 3337 | $('#openai_max_context').val(oai_settings.openai_max_context); |
| @@ -4312,6 +4328,11 @@ async function onModelChange() { | |||
| 4312 | $('#custom_model_id').val(value).trigger('input'); | 4328 | $('#custom_model_id').val(value).trigger('input'); |
| 4313 | } | 4329 | } |
| 4314 | 4330 | ||
| 4331 | if ($(this).is('#model_xai_select')) { | ||
| 4332 | console.log('XAI model changed to', value); | ||
| 4333 | oai_settings.xai_model = value; | ||
| 4334 | } | ||
| 4335 | |||
| 4315 | if (oai_settings.chat_completion_source == chat_completion_sources.SCALE) { | 4336 | if (oai_settings.chat_completion_source == chat_completion_sources.SCALE) { |
| 4316 | if (oai_settings.max_context_unlocked) { | 4337 | if (oai_settings.max_context_unlocked) { |
| 4317 | $('#openai_max_context').attr('max', unlocked_max); | 4338 | $('#openai_max_context').attr('max', unlocked_max); |
| @@ -4584,6 +4605,22 @@ async function onModelChange() { | |||
| 4584 | $('#temp_openai').attr('max', oai_max_temp).val(oai_settings.temp_openai).trigger('input'); | 4605 | $('#temp_openai').attr('max', oai_max_temp).val(oai_settings.temp_openai).trigger('input'); |
| 4585 | } | 4606 | } |
| 4586 | 4607 | ||
| 4608 | if (oai_settings.chat_completion_source === chat_completion_sources.XAI) { | ||
| 4609 | if (oai_settings.max_context_unlocked) { | ||
| 4610 | $('#openai_max_context').attr('max', unlocked_max); | ||
| 4611 | } else if (oai_settings.xai_model.includes('grok-2-vision')) { | ||
| 4612 | $('#openai_max_context').attr('max', max_32k); | ||
| 4613 | } else if (oai_settings.xai_model.includes('grok-vision')) { | ||
| 4614 | $('#openai_max_context').attr('max', max_8k); | ||
| 4615 | } else { | ||
| 4616 | $('#openai_max_context').attr('max', max_128k); | ||
| 4617 | } | ||
| 4618 | |||
| 4619 | oai_settings.openai_max_context = Math.min(Number($('#openai_max_context').attr('max')), oai_settings.openai_max_context); | ||
| 4620 | $('#openai_max_context').val(oai_settings.openai_max_context).trigger('input'); | ||
| 4621 | $('#temp_openai').attr('max', oai_max_temp).val(oai_settings.temp_openai).trigger('input'); | ||
| 4622 | } | ||
| 4623 | |||
| 4587 | if (oai_settings.chat_completion_source === chat_completion_sources.COHERE) { | 4624 | if (oai_settings.chat_completion_source === chat_completion_sources.COHERE) { |
| 4588 | oai_settings.pres_pen_openai = Math.min(Math.max(0, oai_settings.pres_pen_openai), 1); | 4625 | oai_settings.pres_pen_openai = Math.min(Math.max(0, oai_settings.pres_pen_openai), 1); |
| 4589 | $('#pres_pen_openai').attr('max', 1).attr('min', 0).val(oai_settings.pres_pen_openai).trigger('input'); | 4626 | $('#pres_pen_openai').attr('max', 1).attr('min', 0).val(oai_settings.pres_pen_openai).trigger('input'); |
| @@ -4822,6 +4859,19 @@ async function onConnectButtonClick(e) { | |||
| 4822 | } | 4859 | } |
| 4823 | } | 4860 | } |
| 4824 | 4861 | ||
| 4862 | if (oai_settings.chat_completion_source === chat_completion_sources.XAI) { | ||
| 4863 | const api_key_xai = String($('#api_key_xai').val()).trim(); | ||
| 4864 | |||
| 4865 | if (api_key_xai.length) { | ||
| 4866 | await writeSecret(SECRET_KEYS.XAI, api_key_xai); | ||
| 4867 | } | ||
| 4868 | |||
| 4869 | if (!secret_state[SECRET_KEYS.XAI]) { | ||
| 4870 | console.log('No secret key saved for XAI'); | ||
| 4871 | return; | ||
| 4872 | } | ||
| 4873 | } | ||
| 4874 | |||
| 4825 | startStatusLoading(); | 4875 | startStatusLoading(); |
| 4826 | saveSettingsDebounced(); | 4876 | saveSettingsDebounced(); |
| 4827 | await getStatusOpen(); | 4877 | await getStatusOpen(); |
| @@ -4878,6 +4928,9 @@ function toggleChatCompletionForms() { | |||
| 4878 | else if (oai_settings.chat_completion_source == chat_completion_sources.DEEPSEEK) { | 4928 | else if (oai_settings.chat_completion_source == chat_completion_sources.DEEPSEEK) { |
| 4879 | $('#model_deepseek_select').trigger('change'); | 4929 | $('#model_deepseek_select').trigger('change'); |
| 4880 | } | 4930 | } |
| 4931 | else if (oai_settings.chat_completion_source == chat_completion_sources.XAI) { | ||
| 4932 | $('#model_xai_select').trigger('change'); | ||
| 4933 | } | ||
| 4881 | $('[data-source]').each(function () { | 4934 | $('[data-source]').each(function () { |
| 4882 | const validSources = $(this).data('source').split(','); | 4935 | const validSources = $(this).data('source').split(','); |
| 4883 | $(this).toggle(validSources.includes(oai_settings.chat_completion_source)); | 4936 | $(this).toggle(validSources.includes(oai_settings.chat_completion_source)); |
| @@ -5014,6 +5067,8 @@ export function isImageInliningSupported() { | |||
| 5014 | 'pixtral-large-2411', | 5067 | 'pixtral-large-2411', |
| 5015 | 'c4ai-aya-vision-8b', | 5068 | 'c4ai-aya-vision-8b', |
| 5016 | 'c4ai-aya-vision-32b', | 5069 | 'c4ai-aya-vision-32b', |
| 5070 | 'grok-2-vision', | ||
| 5071 | 'grok-vision', | ||
| 5017 | ]; | 5072 | ]; |
| 5018 | 5073 | ||
| 5019 | switch (oai_settings.chat_completion_source) { | 5074 | switch (oai_settings.chat_completion_source) { |
| @@ -5033,6 +5088,8 @@ export function isImageInliningSupported() { | |||
| 5033 | return visionSupportedModels.some(model => oai_settings.mistralai_model.includes(model)); | 5088 | return visionSupportedModels.some(model => oai_settings.mistralai_model.includes(model)); |
| 5034 | case chat_completion_sources.COHERE: | 5089 | case chat_completion_sources.COHERE: |
| 5035 | return visionSupportedModels.some(model => oai_settings.cohere_model.includes(model)); | 5090 | return visionSupportedModels.some(model => oai_settings.cohere_model.includes(model)); |
| 5091 | case chat_completion_sources.XAI: | ||
| 5092 | return visionSupportedModels.some(model => oai_settings.xai_model.includes(model)); | ||
| 5036 | default: | 5093 | default: |
| 5037 | return false; | 5094 | return false; |
| 5038 | } | 5095 | } |
| @@ -5629,6 +5686,7 @@ export function initOpenAI() { | |||
| 5629 | $('#model_deepseek_select').on('change', onModelChange); | 5686 | $('#model_deepseek_select').on('change', onModelChange); |
| 5630 | $('#model_01ai_select').on('change', onModelChange); | 5687 | $('#model_01ai_select').on('change', onModelChange); |
| 5631 | $('#model_custom_select').on('change', onModelChange); | 5688 | $('#model_custom_select').on('change', onModelChange); |
| 5689 | $('#model_xai_select').on('change', onModelChange); | ||
| 5632 | $('#settings_preset_openai').on('change', onSettingsPresetChange); | 5690 | $('#settings_preset_openai').on('change', onSettingsPresetChange); |
| 5633 | $('#new_oai_preset').on('click', onNewPresetClick); | 5691 | $('#new_oai_preset').on('click', onNewPresetClick); |
| 5634 | $('#delete_oai_preset').on('click', onDeletePresetClick); | 5692 | $('#delete_oai_preset').on('click', onDeletePresetClick); |
| @@ -109,6 +109,8 @@ export function extractReasoningFromData(data, { | |||
| 109 | switch (chatCompletionSource ?? oai_settings.chat_completion_source) { | 109 | switch (chatCompletionSource ?? oai_settings.chat_completion_source) { |
| 110 | case chat_completion_sources.DEEPSEEK: | 110 | case chat_completion_sources.DEEPSEEK: |
| 111 | return data?.choices?.[0]?.message?.reasoning_content ?? ''; | 111 | return data?.choices?.[0]?.message?.reasoning_content ?? ''; |
| 112 | case chat_completion_sources.XAI: | ||
| 113 | return data?.choices?.[0]?.message?.reasoning_content ?? ''; | ||
| 112 | case chat_completion_sources.OPENROUTER: | 114 | case chat_completion_sources.OPENROUTER: |
| 113 | return data?.choices?.[0]?.message?.reasoning ?? ''; | 115 | return data?.choices?.[0]?.message?.reasoning ?? ''; |
| 114 | case chat_completion_sources.MAKERSUITE: | 116 | case chat_completion_sources.MAKERSUITE: |
| @@ -42,6 +42,7 @@ export const SECRET_KEYS = { | |||
| 42 | DEEPSEEK: 'api_key_deepseek', | 42 | DEEPSEEK: 'api_key_deepseek', |
| 43 | SERPER: 'api_key_serper', | 43 | SERPER: 'api_key_serper', |
| 44 | FALAI: 'api_key_falai', | 44 | FALAI: 'api_key_falai', |
| 45 | XAI: 'api_key_xai', | ||
| 45 | }; | 46 | }; |
| 46 | 47 | ||
| 47 | const INPUT_MAP = { | 48 | const INPUT_MAP = { |
| @@ -76,6 +77,7 @@ const INPUT_MAP = { | |||
| 76 | [SECRET_KEYS.NANOGPT]: '#api_key_nanogpt', | 77 | [SECRET_KEYS.NANOGPT]: '#api_key_nanogpt', |
| 77 | [SECRET_KEYS.GENERIC]: '#api_key_generic', | 78 | [SECRET_KEYS.GENERIC]: '#api_key_generic', |
| 78 | [SECRET_KEYS.DEEPSEEK]: '#api_key_deepseek', | 79 | [SECRET_KEYS.DEEPSEEK]: '#api_key_deepseek', |
| 80 | [SECRET_KEYS.XAI]: '#api_key_xai', | ||
| 79 | }; | 81 | }; |
| 80 | 82 | ||
| 81 | async function clearSecret() { | 83 | async function clearSecret() { |
| @@ -3942,6 +3942,7 @@ function getModelOptions(quiet) { | |||
| 3942 | { id: 'model_nanogpt_select', api: 'openai', type: chat_completion_sources.NANOGPT }, | 3942 | { id: 'model_nanogpt_select', api: 'openai', type: chat_completion_sources.NANOGPT }, |
| 3943 | { id: 'model_01ai_select', api: 'openai', type: chat_completion_sources.ZEROONEAI }, | 3943 | { id: 'model_01ai_select', api: 'openai', type: chat_completion_sources.ZEROONEAI }, |
| 3944 | { id: 'model_deepseek_select', api: 'openai', type: chat_completion_sources.DEEPSEEK }, | 3944 | { id: 'model_deepseek_select', api: 'openai', type: chat_completion_sources.DEEPSEEK }, |
| 3945 | { id: 'model_xai_select', api: 'openai', type: chat_completion_sources.XAI }, | ||
| 3945 | { id: 'model_novel_select', api: 'novel', type: null }, | 3946 | { id: 'model_novel_select', api: 'novel', type: null }, |
| 3946 | { id: 'horde_model', api: 'koboldhorde', type: null }, | 3947 | { id: 'horde_model', api: 'koboldhorde', type: null }, |
| 3947 | ]; | 3948 | ]; |
| @@ -586,6 +586,7 @@ export class ToolManager { | |||
| 586 | chat_completion_sources.DEEPSEEK, | 586 | chat_completion_sources.DEEPSEEK, |
| 587 | chat_completion_sources.MAKERSUITE, | 587 | chat_completion_sources.MAKERSUITE, |
| 588 | chat_completion_sources.AI21, | 588 | chat_completion_sources.AI21, |
| 589 | chat_completion_sources.XAI, | ||
| 589 | ]; | 590 | ]; |
| 590 | return supportedSources.includes(oai_settings.chat_completion_source); | 591 | return supportedSources.includes(oai_settings.chat_completion_source); |
| 591 | } | 592 | } |
| @@ -176,6 +176,7 @@ export const CHAT_COMPLETION_SOURCES = { | |||
| 176 | ZEROONEAI: '01ai', | 176 | ZEROONEAI: '01ai', |
| 177 | NANOGPT: 'nanogpt', | 177 | NANOGPT: 'nanogpt', |
| 178 | DEEPSEEK: 'deepseek', | 178 | DEEPSEEK: 'deepseek', |
| 179 | XAI: 'xai', | ||
| 179 | }; | 180 | }; |
| 180 | 181 | ||
| 181 | /** | 182 | /** |
| @@ -53,6 +53,7 @@ const API_01AI = 'https://api.lingyiwanwu.com/v1'; | |||
| 53 | const API_AI21 = 'https://api.ai21.com/studio/v1'; | 53 | const API_AI21 = 'https://api.ai21.com/studio/v1'; |
| 54 | const API_NANOGPT = 'https://nano-gpt.com/api/v1'; | 54 | const API_NANOGPT = 'https://nano-gpt.com/api/v1'; |
| 55 | const API_DEEPSEEK = 'https://api.deepseek.com/beta'; | 55 | const API_DEEPSEEK = 'https://api.deepseek.com/beta'; |
| 56 | const API_XAI = 'https://api.x.ai/v1'; | ||
| 56 | 57 | ||
| 57 | /** | 58 | /** |
| 58 | * Applies a post-processing step to the generated messages. | 59 | * Applies a post-processing step to the generated messages. |
| @@ -872,6 +873,9 @@ router.post('/status', async function (request, response_getstatus_openai) { | |||
| 872 | api_url = new URL(request.body.reverse_proxy || API_DEEPSEEK.replace('/beta', '')); | 873 | api_url = new URL(request.body.reverse_proxy || API_DEEPSEEK.replace('/beta', '')); |
| 873 | api_key_openai = request.body.reverse_proxy ? request.body.proxy_password : readSecret(request.user.directories, SECRET_KEYS.DEEPSEEK); | 874 | api_key_openai = request.body.reverse_proxy ? request.body.proxy_password : readSecret(request.user.directories, SECRET_KEYS.DEEPSEEK); |
| 874 | headers = {}; | 875 | headers = {}; |
| 876 | } else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.XAI) { | ||
| 877 | api_url = API_XAI; | ||
| 878 | api_key_openai = readSecret(request.user.directories, SECRET_KEYS.XAI); | ||
| 875 | } else { | 879 | } else { |
| 876 | console.warn('This chat completion source is not supported yet.'); | 880 | console.warn('This chat completion source is not supported yet.'); |
| 877 | return response_getstatus_openai.status(400).send({ error: true }); | 881 | return response_getstatus_openai.status(400).send({ error: true }); |
| @@ -1150,6 +1154,11 @@ router.post('/generate', function (request, response) { | |||
| 1150 | apiKey = readSecret(request.user.directories, SECRET_KEYS.ZEROONEAI); | 1154 | apiKey = readSecret(request.user.directories, SECRET_KEYS.ZEROONEAI); |
| 1151 | headers = {}; | 1155 | headers = {}; |
| 1152 | bodyParams = {}; | 1156 | bodyParams = {}; |
| 1157 | } else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.XAI) { | ||
| 1158 | apiUrl = API_XAI; | ||
| 1159 | apiKey = readSecret(request.user.directories, SECRET_KEYS.XAI); | ||
| 1160 | headers = {}; | ||
| 1161 | bodyParams = {}; | ||
| 1153 | } else { | 1162 | } else { |
| 1154 | console.warn('This chat completion source is not supported yet.'); | 1163 | console.warn('This chat completion source is not supported yet.'); |
| 1155 | return response.status(400).send({ error: true }); | 1164 | return response.status(400).send({ error: true }); |
| @@ -1162,6 +1171,12 @@ router.post('/generate', function (request, response) { | |||
| 1162 | } | 1171 | } |
| 1163 | } | 1172 | } |
| 1164 | 1173 | ||
| 1174 | if ([CHAT_COMPLETION_SOURCES.XAI].includes(request.body.chat_completion_source)) { | ||
| 1175 | if (['grok-3-mini-beta', 'grok-3-mini-fast-beta'].includes(request.body.model)) { | ||
| 1176 | bodyParams['reasoning_effort'] = request.body.reasoning_effort === 'high' ? 'high' : 'low'; | ||
| 1177 | } | ||
| 1178 | } | ||
| 1179 | |||
| 1165 | if (!apiKey && !request.body.reverse_proxy && request.body.chat_completion_source !== CHAT_COMPLETION_SOURCES.CUSTOM) { | 1180 | if (!apiKey && !request.body.reverse_proxy && request.body.chat_completion_source !== CHAT_COMPLETION_SOURCES.CUSTOM) { |
| 1166 | console.warn('OpenAI API key is missing.'); | 1181 | console.warn('OpenAI API key is missing.'); |
| 1167 | return response.status(400).send({ error: true }); | 1182 | return response.status(400).send({ error: true }); |
| @@ -52,6 +52,7 @@ export const SECRET_KEYS = { | |||
| 52 | GENERIC: 'api_key_generic', | 52 | GENERIC: 'api_key_generic', |
| 53 | DEEPSEEK: 'api_key_deepseek', | 53 | DEEPSEEK: 'api_key_deepseek', |
| 54 | SERPER: 'api_key_serper', | 54 | SERPER: 'api_key_serper', |
| 55 | XAI: 'api_key_xai', | ||
| 55 | }; | 56 | }; |
| 56 | 57 | ||
| 57 | // These are the keys that are safe to expose, even if allowKeysExposure is false | 58 | // These are the keys that are safe to expose, even if allowKeysExposure is false |