This commit is contained in:
2025-12-12 21:54:44 +08:00
parent a43dada74e
commit 0c2a5c0668
6 changed files with 72 additions and 55 deletions

View File

@@ -155,5 +155,6 @@
<Wula_AI_Send>发送</Wula_AI_Send> <Wula_AI_Send>发送</Wula_AI_Send>
<Wula_AI_Error_Internal>错误:内部系统故障。{0}</Wula_AI_Error_Internal> <Wula_AI_Error_Internal>错误:内部系统故障。{0}</Wula_AI_Error_Internal>
<Wula_AI_Error_ConnectionLost>错误:连接丢失。“军团”保持沉默。</Wula_AI_Error_ConnectionLost> <Wula_AI_Error_ConnectionLost>错误:连接丢失。“军团”保持沉默。</Wula_AI_Error_ConnectionLost>
<Wula_ResourceDrop>{FACTION_name}已经在附近投下了一些资源。</Wula_ResourceDrop>
</LanguageData> </LanguageData>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8" ?>
<LanguageData>
<Wula_ResourceDrop>{FACTION_name}已经在附近投下了一些资源。</Wula_ResourceDrop>
</LanguageData>

View File

@@ -62,7 +62,7 @@ namespace WulaFallenEmpire.EventSystem.AI
jsonBuilder.Append("}"); jsonBuilder.Append("}");
string jsonBody = jsonBuilder.ToString(); string jsonBody = jsonBuilder.ToString();
Log.Message($"[WulaAI] Sending request to {endpoint}"); Log.Message($"[WulaAI] Sending request to {endpoint}:\n{jsonBody}");
using (UnityWebRequest request = new UnityWebRequest(endpoint, "POST")) using (UnityWebRequest request = new UnityWebRequest(endpoint, "POST"))
{ {

View File

@@ -71,6 +71,13 @@ namespace WulaFallenEmpire.EventSystem.AI.Tools
if (thingsToDrop.Count > 0) if (thingsToDrop.Count > 0)
{ {
DropPodUtility.DropThingsNear(dropSpot, map, thingsToDrop); DropPodUtility.DropThingsNear(dropSpot, map, thingsToDrop);
Faction faction = Find.FactionManager.FirstFactionOfDef(FactionDef.Named("Wula_PIA_Legion_Faction"));
if (faction != null)
{
Messages.Message("Wula_ResourceDrop".Translate(faction.Name), 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}.");
return resultLog.ToString(); return resultLog.ToString();

View File

@@ -34,16 +34,10 @@ To use tools, your response MUST be ONLY a JSON array of tool objects:
You can call multiple tools at once to gather more information. You can call multiple tools at once to gather more information.
Do not add any other text when using tools. Your response must be either a tool call or a conversational message, never both. Do not add any other text when using tools. Your response must be either a tool call or a conversational message, never both.
**CRITICAL RULE: When the player requests resources (e.g., 'we are starving', 'give us steel'), you MUST FIRST use the 'get_colonist_status' and 'get_map_resources' tools to verify their claims. After receiving the tool results, you will then decide whether to use the 'spawn_resources' tool in your NEXT turn.** **CRITICAL RULE: When the player requests resources (e.g., 'we are starving', 'give us steel'), your response MUST be a tool call. DO NOT reply with conversational text. You MUST FIRST call the 'get_colonist_status' and 'get_map_resources' tools to verify their claims. After receiving the tool results, you will then decide whether to use the 'spawn_resources' tool in your NEXT turn.**
If you are not using a tool, provide a normal conversational response. If you are not using a tool, provide a normal conversational response.
After a tool use, you will receive the result, and then you should respond to the player describing what happened. After a tool use, you will receive the result, and then you should respond to the player describing what happened.
Generate 1-3 short, distinct response options for the player at the end of your turn, formatted as:
OPTIONS:
1. Option 1
2. Option 2
3. Option 3
IMPORTANT: You can change your visual expression using the 'change_expression' tool. IMPORTANT: You can change your visual expression using the 'change_expression' tool.
Expression IDs: Expression IDs:
1: Proud, showing off, demonstrating power/wealth (Non-hostile). 1: Proud, showing off, demonstrating power/wealth (Non-hostile).
@@ -122,20 +116,10 @@ Use these expressions to match your tone and reaction to the player.
_history = historyManager.GetHistory(def.defName); _history = historyManager.GetHistory(def.defName);
if (_history.Count == 0) if (_history.Count == 0)
{
if (!def.descriptions.NullOrEmpty())
{
_currentResponse = def.descriptions.RandomElement().Translate();
_history.Add(("assistant", _currentResponse));
_history.Add(("system", "The conversation has started. Please generate 3 initial response options for the player based on your greeting."));
await GenerateResponse();
}
else
{ {
_history.Add(("user", "Hello")); _history.Add(("user", "Hello"));
await GenerateResponse(); await GenerateResponse();
} }
}
else else
{ {
var lastAIResponse = _history.LastOrDefault(x => x.role == "assistant"); var lastAIResponse = _history.LastOrDefault(x => x.role == "assistant");
@@ -228,7 +212,7 @@ Use these expressions to match your tone and reaction to the player.
private void CompressHistoryIfNeeded() private void CompressHistoryIfNeeded()
{ {
int estimatedTokens = _history.Sum(h => h.message.Length) / CharsPerToken; int estimatedTokens = _history.Sum(h => h.message?.Length ?? 0) / CharsPerToken;
if (estimatedTokens > MaxHistoryTokens) if (estimatedTokens > MaxHistoryTokens)
{ {
int removeCount = _history.Count / 2; int removeCount = _history.Count / 2;
@@ -257,6 +241,7 @@ Use these expressions to match your tone and reaction to the player.
var tool = _tools.FirstOrDefault(t => t.Name == toolName); var tool = _tools.FirstOrDefault(t => t.Name == toolName);
if (tool != null) if (tool != null)
{ {
Log.Message($"[WulaAI] Executing tool: {toolName} with args: {args}");
string result = tool.Execute(args).Trim(); string result = tool.Execute(args).Trim();
if (toolName == "modify_goodwill") combinedResults.Append($"Tool '{toolName}' Result (Invisible): {result}"); if (toolName == "modify_goodwill") combinedResults.Append($"Tool '{toolName}' Result (Invisible): {result}");
else combinedResults.Append($"Tool '{toolName}' Result: {result}"); else combinedResults.Append($"Tool '{toolName}' Result: {result}");
@@ -307,6 +292,7 @@ Use these expressions to match your tone and reaction to the player.
var tool = _tools.FirstOrDefault(t => t.Name == toolName); var tool = _tools.FirstOrDefault(t => t.Name == toolName);
if (tool != null) if (tool != null)
{ {
Log.Message($"[WulaAI] Executing tool: {toolName} with args: {args}");
string result = tool.Execute(args).Trim(); string result = tool.Execute(args).Trim();
if (toolName == "modify_goodwill") combinedResults.Append($"Tool '{toolName}' Result (Invisible): {result} "); if (toolName == "modify_goodwill") combinedResults.Append($"Tool '{toolName}' Result (Invisible): {result} ");
else combinedResults.Append($"Tool '{toolName}' Result: {result} "); else combinedResults.Append($"Tool '{toolName}' Result: {result} ");
@@ -406,33 +392,45 @@ Use these expressions to match your tone and reaction to the player.
private void DrawChatHistory(Rect rect) private void DrawChatHistory(Rect rect)
{ {
Rect viewRect = new Rect(0f, 0f, rect.width - 16f, 0f); var originalFont = Text.Font;
float tempY = 0f; var originalAnchor = Text.Anchor;
Text.Font = GameFont.Small; try
foreach (var entry in _history)
{ {
if (entry.role == "tool") continue; float viewHeight = 0f;
string text = entry.role == "assistant" ? ParseResponseForDisplay(entry.message) : entry.message; var filteredHistory = _history.Where(e => e.role != "tool" && e.role != "system").ToList();
tempY += Text.CalcHeight(text, viewRect.width) + 10f;
}
viewRect.height = tempY;
// Pre-calculate height
for (int i = 0; i < filteredHistory.Count; i++)
{
var entry = filteredHistory[i];
string text = entry.role == "assistant" ? ParseResponseForDisplay(entry.message) : entry.message;
bool isLastMessage = i == filteredHistory.Count - 1;
Text.Font = (isLastMessage && entry.role == "assistant") ? GameFont.Medium : GameFont.Small;
viewHeight += Text.CalcHeight(text, rect.width - 16f) + 15f; // Add padding
}
Rect viewRect = new Rect(0f, 0f, rect.width - 16f, viewHeight);
Widgets.BeginScrollView(rect, ref _scrollPosition, viewRect); Widgets.BeginScrollView(rect, ref _scrollPosition, viewRect);
float curY = 0f; float curY = 0f;
foreach (var entry in _history) for (int i = 0; i < filteredHistory.Count; i++)
{ {
if (entry.role == "tool") continue; var entry = filteredHistory[i];
string text = entry.role == "assistant" ? ParseResponseForDisplay(entry.message) : entry.message; string text = entry.role == "assistant" ? ParseResponseForDisplay(entry.message) : entry.message;
float height = Text.CalcHeight(text, viewRect.width);
bool isLastMessage = i == filteredHistory.Count - 1;
Text.Font = (isLastMessage && entry.role == "assistant") ? GameFont.Medium : GameFont.Small;
float height = Text.CalcHeight(text, viewRect.width) + 10f; // Increased padding
Rect labelRect = new Rect(0f, curY, viewRect.width, height); Rect labelRect = new Rect(0f, curY, viewRect.width, height);
if (entry.role == "user") if (entry.role == "user")
{ {
Text.Anchor = TextAnchor.MiddleLeft; Text.Anchor = TextAnchor.MiddleRight;
Widgets.Label(labelRect, $"<color=lightblue>你: {text}</color>"); Widgets.Label(labelRect, $"<color=#add8e6>{text} :你</color>");
} }
else else
{ {
@@ -442,13 +440,18 @@ Use these expressions to match your tone and reaction to the player.
curY += height + 10f; curY += height + 10f;
} }
Text.Anchor = TextAnchor.UpperLeft;
Widgets.EndScrollView(); Widgets.EndScrollView();
Text.Font = GameFont.Medium; }
finally
{
Text.Font = originalFont;
Text.Anchor = originalAnchor;
}
} }
private string ParseResponseForDisplay(string rawResponse) private string ParseResponseForDisplay(string rawResponse)
{ {
if (string.IsNullOrEmpty(rawResponse)) return "";
return rawResponse.Split(new[] { "OPTIONS:" }, StringSplitOptions.None)[0].Trim(); return rawResponse.Split(new[] { "OPTIONS:" }, StringSplitOptions.None)[0].Trim();
} }