mirror of
https://github.com/Ed1s0nZ/CyberStrikeAI.git
synced 2026-07-16 17:07:39 +02:00
77 lines
2.2 KiB
Go
77 lines
2.2 KiB
Go
package multiagent
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"strings"
|
|
|
|
"github.com/cloudwego/eino/adk"
|
|
"github.com/cloudwego/eino/schema"
|
|
"go.uber.org/zap"
|
|
)
|
|
|
|
// toolSearchResultSanitizerMiddleware prevents malformed historical tool_search
|
|
// results (for example an HTML gateway error page) from crashing Eino's dynamic
|
|
// tool loader on every retry. Eino expects every tool_search result to be a JSON
|
|
// object containing selectedTools.
|
|
type toolSearchResultSanitizerMiddleware struct {
|
|
adk.BaseChatModelAgentMiddleware
|
|
logger *zap.Logger
|
|
phase string
|
|
}
|
|
|
|
func newToolSearchResultSanitizerMiddleware(logger *zap.Logger, phase string) adk.ChatModelAgentMiddleware {
|
|
return &toolSearchResultSanitizerMiddleware{logger: logger, phase: phase}
|
|
}
|
|
|
|
type toolSearchResultEnvelope struct {
|
|
SelectedTools []string `json:"selectedTools"`
|
|
}
|
|
|
|
func validToolSearchResult(content string) bool {
|
|
var result toolSearchResultEnvelope
|
|
if err := json.Unmarshal([]byte(content), &result); err != nil {
|
|
return false
|
|
}
|
|
// Reject JSON values such as null. They unmarshal without an error but do not
|
|
// satisfy the object-shaped contract used by the toolsearch middleware.
|
|
return strings.HasPrefix(strings.TrimSpace(content), "{")
|
|
}
|
|
|
|
func (m *toolSearchResultSanitizerMiddleware) BeforeModelRewriteState(
|
|
ctx context.Context,
|
|
state *adk.ChatModelAgentState,
|
|
_ *adk.ModelContext,
|
|
) (context.Context, *adk.ChatModelAgentState, error) {
|
|
if m == nil || state == nil || len(state.Messages) == 0 {
|
|
return ctx, state, nil
|
|
}
|
|
|
|
var rewritten []adk.Message
|
|
repaired := 0
|
|
for i, msg := range state.Messages {
|
|
if msg == nil || msg.Role != schema.Tool || !IsToolSearchTool(msg.ToolName) || validToolSearchResult(msg.Content) {
|
|
continue
|
|
}
|
|
if rewritten == nil {
|
|
rewritten = append([]adk.Message(nil), state.Messages...)
|
|
}
|
|
clone := *msg
|
|
clone.Content = `{"selectedTools":[],"_recovered":true,"reason":"invalid historical tool_search result"}`
|
|
rewritten[i] = &clone
|
|
repaired++
|
|
}
|
|
|
|
if repaired == 0 {
|
|
return ctx, state, nil
|
|
}
|
|
if m.logger != nil {
|
|
m.logger.Warn("invalid historical tool_search results repaired before model call",
|
|
zap.String("phase", m.phase),
|
|
zap.Int("repaired_count", repaired))
|
|
}
|
|
ns := *state
|
|
ns.Messages = rewritten
|
|
return ctx, &ns, nil
|
|
}
|