fix: allow new session binding after /clear command

- 移除 isOldSession 检查,信任客户端的 session ID 作为新会话标识
- 将 sessionBindingTtlDays 默认值从 30 天改为 1 天,避免 Redis 内存累积
- 添加新会话绑定的监控日志(包含 sessionId、messages 数量、accountId 等)
- 完美支持 Claude Code /clear 等合法的新会话场景
- 同步更新前端界面的默认值配置

问题背景:
用户在 Claude Code 中执行 /clear 后,会生成新的 session ID,
但旧的逻辑会检查请求内容判定为"旧会话",导致返回"本地session已污染"错误。

修复方案:
采用方案2(放宽新会话检测)+ TTL 优化,信任客户端的 session ID,
不再检查请求内容是否"看起来像旧会话",由 1 天的 TTL 自动清理过期绑定。

影响范围:
- src/routes/api.js (流式和非流式两处)
- src/services/claudeRelayConfigService.js
- web/admin-spa/src/views/SettingsView.vue
This commit is contained in:
enzyme2013
2026-01-22 17:31:11 +08:00
parent 9ebef1b116
commit 16e2bcfedb
3 changed files with 17 additions and 29 deletions

View File

@@ -370,19 +370,13 @@ async function handleMessagesRequest(req, res) {
accountId && accountId &&
accountType === 'claude-official' accountType === 'claude-official'
) { ) {
// 🚫 检测旧会话(污染的会话 // 🆕 允许新 session ID 创建绑定(支持 Claude Code /clear 等场景
if (isOldSession(req.body)) { // 信任客户端的 session ID 作为新会话的标识,不再检查请求内容
const cfg = await claudeRelayConfigService.getConfig() logger.info(
logger.warn( `🔗 Creating new session binding: sessionId=${originalSessionIdForBinding}, ` +
`🚫 Old session rejected: sessionId=${originalSessionIdForBinding}, messages.length=${req.body?.messages?.length}, tools.length=${req.body?.tools?.length || 0}, isOldSession=true` `messages.length=${req.body?.messages?.length}, tools.length=${req.body?.tools?.length || 0}, ` +
) `accountId=${accountId}, accountType=${accountType}`
return res.status(400).json({ )
error: {
type: 'session_binding_error',
message: cfg.sessionBindingErrorMessage || '你的本地session已污染请清理后使用。'
}
})
}
// 创建绑定 // 创建绑定
try { try {
@@ -928,19 +922,13 @@ async function handleMessagesRequest(req, res) {
accountId && accountId &&
accountType === 'claude-official' accountType === 'claude-official'
) { ) {
// 🚫 检测旧会话(污染的会话 // 🆕 允许新 session ID 创建绑定(支持 Claude Code /clear 等场景
if (isOldSession(req.body)) { // 信任客户端的 session ID 作为新会话的标识,不再检查请求内容
const cfg = await claudeRelayConfigService.getConfig() logger.info(
logger.warn( `🔗 Creating new session binding (non-stream): sessionId=${originalSessionIdForBindingNonStream}, ` +
`🚫 Old session rejected (non-stream): sessionId=${originalSessionIdForBindingNonStream}, messages.length=${req.body?.messages?.length}, tools.length=${req.body?.tools?.length || 0}, isOldSession=true` `messages.length=${req.body?.messages?.length}, tools.length=${req.body?.tools?.length || 0}, ` +
) `accountId=${accountId}, accountType=${accountType}`
return res.status(400).json({ )
error: {
type: 'session_binding_error',
message: cfg.sessionBindingErrorMessage || '你的本地session已污染请清理后使用。'
}
})
}
// 创建绑定 // 创建绑定
try { try {

View File

@@ -14,7 +14,7 @@ const DEFAULT_CONFIG = {
claudeCodeOnlyEnabled: false, claudeCodeOnlyEnabled: false,
globalSessionBindingEnabled: false, globalSessionBindingEnabled: false,
sessionBindingErrorMessage: '你的本地session已污染请清理后使用。', sessionBindingErrorMessage: '你的本地session已污染请清理后使用。',
sessionBindingTtlDays: 30, // 会话绑定 TTL默认30天 sessionBindingTtlDays: 1, // 会话绑定 TTL默认1天支持 /clear 场景,避免 Redis 累积)
// 用户消息队列配置 // 用户消息队列配置
userMessageQueueEnabled: false, // 是否启用用户消息队列(默认关闭) userMessageQueueEnabled: false, // 是否启用用户消息队列(默认关闭)
userMessageQueueDelayMs: 200, // 请求间隔(毫秒) userMessageQueueDelayMs: 200, // 请求间隔(毫秒)

View File

@@ -1676,7 +1676,7 @@ const claudeConfig = ref({
claudeCodeOnlyEnabled: false, claudeCodeOnlyEnabled: false,
globalSessionBindingEnabled: false, globalSessionBindingEnabled: false,
sessionBindingErrorMessage: '你的本地session已污染请清理后使用。', sessionBindingErrorMessage: '你的本地session已污染请清理后使用。',
sessionBindingTtlDays: 30, sessionBindingTtlDays: 1,
userMessageQueueEnabled: false, // 与后端默认值保持一致 userMessageQueueEnabled: false, // 与后端默认值保持一致
userMessageQueueDelayMs: 200, userMessageQueueDelayMs: 200,
userMessageQueueTimeoutMs: 5000, // 与后端默认值保持一致(优化后锁持有时间短无需长等待) userMessageQueueTimeoutMs: 5000, // 与后端默认值保持一致(优化后锁持有时间短无需长等待)
@@ -1952,7 +1952,7 @@ const loadClaudeConfig = async () => {
globalSessionBindingEnabled: response.config?.globalSessionBindingEnabled ?? false, globalSessionBindingEnabled: response.config?.globalSessionBindingEnabled ?? false,
sessionBindingErrorMessage: sessionBindingErrorMessage:
response.config?.sessionBindingErrorMessage || '你的本地session已污染请清理后使用。', response.config?.sessionBindingErrorMessage || '你的本地session已污染请清理后使用。',
sessionBindingTtlDays: response.config?.sessionBindingTtlDays ?? 30, sessionBindingTtlDays: response.config?.sessionBindingTtlDays ?? 1,
userMessageQueueEnabled: response.config?.userMessageQueueEnabled ?? false, // 与后端默认值保持一致 userMessageQueueEnabled: response.config?.userMessageQueueEnabled ?? false, // 与后端默认值保持一致
userMessageQueueDelayMs: response.config?.userMessageQueueDelayMs ?? 200, userMessageQueueDelayMs: response.config?.userMessageQueueDelayMs ?? 200,
userMessageQueueTimeoutMs: response.config?.userMessageQueueTimeoutMs ?? 5000, // 与后端默认值保持一致 userMessageQueueTimeoutMs: response.config?.userMessageQueueTimeoutMs ?? 5000, // 与后端默认值保持一致