feat: add MiniMax provider integration

- Add @supermemory/tools/minimax export for MiniMax OpenAI-compatible API
- Include withSupermemory() wrapper, clampTemperature(), model constants
- Re-export all OpenAI memory tools for use with MiniMax clients
- Add MiniMax to README framework integrations section
- Add 19 unit tests + 3 integration tests
This commit is contained in:
PR Bot 2026-03-24 14:38:43 +08:00
parent fc94dd8308
commit 0ed00104bf
6 changed files with 444 additions and 1 deletions

View file

@ -233,12 +233,21 @@ Drop-in wrappers for every major AI framework:
import { withSupermemory } from "@supermemory/tools/ai-sdk";
const model = withSupermemory(openai("gpt-4o"), "user_123");
// MiniMax (OpenAI-compatible)
import OpenAI from "openai";
import { withSupermemory } from "@supermemory/tools/minimax";
const minimax = new OpenAI({
apiKey: process.env.MINIMAX_API_KEY,
baseURL: "https://api.minimax.io/v1",
});
const client = withSupermemory(minimax, "user_123", { mode: "full" });
// Mastra
import { withSupermemory } from "@supermemory/tools/mastra";
const agent = new Agent(withSupermemory(config, "user-123", { mode: "full" }));
```
**Vercel AI SDK** · **LangChain** · **LangGraph** · **OpenAI Agents SDK** · **Mastra** · **Agno** · **Claude Memory Tool** · **n8n**
**Vercel AI SDK** · **LangChain** · **LangGraph** · **OpenAI Agents SDK** · **MiniMax** · **Mastra** · **Agno** · **Claude Memory Tool** · **n8n**
### Search modes

View file

@ -45,6 +45,7 @@
"./claude-memory": "./dist/claude-memory.js",
"./mastra": "./dist/mastra.js",
"./openai": "./dist/openai/index.js",
"./minimax": "./dist/minimax/index.js",
"./package.json": "./package.json"
},
"repository": {

View file

@ -0,0 +1,150 @@
import type OpenAI from "openai"
import {
createOpenAIMiddleware,
type OpenAIMiddlewareOptions,
} from "../openai/middleware"
/**
* MiniMax model definitions.
*
* MiniMax provides OpenAI-compatible chat models via `https://api.minimax.io/v1`.
*/
export const MINIMAX_MODELS = [
{ id: "MiniMax-M2.7", name: "MiniMax M2.7" },
{ id: "MiniMax-M2.7-highspeed", name: "MiniMax M2.7 Highspeed" },
] as const
export type MiniMaxModelId = (typeof MINIMAX_MODELS)[number]["id"]
/** Default MiniMax API base URL (international). */
export const MINIMAX_BASE_URL = "https://api.minimax.io/v1"
export interface MiniMaxSupermemoryOptions extends OpenAIMiddlewareOptions {
/**
* MiniMax API key. Falls back to `process.env.MINIMAX_API_KEY`.
*/
minimaxApiKey?: string
/**
* MiniMax API base URL. Defaults to `https://api.minimax.io/v1`.
*/
minimaxBaseUrl?: string
}
/**
* Clamps temperature to MiniMax's accepted range (0, 1.0].
* MiniMax does not accept temperature = 0; the minimum is a small positive value.
*/
export function clampTemperature(temperature?: number): number {
if (temperature === undefined || temperature === null) return 1.0
if (temperature <= 0) return 0.01
if (temperature > 1) return 1.0
return temperature
}
/**
* Creates an OpenAI client pre-configured for MiniMax's API and wraps it with
* SuperMemory middleware to automatically inject relevant memories.
*
* This is a convenience wrapper that combines MiniMax client creation with
* SuperMemory's memory middleware, so you get persistent memory out of the box
* when using MiniMax models.
*
* @param openaiClient - An OpenAI client instance configured with MiniMax's base URL and API key.
* You can create one like:
* ```typescript
* import OpenAI from "openai"
* const client = new OpenAI({
* apiKey: process.env.MINIMAX_API_KEY,
* baseURL: "https://api.minimax.io/v1",
* })
* ```
* @param containerTag - The container tag/identifier for memory search (e.g., user ID, project ID)
* @param options - Optional configuration options for the middleware
*
* @returns An OpenAI client with SuperMemory middleware injected for both Chat Completions and Responses APIs
*
* @example
* ```typescript
* import OpenAI from "openai"
* import { withSupermemory } from "@supermemory/tools/minimax"
*
* const minimax = new OpenAI({
* apiKey: process.env.MINIMAX_API_KEY,
* baseURL: "https://api.minimax.io/v1",
* })
*
* const client = withSupermemory(minimax, "user-123", {
* mode: "full",
* addMemory: "always",
* })
*
* const response = await client.chat.completions.create({
* model: "MiniMax-M2.7",
* messages: [{ role: "user", content: "What's my favorite color?" }],
* temperature: 0.7,
* })
* ```
*
* @throws {Error} When SUPERMEMORY_API_KEY environment variable is not set
*/
export function withSupermemory(
openaiClient: OpenAI,
containerTag: string,
options?: OpenAIMiddlewareOptions,
) {
if (!process.env.SUPERMEMORY_API_KEY) {
throw new Error("SUPERMEMORY_API_KEY is not set")
}
const conversationId = options?.conversationId
const verbose = options?.verbose ?? false
const mode = options?.mode ?? "profile"
const addMemory = options?.addMemory ?? "never"
const baseUrl = options?.baseUrl
const openaiWithSupermemory = createOpenAIMiddleware(
openaiClient,
containerTag,
{
conversationId,
verbose,
mode,
addMemory,
baseUrl,
},
)
return openaiWithSupermemory
}
export type { OpenAIMiddlewareOptions }
export type {
MemorySearchResult,
MemoryAddResult,
ProfileResult,
DocumentListResult,
DocumentDeleteResult,
DocumentAddResult,
MemoryForgetResult,
} from "../openai/tools"
export {
createSearchMemoriesFunction,
createAddMemoryFunction,
createGetProfileFunction,
createDocumentListFunction,
createDocumentDeleteFunction,
createDocumentAddFunction,
createMemoryForgetFunction,
supermemoryTools,
getToolDefinitions,
createToolCallExecutor,
createToolCallsExecutor,
createSearchMemoriesTool,
createAddMemoryTool,
createGetProfileTool,
createDocumentListTool,
createDocumentDeleteTool,
createDocumentAddTool,
createMemoryForgetTool,
memoryToolSchemas,
} from "../openai/tools"

View file

@ -0,0 +1,92 @@
/**
* Integration tests for the MiniMax + Supermemory integration.
*
* These tests verify that MiniMax models work correctly through the
* OpenAI-compatible API when wrapped with Supermemory memory middleware.
*
* Requires:
* - MINIMAX_API_KEY: MiniMax API key
* - SUPERMEMORY_API_KEY: Supermemory API key
*/
import { describe, it, expect, vi } from "vitest"
import OpenAI from "openai"
import {
withSupermemory,
MINIMAX_BASE_URL,
clampTemperature,
} from "../../src/minimax"
import "dotenv/config"
const MINIMAX_API_KEY = process.env.MINIMAX_API_KEY || ""
const SUPERMEMORY_API_KEY = process.env.SUPERMEMORY_API_KEY || ""
const shouldRunIntegration = !!MINIMAX_API_KEY && !!SUPERMEMORY_API_KEY
describe.skipIf(!shouldRunIntegration)(
"Integration: MiniMax + Supermemory",
() => {
const createMiniMaxClient = () =>
new OpenAI({
apiKey: MINIMAX_API_KEY,
baseURL: MINIMAX_BASE_URL,
})
it(
"should complete a basic chat via MiniMax API",
async () => {
const client = createMiniMaxClient()
const response = await client.chat.completions.create({
model: "MiniMax-M2.7",
messages: [
{ role: "user", content: 'Say exactly "hello minimax"' },
],
max_tokens: 20,
temperature: clampTemperature(0.7),
})
expect(response.choices).toBeDefined()
expect(response.choices.length).toBeGreaterThan(0)
expect(response.choices[0]?.message?.content).toBeTruthy()
},
30000,
)
it(
"should work with MiniMax-M2.7-highspeed model",
async () => {
const client = createMiniMaxClient()
const response = await client.chat.completions.create({
model: "MiniMax-M2.7-highspeed",
messages: [{ role: "user", content: "What is 2+2?" }],
max_tokens: 20,
temperature: clampTemperature(0.5),
})
expect(response.choices).toBeDefined()
expect(response.choices[0]?.message?.content).toBeTruthy()
},
30000,
)
it(
"should work with supermemory middleware wrapping MiniMax client",
async () => {
const client = createMiniMaxClient()
const wrapped = withSupermemory(
client,
"minimax-integration-test",
{
mode: "profile",
},
)
// The wrapped client should still have the chat API
expect(wrapped.chat.completions.create).toBeDefined()
},
10000,
)
},
)

View file

