From 80565d79e015f743a8f8a227e8060d89aec89fcc Mon Sep 17 00:00:00 2001
From: Timothy Carambat <rambat1010@gmail.com>
Date: Mon, 4 Nov 2024 11:34:29 -0800
Subject: [PATCH] 2488 novita ai llm integration (#2582)

* feat: add new model provider: Novita AI

* feat: finished novita AI

* fix: code lint

* remove unneeded logging

* add back log for novita stream not self closing

* Clarify ENV vars for LLM/embedder seperation for future
Patch ENV check for workspace/agent provider

---------

Co-authored-by: Jason <ggbbddjm@gmail.com>
Co-authored-by: shatfield4 <seanhatfield5@gmail.com>
---
 .vscode/settings.json                         |   1 +
 README.md                                     |   1 +
 docker/.env.example                           |   4 +
 .../LLMSelection/NovitaLLMOptions/index.jsx   | 142 +++++++
 frontend/src/hooks/useGetProvidersModels.js   |   8 +-
 frontend/src/media/llmprovider/novita.png     | Bin 0 -> 39296 bytes
 .../GeneralSettings/LLMPreference/index.jsx   |  11 +
 .../Steps/DataHandling/index.jsx              |   9 +
 .../Steps/LLMPreference/index.jsx             |  10 +
 .../AgentConfig/AgentLLMSelection/index.jsx   |   2 +
 locales/README.ja-JP.md                       |   1 +
 locales/README.zh-CN.md                       |   1 +
 server/.env.example                           |   4 +
 server/models/systemSettings.js               |   5 +
 server/storage/models/.gitignore              |   3 +-
 server/utils/AiProviders/novita/index.js      | 376 ++++++++++++++++++
 server/utils/agents/aibitat/index.js          |   2 +
 .../agents/aibitat/providers/ai-provider.js   |   8 +
 .../utils/agents/aibitat/providers/index.js   |   2 +
 .../utils/agents/aibitat/providers/novita.js  | 115 ++++++
 server/utils/agents/index.js                  |   6 +
 server/utils/helpers/customModels.js          |  18 +
 server/utils/helpers/index.js                 |   6 +
 server/utils/helpers/updateENV.js             |  15 +
 24 files changed, 748 insertions(+), 2 deletions(-)
 create mode 100644 frontend/src/components/LLMSelection/NovitaLLMOptions/index.jsx
 create mode 100644 frontend/src/media/llmprovider/novita.png
 create mode 100644 server/utils/AiProviders/novita/index.js
 create mode 100644 server/utils/agents/aibitat/providers/novita.js

diff --git a/.vscode/settings.json b/.vscode/settings.json
index 14efd3fae..307bbe6c7 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -33,6 +33,7 @@
     "Mintplex",
     "mixtral",
     "moderations",
+    "novita",
     "numpages",
     "Ollama",
     "Oobabooga",
diff --git a/README.md b/README.md
index 4edf49482..861e4fa59 100644
--- a/README.md
+++ b/README.md
@@ -96,6 +96,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/)
+- [Novita AI (chat models)](https://novita.ai/model-api/product/llm-api?utm_source=github_anything-llm&utm_medium=github_readme&utm_campaign=link)
 
 **Embedder models:**
 
diff --git a/docker/.env.example b/docker/.env.example
index 2f6f896b0..058046596 100644
--- a/docker/.env.example
+++ b/docker/.env.example
@@ -90,6 +90,10 @@ GID='1000'
 # LITE_LLM_BASE_PATH='http://127.0.0.1:4000'
 # LITE_LLM_API_KEY='sk-123abc'
 
+# LLM_PROVIDER='novita'
+# NOVITA_LLM_API_KEY='your-novita-api-key-here' check on https://novita.ai/settings#key-management
+# NOVITA_LLM_MODEL_PREF='gryphe/mythomax-l2-13b'
+
 # LLM_PROVIDER='cohere'
 # COHERE_API_KEY=
 # COHERE_MODEL_PREF='command-r'
diff --git a/frontend/src/components/LLMSelection/NovitaLLMOptions/index.jsx b/frontend/src/components/LLMSelection/NovitaLLMOptions/index.jsx
new file mode 100644
index 000000000..26e1fe04b
--- /dev/null
+++ b/frontend/src/components/LLMSelection/NovitaLLMOptions/index.jsx
@@ -0,0 +1,142 @@
+import System from "@/models/system";
+import { CaretDown, CaretUp } from "@phosphor-icons/react";
+import { useState, useEffect } from "react";
+
+export default function NovitaLLMOptions({ settings }) {
+  return (
+    <div className="flex flex-col gap-y-4 mt-1.5">
+      <div className="flex gap-[36px]">
+        <div className="flex flex-col w-60">
+          <label className="text-white text-sm font-semibold block mb-3">
+            Novita API Key
+          </label>
+          <input
+            type="password"
+            name="NovitaLLMApiKey"
+            className="bg-zinc-900 text-white placeholder:text-white/20 text-sm rounded-lg focus:outline-primary-button active:outline-primary-button outline-none block w-full p-2.5"
+            placeholder="Novita API Key"
+            defaultValue={settings?.NovitaLLMApiKey ? "*".repeat(20) : ""}
+            required={true}
+            autoComplete="off"
+            spellCheck={false}
+          />
+        </div>
+        {!settings?.credentialsOnly && (
+          <NovitaModelSelection settings={settings} />
+        )}
+      </div>
+      <AdvancedControls settings={settings} />
+    </div>
+  );
+}
+
+function AdvancedControls({ settings }) {
+  const [showAdvancedControls, setShowAdvancedControls] = useState(false);
+
+  return (
+    <div className="flex flex-col gap-y-4">
+      <button
+        type="button"
+        onClick={() => setShowAdvancedControls(!showAdvancedControls)}
+        className="text-white hover:text-white/70 flex items-center text-sm"
+      >
+        {showAdvancedControls ? "Hide" : "Show"} advanced controls
+        {showAdvancedControls ? (
+          <CaretUp size={14} className="ml-1" />
+        ) : (
+          <CaretDown size={14} className="ml-1" />
+        )}
+      </button>
+      <div hidden={!showAdvancedControls}>
+        <div className="flex flex-col w-60">
+          <label className="text-white text-sm font-semibold block mb-3">
+            Stream Timeout (ms)
+          </label>
+          <input
+            type="number"
+            name="NovitaLLMTimeout"
+            className="bg-zinc-900 text-white placeholder:text-white/20 text-sm rounded-lg focus:outline-primary-button active:outline-primary-button outline-none block w-full p-2.5"
+            placeholder="Timeout value between token responses to auto-timeout the stream"
+            defaultValue={settings?.NovitaLLMTimeout ?? 500}
+            autoComplete="off"
+            onScroll={(e) => e.target.blur()}
+            min={500}
+            step={1}
+          />
+        </div>
+      </div>
+    </div>
+  );
+}
+
+function NovitaModelSelection({ settings }) {
+  const [groupedModels, setGroupedModels] = useState({});
+  const [loading, setLoading] = useState(true);
+
+  useEffect(() => {
+    async function findCustomModels() {
+      setLoading(true);
+      const { models } = await System.customModels("novita");
+      if (models?.length > 0) {
+        const modelsByOrganization = models.reduce((acc, model) => {
+          acc[model.organization] = acc[model.organization] || [];
+          acc[model.organization].push(model);
+          return acc;
+        }, {});
+
+        setGroupedModels(modelsByOrganization);
+      }
+
+      setLoading(false);
+    }
+    findCustomModels();
+  }, []);
+
+  if (loading || Object.keys(groupedModels).length === 0) {
+    return (
+      <div className="flex flex-col w-60">
+        <label className="text-white text-sm font-semibold block mb-3">
+          Chat Model Selection
+        </label>
+        <select
+          name="NovitaLLMModelPref"
+          disabled={true}
+          className="bg-zinc-900 border-gray-500 text-white text-sm rounded-lg block w-full p-2.5"
+        >
+          <option disabled={true} selected={true}>
+            -- loading available models --
+          </option>
+        </select>
+      </div>
+    );
+  }
+
+  return (
+    <div className="flex flex-col w-60">
+      <label className="text-white text-sm font-semibold block mb-3">
+        Chat Model Selection
+      </label>
+      <select
+        name="NovitaLLMModelPref"
+        required={true}
+        className="bg-zinc-900 border-gray-500 text-white text-sm rounded-lg block w-full p-2.5"
+      >
+        {Object.keys(groupedModels)
+          .sort()
+          .map((organization) => (
+            <optgroup key={organization} label={organization}>
+              {groupedModels[organization].map((model) => (
+                <option
+                  key={model.id}
+                  value={model.id}
+                  selected={settings?.NovitaLLMModelPref === model.id}
+                >
+                  {model.name}
+                </option>
+              ))}
+            </optgroup>
+          ))}
+      </select>
+    </div>
+  );
+}
diff --git a/frontend/src/hooks/useGetProvidersModels.js b/frontend/src/hooks/useGetProvidersModels.js
index a493438c7..824587245 100644
--- a/frontend/src/hooks/useGetProvidersModels.js
+++ b/frontend/src/hooks/useGetProvidersModels.js
@@ -63,7 +63,13 @@ function groupModels(models) {
   }, {});
 }
 
-const groupedProviders = ["togetherai", "fireworksai", "openai", "openrouter"];
+const groupedProviders = [
+  "togetherai",
+  "fireworksai",
+  "openai",
+  "novita",
+  "openrouter",
+];
 export default function useGetProviderModels(provider = null) {
   const [defaultModels, setDefaultModels] = useState([]);
   const [customModels, setCustomModels] = useState([]);
diff --git a/frontend/src/media/llmprovider/novita.png b/frontend/src/media/llmprovider/novita.png
new file mode 100644
index 0000000000000000000000000000000000000000..85f18acb240516dde86aef9c99ceb55cd29523c1
GIT binary patch
literal 39296
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

literal 0
HcmV?d00001

diff --git a/frontend/src/pages/GeneralSettings/LLMPreference/index.jsx b/frontend/src/pages/GeneralSettings/LLMPreference/index.jsx
index e7b06e172..9ca39d52b 100644
--- a/frontend/src/pages/GeneralSettings/LLMPreference/index.jsx
+++ b/frontend/src/pages/GeneralSettings/LLMPreference/index.jsx
@@ -11,6 +11,7 @@ import AzureOpenAiLogo from "@/media/llmprovider/azure.png";
 import AnthropicLogo from "@/media/llmprovider/anthropic.png";
 import GeminiLogo from "@/media/llmprovider/gemini.png";
 import OllamaLogo from "@/media/llmprovider/ollama.png";
+import NovitaLogo from "@/media/llmprovider/novita.png";
 import LMStudioLogo from "@/media/llmprovider/lmstudio.png";
 import LocalAiLogo from "@/media/llmprovider/localai.png";
 import TogetherAILogo from "@/media/llmprovider/togetherai.png";
@@ -39,6 +40,7 @@ import LocalAiOptions from "@/components/LLMSelection/LocalAiOptions";
 import NativeLLMOptions from "@/components/LLMSelection/NativeLLMOptions";
 import GeminiLLMOptions from "@/components/LLMSelection/GeminiLLMOptions";
 import OllamaLLMOptions from "@/components/LLMSelection/OllamaLLMOptions";
+import NovitaLLMOptions from "@/components/LLMSelection/NovitaLLMOptions";
 import TogetherAiOptions from "@/components/LLMSelection/TogetherAiOptions";
 import FireworksAiOptions from "@/components/LLMSelection/FireworksAiOptions";
 import MistralOptions from "@/components/LLMSelection/MistralOptions";
@@ -113,6 +115,15 @@ export const AVAILABLE_LLM_PROVIDERS = [
     description: "Run LLMs locally on your own machine.",
     requiredConfig: ["OllamaLLMBasePath"],
   },
+  {
+    name: "Novita AI",
+    value: "novita",
+    logo: NovitaLogo,
+    options: (settings) => <NovitaLLMOptions settings={settings} />,
+    description:
+      "Reliable, Scalable, and Cost-Effective for LLMs from Novita AI",
+    requiredConfig: ["NovitaLLMApiKey"],
+  },
   {
     name: "LM Studio",
     value: "lmstudio",
diff --git a/frontend/src/pages/OnboardingFlow/Steps/DataHandling/index.jsx b/frontend/src/pages/OnboardingFlow/Steps/DataHandling/index.jsx
index 33750cba2..d200f60b1 100644
--- a/frontend/src/pages/OnboardingFlow/Steps/DataHandling/index.jsx
+++ b/frontend/src/pages/OnboardingFlow/Steps/DataHandling/index.jsx
@@ -15,6 +15,7 @@ import MistralLogo from "@/media/llmprovider/mistral.jpeg";
 import HuggingFaceLogo from "@/media/llmprovider/huggingface.png";
 import PerplexityLogo from "@/media/llmprovider/perplexity.png";
 import OpenRouterLogo from "@/media/llmprovider/openrouter.jpeg";
+import NovitaLogo from "@/media/llmprovider/novita.png";
 import GroqLogo from "@/media/llmprovider/groq.png";
 import KoboldCPPLogo from "@/media/llmprovider/koboldcpp.png";
 import TextGenWebUILogo from "@/media/llmprovider/text-generation-webui.png";
@@ -149,6 +150,14 @@ export const LLM_SELECTION_PRIVACY = {
     ],
     logo: OpenRouterLogo,
   },
+  novita: {
+    name: "Novita AI",
+    description: [
+      "Your chats will not be used for training",
+      "Your prompts and document text used in response creation are visible to Novita AI",
+    ],
+    logo: NovitaLogo,
+  },
   groq: {
     name: "Groq",
     description: [
diff --git a/frontend/src/pages/OnboardingFlow/Steps/LLMPreference/index.jsx b/frontend/src/pages/OnboardingFlow/Steps/LLMPreference/index.jsx
index cc17acfd3..5f58cba1a 100644
--- a/frontend/src/pages/OnboardingFlow/Steps/LLMPreference/index.jsx
+++ b/frontend/src/pages/OnboardingFlow/Steps/LLMPreference/index.jsx
@@ -22,6 +22,7 @@ import LiteLLMLogo from "@/media/llmprovider/litellm.png";
 import AWSBedrockLogo from "@/media/llmprovider/bedrock.png";
 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 CohereLogo from "@/media/llmprovider/cohere.png";
@@ -48,6 +49,7 @@ import LiteLLMOptions from "@/components/LLMSelection/LiteLLMOptions";
 import AWSBedrockLLMOptions from "@/components/LLMSelection/AwsBedrockLLMOptions";
 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 LLMItem from "@/components/LLMSelection/LLMItem";
@@ -104,6 +106,14 @@ const LLMS = [
     options: (settings) => <OllamaLLMOptions settings={settings} />,
     description: "Run LLMs locally on your own machine.",
   },
+  {
+    name: "Novita AI",
+    value: "novita",
+    logo: NovitaLogo,
+    options: (settings) => <NovitaLLMOptions settings={settings} />,
+    description:
+      "Reliable, Scalable, and Cost-Effective for LLMs from Novita AI",
+  },
   {
     name: "LM Studio",
     value: "lmstudio",
diff --git a/frontend/src/pages/WorkspaceSettings/AgentConfig/AgentLLMSelection/index.jsx b/frontend/src/pages/WorkspaceSettings/AgentConfig/AgentLLMSelection/index.jsx
index c59a77e71..1e21e50b3 100644
--- a/frontend/src/pages/WorkspaceSettings/AgentConfig/AgentLLMSelection/index.jsx
+++ b/frontend/src/pages/WorkspaceSettings/AgentConfig/AgentLLMSelection/index.jsx
@@ -17,6 +17,7 @@ const ENABLED_PROVIDERS = [
   "koboldcpp",
   "togetherai",
   "openrouter",
+  "novita",
   "mistral",
   "perplexity",
   "textgenwebui",
@@ -40,6 +41,7 @@ const WARN_PERFORMANCE = [
   "ollama",
   "localai",
   "openrouter",
+  "novita",
   "generic-openai",
   "textgenwebui",
 ];
diff --git a/locales/README.ja-JP.md b/locales/README.ja-JP.md
index e273576af..9ba566eb9 100644
--- a/locales/README.ja-JP.md
+++ b/locales/README.ja-JP.md
@@ -85,6 +85,7 @@ AnythingLLMのいくつかのクールな機能
 - [Fireworks AI (チャットモデル)](https://fireworks.ai/)
 - [Perplexity (チャットモデル)](https://www.perplexity.ai/)
 - [OpenRouter (チャットモデル)](https://openrouter.ai/)
+- [Novita AI (チャットモデル)](https://novita.ai/model-api/product/llm-api?utm_source=github_anything-llm&utm_medium=github_readme&utm_campaign=link)
 - [Mistral](https://mistral.ai/)
 - [Groq](https://groq.com/)
 - [Cohere](https://cohere.com/)
diff --git a/locales/README.zh-CN.md b/locales/README.zh-CN.md
index 03e9ece13..df14a8b62 100644
--- a/locales/README.zh-CN.md
+++ b/locales/README.zh-CN.md
@@ -81,6 +81,7 @@ AnythingLLM的一些酷炫特性
 - [Fireworks AI (聊天模型)](https://fireworks.ai/)
 - [Perplexity (聊天模型)](https://www.perplexity.ai/)
 - [OpenRouter (聊天模型)](https://openrouter.ai/)
+- [Novita AI (聊天模型)](https://novita.ai/model-api/product/llm-api?utm_source=github_anything-llm&utm_medium=github_readme&utm_campaign=link)
 - [Mistral](https://mistral.ai/)
 - [Groq](https://groq.com/)
 - [Cohere](https://cohere.com/)
diff --git a/server/.env.example b/server/.env.example
index 199589278..723b3a644 100644
--- a/server/.env.example
+++ b/server/.env.example
@@ -91,6 +91,10 @@ SIG_SALT='salt' # Please generate random string at least 32 chars long.
 # LITE_LLM_BASE_PATH='http://127.0.0.1:4000'
 # LITE_LLM_API_KEY='sk-123abc'
 
+# LLM_PROVIDER='novita'
+# NOVITA_LLM_API_KEY='your-novita-api-key-here' check on https://novita.ai/settings#key-management
+# NOVITA_LLM_MODEL_PREF='gryphe/mythomax-l2-13b'
+
 # LLM_PROVIDER='cohere'
 # COHERE_API_KEY=
 # COHERE_MODEL_PREF='command-r'
diff --git a/server/models/systemSettings.js b/server/models/systemSettings.js
index 41dfc9293..f43118c62 100644
--- a/server/models/systemSettings.js
+++ b/server/models/systemSettings.js
@@ -448,6 +448,11 @@ const SystemSettings = {
       OllamaLLMKeepAliveSeconds: process.env.OLLAMA_KEEP_ALIVE_TIMEOUT ?? 300,
       OllamaLLMPerformanceMode: process.env.OLLAMA_PERFORMANCE_MODE ?? "base",
 
+      // Novita LLM Keys
+      NovitaLLMApiKey: !!process.env.NOVITA_LLM_API_KEY,
+      NovitaLLMModelPref: process.env.NOVITA_LLM_MODEL_PREF,
+      NovitaLLMTimeout: process.env.NOVITA_LLM_TIMEOUT_MS,
+
       // TogetherAI Keys
       TogetherAiApiKey: !!process.env.TOGETHER_AI_API_KEY,
       TogetherAiModelPref: process.env.TOGETHER_AI_MODEL_PREF,
diff --git a/server/storage/models/.gitignore b/server/storage/models/.gitignore
index b78160e79..e669b51b2 100644
--- a/server/storage/models/.gitignore
+++ b/server/storage/models/.gitignore
@@ -2,4 +2,5 @@ Xenova
 downloaded/*
 !downloaded/.placeholder
 openrouter
-apipie
\ No newline at end of file
+apipie
+novita
\ No newline at end of file
diff --git a/server/utils/AiProviders/novita/index.js b/server/utils/AiProviders/novita/index.js
new file mode 100644
index 000000000..f15d20d41
--- /dev/null
+++ b/server/utils/AiProviders/novita/index.js
@@ -0,0 +1,376 @@
+const { NativeEmbedder } = require("../../EmbeddingEngines/native");
+const { v4: uuidv4 } = require("uuid");
+const {
+  writeResponseChunk,
+  clientAbortedHandler,
+} = require("../../helpers/chat/responses");
+const fs = require("fs");
+const path = require("path");
+const { safeJsonParse } = require("../../http");
+const cacheFolder = path.resolve(
+  process.env.STORAGE_DIR
+    ? path.resolve(process.env.STORAGE_DIR, "models", "novita")
+    : path.resolve(__dirname, `../../../storage/models/novita`)
+);
+
+class NovitaLLM {
+  constructor(embedder = null, modelPreference = null) {
+    if (!process.env.NOVITA_LLM_API_KEY)
+      throw new Error("No Novita API key was set.");
+
+    const { OpenAI: OpenAIApi } = require("openai");
+    this.basePath = "https://api.novita.ai/v3/openai";
+    this.openai = new OpenAIApi({
+      baseURL: this.basePath,
+      apiKey: process.env.NOVITA_LLM_API_KEY ?? null,
+      defaultHeaders: {
+        "HTTP-Referer": "https://anythingllm.com",
+        "X-Novita-Source": "anythingllm",
+      },
+    });
+    this.model =
+      modelPreference ||
+      process.env.NOVITA_LLM_MODEL_PREF ||
+      "gryphe/mythomax-l2-13b";
+    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.timeout = this.#parseTimeout();
+
+    if (!fs.existsSync(cacheFolder))
+      fs.mkdirSync(cacheFolder, { recursive: true });
+    this.cacheModelPath = path.resolve(cacheFolder, "models.json");
+    this.cacheAtPath = path.resolve(cacheFolder, ".cached_at");
+
+    this.log(`Loaded with model: ${this.model}`);
+  }
+
+  log(text, ...args) {
+    console.log(`\x1b[36m[${this.constructor.name}]\x1b[0m ${text}`, ...args);
+  }
+
+  /**
+   * Novita has various models that never return `finish_reasons` and thus leave the stream open
+   * which causes issues in subsequent messages. This timeout value forces us to close the stream after
+   * x milliseconds. This is a configurable value via the NOVITA_LLM_TIMEOUT_MS value
+   * @returns {number} The timeout value in milliseconds (default: 500)
+   */
+  #parseTimeout() {
+    if (isNaN(Number(process.env.NOVITA_LLM_TIMEOUT_MS))) return 500;
+    const setValue = Number(process.env.NOVITA_LLM_TIMEOUT_MS);
+    if (setValue < 500) return 500;
+    return setValue;
+  }
+
+  // This checks if the .cached_at file has a timestamp that is more than 1Week (in millis)
+  // from the current date. If it is, then we will refetch the API so that all the models are up
+  // to date.
+  #cacheIsStale() {
+    const MAX_STALE = 6.048e8; // 1 Week in MS
+    if (!fs.existsSync(this.cacheAtPath)) return true;
+    const now = Number(new Date());
+    const timestampMs = Number(fs.readFileSync(this.cacheAtPath));
+    return now - timestampMs > MAX_STALE;
+  }
+
+  // The Novita model API has a lot of models, so we cache this locally in the directory
+  // as if the cache directory JSON file is stale or does not exist we will fetch from API and store it.
+  // This might slow down the first request, but we need the proper token context window
+  // for each model and this is a constructor property - so we can really only get it if this cache exists.
+  // We used to have this as a chore, but given there is an API to get the info - this makes little sense.
+  async #syncModels() {
+    if (fs.existsSync(this.cacheModelPath) && !this.#cacheIsStale())
+      return false;
+
+    this.log("Model cache is not present or stale. Fetching from Novita API.");
+    await fetchNovitaModels();
+    return;
+  }
+
+  #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("")
+    );
+  }
+
+  models() {
+    if (!fs.existsSync(this.cacheModelPath)) return {};
+    return safeJsonParse(
+      fs.readFileSync(this.cacheModelPath, { encoding: "utf-8" }),
+      {}
+    );
+  }
+
+  streamingEnabled() {
+    return "streamGetChatCompletion" in this;
+  }
+
+  static promptWindowLimit(modelName) {
+    const cacheModelPath = path.resolve(cacheFolder, "models.json");
+    const availableModels = fs.existsSync(cacheModelPath)
+      ? safeJsonParse(
+          fs.readFileSync(cacheModelPath, { encoding: "utf-8" }),
+          {}
+        )
+      : {};
+    return availableModels[modelName]?.maxLength || 4096;
+  }
+
+  promptWindowLimit() {
+    const availableModels = this.models();
+    return availableModels[this.model]?.maxLength || 4096;
+  }
+
+  async isValidChatCompletionModel(model = "") {
+    await this.#syncModels();
+    const availableModels = this.models();
+    return availableModels.hasOwnProperty(model);
+  }
+
+  /**
+   * 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,
+          detail: "auto",
+        },
+      });
+    }
+    return content.flat();
+  }
+
+  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(
+        `Novita chat: ${this.model} is not valid for chat completion!`
+      );
+
+    const result = await this.openai.chat.completions
+      .create({
+        model: this.model,
+        messages,
+        temperature,
+      })
+      .catch((e) => {
+        throw new Error(e.message);
+      });
+
+    if (!result.hasOwnProperty("choices") || result.choices.length === 0)
+      return null;
+    return result.choices[0].message.content;
+  }
+
+  async streamGetChatCompletion(messages = null, { temperature = 0.7 }) {
+    if (!(await this.isValidChatCompletionModel(this.model)))
+      throw new Error(
+        `Novita chat: ${this.model} is not valid for chat completion!`
+      );
+
+    const streamRequest = await this.openai.chat.completions.create({
+      model: this.model,
+      stream: true,
+      messages,
+      temperature,
+    });
+    return streamRequest;
+  }
+
+  handleStream(response, stream, responseProps) {
+    const timeoutThresholdMs = this.timeout;
+    const { uuid = uuidv4(), sources = [] } = responseProps;
+
+    return new Promise(async (resolve) => {
+      let fullText = "";
+      let lastChunkTime = null; // null when first token is still not received.
+
+      // Establish listener to early-abort a streaming response
+      // in case things go sideways or the user does not like the response.
+      // We preserve the generated text but continue as if chat was completed
+      // to preserve previously generated content.
+      const handleAbort = () => clientAbortedHandler(resolve, fullText);
+      response.on("close", handleAbort);
+
+      // NOTICE: Not all Novita models will return a stop reason
+      // which keeps the connection open and so the model never finalizes the stream
+      // like the traditional OpenAI response schema does. So in the case the response stream
+      // never reaches a formal close state we maintain an interval timer that if we go >=timeoutThresholdMs with
+      // no new chunks then we kill the stream and assume it to be complete. Novita is quite fast
+      // so this threshold should permit most responses, but we can adjust `timeoutThresholdMs` if
+      // we find it is too aggressive.
+      const timeoutCheck = setInterval(() => {
+        if (lastChunkTime === null) return;
+
+        const now = Number(new Date());
+        const diffMs = now - lastChunkTime;
+        if (diffMs >= timeoutThresholdMs) {
+          this.log(
+            `Novita stream did not self-close and has been stale for >${timeoutThresholdMs}ms. Closing response stream.`
+          );
+          writeResponseChunk(response, {
+            uuid,
+            sources,
+            type: "textResponseChunk",
+            textResponse: "",
+            close: true,
+            error: false,
+          });
+          clearInterval(timeoutCheck);
+          response.removeListener("close", handleAbort);
+          resolve(fullText);
+        }
+      }, 500);
+
+      try {
+        for await (const chunk of stream) {
+          const message = chunk?.choices?.[0];
+          const token = message?.delta?.content;
+          lastChunkTime = Number(new Date());
+
+          if (token) {
+            fullText += token;
+            writeResponseChunk(response, {
+              uuid,
+              sources: [],
+              type: "textResponseChunk",
+              textResponse: token,
+              close: false,
+              error: false,
+            });
+          }
+
+          if (message.finish_reason !== null) {
+            writeResponseChunk(response, {
+              uuid,
+              sources,
+              type: "textResponseChunk",
+              textResponse: "",
+              close: true,
+              error: false,
+            });
+            response.removeListener("close", handleAbort);
+            resolve(fullText);
+          }
+        }
+      } catch (e) {
+        writeResponseChunk(response, {
+          uuid,
+          sources,
+          type: "abort",
+          textResponse: null,
+          close: true,
+          error: e.message,
+        });
+        response.removeListener("close", handleAbort);
+        resolve(fullText);
+      }
+    });
+  }
+
+  // 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);
+  }
+}
+
+async function fetchNovitaModels() {
+  return await fetch(`https://api.novita.ai/v3/openai/models`, {
+    method: "GET",
+    headers: {
+      "Content-Type": "application/json",
+    },
+  })
+    .then((res) => res.json())
+    .then(({ data = [] }) => {
+      const models = {};
+      data.forEach((model) => {
+        models[model.id] = {
+          id: model.id,
+          name: model.title,
+          organization:
+            model.id.split("/")[0].charAt(0).toUpperCase() +
+            model.id.split("/")[0].slice(1),
+          maxLength: model.context_size,
+        };
+      });
+
+      // Cache all response information
+      if (!fs.existsSync(cacheFolder))
+        fs.mkdirSync(cacheFolder, { recursive: true });
+      fs.writeFileSync(
+        path.resolve(cacheFolder, "models.json"),
+        JSON.stringify(models),
+        {
+          encoding: "utf-8",
+        }
+      );
+      fs.writeFileSync(
+        path.resolve(cacheFolder, ".cached_at"),
+        String(Number(new Date())),
+        {
+          encoding: "utf-8",
+        }
+      );
+      return models;
+    })
+    .catch((e) => {
+      console.error(e);
+      return {};
+    });
+}
+
+module.exports = {
+  NovitaLLM,
+  fetchNovitaModels,
+};
diff --git a/server/utils/agents/aibitat/index.js b/server/utils/agents/aibitat/index.js
index 24f027cff..d61867f4d 100644
--- a/server/utils/agents/aibitat/index.js
+++ b/server/utils/agents/aibitat/index.js
@@ -791,6 +791,8 @@ ${this.getHistory({ to: route.to })
         return new Providers.ApiPieProvider({ model: config.model });
       case "xai":
         return new Providers.XAIProvider({ model: config.model });
+      case "novita":
+        return new Providers.NovitaProvider({ model: config.model });
 
       default:
         throw new Error(
diff --git a/server/utils/agents/aibitat/providers/ai-provider.js b/server/utils/agents/aibitat/providers/ai-provider.js
index c9925d1cd..1bbf4a0a4 100644
--- a/server/utils/agents/aibitat/providers/ai-provider.js
+++ b/server/utils/agents/aibitat/providers/ai-provider.js
@@ -206,6 +206,14 @@ class Provider {
           apiKey: process.env.LITE_LLM_API_KEY ?? null,
           ...config,
         });
+      case "novita":
+        return new ChatOpenAI({
+          configuration: {
+            baseURL: "https://api.novita.ai/v3/openai",
+          },
+          apiKey: process.env.NOVITA_LLM_API_KEY ?? null,
+          ...config,
+        });
 
       default:
         throw new Error(`Unsupported provider ${provider} for this task.`);
diff --git a/server/utils/agents/aibitat/providers/index.js b/server/utils/agents/aibitat/providers/index.js
index 47e2d8716..c454c3938 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 NovitaProvider = require("./novita.js");
 
 module.exports = {
   OpenAIProvider,
@@ -40,4 +41,5 @@ module.exports = {
   LiteLLMProvider,
   ApiPieProvider,
   XAIProvider,
+  NovitaProvider,
 };
diff --git a/server/utils/agents/aibitat/providers/novita.js b/server/utils/agents/aibitat/providers/novita.js
new file mode 100644
index 000000000..16251aa25
--- /dev/null
+++ b/server/utils/agents/aibitat/providers/novita.js
@@ -0,0 +1,115 @@
+const OpenAI = require("openai");
+const Provider = require("./ai-provider.js");
+const InheritMultiple = require("./helpers/classes.js");
+const UnTooled = require("./helpers/untooled.js");
+
+/**
+ * The agent provider for the Novita AI provider.
+ */
+class NovitaProvider extends InheritMultiple([Provider, UnTooled]) {
+  model;
+
+  constructor(config = {}) {
+    const { model = "gryphe/mythomax-l2-13b" } = config;
+    super();
+    const client = new OpenAI({
+      baseURL: "https://api.novita.ai/v3/openai",
+      apiKey: process.env.NOVITA_LLM_API_KEY,
+      maxRetries: 3,
+      defaultHeaders: {
+        "HTTP-Referer": "https://anythingllm.com",
+        "X-Novita-Source": "anythingllm",
+      },
+    });
+
+    this._client = client;
+    this.model = model;
+    this.verbose = true;
+  }
+
+  get client() {
+    return this._client;
+  }
+
+  async #handleFunctionCallChat({ messages = [] }) {
+    return await this.client.chat.completions
+      .create({
+        model: this.model,
+        temperature: 0,
+        messages,
+      })
+      .then((result) => {
+        if (!result.hasOwnProperty("choices"))
+          throw new Error("Novita chat: No results!");
+        if (result.choices.length === 0)
+          throw new Error("Novita chat: No results length!");
+        return result.choices[0].message.content;
+      })
+      .catch((_) => {
+        return null;
+      });
+  }
+
+  /**
+   * Create a completion based on the received messages.
+   *
+   * @param messages A list of messages to send to the API.
+   * @param functions
+   * @returns The completion.
+   */
+  async complete(messages, functions = null) {
+    let completion;
+    if (functions.length > 0) {
+      const { toolCall, text } = await this.functionCall(
+        messages,
+        functions,
+        this.#handleFunctionCallChat.bind(this)
+      );
+
+      if (toolCall !== null) {
+        this.providerLog(`Valid tool call found - running ${toolCall.name}.`);
+        this.deduplicator.trackRun(toolCall.name, toolCall.arguments);
+        return {
+          result: null,
+          functionCall: {
+            name: toolCall.name,
+            arguments: toolCall.arguments,
+          },
+          cost: 0,
+        };
+      }
+      completion = { content: text };
+    }
+
+    if (!completion?.content) {
+      this.providerLog("Will assume chat completion without tool call inputs.");
+      const response = await this.client.chat.completions.create({
+        model: this.model,
+        messages: this.cleanMsgs(messages),
+      });
+      completion = response.choices[0].message;
+    }
+
+    // The UnTooled class inherited Deduplicator is mostly useful to prevent the agent
+    // from calling the exact same function over and over in a loop within a single chat exchange
+    // _but_ we should enable it to call previously used tools in a new chat interaction.
+    this.deduplicator.reset("runs");
+    return {
+      result: completion.content,
+      cost: 0,
+    };
+  }
+
+  /**
+   * Get the cost of the completion.
+   *
+   * @param _usage The completion to get the cost for.
+   * @returns The cost of the completion.
+   * Stubbed since Novita AI has no cost basis.
+   */
+  getCost() {
+    return 0;
+  }
+}
+
+module.exports = NovitaProvider;
diff --git a/server/utils/agents/index.js b/server/utils/agents/index.js
index fd7d06e8b..6b1d42af2 100644
--- a/server/utils/agents/index.js
+++ b/server/utils/agents/index.js
@@ -173,6 +173,10 @@ class AgentHandler {
         if (!process.env.XAI_LLM_API_KEY)
           throw new Error("xAI 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.");
+        break;
 
       default:
         throw new Error(
@@ -234,6 +238,8 @@ class AgentHandler {
         return process.env.APIPIE_LLM_MODEL_PREF ?? null;
       case "xai":
         return process.env.XAI_LLM_MODEL_PREF ?? "grok-beta";
+      case "novita":
+        return process.env.NOVITA_LLM_MODEL_PREF ?? "gryphe/mythomax-l2-13b";
       default:
         return null;
     }
diff --git a/server/utils/helpers/customModels.js b/server/utils/helpers/customModels.js
index 7ccbf13c7..163933769 100644
--- a/server/utils/helpers/customModels.js
+++ b/server/utils/helpers/customModels.js
@@ -4,6 +4,7 @@ const { perplexityModels } = require("../AiProviders/perplexity");
 const { togetherAiModels } = require("../AiProviders/togetherAi");
 const { fireworksAiModels } = require("../AiProviders/fireworksAi");
 const { ElevenLabsTTS } = require("../TextToSpeech/elevenLabs");
+const { fetchNovitaModels } = require("../AiProviders/novita");
 const SUPPORT_CUSTOM_MODELS = [
   "openai",
   "localai",
@@ -21,6 +22,7 @@ const SUPPORT_CUSTOM_MODELS = [
   "groq",
   "deepseek",
   "apipie",
+  "novita",
   "xai",
 ];
 
@@ -61,6 +63,8 @@ async function getCustomModels(provider = "", apiKey = null, basePath = null) {
       return await getDeepSeekModels(apiKey);
     case "apipie":
       return await getAPIPieModels(apiKey);
+    case "novita":
+      return await getNovitaModels();
     case "xai":
       return await getXAIModels(apiKey);
     default:
@@ -362,6 +366,20 @@ async function getOpenRouterModels() {
   return { models, error: null };
 }
 
+async function getNovitaModels() {
+  const knownModels = await fetchNovitaModels();
+  if (!Object.keys(knownModels).length === 0)
+    return { models: [], error: null };
+  const models = Object.values(knownModels).map((model) => {
+    return {
+      id: model.id,
+      organization: model.organization,
+      name: model.name,
+    };
+  });
+  return { models, error: null };
+}
+
 async function getAPIPieModels(apiKey = null) {
   const knownModels = await fetchApiPieModels(apiKey);
   if (!Object.keys(knownModels).length === 0)
diff --git a/server/utils/helpers/index.js b/server/utils/helpers/index.js
index 84f971cc6..57ec191e7 100644
--- a/server/utils/helpers/index.js
+++ b/server/utils/helpers/index.js
@@ -165,6 +165,9 @@ function getLLMProvider({ provider = null, model = null } = {}) {
     case "apipie":
       const { ApiPieLLM } = require("../AiProviders/apipie");
       return new ApiPieLLM(embedder, model);
+    case "novita":
+      const { NovitaLLM } = require("../AiProviders/novita");
+      return new NovitaLLM(embedder, model);
     case "xai":
       const { XAiLLM } = require("../AiProviders/xai");
       return new XAiLLM(embedder, model);
@@ -297,6 +300,9 @@ function getLLMProviderClass({ provider = null } = {}) {
     case "apipie":
       const { ApiPieLLM } = require("../AiProviders/apipie");
       return ApiPieLLM;
+    case "novita":
+      const { NovitaLLM } = require("../AiProviders/novita");
+      return NovitaLLM;
     case "xai":
       const { XAiLLM } = require("../AiProviders/xai");
       return XAiLLM;
diff --git a/server/utils/helpers/updateENV.js b/server/utils/helpers/updateENV.js
index 6081159a5..676eb812f 100644
--- a/server/utils/helpers/updateENV.js
+++ b/server/utils/helpers/updateENV.js
@@ -395,6 +395,20 @@ const KEY_MAPPING = {
     checks: [],
   },
 
+  // Novita Options
+  NovitaLLMApiKey: {
+    envKey: "NOVITA_LLM_API_KEY",
+    checks: [isNotEmpty],
+  },
+  NovitaLLMModelPref: {
+    envKey: "NOVITA_LLM_MODEL_PREF",
+    checks: [isNotEmpty],
+  },
+  NovitaLLMTimeout: {
+    envKey: "NOVITA_LLM_TIMEOUT_MS",
+    checks: [],
+  },
+
   // Groq Options
   GroqApiKey: {
     envKey: "GROQ_API_KEY",
@@ -655,6 +669,7 @@ function supportedLLM(input = "") {
     "huggingface",
     "perplexity",
     "openrouter",
+    "novita",
     "groq",
     "koboldcpp",
     "textgenwebui",
-- 
GitLab