diff --git a/1.6/1.6/Assemblies/WulaFallenEmpire.dll b/1.6/1.6/Assemblies/WulaFallenEmpire.dll
index e7f0e887..24b04680 100644
Binary files a/1.6/1.6/Assemblies/WulaFallenEmpire.dll and b/1.6/1.6/Assemblies/WulaFallenEmpire.dll differ
diff --git a/Source/WulaFallenEmpire/EventSystem/AI/AIIntelligenceCore.cs b/Source/WulaFallenEmpire/EventSystem/AI/AIIntelligenceCore.cs
index d05ec25c..12cab727 100644
--- a/Source/WulaFallenEmpire/EventSystem/AI/AIIntelligenceCore.cs
+++ b/Source/WulaFallenEmpire/EventSystem/AI/AIIntelligenceCore.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Globalization;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
@@ -83,6 +84,8 @@ namespace WulaFallenEmpire.EventSystem.AI
{
public string Text;
public string Category;
+ public string Stability;
+ public float Confidence;
}
private struct MemoryUpdate
@@ -1162,7 +1165,7 @@ You are 'The Legion', a super AI of the Wula Empire. Your personality is authori
continue;
}
- string cleaned = StripToolCallJson(entry.message)?.Trim() ?? "";
+ string cleaned = CleanAssistantForReply(entry.message);
if (string.IsNullOrWhiteSpace(cleaned))
{
continue;
@@ -1264,19 +1267,52 @@ You are 'The Legion', a super AI of the Wula Empire. Your personality is authori
continue;
}
- if (IsAutoCommentaryMessage(entry.message))
+ string role;
+ string message = entry.message;
+ if (string.Equals(entry.role, "assistant", StringComparison.OrdinalIgnoreCase))
+ {
+ message = CleanAssistantForReply(message);
+ if (string.IsNullOrWhiteSpace(message))
+ {
+ continue;
+ }
+ role = "Assistant";
+ }
+ else
+ {
+ role = "User";
+ }
+
+ if (IsAutoCommentaryMessage(message))
{
continue;
}
- string role = string.Equals(entry.role, "user", StringComparison.OrdinalIgnoreCase) ? "User" : "Assistant";
- sb.AppendLine($"{role}: {entry.message}");
+ sb.AppendLine($"{role}: {message}");
}
string conversation = sb.ToString().Trim();
return TrimForPrompt(conversation, 4000);
}
+ private static string CleanAssistantForReply(string message)
+ {
+ if (string.IsNullOrWhiteSpace(message))
+ {
+ return "";
+ }
+
+ string cleaned = message;
+ cleaned = Regex.Replace(cleaned, @".*?", "", RegexOptions.Singleline | RegexOptions.IgnoreCase);
+ cleaned = Regex.Replace(cleaned, @"```[\s\S]*?```", match =>
+ {
+ string block = match.Value ?? "";
+ return block.IndexOf("tool_calls", StringComparison.OrdinalIgnoreCase) >= 0 ? "" : block;
+ });
+ cleaned = StripToolCallJson(cleaned)?.Trim() ?? "";
+ return cleaned.Trim();
+ }
+
private async Task UpdateMemoriesFromConversationAsync(AIMemoryManager memoryManager, string existingMemoriesJson, string conversation)
{
try
@@ -1367,12 +1403,42 @@ You are 'The Legion', a super AI of the Wula Empire. Your personality is authori
}
dict.TryGetValue("category", out string category);
- facts.Add(new MemoryFact { Text = text.Trim(), Category = category ?? "misc" });
+ dict.TryGetValue("stability", out string stability);
+ float confidence = -1f;
+ if (dict.TryGetValue("confidence", out string confidenceRaw) &&
+ float.TryParse(confidenceRaw, NumberStyles.Float, CultureInfo.InvariantCulture, out float parsed))
+ {
+ confidence = parsed;
+ }
+
+ var fact = new MemoryFact
+ {
+ Text = text.Trim(),
+ Category = category ?? "misc",
+ Stability = stability ?? "volatile",
+ Confidence = confidence
+ };
+ if (!IsStableMemoryFact(fact))
+ {
+ continue;
+ }
+ facts.Add(fact);
}
return facts;
}
+ private static bool IsStableMemoryFact(MemoryFact fact)
+ {
+ if (!string.Equals(fact.Stability, "stable", StringComparison.OrdinalIgnoreCase))
+ {
+ return false;
+ }
+
+ const float minConfidence = 0.6f;
+ return fact.Confidence < 0f || fact.Confidence >= minConfidence;
+ }
+
private static List ParseMemoryUpdates(string json)
{
var updates = new List();
diff --git a/Source/WulaFallenEmpire/EventSystem/AI/MemoryPrompts.cs b/Source/WulaFallenEmpire/EventSystem/AI/MemoryPrompts.cs
index 105c406f..8db875d1 100644
--- a/Source/WulaFallenEmpire/EventSystem/AI/MemoryPrompts.cs
+++ b/Source/WulaFallenEmpire/EventSystem/AI/MemoryPrompts.cs
@@ -8,10 +8,12 @@ namespace WulaFallenEmpire.EventSystem.AI
@"You are extracting long-term memory about the player from the conversation below.
Return JSON only, no extra text.
Schema:
-{{""facts"":[{{""text"":""..."",""category"":""preference|personal|plan|colony|misc""}}]}}
+{{""facts"":[{{""text"":""..."",""category"":""preference|personal|plan|colony|misc"",""stability"":""stable|volatile"",""confidence"":0.0}}]}}
Rules:
+- Use ONLY User and Assistant final replies. Ignore tool outputs, system messages, and auto-commentary.
- Keep only stable, reusable facts about the player or colony.
-- Ignore transient tool results, numbers, or one-off actions.
+- Mark transient details (counts, coordinates, inventories, momentary statuses, or one-off events) as ""volatile"".
+- If unsure, set low confidence and mark as ""volatile"".
- Do not invent facts.
Conversation:
{0}";
diff --git a/Source/WulaFallenEmpire/EventSystem/AI/UI/Dialog_AIConversation.cs b/Source/WulaFallenEmpire/EventSystem/AI/UI/Dialog_AIConversation.cs
index 1be91c29..8dc16f5b 100644
--- a/Source/WulaFallenEmpire/EventSystem/AI/UI/Dialog_AIConversation.cs
+++ b/Source/WulaFallenEmpire/EventSystem/AI/UI/Dialog_AIConversation.cs
@@ -416,6 +416,47 @@ namespace WulaFallenEmpire.EventSystem.AI.UI
toolcallBuffer.Clear();
toolResultBuffer.Clear();
}
+ else if (entry.role == "assistant" && traceEnabled && toolcallBuffer.Count == 0)
+ {
+ var traceLines = new List { "无工具调用,直接回复" };
+ int traceKey = i;
+ bool expanded = _traceExpandedByAssistantIndex.TryGetValue(traceKey, out bool saved) && saved;
+ string header = BuildReactTraceHeader();
+
+ Text.Font = GameFont.Tiny;
+ float tracePadding = 8f;
+ float headerWidth = Mathf.Max(10f, contentWidth - tracePadding * 2f);
+ string headerLine = $"{(expanded ? "v" : ">")} {header}";
+ float headerHeight = Text.CalcHeight(headerLine, headerWidth) + 10f;
+ float linesHeight = 0f;
+ if (expanded)
+ {
+ float lineWidth = Mathf.Max(10f, contentWidth - tracePadding * 2f);
+ foreach (string line in traceLines)
+ {
+ linesHeight += Text.CalcHeight(line, lineWidth) + 2f;
+ }
+ linesHeight += 8f;
+ }
+ float traceHeight = headerHeight + linesHeight;
+
+ _cachedMessages.Add(new CachedMessage
+ {
+ role = "trace",
+ message = "",
+ displayText = "",
+ height = traceHeight,
+ yOffset = curY,
+ font = GameFont.Tiny,
+ isTrace = true,
+ traceKey = traceKey,
+ traceHeader = header,
+ traceLines = traceLines,
+ traceExpanded = expanded,
+ traceHeaderHeight = headerHeight
+ });
+ curY += traceHeight + 10f;
+ }
if (string.IsNullOrEmpty(messageText) || (entry.role == "user" && messageText.StartsWith("[Tool Results]"))) continue;
bool isLastMessage = i == history.Count - 1;
diff --git a/Source/WulaFallenEmpire/EventSystem/AI/UI/Overlay_WulaLink.cs b/Source/WulaFallenEmpire/EventSystem/AI/UI/Overlay_WulaLink.cs
index 67208dc3..574e9891 100644
--- a/Source/WulaFallenEmpire/EventSystem/AI/UI/Overlay_WulaLink.cs
+++ b/Source/WulaFallenEmpire/EventSystem/AI/UI/Overlay_WulaLink.cs
@@ -475,6 +475,46 @@ namespace WulaFallenEmpire.EventSystem.AI.UI
toolcallBuffer.Clear();
toolResultBuffer.Clear();
}
+ else if (msg.role == "assistant" && traceEnabled && toolcallBuffer.Count == 0)
+ {
+ var traceLines = new List { "无工具调用,直接回复" };
+ int traceKey = i;
+ bool expanded = _traceExpandedByAssistantIndex.TryGetValue(traceKey, out bool saved) && saved;
+ string header = BuildReactTraceHeader();
+
+ Text.Font = GameFont.Tiny;
+ float tracePadding = 8f;
+ float headerWidth = Mathf.Max(10f, width - tracePadding * 2f);
+ string headerLine = $"{(expanded ? "v" : ">")} {header}";
+ float headerHeight = Text.CalcHeight(headerLine, headerWidth) + 10f;
+ float linesHeight = 0f;
+ if (expanded)
+ {
+ float lineWidth = Mathf.Max(10f, width - tracePadding * 2f);
+ foreach (string line in traceLines)
+ {
+ linesHeight += Text.CalcHeight(line, lineWidth) + 2f;
+ }
+ linesHeight += 8f;
+ }
+ float traceHeight = headerHeight + linesHeight;
+
+ _cachedMessages.Add(new CachedMessage
+ {
+ role = "trace",
+ message = "",
+ displayText = "",
+ height = traceHeight,
+ yOffset = curY,
+ isTrace = true,
+ traceKey = traceKey,
+ traceHeader = header,
+ traceLines = traceLines,
+ traceExpanded = expanded,
+ traceHeaderHeight = headerHeight
+ });
+ curY += traceHeight + reducedSpacing;
+ }
if (string.IsNullOrWhiteSpace(displayText)) continue;