mirror of
https://github.com/Ed1s0nZ/CyberStrikeAI.git
synced 2026-08-15 07:30:53 +02:00
79 lines
2.6 KiB
Go
79 lines
2.6 KiB
Go
package multiagent
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"strings"
|
|
|
|
"github.com/cloudwego/eino/compose"
|
|
"github.com/cloudwego/eino/schema"
|
|
)
|
|
|
|
const (
|
|
modelOutputRecoveryKey = "_cyberstrike_model_output_recovery"
|
|
modelOutputRejectedResultPrefix = "[Model Output Rejected]"
|
|
)
|
|
|
|
type modelOutputRecoveryMarker struct {
|
|
Reason string `json:"reason"`
|
|
RepairAttempt int `json:"repair_attempt"`
|
|
}
|
|
|
|
// modelOutputExecutionGuardMiddleware is a compatibility shim for old persisted
|
|
// recovery-marker tool calls. New runs should let the tool layer return normal
|
|
// soft errors to the model instead of pre-rewriting model output.
|
|
func modelOutputExecutionGuardMiddleware() compose.ToolMiddleware {
|
|
messageFor := func(input *compose.ToolInput) (string, bool) {
|
|
if input == nil {
|
|
return "", false
|
|
}
|
|
var envelope map[string]json.RawMessage
|
|
if json.Unmarshal([]byte(input.Arguments), &envelope) != nil {
|
|
return "", false
|
|
}
|
|
raw, ok := envelope[modelOutputRecoveryKey]
|
|
if !ok {
|
|
return "", false
|
|
}
|
|
var marker modelOutputRecoveryMarker
|
|
_ = json.Unmarshal(raw, &marker)
|
|
return fmt.Sprintf("%s Tool call '%s' was not executed because it is a legacy model-output recovery marker (%s). Repair attempt %d.",
|
|
modelOutputRejectedResultPrefix, input.Name, marker.Reason, marker.RepairAttempt), true
|
|
}
|
|
return compose.ToolMiddleware{
|
|
Invokable: func(next compose.InvokableToolEndpoint) compose.InvokableToolEndpoint {
|
|
return func(ctx context.Context, input *compose.ToolInput) (*compose.ToolOutput, error) {
|
|
if msg, reject := messageFor(input); reject {
|
|
return &compose.ToolOutput{Result: msg}, nil
|
|
}
|
|
return next(ctx, input)
|
|
}
|
|
},
|
|
Streamable: func(next compose.StreamableToolEndpoint) compose.StreamableToolEndpoint {
|
|
return func(ctx context.Context, input *compose.ToolInput) (*compose.StreamToolOutput, error) {
|
|
if msg, reject := messageFor(input); reject {
|
|
return &compose.StreamToolOutput{Result: schema.StreamReaderFromArray([]string{msg})}, nil
|
|
}
|
|
return next(ctx, input)
|
|
}
|
|
},
|
|
}
|
|
}
|
|
|
|
func modelOutputRecoveryFromToolCall(tc schema.ToolCall) (modelOutputRecoveryMarker, bool) {
|
|
var envelope map[string]json.RawMessage
|
|
if json.Unmarshal([]byte(tc.Function.Arguments), &envelope) != nil {
|
|
return modelOutputRecoveryMarker{}, false
|
|
}
|
|
raw, ok := envelope[modelOutputRecoveryKey]
|
|
if !ok {
|
|
return modelOutputRecoveryMarker{}, false
|
|
}
|
|
var marker modelOutputRecoveryMarker
|
|
if json.Unmarshal(raw, &marker) != nil {
|
|
return modelOutputRecoveryMarker{}, false
|
|
}
|
|
return marker, strings.TrimSpace(marker.Reason) != "" || marker.RepairAttempt > 0
|
|
}
|