diff --git a/packages/__tests__/cost/__snapshots__/registrySnapshots.test.ts.snap b/packages/__tests__/cost/__snapshots__/registrySnapshots.test.ts.snap index ab023ddc00..75d656f9eb 100644 --- a/packages/__tests__/cost/__snapshots__/registrySnapshots.test.ts.snap +++ b/packages/__tests__/cost/__snapshots__/registrySnapshots.test.ts.snap @@ -3578,6 +3578,102 @@ exports[`Registry Snapshots endpoint configurations snapshot 1`] = ` ], }, }, + "minimax/minimax-m2.5": { + "minimax-m2.5-highspeed:minimax": { + "context": 204000, + "crossRegion": false, + "maxTokens": 8192, + "modelId": "MiniMax-M2.5-highspeed", + "parameters": [ + "frequency_penalty", + "max_tokens", + "presence_penalty", + "response_format", + "stop", + "stream", + "temperature", + "tool_choice", + "tools", + "top_p", + ], + "provider": "minimax", + "ptbEnabled": true, + "regions": [ + "*", + ], + }, + "minimax-m2.5:minimax": { + "context": 204000, + "crossRegion": false, + "maxTokens": 8192, + "modelId": "MiniMax-M2.5", + "parameters": [ + "frequency_penalty", + "max_tokens", + "presence_penalty", + "response_format", + "stop", + "stream", + "temperature", + "tool_choice", + "tools", + "top_p", + ], + "provider": "minimax", + "ptbEnabled": true, + "regions": [ + "*", + ], + }, + }, + "minimax/minimax-m2.7": { + "minimax-m2.7-highspeed:minimax": { + "context": 1000000, + "crossRegion": false, + "maxTokens": 16384, + "modelId": "MiniMax-M2.7-highspeed", + "parameters": [ + "frequency_penalty", + "max_tokens", + "presence_penalty", + "response_format", + "stop", + "stream", + "temperature", + "tool_choice", + "tools", + "top_p", + ], + "provider": "minimax", + "ptbEnabled": true, + "regions": [ + "*", + ], + }, + "minimax-m2.7:minimax": { + "context": 1000000, + "crossRegion": false, + "maxTokens": 16384, + "modelId": "MiniMax-M2.7", + "parameters": [ + "frequency_penalty", + "max_tokens", + "presence_penalty", + "response_format", + "stop", + "stream", + "temperature", + "tool_choice", + "tools", + "top_p", + ], + "provider": "minimax", + "ptbEnabled": true, + "regions": [ + "*", + ], + }, + }, "mistral/mistral-large": { "mistral-large-2411:mistral": { "context": 128000, @@ -7522,6 +7618,14 @@ exports[`Registry Snapshots model coverage snapshot 1`] = ` "openrouter", "openrouter", ], + "minimax/minimax-m2.5": [ + "minimax", + "minimax", + ], + "minimax/minimax-m2.7": [ + "minimax", + "minimax", + ], "mistral/mistral-large": [ "mistral", ], @@ -9321,6 +9425,24 @@ exports[`Registry Snapshots pricing snapshot 1`] = ` }, ], }, + "minimax/minimax-m2.5": { + "minimax": [ + { + "input": 1e-7, + "output": 5.5e-7, + "threshold": 0, + }, + ], + }, + "minimax/minimax-m2.7": { + "minimax": [ + { + "input": 1e-7, + "output": 5.5e-7, + "threshold": 0, + }, + ], + }, "mistral/mistral-large": { "mistral": [ { @@ -10698,6 +10820,30 @@ exports[`Registry Snapshots verify registry state 1`] = ` "groq", ], }, + { + "model": "minimax-m2.5", + "providers": [ + "minimax", + ], + }, + { + "model": "minimax-m2.5-highspeed", + "providers": [ + "minimax", + ], + }, + { + "model": "minimax-m2.7", + "providers": [ + "minimax", + ], + }, + { + "model": "minimax-m2.7-highspeed", + "providers": [ + "minimax", + ], + }, { "model": "mistral-large-2411", "providers": [ @@ -10897,6 +11043,10 @@ exports[`Registry Snapshots verify registry state 1`] = ` "modelCount": 55, "provider": "helicone", }, + { + "modelCount": 4, + "provider": "minimax", + }, { "modelCount": 1, "provider": "mistral", @@ -11017,6 +11167,10 @@ exports[`Registry Snapshots verify registry state 1`] = ` "llama-guard-4", "llama-prompt-guard-2-22m", "llama-prompt-guard-2-86m", + "minimax-m2.5", + "minimax-m2.5-highspeed", + "minimax-m2.7", + "minimax-m2.7-highspeed", "mistral-large-2411", "mistral-nemo", "mistral-small", @@ -11049,9 +11203,9 @@ exports[`Registry Snapshots verify registry state 1`] = ` "claude-3.5-haiku:anthropic:*", ], "totalArchivedConfigs": 0, - "totalEndpoints": 329, - "totalModelProviderConfigs": 329, - "totalModelsWithPtb": 108, - "totalProviders": 21, + "totalEndpoints": 333, + "totalModelProviderConfigs": 333, + "totalModelsWithPtb": 112, + "totalProviders": 22, } `; diff --git a/packages/__tests__/cost/providers/minimax-integration.test.ts b/packages/__tests__/cost/providers/minimax-integration.test.ts new file mode 100644 index 0000000000..ccd97f3ef6 --- /dev/null +++ b/packages/__tests__/cost/providers/minimax-integration.test.ts @@ -0,0 +1,160 @@ +import { describe, it, expect } from "@jest/globals"; +import { registry } from "../../../cost/models/registry"; +import { + buildEndpointUrl, + buildRequestBody, + parseModelString, +} from "../../../cost/models/provider-helpers"; +import { getUsageProcessor } from "../../../cost/usage/getUsageProcessor"; + +describe("MiniMax integration", () => { + describe("model string parsing", () => { + it("should parse minimax-m2.7 without provider", () => { + const result = parseModelString("minimax-m2.7"); + expect(result.data).toBeDefined(); + expect(result.data?.modelName).toBe("minimax-m2.7"); + expect(result.data?.provider).toBeUndefined(); + }); + + it("should parse minimax-m2.7/minimax with provider", () => { + const result = parseModelString("minimax-m2.7/minimax"); + expect(result.data).toBeDefined(); + expect(result.data?.modelName).toBe("minimax-m2.7"); + expect(result.data?.provider).toBe("minimax"); + }); + + it("should parse minimax-m2.5-highspeed/minimax", () => { + const result = parseModelString("minimax-m2.5-highspeed/minimax"); + expect(result.data).toBeDefined(); + expect(result.data?.modelName).toBe("minimax-m2.5-highspeed"); + expect(result.data?.provider).toBe("minimax"); + }); + }); + + describe("endpoint URL building", () => { + it("should build correct URL for minimax-m2.7", () => { + const configResult = registry.getModelProviderConfig( + "minimax-m2.7", + "minimax" + ); + expect(configResult.data).toBeDefined(); + + const endpointResult = registry.buildEndpoint(configResult.data!, {}); + expect(endpointResult.data).toBeDefined(); + + const urlResult = buildEndpointUrl(endpointResult.data!, {}); + expect(urlResult.data).toBe( + "https://api.minimax.io/v1/chat/completions" + ); + }); + }); + + describe("usage processing", () => { + it("should process OpenAI-format usage for minimax", async () => { + const processor = getUsageProcessor("minimax"); + expect(processor).not.toBeNull(); + + const mockResponse = { + id: "minimax-test-123", + object: "chat.completion", + created: Date.now(), + model: "MiniMax-M2.7", + choices: [ + { + index: 0, + message: { + role: "assistant", + content: "Hello! How can I help you?", + }, + finish_reason: "stop", + }, + ], + usage: { + prompt_tokens: 10, + completion_tokens: 8, + total_tokens: 18, + }, + }; + + const result = await processor!.parse({ + responseBody: JSON.stringify(mockResponse), + model: "MiniMax-M2.7", + isStream: false, + }); + expect(result.data).toBeDefined(); + expect(result.data?.input).toBe(10); + expect(result.data?.output).toBe(8); + }); + }); + + describe("PTB endpoints", () => { + it("should return PTB endpoints for minimax-m2.7", () => { + const result = registry.getPtbEndpointsByProvider( + "minimax-m2.7", + "minimax" + ); + expect(result.data).toBeDefined(); + expect(result.data!.length).toBeGreaterThan(0); + expect(result.data![0].provider).toBe("minimax"); + }); + + it("should return PTB endpoints for all MiniMax models", () => { + const models = [ + "minimax-m2.7", + "minimax-m2.7-highspeed", + "minimax-m2.5", + "minimax-m2.5-highspeed", + ]; + + for (const model of models) { + const result = registry.getPtbEndpointsByProvider(model, "minimax"); + expect(result.data).toBeDefined(); + expect(result.data!.length).toBeGreaterThan(0); + } + }); + }); + + describe("full request flow", () => { + it("should build complete request for minimax-m2.7", async () => { + const configResult = registry.getModelProviderConfig( + "minimax-m2.7", + "minimax" + ); + expect(configResult.data).toBeDefined(); + + const endpointResult = registry.buildEndpoint(configResult.data!, {}); + expect(endpointResult.data).toBeDefined(); + + // Build URL + const urlResult = buildEndpointUrl(endpointResult.data!, {}); + expect(urlResult.data).toBe( + "https://api.minimax.io/v1/chat/completions" + ); + + // Build request body + const mockBody = { + model: "minimax-m2.7", + messages: [ + { role: "system", content: "You are a helpful assistant." }, + { role: "user", content: "What is 1+1?" }, + ], + temperature: 0.7, + max_tokens: 100, + }; + + const bodyResult = await buildRequestBody(endpointResult.data!, { + parsedBody: mockBody, + bodyMapping: "OPENAI", + toAnthropic: (body: any) => body, + toChatCompletions: (body: any) => body, + }); + + expect(bodyResult.data).toBeDefined(); + const parsed = JSON.parse(bodyResult.data!); + expect(parsed.model).toBe("MiniMax-M2.7"); + expect(parsed.messages).toHaveLength(2); + expect(parsed.temperature).toBe(0.7); + expect(parsed.max_tokens).toBe(100); + }); + }); +}); diff --git a/packages/__tests__/cost/providers/minimax.test.ts b/packages/__tests__/cost/providers/minimax.test.ts new file mode 100644 index 0000000000..721243a6a7 --- /dev/null +++ b/packages/__tests__/cost/providers/minimax.test.ts @@ -0,0 +1,229 @@ +import { describe, it, expect } from "@jest/globals"; +import { registry } from "../../../cost/models/registry"; +import { buildRequestBody } from "../../../cost/models/provider-helpers"; +import { MiniMaxProvider } from "../../../cost/models/providers/minimax"; +import { providers } from "../../../cost/models/providers"; +import { getUsageProcessor } from "../../../cost/usage/getUsageProcessor"; +import { + heliconeProviderToModelProviderName, + dbProviderToProvider, +} from "../../../cost/models/provider-helpers"; + +describe("MiniMax provider", () => { + describe("provider class", () => { + const provider = new MiniMaxProvider(); + + it("should have correct display name", () => { + expect(provider.displayName).toBe("MiniMax"); + }); + + it("should have correct base URL", () => { + expect(provider.baseUrl).toBe("https://api.minimax.io"); + }); + + it("should use api-key auth", () => { + expect(provider.auth).toBe("api-key"); + }); + + it("should build correct URL", () => { + const url = provider.buildUrl({} as any, {} as any); + expect(url).toBe("https://api.minimax.io/v1/chat/completions"); + }); + + it("should have pricing pages", () => { + expect(provider.pricingPages.length).toBeGreaterThan(0); + }); + + it("should have model pages", () => { + expect(provider.modelPages.length).toBeGreaterThan(0); + }); + }); + + describe("provider registry", () => { + it("should be registered in providers", () => { + expect(providers.minimax).toBeDefined(); + expect(providers.minimax).toBeInstanceOf(MiniMaxProvider); + }); + + it("should have usage processor", () => { + const processor = getUsageProcessor("minimax"); + expect(processor).not.toBeNull(); + }); + }); + + describe("provider name mapping", () => { + it("should map MINIMAX to minimax", () => { + expect(heliconeProviderToModelProviderName("MINIMAX")).toBe("minimax"); + }); + + it("should map db provider names", () => { + expect(dbProviderToProvider("minimax")).toBe("minimax"); + expect(dbProviderToProvider("MiniMax")).toBe("minimax"); + }); + }); + + describe("minimax-m2.7:minimax endpoint", () => { + it("should have correct model config", () => { + const configResult = registry.getModelProviderConfig( + "minimax-m2.7", + "minimax" + ); + expect(configResult.data).toBeDefined(); + expect(configResult.data?.providerModelId).toBe("MiniMax-M2.7"); + expect(configResult.data?.provider).toBe("minimax"); + expect(configResult.data?.author).toBe("minimax"); + }); + + it("should have correct pricing", () => { + const configResult = registry.getModelProviderConfig( + "minimax-m2.7", + "minimax" + ); + expect(configResult.data).toBeDefined(); + expect(configResult.data?.pricing[0].input).toBe(0.0000002); + expect(configResult.data?.pricing[0].output).toBe(0.0000011); + }); + + it("should have correct context length", () => { + const configResult = registry.getModelProviderConfig( + "minimax-m2.7", + "minimax" + ); + expect(configResult.data).toBeDefined(); + expect(configResult.data?.contextLength).toBe(1_000_000); + expect(configResult.data?.maxCompletionTokens).toBe(16_384); + }); + + it("should build endpoint with correct providerModelId", () => { + const configResult = registry.getModelProviderConfig( + "minimax-m2.7", + "minimax" + ); + expect(configResult.data).toBeDefined(); + + const endpointResult = registry.buildEndpoint(configResult.data!, {}); + expect(endpointResult.data).toBeDefined(); + expect(endpointResult.data?.providerModelId).toBe("MiniMax-M2.7"); + }); + + it("should include correct model in request body", async () => { + const configResult = registry.getModelProviderConfig( + "minimax-m2.7", + "minimax" + ); + expect(configResult.data).toBeDefined(); + + const endpointResult = registry.buildEndpoint(configResult.data!, {}); + expect(endpointResult.data).toBeDefined(); + + const mockParsedBody = { + model: "minimax-m2.7", + messages: [{ role: "user", content: "hello" }], + }; + const result = await buildRequestBody(endpointResult.data!, { + parsedBody: mockParsedBody, + bodyMapping: "OPENAI", + toAnthropic: (body: any) => body, + toChatCompletions: (body: any) => body, + }); + + expect(result.data).toBeDefined(); + const parsed = JSON.parse(result.data!); + expect(parsed.model).toBe("MiniMax-M2.7"); + }); + + it("should support required parameters", () => { + const configResult = registry.getModelProviderConfig( + "minimax-m2.7", + "minimax" + ); + expect(configResult.data).toBeDefined(); + const params = configResult.data?.supportedParameters || []; + expect(params).toContain("max_tokens"); + expect(params).toContain("temperature"); + expect(params).toContain("top_p"); + expect(params).toContain("stream"); + expect(params).toContain("tools"); + expect(params).toContain("tool_choice"); + }); + + it("should have PTB enabled", () => { + const configResult = registry.getModelProviderConfig( + "minimax-m2.7", + "minimax" + ); + expect(configResult.data?.ptbEnabled).toBe(true); + }); + }); + + describe("minimax-m2.7-highspeed:minimax endpoint", () => { + it("should have correct model config", () => { + const configResult = registry.getModelProviderConfig( + "minimax-m2.7-highspeed", + "minimax" + ); + expect(configResult.data).toBeDefined(); + expect(configResult.data?.providerModelId).toBe( + "MiniMax-M2.7-highspeed" + ); + }); + + it("should have lower pricing than M2.7", () => { + const configResult = registry.getModelProviderConfig( + "minimax-m2.7-highspeed", + "minimax" + ); + expect(configResult.data).toBeDefined(); + expect(configResult.data?.pricing[0].input).toBe(0.0000001); + expect(configResult.data?.pricing[0].output).toBe(0.00000055); + }); + }); + + describe("minimax-m2.5:minimax endpoint", () => { + it("should have correct model config", () => { + const configResult = registry.getModelProviderConfig( + "minimax-m2.5", + "minimax" + ); + expect(configResult.data).toBeDefined(); + expect(configResult.data?.providerModelId).toBe("MiniMax-M2.5"); + expect(configResult.data?.contextLength).toBe(204_000); + expect(configResult.data?.maxCompletionTokens).toBe(8_192); + }); + }); + + describe("minimax-m2.5-highspeed:minimax endpoint", () => { + it("should have correct model config", () => { + const configResult = registry.getModelProviderConfig( + "minimax-m2.5-highspeed", + "minimax" + ); + expect(configResult.data).toBeDefined(); + expect(configResult.data?.providerModelId).toBe( + "MiniMax-M2.5-highspeed" + ); + }); + }); + + describe("model registry", () => { + it("should list all MiniMax models", () => { + const allModels = registry.getAllModelIds(); + expect(allModels.data).toBeDefined(); + expect(allModels.data).toContain("minimax-m2.7"); + expect(allModels.data).toContain("minimax-m2.7-highspeed"); + expect(allModels.data).toContain("minimax-m2.5"); + expect(allModels.data).toContain("minimax-m2.5-highspeed"); + }); + + it("should return minimax provider for minimax models", () => { + const providers = registry.getModelProviders("minimax-m2.7"); + expect(providers.data).toBeDefined(); + expect(providers.data?.has("minimax")).toBe(true); + }); + + it("should return correct author for minimax models", () => { + const author = registry.getAuthorByModel("minimax-m2.7"); + expect(author).toBe("minimax"); + }); + }); +}); diff --git a/packages/cost/models/authors/minimax/index.ts b/packages/cost/models/authors/minimax/index.ts new file mode 100644 index 0000000000..a7444e6208 --- /dev/null +++ b/packages/cost/models/authors/minimax/index.ts @@ -0,0 +1,26 @@ +/** + * MiniMax model registry aggregation + * Combines all models and endpoints from subdirectories + */ + +import type { ModelConfig, ModelProviderConfig } from "../../types"; + +// Import models +import { models as m27Models } from "./minimax-m2.7/model"; +import { models as m25Models } from "./minimax-m2.5/model"; + +// Import endpoints +import { endpoints as m27Endpoints } from "./minimax-m2.7/endpoints"; +import { endpoints as m25Endpoints } from "./minimax-m2.5/endpoints"; + +// Aggregate models +export const minimaxModels = { + ...m27Models, + ...m25Models, +} satisfies Record; + +// Aggregate endpoints +export const minimaxEndpointConfig = { + ...m27Endpoints, + ...m25Endpoints, +} satisfies Record; diff --git a/packages/cost/models/authors/minimax/metadata.ts b/packages/cost/models/authors/minimax/metadata.ts new file mode 100644 index 0000000000..59d04546a9 --- /dev/null +++ b/packages/cost/models/authors/minimax/metadata.ts @@ -0,0 +1,11 @@ +/** + * MiniMax metadata + */ + +import type { AuthorMetadata } from "../../types"; +import { minimaxModels } from "./index"; + +export const minimaxMetadata = { + modelCount: Object.keys(minimaxModels).length, + supported: true, +} satisfies AuthorMetadata; diff --git a/packages/cost/models/authors/minimax/minimax-m2.5/endpoints.ts b/packages/cost/models/authors/minimax/minimax-m2.5/endpoints.ts new file mode 100644 index 0000000000..c63fbb2a71 --- /dev/null +++ b/packages/cost/models/authors/minimax/minimax-m2.5/endpoints.ts @@ -0,0 +1,68 @@ +import { ModelProviderName } from "../../../providers"; +import type { ModelProviderConfig } from "../../../types"; +import { MiniMaxM25ModelName } from "./model"; + +export const endpoints = { + "minimax-m2.5:minimax": { + provider: "minimax", + author: "minimax", + providerModelId: "MiniMax-M2.5", + pricing: [ + { + threshold: 0, + input: 0.0000002, // $0.20 per 1M tokens + output: 0.0000011, // $1.10 per 1M tokens + }, + ], + contextLength: 204_000, + maxCompletionTokens: 8_192, + supportedParameters: [ + "max_tokens", + "temperature", + "top_p", + "stop", + "stream", + "tools", + "tool_choice", + "response_format", + "frequency_penalty", + "presence_penalty", + ], + ptbEnabled: true, + endpointConfigs: { + "*": {}, + }, + }, + "minimax-m2.5-highspeed:minimax": { + provider: "minimax", + author: "minimax", + providerModelId: "MiniMax-M2.5-highspeed", + pricing: [ + { + threshold: 0, + input: 0.0000001, // $0.10 per 1M tokens + output: 0.00000055, // $0.55 per 1M tokens + }, + ], + contextLength: 204_000, + maxCompletionTokens: 8_192, + supportedParameters: [ + "max_tokens", + "temperature", + "top_p", + "stop", + "stream", + "tools", + "tool_choice", + "response_format", + "frequency_penalty", + "presence_penalty", + ], + ptbEnabled: true, + endpointConfigs: { + "*": {}, + }, + }, +} satisfies Partial< + Record<`${MiniMaxM25ModelName}:${ModelProviderName}`, ModelProviderConfig> +>; diff --git a/packages/cost/models/authors/minimax/minimax-m2.5/model.ts b/packages/cost/models/authors/minimax/minimax-m2.5/model.ts new file mode 100644 index 0000000000..ea4b51162d --- /dev/null +++ b/packages/cost/models/authors/minimax/minimax-m2.5/model.ts @@ -0,0 +1,28 @@ +import type { ModelConfig } from "../../../types"; + +export const models = { + "minimax-m2.5": { + name: "MiniMax M2.5", + author: "minimax", + description: + "MiniMax-M2.5 is a high-performance large language model with 204K token context window. It supports function calling, JSON output, and delivers strong results on coding, reasoning, and general language tasks.", + contextLength: 204_000, + maxOutputTokens: 8_192, + created: "2025-01-01T00:00:00.000Z", + modality: { inputs: ["text"], outputs: ["text"] }, + tokenizer: "MiniMax", + }, + "minimax-m2.5-highspeed": { + name: "MiniMax M2.5 Highspeed", + author: "minimax", + description: + "MiniMax-M2.5-highspeed is an optimized variant of MiniMax-M2.5, offering faster inference at reduced cost. Ideal for high-throughput and latency-sensitive workloads with 204K context support.", + contextLength: 204_000, + maxOutputTokens: 8_192, + created: "2025-01-01T00:00:00.000Z", + modality: { inputs: ["text"], outputs: ["text"] }, + tokenizer: "MiniMax", + }, +} satisfies Record; + +export type MiniMaxM25ModelName = keyof typeof models; diff --git a/packages/cost/models/authors/minimax/minimax-m2.7/endpoints.ts b/packages/cost/models/authors/minimax/minimax-m2.7/endpoints.ts new file mode 100644 index 0000000000..8802f5358c --- /dev/null +++ b/packages/cost/models/authors/minimax/minimax-m2.7/endpoints.ts @@ -0,0 +1,68 @@ +import { ModelProviderName } from "../../../providers"; +import type { ModelProviderConfig } from "../../../types"; +import { MiniMaxM27ModelName } from "./model"; + +export const endpoints = { + "minimax-m2.7:minimax": { + provider: "minimax", + author: "minimax", + providerModelId: "MiniMax-M2.7", + pricing: [ + { + threshold: 0, + input: 0.0000002, // $0.20 per 1M tokens + output: 0.0000011, // $1.10 per 1M tokens + }, + ], + contextLength: 1_000_000, + maxCompletionTokens: 16_384, + supportedParameters: [ + "max_tokens", + "temperature", + "top_p", + "stop", + "stream", + "tools", + "tool_choice", + "response_format", + "frequency_penalty", + "presence_penalty", + ], + ptbEnabled: true, + endpointConfigs: { + "*": {}, + }, + }, + "minimax-m2.7-highspeed:minimax": { + provider: "minimax", + author: "minimax", + providerModelId: "MiniMax-M2.7-highspeed", + pricing: [ + { + threshold: 0, + input: 0.0000001, // $0.10 per 1M tokens + output: 0.00000055, // $0.55 per 1M tokens + }, + ], + contextLength: 1_000_000, + maxCompletionTokens: 16_384, + supportedParameters: [ + "max_tokens", + "temperature", + "top_p", + "stop", + "stream", + "tools", + "tool_choice", + "response_format", + "frequency_penalty", + "presence_penalty", + ], + ptbEnabled: true, + endpointConfigs: { + "*": {}, + }, + }, +} satisfies Partial< + Record<`${MiniMaxM27ModelName}:${ModelProviderName}`, ModelProviderConfig> +>; diff --git a/packages/cost/models/authors/minimax/minimax-m2.7/model.ts b/packages/cost/models/authors/minimax/minimax-m2.7/model.ts new file mode 100644 index 0000000000..2208a6a443 --- /dev/null +++ b/packages/cost/models/authors/minimax/minimax-m2.7/model.ts @@ -0,0 +1,28 @@ +import type { ModelConfig } from "../../../types"; + +export const models = { + "minimax-m2.7": { + name: "MiniMax M2.7", + author: "minimax", + description: + "MiniMax-M2.7 is MiniMax's most capable large language model with 1M token context window. It features advanced reasoning, function calling, and JSON output capabilities, delivering strong performance across coding, mathematical reasoning, and general language tasks.", + contextLength: 1_000_000, + maxOutputTokens: 16_384, + created: "2025-03-01T00:00:00.000Z", + modality: { inputs: ["text"], outputs: ["text"] }, + tokenizer: "MiniMax", + }, + "minimax-m2.7-highspeed": { + name: "MiniMax M2.7 Highspeed", + author: "minimax", + description: + "MiniMax-M2.7-highspeed is an optimized variant of MiniMax-M2.7, offering faster inference speeds while maintaining strong performance. Suitable for latency-sensitive applications with 1M token context support.", + contextLength: 1_000_000, + maxOutputTokens: 16_384, + created: "2025-03-01T00:00:00.000Z", + modality: { inputs: ["text"], outputs: ["text"] }, + tokenizer: "MiniMax", + }, +} satisfies Record; + +export type MiniMaxM27ModelName = keyof typeof models; diff --git a/packages/cost/models/provider-helpers.ts b/packages/cost/models/provider-helpers.ts index ae00f70ee3..7be44200fb 100644 --- a/packages/cost/models/provider-helpers.ts +++ b/packages/cost/models/provider-helpers.ts @@ -62,6 +62,8 @@ export function heliconeProviderToModelProviderName( return "fireworks"; case "CANOPYWAVE": return "canopywave"; + case "MINIMAX": + return "minimax"; // new registry does not have case "LOCAL": case "HELICONE": @@ -159,6 +161,9 @@ export const dbProviderToProvider = ( if (provider === "nebius" || provider === "Nebius") { return "nebius"; } + if (provider === "minimax" || provider === "MiniMax") { + return "minimax"; + } return null; }; diff --git a/packages/cost/models/providers/index.ts b/packages/cost/models/providers/index.ts index 963717d50d..1da0d3fa55 100644 --- a/packages/cost/models/providers/index.ts +++ b/packages/cost/models/providers/index.ts @@ -11,6 +11,7 @@ import { FireworksProvider } from "./fireworks"; import { GoogleProvider } from "./google"; import { GroqProvider } from "./groq"; import { HeliconeProvider } from "./helicone"; +import { MiniMaxProvider } from "./minimax"; import { MistralProvider } from "./mistral"; import { NebiusProvider } from "./nebius"; import { NovitaProvider } from "./novita"; @@ -35,6 +36,7 @@ export const providers = { "google-ai-studio": new GoogleProvider(), groq: new GroqProvider(), helicone: new HeliconeProvider(), + minimax: new MiniMaxProvider(), mistral: new MistralProvider(), nebius: new NebiusProvider(), novita: new NovitaProvider(), @@ -87,6 +89,7 @@ export const ResponsesAPIEnabledProviders: ModelProviderName[] = [ "xai", "baseten", "fireworks", + "minimax", // anthropic and chat completions provider "vertex" diff --git a/packages/cost/models/providers/minimax.ts b/packages/cost/models/providers/minimax.ts new file mode 100644 index 0000000000..7ff7ecd125 --- /dev/null +++ b/packages/cost/models/providers/minimax.ts @@ -0,0 +1,16 @@ +import { BaseProvider } from "./base"; +import type { RequestParams, Endpoint } from "../types"; + +export class MiniMaxProvider extends BaseProvider { + readonly displayName = "MiniMax"; + readonly baseUrl = "https://api.minimax.io"; + readonly auth = "api-key" as const; + readonly pricingPages = ["https://platform.minimaxi.com/document/Price"]; + readonly modelPages = [ + "https://platform.minimaxi.com/document/Models", + ]; + + buildUrl(endpoint: Endpoint, requestParams: RequestParams): string { + return `${this.baseUrl}/v1/chat/completions`; + } +} diff --git a/packages/cost/models/providers/priorities.ts b/packages/cost/models/providers/priorities.ts index 38df67014c..dbaa1ecb48 100644 --- a/packages/cost/models/providers/priorities.ts +++ b/packages/cost/models/providers/priorities.ts @@ -31,6 +31,7 @@ export const PROVIDER_PRIORITIES: Record = { deepseek: 4, fireworks: 4, groq: 4, + minimax: 4, mistral: 4, nebius: 4, novita: 4, diff --git a/packages/cost/models/registry-types.ts b/packages/cost/models/registry-types.ts index 83bd218c62..c2a139c230 100644 --- a/packages/cost/models/registry-types.ts +++ b/packages/cost/models/registry-types.ts @@ -16,6 +16,7 @@ import { alibabaEndpointConfig, alibabaModels } from "./authors/alibaba"; import { metaEndpointConfig, metaModels } from "./authors/meta"; import { zaiEndpointConfig, zaiModels } from "./authors/zai"; import { baiduEndpointConfig, baiduModels } from "./authors/baidu"; +import { minimaxEndpointConfig, minimaxModels } from "./authors/minimax"; // Combine all models for type derivation const allModels = { @@ -28,6 +29,7 @@ const allModels = { ...alibabaModels, ...metaModels, ...baiduModels, + ...minimaxModels, ...zaiModels }; @@ -44,6 +46,7 @@ const modelProviderConfigs = { ...alibabaEndpointConfig, ...metaEndpointConfig, ...baiduEndpointConfig, + ...minimaxEndpointConfig, ...zaiEndpointConfig }; diff --git a/packages/cost/models/registry.ts b/packages/cost/models/registry.ts index 84618d4c46..d0888977b9 100644 --- a/packages/cost/models/registry.ts +++ b/packages/cost/models/registry.ts @@ -30,6 +30,7 @@ import { } from "./authors/moonshotai"; import { alibabaModels, alibabaEndpointConfig } from "./authors/alibaba"; import { deepseekModels, deepseekEndpointConfig } from "./authors/deepseek"; +import { minimaxModels, minimaxEndpointConfig } from "./authors/minimax"; import { mistralModels, mistralEndpointConfig } from "./authors/mistral"; import { zaiModels, zaiEndpointConfig } from "./authors/zai"; import { baiduModels, baiduEndpointConfig } from "./authors/baidu"; @@ -48,6 +49,7 @@ const allModels = { ...moonshotaiModels, ...alibabaModels, ...deepseekModels, + ...minimaxModels, ...mistralModels, ...zaiModels, ...baiduModels, @@ -64,6 +66,7 @@ const modelProviderConfigs = { ...moonshotaiEndpointConfig, ...alibabaEndpointConfig, ...deepseekEndpointConfig, + ...minimaxEndpointConfig, ...mistralEndpointConfig, ...zaiEndpointConfig, ...baiduEndpointConfig, diff --git a/packages/cost/models/types.ts b/packages/cost/models/types.ts index f15dd60799..347847aee0 100644 --- a/packages/cost/models/types.ts +++ b/packages/cost/models/types.ts @@ -27,6 +27,7 @@ export const AUTHORS = [ "alibaba", "zai", "baidu", + "minimax", ] as const; export type AuthorName = (typeof AUTHORS)[number] | "passthrough"; @@ -56,7 +57,8 @@ export type Tokenizer = | "Grok" | "Tekken" | "Zai" - | "Baidu"; + | "Baidu" + | "MiniMax"; export type StandardParameter = | "max_tokens" diff --git a/packages/cost/providers/mappings.ts b/packages/cost/providers/mappings.ts index 7e856b54c5..4636eabb29 100644 --- a/packages/cost/providers/mappings.ts +++ b/packages/cost/providers/mappings.ts @@ -94,6 +94,9 @@ const cerebras = /^https:\/\/api\.cerebras\.ai/; // https://inference.canopywave.io const canopywave = /^https:\/\/inference\.canopywave\.io/; +// https://api.minimax.io +const minimax = /^https:\/\/api\.minimax\.io/; + export const providersNames = [ "OPENAI", "ANTHROPIC", @@ -132,6 +135,7 @@ export const providersNames = [ "CEREBRAS", "BASETEN", "CANOPYWAVE", + "MINIMAX", ] as const; export type ProviderName = (typeof providersNames)[number]; @@ -325,6 +329,11 @@ export const providers: { pattern: canopywave, provider: "CANOPYWAVE", costs: [], + }, + { + pattern: minimax, + provider: "MINIMAX", + costs: [], } ]; diff --git a/packages/cost/usage/getUsageProcessor.ts b/packages/cost/usage/getUsageProcessor.ts index 3dc612abf9..fe056daa36 100644 --- a/packages/cost/usage/getUsageProcessor.ts +++ b/packages/cost/usage/getUsageProcessor.ts @@ -26,6 +26,7 @@ export function getUsageProcessor( case "novita": case "fireworks": case "cerebras": + case "minimax": case "perplexity": return new OpenAIUsageProcessor(); case "anthropic":