feat: add MiniMax as chatbot provider integration#2480
feat: add MiniMax as chatbot provider integration#2480octo-patch wants to merge 1 commit intoEvolutionAPI:mainfrom
Conversation
Add MiniMax AI as a new chatbot provider alongside OpenAI, Dify, Flowise, and others. MiniMax uses the OpenAI-compatible API at api.minimax.io/v1 and supports M2.5 and M2.5-highspeed models for chat completions. Changes: - New minimax chatbot integration (service, controller, router, DTOs, schemas) - Prisma schema models for MinimaxCreds, MinimaxBot, MinimaxSetting (both PostgreSQL and MySQL) - Environment configuration (MINIMAX_ENABLED) - Registration in chatbot router, controller, and server module - Think tag stripping for MiniMax M2.5 responses - 35 unit and integration tests - README documentation
Reviewer's GuideAdds a new MiniMax chatbot provider integration wired through the existing chatbot integration architecture, including service/controller/router layers, Prisma models, configuration flag, validation schemas, DTOs, and tests for conversation handling, think-tag stripping, and credentials/settings management. Sequence diagram for MiniMax chat message processing and think tag strippingsequenceDiagram
actor User
participant WhatsAppClient as WhatsApp_instance
participant ChatbotController
participant MinimaxController
participant MinimaxService
participant PrismaRepository
participant MiniMaxAPI as MiniMax_API
User->>WhatsAppClient: send message content
WhatsAppClient->>ChatbotController: inbound message event
ChatbotController->>MinimaxController: emit(eventData)
MinimaxController->>PrismaRepository: find minimaxBot and settings
MinimaxController->>PrismaRepository: find integrationSession
MinimaxController->>MinimaxService: process(instance, remoteJid, minimaxBot, session, settings, content, pushName, msg)
alt keyword_finish_matched
MinimaxService->>PrismaRepository: update or delete integrationSession
MinimaxService->>MiniMaxAPI: sendTelemetry /minimax/session/finish
MinimaxService-->>MinimaxController: return
else new_session
MinimaxService->>PrismaRepository: createNewSession
MinimaxService->>MinimaxService: initNewSession(..., content)
MinimaxService->>MiniMaxAPI: sendTelemetry /minimax/session/start
MinimaxService-->>MinimaxController: return
else existing_session
MinimaxService->>PrismaRepository: ensure minimaxCreds
MinimaxService->>MinimaxService: sendMessageToBot(...)
MinimaxService->>PrismaRepository: load conversation history
MinimaxService->>MiniMaxAPI: chat.completions.create(model, messages)
MiniMaxAPI-->>MinimaxService: completion with content including <think> tags
MinimaxService->>MinimaxService: strip <think>...</think> from content
MinimaxService->>PrismaRepository: update conversation history in session.context
MinimaxService-->>WhatsAppClient: sendMessageWhatsApp(cleaned_content)
MinimaxService->>PrismaRepository: update session status opened
end
ER diagram for MiniMax Prisma models and relationserDiagram
Instance {
string id PK
string name
}
MinimaxCreds {
string id PK
string name
string apiKey
string instanceId FK
}
MinimaxBot {
string id PK
boolean enabled
string description
string model
json systemMessages
json assistantMessages
json userMessages
int maxTokens
string minimaxCredsId FK
string instanceId FK
}
MinimaxSetting {
string id PK
int expire
string keywordFinish
int delayMessage
string unknownMessage
boolean listeningFromMe
boolean stopBotFromMe
boolean keepOpen
int debounceTime
json ignoreJids
boolean splitMessages
float timePerChar
string minimaxCredsId FK
string minimaxIdFallback FK
string instanceId FK
}
IntegrationSession {
string id PK
string remoteJid
string botId FK
string status
json context
}
Instance ||--o{ MinimaxCreds : has
Instance ||--o{ MinimaxBot : has
Instance ||--o{ MinimaxSetting : has
MinimaxCreds ||--o{ MinimaxBot : used_by
MinimaxCreds ||--o{ MinimaxSetting : used_by
MinimaxBot ||--o{ IntegrationSession : has
MinimaxBot ||--|| MinimaxSetting : fallback_for
MinimaxSetting }o--|| MinimaxBot : minimaxIdFallback
Class diagram for MiniMax chatbot provider integrationclassDiagram
class BaseChatbotService {
}
class MinimaxService {
- OpenAI client
+ MinimaxService(waMonitor, prismaRepository, configService)
+ process(instance, remoteJid, minimaxBot, session, settings, content, pushName, msg) void
- initClient(apiKey) OpenAI
- getBotType() string
- sendMessageToBot(instance, session, settings, minimaxBot, remoteJid, pushName, content, msg) void
- processChatCompletionMessage(instance, minimaxBot, remoteJid, content) string
}
class BaseChatbotController {
}
class MinimaxController {
- MinimaxService minimaxService
- PrismaRepository prismaRepository
- WAMonitoringService waMonitor
- Logger logger
- boolean integrationEnabled
- any botRepository
- any settingsRepository
- any sessionRepository
- any credsRepository
- map~string,object~ userMessageDebounce
+ MinimaxController(minimaxService, prismaRepository, waMonitor)
+ createBot(instance, data) any
+ processBot(instance, remoteJid, bot, session, settings, content, pushName, msg) void
+ createMinimaxCreds(instance, data) any
+ findMinimaxCreds(instance) any
+ deleteCreds(instance, minimaxCredsId) any
+ settings(instance, data) any
+ getModels(instance) any
- getFallbackBotId(settings) string
- getFallbackFieldName() string
- getIntegrationType() string
- getAdditionalBotData(data) map~string,any~
- getAdditionalUpdateFields(data) map~string,any~
- validateNoDuplicatesOnUpdate(botId, instanceId, data) void
}
class RouterBroker {
}
class MinimaxRouter {
+ MinimaxRouter(guards)
+ Router router
}
class MinimaxCredsDto {
string name
string apiKey
}
class BaseChatbotDto {
boolean enabled
string description
string triggerType
string triggerOperator
string triggerValue
integer expire
string keywordFinish
integer delayMessage
string unknownMessage
boolean listeningFromMe
boolean stopBotFromMe
boolean keepOpen
integer debounceTime
string[] ignoreJids
}
class MinimaxDto {
string minimaxCredsId
string model
string[] systemMessages
string[] assistantMessages
string[] userMessages
integer maxTokens
}
class BaseChatbotSettingDto {
string minimaxCredsId
integer expire
string keywordFinish
integer delayMessage
string unknownMessage
boolean listeningFromMe
boolean stopBotFromMe
boolean keepOpen
integer debounceTime
string[] ignoreJids
}
class MinimaxSettingDto {
string minimaxCredsId
string minimaxIdFallback
}
class MinimaxBot {
string id
boolean enabled
string description
string model
any systemMessages
any assistantMessages
any userMessages
integer maxTokens
string minimaxCredsId
string instanceId
}
class MinimaxSetting {
string id
integer expire
string keywordFinish
integer delayMessage
string unknownMessage
boolean listeningFromMe
boolean stopBotFromMe
boolean keepOpen
integer debounceTime
any ignoreJids
boolean splitMessages
number timePerChar
string minimaxCredsId
string minimaxIdFallback
string instanceId
}
class MinimaxCreds {
string id
string name
string apiKey
string instanceId
}
BaseChatbotService <|-- MinimaxService
BaseChatbotController <|-- MinimaxController
RouterBroker <|-- MinimaxRouter
MinimaxDto --|> BaseChatbotDto
MinimaxSettingDto --|> BaseChatbotSettingDto
MinimaxController --> MinimaxService
MinimaxController --> MinimaxBot
MinimaxController --> MinimaxSetting
MinimaxController --> MinimaxCreds
MinimaxService --> MinimaxBot
MinimaxService --> MinimaxSetting
MinimaxService --> MinimaxCreds
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
Hey - I've found 3 issues, and left some high level feedback:
- In
MinimaxController.settings, the mapping between DTO fields and Prisma fields looks inconsistent (minimaxIdFallbackis assigned fromdata.fallbackIdand you returnfallbackIdwhile the DTO/schema exposeminimaxIdFallback), which likely makes the fallback bot ID impossible to set or read correctly; consider aligning the property names end-to-end (DTO, schema, settingsData, and response). - In
MinimaxService.processChatCompletionMessage,completions.choices[0].message.contentis assumed to be a string but the OpenAI SDK can return structured content; it would be safer to normalize this value (handlenulland array-of-parts) before usingreplaceand saving it into history. - Error handling across the new MiniMax code often assumes
errorhas a.message(e.g.,error.message || JSON.stringify(error)); to avoid runtime issues and improve observability, consider narrowingerrortoError(or checkinginstanceof Error) before accessing.messageand falling back cleanly otherwise.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- In `MinimaxController.settings`, the mapping between DTO fields and Prisma fields looks inconsistent (`minimaxIdFallback` is assigned from `data.fallbackId` and you return `fallbackId` while the DTO/schema expose `minimaxIdFallback`), which likely makes the fallback bot ID impossible to set or read correctly; consider aligning the property names end-to-end (DTO, schema, settingsData, and response).
- In `MinimaxService.processChatCompletionMessage`, `completions.choices[0].message.content` is assumed to be a string but the OpenAI SDK can return structured content; it would be safer to normalize this value (handle `null` and array-of-parts) before using `replace` and saving it into history.
- Error handling across the new MiniMax code often assumes `error` has a `.message` (e.g., `error.message || JSON.stringify(error)`); to avoid runtime issues and improve observability, consider narrowing `error` to `Error` (or checking `instanceof Error`) before accessing `.message` and falling back cleanly otherwise.
## Individual Comments
### Comment 1
<location path="src/api/integrations/chatbot/minimax/services/minimax.service.ts" line_range="105-114" />
<code_context>
+ this.initClient(creds.apiKey);
+
+ // Handle keyword finish
+ const keywordFinish = settings?.keywordFinish || '';
+ const normalizedContent = content.toLowerCase().trim();
+ if (keywordFinish.length > 0 && normalizedContent === keywordFinish.toLowerCase()) {
+ if (settings?.keepOpen) {
+ await this.prismaRepository.integrationSession.update({
+ where: { id: session.id },
+ data: { status: 'closed' },
+ });
+ } else {
+ await this.prismaRepository.integrationSession.delete({
+ where: { id: session.id },
+ });
</code_context>
<issue_to_address>
**issue (bug_risk):** Guard against `session` being null/undefined when handling keyword-based session finish.
In this branch you access `session.id` before checking `!session`. On a first message (or when loading the session fails), `session` can be `undefined`, causing a runtime error. Please either return early when `!session` or move the `!session` handling before any use of `session.id`.
</issue_to_address>
### Comment 2
<location path="src/api/integrations/chatbot/minimax/controllers/minimax.controller.ts" line_range="296" />
<code_context>
+ ignoreJids: data.ignoreJids,
+ splitMessages: data.splitMessages,
+ timePerChar: data.timePerChar,
+ minimaxIdFallback: data.fallbackId,
+ MinimaxCreds: data.minimaxCredsId
+ ? {
</code_context>
<issue_to_address>
**issue (bug_risk):** Fallback ID field name in settings doesn’t match DTO/schema, so it will never be persisted.
Here you read `data.fallbackId`, but both `MinimaxSettingDto` and `minimaxSettingSchema` use `minimaxIdFallback`. As a result, the fallback ID will always persist as `undefined`. Please either read from `data.minimaxIdFallback` or rename the DTO/schema field to `fallbackId` so the value is stored correctly.
</issue_to_address>
### Comment 3
<location path="README.md" line_range="73-74" />
<code_context>
- Integrate your Evolution API with OpenAI for AI capabilities, including audio-to-text conversion, available across all Evolution integrations.
+- [MiniMax](https://www.minimaxi.com/):
+ - Integrate your Evolution API with MiniMax AI for chat completion capabilities using MiniMax M2.5 and M2.5-highspeed models via OpenAI-compatible API.
+
- Amazon S3 / Minio:
</code_context>
<issue_to_address>
**nitpick (typo):** Consider adding the article "an" before "OpenAI-compatible API" for grammatical correctness.
You could instead write: "…models via an OpenAI-compatible API." to fix the grammar while preserving the meaning.
```suggestion
- [MiniMax](https://www.minimaxi.com/):
- Integrate your Evolution API with MiniMax AI for chat completion capabilities using MiniMax M2.5 and M2.5-highspeed models via an OpenAI-compatible API.
```
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
| const keywordFinish = settings?.keywordFinish || ''; | ||
| const normalizedContent = content.toLowerCase().trim(); | ||
| if (keywordFinish.length > 0 && normalizedContent === keywordFinish.toLowerCase()) { | ||
| if (settings?.keepOpen) { | ||
| await this.prismaRepository.integrationSession.update({ | ||
| where: { id: session.id }, | ||
| data: { status: 'closed' }, | ||
| }); | ||
| } else { | ||
| await this.prismaRepository.integrationSession.delete({ |
There was a problem hiding this comment.
issue (bug_risk): Guard against session being null/undefined when handling keyword-based session finish.
In this branch you access session.id before checking !session. On a first message (or when loading the session fails), session can be undefined, causing a runtime error. Please either return early when !session or move the !session handling before any use of session.id.
| ignoreJids: data.ignoreJids, | ||
| splitMessages: data.splitMessages, | ||
| timePerChar: data.timePerChar, | ||
| minimaxIdFallback: data.fallbackId, |
There was a problem hiding this comment.
issue (bug_risk): Fallback ID field name in settings doesn’t match DTO/schema, so it will never be persisted.
Here you read data.fallbackId, but both MinimaxSettingDto and minimaxSettingSchema use minimaxIdFallback. As a result, the fallback ID will always persist as undefined. Please either read from data.minimaxIdFallback or rename the DTO/schema field to fallbackId so the value is stored correctly.
| - [MiniMax](https://www.minimaxi.com/): | ||
| - Integrate your Evolution API with MiniMax AI for chat completion capabilities using MiniMax M2.5 and M2.5-highspeed models via OpenAI-compatible API. |
There was a problem hiding this comment.
nitpick (typo): Consider adding the article "an" before "OpenAI-compatible API" for grammatical correctness.
You could instead write: "…models via an OpenAI-compatible API." to fix the grammar while preserving the meaning.
| - [MiniMax](https://www.minimaxi.com/): | |
| - Integrate your Evolution API with MiniMax AI for chat completion capabilities using MiniMax M2.5 and M2.5-highspeed models via OpenAI-compatible API. | |
| - [MiniMax](https://www.minimaxi.com/): | |
| - Integrate your Evolution API with MiniMax AI for chat completion capabilities using MiniMax M2.5 and M2.5-highspeed models via an OpenAI-compatible API. |
Summary
https://api.minimax.io/v1) via the OpenAI SDK<think>...</think>tags from MiniMax M2.5 reasoning model responsesChanges
src/api/integrations/chatbot/minimax/(controller, service, router, DTO, schema)MinimaxCreds,MinimaxBot,MinimaxSettingmodels (both PostgreSQL and MySQL)MINIMAX_ENABLEDtoggleArchitecture
Follows the same pattern as existing chatbot providers:
MinimaxServiceextendsBaseChatbotService<MinimaxBot, MinimaxSetting>MinimaxControllerextendsBaseChatbotController<MinimaxBot, MinimaxDto>MinimaxRouterextendsRouterBrokerwith full CRUD + credentials + settings + sessions endpointsTest plan
npx jest test/minimax.test.ts)npm run build)MiniMax API
https://api.minimax.io/v1MiniMax-M2.5,MiniMax-M2.5-highspeed(204K context)Summary by Sourcery
Add MiniMax as a new chatbot provider integration using an OpenAI-compatible API, including full CRUD endpoints, session handling, and configuration toggles.
New Features:
Enhancements:
Documentation:
Tests: