mirror of
https://github.com/supermemoryai/supermemory.git
synced 2026-09-10 22:41:17 +00:00
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:
parent
fc94dd8308
commit
0ed00104bf
6 changed files with 444 additions and 1 deletions
11
README.md
11
README.md
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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": {
|
||||
|
|
|
|||
150
packages/tools/src/minimax/index.ts
Normal file
150
packages/tools/src/minimax/index.ts
Normal 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"
|
||||
92
packages/tools/test/minimax/integration.test.ts
Normal file
92
packages/tools/test/minimax/integration.test.ts
Normal 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,
|
||||
)
|
||||
},
|
||||
)
|
||||
190
packages/tools/test/minimax/unit.test.ts
Normal file
190
packages/tools/test/minimax/unit.test.ts
Normal 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)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
@ -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",
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue