Merge pull request #13 from dj-oyu/fix/heartbeat-completion-message
fix: heartbeat completion shows LLM result instead of garbled streaming fragment
This commit is contained in:
commit
18d1b6e807
1 changed files with 39 additions and 12 deletions
|
|
@ -43,6 +43,7 @@ import (
|
|||
// activeTask tracks a running agent task for live status and intervention.
|
||||
type activeTask struct {
|
||||
Description string
|
||||
Result string // LLM response summary for completion notification
|
||||
Iteration int
|
||||
MaxIter int
|
||||
StartedAt time.Time
|
||||
|
|
@ -52,6 +53,7 @@ type activeTask struct {
|
|||
lastError *toolLogEntry // sticky: most recent error, persists across iterations
|
||||
projectDir string // detected from exec cd target (authoritative)
|
||||
fileCommonDir string // LCP of file paths relative to workspace (fallback)
|
||||
streamedChunks bool // true after onChunk fires at least once
|
||||
mu sync.Mutex
|
||||
}
|
||||
|
||||
|
|
@ -1054,11 +1056,15 @@ func (al *AgentLoop) runAgentLoop(ctx context.Context, agent *AgentInstance, opt
|
|||
// Publish final task status on completion for background tasks
|
||||
if opts.TaskID != "" {
|
||||
elapsed := time.Since(task.StartedAt)
|
||||
summary := task.Result
|
||||
if summary == "" {
|
||||
summary = task.Description
|
||||
}
|
||||
doneCtx, doneCancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
_ = al.bus.PublishOutbound(doneCtx, bus.OutboundMessage{
|
||||
Channel: opts.Channel,
|
||||
ChatID: opts.ChatID,
|
||||
Content: fmt.Sprintf("\u2705 Task completed (%.1fs)\n%s", elapsed.Seconds(), task.Description),
|
||||
Content: fmt.Sprintf("\u2705 Task completed (%.1fs)\n%s", elapsed.Seconds(), summary),
|
||||
IsTaskStatus: true,
|
||||
TaskID: opts.TaskID,
|
||||
})
|
||||
|
|
@ -1343,6 +1349,24 @@ func (al *AgentLoop) runAgentLoop(ctx context.Context, agent *AgentInstance, opt
|
|||
finalContent = opts.DefaultResponse
|
||||
}
|
||||
|
||||
// 5d. Store result summary for task completion notification
|
||||
if task != nil {
|
||||
task.Result = utils.Truncate(finalContent, 280)
|
||||
}
|
||||
|
||||
// 5e. Replace orphaned streaming status bubble for background tasks.
|
||||
// When SendResponse is false (e.g. heartbeat), no final non-status message
|
||||
// triggers cleanup, so the last streaming chunk persists on Telegram.
|
||||
if opts.Background && !opts.SendResponse && !constants.IsInternalChannel(opts.Channel) && task != nil &&
|
||||
task.streamedChunks {
|
||||
_ = al.bus.PublishOutbound(ctx, bus.OutboundMessage{
|
||||
Channel: opts.Channel,
|
||||
ChatID: opts.ChatID,
|
||||
Content: utils.Truncate(finalContent, 200),
|
||||
IsStatus: true,
|
||||
})
|
||||
}
|
||||
|
||||
// 6. Save final assistant message to session (deferred write-behind)
|
||||
agent.Sessions.AddMessage(opts.SessionKey, "assistant", finalContent)
|
||||
agent.Sessions.MarkDirty(opts.SessionKey)
|
||||
|
|
@ -2175,6 +2199,9 @@ func (al *AgentLoop) runLLMIteration(
|
|||
if !constants.IsInternalChannel(opts.Channel) {
|
||||
lastPublish := time.Time{}
|
||||
onChunk = func(accumulated, reasoning string) {
|
||||
if task != nil {
|
||||
task.streamedChunks = true
|
||||
}
|
||||
if time.Since(lastPublish) < 500*time.Millisecond {
|
||||
return
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue