mirror of
https://github.com/Ed1s0nZ/CyberStrikeAI.git
synced 2026-07-04 11:37:57 +02:00
142 lines
3.7 KiB
Go
142 lines
3.7 KiB
Go
package workflow
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"strings"
|
|
)
|
|
|
|
// FieldBinding selects a value from workflow state (replaces {{...}} templates).
|
|
type FieldBinding struct {
|
|
From string `json:"from"` // inputs | previous | <nodeId>
|
|
Field string `json:"field"` // e.g. output, message
|
|
}
|
|
|
|
func parseFieldBinding(cfg map[string]any, keys ...string) (FieldBinding, bool) {
|
|
for _, key := range keys {
|
|
if cfg == nil {
|
|
continue
|
|
}
|
|
raw, ok := cfg[key]
|
|
if !ok || raw == nil {
|
|
continue
|
|
}
|
|
switch v := raw.(type) {
|
|
case map[string]any:
|
|
return FieldBinding{
|
|
From: strings.TrimSpace(fmt.Sprint(v["from"])),
|
|
Field: strings.TrimSpace(fmt.Sprint(v["field"])),
|
|
}, true
|
|
case string:
|
|
s := strings.TrimSpace(v)
|
|
if s == "" {
|
|
continue
|
|
}
|
|
var b FieldBinding
|
|
if err := json.Unmarshal([]byte(s), &b); err == nil && (b.From != "" || b.Field != "") {
|
|
return b, true
|
|
}
|
|
}
|
|
}
|
|
return FieldBinding{}, false
|
|
}
|
|
|
|
func defaultBinding(from, field string) FieldBinding {
|
|
return FieldBinding{From: from, Field: field}
|
|
}
|
|
|
|
func resolveBinding(b FieldBinding, state *WorkflowLocalState) any {
|
|
from := strings.TrimSpace(b.From)
|
|
field := strings.TrimSpace(b.Field)
|
|
if field == "" {
|
|
field = "output"
|
|
}
|
|
if from == "" || from == "previous" || from == "prev" {
|
|
if field == "output" && state.LastOutput != nil {
|
|
return state.LastOutput["output"]
|
|
}
|
|
return valueFromPath("previous."+field, state)
|
|
}
|
|
if from == "inputs" || from == "input" {
|
|
if field == "" {
|
|
return state.Inputs
|
|
}
|
|
return valueFromPath("inputs."+field, state)
|
|
}
|
|
if from == "outputs" {
|
|
return valueFromPath("outputs."+field, state)
|
|
}
|
|
return valueFromPath(from+"."+field, state)
|
|
}
|
|
|
|
func resolveBindingString(b FieldBinding, state *WorkflowLocalState) string {
|
|
return strings.TrimSpace(fmt.Sprint(resolveBinding(b, state)))
|
|
}
|
|
|
|
func resolveNodeInputBinding(cfg map[string]any, state *WorkflowLocalState) string {
|
|
if b, ok := parseFieldBinding(cfg, "input_binding"); ok {
|
|
return resolveBindingString(b, state)
|
|
}
|
|
// legacy template field removed — default previous.output
|
|
return resolveBindingString(defaultBinding("previous", "output"), state)
|
|
}
|
|
|
|
func resolveOutputSourceBinding(cfg map[string]any, state *WorkflowLocalState) any {
|
|
if b, ok := parseFieldBinding(cfg, "source_binding"); ok {
|
|
return resolveBinding(b, state)
|
|
}
|
|
return resolveBinding(defaultBinding("previous", "output"), state)
|
|
}
|
|
|
|
func resolveHITLPromptBinding(cfg map[string]any, state *WorkflowLocalState) string {
|
|
if b, ok := parseFieldBinding(cfg, "prompt_binding"); ok {
|
|
return resolveBindingString(b, state)
|
|
}
|
|
if s := cfgString(cfg, "prompt"); s != "" {
|
|
return s
|
|
}
|
|
return resolveBindingString(defaultBinding("previous", "output"), state)
|
|
}
|
|
|
|
func toolArgumentBindings(cfg map[string]any) map[string]FieldBinding {
|
|
raw, ok := cfg["argument_bindings"].(map[string]any)
|
|
if !ok || len(raw) == 0 {
|
|
return nil
|
|
}
|
|
out := make(map[string]FieldBinding, len(raw))
|
|
for argName, v := range raw {
|
|
m, ok := v.(map[string]any)
|
|
if !ok {
|
|
continue
|
|
}
|
|
out[argName] = FieldBinding{
|
|
From: strings.TrimSpace(fmt.Sprint(m["from"])),
|
|
Field: strings.TrimSpace(fmt.Sprint(m["field"])),
|
|
}
|
|
}
|
|
return out
|
|
}
|
|
|
|
func resolveToolArguments(cfg map[string]any, state *WorkflowLocalState) (map[string]interface{}, error) {
|
|
bindings := toolArgumentBindings(cfg)
|
|
if len(bindings) > 0 {
|
|
args := make(map[string]interface{}, len(bindings))
|
|
for k, b := range bindings {
|
|
args[k] = resolveBinding(b, state)
|
|
}
|
|
return args, nil
|
|
}
|
|
raw := cfgString(cfg, "arguments")
|
|
if raw == "" {
|
|
return map[string]interface{}{}, nil
|
|
}
|
|
var args map[string]interface{}
|
|
if err := json.Unmarshal([]byte(raw), &args); err != nil {
|
|
return nil, err
|
|
}
|
|
if args == nil {
|
|
args = map[string]interface{}{}
|
|
}
|
|
return args, nil
|
|
}
|