mirror of
https://github.com/CJackHwang/ds2api.git
synced 2026-05-04 08:25:26 +08:00
165 lines
3.1 KiB
Go
165 lines
3.1 KiB
Go
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
|
|
}
|