zc'
This commit is contained in:
Binary file not shown.
@@ -1,6 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8" ?>
|
|
||||||
<LanguageData>
|
|
||||||
|
|
||||||
<Wula_ResourceDrop>{FACTION_name}已经在附近投下了一些资源。</Wula_ResourceDrop>
|
|
||||||
|
|
||||||
</LanguageData>
|
|
||||||
@@ -18,6 +18,9 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "../../../../../../../../Users/Kalo/Downloads/RimTalk-main"
|
"path": "../../../../../../../../Users/Kalo/Downloads/RimTalk-main"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "../../../../../../../../Users/Kalo/Downloads/openai_token-main"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"settings": {}
|
"settings": {}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ namespace WulaFallenEmpire.EventSystem.AI
|
|||||||
private readonly string _apiKey;
|
private readonly string _apiKey;
|
||||||
private readonly string _baseUrl;
|
private readonly string _baseUrl;
|
||||||
private readonly string _model;
|
private readonly string _model;
|
||||||
|
private const int MaxLogChars = 2000;
|
||||||
|
|
||||||
public SimpleAIClient(string apiKey, string baseUrl, string model)
|
public SimpleAIClient(string apiKey, string baseUrl, string model)
|
||||||
{
|
{
|
||||||
@@ -41,28 +42,36 @@ namespace WulaFallenEmpire.EventSystem.AI
|
|||||||
jsonBuilder.Append("\"messages\": [");
|
jsonBuilder.Append("\"messages\": [");
|
||||||
|
|
||||||
// System instruction
|
// System instruction
|
||||||
|
bool firstMessage = true;
|
||||||
if (!string.IsNullOrEmpty(instruction))
|
if (!string.IsNullOrEmpty(instruction))
|
||||||
{
|
{
|
||||||
jsonBuilder.Append($"{{\"role\": \"system\", \"content\": \"{EscapeJson(instruction)}\"}},");
|
jsonBuilder.Append($"{{\"role\": \"system\", \"content\": \"{EscapeJson(instruction)}\"}}");
|
||||||
|
firstMessage = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Messages
|
// Messages
|
||||||
for (int i = 0; i < messages.Count; i++)
|
for (int i = 0; i < messages.Count; i++)
|
||||||
{
|
{
|
||||||
var msg = messages[i];
|
var msg = messages[i];
|
||||||
string role = msg.role.ToLower();
|
string role = (msg.role ?? "user").ToLowerInvariant();
|
||||||
if (role == "ai") role = "assistant";
|
if (role == "ai") role = "assistant";
|
||||||
// Map other roles if needed
|
else if (role == "tool") role = "system"; // Internal-only role; map to supported role for Chat Completions APIs.
|
||||||
|
else if (role != "system" && role != "user" && role != "assistant") role = "user";
|
||||||
|
|
||||||
|
if (!firstMessage) jsonBuilder.Append(",");
|
||||||
jsonBuilder.Append($"{{\"role\": \"{role}\", \"content\": \"{EscapeJson(msg.message)}\"}}");
|
jsonBuilder.Append($"{{\"role\": \"{role}\", \"content\": \"{EscapeJson(msg.message)}\"}}");
|
||||||
if (i < messages.Count - 1) jsonBuilder.Append(",");
|
firstMessage = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
jsonBuilder.Append("]");
|
jsonBuilder.Append("]");
|
||||||
jsonBuilder.Append("}");
|
jsonBuilder.Append("}");
|
||||||
|
|
||||||
string jsonBody = jsonBuilder.ToString();
|
string jsonBody = jsonBuilder.ToString();
|
||||||
Log.Message($"[WulaAI] Sending request to {endpoint}:\n{jsonBody}");
|
if (Prefs.DevMode)
|
||||||
|
{
|
||||||
|
Log.Message($"[WulaAI] Sending request to {endpoint} (model={_model}, messages={messages?.Count ?? 0})");
|
||||||
|
Log.Message($"[WulaAI] Request body (truncated):\n{TruncateForLog(jsonBody)}");
|
||||||
|
}
|
||||||
|
|
||||||
using (UnityWebRequest request = new UnityWebRequest(endpoint, "POST"))
|
using (UnityWebRequest request = new UnityWebRequest(endpoint, "POST"))
|
||||||
{
|
{
|
||||||
@@ -84,24 +93,57 @@ namespace WulaFallenEmpire.EventSystem.AI
|
|||||||
|
|
||||||
if (request.result == UnityWebRequest.Result.ConnectionError || request.result == UnityWebRequest.Result.ProtocolError)
|
if (request.result == UnityWebRequest.Result.ConnectionError || request.result == UnityWebRequest.Result.ProtocolError)
|
||||||
{
|
{
|
||||||
Log.Error($"[WulaAI] API Error: {request.error}\nResponse: {request.downloadHandler.text}");
|
Log.Error($"[WulaAI] API Error: {request.error}\nResponse (truncated): {TruncateForLog(request.downloadHandler.text)}");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
string responseText = request.downloadHandler.text;
|
string responseText = request.downloadHandler.text;
|
||||||
Log.Message($"[WulaAI] Raw Response: {responseText}");
|
if (Prefs.DevMode)
|
||||||
|
{
|
||||||
|
Log.Message($"[WulaAI] Raw Response (truncated): {TruncateForLog(responseText)}");
|
||||||
|
}
|
||||||
return ExtractContent(responseText);
|
return ExtractContent(responseText);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static string TruncateForLog(string s)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(s)) return s;
|
||||||
|
if (s.Length <= MaxLogChars) return s;
|
||||||
|
return s.Substring(0, MaxLogChars) + $"... (truncated, total {s.Length} chars)";
|
||||||
|
}
|
||||||
|
|
||||||
private string EscapeJson(string s)
|
private string EscapeJson(string s)
|
||||||
{
|
{
|
||||||
if (s == null) return "";
|
if (s == null) return "";
|
||||||
return s.Replace("\\", "\\\\")
|
|
||||||
.Replace("\"", "\\\"")
|
StringBuilder sb = new StringBuilder(s.Length + 16);
|
||||||
.Replace("\n", "\\n")
|
for (int i = 0; i < s.Length; i++)
|
||||||
.Replace("\r", "\\r")
|
{
|
||||||
.Replace("\t", "\\t");
|
char c = s[i];
|
||||||
|
switch (c)
|
||||||
|
{
|
||||||
|
case '\\': sb.Append("\\\\"); break;
|
||||||
|
case '"': sb.Append("\\\""); break;
|
||||||
|
case '\n': sb.Append("\\n"); break;
|
||||||
|
case '\r': sb.Append("\\r"); break;
|
||||||
|
case '\t': sb.Append("\\t"); break;
|
||||||
|
case '\b': sb.Append("\\b"); break;
|
||||||
|
case '\f': sb.Append("\\f"); break;
|
||||||
|
default:
|
||||||
|
if (c < 0x20)
|
||||||
|
{
|
||||||
|
sb.Append("\\u");
|
||||||
|
sb.Append(((int)c).ToString("x4"));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sb.Append(c);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sb.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
private string ExtractContent(string json)
|
private string ExtractContent(string json)
|
||||||
@@ -122,7 +164,7 @@ namespace WulaFallenEmpire.EventSystem.AI
|
|||||||
{
|
{
|
||||||
string dataJson = trimmedLine.Substring(6);
|
string dataJson = trimmedLine.Substring(6);
|
||||||
// Extract content from this chunk
|
// Extract content from this chunk
|
||||||
string chunkContent = ExtractJsonValue(dataJson, "content");
|
string chunkContent = TryExtractAssistantContent(dataJson) ?? ExtractJsonValue(dataJson, "content");
|
||||||
if (!string.IsNullOrEmpty(chunkContent))
|
if (!string.IsNullOrEmpty(chunkContent))
|
||||||
{
|
{
|
||||||
fullContent.Append(chunkContent);
|
fullContent.Append(chunkContent);
|
||||||
@@ -134,7 +176,7 @@ namespace WulaFallenEmpire.EventSystem.AI
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Standard non-stream format
|
// Standard non-stream format
|
||||||
return ExtractJsonValue(json, "content");
|
return TryExtractAssistantContent(json) ?? ExtractJsonValue(json, "content");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@@ -144,12 +186,109 @@ namespace WulaFallenEmpire.EventSystem.AI
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private string ExtractJsonValue(string json, string key)
|
private static string TryExtractAssistantContent(string json)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(json)) return null;
|
||||||
|
|
||||||
|
int choicesIndex = json.IndexOf("\"choices\"", StringComparison.Ordinal);
|
||||||
|
if (choicesIndex == -1) return null;
|
||||||
|
|
||||||
|
string firstChoiceJson = TryExtractFirstChoiceObject(json, choicesIndex);
|
||||||
|
if (string.IsNullOrEmpty(firstChoiceJson)) return null;
|
||||||
|
|
||||||
|
int messageIndex = firstChoiceJson.IndexOf("\"message\"", StringComparison.Ordinal);
|
||||||
|
if (messageIndex != -1)
|
||||||
|
{
|
||||||
|
return ExtractJsonValue(firstChoiceJson, "content", messageIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
int deltaIndex = firstChoiceJson.IndexOf("\"delta\"", StringComparison.Ordinal);
|
||||||
|
if (deltaIndex != -1)
|
||||||
|
{
|
||||||
|
return ExtractJsonValue(firstChoiceJson, "content", deltaIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ExtractJsonValue(firstChoiceJson, "text", 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string TryExtractFirstChoiceObject(string json, int choicesKeyIndex)
|
||||||
|
{
|
||||||
|
int arrayStart = json.IndexOf('[', choicesKeyIndex);
|
||||||
|
if (arrayStart == -1) return null;
|
||||||
|
|
||||||
|
int objStart = json.IndexOf('{', arrayStart);
|
||||||
|
if (objStart == -1) return null;
|
||||||
|
|
||||||
|
int objEnd = FindMatchingBrace(json, objStart);
|
||||||
|
if (objEnd == -1) return null;
|
||||||
|
|
||||||
|
return json.Substring(objStart, objEnd - objStart + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int FindMatchingBrace(string json, int startIndex)
|
||||||
|
{
|
||||||
|
int depth = 0;
|
||||||
|
bool inString = false;
|
||||||
|
bool escaped = false;
|
||||||
|
|
||||||
|
for (int i = startIndex; i < json.Length; i++)
|
||||||
|
{
|
||||||
|
char c = json[i];
|
||||||
|
if (inString)
|
||||||
|
{
|
||||||
|
if (escaped)
|
||||||
|
{
|
||||||
|
escaped = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c == '\\')
|
||||||
|
{
|
||||||
|
escaped = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c == '"')
|
||||||
|
{
|
||||||
|
inString = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c == '"')
|
||||||
|
{
|
||||||
|
inString = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c == '{')
|
||||||
|
{
|
||||||
|
depth++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c == '}')
|
||||||
|
{
|
||||||
|
depth--;
|
||||||
|
if (depth == 0) return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string ExtractJsonValue(string json, string key)
|
||||||
{
|
{
|
||||||
// Simple parser to find "key": "value"
|
// Simple parser to find "key": "value"
|
||||||
// This is not a full JSON parser and assumes standard formatting
|
// This is not a full JSON parser and assumes standard formatting
|
||||||
|
return ExtractJsonValue(json, key, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string ExtractJsonValue(string json, string key, int startIndex)
|
||||||
|
{
|
||||||
string keyPattern = $"\"{key}\"";
|
string keyPattern = $"\"{key}\"";
|
||||||
int keyIndex = json.IndexOf(keyPattern);
|
int keyIndex = json.IndexOf(keyPattern, startIndex, StringComparison.Ordinal);
|
||||||
if (keyIndex == -1) return null;
|
if (keyIndex == -1) return null;
|
||||||
|
|
||||||
// Find the colon after the key
|
// Find the colon after the key
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using RimWorld;
|
using RimWorld;
|
||||||
@@ -90,16 +91,24 @@ namespace WulaFallenEmpire.EventSystem.AI.Tools
|
|||||||
|
|
||||||
if (itemsToSpawn.Count == 0)
|
if (itemsToSpawn.Count == 0)
|
||||||
{
|
{
|
||||||
return "Error: No valid items found in request. Usage: <spawn_resources><items><item><name>...</name><count>...</count></item></items></spawn_resources>";
|
string msg = "Error: No valid items found in request. Usage: <spawn_resources><items><item><name>...</name><count>...</count></item></items></spawn_resources>";
|
||||||
|
Messages.Message(msg, MessageTypeDefOf.RejectInput);
|
||||||
|
return msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
Map map = Find.CurrentMap;
|
Map map = GetTargetMap();
|
||||||
if (map == null)
|
if (map == null)
|
||||||
{
|
{
|
||||||
return "Error: No active map.";
|
string msg = "Error: No active map.";
|
||||||
|
Messages.Message(msg, MessageTypeDefOf.RejectInput);
|
||||||
|
return msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
IntVec3 dropSpot = DropCellFinder.TradeDropSpot(map);
|
IntVec3 dropSpot = DropCellFinder.TradeDropSpot(map);
|
||||||
|
if (!dropSpot.IsValid || !dropSpot.InBounds(map))
|
||||||
|
{
|
||||||
|
dropSpot = DropCellFinder.RandomDropSpot(map);
|
||||||
|
}
|
||||||
List<Thing> thingsToDrop = new List<Thing>();
|
List<Thing> thingsToDrop = new List<Thing>();
|
||||||
StringBuilder resultLog = new StringBuilder();
|
StringBuilder resultLog = new StringBuilder();
|
||||||
resultLog.Append("Success: Dropped ");
|
resultLog.Append("Success: Dropped ");
|
||||||
@@ -114,27 +123,60 @@ namespace WulaFallenEmpire.EventSystem.AI.Tools
|
|||||||
|
|
||||||
if (thingsToDrop.Count > 0)
|
if (thingsToDrop.Count > 0)
|
||||||
{
|
{
|
||||||
DropPodUtility.DropThingsNear(dropSpot, map, thingsToDrop);
|
// If the conversation window pauses the game, incoming drop pods may not "land" until unpaused.
|
||||||
|
// To keep this tool reliable, place items immediately when paused; otherwise, use drop pods.
|
||||||
Faction faction = Find.FactionManager.FirstFactionOfDef(FactionDef.Named("Wula_PIA_Legion_Faction"));
|
bool isPaused = Find.TickManager != null && Find.TickManager.Paused;
|
||||||
if (faction != null)
|
if (isPaused)
|
||||||
{
|
{
|
||||||
Messages.Message("Wula_ResourceDrop".Translate(faction.def.defName.Named("FACTION_name")), new LookTargets(dropSpot, map), MessageTypeDefOf.PositiveEvent);
|
foreach (var thing in thingsToDrop)
|
||||||
|
{
|
||||||
|
GenPlace.TryPlaceThing(thing, dropSpot, map, ThingPlaceMode.Near);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DropPodUtility.DropThingsNear(dropSpot, map, thingsToDrop);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Faction faction = Find.FactionManager.FirstFactionOfDef(FactionDef.Named("Wula_PIA_Legion_Faction"));
|
||||||
|
string letterText = faction != null
|
||||||
|
? "Wula_ResourceDrop".Translate(faction.def.defName.Named("FACTION_name"))
|
||||||
|
: "Wula_ResourceDrop".Translate("Unknown".Named("FACTION_name"));
|
||||||
|
Messages.Message(letterText, new LookTargets(dropSpot, map), MessageTypeDefOf.PositiveEvent);
|
||||||
|
|
||||||
resultLog.Length -= 2; // Remove trailing comma
|
resultLog.Length -= 2; // Remove trailing comma
|
||||||
resultLog.Append($" at {dropSpot}.");
|
resultLog.Append($" at {dropSpot}. {(isPaused ? "(placed immediately because game is paused)" : "(drop pods inbound)")}");
|
||||||
return resultLog.ToString();
|
return resultLog.ToString();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return "Error: Failed to create items.";
|
string msg = "Error: Failed to create items.";
|
||||||
|
Messages.Message(msg, MessageTypeDefOf.RejectInput);
|
||||||
|
return msg;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
return $"Error: {ex.Message}";
|
string msg = $"Error: {ex.Message}";
|
||||||
}
|
Messages.Message(msg, MessageTypeDefOf.RejectInput);
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Map GetTargetMap()
|
||||||
|
{
|
||||||
|
Map map = Find.CurrentMap;
|
||||||
|
if (map != null) return map;
|
||||||
|
|
||||||
|
if (Find.Maps != null)
|
||||||
|
{
|
||||||
|
Map homeMap = Find.Maps.FirstOrDefault(m => m != null && m.IsPlayerHome);
|
||||||
|
if (homeMap != null) return homeMap;
|
||||||
|
|
||||||
|
if (Find.Maps.Count > 0) return Find.Maps[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -228,6 +228,19 @@ When the player requests any form of resources, you MUST follow this multi-turn
|
|||||||
StartConversation();
|
StartConversation();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void PersistHistory()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var historyManager = Find.World?.GetComponent<AIHistoryManager>();
|
||||||
|
historyManager?.SaveHistory(def.defName, _history);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Error($"[WulaAI] Failed to persist AI history: {ex}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void LoadPortraits()
|
private void LoadPortraits()
|
||||||
{
|
{
|
||||||
for (int i = 1; i <= 6; i++)
|
for (int i = 1; i <= 6; i++)
|
||||||
@@ -281,6 +294,7 @@ When the player requests any form of resources, you MUST follow this multi-turn
|
|||||||
if (_history.Count == 0)
|
if (_history.Count == 0)
|
||||||
{
|
{
|
||||||
_history.Add(("user", "Hello"));
|
_history.Add(("user", "Hello"));
|
||||||
|
PersistHistory();
|
||||||
await GenerateResponse();
|
await GenerateResponse();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -379,6 +393,7 @@ When the player requests any form of resources, you MUST follow this multi-turn
|
|||||||
{
|
{
|
||||||
_history.RemoveRange(0, removeCount);
|
_history.RemoveRange(0, removeCount);
|
||||||
_history.Insert(0, ("system", "[Previous conversation summarized]"));
|
_history.Insert(0, ("system", "[Previous conversation summarized]"));
|
||||||
|
PersistHistory();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -422,8 +437,17 @@ When the player requests any form of resources, you MUST follow this multi-turn
|
|||||||
argsXml = contentMatch.Groups[1].Value;
|
argsXml = contentMatch.Groups[1].Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Prefs.DevMode)
|
||||||
|
{
|
||||||
Log.Message($"[WulaAI] Executing tool: {toolName} with args: {argsXml}");
|
Log.Message($"[WulaAI] Executing tool: {toolName} with args: {argsXml}");
|
||||||
|
}
|
||||||
|
|
||||||
string result = tool.Execute(argsXml).Trim();
|
string result = tool.Execute(argsXml).Trim();
|
||||||
|
if (Prefs.DevMode && !string.IsNullOrEmpty(result))
|
||||||
|
{
|
||||||
|
string toLog = result.Length <= 2000 ? result : result.Substring(0, 2000) + $"... (truncated, total {result.Length} chars)";
|
||||||
|
Log.Message($"[WulaAI] Tool '{toolName}' result: {toLog}");
|
||||||
|
}
|
||||||
|
|
||||||
if (toolName == "modify_goodwill")
|
if (toolName == "modify_goodwill")
|
||||||
{
|
{
|
||||||
@@ -436,9 +460,9 @@ When the player requests any form of resources, you MUST follow this multi-turn
|
|||||||
}
|
}
|
||||||
|
|
||||||
_history.Add(("assistant", xml));
|
_history.Add(("assistant", xml));
|
||||||
// Use role "user" for tool results to avoid API errors about tool_calls format.
|
// Persist tool results with a dedicated role; the API request maps this role to a supported one.
|
||||||
// This is safe and won't break AI logic, as the AI still sees the result clearly.
|
_history.Add(("tool", $"[Tool Results]\n{combinedResults.ToString().Trim()}"));
|
||||||
_history.Add(("user", $"[Tool Results]\n{combinedResults.ToString().Trim()}"));
|
PersistHistory();
|
||||||
|
|
||||||
// Check if there is any text content in the response
|
// Check if there is any text content in the response
|
||||||
string textContent = Regex.Replace(xml, @"<([a-zA-Z0-9_]+)(?:>.*?</\1>|/>)", "", RegexOptions.Singleline).Trim();
|
string textContent = Regex.Replace(xml, @"<([a-zA-Z0-9_]+)(?:>.*?</\1>|/>)", "", RegexOptions.Singleline).Trim();
|
||||||
@@ -460,6 +484,7 @@ When the player requests any form of resources, you MUST follow this multi-turn
|
|||||||
{
|
{
|
||||||
Log.Error($"[WulaAI] Exception in HandleXmlToolUsage: {ex}");
|
Log.Error($"[WulaAI] Exception in HandleXmlToolUsage: {ex}");
|
||||||
_history.Add(("tool", $"Error processing tool call: {ex.Message}"));
|
_history.Add(("tool", $"Error processing tool call: {ex.Message}"));
|
||||||
|
PersistHistory();
|
||||||
await GenerateResponse(isContinuation: true);
|
await GenerateResponse(isContinuation: true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -473,6 +498,7 @@ When the player requests any form of resources, you MUST follow this multi-turn
|
|||||||
if (_history.Count == 0 || _history.Last().role != "assistant" || _history.Last().message != rawResponse)
|
if (_history.Count == 0 || _history.Last().role != "assistant" || _history.Last().message != rawResponse)
|
||||||
{
|
{
|
||||||
_history.Add(("assistant", rawResponse));
|
_history.Add(("assistant", rawResponse));
|
||||||
|
PersistHistory();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -563,7 +589,9 @@ When the player requests any form of resources, you MUST follow this multi-turn
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
float viewHeight = 0f;
|
float viewHeight = 0f;
|
||||||
var filteredHistory = _history.Where(e => e.role != "tool" && e.role != "system").ToList();
|
var filteredHistory = _history
|
||||||
|
.Where(e => e.role != "system" && (Prefs.DevMode || e.role != "tool"))
|
||||||
|
.ToList();
|
||||||
// Pre-calculate height
|
// Pre-calculate height
|
||||||
for (int i = 0; i < filteredHistory.Count; i++)
|
for (int i = 0; i < filteredHistory.Count; i++)
|
||||||
{
|
{
|
||||||
@@ -603,7 +631,7 @@ When the player requests any form of resources, you MUST follow this multi-turn
|
|||||||
if (entry.role == "user")
|
if (entry.role == "user")
|
||||||
{
|
{
|
||||||
Text.Anchor = TextAnchor.MiddleRight;
|
Text.Anchor = TextAnchor.MiddleRight;
|
||||||
Widgets.Label(labelRect, $"<color=#add8e6>{text} :你</color>");
|
Widgets.Label(labelRect, $"<color=#add8e6>{text}</color>");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -707,6 +735,7 @@ When the player requests any form of resources, you MUST follow this multi-turn
|
|||||||
private async void SelectOption(string text)
|
private async void SelectOption(string text)
|
||||||
{
|
{
|
||||||
_history.Add(("user", text));
|
_history.Add(("user", text));
|
||||||
|
PersistHistory();
|
||||||
_scrollToBottom = true;
|
_scrollToBottom = true;
|
||||||
await GenerateResponse();
|
await GenerateResponse();
|
||||||
}
|
}
|
||||||
@@ -714,6 +743,7 @@ When the player requests any form of resources, you MUST follow this multi-turn
|
|||||||
public override void PostClose()
|
public override void PostClose()
|
||||||
{
|
{
|
||||||
if (Instance == this) Instance = null;
|
if (Instance == this) Instance = null;
|
||||||
|
PersistHistory();
|
||||||
base.PostClose();
|
base.PostClose();
|
||||||
HandleAction(def.dismissEffects);
|
HandleAction(def.dismissEffects);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user