mirror of
https://github.com/Ed1s0nZ/CyberStrikeAI.git
synced 2026-07-14 07:57:26 +02:00
Add files via upload
This commit is contained in:
@@ -0,0 +1,157 @@
|
||||
package multiagent
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"strings"
|
||||
|
||||
"github.com/cloudwego/eino/adk/prebuilt/planexecute"
|
||||
)
|
||||
|
||||
// lenientPlan keeps plan_execute running even when model tool arguments contain minor JSON defects.
|
||||
// It first tries strict JSON, then falls back to lightweight step extraction heuristics.
|
||||
type lenientPlan struct {
|
||||
Steps []string `json:"steps"`
|
||||
}
|
||||
|
||||
func newLenientPlan(context.Context) planexecute.Plan {
|
||||
return &lenientPlan{}
|
||||
}
|
||||
|
||||
func (p *lenientPlan) FirstStep() string {
|
||||
if p == nil || len(p.Steps) == 0 {
|
||||
return ""
|
||||
}
|
||||
return p.Steps[0]
|
||||
}
|
||||
|
||||
func (p *lenientPlan) MarshalJSON() ([]byte, error) {
|
||||
type alias lenientPlan
|
||||
return json.Marshal((*alias)(p))
|
||||
}
|
||||
|
||||
func (p *lenientPlan) UnmarshalJSON(b []byte) error {
|
||||
type alias lenientPlan
|
||||
var strict alias
|
||||
if err := json.Unmarshal(b, &strict); err == nil {
|
||||
strict.Steps = normalizePlanSteps(strict.Steps)
|
||||
if len(strict.Steps) > 0 {
|
||||
*p = lenientPlan(strict)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
steps := extractPlanStepsLenient(string(b))
|
||||
if len(steps) == 0 {
|
||||
steps = []string{"继续按当前目标执行下一步,并输出可验证证据。"}
|
||||
}
|
||||
p.Steps = steps
|
||||
return nil
|
||||
}
|
||||
|
||||
func extractPlanStepsLenient(raw string) []string {
|
||||
s := strings.TrimSpace(stripCodeFence(raw))
|
||||
if s == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
if extracted, ok := sliceByStepsArray(s); ok {
|
||||
var arr []string
|
||||
if err := json.Unmarshal([]byte(extracted), &arr); err == nil {
|
||||
arr = normalizePlanSteps(arr)
|
||||
if len(arr) > 0 {
|
||||
return arr
|
||||
}
|
||||
}
|
||||
if arr := splitStepsHeuristically(strings.Trim(extracted, "[]")); len(arr) > 0 {
|
||||
return arr
|
||||
}
|
||||
}
|
||||
|
||||
// Last-resort: treat plaintext body as one actionable step.
|
||||
s = strings.TrimSpace(s)
|
||||
if s == "" {
|
||||
return nil
|
||||
}
|
||||
return []string{s}
|
||||
}
|
||||
|
||||
func sliceByStepsArray(s string) (string, bool) {
|
||||
lower := strings.ToLower(s)
|
||||
key := `"steps"`
|
||||
i := strings.Index(lower, key)
|
||||
if i < 0 {
|
||||
return "", false
|
||||
}
|
||||
start := strings.Index(s[i:], "[")
|
||||
if start < 0 {
|
||||
return "", false
|
||||
}
|
||||
start += i
|
||||
depth := 0
|
||||
for j := start; j < len(s); j++ {
|
||||
switch s[j] {
|
||||
case '[':
|
||||
depth++
|
||||
case ']':
|
||||
depth--
|
||||
if depth == 0 {
|
||||
return s[start : j+1], true
|
||||
}
|
||||
}
|
||||
}
|
||||
return "", false
|
||||
}
|
||||
|
||||
func splitStepsHeuristically(body string) []string {
|
||||
body = strings.ReplaceAll(body, "\r\n", "\n")
|
||||
body = strings.ReplaceAll(body, "\\n", "\n")
|
||||
var parts []string
|
||||
if strings.Contains(body, "\n") {
|
||||
for _, line := range strings.Split(body, "\n") {
|
||||
parts = append(parts, line)
|
||||
}
|
||||
} else {
|
||||
for _, seg := range strings.Split(body, ",") {
|
||||
parts = append(parts, seg)
|
||||
}
|
||||
}
|
||||
|
||||
out := make([]string, 0, len(parts))
|
||||
for _, part := range parts {
|
||||
t := strings.TrimSpace(part)
|
||||
t = strings.Trim(t, "\"'`")
|
||||
t = strings.TrimLeft(t, "-*0123456789.、 \t")
|
||||
t = strings.TrimSpace(strings.ReplaceAll(t, `\"`, `"`))
|
||||
if t == "" {
|
||||
continue
|
||||
}
|
||||
out = append(out, t)
|
||||
}
|
||||
return normalizePlanSteps(out)
|
||||
}
|
||||
|
||||
func normalizePlanSteps(in []string) []string {
|
||||
out := make([]string, 0, len(in))
|
||||
for _, step := range in {
|
||||
t := strings.TrimSpace(step)
|
||||
if t == "" {
|
||||
continue
|
||||
}
|
||||
out = append(out, t)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func stripCodeFence(s string) string {
|
||||
s = strings.TrimSpace(s)
|
||||
if !strings.HasPrefix(s, "```") {
|
||||
return s
|
||||
}
|
||||
s = strings.TrimPrefix(s, "```json")
|
||||
s = strings.TrimPrefix(s, "```JSON")
|
||||
s = strings.TrimPrefix(s, "```")
|
||||
s = strings.TrimSuffix(strings.TrimSpace(s), "```")
|
||||
return strings.TrimSpace(s)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user