package toolcall import ( "encoding/json" "html" "strings" ) func parseLooseJSONArrayValue(raw, paramName string) ([]any, bool) { if preservesCDATAStringParameter(paramName) { return nil, false } trimmed := strings.TrimSpace(html.UnescapeString(raw)) if trimmed == "" { return nil, false } if parsed, ok := parseLooseJSONArrayCandidate(trimmed, paramName); ok { return parsed, true } segments, ok := splitTopLevelJSONValues(trimmed) if !ok { return nil, false } out := make([]any, 0, len(segments)) for _, segment := range segments { parsed, ok := parseLooseArrayElementValue(segment) if !ok { return nil, false } out = append(out, parsed) } return out, true } func parseLooseJSONArrayCandidate(raw, paramName string) ([]any, bool) { parsed, ok := parseLooseArrayElementValue(raw) if !ok { return nil, false } return coerceArrayValue(parsed, paramName) } func parseLooseArrayElementValue(raw string) (any, bool) { trimmed := strings.TrimSpace(html.UnescapeString(raw)) if trimmed == "" { return nil, false } var parsed any if err := json.Unmarshal([]byte(trimmed), &parsed); err == nil { return parsed, true } repairedBackslashes := repairInvalidJSONBackslashes(trimmed) if repairedBackslashes != trimmed { if err := json.Unmarshal([]byte(repairedBackslashes), &parsed); err == nil { return parsed, true } } repairedLoose := RepairLooseJSON(trimmed) if repairedLoose != trimmed { if err := json.Unmarshal([]byte(repairedLoose), &parsed); err == nil { return parsed, true } } if strings.Contains(trimmed, "<") && strings.Contains(trimmed, ">") { if parsedXML, ok := parseXMLFragmentValue(trimmed); ok { return parsedXML, true } } return nil, false } func coerceArrayValue(value any, paramName string) ([]any, bool) { switch x := value.(type) { case []any: return x, true case map[string]any: if len(x) != 1 { return nil, false } if items, ok := x["item"]; ok { if arr, ok := coerceArrayValue(items, ""); ok { return arr, true } return []any{items}, true } if paramName != "" { if wrapped, ok := x[paramName]; ok { if arr, ok := coerceArrayValue(wrapped, ""); ok { return arr, true } } } } return nil, false } func splitTopLevelJSONValues(raw string) ([]string, bool) { trimmed := strings.TrimSpace(raw) if trimmed == "" { return nil, false } values := make([]string, 0, 2) start := 0 depth := 0 inString := false escaped := false for i, r := range trimmed { if inString { if escaped { escaped = false continue } switch r { case '\\': escaped = true case '"': inString = false } continue } switch r { case '"': inString = true case '{', '[': depth++ case '}', ']': if depth > 0 { depth-- } case ',': if depth == 0 { segment := strings.TrimSpace(trimmed[start:i]) if segment == "" { return nil, false } values = append(values, segment) start = i + 1 } } } last := strings.TrimSpace(trimmed[start:]) if last == "" { return nil, false } values = append(values, last) if len(values) < 2 { return nil, false } return values, true }