feat(feishu): improve document comment session, rich parsing, and typing feedback (#63785)

* Feishu: upgrade comment session, context parsing, and typing reaction

* test(feishu): align comment prompt assertions
This commit is contained in:
wittam-01
2026-04-11 17:26:21 +08:00
committed by GitHub
parent 2c57ec7b5f
commit ebb72baba3
15 changed files with 2737 additions and 148 deletions

View File

@@ -29,7 +29,8 @@ type HandleFeishuCommentEventParams = {
function buildCommentSessionKey(params: {
core: ReturnType<typeof getFeishuRuntime>;
route: ResolvedAgentRoute;
commentTarget: string;
fileType: string;
fileToken: string;
}): string {
return params.core.channel.routing.buildAgentSessionKey({
agentId: params.route.agentId,
@@ -37,7 +38,7 @@ function buildCommentSessionKey(params: {
accountId: params.route.accountId,
peer: {
kind: "direct",
id: params.commentTarget,
id: `comment-doc:${params.fileType}:${params.fileToken}`,
},
dmScope: "per-account-channel-peer",
});
@@ -172,7 +173,8 @@ export async function handleFeishuCommentEvent(
const commentSessionKey = buildCommentSessionKey({
core,
route,
commentTarget,
fileType: turn.fileType,
fileToken: turn.fileToken,
});
const bodyForAgent = `[message_id: ${turn.messageId}]\n${turn.prompt}`;
const ctxPayload = core.channel.reply.finalizeInboundContext({
@@ -193,6 +195,9 @@ export async function handleFeishuCommentEvent(
Provider: "feishu",
Surface: "feishu-comment",
MessageSid: turn.messageId,
// For Feishu comment turns, MessageThreadId carries the inbound reply_id so
// comment-aware tools can clean typing reaction before sending visible output.
MessageThreadId: turn.replyId,
Timestamp: parseTimestampMs(turn.timestamp),
WasMentioned: turn.isMentioned,
CommandAuthorized: false,
@@ -214,36 +219,41 @@ export async function handleFeishuCommentEvent(
},
});
const { dispatcher, replyOptions, markDispatchIdle } = createFeishuCommentReplyDispatcher({
cfg: effectiveCfg,
agentId: route.agentId,
runtime,
accountId: account.accountId,
fileToken: turn.fileToken,
fileType: turn.fileType,
commentId: turn.commentId,
isWholeComment: turn.isWholeComment,
});
const { dispatcher, replyOptions, markDispatchIdle, markRunComplete, cleanupTypingReaction } =
createFeishuCommentReplyDispatcher({
cfg: effectiveCfg,
agentId: route.agentId,
runtime,
accountId: account.accountId,
fileToken: turn.fileToken,
fileType: turn.fileType,
commentId: turn.commentId,
replyId: turn.replyId,
isWholeComment: turn.isWholeComment,
});
log(
`feishu[${account.accountId}]: dispatching drive comment to agent ` +
`(session=${commentSessionKey} comment=${turn.commentId} type=${turn.noticeType})`,
);
const { queuedFinal, counts } = await core.channel.reply.withReplyDispatcher({
dispatcher,
onSettled: () => {
markDispatchIdle();
},
run: () =>
core.channel.reply.dispatchReplyFromConfig({
ctx: ctxPayload,
cfg: effectiveCfg,
dispatcher,
replyOptions,
}),
});
log(
`feishu[${account.accountId}]: drive comment dispatch complete ` +
`(queuedFinal=${queuedFinal}, replies=${counts.final}, session=${commentSessionKey})`,
);
try {
log(
`feishu[${account.accountId}]: dispatching drive comment to agent ` +
`(session=${commentSessionKey} comment=${turn.commentId} type=${turn.noticeType})`,
);
const { queuedFinal, counts } = await core.channel.reply.withReplyDispatcher({
dispatcher,
run: () =>
core.channel.reply.dispatchReplyFromConfig({
ctx: ctxPayload,
cfg: effectiveCfg,
dispatcher,
replyOptions,
}),
});
log(
`feishu[${account.accountId}]: drive comment dispatch complete ` +
`(queuedFinal=${queuedFinal}, replies=${counts.final}, session=${commentSessionKey})`,
);
} finally {
markRunComplete();
markDispatchIdle();
void cleanupTypingReaction();
}
}