Repository navigation
Conversation
|
|
Caution Review failedThe pull request is closed. Note
|
| Cohort / File(s) | Summary |
|---|---|
模组元数据与文档 About/About.xml, INTRODUCTION.txt |
添加 modVersion,新增 RimMind - Core 文档,描述核心架构、功能、API 与配置说明。 |
本地化字符串 Languages/English/Keyed/RimMind_Core.xml, Languages/ChineseSimplified/Keyed/RimMind_Core.xml |
新增大量英文/简体中文本地化键(队列与请求控制、队列状态/操作标签、上下文过滤描述、提示片段等)。 |
公共 API 扩展 Source/AICoreAPI.cs |
将静态 provider 签名改为可空返回,新增队列控制/查询、提供者查询、跳过检查注册/评估、事件回调与故事讲述器跳过检查等多项公共方法与属性。 |
请求/响应/客户端 类型 Source/Client/AIRequest.cs, Source/Client/AIRequestState.cs, Source/Client/AIResponse.cs, Source/Client/IAIClient.cs |
新增 Priority/MaxRetryCount/State 等字段与枚举;AIResponse 增加多项遥测字段与 Cancelled 工厂;IAIClient 增加 IsLocalEndpoint 属性。 |
OpenAI 客户端实现 Source/Client/OpenAI/OpenAIClient.cs |
新增 IsLocalEndpoint 检测、引入 AIHttpException、PostAsync 返回 (text,statusCode)、并在响应中填充遥测(处理时长、HTTP 状态、请求字节数、优先级)并记录调试日志。 |
队列实现重写 Source/Core/AIRequestQueue.cs |
用 TrackedRequest 列表替代旧 FIFO,按优先级选择就绪项、处理冷却/过期、超时与重试、局部模型互斥、暂停/恢复与取消,新增多项公开控制/查询 API 与活动/队列检查。 |
调试与遥测 UI/工具 Source/Core/AIDebugLog.cs, Source/Debug/AICoreDebugActions.cs, Source/UI/Window_AIDebugLog.cs |
AIDebugEntry 增加遥测字段(Priority/State/AttemptCount/QueueWaitMs/ProcessingMs/HttpStatusCode/RequestPayloadBytes);添加队列调试动作(ShowQueueState/PauseQueue/ResumeQueue);日志窗口展示额外遥测与优先级/HTTP 状态等。 |
上下文构建与提示处理 Source/Core/GameContextBuilder.cs, Source/Core/Prompt/ContextComposer.cs, Source/Core/Prompt/PromptSanitizer.cs, Source/Core/Prompt/StructuredPromptBuilder.cs |
新增 PromptSanitizer 并在构建后调用;添加物品质量/损坏标记和按数量汇总的库存输出;将硬编码省略文本替换为可翻译字符串。 |
设置与上下文过滤 Source/Settings/AICoreSettings.cs, Source/Settings/ContextSettings.cs |
新增 maxConcurrentRequests、maxRetryCount、requestTimeoutMs 并持久化;添加 IncludeInventory 与 exposedProviders 并在预设中调整 IncludeInventory。 |
设置 UI 与请求 UI Source/UI/AICoreSettingsUI.cs, Source/UI/RequestEntry.cs, Source/UI/RequestOverlay.cs |
实现多行换行选项卡栏并新增“队列”选项卡与队列管理界面;在 API 页添加并发/重试/超时控件;上下文复选框增加描述;RequestEntry 支持 optionTooltips,RequestOverlay 显示选项提示。 |
Sequence Diagram(s)
sequenceDiagram
participant Mod as rgba(46,134,193,0.5)
participant API as rgba(39,174,96,0.5)
participant Queue as rgba(241,196,15,0.5)
participant Client as rgba(155,89,182,0.5)
participant LLM as rgba(231,76,60,0.5)
Mod->>API: Enqueue(AIRequest)
API->>Queue: Enqueue(request, callback)
Note over Queue: 按模块头部选取就绪请求并按优先级排序
alt 无法处理(已暂停/并发满/局部模型占用)
Queue-->>Mod: 保留在队列中
else 可处理
Queue->>Client: FireRequest(TrackedRequest)
Client->>LLM: SendAsync(AIRequest)
LLM-->>Client: AIResponse (+status, tokens)
Client-->>Queue: 返回 AIResponse(含 ProcessingMs/HttpStatus/Bytes/Priority/Attempt)
alt 成功
Queue->>Mod: 回调(Completed response)
else 可重试且未超限
Queue->>Queue: 增加 Attempt 重入队列
else 失败/取消
Queue->>Mod: 回调(Error/Cancelled)
end
end
Note over API,Queue: API 可在任意时刻:Pause/Resume/Cancel/Query 状态
Estimated code review effort
🎯 4 (复杂) | ⏱️ ~60 分钟
Possibly related PRs
- Merge trae branch into main #4 — 主 PR(相同修改集合,直接相关,包含 AI 核心、队列、客户端、UI 与设置变更)。
✨ Finishing Touches
📝 Generate docstrings
- Create stacked PR
- Commit on current branch
🧪 Generate unit tests (beta)
- Create PR with unit tests
- Commit unit tests in branch
trae
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.
Comment @coderabbitai help to get the list of available commands and usage tips.
There was a problem hiding this comment.
Actionable comments posted: 9
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
Source/Core/AIDebugLog.cs (1)
25-31:⚠️ Potential issue | 🟠 Major把
Find.TickManager访问移回主线程。
Record()可能从 AI 请求完成的后台路径调用;这里在入队前读取Find.TickManager.TicksGame仍然是后台访问 RimWorld API 的风险。建议只在GameComponentTick()drain 队列时填充GameTick。As per coding guidelines,
**/*.cs: Never call RimWorld or Unity APIs from background threads; all game state operations must happen on the main thread.建议修复
public override void GameComponentTick() { while (_pendingEntries.TryDequeue(out var entry)) { + entry.GameTick = Find.TickManager.TicksGame; if (_entries.Count >= MaxEntries) _entries.RemoveAt(0); _entries.Add(entry); } @@ _instance?._pendingEntries.Enqueue(new AIDebugEntry { - GameTick = Find.TickManager.TicksGame, Source = request.RequestId, ModelName = RimMindCoreMod.Settings.modelName,Also applies to: 37-60
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@Source/Core/AIDebugLog.cs` around lines 25 - 31, Record() currently reads Find.TickManager.TicksGame on a background thread before enqueuing, which violates the rule against calling RimWorld/Unity APIs off the main thread; change Record() to only capture non-game-thread-safe data and enqueue a placeholder entry (without accessing Find.TickManager), and then in GameComponentTick() when draining _pendingEntries (the existing loop over _pendingEntries.TryDequeue), set entry.GameTick = Find.TickManager.TicksGame on the main thread before adding to _entries (ensure MaxEntries handling and _entries.Add(entry) remain in GameComponentTick); update any code paths that relied on Record() populating GameTick to expect GameTick to be filled during GameComponentTick().Source/Client/OpenAI/OpenAIClient.cs (1)
47-72:⚠️ Potential issue | 🟡 Minor失败响应会丢失 HTTP 状态码。
PostAsync()在 4xx/5xx 时抛出普通Exception,SendAsync的失败分支无法拿到responseCode,所以新增的HttpStatusCode遥测只在成功路径有效。建议修复
+ private sealed class AIHttpException : Exception + { + public long StatusCode { get; } + + public AIHttpException(long statusCode, string message) : base(message) + { + StatusCode = statusCode; + } + } + public async Task<AIResponse> SendAsync(AIRequest request) { string endpoint = FormatEndpoint(_settings.apiEndpoint); string json = BuildRequestJson(request); @@ - catch (Exception ex) + catch (AIHttpException ex) + { + sw.Stop(); + AIRequestQueue.LogFromBackground($"[RimMind] Request failed ({request.RequestId}): {ex.Message}", isWarning: true); + var response = AIResponse.Failure(request.RequestId, ex.Message); + response.ProcessingMs = sw.ElapsedMilliseconds; + response.HttpStatusCode = ex.StatusCode; + response.RequestPayloadBytes = Encoding.UTF8.GetByteCount(json); + response.Priority = request.Priority; + AIDebugLog.Record(request, response, (int)sw.ElapsedMilliseconds); + return response; + } + catch (Exception ex) { sw.Stop(); AIRequestQueue.LogFromBackground($"[RimMind] Request failed ({request.RequestId}): {ex.Message}", isWarning: true); var response = AIResponse.Failure(request.RequestId, ex.Message); @@ - throw new Exception($"HTTP {webRequest.responseCode}: {detail}"); + throw new AIHttpException(webRequest.responseCode, $"HTTP {webRequest.responseCode}: {detail}"); }Also applies to: 152-158
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@Source/Client/OpenAI/OpenAIClient.cs` around lines 47 - 72, PostAsync currently throws a generic Exception on 4xx/5xx so the catch in SendAsync can't populate HttpStatusCode; update PostAsync to surface the HTTP status (either by throwing a custom exception or HttpRequestException that includes StatusCode, or by returning a result object that always contains the status code), then in SendAsync's catch (the try/catch around PostAsync usage) catch that specific exception, extract the HTTP status code and set response.HttpStatusCode before creating AIResponse.Failure and calling AIDebugLog.Record; apply the same extraction logic to the other failing branch noted (lines ~152-158) so telemetry always records the HTTP status code or a sensible default when unavailable.
🧹 Nitpick comments (3)
Source/Core/Prompt/StructuredPromptBuilder.cs (1)
98-98: 消毒路径不统一
Build()现在会通过PromptSanitizer.Sanitize归一化花括号,但ContextComposer.BuildFromSections()(Source/Core/Prompt/ContextComposer.cs:40-52)在直接从PromptSection组装时并未调用同一消毒逻辑。当下游通过ToSection(...)再拼入BuildFromSections时,内容已被消毒一次,而外部直接构造的PromptSection则未消毒,最终发给 LLM 的文本行为取决于构造路径。建议将消毒统一到最终"即将发送到 LLM"的边界(例如BuildFromSections或客户端发送前),避免双重消毒或漏消毒。🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@Source/Core/Prompt/StructuredPromptBuilder.cs` at line 98, Build() currently calls PromptSanitizer.Sanitize but ContextComposer.BuildFromSections(...) does not, causing inconsistent sanitization depending on whether sections were produced via ToSection(...) or constructed externally; change the sanitization boundary so BuildFromSections (or the single place immediately before sending to the LLM) is responsible for sanitizing all assembled text: remove duplicate sanitization from Build()/ToSection if present and add a single call to PromptSanitizer.Sanitize inside ContextComposer.BuildFromSections (or the final send path), ensuring PromptSanitizer.Sanitize(...) is applied exactly once to the final concatenated prompt.Source/Client/AIRequestState.cs (1)
3-17: 枚举定义 LGTM
AIRequestState覆盖了 Queued/Processing/Completed/Error/Cancelled 五态,与AIRequestQueue中 Enqueue/Processing/Retry/Cancel 路径一一对应;AIRequestPriority显式赋值High=0 / Normal=1 / Low=2,与队列按Request.Priority升序插入(低数值先出)的逻辑一致。仅一条可选建议:若后续希望在存档中持久化状态/优先级,可考虑显式固定每个枚举值(如
Queued = 0, Processing = 1 ...),避免将来增删成员时改变序号。🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@Source/Client/AIRequestState.cs` around lines 3 - 17, The enums AIRequestState and AIRequestPriority currently rely on implicit integer values; to make them stable for future persistence or serialization, explicitly assign integer values to each member (e.g., Queued = 0, Processing = 1, Completed = 2, Error = 3, Cancelled = 4 and keep High = 0, Normal = 1, Low = 2) by updating the AIRequestState and AIRequestPriority declarations so adding/removing members won't shift underlying numeric values.Source/Core/Prompt/PromptSanitizer.cs (1)
5-9: 花括号反转义的边界行为值得注意当前实现使用顺序
Replace("{{","{")和Replace("}}","}"),对奇数个连续大括号的处理结果可能不符合直觉,例如"{{{"会变成"{{"(第一次替换后剩余"{{",第二次 Replace 针对}}不会再影响它),而"{{{{"会正确变成"{{"。如果上游 Prompt 文本中可能包含用户内容里的连续花括号(例如 JSON 示例、代码片段),建议在文档/注释里明确该函数的语义(是"反转义模板占位符"还是"去重双花括号"),以避免后续模块误用。另外,
StructuredPromptBuilder.Build()会调用 Sanitize,但ContextComposer.BuildFromSections()(位于Source/Core/Prompt/ContextComposer.cs:40-52)直接拼接PromptSection.Content并未经过该消毒器,若 Section 内容里有{{ ... }}转义意图,会出现两条路径行为不一致。建议要么在BuildFromSections中也统一调用PromptSanitizer.Sanitize,要么只在最终提交给 LLM 的边界处消毒一次。🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@Source/Core/Prompt/PromptSanitizer.cs` around lines 5 - 9, Sanitize currently does sequential Replace("{{","{") and Replace("}}","}") which yields surprising results for odd runs of braces (e.g., "{{{" -> "{{"); clarify its intended semantics (whether it is strictly "unescape template placeholders" vs "collapse double braces") in the PromptSanitizer.Sanitize XML doc comment and/or public API docs, and make behavior consistent across builders by either calling PromptSanitizer.Sanitize on each PromptSection.Content inside ContextComposer.BuildFromSections or else removing per-section sanitization and ensuring StructuredPromptBuilder.Build (the single final submission point) is the only place that calls Sanitize; pick one approach and apply it consistently so StructuredPromptBuilder.Build(), ContextComposer.BuildFromSections(), and PromptSection.Content handling produce identical results.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@INTRODUCTION.txt`:
- Around line 67-68: 将“API Key 仅存储在本地 RimWorld
设置文件中,不会上传到任何服务器。”这句改为明确且不误导的表述:保留“本地存储”信息,同时说明 API Key 会作为认证信息发送到用户配置的 AI API
服务商(即只会发往用户指定的 endpoint),且不会发送到 RimMind 自有服务器或其他未经授权的第三方;替换原问答中“Q: API Key
安全吗?”下的回答文本(定位标识为问句文本 "Q: API Key 安全吗?" 及其当前回答行)为上述更精确的说明。
In `@Languages/ChineseSimplified/Keyed/RimMind_Core.xml`:
- Around line 132-133: RimMind.Core.Context.IncludeLocation
的描述误导用户说会注入“位置坐标”,但实际只注入房间/室内外和温度;更新 RimMind.Core.Context.IncludeLocation.Desc
文本以去掉“位置坐标”并明确说明注入的是房间/室内外状态和温度(例如改为“将小人的房间/室内或室外位置状态及所在区域温度注入 AI 上下文”),确保符号
RimMind.Core.Context.IncludeLocation 和 RimMind.Core.Context.IncludeLocation.Desc
保持一致且语义准确。
In `@Source/AICoreAPI.cs`:
- Around line 339-346: GetRegisteredCategories currently returns all keys from
_staticProviders, _pawnProviders, and _dynamicProviders without applying the
exposedProviders filter, which leaks unexposed category names; update
GetRegisteredCategories to filter the combined list through exposedProviders
(the same predicate used by the Get*ProviderData methods) before returning so
only exposed categories are listed, referencing GetRegisteredCategories,
exposedProviders, and the existing Get*ProviderData implementations to mirror
their filtering behavior.
- Around line 419-527: The registries currently iterate the live collections and
lack unregister APIs for incident/storyteller, which can cause "collection
modified" exceptions when callbacks register/unregister themselves and leave
stale delegates; fix by iterating over snapshots instead (e.g. enumerate
_dialogueSkipChecks.Values.ToList(), _floatMenuSkipChecks.Values.ToList(),
_actionSkipChecks.Values.ToList(), _incidentExecutedCallbacks.ToList(),
_storytellerIncidentSkipChecks.ToList() in
ShouldSkipDialogue/ShouldSkipFloatMenu/ShouldSkipAction/NotifyIncidentExecuted/ShouldSkipStorytellerIncident)
so modifications during callbacks are safe, and add symmetric Unregister methods
for the incident API (e.g. UnregisterIncidentExecutedCallback(Action callback))
and storyteller skip checks (e.g.
UnregisterStorytellerIncidentSkipCheck(Func<bool> check)) to remove stale
delegates.
In `@Source/Client/IAIClient.cs`:
- Line 11: The current IsLocalEndpoint implementation (referenced from
IAIClient.IsLocalEndpoint and OpenAIClient) incorrectly detects local endpoints
by simple substring checks and is vulnerable to false positives/negatives and
race conditions when RimMindCoreSettings.apiEndpoint changes during request
processing; fix it by parsing the endpoint with System.Uri, extract host, try
IPAddress.TryParse and use IPAddress.IsLoopback for loopback addresses (handle
IPv4 and IPv6 like 127.0.0.1 and ::1), explicitly treat "localhost" and known
hostnames such as "host.docker.internal" as local, and avoid substring matches
on the whole URL path to prevent false positives; additionally ensure stability
by snapshotting the computed bool into the TrackedRequest (e.g.,
TrackedRequest.IsLocalSnapshot) at enqueue time or by making
OpenAIClient.IsLocalEndpoint return a value derived from an immutable cached Uri
so concurrent changes to RimMindCoreSettings.apiEndpoint do not change the
result mid-request.
In `@Source/Client/OpenAI/OpenAIClient.cs`:
- Around line 27-34: The IsLocalEndpoint property incorrectly uses
string.Contains on _settings.apiEndpoint, which misdetects loopback hosts and
misses variants like uppercase LOCALHOST and IPv6 [::1]; change the check to
parse the endpoint as a Uri and use Uri.IsLoopback (eg. add a helper like
IsLoopbackEndpoint(string endpoint) that calls Uri.TryCreate(..., out uri) and
returns uri.IsLoopback) and update IsLocalEndpoint (and the similar check at the
other occurrence around the class) to call that helper so detection is based on
the URI host rather than substring matching.
In `@Source/Core/AIRequestQueue.cs`:
- Around line 261-329: FireRequest currently mutates game state from a
background Task.Run (removing from _activeRequests/_requestIdToActive, modifying
_modQueues, setting _isProcessingLocalRequest and enqueuing results), causing
races with GameComponentTick(), UI and cancel/timeout paths; instead, have the
background task only build an immutable outcome object (e.g. response +
tracked.TrackingId + intent: Retry/Complete) and enqueue that into a thread-safe
pending-actions queue (or reuse _results with an explicit action kind), then
perform all state changes (removing from _activeRequests/_requestIdToActive,
re-queuing into _modQueues, setting _isProcessingLocalRequest, invoking
callbacks) on the main thread inside GameComponentTick() or a new
ProcessPendingActions() called from it; ensure FireRequest no longer touches
_activeRequests/_requestIdToActive/_modQueues/_isProcessingLocalRequest and that
GameComponentTick() checks for timeouts/cancellations before applying a queued
retry/completion.
In `@Source/UI/AICoreSettingsUI.cs`:
- Around line 371-430: The height calculation under contentH currently uses
modCount = queue.GetAllQueueDepths().Count which misses cooldown-only mods and
ModCooldownGetters entries; compute the full set first (using
queue.GetAllQueueDepths(), queue.GetAllCooldowns(), and
RimMindAPI.ModCooldownGetters) into allModIds and use allModIds.Count when
computing contentH (replace references to GetAllQueueDepths().Count with the
unioned allModIds.Count) so the viewRect height matches the actual per-mod rows
and scrolling works correctly.
In `@Source/UI/Window_AIDebugLog.cs`:
- Around line 116-126: The telemetry UILabels in Window_AIDebugLog.cs build
hardcoded English strings (the telemetry variable and the retry/wait/token
labels) which must be replaced with translation keys; update the construction of
telemetry (used in the Widgets.Label call that renders telemetry) to use keyed
translations such as "RimMind.Core.UI.DebugLog.retry".Translate(),
"RimMind.Core.UI.DebugLog.wait".Translate(),
"RimMind.Core.UI.DebugLog.tok".Translate() (and any other needed keys like
attempt/queueWait) concatenated with the runtime values (entry.AttemptCount,
entry.QueueWaitMs, entry.TokensUsed, entry.ModelName) so all visible UI text
uses the RimMind.Core.UI.DebugLog.* keys and call .Translate() before rendering.
---
Outside diff comments:
In `@Source/Client/OpenAI/OpenAIClient.cs`:
- Around line 47-72: PostAsync currently throws a generic Exception on 4xx/5xx
so the catch in SendAsync can't populate HttpStatusCode; update PostAsync to
surface the HTTP status (either by throwing a custom exception or
HttpRequestException that includes StatusCode, or by returning a result object
that always contains the status code), then in SendAsync's catch (the try/catch
around PostAsync usage) catch that specific exception, extract the HTTP status
code and set response.HttpStatusCode before creating AIResponse.Failure and
calling AIDebugLog.Record; apply the same extraction logic to the other failing
branch noted (lines ~152-158) so telemetry always records the HTTP status code
or a sensible default when unavailable.
In `@Source/Core/AIDebugLog.cs`:
- Around line 25-31: Record() currently reads Find.TickManager.TicksGame on a
background thread before enqueuing, which violates the rule against calling
RimWorld/Unity APIs off the main thread; change Record() to only capture
non-game-thread-safe data and enqueue a placeholder entry (without accessing
Find.TickManager), and then in GameComponentTick() when draining _pendingEntries
(the existing loop over _pendingEntries.TryDequeue), set entry.GameTick =
Find.TickManager.TicksGame on the main thread before adding to _entries (ensure
MaxEntries handling and _entries.Add(entry) remain in GameComponentTick); update
any code paths that relied on Record() populating GameTick to expect GameTick to
be filled during GameComponentTick().
---
Nitpick comments:
In `@Source/Client/AIRequestState.cs`:
- Around line 3-17: The enums AIRequestState and AIRequestPriority currently
rely on implicit integer values; to make them stable for future persistence or
serialization, explicitly assign integer values to each member (e.g., Queued =
0, Processing = 1, Completed = 2, Error = 3, Cancelled = 4 and keep High = 0,
Normal = 1, Low = 2) by updating the AIRequestState and AIRequestPriority
declarations so adding/removing members won't shift underlying numeric values.
In `@Source/Core/Prompt/PromptSanitizer.cs`:
- Around line 5-9: Sanitize currently does sequential Replace("{{","{") and
Replace("}}","}") which yields surprising results for odd runs of braces (e.g.,
"{{{" -> "{{"); clarify its intended semantics (whether it is strictly "unescape
template placeholders" vs "collapse double braces") in the
PromptSanitizer.Sanitize XML doc comment and/or public API docs, and make
behavior consistent across builders by either calling PromptSanitizer.Sanitize
on each PromptSection.Content inside ContextComposer.BuildFromSections or else
removing per-section sanitization and ensuring StructuredPromptBuilder.Build
(the single final submission point) is the only place that calls Sanitize; pick
one approach and apply it consistently so StructuredPromptBuilder.Build(),
ContextComposer.BuildFromSections(), and PromptSection.Content handling produce
identical results.
In `@Source/Core/Prompt/StructuredPromptBuilder.cs`:
- Line 98: Build() currently calls PromptSanitizer.Sanitize but
ContextComposer.BuildFromSections(...) does not, causing inconsistent
sanitization depending on whether sections were produced via ToSection(...) or
constructed externally; change the sanitization boundary so BuildFromSections
(or the single place immediately before sending to the LLM) is responsible for
sanitizing all assembled text: remove duplicate sanitization from
Build()/ToSection if present and add a single call to PromptSanitizer.Sanitize
inside ContextComposer.BuildFromSections (or the final send path), ensuring
PromptSanitizer.Sanitize(...) is applied exactly once to the final concatenated
prompt.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 91eacd5f-1248-4d86-bf74-a8ab03d72605
⛔ Files ignored due to path filters (4)
AGENTS.mdis excluded by!**/*.mdCLAUDE.mdis excluded by!**/*.mdINTRODUCTION.mdis excluded by!**/*.mdREADME.mdis excluded by!**/*.md
📒 Files selected for processing (23)
About/About.xmlINTRODUCTION.txtLanguages/ChineseSimplified/Keyed/RimMind_Core.xmlLanguages/English/Keyed/RimMind_Core.xmlSource/AICoreAPI.csSource/Client/AIRequest.csSource/Client/AIRequestState.csSource/Client/AIResponse.csSource/Client/IAIClient.csSource/Client/OpenAI/OpenAIClient.csSource/Core/AIDebugLog.csSource/Core/AIRequestQueue.csSource/Core/GameContextBuilder.csSource/Core/Prompt/ContextComposer.csSource/Core/Prompt/PromptSanitizer.csSource/Core/Prompt/StructuredPromptBuilder.csSource/Debug/AICoreDebugActions.csSource/Settings/AICoreSettings.csSource/Settings/ContextSettings.csSource/UI/AICoreSettingsUI.csSource/UI/RequestEntry.csSource/UI/RequestOverlay.csSource/UI/Window_AIDebugLog.cs
|
🔄 需要修改 - @coderabbitai[bot] Actionable comments posted: 9 Caution Some comments are outside the diff and can’t be posted inline due to platform limitations.
|
|
Tip For best results, initiate chat on the files or code changes.
🔴 需要优先处理(线程安全 / 数据竞争)
🟡 次要问题
🔵 Nitpick(可选优化)
优先级最高的是 第1、2条线程安全问题,建议尽快修复以避免潜在的崩溃或状态不一致。其余问题可以在后续迭代中处理。如需针对某个具体问题生成修复代码,请告知! |
… i18n - AIDebugLog: move Find.TickManager.TicksGame to GameComponentTick (main thread) - OpenAIClient: add AIHttpException to preserve HTTP status code on failure - OpenAIClient: replace string.Contains with Uri.IsLoopback for IsLocalEndpoint - AIRequestQueue: move all state mutations from FireRequest background task to main thread via PendingFireResult queue - AIRequestQueue: add IsLocalEndpointSnapshot to TrackedRequest for thread safety - AICoreAPI: filter GetRegisteredCategories by exposedProviders - AICoreAPI: snapshot iteration for skip checks and callbacks - AICoreAPI: add UnregisterIncidentExecutedCallback and UnregisterStorytellerIncidentSkipCheck - INTRODUCTION.txt: fix misleading API Key security statement - RimMind_Core.xml: fix IncludeLocation.Desc (position -> room/indoors/outdoors) - AICoreSettingsUI: fix queue tab height calculation to include cooldown-only mods - Window_AIDebugLog: replace hardcoded English strings with translation keys - ContextComposer: add PromptSanitizer.Sanitize to BuildFromSections - AIRequestState: explicit enum values for serialization stability
变更摘要
将 trae 分支的更改合并到 main,并修复 CodeRabbit 审查提出的全部问题。
变更类型
详细说明
线程安全修复(Major)
Find.TickManager.TicksGame从Record()(后台线程)移至GameComponentTick()(主线程),避免后台线程访问 RimWorld APIFireRequest中的所有状态变更(_activeRequests、_requestIdToActive、_modQueues、_isProcessingLocalRequest)从后台 Task.Run 移至主线程,通过新增的PendingFireResult队列桥接IsLocalEndpointSnapshot字段到TrackedRequest,在入队时快照IsLocalEndpoint值,避免后台线程读取可变的 settingsAPI 正确性修复(Minor)
AIHttpException内部类,在 HTTP 4xx/5xx 时保留状态码,使SendAsync的 catch 分支能正确填充response.HttpStatusCodeIsLocalEndpoint从string.Contains改为Uri.IsLoopback+ 显式检查localhost/host.docker.internal,修复 IPv6[::1]和大小写误判GetRegisteredCategories()现在通过exposedProviders过滤,与GetProviderData系列方法行为一致.ToList()快照,防止回调中注册/注销导致集合修改异常UnregisterIncidentExecutedCallback和UnregisterStorytellerIncidentSkipCheck对称卸载方法UI/本地化修复
GetAllQueueDepths、GetAllCooldowns、ModCooldownGetters三源,修复仅冷却 mod 行缺失导致滚动异常IncludeLocation.Desc从"位置坐标"改为"室内/室外/房间类型"(中英文同步修正)其他
BuildFromSections添加PromptSanitizer.Sanitize调用,与StructuredPromptBuilder.Build行为统一Queued=0, Processing=1, ...),保证序列化稳定性测试说明
dotnet build成功)版本号影响判断
UnregisterIncidentExecutedCallback、UnregisterStorytellerIncidentSkipCheck;TrackedRequest新增IsLocalEndpointSnapshot字段)其他信息
本次修改回应了 CodeRabbit PR#4 审查的全部 9 条可操作建议和 3 条 Nitpick 建议。
Summary by CodeRabbit
发布说明
新功能
改进
文档