@@ -118,6 +118,7 @@ class AgentLoop(
118118 * Android: single profile → use MAX (160) for safety headroom since no auth failover.
119119 */
120120 private const val MAX_RUN_LOOP_ITERATIONS = 160
121+ private const val MAX_THINKING_CHARS = 10_000 // Thinking 内容最大字符数,防止幻觉死循环
121122
122123 /* *
123124 * Overload backoff: aligned with OpenClaw OVERLOAD_FAILOVER_BACKOFF_POLICY.
@@ -546,6 +547,10 @@ class AgentLoop(
546547 // Scrub Anthropic refusal magic string from system prompt (aligned with OpenClaw scrubAnthropicRefusalMagic)
547548 val scrubbedMessages = scrubAnthropicRefusalMagic(messages)
548549
550+ // Thinking 重复检测(防幻觉死循环)
551+ var thinkingRepeatCount = 0
552+ var lastThinkingSig = " "
553+
549554 kotlinx.coroutines.withTimeout(LLM_TIMEOUT_MS ) {
550555 llmProvider.chatWithToolsStreaming(
551556 messages = scrubbedMessages,
@@ -555,8 +560,23 @@ class AgentLoop(
555560 ).collect { chunk ->
556561 when (chunk.type) {
557562 ChunkType .THINKING_DELTA -> {
558- thinkingAccumulated.append(chunk.text)
559- _progressFlow .emit(ProgressUpdate .ReasoningDelta (chunk.text))
563+ // 检测重复 thinking(模型卡在循环)
564+ val sig = chunk.text.take(50 ).trim()
565+ if (sig.isNotEmpty() && sig == lastThinkingSig) {
566+ thinkingRepeatCount++
567+ if (thinkingRepeatCount > 20 ) {
568+ writeLog(" ⚠️ Thinking 重复超过 20 次,跳过剩余 thinking" )
569+ Log .w(TAG , " Thinking repetition detected ($thinkingRepeatCount times), skipping" )
570+ // 不再累积,也不再推送
571+ }
572+ } else {
573+ thinkingRepeatCount = 0
574+ lastThinkingSig = sig
575+ }
576+ if (thinkingRepeatCount <= 20 && thinkingAccumulated.length < MAX_THINKING_CHARS ) {
577+ thinkingAccumulated.append(chunk.text)
578+ _progressFlow .emit(ProgressUpdate .ReasoningDelta (chunk.text))
579+ }
560580 }
561581 ChunkType .TEXT_DELTA -> {
562582 contentAccumulated.append(chunk.text)
0 commit comments