diff --git a/AIChatPanel.xaml.cs b/AIChatPanel.xaml.cs index 832f91b..e6ef214 100644 --- a/AIChatPanel.xaml.cs +++ b/AIChatPanel.xaml.cs @@ -364,6 +364,7 @@ namespace AnotherReplayReader OnChunk, _linkedCts.Token); UpdateTokenDisplay(overviewResult); + ReportReasoningGuardResult(overviewResult); _overview = OverviewParser.Parse(overviewResult.Response); _overviewNarrative = _overview.Narrative; AppendLog( @@ -490,6 +491,7 @@ namespace AnotherReplayReader OnChunk, _linkedCts.Token); UpdateTokenDisplay(segmentResult); + ReportReasoningGuardResult(segmentResult); segmentResponse = segmentResult.Response; if (backqueryCount >= maxBackqueriesPerSegment) @@ -582,6 +584,7 @@ namespace AnotherReplayReader _suppressDisplay = false; } UpdateTokenDisplay(revisionResult); + ReportReasoningGuardResult(revisionResult); if (string.IsNullOrWhiteSpace(revisionResult.Response)) { @@ -675,6 +678,7 @@ namespace AnotherReplayReader _linkedCts.Token); UpdateTokenDisplay(result); + ReportReasoningGuardResult(result); // 总结轮回查:允许模型请求一次远处原始区间,作为同一会话的追加输入。 if (_replayData is null) @@ -727,6 +731,7 @@ namespace AnotherReplayReader OnChunk, _linkedCts.Token); UpdateTokenDisplay(finalSummary); + ReportReasoningGuardResult(finalSummary); AppendLog("总结完成", "已根据回查区间补充最终总结。", false); } @@ -752,7 +757,9 @@ namespace AnotherReplayReader var total = 0; foreach (var message in messages) { - total += AiContextBudget.EstimateTokens(message.Content); + total += AiContextBudget.EstimateTokens(message.Content ?? string.Empty); + total += AiContextBudget.EstimateTokens( + message.ReasoningContent ?? string.Empty); } var check = AiContextBudget.CheckRequestUsage( total, requestContext.Provider, requestContext.Model); @@ -806,6 +813,44 @@ namespace AnotherReplayReader _chunkQueue.Enqueue((chunk, DateTimeOffset.UtcNow)); } + private void ReportReasoningGuardResult(AIAnalyze.Result result) + { + if (!result.ReasoningInterrupted + && !result.ContinuationApplied + && string.IsNullOrWhiteSpace(result.ReasoningContinuationError)) + { + return; + } + + if (!string.IsNullOrWhiteSpace(result.ReasoningContinuationError)) + { + AppendLog("推理保护警告", result.ReasoningContinuationError, false); + } + else if (result.ContinuationApplied) + { + AppendLog("推理保护", "已请求 AI 尽快收尾,并完成最终回答。", false); + } + else if (result.ReasoningInterrupted) + { + AppendLog("推理保护", "检测到推理内容超限,正在处理续写结果。", false); + } + + if (!string.IsNullOrWhiteSpace(result.ReasoningOriginalRequestJson)) + { + AppendLog( + "推理保护:首次请求消息", + result.ReasoningOriginalRequestJson, + true); + } + if (!string.IsNullOrWhiteSpace(result.ReasoningContinuationRequestJson)) + { + AppendLog( + "推理保护:续写请求完整消息", + result.ReasoningContinuationRequestJson, + true); + } + } + private void StartThinkingBlock() { _thinkingStartTime = DateTime.Now; @@ -1035,6 +1080,7 @@ namespace AnotherReplayReader var thinkSb = new StringBuilder(); var contentSb = new StringBuilder(); var errorSb = new StringBuilder(); + var guardTriggered = false; while (_chunkQueue.TryDequeue(out var data)) { var (chunk, time) = data; @@ -1062,6 +1108,11 @@ namespace AnotherReplayReader { errorSb.AppendLine(chunk.Text); } + else if (chunk.Type == AIAnalyze.AIChunkType.ReasoningGuard) + { + EndThinkingBlock(); + guardTriggered = true; + } } if (thinkSb.Length > 0) @@ -1080,6 +1131,10 @@ namespace AnotherReplayReader { AddErrorBlock(errorSb.ToString()); } + if (guardTriggered) + { + _currentContent = null; + } } private void AutoScroll() diff --git a/AIProviderSettingsControl.xaml b/AIProviderSettingsControl.xaml index 96be9b2..74bb221 100644 --- a/AIProviderSettingsControl.xaml +++ b/AIProviderSettingsControl.xaml @@ -143,6 +143,7 @@ + @@ -164,20 +165,34 @@ Content="支持 SSE 流式输出" Margin="0,5"/> -