Skip to content

Commit 49f716c

Browse files
nieaoclaude
andcommitted
fix(bot): callback 后新一轮 conclusion 没回飞书 — 抽 castAletheiaPrompt helper
问题: handleCardAction 5 个 case (decompose/dispatch/challenge/dispatch_all/redecompose) 都是 cast 新 prompt 但没注册新 pendingFeedback. pendingFeedbackByRoom 里的 ctx.fed 还是 true (上一轮发过反馈卡), reverse observer 看到新 conclusion 时直接 return. 修复: 抽 castAletheiaPrompt(room, chatId, text, attribution) helper: - proxyPost cast - 成功后立刻 registerPendingFeedback (重置 fed=false) - ensureReverseChannel (channel 已建则 noop) handleMessage 默认分支 + 5 个 callback case 全部走这个 helper, 保证 cast = register 原子绑定, 不会漏注册. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 9fb1e00 commit 49f716c

1 file changed

Lines changed: 24 additions & 29 deletions

File tree

server/feishu-bot.mjs

Lines changed: 24 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -489,11 +489,8 @@ async function handleMessage(evt) {
489489
replyText(messageId, `🤖 收到, 去办了 — 即将启动元认知 5 步...`).catch(() => {})
490490

491491
try {
492-
const r = await proxyPost('/canvas/cast/aletheia-prompt', { room, text: content, attribution })
492+
const r = await castAletheiaPrompt(room, chatId, content, attribution)
493493
if (r.ok) {
494-
// 记录这一轮等元认知的"待反馈"上下文; reverse channel 看到 conclusion 时回查
495-
registerPendingFeedback(room, { chatId, prompt: content, sentAt: Date.now() })
496-
ensureReverseChannel(room)
497494
const peers = (r.peers ?? 0)
498495
const tip = peers > 0
499496
? `已写入画布 inbox · 在线 ${peers} 人 · 选举执行者中 · 完成后我会发反馈卡片`
@@ -516,7 +513,20 @@ const pendingFeedbackByRoom = new Map() // room → { chatId, prompt, sentAt, fe
516513
let _cardSchemaDumped = false
517514

518515
function registerPendingFeedback(room, ctx) {
516+
// 重置 fed=false 让新一轮 conclusion 能再次触发反馈卡
517+
// (老 ctx 已发过的 conclusion key 仍在 sentConclusions 防重复, 不影响新轮 conclusion)
519518
pendingFeedbackByRoom.set(room, { ...ctx, fed: false })
519+
log(`[reverse] register pending feedback room=${room} prompt="${(ctx.prompt || '').slice(0, 30)}"`)
520+
}
521+
522+
// 调用 source-proxy cast + 同时注册反馈跟踪 (callback 路径必走这个 helper, 避免漏注册)
523+
async function castAletheiaPrompt(room, chatId, text, attribution) {
524+
const r = await proxyPost('/canvas/cast/aletheia-prompt', { room, text, attribution })
525+
if (r.ok && chatId) {
526+
registerPendingFeedback(room, { chatId, prompt: text, sentAt: Date.now() })
527+
ensureReverseChannel(room)
528+
}
529+
return r
520530
}
521531

522532
function ensureReverseChannel(room) {
@@ -745,11 +755,8 @@ async function handleCardAction(evt) {
745755
if (!title) return
746756
if (chatId) sendText(chatId, `⏳ 深挖中: 「${title}」...`).catch(() => {})
747757
const prompt = `深挖这个分支: 「${title}」 — 拆解到下一层细节, 给出可执行的子任务和关键变量.`
748-
const r = await proxyPost('/canvas/cast/aletheia-prompt', {
749-
room,
750-
text: prompt,
751-
attribution: { name: DAEMON_AS_NAME, via: 'feishu-card', chatId, action: 'decompose', srcNodeId: value.nodeId || '' },
752-
})
758+
const r = await castAletheiaPrompt(room, chatId, prompt,
759+
{ name: DAEMON_AS_NAME, via: 'feishu-card', chatId, action: 'decompose', srcNodeId: value.nodeId || '' })
753760
if (chatId) {
754761
await sendText(chatId, r.ok
755762
? `✓ 已下达深挖指令 (在线 ${r.peers ?? 0} cc) — 等画布产生新节点后会再发一轮反馈\n${r.canvasUrl}`
@@ -765,11 +772,8 @@ async function handleCardAction(evt) {
765772
if (!title) return
766773
if (chatId) sendText(chatId, `⏳ 派单中: 「${title}」 → Hermes worker...`).catch(() => {})
767774
const prompt = `派单执行: 「${title}」 — 把它转成一个 taskNode 并派给 Hermes worker, 拿真实结果回填 resultNode.`
768-
const r = await proxyPost('/canvas/cast/aletheia-prompt', {
769-
room,
770-
text: prompt,
771-
attribution: { name: DAEMON_AS_NAME, via: 'feishu-card', chatId, action: 'dispatch', srcNodeId: value.nodeId || '' },
772-
})
775+
const r = await castAletheiaPrompt(room, chatId, prompt,
776+
{ name: DAEMON_AS_NAME, via: 'feishu-card', chatId, action: 'dispatch', srcNodeId: value.nodeId || '' })
773777
if (chatId) {
774778
await sendText(chatId, r.ok
775779
? `✓ 派单已下达 (在线 ${r.peers ?? 0} cc) — Hermes 跑完后会写 resultNode 到画布\n${r.canvasUrl}`
@@ -785,11 +789,8 @@ async function handleCardAction(evt) {
785789
if (!title) return
786790
if (chatId) sendText(chatId, `⏳ 反驳中: 「${title}」...`).catch(() => {})
787791
const prompt = `反驳这个分支: 「${title}」 — 列出最致命的 3 条质疑, 每条说明"假设 / 反例 / 影响". 用建设性的口吻.`
788-
const r = await proxyPost('/canvas/cast/aletheia-prompt', {
789-
room,
790-
text: prompt,
791-
attribution: { name: DAEMON_AS_NAME, via: 'feishu-card', chatId, action: 'challenge', srcNodeId: value.nodeId || '' },
792-
})
792+
const r = await castAletheiaPrompt(room, chatId, prompt,
793+
{ name: DAEMON_AS_NAME, via: 'feishu-card', chatId, action: 'challenge', srcNodeId: value.nodeId || '' })
793794
if (chatId) {
794795
await sendText(chatId, r.ok
795796
? `✓ 反驳指令已下达 (在线 ${r.peers ?? 0} cc) — challengeNode 出来后会再发一轮反馈\n${r.canvasUrl}`
@@ -803,11 +804,8 @@ async function handleCardAction(evt) {
803804
const room = value.room || roomOf(chatId)
804805
if (chatId) sendText(chatId, `⏳ 派单全部分支中, 给 Hermes worker...`).catch(() => {})
805806
const prompt = `派单全部: 把当前画布上所有未派单的 ontology 分支转为 taskNode, 批量派给 Hermes worker, 拿真实结果回填.`
806-
const r = await proxyPost('/canvas/cast/aletheia-prompt', {
807-
room,
808-
text: prompt,
809-
attribution: { name: DAEMON_AS_NAME, via: 'feishu-card', chatId, action: 'dispatch_all' },
810-
})
807+
const r = await castAletheiaPrompt(room, chatId, prompt,
808+
{ name: DAEMON_AS_NAME, via: 'feishu-card', chatId, action: 'dispatch_all' })
811809
if (chatId) {
812810
await sendText(chatId, r.ok
813811
? `✓ 全量派单已下达 (在线 ${r.peers ?? 0} cc)\n${r.canvasUrl}`
@@ -826,11 +824,8 @@ async function handleCardAction(evt) {
826824
}
827825
if (chatId) sendText(chatId, `⏳ 重新拆解中: 「${origPrompt.slice(0, 40)}」...`).catch(() => {})
828826
const prompt = `重新拆解 (上次结论不满意): ${origPrompt} — 这次换一个角度, 例如限定具体场景或缩小规模.`
829-
const r = await proxyPost('/canvas/cast/aletheia-prompt', {
830-
room,
831-
text: prompt,
832-
attribution: { name: DAEMON_AS_NAME, via: 'feishu-card', chatId, action: 'redecompose' },
833-
})
827+
const r = await castAletheiaPrompt(room, chatId, prompt,
828+
{ name: DAEMON_AS_NAME, via: 'feishu-card', chatId, action: 'redecompose' })
834829
if (chatId) {
835830
await sendText(chatId, r.ok
836831
? `✓ 重新拆解已下达 (在线 ${r.peers ?? 0} cc)\n${r.canvasUrl}`

0 commit comments

Comments
 (0)