feat(wecom): implement periodic processing hints and enforce WeCom stream deadline
This commit is contained in:
parent
6f5d1f336f
commit
ed810259eb
1 changed files with 48 additions and 6 deletions
|
|
@ -26,6 +26,12 @@ const (
|
||||||
wsSubscribeTimeout = 10 * time.Second
|
wsSubscribeTimeout = 10 * time.Second
|
||||||
wsMaxReconnectWait = 60 * time.Second
|
wsMaxReconnectWait = 60 * time.Second
|
||||||
wsInitialReconnect = time.Second
|
wsInitialReconnect = time.Second
|
||||||
|
|
||||||
|
// WeCom requires finish=true within 6 minutes of the first stream frame.
|
||||||
|
// wsStreamTickInterval controls how often we send an in-progress hint.
|
||||||
|
// wsStreamMaxDuration is a safety margin below the 6-minute hard limit.
|
||||||
|
wsStreamTickInterval = 30 * time.Second
|
||||||
|
wsStreamMaxDuration = 5*time.Minute + 30*time.Second
|
||||||
)
|
)
|
||||||
|
|
||||||
// WeComAIBotWSChannel implements channels.Channel for WeCom AI Bot using the
|
// WeComAIBotWSChannel implements channels.Channel for WeCom AI Bot using the
|
||||||
|
|
@ -605,15 +611,51 @@ func (c *WeComAIBotWSChannel) handleWSTextMessage(reqID string, msg WeComAIBotWS
|
||||||
"aibotid": msg.AIBotID,
|
"aibotid": msg.AIBotID,
|
||||||
"stream_id": streamID,
|
"stream_id": streamID,
|
||||||
}
|
}
|
||||||
|
// PublishInbound is non-blocking; the agent will call Send() when done.
|
||||||
c.HandleMessage(taskCtx, peer, msg.MsgID, userID, chatID,
|
c.HandleMessage(taskCtx, peer, msg.MsgID, userID, chatID,
|
||||||
msg.Text.Content, nil, metadata, sender)
|
msg.Text.Content, nil, metadata, sender)
|
||||||
|
|
||||||
// Wait for the agent reply and send it as the final stream frame.
|
// Wait for the agent reply. While waiting, send periodic finish=false
|
||||||
|
// hints so the user knows processing is still in progress.
|
||||||
|
// WeCom requires finish=true within 6 minutes of the first stream frame;
|
||||||
|
// wsStreamMaxDuration enforces that limit with a safety margin.
|
||||||
|
waitHints := []string{
|
||||||
|
"⏳ Processing, please wait...",
|
||||||
|
"⏳ Still processing, please wait...",
|
||||||
|
"⏳ Almost there, please wait...",
|
||||||
|
}
|
||||||
|
ticker := time.NewTicker(wsStreamTickInterval)
|
||||||
|
defer ticker.Stop()
|
||||||
|
deadlineTimer := time.NewTimer(wsStreamMaxDuration)
|
||||||
|
defer deadlineTimer.Stop()
|
||||||
|
tickCount := 0
|
||||||
|
for {
|
||||||
select {
|
select {
|
||||||
case answer := <-task.answerCh:
|
case answer := <-task.answerCh:
|
||||||
|
// Agent replied — deliver the real answer as the final frame.
|
||||||
c.wsSendStreamFinish(reqID, streamID, answer)
|
c.wsSendStreamFinish(reqID, streamID, answer)
|
||||||
|
return
|
||||||
|
case <-ticker.C:
|
||||||
|
// Send an in-progress hint (finish=false). WeCom replaces the
|
||||||
|
// displayed content with the latest non-finish frame, so the
|
||||||
|
// user just sees the most recent hint, not an accumulation.
|
||||||
|
hint := waitHints[tickCount%len(waitHints)]
|
||||||
|
tickCount++
|
||||||
|
logger.DebugCF("wecom_aibot", "Sending stream progress hint",
|
||||||
|
map[string]any{"chat_id": chatID, "tick": tickCount})
|
||||||
|
c.wsSendStreamChunk(reqID, streamID, false, hint)
|
||||||
|
case <-deadlineTimer.C:
|
||||||
|
// Hard deadline reached before the agent replied. Close the
|
||||||
|
// stream with a timeout notice (still within the 6-minute window).
|
||||||
|
logger.WarnCF("wecom_aibot", "Stream deadline reached without agent reply",
|
||||||
|
map[string]any{"chat_id": chatID, "stream_id": streamID})
|
||||||
|
c.wsSendStreamFinish(reqID, streamID,
|
||||||
|
"⏳ Processing is taking longer than expected. Please resend your message to try again.")
|
||||||
|
return
|
||||||
case <-taskCtx.Done():
|
case <-taskCtx.Done():
|
||||||
// Connection dropped or task canceled; nothing to send.
|
// Connection dropped or task canceled; nothing to send.
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue