feat(agent): enhance event emission for final answers and fallback handling

- Updated the AgentEngine to emit final answer events even when the LLM stops without calling the final_answer tool, ensuring the frontend can render responses correctly.
- Added fallback logic in the AgentStreamHandler to emit final answers as fallback events when no answer events are streamed, improving robustness in edge cases.
This commit is contained in:
wizardchen
2026-03-19 17:21:13 +08:00
committed by lyingbug
parent c25741673c
commit 8f1237d64f
2 changed files with 53 additions and 2 deletions
@@ -445,6 +445,42 @@ func (h *AgentStreamHandler) handleComplete(ctx context.Context, evt event.Event
}
}
// Fallback: if no answer events were streamed but we have a final answer,
// emit it as answer events so the frontend can render it properly.
// This guards against edge cases where the LLM stops without calling final_answer.
if h.finalAnswer == "" && data.FinalAnswer != "" {
logger.GetLogger(h.ctx).Warnf(
"No answer events were streamed, emitting fallback answer (len=%d)", len(data.FinalAnswer),
)
fallbackID := fmt.Sprintf("answer-fallback-%d", time.Now().UnixMilli())
if err := h.streamManager.AppendEvent(h.ctx, h.sessionID, h.assistantMessageID, interfaces.StreamEvent{
ID: fallbackID,
Type: types.ResponseTypeAnswer,
Content: data.FinalAnswer,
Done: false,
Timestamp: time.Now(),
Data: map[string]interface{}{
"event_id": fallbackID,
"is_fallback": true,
},
}); err != nil {
logger.GetLogger(h.ctx).Errorf("Append fallback answer event failed: %v", err)
}
if err := h.streamManager.AppendEvent(h.ctx, h.sessionID, h.assistantMessageID, interfaces.StreamEvent{
ID: fallbackID,
Type: types.ResponseTypeAnswer,
Content: "",
Done: true,
Timestamp: time.Now(),
Data: map[string]interface{}{
"event_id": fallbackID,
"is_fallback": true,
},
}); err != nil {
logger.GetLogger(h.ctx).Errorf("Append fallback answer done event failed: %v", err)
}
}
// Send completion event to stream manager so SSE can detect completion
if err := h.streamManager.AppendEvent(h.ctx, h.sessionID, h.assistantMessageID, interfaces.StreamEvent{
ID: evt.ID,