From 8189ce5274493ef1fc4bf044170076e95c36aa28 Mon Sep 17 00:00:00 2001 From: Wang Qi Date: Fri, 30 Oct 2026 12:46:07 +0800 Subject: [PATCH] Fix text processing to treat input as array if input is an array (#21743) --- internal/agent/component/string_transform.go | 35 +++++++++++++++++--- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/internal/agent/component/string_transform.go b/internal/agent/component/string_transform.go index 8973db95c3..28e243b8e6 100644 --- a/internal/agent/component/string_transform.go +++ b/internal/agent/component/string_transform.go @@ -30,6 +30,7 @@ package component import ( "context" "fmt" + "reflect" "regexp" "strings" @@ -45,7 +46,7 @@ type stringTransformParam struct { Method string `json:"method"` // "split" or "merge" Script string `json:"script"` // merge mode: template SplitRef string `json:"split_ref"` // split mode: state ref to read - Delimiters []string `json:"delimiters"` // split mode: literal delimiters + Delimiters []string `json:"delimiters"` // split: literal delimiters; merge: first delimiter joins arrays } // Update copies a fresh param map into the receiver. @@ -309,11 +310,37 @@ func (s *StringTransformComponent) doSplit(_ context.Context, state *runtime.Can // the resolved script. func (s *StringTransformComponent) doMerge(_ context.Context, state *runtime.CanvasState, inputs map[string]any) map[string]any { script := s.param.Script + formatValue := func(value any) string { + v := reflect.ValueOf(value) + if v.Kind() == reflect.Slice || v.Kind() == reflect.Array { + parts := make([]string, v.Len()) + for i := range parts { + parts[i] = fmt.Sprintf("%v", v.Index(i).Interface()) + } + return strings.Join(parts, s.param.Delimiters[0]) + } + return fmt.Sprintf("%v", value) + } // First pass: state-level template resolution for any runtime ref // syntax the canvas supports, including single-brace legacy refs and - // iteration aliases like {item}/{index}. - if resolved, err := runtime.ResolveTemplateAuto(script, state); err == nil { + // iteration aliases like {item}/{index}. Resolve arrays before the + // generic template renderer can stringify them. + if !runtime.ContainsJinjaSyntax(script) { + resolved := true + merged := runtime.VarRefPattern.ReplaceAllStringFunc(script, func(match string) string { + ref := runtime.VarRefPattern.FindStringSubmatch(match)[1] + value, err := state.GetVar(ref) + if err != nil || value == nil { + resolved = false + return match + } + return formatValue(value) + }) + if resolved { + script = merged + } + } else if resolved, err := runtime.ResolveTemplateAuto(script, state); err == nil { script = resolved } @@ -332,7 +359,7 @@ func (s *StringTransformComponent) doMerge(_ context.Context, state *runtime.Can } else { value = "" } - script = strings.ReplaceAll(script, placeholder, fmt.Sprintf("%v", value)) + script = strings.ReplaceAll(script, placeholder, formatValue(value)) } return map[string]any{"result": script} }