mirror of
https://gitee.com/mateos/mateclaw.git
synced 2026-09-13 03:13:41 +08:00
fix(agent): always write FINAL_SUMMARY in DirectAnswerNode
This commit is contained in:
parent
0c5c5bc2c2
commit
ca5387ed65
@ -3,19 +3,37 @@ package vip.mate.agent.graph.plan.node;
|
||||
import com.alibaba.cloud.ai.graph.OverAllState;
|
||||
import com.alibaba.cloud.ai.graph.action.NodeAction;
|
||||
import vip.mate.agent.graph.plan.state.PlanStateKeys;
|
||||
import vip.mate.agent.graph.state.MateClawStateKeys;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 直接回答节点
|
||||
* <p>
|
||||
* 当 PlanGenerationNode 判定用户消息是简单问答时,
|
||||
* 将 direct_answer 透传为 final_summary,直接结束图执行。
|
||||
* When PlanGenerationNode classifies the user's message as a simple
|
||||
* question, this node propagates {@code direct_answer} into
|
||||
* {@code FINAL_SUMMARY} so the graph terminates with the answer in the
|
||||
* canonical place every downstream consumer reads from.
|
||||
* <p>
|
||||
* 如果 PlanGenerationNode 已通过 broadcastContent() 推送了内容
|
||||
* (contentStreamed=true),则不再复制到 FINAL_SUMMARY,
|
||||
* 避免 StreamAccumulator 重复收集导致持久化内容翻倍。
|
||||
* Earlier versions skipped writing FINAL_SUMMARY when
|
||||
* {@code CONTENT_STREAMED=true}, on the theory that broadcastContent had
|
||||
* already pushed the text and a second copy in FINAL_SUMMARY would cause
|
||||
* double persistence. That was wrong: broadcastContent goes directly to
|
||||
* the SSE side-channel via {@code streamTracker.broadcastDelta} and does
|
||||
* NOT participate in the DB segment that ChatController accumulates from
|
||||
* the structured stream. Skipping FINAL_SUMMARY left
|
||||
* {@code AgentService.chat()} (the sync entry used by every IM channel)
|
||||
* with an empty reply, which silently dropped DingTalk / Slack /
|
||||
* Telegram replies on the direct-answer path. It also left
|
||||
* {@code mate_message.content} empty on the web channel — the SSE
|
||||
* client saw the answer in real time but reopening the conversation
|
||||
* showed a blank assistant turn.
|
||||
* <p>
|
||||
* Re-broadcast suppression is the responsibility of the stream layer,
|
||||
* not this node:
|
||||
* {@link vip.mate.agent.graph.plan.StateGraphPlanExecuteAgent#chatStructuredStream}
|
||||
* tags the FINAL_SUMMARY delta as {@code persistOnly} when
|
||||
* CONTENT_STREAMED is true, and {@code ChatController} respects that flag
|
||||
* to persist without re-pushing.
|
||||
*
|
||||
* @author MateClaw Team
|
||||
*/
|
||||
@ -23,11 +41,6 @@ public class DirectAnswerNode implements NodeAction {
|
||||
|
||||
@Override
|
||||
public Map<String, Object> apply(OverAllState state) {
|
||||
boolean alreadyStreamed = state.value(MateClawStateKeys.CONTENT_STREAMED, false);
|
||||
if (alreadyStreamed) {
|
||||
// broadcastContent 已推送并被 accumulator 收集,不重复写入 FINAL_SUMMARY
|
||||
return Map.of();
|
||||
}
|
||||
String directAnswer = state.value(PlanStateKeys.DIRECT_ANSWER, "");
|
||||
return Map.of(PlanStateKeys.FINAL_SUMMARY, directAnswer);
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user