zc
This commit is contained in:
Binary file not shown.
@@ -964,6 +964,13 @@ You are 'The Legion', a super AI of the Wula Empire. Your personality is authori
|
||||
return trimmed.Length >= 4;
|
||||
}
|
||||
|
||||
private void AddTraceNote(string note)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(note)) return;
|
||||
_history.Add(("trace", note.Trim()));
|
||||
PersistHistory();
|
||||
}
|
||||
|
||||
private bool IsToolAvailable(string toolName)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(toolName)) return false;
|
||||
@@ -1165,6 +1172,10 @@ You are 'The Legion', a super AI of the Wula Empire. Your personality is authori
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (string.Equals(entry.role, "trace", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (string.Equals(entry.role, "tool", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
if (lastUserIndex != -1 && i > lastUserIndex)
|
||||
@@ -1886,6 +1897,7 @@ You are 'The Legion', a super AI of the Wula Empire. Your personality is authori
|
||||
if (LooksLikeNaturalReply(normalizedResponse))
|
||||
{
|
||||
toolPhaseReplyCandidate = normalizedResponse;
|
||||
AddTraceNote(normalizedResponse);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1902,6 +1914,7 @@ You are 'The Legion', a super AI of the Wula Empire. Your personality is authori
|
||||
if (LooksLikeNaturalReply(normalizedFixed))
|
||||
{
|
||||
toolPhaseReplyCandidate = normalizedFixed;
|
||||
AddTraceNote(normalizedFixed);
|
||||
}
|
||||
if (Prefs.DevMode)
|
||||
{
|
||||
@@ -1932,6 +1945,24 @@ You are 'The Legion', a super AI of the Wula Empire. Your personality is authori
|
||||
}
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(parsedSource))
|
||||
{
|
||||
string traceText = parsedSource;
|
||||
if (!string.IsNullOrWhiteSpace(jsonFragment))
|
||||
{
|
||||
int idx = traceText.IndexOf(jsonFragment, StringComparison.Ordinal);
|
||||
if (idx >= 0)
|
||||
{
|
||||
traceText = traceText.Remove(idx, jsonFragment.Length);
|
||||
}
|
||||
}
|
||||
traceText = traceText.Trim();
|
||||
if (LooksLikeNaturalReply(traceText))
|
||||
{
|
||||
AddTraceNote(traceText);
|
||||
}
|
||||
}
|
||||
|
||||
var invalidTools = toolCalls
|
||||
.Where(c => !IsToolAvailable(c.Name))
|
||||
.Select(c => c.Name)
|
||||
|
||||
@@ -31,6 +31,7 @@ namespace WulaFallenEmpire.EventSystem.AI.UI
|
||||
private int _currentPortraitId = 0;
|
||||
private static readonly Regex ExpressionTagRegex = new Regex(@"\[EXPR\s*:\s*([1-6])\s*\]", RegexOptions.IgnoreCase);
|
||||
private readonly Dictionary<int, bool> _traceExpandedByAssistantIndex = new Dictionary<int, bool>();
|
||||
private readonly Dictionary<int, string> _traceHeaderByAssistantIndex = new Dictionary<int, string>();
|
||||
|
||||
private class CachedMessage
|
||||
{
|
||||
@@ -325,6 +326,11 @@ namespace WulaFallenEmpire.EventSystem.AI.UI
|
||||
if (Math.Abs(_lastUsedWidth - width) < 0.1f && history.Count == _lastHistoryCount) return;
|
||||
|
||||
_lastUsedWidth = width;
|
||||
if (_lastHistoryCount >= 0 && history.Count < _lastHistoryCount)
|
||||
{
|
||||
_traceExpandedByAssistantIndex.Clear();
|
||||
_traceHeaderByAssistantIndex.Clear();
|
||||
}
|
||||
_lastHistoryCount = history.Count;
|
||||
_cachedMessages.Clear();
|
||||
_cachedTotalHeight = 0f;
|
||||
@@ -333,6 +339,7 @@ namespace WulaFallenEmpire.EventSystem.AI.UI
|
||||
float contentWidth = width - innerPadding * 2;
|
||||
var toolcallBuffer = new List<string>();
|
||||
var toolResultBuffer = new List<string>();
|
||||
var traceNoteBuffer = new List<string>();
|
||||
bool traceEnabled = WulaFallenEmpireMod.settings?.showReactTraceInUI == true;
|
||||
|
||||
for (int i = 0; i < history.Count; i++)
|
||||
@@ -342,6 +349,7 @@ namespace WulaFallenEmpire.EventSystem.AI.UI
|
||||
{
|
||||
toolcallBuffer.Clear();
|
||||
toolResultBuffer.Clear();
|
||||
traceNoteBuffer.Clear();
|
||||
}
|
||||
|
||||
if (entry.role == "toolcall")
|
||||
@@ -362,6 +370,15 @@ namespace WulaFallenEmpire.EventSystem.AI.UI
|
||||
continue;
|
||||
}
|
||||
|
||||
if (entry.role == "trace")
|
||||
{
|
||||
if (traceEnabled)
|
||||
{
|
||||
traceNoteBuffer.Add(entry.message ?? "");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
string messageText = entry.role == "assistant"
|
||||
? ParseResponseForDisplay(entry.message)
|
||||
: AIIntelligenceCore.StripContextInfo(entry.message);
|
||||
@@ -371,12 +388,12 @@ namespace WulaFallenEmpire.EventSystem.AI.UI
|
||||
if (entry.role == "user" && entry.message.Contains("[AUTO_COMMENTARY]")) continue;
|
||||
if (entry.role == "assistant" && traceEnabled && toolcallBuffer.Count > 0)
|
||||
{
|
||||
var traceLines = BuildTraceLines(toolcallBuffer, toolResultBuffer);
|
||||
var traceLines = BuildTraceLines(toolcallBuffer, toolResultBuffer, traceNoteBuffer);
|
||||
if (traceLines.Count > 0)
|
||||
{
|
||||
int traceKey = i;
|
||||
bool expanded = _traceExpandedByAssistantIndex.TryGetValue(traceKey, out bool saved) && saved;
|
||||
string header = BuildReactTraceHeader();
|
||||
string header = GetTraceHeader(traceKey, false);
|
||||
|
||||
Text.Font = GameFont.Tiny;
|
||||
float tracePadding = 8f;
|
||||
@@ -415,13 +432,18 @@ namespace WulaFallenEmpire.EventSystem.AI.UI
|
||||
|
||||
toolcallBuffer.Clear();
|
||||
toolResultBuffer.Clear();
|
||||
traceNoteBuffer.Clear();
|
||||
}
|
||||
else if (entry.role == "assistant" && traceEnabled && toolcallBuffer.Count == 0)
|
||||
{
|
||||
var traceLines = new List<string> { "无工具调用,直接回复" };
|
||||
int traceKey = i;
|
||||
bool expanded = _traceExpandedByAssistantIndex.TryGetValue(traceKey, out bool saved) && saved;
|
||||
string header = BuildReactTraceHeader();
|
||||
var traceLines = BuildTraceLines(toolcallBuffer, toolResultBuffer, traceNoteBuffer);
|
||||
if (traceLines.Count == 0)
|
||||
{
|
||||
traceLines.Add("无工具调用,直接回复");
|
||||
}
|
||||
int traceKey = i;
|
||||
bool expanded = _traceExpandedByAssistantIndex.TryGetValue(traceKey, out bool saved) && saved;
|
||||
string header = GetTraceHeader(traceKey, false);
|
||||
|
||||
Text.Font = GameFont.Tiny;
|
||||
float tracePadding = 8f;
|
||||
@@ -456,6 +478,7 @@ namespace WulaFallenEmpire.EventSystem.AI.UI
|
||||
traceHeaderHeight = headerHeight
|
||||
});
|
||||
curY += traceHeight + 10f;
|
||||
traceNoteBuffer.Clear();
|
||||
}
|
||||
if (string.IsNullOrEmpty(messageText) || (entry.role == "user" && messageText.StartsWith("[Tool Results]"))) continue;
|
||||
|
||||
@@ -491,9 +514,59 @@ namespace WulaFallenEmpire.EventSystem.AI.UI
|
||||
float innerPadding = 5f;
|
||||
float contentWidth = rect.width - 16f - innerPadding * 2;
|
||||
UpdateCacheIfNeeded(rect.width - 16f);
|
||||
bool traceEnabled = WulaFallenEmpireMod.settings?.showReactTraceInUI == true;
|
||||
CachedMessage liveTraceEntry = null;
|
||||
float liveTraceHeight = 0f;
|
||||
if (_isThinking && traceEnabled)
|
||||
{
|
||||
var liveLines = BuildLiveTraceLines();
|
||||
if (liveLines.Count == 0)
|
||||
{
|
||||
liveLines.Add("思考中…");
|
||||
}
|
||||
int traceKey = -1;
|
||||
bool expanded = _traceExpandedByAssistantIndex.TryGetValue(traceKey, out bool saved) ? saved : true;
|
||||
string header = GetTraceHeader(traceKey, true);
|
||||
|
||||
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 liveLines)
|
||||
{
|
||||
linesHeight += Text.CalcHeight(line, lineWidth) + 2f;
|
||||
}
|
||||
linesHeight += 8f;
|
||||
}
|
||||
float traceHeight = headerHeight + linesHeight;
|
||||
liveTraceHeight = traceHeight + 10f;
|
||||
liveTraceEntry = new CachedMessage
|
||||
{
|
||||
role = "trace",
|
||||
message = "",
|
||||
displayText = "",
|
||||
height = traceHeight,
|
||||
yOffset = 0f,
|
||||
font = GameFont.Tiny,
|
||||
isTrace = true,
|
||||
traceKey = traceKey,
|
||||
traceHeader = header,
|
||||
traceLines = liveLines,
|
||||
traceExpanded = expanded,
|
||||
traceHeaderHeight = headerHeight
|
||||
};
|
||||
}
|
||||
|
||||
float totalHeight = _cachedTotalHeight;
|
||||
if (_isThinking) totalHeight += 40f;
|
||||
if (_isThinking)
|
||||
{
|
||||
totalHeight += liveTraceEntry != null ? liveTraceHeight : 40f;
|
||||
}
|
||||
|
||||
Rect viewRect = new Rect(0f, 0f, rect.width - 16f, totalHeight);
|
||||
if (_scrollToBottom)
|
||||
@@ -541,7 +614,15 @@ namespace WulaFallenEmpire.EventSystem.AI.UI
|
||||
if (_isThinking)
|
||||
{
|
||||
float thinkingY = _cachedTotalHeight > 0 ? _cachedTotalHeight : 0f;
|
||||
if (thinkingY + 40f >= viewTop && thinkingY <= viewBottom)
|
||||
if (liveTraceEntry != null)
|
||||
{
|
||||
if (thinkingY + liveTraceEntry.height >= viewTop && thinkingY <= viewBottom)
|
||||
{
|
||||
Rect traceRect = new Rect(innerPadding, thinkingY, contentWidth, liveTraceEntry.height);
|
||||
DrawReactTracePanel(traceRect, liveTraceEntry);
|
||||
}
|
||||
}
|
||||
else if (thinkingY + 40f >= viewTop && thinkingY <= viewBottom)
|
||||
{
|
||||
DrawThinkingIndicator(new Rect(innerPadding, thinkingY, contentWidth, 35f));
|
||||
}
|
||||
@@ -574,19 +655,19 @@ namespace WulaFallenEmpire.EventSystem.AI.UI
|
||||
return text.Split(new[] { "OPTIONS:" }, StringSplitOptions.None)[0].Trim();
|
||||
}
|
||||
|
||||
private List<string> BuildTraceLines(List<string> toolcallBuffer, List<string> toolResultBuffer)
|
||||
private List<string> BuildTraceLines(List<string> toolcallBuffer, List<string> toolResultBuffer, List<string> traceNotes)
|
||||
{
|
||||
var lines = new List<string>();
|
||||
if (toolcallBuffer == null || toolcallBuffer.Count == 0) return lines;
|
||||
bool hasToolCalls = toolcallBuffer != null && toolcallBuffer.Count > 0;
|
||||
|
||||
int stepIndex = 0;
|
||||
int maxSteps = Math.Max(toolcallBuffer.Count, toolResultBuffer.Count);
|
||||
int maxSteps = Math.Max(toolcallBuffer?.Count ?? 0, toolResultBuffer?.Count ?? 0);
|
||||
for (int i = 0; i < maxSteps; i++)
|
||||
{
|
||||
bool anyStepContent = false;
|
||||
stepIndex++;
|
||||
|
||||
if (i < toolcallBuffer.Count &&
|
||||
if (hasToolCalls && i < toolcallBuffer.Count &&
|
||||
JsonToolCallParser.TryParseToolCallsFromText(toolcallBuffer[i], out var calls, out _))
|
||||
{
|
||||
foreach (var call in calls)
|
||||
@@ -601,7 +682,7 @@ namespace WulaFallenEmpire.EventSystem.AI.UI
|
||||
}
|
||||
}
|
||||
|
||||
if (i < toolResultBuffer.Count)
|
||||
if (toolResultBuffer != null && i < toolResultBuffer.Count)
|
||||
{
|
||||
foreach (string resultLine in ExtractToolResultLines(toolResultBuffer[i], 4))
|
||||
{
|
||||
@@ -616,6 +697,16 @@ namespace WulaFallenEmpire.EventSystem.AI.UI
|
||||
}
|
||||
}
|
||||
|
||||
if (traceNotes != null && traceNotes.Count > 0)
|
||||
{
|
||||
foreach (string note in traceNotes)
|
||||
{
|
||||
string trimmed = (note ?? "").Trim();
|
||||
if (string.IsNullOrWhiteSpace(trimmed)) continue;
|
||||
lines.Add($"模型 · {TrimForDisplay(trimmed, 220)}");
|
||||
}
|
||||
}
|
||||
|
||||
return lines;
|
||||
}
|
||||
|
||||
@@ -650,10 +741,67 @@ namespace WulaFallenEmpire.EventSystem.AI.UI
|
||||
return text.Substring(0, maxChars) + "...";
|
||||
}
|
||||
|
||||
private string BuildReactTraceHeader()
|
||||
private List<string> BuildLiveTraceLines()
|
||||
{
|
||||
string state = _isThinking ? "思考中" : "已思考";
|
||||
float elapsed = _isThinking
|
||||
if (_core == null) return new List<string>();
|
||||
var history = _core.GetHistorySnapshot();
|
||||
if (history == null || history.Count == 0) return new List<string>();
|
||||
|
||||
int lastUserIndex = -1;
|
||||
for (int i = history.Count - 1; i >= 0; i--)
|
||||
{
|
||||
if (history[i].role == "user")
|
||||
{
|
||||
lastUserIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (lastUserIndex == -1) return new List<string>();
|
||||
|
||||
var toolcallBuffer = new List<string>();
|
||||
var toolResultBuffer = new List<string>();
|
||||
var traceNoteBuffer = new List<string>();
|
||||
for (int i = lastUserIndex + 1; i < history.Count; i++)
|
||||
{
|
||||
var entry = history[i];
|
||||
if (entry.role == "toolcall")
|
||||
{
|
||||
toolcallBuffer.Add(entry.message ?? "");
|
||||
}
|
||||
else if (entry.role == "tool")
|
||||
{
|
||||
toolResultBuffer.Add(entry.message ?? "");
|
||||
}
|
||||
else if (entry.role == "trace")
|
||||
{
|
||||
traceNoteBuffer.Add(entry.message ?? "");
|
||||
}
|
||||
}
|
||||
|
||||
return BuildTraceLines(toolcallBuffer, toolResultBuffer, traceNoteBuffer);
|
||||
}
|
||||
|
||||
private string GetTraceHeader(int traceKey, bool isLive)
|
||||
{
|
||||
if (isLive)
|
||||
{
|
||||
return BuildReactTraceHeader(true);
|
||||
}
|
||||
|
||||
if (_traceHeaderByAssistantIndex.TryGetValue(traceKey, out string header))
|
||||
{
|
||||
return header;
|
||||
}
|
||||
|
||||
header = BuildReactTraceHeader(false);
|
||||
_traceHeaderByAssistantIndex[traceKey] = header;
|
||||
return header;
|
||||
}
|
||||
|
||||
private string BuildReactTraceHeader(bool isLive)
|
||||
{
|
||||
string state = isLive ? "思考中" : "已思考";
|
||||
float elapsed = isLive
|
||||
? Mathf.Max(0f, Time.realtimeSinceStartup - (_core?.ThinkingStartTime ?? 0f))
|
||||
: _core?.LastThinkingDuration ?? 0f;
|
||||
string elapsedText = elapsed > 0f ? elapsed.ToString("0.0", CultureInfo.InvariantCulture) : "0.0";
|
||||
|
||||
@@ -26,6 +26,7 @@ namespace WulaFallenEmpire.EventSystem.AI.UI
|
||||
private List<CachedMessage> _cachedMessages = new List<CachedMessage>();
|
||||
private float _cachedTotalHeight = 0f;
|
||||
private readonly Dictionary<int, bool> _traceExpandedByAssistantIndex = new Dictionary<int, bool>();
|
||||
private readonly Dictionary<int, string> _traceHeaderByAssistantIndex = new Dictionary<int, string>();
|
||||
|
||||
private class CachedMessage
|
||||
{
|
||||
@@ -377,6 +378,11 @@ namespace WulaFallenEmpire.EventSystem.AI.UI
|
||||
}
|
||||
|
||||
_lastUsedWidth = width;
|
||||
if (_lastHistoryCount >= 0 && history.Count < _lastHistoryCount)
|
||||
{
|
||||
_traceExpandedByAssistantIndex.Clear();
|
||||
_traceHeaderByAssistantIndex.Clear();
|
||||
}
|
||||
_lastHistoryCount = history.Count;
|
||||
_cachedMessages.Clear();
|
||||
_cachedTotalHeight = 0f;
|
||||
@@ -384,6 +390,7 @@ namespace WulaFallenEmpire.EventSystem.AI.UI
|
||||
float curY = 10f;
|
||||
var toolcallBuffer = new List<string>();
|
||||
var toolResultBuffer = new List<string>();
|
||||
var traceNoteBuffer = new List<string>();
|
||||
bool traceEnabled = WulaFallenEmpireMod.settings?.showReactTraceInUI == true;
|
||||
|
||||
for (int i = 0; i < history.Count; i++)
|
||||
@@ -394,6 +401,7 @@ namespace WulaFallenEmpire.EventSystem.AI.UI
|
||||
{
|
||||
toolcallBuffer.Clear();
|
||||
toolResultBuffer.Clear();
|
||||
traceNoteBuffer.Clear();
|
||||
}
|
||||
|
||||
if (msg.role == "toolcall")
|
||||
@@ -414,6 +422,15 @@ namespace WulaFallenEmpire.EventSystem.AI.UI
|
||||
continue;
|
||||
}
|
||||
|
||||
if (msg.role == "trace")
|
||||
{
|
||||
if (traceEnabled)
|
||||
{
|
||||
traceNoteBuffer.Add(msg.message ?? "");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (msg.role == "system" && !Prefs.DevMode) continue;
|
||||
|
||||
// Hide auto-commentary system messages (user-side) from display
|
||||
@@ -431,12 +448,12 @@ namespace WulaFallenEmpire.EventSystem.AI.UI
|
||||
|
||||
if (msg.role == "assistant" && traceEnabled && toolcallBuffer.Count > 0)
|
||||
{
|
||||
var traceLines = BuildTraceLines(toolcallBuffer, toolResultBuffer);
|
||||
var traceLines = BuildTraceLines(toolcallBuffer, toolResultBuffer, traceNoteBuffer);
|
||||
if (traceLines.Count > 0)
|
||||
{
|
||||
int traceKey = i;
|
||||
bool expanded = _traceExpandedByAssistantIndex.TryGetValue(traceKey, out bool saved) && saved;
|
||||
string header = BuildReactTraceHeader();
|
||||
string header = GetTraceHeader(traceKey, false);
|
||||
|
||||
Text.Font = GameFont.Tiny;
|
||||
float padding = 8f;
|
||||
@@ -474,13 +491,18 @@ namespace WulaFallenEmpire.EventSystem.AI.UI
|
||||
|
||||
toolcallBuffer.Clear();
|
||||
toolResultBuffer.Clear();
|
||||
traceNoteBuffer.Clear();
|
||||
}
|
||||
else if (msg.role == "assistant" && traceEnabled && toolcallBuffer.Count == 0)
|
||||
{
|
||||
var traceLines = new List<string> { "无工具调用,直接回复" };
|
||||
var traceLines = BuildTraceLines(toolcallBuffer, toolResultBuffer, traceNoteBuffer);
|
||||
if (traceLines.Count == 0)
|
||||
{
|
||||
traceLines.Add("无工具调用,直接回复");
|
||||
}
|
||||
int traceKey = i;
|
||||
bool expanded = _traceExpandedByAssistantIndex.TryGetValue(traceKey, out bool saved) && saved;
|
||||
string header = BuildReactTraceHeader();
|
||||
string header = GetTraceHeader(traceKey, false);
|
||||
|
||||
Text.Font = GameFont.Tiny;
|
||||
float tracePadding = 8f;
|
||||
@@ -514,6 +536,7 @@ namespace WulaFallenEmpire.EventSystem.AI.UI
|
||||
traceHeaderHeight = headerHeight
|
||||
});
|
||||
curY += traceHeight + reducedSpacing;
|
||||
traceNoteBuffer.Clear();
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(displayText)) continue;
|
||||
@@ -540,10 +563,57 @@ namespace WulaFallenEmpire.EventSystem.AI.UI
|
||||
float width = rect.width - 26f; // Scrollbar space
|
||||
UpdateCacheIfNeeded(width);
|
||||
|
||||
bool traceEnabled = WulaFallenEmpireMod.settings?.showReactTraceInUI == true;
|
||||
CachedMessage liveTraceEntry = null;
|
||||
float liveTraceHeight = 0f;
|
||||
if (_core != null && _core.IsThinking && traceEnabled)
|
||||
{
|
||||
var liveLines = BuildLiveTraceLines();
|
||||
if (liveLines.Count == 0)
|
||||
{
|
||||
liveLines.Add("思考中…");
|
||||
}
|
||||
int traceKey = -1;
|
||||
bool expanded = _traceExpandedByAssistantIndex.TryGetValue(traceKey, out bool saved) ? saved : true;
|
||||
string header = GetTraceHeader(traceKey, true);
|
||||
|
||||
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 liveLines)
|
||||
{
|
||||
linesHeight += Text.CalcHeight(line, lineWidth) + 2f;
|
||||
}
|
||||
linesHeight += 8f;
|
||||
}
|
||||
float traceHeight = headerHeight + linesHeight;
|
||||
liveTraceHeight = traceHeight + 8f;
|
||||
liveTraceEntry = new CachedMessage
|
||||
{
|
||||
role = "trace",
|
||||
message = "",
|
||||
displayText = "",
|
||||
height = traceHeight,
|
||||
yOffset = 0f,
|
||||
isTrace = true,
|
||||
traceKey = traceKey,
|
||||
traceHeader = header,
|
||||
traceLines = liveLines,
|
||||
traceExpanded = expanded,
|
||||
traceHeaderHeight = headerHeight
|
||||
};
|
||||
}
|
||||
|
||||
float totalContentHeight = _cachedTotalHeight;
|
||||
if (_core != null && _core.IsThinking)
|
||||
{
|
||||
totalContentHeight += 40f;
|
||||
totalContentHeight += liveTraceEntry != null ? liveTraceHeight : 40f;
|
||||
}
|
||||
|
||||
Rect viewRect = new Rect(0, 0, width, totalContentHeight);
|
||||
@@ -593,10 +663,21 @@ namespace WulaFallenEmpire.EventSystem.AI.UI
|
||||
if (_core != null && _core.IsThinking)
|
||||
{
|
||||
float thinkingY = _cachedTotalHeight > 0 ? _cachedTotalHeight : 10f;
|
||||
Rect thinkingRect = new Rect(0, thinkingY, width, 30f);
|
||||
if (thinkingY + 30f >= viewTop && thinkingY <= viewBottom)
|
||||
if (liveTraceEntry != null)
|
||||
{
|
||||
DrawThinkingIndicator(thinkingRect);
|
||||
if (thinkingY + liveTraceEntry.height >= viewTop && thinkingY <= viewBottom)
|
||||
{
|
||||
Rect traceRect = new Rect(0, thinkingY, width, liveTraceEntry.height);
|
||||
DrawReactTracePanel(traceRect, liveTraceEntry);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Rect thinkingRect = new Rect(0, thinkingY, width, 30f);
|
||||
if (thinkingY + 30f >= viewTop && thinkingY <= viewBottom)
|
||||
{
|
||||
DrawThinkingIndicator(thinkingRect);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -616,19 +697,19 @@ namespace WulaFallenEmpire.EventSystem.AI.UI
|
||||
return text.Remove(index, fragment.Length).Trim();
|
||||
}
|
||||
|
||||
private List<string> BuildTraceLines(List<string> toolcallBuffer, List<string> toolResultBuffer)
|
||||
private List<string> BuildTraceLines(List<string> toolcallBuffer, List<string> toolResultBuffer, List<string> traceNotes)
|
||||
{
|
||||
var lines = new List<string>();
|
||||
if (toolcallBuffer == null || toolcallBuffer.Count == 0) return lines;
|
||||
bool hasToolCalls = toolcallBuffer != null && toolcallBuffer.Count > 0;
|
||||
|
||||
int stepIndex = 0;
|
||||
int maxSteps = Math.Max(toolcallBuffer.Count, toolResultBuffer.Count);
|
||||
int maxSteps = Math.Max(toolcallBuffer?.Count ?? 0, toolResultBuffer?.Count ?? 0);
|
||||
for (int i = 0; i < maxSteps; i++)
|
||||
{
|
||||
bool anyStepContent = false;
|
||||
stepIndex++;
|
||||
|
||||
if (i < toolcallBuffer.Count &&
|
||||
if (hasToolCalls && i < toolcallBuffer.Count &&
|
||||
JsonToolCallParser.TryParseToolCallsFromText(toolcallBuffer[i], out var calls, out _))
|
||||
{
|
||||
foreach (var call in calls)
|
||||
@@ -643,7 +724,7 @@ namespace WulaFallenEmpire.EventSystem.AI.UI
|
||||
}
|
||||
}
|
||||
|
||||
if (i < toolResultBuffer.Count)
|
||||
if (toolResultBuffer != null && i < toolResultBuffer.Count)
|
||||
{
|
||||
foreach (string resultLine in ExtractToolResultLines(toolResultBuffer[i], 4))
|
||||
{
|
||||
@@ -658,6 +739,16 @@ namespace WulaFallenEmpire.EventSystem.AI.UI
|
||||
}
|
||||
}
|
||||
|
||||
if (traceNotes != null && traceNotes.Count > 0)
|
||||
{
|
||||
foreach (string note in traceNotes)
|
||||
{
|
||||
string trimmed = (note ?? "").Trim();
|
||||
if (string.IsNullOrWhiteSpace(trimmed)) continue;
|
||||
lines.Add($"模型 · {TrimForDisplay(trimmed, 220)}");
|
||||
}
|
||||
}
|
||||
|
||||
return lines;
|
||||
}
|
||||
|
||||
@@ -692,11 +783,68 @@ namespace WulaFallenEmpire.EventSystem.AI.UI
|
||||
return text.Substring(0, maxChars) + "...";
|
||||
}
|
||||
|
||||
private string BuildReactTraceHeader()
|
||||
private List<string> BuildLiveTraceLines()
|
||||
{
|
||||
string state = _core != null && _core.IsThinking ? "思考中" : "已思考";
|
||||
if (_core == null) return new List<string>();
|
||||
var history = _core.GetHistorySnapshot();
|
||||
if (history == null || history.Count == 0) return new List<string>();
|
||||
|
||||
int lastUserIndex = -1;
|
||||
for (int i = history.Count - 1; i >= 0; i--)
|
||||
{
|
||||
if (history[i].role == "user")
|
||||
{
|
||||
lastUserIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (lastUserIndex == -1) return new List<string>();
|
||||
|
||||
var toolcallBuffer = new List<string>();
|
||||
var toolResultBuffer = new List<string>();
|
||||
var traceNoteBuffer = new List<string>();
|
||||
for (int i = lastUserIndex + 1; i < history.Count; i++)
|
||||
{
|
||||
var entry = history[i];
|
||||
if (entry.role == "toolcall")
|
||||
{
|
||||
toolcallBuffer.Add(entry.message ?? "");
|
||||
}
|
||||
else if (entry.role == "tool")
|
||||
{
|
||||
toolResultBuffer.Add(entry.message ?? "");
|
||||
}
|
||||
else if (entry.role == "trace")
|
||||
{
|
||||
traceNoteBuffer.Add(entry.message ?? "");
|
||||
}
|
||||
}
|
||||
|
||||
return BuildTraceLines(toolcallBuffer, toolResultBuffer, traceNoteBuffer);
|
||||
}
|
||||
|
||||
private string GetTraceHeader(int traceKey, bool isLive)
|
||||
{
|
||||
if (isLive)
|
||||
{
|
||||
return BuildReactTraceHeader(true);
|
||||
}
|
||||
|
||||
if (_traceHeaderByAssistantIndex.TryGetValue(traceKey, out string header))
|
||||
{
|
||||
return header;
|
||||
}
|
||||
|
||||
header = BuildReactTraceHeader(false);
|
||||
_traceHeaderByAssistantIndex[traceKey] = header;
|
||||
return header;
|
||||
}
|
||||
|
||||
private string BuildReactTraceHeader(bool isLive)
|
||||
{
|
||||
string state = isLive ? "思考中" : "已思考";
|
||||
float startTime = _core?.ThinkingStartTime ?? 0f;
|
||||
float elapsed = _core != null && _core.IsThinking
|
||||
float elapsed = isLive && _core != null
|
||||
? Mathf.Max(0f, Time.realtimeSinceStartup - startTime)
|
||||
: _core?.LastThinkingDuration ?? 0f;
|
||||
string elapsedText = elapsed > 0f ? elapsed.ToString("0.0", System.Globalization.CultureInfo.InvariantCulture) : "0.0";
|
||||
|
||||
@@ -99,15 +99,15 @@ namespace WulaFallenEmpire
|
||||
|
||||
listingStandard.GapLine();
|
||||
listingStandard.Label("<color=cyan>ReAct Loop Settings</color>");
|
||||
listingStandard.Label("Default Steps:");
|
||||
listingStandard.Label("Default Steps (min 1):");
|
||||
Rect stepsRect = listingStandard.GetRect(Text.LineHeight);
|
||||
Widgets.TextFieldNumeric(stepsRect, ref settings.reactMaxSteps, ref _reactMaxStepsBuffer, 1, int.MaxValue);
|
||||
|
||||
listingStandard.Label("Max Steps Limit (step_budget upper bound):");
|
||||
listingStandard.Label("Max Steps Limit (step_budget upper bound, min 1):");
|
||||
Rect stepsMaxRect = listingStandard.GetRect(Text.LineHeight);
|
||||
Widgets.TextFieldNumeric(stepsMaxRect, ref settings.reactMaxStepsMax, ref _reactMaxStepsMaxBuffer, 1, int.MaxValue);
|
||||
|
||||
listingStandard.Label("Max Seconds (2-60):");
|
||||
listingStandard.Label("Max Seconds (min 2):");
|
||||
Rect secondsRect = listingStandard.GetRect(Text.LineHeight);
|
||||
Widgets.TextFieldNumeric(secondsRect, ref settings.reactMaxSeconds, ref _reactMaxSecondsBuffer, 10f, 600f);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user