fix(streaming): 修复 refusal 响应导致的错误日志并添加友好提示#36
Merged
mirrorange merged 1 commit intomirrorange:mainfrom Dec 22, 2025
Merged
Conversation
- 补全 MessageDeltaData.stop_reason 类型(添加 pause_turn 和 refusal) - 为 ContentBlockStopEvent 添加边界检查,防止 refusal 响应导致 IndexError - 检测 refusal 响应时注入 ErrorEvent,向客户端返回友好错误提示 问题:当 Claude.ai 返回 stop_reason="refusal" 时,响应跳过 content_block_start 直接发送 content_block_stop,导致访问空数组时崩溃(IndexError);同时也优化处理 refusal 空回复,增加返回友好错误提示。 (cherry picked from commit b3ca6c4)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
修复 Claude.ai 返回
stop_reason: "refusal"时的空回复问题,并添加友好的错误提示。Background
问题发现
在使用 Sonnet 4.5 时,发送某些特定内容(如
Q29kZQ==)会触发 Claude.ai 的安全过滤器,返回
stop_reason: "refusal"响应。此时:IndexError错误日志根本原因
正常响应的事件流:
message_start → content_block_start → content_block_delta(s) → content_block_stop → message_delta → message_stop
Refusal 响应的事件流:
message_start → content_block_stop → message_delta(stop_reason="refusal") → message_stop
↑
跳过了 content_block_start!
当收到
content_block_stop时,代码直接访问content[index],但由于没有content_block_start,content 数组为空,导致IndexError。Claude.ai 网页版的处理方式
Claude.ai 网页版在遇到 refusal 时会显示友好提示:
Solution
1. 补全模型定义
app/models/streaming.py中MessageDeltaData.stop_reason补充缺失的类型:"pause_turn""refusal"使其与
Message.stop_reason保持一致。2. 添加边界检查
app/processors/claude_ai/message_collector_processor.py中ContentBlockStopEvent处理添加边界检查,避免访问空数组产生错误日志。
3. 注入友好错误提示
检测到
stop_reason == "refusal"且content为空时,注入ErrorEvent:{ "type": "error", "error": { "type": "refusal", "message": "Chat paused: Claude's safety filters flagged this message. This occasionally happens with normal, safe messages. Try rephrasing or using a different model." } }