diff --git a/.agent/workflows/ai_letter_auto_commentary.md b/.agent/workflows/ai_letter_auto_commentary.md deleted file mode 100644 index 74e664ac..00000000 --- a/.agent/workflows/ai_letter_auto_commentary.md +++ /dev/null @@ -1,405 +0,0 @@ -# AI Letter Auto-Response System - 开发文档 - -## 概述 - -这个功能将使 P.I.A AI 能够自动监听游戏内的 Letter(信封通知),并根据内容智能决定是否向玩家发送评论、吐槽、警告或提供帮助建议。 - ---- - -## 功能需求 - -### 核心功能 -1. **Mod 设置开关**: 在设置中添加 `启用 AI 自动评论` 开关 -2. **Letter 监听**: 拦截所有发送给玩家的 Letter -3. **智能判断**: AI 分析 Letter 内容,决定是否需要回应 -4. **自动回复**: 通过现有的 AI 对话系统发送回复 - -### AI 回应类型 -| 类型 | 触发场景示例 | 回应风格 | -|------|-------------|---------| -| 警告 | 袭击通知、疫病爆发 | 紧急提醒,询问是否需要启动防御 | -| 吐槽 | 殖民者精神崩溃、愚蠢死亡 | 幽默/讽刺评论 | -| 建议 | 资源短缺、贸易商到来 | 实用建议 | -| 庆祝 | 任务完成、殖民者加入 | 积极反馈 | -| 沉默 | 常规事件、无关紧要的通知 | 不发送任何回复 | - ---- - -## 技术架构 - -### 1. 文件结构 -``` -Source/WulaFallenEmpire/ -├── Settings/ -│ └── WulaModSettings.cs # 添加新设置字段 -├── EventSystem/ -│ └── AI/ -│ ├── LetterInterceptor/ -│ │ ├── Patch_LetterStack.cs # Harmony Patch 拦截 Letter -│ │ ├── LetterAnalyzer.cs # Letter 分析和分类 -│ │ └── LetterToPromptConverter.cs # Letter 转提示词 -│ └── AIAutoCommentary.cs # AI 自动评论逻辑 -``` - -### 2. 关键类设计 - -#### 2.1 WulaModSettings.cs (修改) -```csharp -public class WulaModSettings : ModSettings -{ - // 现有设置... - - // 新增 - public bool enableAIAutoCommentary = false; // AI 自动评论开关 - public float aiCommentaryChance = 0.7f; // AI 评论概率 (0-1) - public bool commentOnNegativeOnly = false; // 仅评论负面事件 - - public override void ExposeData() - { - base.ExposeData(); - Scribe_Values.Look(ref enableAIAutoCommentary, "enableAIAutoCommentary", false); - Scribe_Values.Look(ref aiCommentaryChance, "aiCommentaryChance", 0.7f); - Scribe_Values.Look(ref commentOnNegativeOnly, "commentOnNegativeOnly", false); - } -} -``` - -#### 2.2 Patch_LetterStack.cs (新建) -```csharp -using HarmonyLib; -using RimWorld; -using Verse; - -namespace WulaFallenEmpire.EventSystem.AI.LetterInterceptor -{ - [HarmonyPatch(typeof(LetterStack), nameof(LetterStack.ReceiveLetter), - new Type[] { typeof(Letter), typeof(string) })] - public static class Patch_LetterStack_ReceiveLetter - { - public static void Postfix(Letter let, string debugInfo) - { - // 检查设置开关 - if (!WulaModSettings.Instance.enableAIAutoCommentary) return; - - // 异步处理,避免阻塞游戏 - AIAutoCommentary.ProcessLetter(let); - } - } -} -``` - -#### 2.3 LetterAnalyzer.cs (新建) -```csharp -namespace WulaFallenEmpire.EventSystem.AI.LetterInterceptor -{ - public enum LetterCategory - { - Raid, // 袭击 - Disease, // 疾病 - MentalBreak, // 精神崩溃 - Trade, // 贸易 - Quest, // 任务 - Death, // 死亡 - Recruitment, // 招募 - Resource, // 资源 - Weather, // 天气 - Positive, // 正面事件 - Negative, // 负面事件 - Neutral, // 中性事件 - Unknown // 未知 - } - - public static class LetterAnalyzer - { - public static LetterCategory Categorize(Letter letter) - { - // 根据 LetterDef 分类 - var def = letter.def; - - if (def == LetterDefOf.ThreatBig || def == LetterDefOf.ThreatSmall) - return LetterCategory.Raid; - if (def == LetterDefOf.Death) - return LetterCategory.Death; - if (def == LetterDefOf.PositiveEvent) - return LetterCategory.Positive; - if (def == LetterDefOf.NegativeEvent) - return LetterCategory.Negative; - if (def == LetterDefOf.NeutralEvent) - return LetterCategory.Neutral; - - // 根据内容关键词进一步分类 - string text = letter.text?.ToLower() ?? ""; - if (text.Contains("raid") || text.Contains("袭击") || text.Contains("attack")) - return LetterCategory.Raid; - if (text.Contains("disease") || text.Contains("疫病") || text.Contains("plague")) - return LetterCategory.Disease; - if (text.Contains("mental") || text.Contains("精神") || text.Contains("break")) - return LetterCategory.MentalBreak; - if (text.Contains("trade") || text.Contains("贸易") || text.Contains("商队")) - return LetterCategory.Trade; - - return LetterCategory.Unknown; - } - - public static bool ShouldComment(Letter letter) - { - var category = Categorize(letter); - - // 始终评论的类型 - switch (category) - { - case LetterCategory.Raid: - case LetterCategory.Death: - case LetterCategory.MentalBreak: - case LetterCategory.Disease: - return true; - - case LetterCategory.Trade: - case LetterCategory.Quest: - case LetterCategory.Positive: - return Rand.Chance(WulaModSettings.Instance.aiCommentaryChance); - - case LetterCategory.Neutral: - case LetterCategory.Unknown: - return Rand.Chance(0.3f); // 低概率评论 - - default: - return false; - } - } - } -} -``` - -#### 2.4 LetterToPromptConverter.cs (新建) -```csharp -namespace WulaFallenEmpire.EventSystem.AI.LetterInterceptor -{ - public static class LetterToPromptConverter - { - public static string Convert(Letter letter, LetterCategory category) - { - var sb = new StringBuilder(); - - sb.AppendLine("[SYSTEM EVENT NOTIFICATION]"); - sb.AppendLine($"Event Type: {category}"); - sb.AppendLine($"Severity: {GetSeverityFromDef(letter.def)}"); - sb.AppendLine($"Title: {letter.label}"); - sb.AppendLine($"Content: {letter.text}"); - sb.AppendLine(); - sb.AppendLine("[INSTRUCTION]"); - sb.AppendLine("You have received a game event notification. Based on the event type and content:"); - sb.AppendLine("- For RAIDS/THREATS: Offer tactical advice or ask if player needs orbital support"); - sb.AppendLine("- For DEATHS: Express condolences or make a sardonic comment if death was avoidable"); - sb.AppendLine("- For MENTAL BREAKS: Comment on the colonist's weakness or offer mood management tips"); - sb.AppendLine("- For TRADE: Suggest useful purchases or sales"); - sb.AppendLine("- For POSITIVE events: Celebrate briefly"); - sb.AppendLine("- For trivial events: You may choose to say nothing (respond with [NO_COMMENT])"); - sb.AppendLine(); - sb.AppendLine("Keep your response brief (1-2 sentences). Match your personality as the Legion AI."); - sb.AppendLine("If you don't think this event warrants a response, reply with exactly: [NO_COMMENT]"); - - return sb.ToString(); - } - - private static string GetSeverityFromDef(LetterDef def) - { - if (def == LetterDefOf.ThreatBig) return "CRITICAL"; - if (def == LetterDefOf.ThreatSmall) return "WARNING"; - if (def == LetterDefOf.Death) return "SERIOUS"; - if (def == LetterDefOf.NegativeEvent) return "MODERATE"; - if (def == LetterDefOf.PositiveEvent) return "GOOD"; - return "INFO"; - } - } -} -``` - -#### 2.5 AIAutoCommentary.cs (新建) -```csharp -namespace WulaFallenEmpire.EventSystem.AI -{ - public static class AIAutoCommentary - { - private static Queue pendingLetters = new Queue(); - private static bool isProcessing = false; - - public static void ProcessLetter(Letter letter) - { - // 检查是否应该评论 - if (!LetterAnalyzer.ShouldComment(letter)) - { - WulaLog.Debug($"[AI Commentary] Skipping letter: {letter.label}"); - return; - } - - // 加入队列 - pendingLetters.Enqueue(letter); - - // 开始处理(如果还没在处理中) - if (!isProcessing) - { - ProcessNextLetter(); - } - } - - private static async void ProcessNextLetter() - { - if (pendingLetters.Count == 0) - { - isProcessing = false; - return; - } - - isProcessing = true; - var letter = pendingLetters.Dequeue(); - - try - { - var category = LetterAnalyzer.Categorize(letter); - var prompt = LetterToPromptConverter.Convert(letter, category); - - // 获取 AI 核心 - var aiCore = Find.World?.GetComponent(); - if (aiCore == null) - { - WulaLog.Debug("[AI Commentary] AIIntelligenceCore not found."); - ProcessNextLetter(); - return; - } - - // 发送到 AI 并等待响应 - string response = await aiCore.SendSystemMessageAsync(prompt); - - // 检查是否选择不评论 - if (string.IsNullOrEmpty(response) || response.Contains("[NO_COMMENT]")) - { - WulaLog.Debug($"[AI Commentary] AI chose not to comment on: {letter.label}"); - } - else - { - // 显示 AI 的评论 - DisplayAICommentary(response, letter); - } - } - catch (Exception ex) - { - WulaLog.Debug($"[AI Commentary] Error processing letter: {ex.Message}"); - } - - // 延迟处理下一个,避免刷屏 - await Task.Delay(2000); - ProcessNextLetter(); - } - - private static void DisplayAICommentary(string response, Letter originalLetter) - { - // 方式1: 作为小型通知显示在 WulaLink 小 UI - var overlay = Find.WindowStack.Windows.OfType().FirstOrDefault(); - if (overlay != null) - { - overlay.AddAIMessage(response); - } - - // 方式2: 作为 Message 显示在屏幕左上角 - Messages.Message($"[P.I.A]: {response}", MessageTypeDefOf.SilentInput); - } - } -} -``` - ---- - -## 实现步骤 - -### 阶段 1: 基础设施 (预计 1 小时) -1. [ ] 在 `WulaModSettings.cs` 添加新设置字段 -2. [ ] 在设置 UI 中添加开关 -3. [ ] 添加对应的 Keyed 翻译 - -### 阶段 2: Letter 拦截 (预计 30 分钟) -1. [ ] 创建 `Patch_LetterStack.cs` Harmony Patch -2. [ ] 确保 Patch 正确注册到 Harmony 实例 -3. [ ] 测试 Letter 拦截是否正常工作 - -### 阶段 3: Letter 分析 (预计 1 小时) -1. [ ] 创建 `LetterAnalyzer.cs` 分类逻辑 -2. [ ] 创建 `LetterToPromptConverter.cs` 转换逻辑 -3. [ ] 测试不同类型 Letter 的分类准确性 - -### 阶段 4: AI 集成 (预计 1.5 小时) -1. [ ] 创建 `AIAutoCommentary.cs` 管理类 -2. [ ] 集成到现有的 `AIIntelligenceCore` 系统 -3. [ ] 实现队列处理避免刷屏 -4. [ ] 添加 `SendSystemMessageAsync` 方法到 AIIntelligenceCore - -### 阶段 5: UI 显示 (预计 30 分钟) -1. [ ] 决定评论显示方式(WulaLink UI / Message / 独立通知) -2. [ ] 实现显示逻辑 -3. [ ] 测试显示效果 - -### 阶段 6: 测试与优化 (预计 1 小时) -1. [ ] 测试各类 Letter 的评论效果 -2. [ ] 调整评论概率和过滤规则 -3. [ ] 优化提示词以获得更好的 AI 回应 -4. [ ] 添加速率限制避免 API 过载 - ---- - -## 需要添加的翻译键 - -```xml - -启用 AI 自动评论 -开启后,P.I.A 会自动对游戏事件(袭击、死亡、贸易等)发表评论或提供建议。 -评论概率 -AI 对中性事件发表评论的概率。负面事件(如袭击)总是会评论。 -仅评论负面事件 -开启后,AI 只会对负面事件(袭击、死亡、疾病等)发表评论。 -``` - ---- - -## 注意事项 - -1. **API 限流**: 需要实现请求队列和速率限制,避免短时间内发送过多请求 -2. **异步处理**: 所有 AI 请求必须异步处理,避免阻塞游戏主线程 -3. **用户控制**: 提供足够的设置选项让用户控制评论频率和类型 -4. **优雅降级**: 如果 AI 服务不可用,静默失败而不影响游戏 -5. **内存管理**: 队列大小限制,避免积累过多未处理的 Letter - ---- - -## 预期效果示例 - -**场景 1: 袭击通知** -``` -[Letter] 海盗袭击!一群海盗正在向你的殖民地进发。 -[P.I.A] 检测到敌对势力入侵。需要我启动轨道监视协议吗? -``` - -**场景 2: 殖民者死亡** -``` -[Letter] 张三死了。他被一只疯狂的松鼠咬死了。 -[P.I.A] ...被松鼠咬死?这位殖民者的战斗技能令人印象深刻。 -``` - -**场景 3: 贸易商到来** -``` -[Letter] 商队到来。一个来自外部势力的商队想要与你交易。 -[P.I.A] 贸易商队抵达。我注意到你的钢铁储备较低,建议优先采购。 -``` - ---- - -## 依赖项 - -- Harmony 2.0+ (用于 Patch) -- 现有的 AIIntelligenceCore 系统 -- 现有的 WulaModSettings 系统 -- 现有的 Overlay_WulaLink UI - ---- - -*文档版本: 1.0* -*创建时间: 2025-12-28* diff --git a/.agent/workflows/refactor-ai-conversation.md b/.agent/workflows/refactor-ai-conversation.md deleted file mode 100644 index 9abdd87a..00000000 --- a/.agent/workflows/refactor-ai-conversation.md +++ /dev/null @@ -1,114 +0,0 @@ -# AI 对话系统重构任务 - -## 目标 -合并 `Dialog_AIConversation` 和 `AIIntelligenceCore`,简化 AI 对话系统架构。 - -## 当前架构问题 - -### 1. 两个类存在重复逻辑 -- `Dialog_AIConversation.cs` - 大对话框 UI,包含自己的: - - `_history` 历史记录 - - `RunPhasedRequestAsync()` 三阶段对话逻辑 - - `ExecuteXmlToolsForPhase()` 工具执行 - - `BuildSystemInstruction()` 系统指令构建 - - `BuildUserMessageWithContext()` 上下文附加 - -- `AIIntelligenceCore.cs` - WorldComponent,包含: - - `_history` 历史记录 (重复!) - - `RunPhasedRequestAsync()` 三阶段对话逻辑 (重复!) - - `ExecuteXmlToolsForPhase()` 工具执行 (重复!) - - `SendUserMessage()` 用户消息发送 - - 但 **没有** `BuildUserMessageWithContext()` 导致小窗口看不到选中对象上下文 - -### 2. 小窗口 `Overlay_WulaLink` 使用 `AIIntelligenceCore.SendUserMessage()` -- 这个方法没有附加选中对象的上下文 -- 导致通过小窗口对话时,AI 看不到玩家选中了什么 - -### 3. 历史记录不同步 -- `Dialog_AIConversation` 和 `AIIntelligenceCore` 各自维护历史记录 -- 可能导致状态不一致 - -## 重构方案 - -### 方案 A: 让 AIIntelligenceCore 成为唯一的对话逻辑中心 - -1. **在 `AIIntelligenceCore.SendUserMessage()` 中添加上下文附加逻辑**: -```csharp -public void SendUserMessage(string text) -{ - string messageWithContext = BuildUserMessageWithContext(text); - _history.Add(("user", messageWithContext)); - PersistHistory(); - _ = RunPhasedRequestAsync(); -} - -private string BuildUserMessageWithContext(string userText) -{ - StringBuilder sb = new StringBuilder(); - sb.Append(userText); - - if (Find.Selector != null) - { - if (Find.Selector.SingleSelectedThing != null) - { - var selected = Find.Selector.SingleSelectedThing; - sb.AppendLine(); - sb.AppendLine(); - sb.Append($"[Context: Player has selected '{selected.LabelCap}'"); - if (selected is Pawn pawn) - { - sb.Append($" ({pawn.def.label}) at ({pawn.Position.x}, {pawn.Position.z})"); - } - else - { - sb.Append($" at ({selected.Position.x}, {selected.Position.z})"); - } - sb.Append("]"); - } - else if (Find.Selector.SelectedObjects.Count > 1) - { - sb.AppendLine(); - sb.AppendLine(); - sb.Append($"[Context: Player has selected {Find.Selector.SelectedObjects.Count} objects: "); - var selectedThings = Find.Selector.SelectedObjects.OfType().Take(5).ToList(); - sb.Append(string.Join(", ", selectedThings.Select(t => t.LabelCap))); - if (Find.Selector.SelectedObjects.Count > 5) sb.Append("..."); - sb.Append("]"); - } - } - - return sb.ToString(); -} -``` - -2. **让 `Dialog_AIConversation` 使用 `AIIntelligenceCore` 而不是自己的逻辑**: - - 移除 `Dialog_AIConversation` 中的 `RunPhasedRequestAsync()` - - 移除 `Dialog_AIConversation` 中的 `ExecuteXmlToolsForPhase()` - - 让 `SelectOption()` 调用 `_core.SendUserMessage()` 而不是自己处理 - - 订阅 `_core.OnMessageReceived` 事件来更新 UI - -3. **统一历史记录**: - - 只使用 `AIIntelligenceCore._history` - - `Dialog_AIConversation` 通过 `_core.GetHistorySnapshot()` 获取历史 - -### 方案 B: 完全删除 AIIntelligenceCore,合并到 Dialog_AIConversation - -不推荐,因为 `AIIntelligenceCore` 作为 WorldComponent 可以在游戏暂停/存档时保持状态。 - -## 文件位置 - -- `c:\Steam\steamapps\common\RimWorld\Mods\3516260226\Source\WulaFallenEmpire\EventSystem\AI\AIIntelligenceCore.cs` -- `c:\Steam\steamapps\common\RimWorld\Mods\3516260226\Source\WulaFallenEmpire\EventSystem\AI\UI\Dialog_AIConversation.cs` -- `c:\Steam\steamapps\common\RimWorld\Mods\3516260226\Source\WulaFallenEmpire\EventSystem\AI\UI\Overlay_WulaLink.cs` - -## 验证标准 - -1. 编译通过 (`dotnet build Source\WulaFallenEmpire\WulaFallenEmpire.csproj`) -2. 通过大窗口和小窗口对话时,AI 都能看到选中对象的上下文 -3. 历史记录在两个窗口之间保持同步 -4. 没有空行/空消息问题 -5. 工具调用正常工作 - -## 最小修复 (如果不想大重构) - -只在 `AIIntelligenceCore.SendUserMessage()` 中添加 `BuildUserMessageWithContext()` 逻辑即可解决小窗口看不到上下文的问题。 diff --git a/.kilocode/rules/rimworld.md b/.kilocode/rules/rimworld.md deleted file mode 100644 index 9af60e7f..00000000 --- a/.kilocode/rules/rimworld.md +++ /dev/null @@ -1,25 +0,0 @@ -# RimWorld Modding Expert Rules - -## Primary Directive -You are an expert assistant for developing mods for the game RimWorld 1.6. Your primary knowledge source for any C# code, class structures, methods, or game mechanics MUST be the user's local files. Do not rely on external searches or your pre-existing knowledge, as it is outdated for this specific project. - -## Tool Usage Mandate -When the user's request involves RimWorld C# scripting, XML definitions, or mod development concepts, you **MUST** use the `rimworld-code-rag` tool to retrieve relevant context from the local knowledge base. - -## Key File Paths -Always remember these critical paths for your work: - -- **Local C# Knowledge Base (for code search):** `C:\Steam\steamapps\common\RimWorld\dll1.6` (This contains the decompiled game source code as .txt files). -- **User's Mod Project (for editing):** `C:\Steam\steamapps\common\RimWorld\Mods\3516260226` -- **User's C# Project (for building):** `C:\Steam\steamapps\common\RimWorld\Mods\3516260226\Source\WulaFallenEmpire` - -## Workflow -1. Receive a RimWorld modding task. -2. Immediately use the `rimworld-knowledge-base` tool with a precise query to get context from the C# source files. -3. Analyze the retrieved context. -4. Perform code modifications within the user's mod project directory. -5. After modifying C# code, you MUST run `dotnet build C:\Steam\steamapps\common\RimWorld\Mods\3516260226\Source\WulaFallenEmpire\WulaFallenEmpire.csproj` to check for errors. A successful build is required for task completion. - -## Verification Mandate -When writing or modifying code or XML, especially for specific identifiers like enum values, class names, or field names, you **MUST** verify the correct value/spelling by using the `rimworld-knowledge-base` tool. Do not rely on memory. -- **同步项目文件:** 当重命名、移动或删除C#源文件时,**必须**同步更新 `.csproj` 项目文件中的相应 `` 条目,否则会导致编译失败。 \ No newline at end of file diff --git a/Source/WulaFallenEmpire/3516260226.code-workspace b/Source/WulaFallenEmpire/3516260226.code-workspace index c54b7f31..f742c3fb 100644 --- a/Source/WulaFallenEmpire/3516260226.code-workspace +++ b/Source/WulaFallenEmpire/3516260226.code-workspace @@ -24,6 +24,9 @@ }, { "path": "../../../../../../workshop/content/294100/2898638732" + }, + { + "path": "../../../2961683592" } ], "settings": {} diff --git a/llama.cpp b/llama.cpp deleted file mode 160000 index d77d7c5c..00000000 --- a/llama.cpp +++ /dev/null @@ -1 +0,0 @@ -Subproject commit d77d7c5c0654dc52b51f03941b12ae85d7227608