diff --git a/README.md b/README.md index a23c94bcf6e..428d1864bb2 100644 --- a/README.md +++ b/README.md @@ -99,6 +99,7 @@ AnythingLLM divides your documents into objects called `workspaces`. A Workspace - [Text Generation Web UI](https://github.com/oobabooga/text-generation-webui) - [Apipie](https://apipie.ai/) - [xAI](https://x.ai/) +- [Z.AI (chat models)](https://z.ai/model-api) - [Novita AI (chat models)](https://novita.ai/model-api/product/llm-api?utm_source=github_anything-llm&utm_medium=github_readme&utm_campaign=link) - [PPIO](https://ppinfra.com?utm_source=github_anything-llm) - [Moonshot AI](https://www.moonshot.ai/) diff --git a/docker/.env.example b/docker/.env.example index 27fa1c013c6..5a51d796d6c 100644 --- a/docker/.env.example +++ b/docker/.env.example @@ -128,6 +128,10 @@ GID='1000' # XAI_LLM_API_KEY='xai-your-api-key-here' # XAI_LLM_MODEL_PREF='grok-beta' +# LLM_PROVIDER='zai' +# ZAI_API_KEY="your-zai-api-key-here" +# ZAI_MODEL_PREF="glm-4.5" + # LLM_PROVIDER='nvidia-nim' # NVIDIA_NIM_LLM_BASE_PATH='http://127.0.0.1:8000' # NVIDIA_NIM_LLM_MODEL_PREF='meta/llama-3.2-3b-instruct' diff --git a/frontend/src/components/LLMSelection/ZAiLLMOptions/index.jsx b/frontend/src/components/LLMSelection/ZAiLLMOptions/index.jsx new file mode 100644 index 00000000000..c31826f4cd4 --- /dev/null +++ b/frontend/src/components/LLMSelection/ZAiLLMOptions/index.jsx @@ -0,0 +1,114 @@ +import { useState, useEffect } from "react"; +import System from "@/models/system"; + +export default function ZAiLLMOptions({ settings }) { + const [inputValue, setInputValue] = useState(settings?.ZAiApiKey); + const [apiKey, setApiKey] = useState(settings?.ZAiApiKey); + + return ( +
+
+ + setInputValue(e.target.value)} + onBlur={() => setApiKey(inputValue)} + /> +
+ + {!settings?.credentialsOnly && ( + + )} +
+ ); +} + +function ZAiModelSelection({ apiKey, settings }) { + const [customModels, setCustomModels] = useState([]); + const [loading, setLoading] = useState(true); + + useEffect(() => { + async function findCustomModels() { + if (!apiKey) { + setCustomModels([]); + setLoading(true); + return; + } + + try { + setLoading(true); + const { models } = await System.customModels("zai", apiKey); + setCustomModels(models || []); + } catch (error) { + console.error("Failed to fetch custom models:", error); + setCustomModels([]); + } finally { + setLoading(false); + } + } + findCustomModels(); + }, [apiKey]); + + if (loading) { + return ( +
+ + +

+ Enter a valid API key to view all available models for your account. +

+
+ ); + } + + return ( +
+ + +

+ Select the Z.AI model you want to use for your conversations. +

+
+ ); +} diff --git a/frontend/src/media/llmprovider/zai.png b/frontend/src/media/llmprovider/zai.png new file mode 100644 index 00000000000..e83c6da4c0a Binary files /dev/null and b/frontend/src/media/llmprovider/zai.png differ diff --git a/frontend/src/pages/GeneralSettings/LLMPreference/index.jsx b/frontend/src/pages/GeneralSettings/LLMPreference/index.jsx index 671f7e867da..19177607000 100644 --- a/frontend/src/pages/GeneralSettings/LLMPreference/index.jsx +++ b/frontend/src/pages/GeneralSettings/LLMPreference/index.jsx @@ -29,6 +29,7 @@ import AWSBedrockLogo from "@/media/llmprovider/bedrock.png"; import DeepSeekLogo from "@/media/llmprovider/deepseek.png"; import APIPieLogo from "@/media/llmprovider/apipie.png"; import XAILogo from "@/media/llmprovider/xai.png"; +import ZAiLogo from "@/media/llmprovider/zai.png"; import NvidiaNimLogo from "@/media/llmprovider/nvidia-nim.png"; import PPIOLogo from "@/media/llmprovider/ppio.png"; import DellProAiStudioLogo from "@/media/llmprovider/dpais.png"; @@ -62,6 +63,7 @@ import AWSBedrockLLMOptions from "@/components/LLMSelection/AwsBedrockLLMOptions import DeepSeekOptions from "@/components/LLMSelection/DeepSeekOptions"; import ApiPieLLMOptions from "@/components/LLMSelection/ApiPieOptions"; import XAILLMOptions from "@/components/LLMSelection/XAiLLMOptions"; +import ZAiLLMOptions from "@/components/LLMSelection/ZAiLLMOptions"; import NvidiaNimOptions from "@/components/LLMSelection/NvidiaNimOptions"; import PPIOLLMOptions from "@/components/LLMSelection/PPIOLLMOptions"; import DellProAiStudioOptions from "@/components/LLMSelection/DPAISOptions"; @@ -335,6 +337,14 @@ export const AVAILABLE_LLM_PROVIDERS = [ description: "Run xAI's powerful LLMs like Grok-2 and more.", requiredConfig: ["XAIApiKey", "XAIModelPref"], }, + { + name: "Z.AI", + value: "zai", + logo: ZAiLogo, + options: (settings) => , + description: "Run Z.AI's powerful GLM models.", + requiredConfig: ["ZAiApiKey"], + }, { name: "Generic OpenAI", value: "generic-openai", diff --git a/frontend/src/pages/OnboardingFlow/Steps/DataHandling/index.jsx b/frontend/src/pages/OnboardingFlow/Steps/DataHandling/index.jsx index b12979a889d..fbb767c82c8 100644 --- a/frontend/src/pages/OnboardingFlow/Steps/DataHandling/index.jsx +++ b/frontend/src/pages/OnboardingFlow/Steps/DataHandling/index.jsx @@ -25,6 +25,7 @@ import AWSBedrockLogo from "@/media/llmprovider/bedrock.png"; import DeepSeekLogo from "@/media/llmprovider/deepseek.png"; import APIPieLogo from "@/media/llmprovider/apipie.png"; import XAILogo from "@/media/llmprovider/xai.png"; +import ZAiLogo from "@/media/llmprovider/zai.png"; import CohereLogo from "@/media/llmprovider/cohere.png"; import ZillizLogo from "@/media/vectordbs/zilliz.png"; import AstraDBLogo from "@/media/vectordbs/astraDB.png"; @@ -231,6 +232,15 @@ export const LLM_SELECTION_PRIVACY = { ], logo: XAILogo, }, + zai: { + name: "Z.AI", + description: [ + "Your content is processed in real-time and not stored on Z.AI servers", + "Your prompts and document text are visible to Z.AI during processing", + "Data is processed in accordance with Z.AI's API Services terms", + ], + logo: ZAiLogo, + }, ppio: { name: "PPIO", description: [ diff --git a/frontend/src/pages/OnboardingFlow/Steps/LLMPreference/index.jsx b/frontend/src/pages/OnboardingFlow/Steps/LLMPreference/index.jsx index 7a16985fe11..ed4b02f7660 100644 --- a/frontend/src/pages/OnboardingFlow/Steps/LLMPreference/index.jsx +++ b/frontend/src/pages/OnboardingFlow/Steps/LLMPreference/index.jsx @@ -23,6 +23,7 @@ import DeepSeekLogo from "@/media/llmprovider/deepseek.png"; import APIPieLogo from "@/media/llmprovider/apipie.png"; import NovitaLogo from "@/media/llmprovider/novita.png"; import XAILogo from "@/media/llmprovider/xai.png"; +import ZAiLogo from "@/media/llmprovider/zai.png"; import NvidiaNimLogo from "@/media/llmprovider/nvidia-nim.png"; import CohereLogo from "@/media/llmprovider/cohere.png"; import PPIOLogo from "@/media/llmprovider/ppio.png"; @@ -54,6 +55,7 @@ import DeepSeekOptions from "@/components/LLMSelection/DeepSeekOptions"; import ApiPieLLMOptions from "@/components/LLMSelection/ApiPieOptions"; import NovitaLLMOptions from "@/components/LLMSelection/NovitaLLMOptions"; import XAILLMOptions from "@/components/LLMSelection/XAiLLMOptions"; +import ZAiLLMOptions from "@/components/LLMSelection/ZAiLLMOptions"; import NvidiaNimOptions from "@/components/LLMSelection/NvidiaNimOptions"; import PPIOLLMOptions from "@/components/LLMSelection/PPIOLLMOptions"; import DellProAiStudioOptions from "@/components/LLMSelection/DPAISOptions"; @@ -267,6 +269,13 @@ const LLMS = [ options: (settings) => , description: "Run xAI's powerful LLMs like Grok-2 and more.", }, + { + name: "Z.AI", + value: "zai", + logo: ZAiLogo, + options: (settings) => , + description: "Run Z.AI's powerful GLM models.", + }, { name: "Moonshot AI", value: "moonshotai", diff --git a/frontend/src/pages/WorkspaceSettings/AgentConfig/AgentLLMSelection/index.jsx b/frontend/src/pages/WorkspaceSettings/AgentConfig/AgentLLMSelection/index.jsx index 467bae855a4..427844f1a8a 100644 --- a/frontend/src/pages/WorkspaceSettings/AgentConfig/AgentLLMSelection/index.jsx +++ b/frontend/src/pages/WorkspaceSettings/AgentConfig/AgentLLMSelection/index.jsx @@ -29,11 +29,13 @@ const ENABLED_PROVIDERS = [ "litellm", "apipie", "xai", + "zai", "nvidia-nim", "gemini", "moonshotai", "cometapi", "foundry", + "zai", // TODO: More agent support. // "cohere", // Has tool calling and will need to build explicit support // "huggingface" // Can be done but already has issues with no-chat templated. Needs to be tested. diff --git a/locales/README.fa-IR.md b/locales/README.fa-IR.md index c28abf648ae..342aed2dd55 100644 --- a/locales/README.fa-IR.md +++ b/locales/README.fa-IR.md @@ -102,6 +102,7 @@ AnythingLLM اسناد شما را به اشیایی به نام `workspaces` ت - [Text Generation Web UI](https://github.com/oobabooga/text-generation-webui) - [Apipie](https://apipie.ai/) - [xAI](https://x.ai/) +- [Z.AI (chat models)](https://z.ai/model-api) - [Novita AI (chat models)](https://novita.ai/model-api/product/llm-api?utm_source=github_anything-llm&utm_medium=github_readme&utm_campaign=link) - [PPIO](https://ppinfra.com?utm_source=github_anything-llm) diff --git a/locales/README.ja-JP.md b/locales/README.ja-JP.md index d6fef0fa5b7..afb4e5aff14 100644 --- a/locales/README.ja-JP.md +++ b/locales/README.ja-JP.md @@ -90,6 +90,8 @@ AnythingLLMは、ドキュメントを`ワークスペース`と呼ばれるオ - [Groq](https://groq.com/) - [Cohere](https://cohere.com/) - [KoboldCPP](https://github.com/LostRuins/koboldcpp) +- [xAI](https://x.ai/) +- [Z.AI (チャットモデル)](https://z.ai/model-api) - [PPIO](https://ppinfra.com?utm_source=github_anything-llm) - [CometAPI (チャットモデル)](https://api.cometapi.com/) diff --git a/locales/README.tr-TR.md b/locales/README.tr-TR.md index 9f539779503..1743db31884 100644 --- a/locales/README.tr-TR.md +++ b/locales/README.tr-TR.md @@ -33,9 +33,9 @@ Belgelerinizle sohbet edin, yapay zeka ajanlarını kullanın, son derece özell

-

-👉 Masaüstü için AnythingLLM (Mac, Windows ve Linux)! Şimdi İndir -

+

+👉 Masaüstü için AnythingLLM (Mac, Windows ve Linux)! Şimdi İndir +

Herhangi bir belgeyi, kaynağı veya içeriği sohbet sırasında herhangi bir büyük dil modelinin referans olarak kullanabileceği bir bağlama dönüştürmenizi sağlayan tam kapsamlı bir uygulama. Bu uygulama, kullanmak istediğiniz LLM veya Vektör Veritabanını seçmenize olanak tanırken, çok kullanıcılı yönetim ve yetkilendirme desteği de sunar. @@ -48,29 +48,29 @@ Herhangi bir belgeyi, kaynağı veya içeriği sohbet sırasında herhangi bir b -### Ürün Genel Bakışı +### Ürün Genel Bakışı -AnythingLLM, ticari hazır büyük dil modellerini veya popüler açık kaynak LLM'leri ve vektör veritabanı çözümlerini kullanarak, hiçbir ödün vermeden özel bir ChatGPT oluşturmanıza olanak tanıyan tam kapsamlı bir uygulamadır. Bu uygulamayı yerel olarak çalıştırabilir veya uzaktan barındırarak sağladığınız belgelerle akıllı sohbetler gerçekleştirebilirsiniz. +AnythingLLM, ticari hazır büyük dil modellerini veya popüler açık kaynak LLM'leri ve vektör veritabanı çözümlerini kullanarak, hiçbir ödün vermeden özel bir ChatGPT oluşturmanıza olanak tanıyan tam kapsamlı bir uygulamadır. Bu uygulamayı yerel olarak çalıştırabilir veya uzaktan barındırarak sağladığınız belgelerle akıllı sohbetler gerçekleştirebilirsiniz. -AnythingLLM, belgelerinizi **"çalışma alanları" (workspaces)** adı verilen nesnelere ayırır. Bir çalışma alanı, bir sohbet dizisi gibi çalışır ancak belgelerinizi kapsülleyen bir yapı sunar. Çalışma alanları belgeleri paylaşabilir, ancak birbirleriyle iletişim kurmaz, böylece her çalışma alanının bağlamını temiz tutabilirsiniz. +AnythingLLM, belgelerinizi **"çalışma alanları" (workspaces)** adı verilen nesnelere ayırır. Bir çalışma alanı, bir sohbet dizisi gibi çalışır ancak belgelerinizi kapsülleyen bir yapı sunar. Çalışma alanları belgeleri paylaşabilir, ancak birbirleriyle iletişim kurmaz, böylece her çalışma alanının bağlamını temiz tutabilirsiniz. -## AnythingLLM’in Harika Özellikleri +## AnythingLLM’in Harika Özellikleri -- 🆕 [**Özel Yapay Zeka Ajanları**](https://docs.anythingllm.com/agent/custom/introduction) -- 🆕 [**Kod yazmadan AI Ajanı oluşturma aracı**](https://docs.anythingllm.com/agent-flows/overview) -- 🖼️ **Çoklu-mod desteği (hem kapalı kaynak hem de açık kaynak LLM'ler!)** -- 👤 Çok kullanıcılı destek ve yetkilendirme _(Yalnızca Docker sürümünde)_ -- 🦾 Çalışma alanı içinde ajanlar (web'de gezinme vb.) -- 💬 [Web sitenize gömülebilir özel sohbet aracı](https://github.com/Mintplex-Labs/anythingllm-embed/blob/main/README.md) _(Yalnızca Docker sürümünde)_ -- 📖 Çoklu belge türü desteği (PDF, TXT, DOCX vb.) -- Sade ve kullanışlı sohbet arayüzü, sürükle-bırak özelliği ve net kaynak gösterimi. -- %100 bulut konuşlandırmaya hazır. -- [Tüm popüler kapalı ve açık kaynak LLM sağlayıcılarıyla](#supported-llms-embedder-models-speech-models-and-vector-databases) uyumlu. -- Büyük belgeleri yönetirken zaman ve maliyet tasarrufu sağlayan dahili optimizasyonlar. -- Özel entegrasyonlar için tam kapsamlı Geliştirici API’si. +- 🆕 [**Özel Yapay Zeka Ajanları**](https://docs.anythingllm.com/agent/custom/introduction) +- 🆕 [**Kod yazmadan AI Ajanı oluşturma aracı**](https://docs.anythingllm.com/agent-flows/overview) +- 🖼️ **Çoklu-mod desteği (hem kapalı kaynak hem de açık kaynak LLM'ler!)** +- 👤 Çok kullanıcılı destek ve yetkilendirme _(Yalnızca Docker sürümünde)_ +- 🦾 Çalışma alanı içinde ajanlar (web'de gezinme vb.) +- 💬 [Web sitenize gömülebilir özel sohbet aracı](https://github.com/Mintplex-Labs/anythingllm-embed/blob/main/README.md) _(Yalnızca Docker sürümünde)_ +- 📖 Çoklu belge türü desteği (PDF, TXT, DOCX vb.) +- Sade ve kullanışlı sohbet arayüzü, sürükle-bırak özelliği ve net kaynak gösterimi. +- %100 bulut konuşlandırmaya hazır. +- [Tüm popüler kapalı ve açık kaynak LLM sağlayıcılarıyla](#supported-llms-embedder-models-speech-models-and-vector-databases) uyumlu. +- Büyük belgeleri yönetirken zaman ve maliyet tasarrufu sağlayan dahili optimizasyonlar. +- Özel entegrasyonlar için tam kapsamlı Geliştirici API’si. - Ve çok daha fazlası... Kurup keşfedin! -### Desteklenen LLM'ler, Embedding Modelleri, Konuşma Modelleri ve Vektör Veritabanları +### Desteklenen LLM'ler, Embedding Modelleri, Konuşma Modelleri ve Vektör Veritabanları **Büyük Dil Modelleri (LLMs):** @@ -99,6 +99,7 @@ AnythingLLM, belgelerinizi **"çalışma alanları" (workspaces)** adı verilen - [Text Generation Web UI](https://github.com/oobabooga/text-generation-webui) - [Apipie](https://apipie.ai/) - [xAI](https://x.ai/) +- [Z.AI (chat models)](https://z.ai/model-api) - [Novita AI (chat models)](https://novita.ai/model-api/product/llm-api?utm_source=github_anything-llm&utm_medium=github_readme&utm_campaign=link) - [PPIO](https://ppinfra.com?utm_source=github_anything-llm) @@ -141,18 +142,18 @@ AnythingLLM, belgelerinizi **"çalışma alanları" (workspaces)** adı verilen - [Milvus](https://milvus.io) - [Zilliz](https://zilliz.com) -### Teknik Genel Bakış +### Teknik Genel Bakış -Bu monorepo üç ana bölümden oluşmaktadır: +Bu monorepo üç ana bölümden oluşmaktadır: -- **`frontend`**: ViteJS + React tabanlı bir ön yüz, LLM'in kullanabileceği tüm içeriği kolayca oluşturup yönetmenizi sağlar. -- **`server`**: NodeJS ve Express tabanlı bir sunucu, tüm etkileşimleri yönetir ve vektör veritabanı işlemleri ile LLM entegrasyonlarını gerçekleştirir. -- **`collector`**: Kullanıcı arayüzünden gelen belgeleri işleyen ve ayrıştıran NodeJS Express tabanlı bir sunucu. -- **`docker`**: Docker kurulum talimatları, derleme süreci ve kaynak koddan nasıl derleneceğine dair bilgiler içerir. -- **`embed`**: [Web gömme widget’ı](https://github.com/Mintplex-Labs/anythingllm-embed) oluşturma ve entegrasyonu için alt modül. +- **`frontend`**: ViteJS + React tabanlı bir ön yüz, LLM'in kullanabileceği tüm içeriği kolayca oluşturup yönetmenizi sağlar. +- **`server`**: NodeJS ve Express tabanlı bir sunucu, tüm etkileşimleri yönetir ve vektör veritabanı işlemleri ile LLM entegrasyonlarını gerçekleştirir. +- **`collector`**: Kullanıcı arayüzünden gelen belgeleri işleyen ve ayrıştıran NodeJS Express tabanlı bir sunucu. +- **`docker`**: Docker kurulum talimatları, derleme süreci ve kaynak koddan nasıl derleneceğine dair bilgiler içerir. +- **`embed`**: [Web gömme widget’ı](https://github.com/Mintplex-Labs/anythingllm-embed) oluşturma ve entegrasyonu için alt modül. - **`browser-extension`**: [Chrome tarayıcı eklentisi](https://github.com/Mintplex-Labs/anythingllm-extension) için alt modül. -## 🛳 Kendi Sunucunuzda Barındırma +## 🛳 Kendi Sunucunuzda Barındırma Mintplex Labs ve topluluk, AnythingLLM'i yerel olarak çalıştırmak için çeşitli dağıtım yöntemleri, betikler ve şablonlar sunmaktadır. Aşağıdaki tabloya göz atarak tercih ettiğiniz ortamda nasıl dağıtım yapabileceğinizi öğrenebilir veya otomatik dağıtım seçeneklerini keşfedebilirsiniz. | Docker | AWS | GCP | Digital Ocean | Render.com | @@ -163,86 +164,86 @@ Mintplex Labs ve topluluk, AnythingLLM'i yerel olarak çalıştırmak için çe | --- | --- | --- | | [![Deploy on Railway][railway-btn]][railway-deploy] | [![Deploy on RepoCloud][repocloud-btn]][repocloud-deploy] | [![Deploy on Elestio][elestio-btn]][elestio-deploy] | -[veya Docker kullanmadan üretim ortamında AnythingLLM kurun →](../BARE_METAL.md) +[veya Docker kullanmadan üretim ortamında AnythingLLM kurun →](../BARE_METAL.md) -## Geliştirme İçin Kurulum +## Geliştirme İçin Kurulum -- `yarn setup` → Uygulamanın her bileşeni için gerekli `.env` dosyalarını oluşturur (repo’nun kök dizininden çalıştırılmalıdır). - - Devam etmeden önce bu dosyaları doldurun. **Özellikle `server/.env.development` dosyasının doldurulduğundan emin olun**, aksi takdirde sistem düzgün çalışmaz. -- `yarn dev:server` → Sunucuyu yerel olarak başlatır (repo’nun kök dizininden çalıştırılmalıdır). -- `yarn dev:frontend` → Ön yüzü yerel olarak çalıştırır (repo’nun kök dizininden çalıştırılmalıdır). -- `yarn dev:collector` → Belge toplayıcıyı çalıştırır (repo’nun kök dizininden çalıştırılmalıdır). +- `yarn setup` → Uygulamanın her bileşeni için gerekli `.env` dosyalarını oluşturur (repo’nun kök dizininden çalıştırılmalıdır). + - Devam etmeden önce bu dosyaları doldurun. **Özellikle `server/.env.development` dosyasının doldurulduğundan emin olun**, aksi takdirde sistem düzgün çalışmaz. +- `yarn dev:server` → Sunucuyu yerel olarak başlatır (repo’nun kök dizininden çalıştırılmalıdır). +- `yarn dev:frontend` → Ön yüzü yerel olarak çalıştırır (repo’nun kök dizininden çalıştırılmalıdır). +- `yarn dev:collector` → Belge toplayıcıyı çalıştırır (repo’nun kök dizininden çalıştırılmalıdır). -[Belgeler hakkında bilgi edinin](../server/storage/documents/DOCUMENTS.md) +[Belgeler hakkında bilgi edinin](../server/storage/documents/DOCUMENTS.md) -[Vektör önbellekleme hakkında bilgi edinin](../server/storage/vector-cache/VECTOR_CACHE.md) +[Vektör önbellekleme hakkında bilgi edinin](../server/storage/vector-cache/VECTOR_CACHE.md) -## Harici Uygulamalar ve Entegrasyonlar +## Harici Uygulamalar ve Entegrasyonlar -_Bu uygulamalar Mintplex Labs tarafından yönetilmemektedir, ancak AnythingLLM ile uyumludur. Burada listelenmeleri bir onay anlamına gelmez._ +_Bu uygulamalar Mintplex Labs tarafından yönetilmemektedir, ancak AnythingLLM ile uyumludur. Burada listelenmeleri bir onay anlamına gelmez._ -- [Midori AI Alt Sistem Yöneticisi](https://io.midori-ai.xyz/subsystem/anythingllm/) - Docker konteyner teknolojisini kullanarak yapay zeka sistemlerini verimli bir şekilde dağıtmanın pratik bir yolu. -- [Coolify](https://coolify.io/docs/services/anythingllm/) - Tek tıklamayla AnythingLLM dağıtımı yapmanıza olanak tanır. +- [Midori AI Alt Sistem Yöneticisi](https://io.midori-ai.xyz/subsystem/anythingllm/) - Docker konteyner teknolojisini kullanarak yapay zeka sistemlerini verimli bir şekilde dağıtmanın pratik bir yolu. +- [Coolify](https://coolify.io/docs/services/anythingllm/) - Tek tıklamayla AnythingLLM dağıtımı yapmanıza olanak tanır. - [GPTLocalhost for Microsoft Word](https://gptlocalhost.com/demo/) - AnythingLLM’i Microsoft Word içinde kullanmanıza olanak tanıyan yerel bir Word eklentisi. -## Telemetri ve Gizlilik +## Telemetri ve Gizlilik -Mintplex Labs Inc. tarafından geliştirilen AnythingLLM, anonim kullanım bilgilerini toplayan bir telemetri özelliği içermektedir. +Mintplex Labs Inc. tarafından geliştirilen AnythingLLM, anonim kullanım bilgilerini toplayan bir telemetri özelliği içermektedir. -
-AnythingLLM için Telemetri ve Gizlilik hakkında daha fazla bilgi +
+AnythingLLM için Telemetri ve Gizlilik hakkında daha fazla bilgi -### Neden? +### Neden? -Bu bilgileri, AnythingLLM’in nasıl kullanıldığını anlamak, yeni özellikler ve hata düzeltmelerine öncelik vermek ve uygulamanın performansını ve kararlılığını iyileştirmek için kullanıyoruz. +Bu bilgileri, AnythingLLM’in nasıl kullanıldığını anlamak, yeni özellikler ve hata düzeltmelerine öncelik vermek ve uygulamanın performansını ve kararlılığını iyileştirmek için kullanıyoruz. -### Telemetriden Çıkış Yapma (Opt-Out) +### Telemetriden Çıkış Yapma (Opt-Out) -Sunucu veya Docker `.env` ayarlarında `DISABLE_TELEMETRY` değerini "true" olarak ayarlayarak telemetriyi devre dışı bırakabilirsiniz. Ayrıca, uygulama içinde **Kenar Çubuğu > Gizlilik** bölümüne giderek de bu özelliği kapatabilirsiniz. +Sunucu veya Docker `.env` ayarlarında `DISABLE_TELEMETRY` değerini "true" olarak ayarlayarak telemetriyi devre dışı bırakabilirsiniz. Ayrıca, uygulama içinde **Kenar Çubuğu > Gizlilik** bölümüne giderek de bu özelliği kapatabilirsiniz. -### Hangi Verileri Açıkça Takip Ediyoruz? +### Hangi Verileri Açıkça Takip Ediyoruz? -Yalnızca ürün ve yol haritası kararlarını almamıza yardımcı olacak kullanım detaylarını takip ediyoruz: +Yalnızca ürün ve yol haritası kararlarını almamıza yardımcı olacak kullanım detaylarını takip ediyoruz: -- Kurulum türü (Docker veya Masaüstü) -- Bir belgenin eklenme veya kaldırılma olayı. **Belgenin içeriği hakkında hiçbir bilgi toplanmaz**, yalnızca olayın gerçekleştiği kaydedilir. Bu, kullanım sıklığını anlamamıza yardımcı olur. -- Kullanılan vektör veritabanı türü. Hangi sağlayıcının daha çok tercih edildiğini belirlemek için bu bilgiyi topluyoruz. -- Kullanılan LLM türü. En popüler modelleri belirleyerek bu sağlayıcılara öncelik verebilmemizi sağlar. -- Sohbet başlatılması. Bu en sık gerçekleşen "olay" olup, projenin günlük etkinliği hakkında genel bir fikir edinmemize yardımcı olur. **Yalnızca olay kaydedilir, sohbetin içeriği veya doğası hakkında hiçbir bilgi toplanmaz.** +- Kurulum türü (Docker veya Masaüstü) +- Bir belgenin eklenme veya kaldırılma olayı. **Belgenin içeriği hakkında hiçbir bilgi toplanmaz**, yalnızca olayın gerçekleştiği kaydedilir. Bu, kullanım sıklığını anlamamıza yardımcı olur. +- Kullanılan vektör veritabanı türü. Hangi sağlayıcının daha çok tercih edildiğini belirlemek için bu bilgiyi topluyoruz. +- Kullanılan LLM türü. En popüler modelleri belirleyerek bu sağlayıcılara öncelik verebilmemizi sağlar. +- Sohbet başlatılması. Bu en sık gerçekleşen "olay" olup, projenin günlük etkinliği hakkında genel bir fikir edinmemize yardımcı olur. **Yalnızca olay kaydedilir, sohbetin içeriği veya doğası hakkında hiçbir bilgi toplanmaz.** -Bu verileri doğrulamak için kod içinde **`Telemetry.sendTelemetry` çağrılarını** inceleyebilirsiniz. Ayrıca, bu olaylar günlük kaydına yazıldığı için hangi verilerin gönderildiğini görebilirsiniz (eğer etkinleştirilmişse). **IP adresi veya diğer tanımlayıcı bilgiler toplanmaz.** Telemetri sağlayıcısı, açık kaynaklı bir telemetri toplama hizmeti olan [PostHog](https://posthog.com/)‘dur. +Bu verileri doğrulamak için kod içinde **`Telemetry.sendTelemetry` çağrılarını** inceleyebilirsiniz. Ayrıca, bu olaylar günlük kaydına yazıldığı için hangi verilerin gönderildiğini görebilirsiniz (eğer etkinleştirilmişse). **IP adresi veya diğer tanımlayıcı bilgiler toplanmaz.** Telemetri sağlayıcısı, açık kaynaklı bir telemetri toplama hizmeti olan [PostHog](https://posthog.com/)‘dur. [Kaynak kodda tüm telemetri olaylarını görüntüle](https://github.com/search?q=repo%3AMintplex-Labs%2Fanything-llm%20.sendTelemetry\(&type=code)
-## 👋 Katkıda Bulunma +## 👋 Katkıda Bulunma -- Bir **issue** oluşturun. -- `-` formatında bir **PR (Pull Request)** oluşturun. -- Çekirdek ekipten **LGTM (Looks Good To Me)** onayı alın. +- Bir **issue** oluşturun. +- `-` formatında bir **PR (Pull Request)** oluşturun. +- Çekirdek ekipten **LGTM (Looks Good To Me)** onayı alın. -## 🌟 Katkıda Bulunanlar +## 🌟 Katkıda Bulunanlar -[![anythingllm contributors](https://contrib.rocks/image?repo=mintplex-labs/anything-llm)](https://github.com/mintplex-labs/anything-llm/graphs/contributors) +[![anythingllm contributors](https://contrib.rocks/image?repo=mintplex-labs/anything-llm)](https://github.com/mintplex-labs/anything-llm/graphs/contributors) -[![Star History Chart](https://api.star-history.com/svg?repos=mintplex-labs/anything-llm&type=Timeline)](https://star-history.com/#mintplex-labs/anything-llm&Date) +[![Star History Chart](https://api.star-history.com/svg?repos=mintplex-labs/anything-llm&type=Timeline)](https://star-history.com/#mintplex-labs/anything-llm&Date) -## 🔗 Diğer Ürünler +## 🔗 Diğer Ürünler -- **[VectorAdmin][vector-admin]:** Vektör veritabanlarını yönetmek için hepsi bir arada GUI ve araç paketi. -- **[OpenAI Assistant Swarm][assistant-swarm]:** Tüm OpenAI asistanlarınızı tek bir ajan tarafından yönetilen bir yapay zeka ordusuna dönüştürün. +- **[VectorAdmin][vector-admin]:** Vektör veritabanlarını yönetmek için hepsi bir arada GUI ve araç paketi. +- **[OpenAI Assistant Swarm][assistant-swarm]:** Tüm OpenAI asistanlarınızı tek bir ajan tarafından yönetilen bir yapay zeka ordusuna dönüştürün. -
+
-[![][back-to-top]](#readme-top) +[![][back-to-top]](#readme-top) -
+
---- +--- -Telif Hakkı © 2025 [Mintplex Labs][profile-link].
+Telif Hakkı © 2025 [Mintplex Labs][profile-link].
Bu proje [MIT](../LICENSE) lisansı ile lisanslanmıştır. diff --git a/locales/README.zh-CN.md b/locales/README.zh-CN.md index aa328351449..c5408dc6949 100644 --- a/locales/README.zh-CN.md +++ b/locales/README.zh-CN.md @@ -98,6 +98,7 @@ AnythingLLM将您的文档划分为称为`workspaces` (工作区)的对象。工 - [Text Generation Web UI](https://github.com/oobabooga/text-generation-webui) - [Apipie](https://apipie.ai/) - [xAI](https://x.ai/) +- [Z.AI (聊天模型)](https://z.ai/model-api) - [Novita AI (聊天模型)](https://novita.ai/model-api/product/llm-api?utm_source=github_anything-llm&utm_medium=github_readme&utm_campaign=link) - [PPIO (聊天模型)](https://ppinfra.com?utm_source=github_anything-llm) - [CometAPI (聊天模型)](https://api.cometapi.com/) diff --git a/server/.env.example b/server/.env.example index 3dc0bd596c4..1ca0f243b1d 100644 --- a/server/.env.example +++ b/server/.env.example @@ -131,6 +131,10 @@ SIG_SALT='salt' # Please generate random string at least 32 chars long. # XAI_LLM_API_KEY='xai-your-api-key-here' # XAI_LLM_MODEL_PREF='grok-beta' +# LLM_PROVIDER='zai' +# ZAI_API_KEY="your-zai-api-key-here" +# ZAI_MODEL_PREF="glm-4.5" + # LLM_PROVIDER='nvidia-nim' # NVIDIA_NIM_LLM_BASE_PATH='http://127.0.0.1:8000' # NVIDIA_NIM_LLM_MODEL_PREF='meta/llama-3.2-3b-instruct' diff --git a/server/endpoints/utils.js b/server/endpoints/utils.js index 0bb51b83052..136245dc946 100644 --- a/server/endpoints/utils.js +++ b/server/endpoints/utils.js @@ -145,6 +145,9 @@ function getModelTag() { case "moonshotai": model = process.env.MOONSHOT_AI_MODEL_PREF; break; + case "zai": + model = process.env.ZAI_MODEL_PREF; + break; default: model = "--"; break; diff --git a/server/models/systemSettings.js b/server/models/systemSettings.js index 3a7a4b21554..e2013af7345 100644 --- a/server/models/systemSettings.js +++ b/server/models/systemSettings.js @@ -621,6 +621,10 @@ const SystemSettings = { CometApiLLMApiKey: !!process.env.COMETAPI_LLM_API_KEY, CometApiLLMModelPref: process.env.COMETAPI_LLM_MODEL_PREF, CometApiLLMTimeout: process.env.COMETAPI_LLM_TIMEOUT_MS, + + // Z.AI Keys + ZAiApiKey: !!process.env.ZAI_API_KEY, + ZAiModelPref: process.env.ZAI_MODEL_PREF, }; }, diff --git a/server/utils/AiProviders/modelMap/index.js b/server/utils/AiProviders/modelMap/index.js index 8ff713eeb62..bfd720d462b 100644 --- a/server/utils/AiProviders/modelMap/index.js +++ b/server/utils/AiProviders/modelMap/index.js @@ -19,6 +19,7 @@ class ContextWindowFinder { xai: "xai", deepseek: "deepseek", moonshot: "moonshot", + zai: "vercel_ai_gateway", // Vercel has correct context windows for Z.AI models }; static expiryMs = 1000 * 60 * 60 * 24 * 3; // 3 days static remoteUrl = diff --git a/server/utils/AiProviders/zai/index.js b/server/utils/AiProviders/zai/index.js new file mode 100644 index 00000000000..9311affe06b --- /dev/null +++ b/server/utils/AiProviders/zai/index.js @@ -0,0 +1,189 @@ +const { NativeEmbedder } = require("../../EmbeddingEngines/native"); +const { + LLMPerformanceMonitor, +} = require("../../helpers/chat/LLMPerformanceMonitor"); +const { + handleDefaultStreamResponseV2, +} = require("../../helpers/chat/responses"); +const { MODEL_MAP } = require("../modelMap"); + +class ZAiLLM { + constructor(embedder = null, modelPreference = null) { + if (!process.env.ZAI_API_KEY) throw new Error("No Z.AI API key was set."); + this.className = "ZAiLLM"; + const { OpenAI: OpenAIApi } = require("openai"); + + this.openai = new OpenAIApi({ + baseURL: "https://api.z.ai/api/paas/v4", + apiKey: process.env.ZAI_API_KEY, + }); + this.model = modelPreference || process.env.ZAI_MODEL_PREF || "glm-4.5"; + this.limits = { + history: this.promptWindowLimit() * 0.15, + system: this.promptWindowLimit() * 0.15, + user: this.promptWindowLimit() * 0.7, + }; + + this.embedder = embedder ?? new NativeEmbedder(); + this.defaultTemp = 0.7; + this.log( + `Initialized ${this.model} with context window ${this.promptWindowLimit()}` + ); + } + + log(text, ...args) { + console.log(`\x1b[36m[${this.className}]\x1b[0m ${text}`, ...args); + } + + #appendContext(contextTexts = []) { + if (!contextTexts || !contextTexts.length) return ""; + return ( + "\nContext:\n" + + contextTexts + .map((text, i) => { + return `[CONTEXT ${i}]:\n${text}\n[END CONTEXT ${i}]\n\n`; + }) + .join("") + ); + } + + streamingEnabled() { + return "streamGetChatCompletion" in this; + } + + static promptWindowLimit(modelName) { + return MODEL_MAP.get("zai", modelName) ?? 131072; + } + + promptWindowLimit() { + return MODEL_MAP.get("zai", this.model) ?? 131072; + } + + async isValidChatCompletionModel(modelName = "") { + return !!modelName; // name just needs to exist + } + + /** + * Generates appropriate content array for a message + attachments. + * @param {{userPrompt:string, attachments: import("../../helpers").Attachment[]}} + * @returns {string|object[]} + */ + #generateContent({ userPrompt, attachments = [] }) { + if (!attachments.length) return userPrompt; + + const content = [{ type: "text", text: userPrompt }]; + for (let attachment of attachments) { + content.push({ + type: "image_url", + image_url: { + url: attachment.contentString, + }, + }); + } + return content.flat(); + } + + /** + * Construct the user prompt for this model. + * @param {{attachments: import("../../helpers").Attachment[]}} param0 + * @returns + */ + constructPrompt({ + systemPrompt = "", + contextTexts = [], + chatHistory = [], + userPrompt = "", + attachments = [], + }) { + const prompt = { + role: "system", + content: `${systemPrompt}${this.#appendContext(contextTexts)}`, + }; + return [ + prompt, + ...chatHistory, + { + role: "user", + content: this.#generateContent({ userPrompt, attachments }), + }, + ]; + } + + async getChatCompletion(messages = null, { temperature = 0.7 }) { + if (!(await this.isValidChatCompletionModel(this.model))) + throw new Error( + `Z.AI:chatCompletion: ${this.model} is not valid for chat completion!` + ); + + const result = await LLMPerformanceMonitor.measureAsyncFunction( + this.openai.chat.completions + .create({ + model: this.model, + messages, + temperature, + }) + .catch((e) => { + throw new Error(e.message); + }) + ); + + if ( + !result.output.hasOwnProperty("choices") || + result.output.choices.length === 0 + ) + return null; + + return { + textResponse: result.output.choices[0].message.content, + metrics: { + prompt_tokens: result.output.usage?.prompt_tokens || 0, + completion_tokens: result.output.usage?.completion_tokens || 0, + total_tokens: result.output.usage?.total_tokens || 0, + outputTps: result.output.usage?.completion_tokens / result.duration, + duration: result.duration, + }, + }; + } + + async streamGetChatCompletion(messages = null, { temperature = 0.7 }) { + if (!(await this.isValidChatCompletionModel(this.model))) + throw new Error( + `Z.AI:streamChatCompletion: ${this.model} is not valid for chat completion!` + ); + + const measuredStreamRequest = await LLMPerformanceMonitor.measureStream( + this.openai.chat.completions.create({ + model: this.model, + stream: true, + messages, + temperature, + }), + messages, + false + ); + + return measuredStreamRequest; + } + + handleStream(response, stream, responseProps) { + return handleDefaultStreamResponseV2(response, stream, responseProps); + } + + // Simple wrapper for dynamic embedder & normalize interface for all LLM implementations + async embedTextInput(textInput) { + return await this.embedder.embedTextInput(textInput); + } + async embedChunks(textChunks = []) { + return await this.embedder.embedChunks(textChunks); + } + + async compressMessages(promptArgs = {}, rawHistory = []) { + const { messageArrayCompressor } = require("../../helpers/chat"); + const messageArray = this.constructPrompt(promptArgs); + return await messageArrayCompressor(this, messageArray, rawHistory); + } +} + +module.exports = { + ZAiLLM, +}; diff --git a/server/utils/agents/aibitat/index.js b/server/utils/agents/aibitat/index.js index 65b5a146dda..fd7c7f06180 100644 --- a/server/utils/agents/aibitat/index.js +++ b/server/utils/agents/aibitat/index.js @@ -962,6 +962,8 @@ ${this.getHistory({ to: route.to }) return new Providers.ApiPieProvider({ model: config.model }); case "xai": return new Providers.XAIProvider({ model: config.model }); + case "zai": + return new Providers.ZAIProvider({ model: config.model }); case "novita": return new Providers.NovitaProvider({ model: config.model }); case "ppio": diff --git a/server/utils/agents/aibitat/providers/ai-provider.js b/server/utils/agents/aibitat/providers/ai-provider.js index 5c35ee2e03e..7c061132396 100644 --- a/server/utils/agents/aibitat/providers/ai-provider.js +++ b/server/utils/agents/aibitat/providers/ai-provider.js @@ -165,6 +165,14 @@ class Provider { apiKey: process.env.XAI_LLM_API_KEY ?? null, ...config, }); + case "zai": + return new ChatOpenAI({ + configuration: { + baseURL: "https://api.z.ai/api/paas/v4", + }, + apiKey: process.env.ZAI_API_KEY ?? null, + ...config, + }); case "novita": return new ChatOpenAI({ configuration: { diff --git a/server/utils/agents/aibitat/providers/index.js b/server/utils/agents/aibitat/providers/index.js index 8cf2e7422b3..f927c82c09d 100644 --- a/server/utils/agents/aibitat/providers/index.js +++ b/server/utils/agents/aibitat/providers/index.js @@ -18,6 +18,7 @@ const DeepSeekProvider = require("./deepseek.js"); const LiteLLMProvider = require("./litellm.js"); const ApiPieProvider = require("./apipie.js"); const XAIProvider = require("./xai.js"); +const ZAIProvider = require("./zai.js"); const NovitaProvider = require("./novita.js"); const NvidiaNimProvider = require("./nvidiaNim.js"); const PPIOProvider = require("./ppio.js"); @@ -48,6 +49,7 @@ module.exports = { LiteLLMProvider, ApiPieProvider, XAIProvider, + ZAIProvider, NovitaProvider, CometApiProvider, NvidiaNimProvider, diff --git a/server/utils/agents/aibitat/providers/zai.js b/server/utils/agents/aibitat/providers/zai.js new file mode 100644 index 00000000000..98630e2782f --- /dev/null +++ b/server/utils/agents/aibitat/providers/zai.js @@ -0,0 +1,88 @@ +const OpenAI = require("openai"); +const Provider = require("./ai-provider.js"); +const InheritMultiple = require("./helpers/classes.js"); +const UnTooled = require("./helpers/untooled.js"); + +class ZAIProvider extends InheritMultiple([Provider, UnTooled]) { + model; + + constructor(config = {}) { + const { model = "glm-4.5" } = config; + super(); + const client = new OpenAI({ + baseURL: "https://api.z.ai/api/paas/v4", + apiKey: process.env.ZAI_API_KEY, + maxRetries: 3, + }); + + this._client = client; + this.model = model; + this.verbose = true; + } + + /** + * Create a completion based on the received messages. + * + * @param messages A list of messages to send to the API. + * @param functions + * @returns The completion. + */ + get client() { + return this._client; + } + + get supportsAgentStreaming() { + return true; + } + + async #handleFunctionCallChat({ messages = [] }) { + return await this.client.chat.completions + .create({ + model: this.model, + messages, + }) + .then((result) => { + if (!result.hasOwnProperty("choices")) + throw new Error("Z.AI chat: No results!"); + if (result.choices.length === 0) + throw new Error("Z.AI chat: No results length!"); + return result.choices[0].message.content; + }) + .catch((_) => { + return null; + }); + } + + async #handleFunctionCallStream({ messages = [] }) { + return await this.client.chat.completions.create({ + model: this.model, + stream: true, + messages, + }); + } + + async stream(messages, functions = [], eventHandler = null) { + return await UnTooled.prototype.stream.call( + this, + messages, + functions, + this.#handleFunctionCallStream.bind(this), + eventHandler + ); + } + + async complete(messages, functions = []) { + return await UnTooled.prototype.complete.call( + this, + messages, + functions, + this.#handleFunctionCallChat.bind(this) + ); + } + + getCost(_usage) { + return 0; + } +} + +module.exports = ZAIProvider; diff --git a/server/utils/agents/index.js b/server/utils/agents/index.js index 4ed1ddea0a8..10972594979 100644 --- a/server/utils/agents/index.js +++ b/server/utils/agents/index.js @@ -172,6 +172,10 @@ class AgentHandler { if (!process.env.XAI_LLM_API_KEY) throw new Error("xAI API Key must be provided to use agents."); break; + case "zai": + if (!process.env.ZAI_API_KEY) + throw new Error("Z.AI API Key must be provided to use agents."); + break; case "novita": if (!process.env.NOVITA_LLM_API_KEY) throw new Error("Novita API Key must be provided to use agents."); @@ -275,6 +279,8 @@ class AgentHandler { return process.env.APIPIE_LLM_MODEL_PREF ?? null; case "xai": return process.env.XAI_LLM_MODEL_PREF ?? "grok-beta"; + case "zai": + return process.env.ZAI_MODEL_PREF ?? "glm-4.5"; case "novita": return process.env.NOVITA_LLM_MODEL_PREF ?? "deepseek/deepseek-r1"; case "nvidia-nim": diff --git a/server/utils/helpers/customModels.js b/server/utils/helpers/customModels.js index 7a62a67d543..5c8d1962c14 100644 --- a/server/utils/helpers/customModels.js +++ b/server/utils/helpers/customModels.js @@ -38,6 +38,7 @@ const SUPPORT_CUSTOM_MODELS = [ "moonshotai", "foundry", "cohere", + "zai", // Embedding Engines "native-embedder", "cohere-embedder", @@ -100,6 +101,8 @@ async function getCustomModels(provider = "", apiKey = null, basePath = null) { return await getFoundryModels(basePath); case "cohere": return await getCohereModels(apiKey, "chat"); + case "zai": + return await getZAiModels(apiKey); case "native-embedder": return await getNativeEmbedderModels(); case "cohere-embedder": @@ -798,6 +801,29 @@ async function getCohereModels(_apiKey = null, type = "chat") { return { models, error: null }; } +async function getZAiModels(_apiKey = null) { + const { OpenAI: OpenAIApi } = require("openai"); + const apiKey = + _apiKey === true + ? process.env.ZAI_API_KEY + : _apiKey || process.env.ZAI_API_KEY || null; + const openai = new OpenAIApi({ + baseURL: "https://api.z.ai/api/paas/v4", + apiKey, + }); + const models = await openai.models + .list() + .then((results) => results.data) + .catch((e) => { + console.error(`Z.AI:listModels`, e.message); + return []; + }); + + // Api Key was successful so lets save it for future uses + if (models.length > 0 && !!apiKey) process.env.ZAI_API_KEY = apiKey; + return { models, error: null }; +} + module.exports = { getCustomModels, SUPPORT_CUSTOM_MODELS, diff --git a/server/utils/helpers/index.js b/server/utils/helpers/index.js index 819a464c6d0..04cd8a07119 100644 --- a/server/utils/helpers/index.js +++ b/server/utils/helpers/index.js @@ -218,6 +218,9 @@ function getLLMProvider({ provider = null, model = null } = {}) { case "foundry": const { FoundryLLM } = require("../AiProviders/foundry"); return new FoundryLLM(embedder, model); + case "zai": + const { ZAiLLM } = require("../AiProviders/zai"); + return new ZAiLLM(embedder, model); default: throw new Error( `ENV: No valid LLM_PROVIDER value found in environment! Using ${process.env.LLM_PROVIDER}` @@ -374,6 +377,9 @@ function getLLMProviderClass({ provider = null } = {}) { case "foundry": const { FoundryLLM } = require("../AiProviders/foundry"); return FoundryLLM; + case "zai": + const { ZAiLLM } = require("../AiProviders/zai"); + return ZAiLLM; default: return null; } @@ -446,6 +452,8 @@ function getBaseLLMProviderModel({ provider = null } = {}) { return process.env.COMETAPI_LLM_MODEL_PREF; case "foundry": return process.env.FOUNDRY_MODEL_PREF; + case "zai": + return process.env.ZAI_MODEL_PREF; default: return null; } diff --git a/server/utils/helpers/updateENV.js b/server/utils/helpers/updateENV.js index c8109efb193..34225501dea 100644 --- a/server/utils/helpers/updateENV.js +++ b/server/utils/helpers/updateENV.js @@ -740,6 +740,16 @@ const KEY_MAPPING = { envKey: "COMETAPI_LLM_TIMEOUT_MS", checks: [], }, + + // Z.AI Options + ZAiApiKey: { + envKey: "ZAI_API_KEY", + checks: [isNotEmpty], + }, + ZAiModelPref: { + envKey: "ZAI_MODEL_PREF", + checks: [isNotEmpty], + }, }; function isNotEmpty(input = "") { @@ -851,6 +861,7 @@ function supportedLLM(input = "") { "moonshotai", "cometapi", "foundry", + "zai", ].includes(input); return validSelection ? null : `${input} is not a valid LLM provider.`; }