fix: Ai review fixes — quit-race, token overflow, comment + nits
- Guard conversations.remember() on asker==null: a PlayerQuitEvent forgets the history (carry-forward #6), and re-adding here after the quit would resurrect it. lastAnswer stays regardless so /ia corrigir can still correct the last answer. - Saturate the retry token ceiling: max_tokens near Integer.MAX_VALUE would overflow to a negative budget sent to the API. - Tighten the constructor comment: aiUrl/aiWikiChars/aiMemoryExchanges/ aiMemoryMinutes are baked; everything else (aiProfile, aiModel, aiMaxTokens, aiTemperature, aiInstructions, aiServerContext) is read live, not just aiProfile. - Drop unused import java.util.List; add trailing newline.
This commit is contained in:
@@ -11,7 +11,6 @@ import java.nio.file.Files;
|
|||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
@@ -89,9 +88,12 @@ final class Ai {
|
|||||||
this.conversations = new Conversations(settings.aiMemoryExchanges(), settings.aiMemoryMinutes());
|
this.conversations = new Conversations(settings.aiMemoryExchanges(), settings.aiMemoryMinutes());
|
||||||
this.corrections = new Corrections(new java.io.File(plugin.getDataFolder(), "correcoes.yml"));
|
this.corrections = new Corrections(new java.io.File(plugin.getDataFolder(), "correcoes.yml"));
|
||||||
// Note: aiUrl(), aiWikiChars(), aiMemoryExchanges() and aiMemoryMinutes()
|
// Note: aiUrl(), aiWikiChars(), aiMemoryExchanges() and aiMemoryMinutes()
|
||||||
// are baked here at construction. Only aiProfile() is read live in the
|
// are baked here at construction (passed to the MiniMax/Wiki/Conversations
|
||||||
// async body, which is correct — operators switch profiles live without
|
// constructors and not re-read). Everything else — aiProfile(), aiModel(),
|
||||||
// a restart, and the other settings are not meant to be hot-swapped.
|
// aiMaxTokens(), aiTemperature(), aiInstructions(), aiServerContext() — is
|
||||||
|
// read live in the async body, so operators can hot-swap them. Profiles in
|
||||||
|
// particular switch live without a restart; the baked four are not meant
|
||||||
|
// to be hot-swapped.
|
||||||
}
|
}
|
||||||
|
|
||||||
/** True if a key is configured. Without one the module stays quiet. */
|
/** True if a key is configured. Without one the module stays quiet. */
|
||||||
@@ -247,8 +249,11 @@ final class Ai {
|
|||||||
// occasionally drops a foreign word mid-sentence. Both are
|
// occasionally drops a foreign word mid-sentence. Both are
|
||||||
// worth one retry before giving up (carry-forwards #3 and #7).
|
// worth one retry before giving up (carry-forwards #3 and #7).
|
||||||
if (answer == null || AiText.hasForeignScript(answer)) {
|
if (answer == null || AiText.hasForeignScript(answer)) {
|
||||||
answer = api.answer(key, settings.aiModel(), messages,
|
// Cap before doubling: an absurd ia.max-tokens near
|
||||||
settings.aiMaxTokens() * 2, 0.1);
|
// Integer.MAX_VALUE would overflow to a negative budget
|
||||||
|
// and be sent to the API. The default (1200) is unaffected.
|
||||||
|
int retryTokens = Math.min(settings.aiMaxTokens(), Integer.MAX_VALUE / 2) * 2;
|
||||||
|
answer = api.answer(key, settings.aiModel(), messages, retryTokens, 0.1);
|
||||||
}
|
}
|
||||||
if (answer != null && AiText.hasForeignScript(answer)) {
|
if (answer != null && AiText.hasForeignScript(answer)) {
|
||||||
plugin.getLogger().warning("Resposta descartada por idioma estrangeiro.");
|
plugin.getLogger().warning("Resposta descartada por idioma estrangeiro.");
|
||||||
@@ -317,7 +322,13 @@ final class Ai {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
String clean = AiText.sanitise(answer, settings.aiMaxAnswer());
|
String clean = AiText.sanitise(answer, settings.aiMaxAnswer());
|
||||||
conversations.remember(askerId, question, clean);
|
// Only remember if the asker is still online: a PlayerQuitEvent forgets
|
||||||
|
// the player's history (carry-forward #6), and re-adding here after the
|
||||||
|
// quit would resurrect it. lastAnswer stays regardless, so /ia corrigir
|
||||||
|
// can still correct the last answer even after the asker left.
|
||||||
|
if (asker != null) {
|
||||||
|
conversations.remember(askerId, question, clean);
|
||||||
|
}
|
||||||
lastAnswer = new Answered(askerId, question, clean);
|
lastAnswer = new Answered(askerId, question, clean);
|
||||||
|
|
||||||
Component message = Msg.tag("IA", NamedTextColor.LIGHT_PURPLE)
|
Component message = Msg.tag("IA", NamedTextColor.LIGHT_PURPLE)
|
||||||
@@ -359,4 +370,4 @@ final class Ai {
|
|||||||
return askedToday;
|
return askedToday;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user