fix(ia): prevent private notes leak in places tool, guard recordTurn against disk failure, and add tests
This commit is contained in:
@@ -437,6 +437,7 @@ final class Ai {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
String clean = String.join(" ", segments);
|
String clean = String.join(" ", segments);
|
||||||
|
lastAnswer = new Answered(askerId, question, clean);
|
||||||
// Only remember if the asker is still online: a PlayerQuitEvent forgets
|
// Only remember if the asker is still online: a PlayerQuitEvent forgets
|
||||||
// the player's history (carry-forward #6), and re-adding here after the
|
// the player's history (carry-forward #6), and re-adding here after the
|
||||||
// quit would resurrect it. lastAnswer stays regardless, so /ia corrigir
|
// quit would resurrect it. lastAnswer stays regardless, so /ia corrigir
|
||||||
@@ -444,10 +445,13 @@ final class Ai {
|
|||||||
if (asker != null) {
|
if (asker != null) {
|
||||||
conversations.remember(askerId, question, clean);
|
conversations.remember(askerId, question, clean);
|
||||||
if (plugin.playerMemory() != null) {
|
if (plugin.playerMemory() != null) {
|
||||||
plugin.playerMemory().recordTurn(askerId, asker.getName(), question, clean);
|
try {
|
||||||
|
plugin.playerMemory().recordTurn(askerId, asker.getName(), question, clean);
|
||||||
|
} catch (RuntimeException e) {
|
||||||
|
plugin.getLogger().warning("Falha ao gravar memória da IA para " + asker.getName() + ": " + e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
lastAnswer = new Answered(askerId, question, clean);
|
|
||||||
|
|
||||||
if (isPrivate || !settings.aiPublic()) {
|
if (isPrivate || !settings.aiPublic()) {
|
||||||
if (asker != null) {
|
if (asker != null) {
|
||||||
|
|||||||
@@ -146,7 +146,20 @@ final class Tools {
|
|||||||
}
|
}
|
||||||
String uuidStr = who.uuid();
|
String uuidStr = who.uuid();
|
||||||
List<DeathLog.Entry> deaths = plugin.deathLog().forPlayer(uuidStr);
|
List<DeathLog.Entry> deaths = plugin.deathLog().forPlayer(uuidStr);
|
||||||
List<Note> notes = plugin.notes().visibleTo(uuidStr, null, "");
|
List<Note> notes = plugin.notes().visibleTo(uuidStr, Note.Scope.PUBLICA, "");
|
||||||
|
return formatPlayerPlaces(who, deaths, notes);
|
||||||
|
}
|
||||||
|
|
||||||
|
String formatPlayerPlaces(OfflineStats.Known who, List<DeathLog.Entry> deaths, List<Note> visibleNotes) {
|
||||||
|
String uuidStr = who.uuid();
|
||||||
|
List<Note> notes = new java.util.ArrayList<>();
|
||||||
|
if (visibleNotes != null) {
|
||||||
|
for (Note n : visibleNotes) {
|
||||||
|
if (n.scope() == Note.Scope.PUBLICA && n.authorId() != null && n.authorId().equals(uuidStr)) {
|
||||||
|
notes.add(n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
sb.append("Lugares conhecidos de ").append(who.name()).append(":\n");
|
sb.append("Lugares conhecidos de ").append(who.name()).append(":\n");
|
||||||
@@ -164,7 +177,7 @@ final class Tools {
|
|||||||
sb.append("\n");
|
sb.append("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (deaths.isEmpty()) {
|
if (deaths == null || deaths.isEmpty()) {
|
||||||
sb.append("- Mortes recentes: nenhum registro de morte recente.");
|
sb.append("- Mortes recentes: nenhum registro de morte recente.");
|
||||||
} else {
|
} else {
|
||||||
sb.append("- Mortes recentes: ");
|
sb.append("- Mortes recentes: ");
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ package dev.marcospaulo.canalhandia;
|
|||||||
import com.google.gson.JsonArray;
|
import com.google.gson.JsonArray;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
@@ -42,4 +44,35 @@ class ToolsTest {
|
|||||||
String res = tools.run("wiki", "malformed json");
|
String res = tools.run("wiki", "malformed json");
|
||||||
assertTrue(res.contains("argumentos inválidos"));
|
assertTrue(res.contains("argumentos inválidos"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void formatPlayerPlacesFiltersOutPrivateNotesAndOtherAuthors() {
|
||||||
|
Tools tools = new Tools(null, null, null, s -> {});
|
||||||
|
OfflineStats.Known who = new OfflineStats.Known("uuid-ana", "ana");
|
||||||
|
|
||||||
|
Note privateNote = new Note(1, Note.Scope.PRIVADA, "ana", "uuid-ana", "segredo", "world", 10, 20, 30, 1000L);
|
||||||
|
Note publicNote = new Note(2, Note.Scope.PUBLICA, "ana", "uuid-ana", "vila do spawn", "world", 100, 64, 200, 1000L);
|
||||||
|
Note otherAuthorPublicNote = new Note(3, Note.Scope.PUBLICA, "bob", "uuid-bob", "base do bob", "world", 500, 64, 500, 1000L);
|
||||||
|
|
||||||
|
String formatted = tools.formatPlayerPlaces(who, List.of(), List.of(privateNote, publicNote, otherAuthorPublicNote));
|
||||||
|
|
||||||
|
assertTrue(formatted.contains("vila do spawn"));
|
||||||
|
assertFalse(formatted.contains("segredo"), "Private notes must never be included in places output");
|
||||||
|
assertFalse(formatted.contains("base do bob"), "Notes of other players must not be included");
|
||||||
|
assertTrue(formatted.contains("nenhum registro de morte recente"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void formatPlayerPlacesIncludesDeathsAndFormatsPlaces() {
|
||||||
|
Tools tools = new Tools(null, null, null, s -> {});
|
||||||
|
OfflineStats.Known who = new OfflineStats.Known("uuid-ana", "ana");
|
||||||
|
|
||||||
|
DeathLog.Entry d = new DeathLog.Entry("uuid-ana", "abraçou um Creeper", "Mundo normal", 12, 64, -80, 1000L);
|
||||||
|
String formatted = tools.formatPlayerPlaces(who, List.of(d), List.of());
|
||||||
|
|
||||||
|
assertTrue(formatted.contains("Lugares conhecidos de ana:"));
|
||||||
|
assertTrue(formatted.contains("nenhuma base salva"));
|
||||||
|
assertTrue(formatted.contains("12, 64, -80 (Mundo normal)"));
|
||||||
|
assertTrue(formatted.contains("abraçou um Creeper"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user