mirror of
https://github.com/Ed1s0nZ/CyberStrikeAI.git
synced 2026-05-27 01:32:26 +02:00
123 lines
4.1 KiB
Go
123 lines
4.1 KiB
Go
package handler
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"strings"
|
|
"time"
|
|
|
|
"cyberstrike-ai/internal/agent"
|
|
"cyberstrike-ai/internal/multiagent"
|
|
)
|
|
|
|
func (h *AgentHandler) einoRunRetryMaxAttempts() int {
|
|
if h.config != nil {
|
|
return multiagent.RunRetryMaxAttemptsFromConfig(&h.config.MultiAgent.EinoMiddleware)
|
|
}
|
|
return multiagent.RunRetryMaxAttemptsFromConfig(nil)
|
|
}
|
|
|
|
func (h *AgentHandler) einoRunRetryMaxBackoffSec() int {
|
|
if h.config != nil && h.config.MultiAgent.EinoMiddleware.RunRetryMaxBackoffSec > 0 {
|
|
return h.config.MultiAgent.EinoMiddleware.RunRetryMaxBackoffSec
|
|
}
|
|
return 0
|
|
}
|
|
|
|
// applyEinoTraceResumeSegment 中断并继续:persist last_react_* → loadHistory,可选替换下一段 user 文案。
|
|
func (h *AgentHandler) applyEinoTraceResumeSegment(
|
|
conversationID string,
|
|
result *multiagent.RunResult,
|
|
curHistory *[]agent.ChatMessage,
|
|
curFinalMessage *string,
|
|
segmentUserMessage string,
|
|
) {
|
|
if shouldPersistEinoAgentTraceAfterRunError(context.Background()) {
|
|
h.persistEinoAgentTraceForResume(conversationID, result)
|
|
}
|
|
if hist, err := h.loadHistoryFromAgentTrace(conversationID); err == nil && len(hist) > 0 {
|
|
*curHistory = hist
|
|
}
|
|
if segmentUserMessage != "" {
|
|
*curFinalMessage = segmentUserMessage
|
|
}
|
|
}
|
|
|
|
// applyEinoTransientRetrySegment 临时错误重试:恢复轨迹并保留本请求原始 user 文案(不注入续跑说明)。
|
|
// segmentUserMessage 为本轮 HTTP 请求开始时用户发送的内容,避免因清空 finalMessage 而丢失「你好」等短句。
|
|
func (h *AgentHandler) applyEinoTransientRetrySegment(
|
|
conversationID string,
|
|
result *multiagent.RunResult,
|
|
curHistory *[]agent.ChatMessage,
|
|
curFinalMessage *string,
|
|
segmentUserMessage string,
|
|
) {
|
|
if shouldPersistEinoAgentTraceAfterRunError(context.Background()) {
|
|
h.persistEinoAgentTraceForResume(conversationID, result)
|
|
}
|
|
if hist, err := h.loadHistoryFromAgentTrace(conversationID); err == nil && len(hist) > 0 {
|
|
*curHistory = hist
|
|
}
|
|
if s := strings.TrimSpace(segmentUserMessage); s != "" {
|
|
*curFinalMessage = segmentUserMessage
|
|
}
|
|
}
|
|
|
|
// handleEinoTransientRetryContinue 在 SSE 任务循环内处理临时错误重试;返回 true 表示外层 for 应 continue。
|
|
func (h *AgentHandler) handleEinoTransientRetryContinue(
|
|
baseCtx context.Context,
|
|
conversationID string,
|
|
result *multiagent.RunResult,
|
|
runErr error,
|
|
transientAttempts *int,
|
|
curHistory *[]agent.ChatMessage,
|
|
curFinalMessage *string,
|
|
segmentUserMessage string,
|
|
progressCallback func(eventType, message string, data interface{}),
|
|
sendProgress func(msg string, extra map[string]interface{}),
|
|
) (handled bool, fatal error) {
|
|
if !errors.Is(runErr, multiagent.ErrTransientRetryContinue) {
|
|
return false, nil
|
|
}
|
|
maxAttempts := h.einoRunRetryMaxAttempts()
|
|
*transientAttempts++
|
|
if *transientAttempts > maxAttempts {
|
|
if shouldPersistEinoAgentTraceAfterRunError(baseCtx) {
|
|
h.persistEinoAgentTraceForResume(conversationID, result)
|
|
}
|
|
return false, errors.New("transient retry exhausted: " + runErr.Error())
|
|
}
|
|
attemptNo := *transientAttempts
|
|
backoff := multiagent.TransientRetryBackoff(attemptNo-1, h.einoRunRetryMaxBackoffSec())
|
|
if progressCallback != nil {
|
|
progressCallback("eino_run_retry", fmt.Sprintf("遇到临时错误,%d 秒后第 %d/%d 次重试…", int(backoff.Seconds()), attemptNo, maxAttempts), map[string]interface{}{
|
|
"conversationId": conversationID,
|
|
"source": "eino",
|
|
"attempt": attemptNo,
|
|
"maxAttempts": maxAttempts,
|
|
"backoffSec": int(backoff.Seconds()),
|
|
})
|
|
}
|
|
select {
|
|
case <-baseCtx.Done():
|
|
return false, context.Cause(baseCtx)
|
|
case <-time.After(backoff):
|
|
}
|
|
h.applyEinoTransientRetrySegment(conversationID, result, curHistory, curFinalMessage, segmentUserMessage)
|
|
if progressCallback != nil {
|
|
progressCallback("eino_run_retry", "已恢复上下文,正在重试…", map[string]interface{}{
|
|
"conversationId": conversationID,
|
|
"source": "eino",
|
|
"attempt": attemptNo,
|
|
})
|
|
}
|
|
if sendProgress != nil {
|
|
sendProgress("正在重试…", map[string]interface{}{
|
|
"conversationId": conversationID,
|
|
"source": "transient_retry",
|
|
})
|
|
}
|
|
return true, nil
|
|
}
|