mirror of
https://github.com/Ed1s0nZ/CyberStrikeAI.git
synced 2026-08-15 07:30:53 +02:00
168 lines
5.9 KiB
Go
168 lines
5.9 KiB
Go
package multiagent
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
|
|
"github.com/cloudwego/eino/adk"
|
|
"github.com/cloudwego/eino/schema"
|
|
"go.uber.org/zap"
|
|
)
|
|
|
|
type einoAssistantStreamEventHandlerConfig struct {
|
|
Context context.Context
|
|
ConversationID string
|
|
OrchMode string
|
|
Progress func(eventType, message string, data interface{})
|
|
Logger *zap.Logger
|
|
SnapshotMCPIDs func() []string
|
|
StreamsMainAssistant func(agent string) bool
|
|
EinoRoleTag func(agent string) string
|
|
RunProgress *einoRunProgressTracker
|
|
StdoutSuppressor *einoExecuteStdoutSuppressor
|
|
AssistantOutput *einoAssistantOutputAccumulator
|
|
RunMessages *einoRunMessageAccumulator
|
|
Usage *einoRunUsageAccumulator
|
|
ToolCallCompletion *einoStreamToolCallCompletionHandler
|
|
NextMainStreamID func() string
|
|
NextReasoningStreamID func() string
|
|
NextSubAgentReplyStreamID func() string
|
|
}
|
|
|
|
type einoAssistantStreamEventHandler struct {
|
|
ctx context.Context
|
|
conversationID string
|
|
orchMode string
|
|
progress func(eventType, message string, data interface{})
|
|
logger *zap.Logger
|
|
snapshotMCPIDs func() []string
|
|
streamsMainAssistant func(agent string) bool
|
|
einoRoleTag func(agent string) string
|
|
runProgress *einoRunProgressTracker
|
|
stdoutSuppressor *einoExecuteStdoutSuppressor
|
|
assistantOutput *einoAssistantOutputAccumulator
|
|
runMessages *einoRunMessageAccumulator
|
|
usage *einoRunUsageAccumulator
|
|
toolCallCompletion *einoStreamToolCallCompletionHandler
|
|
nextMainStreamID func() string
|
|
nextReasoningStreamID func() string
|
|
nextSubAgentReplyStreamID func() string
|
|
}
|
|
|
|
func newEinoAssistantStreamEventHandler(cfg einoAssistantStreamEventHandlerConfig) *einoAssistantStreamEventHandler {
|
|
if cfg.Context == nil {
|
|
cfg.Context = context.Background()
|
|
}
|
|
if cfg.SnapshotMCPIDs == nil {
|
|
cfg.SnapshotMCPIDs = func() []string { return nil }
|
|
}
|
|
if cfg.StreamsMainAssistant == nil {
|
|
cfg.StreamsMainAssistant = func(string) bool { return true }
|
|
}
|
|
if cfg.EinoRoleTag == nil {
|
|
cfg.EinoRoleTag = func(string) string { return "" }
|
|
}
|
|
if cfg.NextMainStreamID == nil {
|
|
cfg.NextMainStreamID = func() string { return "eino-main" }
|
|
}
|
|
if cfg.NextReasoningStreamID == nil {
|
|
cfg.NextReasoningStreamID = func() string { return "eino-reasoning" }
|
|
}
|
|
if cfg.NextSubAgentReplyStreamID == nil {
|
|
cfg.NextSubAgentReplyStreamID = func() string { return "eino-sub-reply" }
|
|
}
|
|
return &einoAssistantStreamEventHandler{
|
|
ctx: cfg.Context,
|
|
conversationID: cfg.ConversationID,
|
|
orchMode: cfg.OrchMode,
|
|
progress: cfg.Progress,
|
|
logger: cfg.Logger,
|
|
snapshotMCPIDs: cfg.SnapshotMCPIDs,
|
|
streamsMainAssistant: cfg.StreamsMainAssistant,
|
|
einoRoleTag: cfg.EinoRoleTag,
|
|
runProgress: cfg.RunProgress,
|
|
stdoutSuppressor: cfg.StdoutSuppressor,
|
|
assistantOutput: cfg.AssistantOutput,
|
|
runMessages: cfg.RunMessages,
|
|
usage: cfg.Usage,
|
|
toolCallCompletion: cfg.ToolCallCompletion,
|
|
nextMainStreamID: cfg.NextMainStreamID,
|
|
nextReasoningStreamID: cfg.NextReasoningStreamID,
|
|
nextSubAgentReplyStreamID: cfg.NextSubAgentReplyStreamID,
|
|
}
|
|
}
|
|
|
|
func (h *einoAssistantStreamEventHandler) Handle(mv *adk.MessageVariant, agentName string) (handled bool, recvErr error) {
|
|
if h == nil || mv == nil || !mv.IsStreaming || mv.MessageStream == nil || mv.Role == schema.Tool {
|
|
return false, nil
|
|
}
|
|
mainStreamID := h.nextMainStreamID()
|
|
mainEmitter := newEinoMainResponseStreamEmitter(
|
|
h.conversationID, h.orchMode, agentName, mainStreamID, h.mainIteration(agentName), h.progress, h.snapshotMCPIDs,
|
|
)
|
|
reasoningEmitter := newEinoReasoningStreamEmitter(
|
|
h.conversationID,
|
|
h.orchMode,
|
|
agentName,
|
|
h.einoRoleTag(agentName),
|
|
h.progress,
|
|
h.nextReasoningStreamID,
|
|
)
|
|
var toolStreamFragments []schema.ToolCall
|
|
var streamUsage *schema.TokenUsage
|
|
subReplyEmitter := newEinoSubAgentReplyEmitter(
|
|
h.conversationID,
|
|
agentName,
|
|
h.progress,
|
|
h.nextSubAgentReplyStreamID,
|
|
)
|
|
mainAssistantStream := newEinoMainAssistantStreamHandler(einoMainAssistantStreamHandlerConfig{
|
|
AgentName: agentName,
|
|
Emitter: mainEmitter,
|
|
StdoutSuppressor: h.stdoutSuppressor,
|
|
AssistantOutput: h.assistantOutput,
|
|
RunMessages: h.runMessages,
|
|
})
|
|
recvErr = recvEinoSchemaMessageStreamWithContext(h.ctx, mv.MessageStream, 8, func(chunk *schema.Message) {
|
|
reasoningEmitter.EmitDelta(chunk.ReasoningContent)
|
|
if chunk.Content != "" {
|
|
if h.streamsMainAssistant(agentName) {
|
|
mainAssistantStream.EmitDelta(chunk.Content)
|
|
} else if !h.streamsMainAssistant(agentName) {
|
|
subReplyEmitter.EmitDelta(chunk.Content)
|
|
}
|
|
}
|
|
if len(chunk.ToolCalls) > 0 {
|
|
toolStreamFragments = append(toolStreamFragments, chunk.ToolCalls...)
|
|
}
|
|
if chunk.ResponseMeta != nil && chunk.ResponseMeta.Usage != nil {
|
|
streamUsage = maxEinoTokenUsage(streamUsage, chunk.ResponseMeta.Usage)
|
|
}
|
|
})
|
|
if recvErr != nil && !errors.Is(recvErr, context.Canceled) && h.logger != nil {
|
|
h.logger.Warn("eino stream recv error, flushing incomplete stream",
|
|
zap.Error(recvErr),
|
|
zap.String("agent", agentName),
|
|
zap.Int("toolFragments", len(toolStreamFragments)))
|
|
}
|
|
reasoningEmitter.Finish()
|
|
if h.streamsMainAssistant(agentName) {
|
|
mainAssistantStream.Finish()
|
|
}
|
|
subReplyEmitter.Finish()
|
|
if h.toolCallCompletion != nil {
|
|
h.toolCallCompletion.Complete(toolStreamFragments, agentName)
|
|
}
|
|
if h.usage != nil {
|
|
h.usage.AddUsage(streamUsage)
|
|
}
|
|
return true, recvErr
|
|
}
|
|
|
|
func (h *einoAssistantStreamEventHandler) mainIteration(agentName string) int {
|
|
if h == nil || h.runProgress == nil {
|
|
return 0
|
|
}
|
|
return h.runProgress.MainIteration(agentName)
|
|
}
|