Add official GLM API as CC provider (#4678) * Add UI elements * Add support for model configuration * fix: update API request parameters for improved handling * Add logo img * Fix tool calling with negative index * Include tool calls into 'last in context' calculation * feat: add support for captioning
Signed| @@ -0,0 +1,3 @@ | ||
| 1 | +<svg version="1.1" x="0" y="0" xml:space="preserve" id="svg6" width="18.60156" height="15.82031" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 18.60156 15.82031"> | |
| 2 | + <path id="path2" d="M.4707 0v2.33008h7.09961c.36 0 .7004-.1807.9004-.4707L9.77147.00977S.4607.01.4707 0zm10.68946.00977L0 15.8203h7.4414L18.60157.00977Zm-.11914 13.48046c-.36 0-.7004.1807-.9004.4707l-1.31054 1.85938h9.30078v-2.33008z"/> | |
| 3 | +</svg> | |
| @@ -693,7 +693,7 @@ | ||
| 693 | 693 | </span> |
| 694 | 694 | </div> |
| 695 | 695 | </div> |
| 696 | 696 | <div class="range-block" data-source="openai,claude,aimlapi,openrouter,ai21,makersuite,vertexai,mistralai,custom,cohere,perplexity,groq,electronhub,nanogpt,deepseek,xai,pollinations,moonshot,fireworks,cometapi,azure_openai,zai"> |
| 697 | 697 | <div class="range-block-title" data-i18n="Temperature"> |
| 698 | 698 | Temperature |
| 699 | 699 | </div> |
| @@ -745,7 +745,7 @@ | ||
| 745 | 745 | </div> |
| 746 | 746 | </div> |
| 747 | 747 | </div> |
| 748 | 748 | <div class="range-block" data-source="openai,claude,aimlapi,openrouter,ai21,makersuite,vertexai,mistralai,custom,cohere,perplexity,groq,electronhub,nanogpt,deepseek,xai,pollinations,moonshot,fireworks,cometapi,azure_openai,zai"> |
| 749 | 749 | <div class="range-block-title" data-i18n="Top P"> |
| 750 | 750 | Top P |
| 751 | 751 | </div> |
| @@ -1965,7 +1965,7 @@ | ||
| 1965 | 1965 | </b> |
| 1966 | 1966 | </div> |
| 1967 | 1967 | </div> |
| 1968 | 1968 | <div class="range-block" data-source="openai,cohere,mistralai,custom,claude,aimlapi,openrouter,groq,deepseek,makersuite,vertexai,ai21,xai,pollinations,moonshot,fireworks,cometapi,electronhub,azure_openai,zai"> |
| 1969 | 1969 | <label for="openai_function_calling" class="checkbox_label flexWrap widthFreeExpand"> |
| 1970 | 1970 | <input id="openai_function_calling" type="checkbox" /> |
| 1971 | 1971 | <span data-i18n="Enable function calling">Enable function calling</span> |
| @@ -1980,7 +1980,7 @@ | ||
| 1980 | 1980 | <strong data-i18n="enable_functions_desc_4">Not supported when Prompt Post-Processing with "no tools" is used!</strong> |
| 1981 | 1981 | </div> |
| 1982 | 1982 | </div> |
| 1983 | 1983 | <div class="range-block" data-source="openai,aimlapi,openrouter,mistralai,makersuite,vertexai,claude,custom,xai,pollinations,moonshot,cohere,cometapi,nanogpt,electronhub,azure_openai,zai"> |
| 1984 | 1984 | <label for="openai_image_inlining" class="checkbox_label flexWrap widthFreeExpand"> |
| 1985 | 1985 | <input id="openai_image_inlining" type="checkbox" /> |
| 1986 | 1986 | <span data-i18n="Send inline images">Send inline images</span> |
| @@ -1996,7 +1996,7 @@ | ||
| 1996 | 1996 | <code><i class="fa-solid fa-wand-magic-sparkles"></i></code> |
| 1997 | 1997 | <span data-i18n="image_inlining_hint_3">menu to attach an image file to the chat.</span> |
| 1998 | 1998 | </div> |
| 1999 | 1999 | <div class="flex-container flexFlowColumn wide100p textAlignCenter marginTop10" data-source="openai,custom,xai,pollinations,cohere,cometapi,nanogpt,moonshot,aimlapi,openrouter,mistralai,electronhub,azure_openai,zai"> |
| 2000 | 2000 | <div class="flex-container oneline-dropdown"> |
| 2001 | 2001 | <label for="openai_inline_image_quality" data-i18n="Inline Image Quality"> |
| 2002 | 2002 | Inline Image Quality |
| @@ -2058,7 +2058,7 @@ | ||
| 2058 | 2058 | </span> |
| 2059 | 2059 | </div> |
| 2060 | 2060 | </div> |
| 2061 | 2061 | <div class="range-block" data-source="deepseek,aimlapi,openrouter,custom,claude,xai,makersuite,vertexai,pollinations,moonshot,mistralai,fireworks,cometapi,electronhub,azure_openai,nanogpt,zai"> |
| 2062 | 2062 | <label for="openai_show_thoughts" class="checkbox_label widthFreeExpand"> |
| 2063 | 2063 | <input id="openai_show_thoughts" type="checkbox" /> |
| 2064 | 2064 | <span data-i18n="Request model reasoning">Request model reasoning</span> |
| @@ -2801,6 +2801,7 @@ | ||
| 2801 | 2801 | <option value="perplexity">Perplexity</option> |
| 2802 | 2802 | <option value="pollinations">Pollinations</option> |
| 2803 | 2803 | <option value="xai">xAI (Grok)</option> |
| 2804 | + <option value="zai">Z.AI (GLM)</option> | |
| 2804 | 2805 | </optgroup> |
| 2805 | 2806 | </select> |
| 2806 | 2807 | <div class="inline-drawer wide100p" data-source="openai,claude,mistralai,makersuite,vertexai,deepseek,xai"> |
| @@ -3674,6 +3675,31 @@ | ||
| 3674 | 3675 | <option value="kimi-thinking-preview">kimi-thinking-preview</option> |
| 3675 | 3676 | </select> |
| 3676 | 3677 | </div> |
| 3678 | + <div id="zai_form" data-source="zai"> | |
| 3679 | + <h4> | |
| 3680 | + <a data-i18n="Z.AI API Key" href="https://z.ai/manage-apikey/apikey-list" target="_blank" rel="noopener noreferrer"> | |
| 3681 | + Z.AI API Key | |
| 3682 | + </a> | |
| 3683 | + </h4> | |
| 3684 | + <div class="flex-container"> | |
| 3685 | + <input id="api_key_zai" name="api_key_zai" class="text_pole flex1" value="" type="text" autocomplete="off"> | |
| 3686 | + <div title="Manage API keys" data-i18n="[title]Manage API keys" class="menu_button fa-solid fa-key fa-fw manage-api-keys" data-key="api_key_zai"></div> | |
| 3687 | + </div> | |
| 3688 | + <div data-for="api_key_zai" class="neutral_warning" data-i18n="For privacy reasons, your API key will be hidden after you click 'Connect'."> | |
| 3689 | + For privacy reasons, your API key will be hidden after you click 'Connect'. | |
| 3690 | + </div> | |
| 3691 | + <h4 data-i18n="Z.AI Model">Z.AI Model</h4> | |
| 3692 | + <select id="model_zai_select"> | |
| 3693 | + <option value="glm-4.6">glm-4.6</option> | |
| 3694 | + <option value="glm-4.5v">glm-4.5v</option> | |
| 3695 | + <option value="glm-4.5">glm-4.5</option> | |
| 3696 | + <option value="glm-4.5-air">glm-4.5-air</option> | |
| 3697 | + <option value="glm-4.5-x">glm-4.5-x</option> | |
| 3698 | + <option value="glm-4.5-airx">glm-4.5-airx</option> | |
| 3699 | + <option value="glm-4.5-flash">glm-4.5-flash</option> | |
| 3700 | + <option value="glm-4-32b-0414-128k">glm-4-32b-0414-128k</option> | |
| 3701 | + </select> | |
| 3702 | + </div> | |
| 3677 | 3703 | <div id="azure_openai_settings" data-source="azure_openai"> |
| 3678 | 3704 | <!-- Azure Base URL --> |
| 3679 | 3705 | <h4><span data-i18n="Azure Base URL">Azure Base URL</span></h4> |
| @@ -5264,7 +5264,7 @@ function setInContextMessages(msgInContextCount, type) { | ||
| 5264 | 5264 | msgInContextCount++; |
| 5265 | 5265 | } |
| 5266 | 5266 | |
| 5267 | 5267 | const lastMessageBlock = chatElement.find('.mes:not([is_system="true"]), .mes.toolCall').eq(-msgInContextCount); |
| 5268 | 5268 | lastMessageBlock.addClass('lastInContext'); |
| 5269 | 5269 | |
| 5270 | 5270 | if (lastMessageBlock.length === 0) { |
| @@ -5520,6 +5520,7 @@ export function extractJsonFromData(data, { mainApi = null, chatCompletionSource | ||
| 5520 | 5520 | case chat_completion_sources.XAI: |
| 5521 | 5521 | case chat_completion_sources.ELECTRONHUB: |
| 5522 | 5522 | case chat_completion_sources.AZURE_OPENAI: |
| 5523 | + case chat_completion_sources.ZAI: | |
| 5523 | 5524 | default: |
| 5524 | 5525 | result = tryParse(text); |
| 5525 | 5526 | break; |
| @@ -411,6 +411,7 @@ function RA_autoconnect(PrevApi) { | ||
| 411 | 411 | || (secret_state[SECRET_KEYS.MOONSHOT] && oai_settings.chat_completion_source == chat_completion_sources.MOONSHOT) |
| 412 | 412 | || (secret_state[SECRET_KEYS.FIREWORKS] && oai_settings.chat_completion_source == chat_completion_sources.FIREWORKS) |
| 413 | 413 | || (secret_state[SECRET_KEYS.COMETAPI] && oai_settings.chat_completion_source == chat_completion_sources.COMETAPI) |
| 414 | + || (secret_state[SECRET_KEYS.ZAI] && oai_settings.chat_completion_source == chat_completion_sources.ZAI) | |
| 414 | 415 | || (oai_settings.chat_completion_source === chat_completion_sources.POLLINATIONS) |
| 415 | 416 | || (isValidUrl(oai_settings.custom_url) && oai_settings.chat_completion_source == chat_completion_sources.CUSTOM) |
| 416 | 417 | || (secret_state[SECRET_KEYS.AZURE_OPENAI] && oai_settings.chat_completion_source == chat_completion_sources.AZURE_OPENAI) |
| @@ -442,6 +442,7 @@ jQuery(async function () { | ||
| 442 | 442 | 'moonshot': SECRET_KEYS.MOONSHOT, |
| 443 | 443 | 'nanogpt': SECRET_KEYS.NANOGPT, |
| 444 | 444 | 'electronhub': SECRET_KEYS.ELECTRONHUB, |
| 445 | + 'zai': SECRET_KEYS.ZAI, | |
| 445 | 446 | }; |
| 446 | 447 | |
| 447 | 448 | if (chatCompletionApis[api] && secret_state[chatCompletionApis[api]]) { |
| @@ -37,6 +37,7 @@ | ||
| 37 | 37 | <option value="pollinations">Pollinations</option> |
| 38 | 38 | <option value="vllm">vLLM</option> |
| 39 | 39 | <option value="xai">xAI (Grok)</option> |
| 40 | + <option value="zai">Z.AI (GLM)</option> | |
| 40 | 41 | </select> |
| 41 | 42 | </div> |
| 42 | 43 | <div class="flex1 flex-container flexFlowColumn flexNoGap"> |
| @@ -151,6 +152,7 @@ | ||
| 151 | 152 | <option data-type="ollama" value="mistral-small3.2">mistral-small3.2</option> |
| 152 | 153 | <option data-type="ollama" value="llama3.2-vision">llama3.2-vision</option> |
| 153 | 154 | <option data-type="ollama" value="llama4">llama4</option> |
| 155 | + <option data-type="zai" value="glm-4.5v">glm-4.5v</option> | |
| 154 | 156 | <option data-type="llamacpp" value="llamacpp_current" data-i18n="currently_loaded">[Currently loaded]</option> |
| 155 | 157 | <option data-type="ooba" value="ooba_current" data-i18n="currently_loaded">[Currently loaded]</option> |
| 156 | 158 | <option data-type="koboldcpp" value="koboldcpp_current" data-i18n="currently_loaded">[Currently loaded]</option> |
| @@ -255,6 +255,10 @@ function throwIfInvalidModel(useReverseProxy) { | ||
| 255 | 255 | if (multimodalApi === 'electronhub' && !secret_state[SECRET_KEYS.ELECTRONHUB]) { |
| 256 | 256 | throw new Error('Electron Hub API key is not set.'); |
| 257 | 257 | } |
| 258 | + | |
| 259 | + if (multimodalApi === 'zai' && !secret_state[SECRET_KEYS.ZAI]) { | |
| 260 | + throw new Error('Z.AI API key is not set.'); | |
| 261 | + } | |
| 258 | 262 | } |
| 259 | 263 | |
| 260 | 264 | /** |
| @@ -189,6 +189,7 @@ export const chat_completion_sources = { | ||
| 189 | 189 | FIREWORKS: 'fireworks', |
| 190 | 190 | COMETAPI: 'cometapi', |
| 191 | 191 | AZURE_OPENAI: 'azure_openai', |
| 192 | + ZAI: 'zai', | |
| 192 | 193 | }; |
| 193 | 194 | |
| 194 | 195 | const character_names_behavior = { |
| @@ -294,6 +295,7 @@ export const settingsToUpdate = { | ||
| 294 | 295 | custom_prompt_post_processing: ['#custom_prompt_post_processing', 'custom_prompt_post_processing', false, true], |
| 295 | 296 | google_model: ['#model_google_select', 'google_model', false, true], |
| 296 | 297 | vertexai_model: ['#model_vertexai_select', 'vertexai_model', false, true], |
| 298 | + zai_model: ['#model_zai_select', 'zai_model', false, true], | |
| 297 | 299 | openai_max_context: ['#openai_max_context', 'openai_max_context', false, false], |
| 298 | 300 | openai_max_tokens: ['#openai_max_tokens', 'openai_max_tokens', false, false], |
| 299 | 301 | wrap_in_quotes: ['#wrap_in_quotes', 'wrap_in_quotes', true, false], |
| @@ -391,6 +393,7 @@ const default_settings = { | ||
| 391 | 393 | cometapi_model: 'gpt-4o', |
| 392 | 394 | moonshot_model: 'kimi-latest', |
| 393 | 395 | fireworks_model: 'accounts/fireworks/models/kimi-k2-instruct', |
| 396 | + zai_model: 'glm-4.6', | |
| 394 | 397 | azure_base_url: '', |
| 395 | 398 | azure_deployment_name: '', |
| 396 | 399 | azure_api_version: '2024-02-15-preview', |
| @@ -487,6 +490,7 @@ const oai_settings = { | ||
| 487 | 490 | cometapi_model: 'gpt-4o', |
| 488 | 491 | moonshot_model: 'kimi-latest', |
| 489 | 492 | fireworks_model: 'accounts/fireworks/models/kimi-k2-instruct', |
| 493 | + zai_model: 'glm-4.6', | |
| 490 | 494 | azure_base_url: '', |
| 491 | 495 | azure_deployment_name: '', |
| 492 | 496 | azure_api_version: '2024-02-15-preview', |
| @@ -1532,7 +1536,7 @@ export async function prepareOpenAIMessages({ | ||
| 1532 | 1536 | const eventData = { chat, dryRun }; |
| 1533 | 1537 | await eventSource.emit(event_types.CHAT_COMPLETION_PROMPT_READY, eventData); |
| 1534 | 1538 | |
| 1535 | 1539 | openai_messages_count = chat.filter(x => !x?.tool_calls && (x?.role === ['user', ||'assistant', 'tool'].includes(x?.role === 'assistant'))?.length || 0; |
| 1536 | 1540 | |
| 1537 | 1541 | return [chat, promptManager.tokenHandler.counts]; |
| 1538 | 1542 | } |
| @@ -1664,6 +1668,8 @@ export function getChatCompletionModel(source = null) { | ||
| 1664 | 1668 | return oai_settings.fireworks_model; |
| 1665 | 1669 | case chat_completion_sources.AZURE_OPENAI: |
| 1666 | 1670 | return oai_settings.azure_openai_model; |
| 1671 | + case chat_completion_sources.ZAI: | |
| 1672 | + return oai_settings.zai_model; | |
| 1667 | 1673 | default: |
| 1668 | 1674 | console.error(`Unknown chat completion source: ${activeSource}`); |
| 1669 | 1675 | return ''; |
| @@ -1921,7 +1927,7 @@ function saveModelList(data) { | ||
| 1921 | 1927 | } |
| 1922 | 1928 | |
| 1923 | 1929 | if (oai_settings.chat_completion_source === chat_completion_sources.MAKERSUITE) { |
| 1924 | 1930 | // Clear only the "Other" optgroup for dynamic models |
| 1925 | 1931 | $('#google_other_models').empty(); |
| 1926 | 1932 | |
| 1927 | 1933 | // Get static model options that are already in the HTML |
| @@ -1932,7 +1938,7 @@ function saveModelList(data) { | ||
| 1932 | 1938 | |
| 1933 | 1939 | // Add dynamic models to the "Other" group |
| 1934 | 1940 | model_list.forEach((model) => { |
| 1935 | 1941 | // Only add if not already in static list |
| 1936 | 1942 | if (!staticModels.includes(model.id)) { |
| 1937 | 1943 | $('#google_other_models').append( |
| 1938 | 1944 | $('<option>', { |
| @@ -2299,7 +2305,8 @@ async function sendOpenAIRequest(type, messages, signal, { jsonSchema = null } = | ||
| 2299 | 2305 | const isXAI = oai_settings.chat_completion_source == chat_completion_sources.XAI; |
| 2300 | 2306 | const isPollinations = oai_settings.chat_completion_source == chat_completion_sources.POLLINATIONS; |
| 2301 | 2307 | const isMoonshot = oai_settings.chat_completion_source == chat_completion_sources.MOONSHOT; |
| 2302 | 2308 | const isAzureOpenAI = oai_settings.chat_completion_source == chat_completion_sources.AZURE_OPENAI; // Add this line |
| 2309 | + const isZai = oai_settings.chat_completion_source == chat_completion_sources.ZAI; | |
| 2303 | 2310 | const isTextCompletion = isOAI && textCompletionModels.includes(oai_settings.openai_model); |
| 2304 | 2311 | const isQuiet = type === 'quiet'; |
| 2305 | 2312 | const isImpersonate = type === 'impersonate'; |
| @@ -2500,6 +2507,14 @@ async function sendOpenAIRequest(type, messages, signal, { jsonSchema = null } = | ||
| 2500 | 2507 | generate_data['top_k'] = Number(oai_settings.top_k_openai); |
| 2501 | 2508 | } |
| 2502 | 2509 | |
| 2510 | + // https://docs.z.ai/api-reference/llm/chat-completion | |
| 2511 | + if (isZai) { | |
| 2512 | + generate_data['top_p'] = generate_data.top_p || 0.01; | |
| 2513 | + generate_data['stop'] = getCustomStoppingStrings(1); | |
| 2514 | + delete generate_data.presence_penalty; | |
| 2515 | + delete generate_data.frequency_penalty; | |
| 2516 | + } | |
| 2517 | + | |
| 2503 | 2518 | const seedSupportedSources = [ |
| 2504 | 2519 | chat_completion_sources.OPENAI, |
| 2505 | 2520 | chat_completion_sources.AZURE_OPENAI, |
| @@ -2681,7 +2696,7 @@ export function getStreamingReply(data, state, { chatCompletionSource = null, ov | ||
| 2681 | 2696 | state.reasoning += (data.choices?.filter(x => x?.delta?.reasoning)?.[0]?.delta?.reasoning || ''); |
| 2682 | 2697 | } |
| 2683 | 2698 | return data.choices?.[0]?.delta?.content ?? data.choices?.[0]?.message?.content ?? data.choices?.[0]?.text ?? ''; |
| 2684 | 2699 | } else if ([chat_completion_sources.CUSTOM, chat_completion_sources.POLLINATIONS, chat_completion_sources.AIMLAPI, chat_completion_sources.MOONSHOT, chat_completion_sources.COMETAPI, chat_completion_sources.ELECTRONHUB, chat_completion_sources.NANOGPT, chat_completion_sources.ZAI].includes(chat_completion_source)) { |
| 2685 | 2700 | if (show_thoughts) { |
| 2686 | 2701 | state.reasoning += |
| 2687 | 2702 | data.choices?.filter(x => x?.delta?.reasoning_content)?.[0]?.delta?.reasoning_content ?? |
| @@ -3655,6 +3670,7 @@ function loadOpenAISettings(data, settings) { | ||
| 3655 | 3670 | oai_settings.cometapi_model = settings.cometapi_model ?? default_settings.cometapi_model; |
| 3656 | 3671 | oai_settings.moonshot_model = settings.moonshot_model ?? default_settings.moonshot_model; |
| 3657 | 3672 | oai_settings.fireworks_model = settings.fireworks_model ?? default_settings.fireworks_model; |
| 3673 | + oai_settings.zai_model = settings.zai_model ?? default_settings.zai_model; | |
| 3658 | 3674 | oai_settings.custom_model = settings.custom_model ?? default_settings.custom_model; |
| 3659 | 3675 | oai_settings.custom_url = settings.custom_url ?? default_settings.custom_url; |
| 3660 | 3676 | oai_settings.custom_include_body = settings.custom_include_body ?? default_settings.custom_include_body; |
| @@ -3760,6 +3776,8 @@ function loadOpenAISettings(data, settings) { | ||
| 3760 | 3776 | $(`#model_pollinations_select option[value="${oai_settings.pollinations_model}"`).prop('selected', true); |
| 3761 | 3777 | $('#model_moonshot_select').val(oai_settings.moonshot_model); |
| 3762 | 3778 | $(`#model_moonshot_select option[value="${oai_settings.moonshot_model}"`).prop('selected', true); |
| 3779 | + $('#model_zai_select').val(oai_settings.zai_model); | |
| 3780 | + $(`#model_zai_select option[value="${oai_settings.zai_model}"`).prop('selected', true); | |
| 3763 | 3781 | $('#custom_model_id').val(oai_settings.custom_model); |
| 3764 | 3782 | $('#custom_api_url_text').val(oai_settings.custom_url); |
| 3765 | 3783 | $('#azure_base_url').val(oai_settings.azure_base_url); |
| @@ -3933,6 +3951,7 @@ async function getStatusOpen() { | ||
| 3933 | 3951 | chat_completion_sources.AI21, |
| 3934 | 3952 | chat_completion_sources.VERTEXAI, |
| 3935 | 3953 | chat_completion_sources.PERPLEXITY, |
| 3954 | + chat_completion_sources.ZAI, | |
| 3936 | 3955 | ]; |
| 3937 | 3956 | if (noValidateSources.includes(oai_settings.chat_completion_source)) { |
| 3938 | 3957 | let status = t`Key saved; press \"Test Message\" to verify.`; |
| @@ -4059,6 +4078,7 @@ async function saveOpenAIPreset(name, settings, triggerUi = true) { | ||
| 4059 | 4078 | moonshot_model: settings.moonshot_model, |
| 4060 | 4079 | fireworks_model: settings.fireworks_model, |
| 4061 | 4080 | cometapi_model: settings.cometapi_model, |
| 4081 | + zai_model: settings.zai_model, | |
| 4062 | 4082 | custom_model: settings.custom_model, |
| 4063 | 4083 | custom_url: settings.custom_url, |
| 4064 | 4084 | custom_include_body: settings.custom_include_body, |
| @@ -4713,6 +4733,29 @@ function getGroqMaxContext(model, isUnlocked) { | ||
| 4713 | 4733 | return Object.entries(contextMap).find(([key]) => model.includes(key))?.[1] || max_128k; |
| 4714 | 4734 | } |
| 4715 | 4735 | |
| 4736 | +/** | |
| 4737 | + * Get the maximum context size for the Z.AI model | |
| 4738 | + * @param {string} model Model identifier | |
| 4739 | + * @param {boolean} isUnlocked If context limits are unlocked | |
| 4740 | + * @returns {number} Maximum context size in tokens | |
| 4741 | + */ | |
| 4742 | +function getZaiMaxContext(model, isUnlocked) { | |
| 4743 | + if (isUnlocked) { | |
| 4744 | + return unlocked_max; | |
| 4745 | + } | |
| 4746 | + | |
| 4747 | + const contextMap = { | |
| 4748 | + 'glm-4.6': max_200k, | |
| 4749 | + 'glm-4.5': max_128k, | |
| 4750 | + 'glm-4-32b-0414-128k': max_128k, | |
| 4751 | + 'glm-4.5-air': max_128k, | |
| 4752 | + 'glm-4.5v': max_64k, | |
| 4753 | + }; | |
| 4754 | + | |
| 4755 | + // Return context size if model found, otherwise default to 128k | |
| 4756 | + return Object.entries(contextMap).find(([key]) => model.includes(key))?.[1] || max_128k; | |
| 4757 | +} | |
| 4758 | + | |
| 4716 | 4759 | function getMoonshotMaxContext(model, isUnlocked) { |
| 4717 | 4760 | if (isUnlocked) { |
| 4718 | 4761 | return unlocked_max; |
| @@ -4980,6 +5023,11 @@ async function onModelChange() { | ||
| 4980 | 5023 | oai_settings.azure_openai_model = value; |
| 4981 | 5024 | } |
| 4982 | 5025 | |
| 5026 | + if ($(this).is('#model_zai_select')) { | |
| 5027 | + console.log('ZAI model changed to', value); | |
| 5028 | + oai_settings.zai_model = value; | |
| 5029 | + } | |
| 5030 | + | |
| 4983 | 5031 | if ([chat_completion_sources.MAKERSUITE, chat_completion_sources.VERTEXAI].includes(oai_settings.chat_completion_source)) { |
| 4984 | 5032 | if (oai_settings.max_context_unlocked) { |
| 4985 | 5033 | $('#openai_max_context').attr('max', max_2mil); |
| @@ -5282,6 +5330,15 @@ async function onModelChange() { | ||
| 5282 | 5330 | $('#temp_openai').attr('max', oai_max_temp).val(oai_settings.temp_openai).trigger('input'); |
| 5283 | 5331 | } |
| 5284 | 5332 | |
| 5333 | + if (oai_settings.chat_completion_source == chat_completion_sources.ZAI) { | |
| 5334 | + const maxContext = getZaiMaxContext(oai_settings.zai_model, oai_settings.max_context_unlocked); | |
| 5335 | + $('#openai_max_context').attr('max', maxContext); | |
| 5336 | + oai_settings.openai_max_context = Math.min(Number($('#openai_max_context').attr('max')), oai_settings.openai_max_context); | |
| 5337 | + $('#openai_max_context').val(oai_settings.openai_max_context).trigger('input'); | |
| 5338 | + oai_settings.temp_openai = Math.min(claude_max_temp, oai_settings.temp_openai); | |
| 5339 | + $('#temp_openai').attr('max', claude_max_temp).val(oai_settings.temp_openai).trigger('input'); | |
| 5340 | + } | |
| 5341 | + | |
| 5285 | 5342 | $('#openai_max_context_counter').attr('max', Number($('#openai_max_context').attr('max'))); |
| 5286 | 5343 | |
| 5287 | 5344 | saveSettingsDebounced(); |
| @@ -5583,6 +5640,18 @@ async function onConnectButtonClick(e) { | ||
| 5583 | 5640 | } |
| 5584 | 5641 | } |
| 5585 | 5642 | |
| 5643 | + if (oai_settings.chat_completion_source == chat_completion_sources.ZAI) { | |
| 5644 | + const api_key_zai = String($('#api_key_zai').val()).trim(); | |
| 5645 | + | |
| 5646 | + if (api_key_zai.length) { | |
| 5647 | + await writeSecret(SECRET_KEYS.ZAI, api_key_zai); | |
| 5648 | + } | |
| 5649 | + | |
| 5650 | + if (!api_key_zai && !secret_state[SECRET_KEYS.ZAI]) { | |
| 5651 | + console.log('No secret key saved for ZAI'); | |
| 5652 | + return; | |
| 5653 | + } | |
| 5654 | + } | |
| 5586 | 5655 | |
| 5587 | 5656 | startStatusLoading(); |
| 5588 | 5657 | saveSettingsDebounced(); |
| @@ -5660,6 +5729,9 @@ function toggleChatCompletionForms() { | ||
| 5660 | 5729 | else if (oai_settings.chat_completion_source == chat_completion_sources.AZURE_OPENAI) { |
| 5661 | 5730 | $('#azure_openai_model').trigger('change'); |
| 5662 | 5731 | } |
| 5732 | + else if (oai_settings.chat_completion_source == chat_completion_sources.ZAI) { | |
| 5733 | + $('#model_zai_select').trigger('change'); | |
| 5734 | + } | |
| 5663 | 5735 | |
| 5664 | 5736 | $('[data-source]').each(function () { |
| 5665 | 5737 | const validSources = $(this).data('source').split(','); |
| @@ -5774,6 +5846,8 @@ export function isImageInliningSupported() { | ||
| 5774 | 5846 | 'moonshot-v1-8k-vision-preview', |
| 5775 | 5847 | 'moonshot-v1-32k-vision-preview', |
| 5776 | 5848 | 'moonshot-v1-128k-vision-preview', |
| 5849 | + // Z.AI (GLM) | |
| 5850 | + 'glm-4.5v', | |
| 5777 | 5851 | ]; |
| 5778 | 5852 | |
| 5779 | 5853 | switch (oai_settings.chat_completion_source) { |
| @@ -5816,6 +5890,8 @@ export function isImageInliningSupported() { | ||
| 5816 | 5890 | return visionSupportedModels.some(model => oai_settings.moonshot_model.includes(model)); |
| 5817 | 5891 | case chat_completion_sources.NANOGPT: |
| 5818 | 5892 | return (Array.isArray(model_list) && model_list.find(m => m.id === oai_settings.nanogpt_model)?.capabilities?.vision); |
| 5893 | + case chat_completion_sources.ZAI: | |
| 5894 | + return visionSupportedModels.some(model => oai_settings.zai_model.includes(model)); | |
| 5819 | 5895 | default: |
| 5820 | 5896 | return false; |
| 5821 | 5897 | } |
| @@ -6664,6 +6740,7 @@ export function initOpenAI() { | ||
| 6664 | 6740 | $('#model_moonshot_select').on('change', onModelChange); |
| 6665 | 6741 | $('#model_fireworks_select').on('change', onModelChange); |
| 6666 | 6742 | $('#azure_openai_model').on('change', onModelChange); |
| 6743 | + $('#model_zai_select').on('change', onModelChange); | |
| 6667 | 6744 | $('#settings_preset_openai').on('change', onSettingsPresetChange); |
| 6668 | 6745 | $('#new_oai_preset').on('click', onNewPresetClick); |
| 6669 | 6746 | $('#delete_oai_preset').on('click', onDeletePresetClick); |
| @@ -127,6 +127,7 @@ export function extractReasoningFromData(data, { | ||
| 127 | 127 | case chat_completion_sources.COMETAPI: |
| 128 | 128 | case chat_completion_sources.ELECTRONHUB: |
| 129 | 129 | case chat_completion_sources.NANOGPT: |
| 130 | + case chat_completion_sources.ZAI: | |
| 130 | 131 | case chat_completion_sources.CUSTOM: { |
| 131 | 132 | return data?.choices?.[0]?.message?.reasoning_content |
| 132 | 133 | ?? data?.choices?.[0]?.message?.reasoning |
| @@ -68,6 +68,7 @@ export const SECRET_KEYS = { | ||
| 68 | 68 | MINIMAX_GROUP_ID: 'minimax_group_id', |
| 69 | 69 | MOONSHOT: 'api_key_moonshot', |
| 70 | 70 | COMETAPI: 'api_key_cometapi', |
| 71 | + ZAI: 'api_key_zai', | |
| 71 | 72 | }; |
| 72 | 73 | |
| 73 | 74 | const FRIENDLY_NAMES = { |
| @@ -124,6 +125,7 @@ const FRIENDLY_NAMES = { | ||
| 124 | 125 | [SECRET_KEYS.MOONSHOT]: 'Moonshot AI', |
| 125 | 126 | [SECRET_KEYS.COMETAPI]: 'CometAPI', |
| 126 | 127 | [SECRET_KEYS.AZURE_OPENAI]: 'Azure OpenAI', |
| 128 | + [SECRET_KEYS.ZAI]: 'Z.AI', | |
| 127 | 129 | }; |
| 128 | 130 | |
| 129 | 131 | const INPUT_MAP = { |
| @@ -163,6 +165,7 @@ const INPUT_MAP = { | ||
| 163 | 165 | [SECRET_KEYS.FIREWORKS]: '#api_key_fireworks', |
| 164 | 166 | [SECRET_KEYS.COMETAPI]: '#api_key_cometapi', |
| 165 | 167 | [SECRET_KEYS.AZURE_OPENAI]: '#api_key_azure_openai', |
| 168 | + [SECRET_KEYS.ZAI]: '#api_key_zai', | |
| 166 | 169 | }; |
| 167 | 170 | |
| 168 | 171 | const getLabel = () => moment().format('L LT'); |
| @@ -4858,6 +4858,7 @@ function getModelOptions(quiet) { | ||
| 4858 | 4858 | { id: 'model_moonshot_select', api: 'openai', type: chat_completion_sources.MOONSHOT }, |
| 4859 | 4859 | { id: 'model_fireworks_select', api: 'openai', type: chat_completion_sources.FIREWORKS }, |
| 4860 | 4860 | { id: 'model_cometapi_select', api: 'openai', type: chat_completion_sources.COMETAPI }, |
| 4861 | + { id: 'model_zai_select', api: 'openai', type: chat_completion_sources.ZAI }, | |
| 4861 | 4862 | { id: 'model_novel_select', api: 'novel', type: null }, |
| 4862 | 4863 | { id: 'horde_model', api: 'koboldhorde', type: null }, |
| 4863 | 4864 | ]; |
| @@ -444,9 +444,9 @@ export class ToolManager { | ||
| 444 | 444 | } |
| 445 | 445 | |
| 446 | 446 | for (const toolCallDelta of toolCallDeltas) { |
| 447 | 447 | const toolCallIndex = (typeof toolCallDelta?.index ==>= 'number')0 ? toolCallDelta.index : toolCallDeltas.indexOf(toolCallDelta); |
| 448 | 448 | |
| 449 | 449 | if (isNaN(toolCallIndex) || toolCallIndex < 0) { |
| 450 | 450 | continue; |
| 451 | 451 | } |
| 452 | 452 | |
| @@ -661,6 +661,7 @@ export class ToolManager { | ||
| 661 | 661 | chat_completion_sources.COMETAPI, |
| 662 | 662 | chat_completion_sources.ELECTRONHUB, |
| 663 | 663 | chat_completion_sources.AZURE_OPENAI, |
| 664 | + chat_completion_sources.ZAI, | |
| 664 | 665 | ]; |
| 665 | 666 | return supportedSources.includes(oai_settings.chat_completion_source); |
| 666 | 667 | } |
| @@ -183,6 +183,7 @@ export const CHAT_COMPLETION_SOURCES = { | ||
| 183 | 183 | FIREWORKS: 'fireworks', |
| 184 | 184 | COMETAPI: 'cometapi', |
| 185 | 185 | AZURE_OPENAI: 'azure_openai', |
| 186 | + ZAI: 'zai', | |
| 186 | 187 | }; |
| 187 | 188 | |
| 188 | 189 | /** |
| @@ -73,6 +73,7 @@ const API_POLLINATIONS = 'https://text.pollinations.ai/openai'; | ||
| 73 | 73 | const API_MOONSHOT = 'https://api.moonshot.ai/v1'; |
| 74 | 74 | const API_FIREWORKS = 'https://api.fireworks.ai/inference/v1'; |
| 75 | 75 | const API_COMETAPI = 'https://api.cometapi.com/v1'; |
| 76 | +const API_ZAI = 'https://api.z.ai/api/paas/v4'; | |
| 76 | 77 | |
| 77 | 78 | /** |
| 78 | 79 | * Gets OpenRouter transforms based on the request. |
| @@ -1958,6 +1959,20 @@ router.post('/generate', function (request, response) { | ||
| 1958 | 1959 | reasoning_effort: request.body.reasoning_effort, |
| 1959 | 1960 | }; |
| 1960 | 1961 | throw new Error('This provider is temporarily disabled.'); |
| 1962 | + } else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.ZAI) { | |
| 1963 | + apiUrl = API_ZAI; | |
| 1964 | + apiKey = readSecret(request.user.directories, SECRET_KEYS.ZAI); | |
| 1965 | + headers = { | |
| 1966 | + 'Accept-Language': 'en-US,en', | |
| 1967 | + }; | |
| 1968 | + bodyParams = { | |
| 1969 | + thinking: { | |
| 1970 | + type: request.body.include_reasoning ? 'enabled' : 'disabled', | |
| 1971 | + }, | |
| 1972 | + }; | |
| 1973 | + if (request.body.json_schema) { | |
| 1974 | + setJsonObjectFormat(bodyParams, request.body.messages, request.body.json_schema); | |
| 1975 | + } | |
| 1961 | 1976 | } else { |
| 1962 | 1977 | console.warn('This chat completion source is not supported yet.'); |
| 1963 | 1978 | return response.status(400).send({ error: true }); |
| @@ -85,6 +85,10 @@ router.post('/caption-image', async (request, response) => { | ||
| 85 | 85 | key = readSecret(request.user.directories, SECRET_KEYS.ELECTRONHUB); |
| 86 | 86 | } |
| 87 | 87 | |
| 88 | + if (request.body.api === 'zai') { | |
| 89 | + key = readSecret(request.user.directories, SECRET_KEYS.ZAI); | |
| 90 | + } | |
| 91 | + | |
| 88 | 92 | const noKeyTypes = ['custom', 'ooba', 'koboldcpp', 'vllm', 'llamacpp', 'pollinations']; |
| 89 | 93 | if (!key && !request.body.reverse_proxy && !noKeyTypes.includes(request.body.api)) { |
| 90 | 94 | console.warn('No key found for API', request.body.api); |
| @@ -177,6 +181,10 @@ router.post('/caption-image', async (request, response) => { | ||
| 177 | 181 | apiUrl = 'https://api.electronhub.ai/v1/chat/completions'; |
| 178 | 182 | } |
| 179 | 183 | |
| 184 | + if (request.body.api === 'zai') { | |
| 185 | + apiUrl = 'https://api.z.ai/api/paas/v4/chat/completions'; | |
| 186 | + } | |
| 187 | + | |
| 180 | 188 | if (['koboldcpp', 'vllm', 'llamacpp', 'ooba'].includes(request.body.api)) { |
| 181 | 189 | apiUrl = `${trimV1(request.body.server_url)}/v1/chat/completions`; |
| 182 | 190 | } |
| @@ -61,6 +61,7 @@ export const SECRET_KEYS = { | ||
| 61 | 61 | MOONSHOT: 'api_key_moonshot', |
| 62 | 62 | COMETAPI: 'api_key_cometapi', |
| 63 | 63 | AZURE_OPENAI: 'api_key_azure_openai', |
| 64 | + ZAI: 'api_key_zai', | |
| 64 | 65 | }; |
| 65 | 66 | |
| 66 | 67 | /** |