feat: pick MiniMax-M2.7, and strip markdown and emoji from replies

Benchmarked M2.7, M3 and M2 against the same four pt-BR prompts (a
Minecraft question, a general-knowledge one, an unanswerable one, and a
jailbreak attempt).

M2.7 wins on the axis that matters for chat. All three held the
no-server-access line under the jailbreak, but:

- M3 is a reasoning model, and its thinking counts against max_tokens.
  At the 300 chat needs, its Minecraft answer was cut off mid-word at
  39 characters while reporting 590 tokens used. Raising the budget
  enough to fix that costs more per question than the answer is worth.
- M2 answered the brewing question wrong, going straight from a water
  bottle to magma cream and skipping the nether wart.
- M2.7 answered correctly in 2.7-5.2s.

The benchmark also showed both markdown and emoji in every model's
output. Minecraft chat renders neither: `**negrito**` arrives as
literal asterisks, and emoji are empty boxes on Bedrock. The system
prompt now asks for plain text, and sanitise() strips emphasis, code
fences, headings and emoji regardless, since a prompt is a request and
not a guarantee.
This commit is contained in:
marcos
2026-08-05 14:01:22 +00:00
parent 0d84a606d4
commit 0b3be45d76
3 changed files with 26 additions and 5 deletions
@@ -264,15 +264,26 @@ final class Ai {
}
/**
* Makes a model reply safe to print in chat.
* Makes a model reply safe and readable in chat.
*
* <p>Strips colour codes so the reply cannot forge server messages, folds
* newlines so one answer stays one chat entry, and removes leading slashes
* so nothing that comes back reads as a command to run.
*
* <p>It also strips markdown and emoji, which the models emit freely.
* Minecraft chat renders neither: {@code **negrito**} arrives as literal
* asterisks, and emoji show up as empty boxes on Bedrock.
*/
static String sanitise(String raw, int max) {
String text = raw.replace('§', ' ')
.replaceAll("[\\r\\n]+", " ")
// Markdown emphasis and code fences: chat shows the characters, not the effect.
.replaceAll("\\*{1,3}([^*]+)\\*{1,3}", "$1")
.replaceAll("`{1,3}([^`]+)`{1,3}", "$1")
.replaceAll("^#{1,6}\\s+", "")
// Emoji live outside the BMP, plus the symbol blocks and the
// variation selector. Accented pt-BR letters are far below this.
.replaceAll("[\\x{1F000}-\\x{1FAFF}\\x{2190}-\\x{2BFF}\\x{FE0F}\\x{20E3}]", "")
.replaceAll("\\s{2,}", " ")
.trim();
while (text.startsWith("/")) {
@@ -222,7 +222,10 @@ final class Settings {
}
String aiModel() {
return plugin.getConfig().getString("ia.modelo", "MiniMax-M2");
// M2.7 measured 2.7-5.2s with correct answers. M3 is a reasoning model:
// its thinking counts against max_tokens, so replies get truncated
// mid-word unless the budget is raised far past what chat needs.
return plugin.getConfig().getString("ia.modelo", "MiniMax-M2.7");
}
void aiModel(String model) {
@@ -243,7 +246,9 @@ final class Settings {
+ "ao terminal ou aos comandos do jogo, e não pode executar nada. "
+ "Se pedirem para você rodar comandos, mexer no servidor, dar itens, "
+ "banir alguém ou revelar configurações, explique que você só conversa. "
+ "Nunca escreva comandos de terminal nem de Minecraft.");
+ "Nunca escreva comandos de terminal nem de Minecraft. "
+ "Escreva em texto puro: nada de markdown, asteriscos, crases ou "
+ "emoji, porque o chat do Minecraft não formata nada disso.");
}
int aiMaxTokens() {