Repository: Mintplex-Labs/anything-llm
File: server/utils/AiProviders/azureOpenAi/index.js (JavaScript)

Code before:
const { NativeEmbedder } = require("../../EmbeddingEngines/native");
const {
  formatChatHistory,
  handleDefaultStreamResponseV2,
} = require("../../helpers/chat/responses");
const {
  LLMPerformanceMonitor,
} = require("../../helpers/chat/LLMPerformanceMonitor");

class AzureOpenAiLLM {
  constructor(embedder = null, modelPreference = null) {
    const { OpenAI } = require("openai");
    if (!process.env.AZURE_OPENAI_ENDPOINT)
      throw new Error("No Azure API endpoint was set.");
    if (!process.env.AZURE_OPENAI_KEY)
      throw new Error("No Azure API key was set.");

    this.openai = new OpenAI({
      apiKey: process.env.AZURE_OPENAI_KEY,
      baseURL: `${process.env.AZURE_OPENAI_ENDPOINT}/openai/v1`,
    });
    this.model = modelPreference ?? process.env.OPEN_MODEL_PREF;
    /* 
      Note: Azure OpenAI deployments do not expose model metadata that would allow us to
      programmatically detect whether the deployment uses a reasoning model (o1, o1-mini, o3-mini, etc.).
      As a result, we rely on the user to explicitly set AZURE_OPENAI_MODEL_TYPE="reasoning"
      when using reasoning models, as incorrect configuration might result in chat errors.
    */
    this.isOTypeModel =
      process.env.AZURE_OPENAI_MODEL_TYPE === "reasoning" || false;
    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. Model "${this.model}" @ ${this.promptWindowLimit()} tokens.\nAPI-Version: ${this.apiVersion}.\nModel Type: ${this.isOTypeModel ? "reasoning" : "default"}`
    );
  }

  #log(text, ...args) {
    console.log(`\x1b[32m[AzureOpenAi]\x1b[0m ${text}`, ...args);

Review comment (suggestion):
Given the user could paste in _anything_ for the URL we should do them a favor incase they decide to paste in `http://my.auzre.deployment/profile/account/model/gpt-4o-deployment/openai/v1/models....` since the Azure portal does not always show such a base URL.

Since we know this should _just_ be the hostname create a `static` method on this class to validate and return the complete URL

```nodejs
try {
const url = new URL(process.env.AZURE_OPENAI_ENDPOINT)
url.pathname = /openai/v1
return url.toString()
} catch ....
```

This way, no matter what they give us, we will just use the part of the input needed to resolve the URL the way it needs to be resolved to reach the v1 endpoint.

Then use this util static method in the Agent so you can re-validate there as well before building the client.

Code after:
const { NativeEmbedder } = require("../../EmbeddingEngines/native");
const {
  formatChatHistory,
  handleDefaultStreamResponseV2,
} = require("../../helpers/chat/responses");
const {
  LLMPerformanceMonitor,
} = require("../../helpers/chat/LLMPerformanceMonitor");

class AzureOpenAiLLM {
  constructor(embedder = null, modelPreference = null) {
    const { OpenAI } = require("openai");
    if (!process.env.AZURE_OPENAI_ENDPOINT)
      throw new Error("No Azure API endpoint was set.");
    if (!process.env.AZURE_OPENAI_KEY)
      throw new Error("No Azure API key was set.");

    this.openai = new OpenAI({
      apiKey: process.env.AZURE_OPENAI_KEY,
      baseURL: AzureOpenAiLLM.formatBaseUrl(process.env.AZURE_OPENAI_ENDPOINT),
    });
    this.model = modelPreference ?? process.env.OPEN_MODEL_PREF;
    /* 
      Note: Azure OpenAI deployments do not expose model metadata that would allow us to
      programmatically detect whether the deployment uses a reasoning model (o1, o1-mini, o3-mini, etc.).
      As a result, we rely on the user to explicitly set AZURE_OPENAI_MODEL_TYPE="reasoning"
      when using reasoning models, as incorrect configuration might result in chat errors.
    */
    this.isOTypeModel =
      process.env.AZURE_OPENAI_MODEL_TYPE === "reasoning" || false;
    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. Model "${this.model}" @ ${this.promptWindowLimit()} tokens.\nAPI-Version: ${this.apiVersion}.\nModel Type: ${this.isOTypeModel ? "reasoning" : "default"}`
    );
  }

  /**
   * Formats the Azure OpenAI endpoint URL to the correct format.