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_Error_Internal>错误:内部系统故障。{0}</Wula_AI_Error_Internal>
<Wula_AI_Error_ConnectionLost>错误:连接丢失。“军团”保持沉默。</Wula_AI_Error_ConnectionLost>
<Wula_ResourceDrop>{FACTION_name}已经在附近投下了一些资源。</Wula_ResourceDrop>
</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("}");
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"))
{

View File

@@ -71,6 +71,13 @@ namespace WulaFallenEmpire.EventSystem.AI.Tools
if (thingsToDrop.Count > 0)
{
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.Append($" at {dropSpot}.");
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.
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.
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.
Expression IDs:
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);
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"));
await GenerateResponse();
}
}
else
{
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()
{
int estimatedTokens = _history.Sum(h => h.message.Length) / CharsPerToken;
int estimatedTokens = _history.Sum(h => h.message?.Length ?? 0) / CharsPerToken;
if (estimatedTokens > MaxHistoryTokens)
{
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);
if (tool != null)
{
Log.Message($"[WulaAI] Executing tool: {toolName} with args: {args}");
string result = tool.Execute(args).Trim();
if (toolName == "modify_goodwill") combinedResults.Append($"Tool '{toolName}' Result (Invisible): {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);
if (tool != null)
{
Log.Message($"[WulaAI] Executing tool: {toolName} with args: {args}");
string result = tool.Execute(args).Trim();
if (toolName == "modify_goodwill") combinedResults.Append($"Tool '{toolName}' Result (Invisible): {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)
{
Rect viewRect = new Rect(0f, 0f, rect.width - 16f, 0f);
float tempY = 0f;
var originalFont = Text.Font;
var originalAnchor = Text.Anchor;
Text.Font = GameFont.Small;
foreach (var entry in _history)
try
{
if (entry.role == "tool") continue;
string text = entry.role == "assistant" ? ParseResponseForDisplay(entry.message) : entry.message;
tempY += Text.CalcHeight(text, viewRect.width) + 10f;
}
viewRect.height = tempY;
float viewHeight = 0f;
var filteredHistory = _history.Where(e => e.role != "tool" && e.role != "system").ToList();
// 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);
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;
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);
if (entry.role == "user")
{
Text.Anchor = TextAnchor.MiddleLeft;
Widgets.Label(labelRect, $"<color=lightblue>你: {text}</color>");
Text.Anchor = TextAnchor.MiddleRight;
Widgets.Label(labelRect, $"<color=#add8e6>{text} :你</color>");
}
else
{
@@ -442,13 +440,18 @@ Use these expressions to match your tone and reaction to the player.
curY += height + 10f;
}
Text.Anchor = TextAnchor.UpperLeft;
Widgets.EndScrollView();
Text.Font = GameFont.Medium;
}
finally
{
Text.Font = originalFont;
Text.Anchor = originalAnchor;
}
}
private string ParseResponseForDisplay(string rawResponse)
{
if (string.IsNullOrEmpty(rawResponse)) return "";
return rawResponse.Split(new[] { "OPTIONS:" }, StringSplitOptions.None)[0].Trim();
}