Skip to content

Commit 4679a8c

Browse files
nieaoclaude
andcommitted
fix(election): bot 不参与 inbox 执行者选举 — setLocalState(null) + 前端 filter user
bot 反向通道的 yjs provider 默认会进 awareness states. clientID 比 用户 cc 小时被 isElectedExecutor 选成"最小者", 用户的 BottomAIBar isElectedExecutor 返回 false → 不 fire → inbox pending 永远卡死. 双重保险: 1. bot: provider.awareness.setLocalState(null) — 在 awareness 里隐身 2. 前端: 选举只数有 state.user 字段的 awareness — 没 user 的 spectator (bot daemon / inspect 脚本) 自然被排除 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 9127625 commit 4679a8c

2 files changed

Lines changed: 10 additions & 2 deletions

File tree

server/feishu-bot.mjs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -543,6 +543,9 @@ function ensureReverseChannel(room) {
543543
log(`[reverse] 订阅 yjs room=${room} ws=${Y_WS_URL}`)
544544
const doc = new Y.Doc()
545545
const provider = new WebsocketProvider(Y_WS_URL, room, doc, { connect: true, WebSocketPolyfill: WebSocket })
546+
// 关键: bot 不能参与 BottomAIBar 的"最小 clientID 选举", 否则比用户 cc id 小时会把用户挤出执行者位置
547+
// setLocalState(null) 让 bot 在 awareness 里不可见, 用户 cc 不会把它算作竞争者
548+
try { provider.awareness?.setLocalState(null) } catch {}
546549
const yNodes = doc.getMap('nodes')
547550

548551
// 等同步完成才记 baseline (否则会把已有节点都算成"新"的)

src/collab/aletheiaInbox.js

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ function getInboxMap() {
2727
return _inboxMap
2828
}
2929

30-
/** 当前在线 awareness 状态里 client id 最小者 — 简单选举, 多 cc 不重复执行 */
30+
/** 当前在线 awareness 状态里 client id 最小者 — 简单选举, 多 cc 不重复执行
31+
* 关键: 必须只算 *有 user 字段* 的 awareness — bot daemon 等 spectator 没有 user, 不参与选举 */
3132
function isElectedExecutor() {
3233
const provider = getProvider()
3334
if (!provider) return true // provider 未就绪默认让自己 fire (单机)
@@ -36,7 +37,11 @@ function isElectedExecutor() {
3637
const states = awareness.getStates()
3738
if (states.size === 0) return true
3839
let minId = myId
39-
states.forEach((_state, clientId) => { if (clientId < minId) minId = clientId })
40+
states.forEach((state, clientId) => {
41+
// 只把"真用户" cc 计入选举 — 没 user 字段的是 bot/script 等 spectator
42+
if (!state || !state.user) return
43+
if (clientId < minId) minId = clientId
44+
})
4045
return minId === myId
4146
}
4247

0 commit comments

Comments
 (0)