mirror of
https://github.com/Ed1s0nZ/CyberStrikeAI.git
synced 2026-08-15 15:40:38 +02:00
250 lines
8.3 KiB
Go
250 lines
8.3 KiB
Go
package multiagent
|
|
|
|
import (
|
|
"errors"
|
|
"io"
|
|
"testing"
|
|
|
|
"github.com/cloudwego/eino/adk"
|
|
"github.com/cloudwego/eino/schema"
|
|
)
|
|
|
|
func TestAdaptAgenticEventToEinoEventsAssistantMessage(t *testing.T) {
|
|
usage := &schema.TokenUsage{PromptTokens: 10, CompletionTokens: 5, TotalTokens: 15}
|
|
ev := &adk.TypedAgentEvent[*schema.AgenticMessage]{
|
|
AgentName: "agentic",
|
|
Output: &adk.TypedAgentOutput[*schema.AgenticMessage]{
|
|
MessageOutput: &adk.TypedMessageVariant[*schema.AgenticMessage]{
|
|
Message: &schema.AgenticMessage{
|
|
Role: schema.AgenticRoleTypeAssistant,
|
|
ResponseMeta: &schema.AgenticResponseMeta{TokenUsage: usage},
|
|
ContentBlocks: []*schema.ContentBlock{
|
|
schema.NewContentBlock(&schema.Reasoning{Text: "think"}),
|
|
schema.NewContentBlock(&schema.AssistantGenText{Text: "calling"}),
|
|
schema.NewContentBlock(&schema.FunctionToolCall{CallID: "call-1", Name: "scan", Arguments: `{"host":"127.0.0.1"}`}),
|
|
},
|
|
},
|
|
},
|
|
CustomizedOutput: "custom",
|
|
},
|
|
}
|
|
|
|
got := adaptAgenticEventToEinoEvents(ev)
|
|
if len(got) != 1 {
|
|
t.Fatalf("events = %d, want 1", len(got))
|
|
}
|
|
mv := got[0].Output.MessageOutput
|
|
if got[0].AgentName != "agentic" || got[0].Output.CustomizedOutput != "custom" {
|
|
t.Fatalf("event metadata = %#v", got[0])
|
|
}
|
|
if mv.Role != schema.Assistant || mv.Message.Role != schema.Assistant {
|
|
t.Fatalf("role = %q/%q, want assistant", mv.Role, mv.Message.Role)
|
|
}
|
|
if mv.Message.Content != "calling" || mv.Message.ReasoningContent != "think" {
|
|
t.Fatalf("message text = %#v", mv.Message)
|
|
}
|
|
if len(mv.Message.ToolCalls) != 1 || mv.Message.ToolCalls[0].ID != "call-1" || mv.Message.ToolCalls[0].Function.Name != "scan" {
|
|
t.Fatalf("tool calls = %#v", mv.Message.ToolCalls)
|
|
}
|
|
if mv.Message.ResponseMeta == nil || mv.Message.ResponseMeta.Usage != usage {
|
|
t.Fatalf("usage = %#v, want original usage", mv.Message.ResponseMeta)
|
|
}
|
|
}
|
|
|
|
func TestAdaptAgenticEventToEinoEventsPureToolResult(t *testing.T) {
|
|
ev := &adk.TypedAgentEvent[*schema.AgenticMessage]{
|
|
Output: &adk.TypedAgentOutput[*schema.AgenticMessage]{
|
|
MessageOutput: &adk.TypedMessageVariant[*schema.AgenticMessage]{
|
|
Message: &schema.AgenticMessage{
|
|
Role: schema.AgenticRoleTypeUser,
|
|
ContentBlocks: []*schema.ContentBlock{
|
|
schema.NewContentBlock(&schema.FunctionToolResult{
|
|
CallID: "call-2",
|
|
Name: "execute",
|
|
Content: []*schema.FunctionToolResultContentBlock{{
|
|
Type: schema.FunctionToolResultContentBlockTypeText,
|
|
Text: &schema.UserInputText{Text: "done"},
|
|
}},
|
|
}),
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
got := adaptAgenticEventToEinoEvents(ev)
|
|
if len(got) != 1 {
|
|
t.Fatalf("events = %d, want 1", len(got))
|
|
}
|
|
msg := got[0].Output.MessageOutput.Message
|
|
if got[0].Output.MessageOutput.Role != schema.Tool || msg.Role != schema.Tool || msg.ToolName != "execute" || msg.ToolCallID != "call-2" || msg.Content != "done" {
|
|
t.Fatalf("tool event = %#v message=%#v", got[0].Output.MessageOutput, msg)
|
|
}
|
|
}
|
|
|
|
func TestAdaptAgenticEventToEinoEventsSplitsMixedToolResult(t *testing.T) {
|
|
ev := &adk.TypedAgentEvent[*schema.AgenticMessage]{
|
|
Output: &adk.TypedAgentOutput[*schema.AgenticMessage]{
|
|
MessageOutput: &adk.TypedMessageVariant[*schema.AgenticMessage]{
|
|
Message: &schema.AgenticMessage{
|
|
Role: schema.AgenticRoleTypeAssistant,
|
|
ContentBlocks: []*schema.ContentBlock{
|
|
schema.NewContentBlock(&schema.AssistantGenText{Text: "text"}),
|
|
schema.NewContentBlock(&schema.FunctionToolResult{
|
|
CallID: "call-3",
|
|
Name: "grep",
|
|
Content: []*schema.FunctionToolResultContentBlock{{
|
|
Type: schema.FunctionToolResultContentBlockTypeText,
|
|
Text: &schema.UserInputText{Text: "match"},
|
|
}},
|
|
}),
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
got := adaptAgenticEventToEinoEvents(ev)
|
|
if len(got) != 2 {
|
|
t.Fatalf("events = %d, want assistant + tool", len(got))
|
|
}
|
|
if got[0].Output.MessageOutput.Role != schema.Assistant || got[0].Output.MessageOutput.Message.Content != "text" {
|
|
t.Fatalf("assistant event = %#v", got[0].Output.MessageOutput)
|
|
}
|
|
if got[1].Output.MessageOutput.Role != schema.Tool || got[1].Output.MessageOutput.Message.ToolName != "grep" {
|
|
t.Fatalf("tool event = %#v", got[1].Output.MessageOutput)
|
|
}
|
|
}
|
|
|
|
func TestAdaptAgenticEventToEinoEventsStreamingAssistant(t *testing.T) {
|
|
stream := schema.StreamReaderFromArray([]*schema.AgenticMessage{
|
|
{
|
|
Role: schema.AgenticRoleTypeAssistant,
|
|
ContentBlocks: []*schema.ContentBlock{
|
|
schema.NewContentBlock(&schema.AssistantGenText{Text: "hel"}),
|
|
},
|
|
},
|
|
{
|
|
Role: schema.AgenticRoleTypeAssistant,
|
|
ContentBlocks: []*schema.ContentBlock{
|
|
schema.NewContentBlock(&schema.AssistantGenText{Text: "lo"}),
|
|
},
|
|
},
|
|
})
|
|
ev := &adk.TypedAgentEvent[*schema.AgenticMessage]{
|
|
Output: &adk.TypedAgentOutput[*schema.AgenticMessage]{
|
|
MessageOutput: &adk.TypedMessageVariant[*schema.AgenticMessage]{
|
|
IsStreaming: true,
|
|
MessageStream: stream,
|
|
AgenticRole: schema.AgenticRoleTypeAssistant,
|
|
},
|
|
},
|
|
}
|
|
|
|
got := adaptAgenticEventToEinoEvents(ev)
|
|
if len(got) != 1 {
|
|
t.Fatalf("events = %d, want 1", len(got))
|
|
}
|
|
mv := got[0].Output.MessageOutput
|
|
if !mv.IsStreaming || mv.Role != schema.Assistant {
|
|
t.Fatalf("stream variant = %#v", mv)
|
|
}
|
|
first, err := mv.MessageStream.Recv()
|
|
if err != nil || first.Content != "hel" {
|
|
t.Fatalf("first = %#v err=%v", first, err)
|
|
}
|
|
second, err := mv.MessageStream.Recv()
|
|
if err != nil || second.Content != "lo" {
|
|
t.Fatalf("second = %#v err=%v", second, err)
|
|
}
|
|
_, err = mv.MessageStream.Recv()
|
|
if !errors.Is(err, io.EOF) {
|
|
t.Fatalf("final err = %v, want EOF", err)
|
|
}
|
|
}
|
|
|
|
func TestAdaptAgenticStreamingToolResultFeedsClassicToolResultHandler(t *testing.T) {
|
|
stream := schema.StreamReaderFromArray([]*schema.AgenticMessage{
|
|
{
|
|
Role: schema.AgenticRoleTypeUser,
|
|
ContentBlocks: []*schema.ContentBlock{
|
|
schema.NewContentBlock(&schema.FunctionToolResult{
|
|
CallID: "call-agentic-stream",
|
|
Name: "execute",
|
|
Content: []*schema.FunctionToolResultContentBlock{{
|
|
Type: schema.FunctionToolResultContentBlockTypeText,
|
|
Text: &schema.UserInputText{Text: "partial "},
|
|
}},
|
|
}),
|
|
},
|
|
},
|
|
{
|
|
Role: schema.AgenticRoleTypeUser,
|
|
ContentBlocks: []*schema.ContentBlock{
|
|
schema.NewContentBlock(&schema.FunctionToolResult{
|
|
CallID: "call-agentic-stream",
|
|
Name: "execute",
|
|
Content: []*schema.FunctionToolResultContentBlock{{
|
|
Type: schema.FunctionToolResultContentBlockTypeText,
|
|
Text: &schema.UserInputText{Text: "done"},
|
|
}},
|
|
}),
|
|
},
|
|
},
|
|
})
|
|
ev := &adk.TypedAgentEvent[*schema.AgenticMessage]{
|
|
AgentName: "agentic",
|
|
Output: &adk.TypedAgentOutput[*schema.AgenticMessage]{
|
|
MessageOutput: &adk.TypedMessageVariant[*schema.AgenticMessage]{
|
|
IsStreaming: true,
|
|
MessageStream: stream,
|
|
AgenticRole: schema.AgenticRoleTypeUser,
|
|
},
|
|
},
|
|
}
|
|
|
|
got := adaptAgenticEventToEinoEvents(ev)
|
|
if len(got) != 1 || got[0].Output == nil || got[0].Output.MessageOutput == nil {
|
|
t.Fatalf("events = %#v", got)
|
|
}
|
|
mv := got[0].Output.MessageOutput
|
|
if !mv.IsStreaming || mv.Role != schema.Tool {
|
|
t.Fatalf("streaming variant = %#v, want tool stream", mv)
|
|
}
|
|
|
|
var event map[string]interface{}
|
|
runMessages := newEinoRunMessageAccumulator(nil)
|
|
emitter := newEinoToolResultProgressEmitter(einoToolResultProgressEmitterConfig{
|
|
ConversationID: "conv-agentic",
|
|
Progress: func(eventType, _ string, data interface{}) {
|
|
if eventType == "tool_result" {
|
|
event, _ = data.(map[string]interface{})
|
|
}
|
|
},
|
|
})
|
|
handler := newEinoToolResultEventHandler(einoToolResultEventHandlerConfig{
|
|
RunMessages: runMessages,
|
|
Emitter: emitter,
|
|
})
|
|
if !handler.HandleStreaming(mv, "agentic") {
|
|
t.Fatal("agentic streaming tool result was not handled")
|
|
}
|
|
if event["toolName"] != "execute" || event["toolCallId"] != "call-agentic-stream" || event["result"] != "partial done" {
|
|
t.Fatalf("tool result event = %#v", event)
|
|
}
|
|
msgs := runMessages.Messages()
|
|
if len(msgs) != 1 || msgs[0].ToolName != "execute" || msgs[0].ToolCallID != "call-agentic-stream" || msgs[0].Content != "partial done" {
|
|
t.Fatalf("run messages = %#v", msgs)
|
|
}
|
|
}
|
|
|
|
func TestAdaptAgenticEventToEinoEventsPreservesErrorOnlyEvent(t *testing.T) {
|
|
wantErr := errors.New("boom")
|
|
ev := &adk.TypedAgentEvent[*schema.AgenticMessage]{AgentName: "agentic", Err: wantErr}
|
|
|
|
got := adaptAgenticEventToEinoEvents(ev)
|
|
if len(got) != 1 || got[0].AgentName != "agentic" || !errors.Is(got[0].Err, wantErr) {
|
|
t.Fatalf("events = %#v", got)
|
|
}
|
|
}
|