File size: 4,546 Bytes
05c5ed5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
982b5dc
05c5ed5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
import { createAzureOpenAICompatible } from "./azure-openai-compatible";
import { createOpenAICompatible } from "@ai-sdk/openai-compatible";
import { LanguageModel } from "ai";
import { isString } from "lib/utils";
import logger from "logger";
import { z } from "zod";

/**
 * OpenAI-compatible models from an environment variable.
 * @returns An object containing the loaded models and a set of models
 *          that do not support tool calls.
 */
export function createOpenAICompatibleModels(
  config: OpenAICompatibleProvider[],
) {
  const providers: Record<string, Record<string, LanguageModel>> = {};
  const unsupportedModels = new Set<LanguageModel>();

  if (!config?.length) {
    return { providers, unsupportedModels };
  }
  try {
    config.forEach(({ provider, models, baseUrl, apiKey }) => {
      const providerKey = provider;
      const customProvider = createOpenAICompatible({
        name: provider,
        apiKey: apiKey || "dummy-key",
        baseURL: baseUrl!,
      });

      providers[providerKey] = {};

      if (provider === "Azure OpenAI") {
        // Handle Azure OpenAI with specific requirements (new addition)
        const azureProvider = createAzureOpenAICompatible({
          name: provider,
          apiKey: apiKey,
          baseURL: baseUrl!,
        });

        models.forEach(
          ({ apiName, uiName, supportsTools, apiVersion: modelApiVersion }) => {
            if (!modelApiVersion) {
              throw new Error(
                `API version is required for Azure OpenAI model: ${uiName}`,
              );
            }
            const model = azureProvider(apiName, modelApiVersion);
            providers[providerKey][uiName] = model;

            if (!supportsTools) {
              unsupportedModels.add(model);
            }
          },
        );
      } else {
        // Standard OpenAI-compatible providers (original implementation)
        models.forEach(({ apiName, uiName, supportsTools }) => {
          const model = customProvider(apiName);
          providers[providerKey][uiName] = model;

          if (!supportsTools) {
            unsupportedModels.add(model);
          }
        });
      }
    });
  } catch (error) {
    console.error("Failed to load or parse dynamic models:", error);
  }

  return { providers, unsupportedModels };
}

// Define the schema for a single AI model that is compatible with OpenAI's API structure.
const OpenAICompatibleModelSchema = z.object({
  apiName: z.string().describe("The internal API name for the model."),
  uiName: z.string().describe("The user-friendly name for the model."),
  // Whether the model supports external tools/function calling, specifically for multi-cloud platform (MCP) servers.
  supportsTools: z
    .boolean()
    .describe(
      "Indicates if the model supports external tools/function calling for multi-cloud platform (MCP) servers.",
    ),
  apiVersion: z
    .string()
    .optional()
    .describe(
      "For Azure OpenAI, the API version for this specific model. Required for Azure OpenAI models.",
    ),
});

// Define the schema for a provider that is compatible with OpenAI's API structure,
// which includes a list of its OpenAI-compatible models.
export const OpenAICompatibleProviderSchema = z.object({
  provider: z.string().describe("Your api key"),
  models: z
    .array(OpenAICompatibleModelSchema)
    .describe("A list of AI models offered by this provider."),
  // The environment variable name for the provider's API key. Stored in .env.
  apiKey: z
    .string()
    .describe(
      "The name of the environment variable (e.g., 'OPENAI_API_KEY') for the provider's API key. This key should be stored in a .env file.",
    ),
  // The base URL for the provider's API. Defaults to the provider's default API endpoint. Should be OpenAI-like.
  baseUrl: z
    .string()
    .url()
    .optional()
    .describe(
      "The base URL for the provider's API. Defaults to the provider's official endpoint. Should typically follow an OpenAI-like structure (e.g., ending with '/v1').",
    ),
});

// Infer the type for a single OpenAI-compatible provider.
export type OpenAICompatibleProvider = z.infer<
  typeof OpenAICompatibleProviderSchema
>;

export const openaiCompatibleModelsSafeParse = (
  providers: string | OpenAICompatibleProvider[] = [],
) => {
  try {
    const value = isString(providers) ? JSON.parse(providers) : providers;
    return z.array(OpenAICompatibleProviderSchema).parse(value);
  } catch (error) {
    logger.error(error);
    return [];
  }
};