@ -0,0 +1,190 @@
/**
* Unit tests for the MiniMax integration module
*/
import { describe, it, expect, beforeEach, vi, afterEach } from "vitest"
import {
withSupermemory,
clampTemperature,
MINIMAX_MODELS,
MINIMAX_BASE_URL,
supermemoryTools,
getToolDefinitions,
memoryToolSchemas,
} from "../../src/minimax"
import type OpenAI from "openai"
import "dotenv/config"
// Mock OpenAI client
const createMockOpenAIClient = (): OpenAI => {
const originalCreate = vi.fn()
const responsesCreate = vi.fn()
return {
chat: {
completions: {
create: originalCreate,
},
},
responses: {
create: responsesCreate,
},
} as unknown as OpenAI
}
describe("Unit: MiniMax integration", () => {
let originalEnv: string | undefined
let originalSupermemoryKey: string | undefined
beforeEach(() => {
originalEnv = process.env.MINIMAX_API_KEY
originalSupermemoryKey = process.env.SUPERMEMORY_API_KEY
vi.clearAllMocks()
})
afterEach(() => {
if (originalEnv) {
process.env.MINIMAX_API_KEY = originalEnv
} else {
delete process.env.MINIMAX_API_KEY
}
if (originalSupermemoryKey) {
process.env.SUPERMEMORY_API_KEY = originalSupermemoryKey
} else {
delete process.env.SUPERMEMORY_API_KEY
}
})
describe("MINIMAX_MODELS", () => {
it("should contain MiniMax-M2.7", () => {
expect(MINIMAX_MODELS.some((m) => m.id === "MiniMax-M2.7")).toBe(true)
})
it("should contain MiniMax-M2.7-highspeed", () => {
expect(
MINIMAX_MODELS.some((m) => m.id === "MiniMax-M2.7-highspeed"),
).toBe(true)
})
it("should have exactly 2 models", () => {
expect(MINIMAX_MODELS).toHaveLength(2)
})
})
describe("MINIMAX_BASE_URL", () => {
it("should use api.minimax.io", () => {
expect(MINIMAX_BASE_URL).toBe("https://api.minimax.io/v1")
})
it("should not use api.minimax.chat", () => {
expect(MINIMAX_BASE_URL).not.toContain("minimax.chat")
})
})
describe("clampTemperature", () => {
it("should return 1.0 for undefined", () => {
expect(clampTemperature(undefined)).toBe(1.0)
})
it("should return 1.0 for null", () => {
expect(clampTemperature(null as unknown as number)).toBe(1.0)
})
it("should clamp 0 to 0.01", () => {
expect(clampTemperature(0)).toBe(0.01)
})
it("should clamp negative values to 0.01", () => {
expect(clampTemperature(-0.5)).toBe(0.01)
})
it("should clamp values above 1.0 to 1.0", () => {
expect(clampTemperature(1.5)).toBe(1.0)
expect(clampTemperature(2.0)).toBe(1.0)
})
it("should pass through valid values", () => {
expect(clampTemperature(0.5)).toBe(0.5)
expect(clampTemperature(0.7)).toBe(0.7)
expect(clampTemperature(1.0)).toBe(1.0)
expect(clampTemperature(0.01)).toBe(0.01)
})
})
describe("withSupermemory", () => {
it("should throw error if SUPERMEMORY_API_KEY is not set", () => {
delete process.env.SUPERMEMORY_API_KEY
const mockClient = createMockOpenAIClient()
expect(() => {
withSupermemory(mockClient, "test-container")
}).toThrow("SUPERMEMORY_API_KEY is not set")
})
it("should successfully wrap OpenAI client with valid keys", () => {
process.env.SUPERMEMORY_API_KEY = "test-supermemory-key"
const mockClient = createMockOpenAIClient()
const wrapped = withSupermemory(mockClient, "test-container")
expect(wrapped).toBeDefined()
expect(wrapped.chat).toBeDefined()
expect(wrapped.chat.completions).toBeDefined()
expect(wrapped.chat.completions.create).toBeDefined()
})
it("should accept all middleware options", () => {
process.env.SUPERMEMORY_API_KEY = "test-supermemory-key"
const mockClient = createMockOpenAIClient()
expect(() => {
withSupermemory(mockClient, "test-container", {
conversationId: "conv-123",
verbose: true,
mode: "full",
addMemory: "always",
baseUrl: "https://custom.supermemory.ai",
})
}).not.toThrow()
})
})
describe("Tool re-exports", () => {
it("should export supermemoryTools function", () => {
expect(typeof supermemoryTools).toBe("function")
})
it("should export getToolDefinitions function", () => {
expect(typeof getToolDefinitions).toBe("function")
})
it("should export memoryToolSchemas", () => {
expect(memoryToolSchemas).toBeDefined()
expect(memoryToolSchemas.searchMemories).toBeDefined()
expect(memoryToolSchemas.addMemory).toBeDefined()
expect(memoryToolSchemas.getProfile).toBeDefined()
expect(memoryToolSchemas.documentList).toBeDefined()
expect(memoryToolSchemas.documentDelete).toBeDefined()
expect(memoryToolSchemas.documentAdd).toBeDefined()
expect(memoryToolSchemas.memoryForget).toBeDefined()
})
it("should create tools with API key", () => {
const tools = supermemoryTools("test-api-key")
expect(tools.searchMemories).toBeDefined()
expect(tools.addMemory).toBeDefined()
expect(tools.getProfile).toBeDefined()
expect(tools.documentList).toBeDefined()
expect(tools.documentDelete).toBeDefined()
expect(tools.documentAdd).toBeDefined()
expect(tools.memoryForget).toBeDefined()
})
it("should return 7 tool definitions", () => {
const definitions = getToolDefinitions()
expect(definitions).toHaveLength(7)
expect(definitions.every((d) => d.type === "function")).toBe(true)
})
})
})

View file

@ -6,6 +6,7 @@ export default defineConfig({
"src/ai-sdk.ts",
"src/claude-memory.ts",
"src/openai/index.ts",
"src/minimax/index.ts",
"src/mastra.ts",
],
format: "esm",