Files
ds2api/internal/toolcall/toolcalls_dsml.go

85 lines
1.7 KiB
Go

package toolcall
import (
"strings"
"unicode/utf8"
)
func normalizeDSMLToolCallMarkup(text string) (string, bool) {
if text == "" {
return "", true
}
hasAliasLikeMarkup, _ := ContainsToolMarkupSyntaxOutsideIgnored(text)
if !hasAliasLikeMarkup {
return text, true
}
return rewriteDSMLToolMarkupOutsideIgnored(text), true
}
func rewriteDSMLToolMarkupOutsideIgnored(text string) string {
if text == "" {
return ""
}
var b strings.Builder
b.Grow(len(text))
for i := 0; i < len(text); {
next, advanced, blocked := skipXMLIgnoredSection(text, i)
if blocked {
b.WriteString(text[i:])
break
}
if advanced {
b.WriteString(text[i:next])
i = next
continue
}
tag, ok := scanToolMarkupTagAt(text, i)
if !ok {
b.WriteByte(text[i])
i++
continue
}
if tag.DSMLLike {
b.WriteByte('<')
if tag.Closing {
b.WriteByte('/')
}
b.WriteString(tag.Name)
tail := normalizeToolMarkupTagTailForXML(text[tag.NameEnd : tag.End+1])
b.WriteString(tail)
if !strings.HasSuffix(tail, ">") {
b.WriteByte('>')
}
i = tag.End + 1
continue
}
b.WriteString(text[tag.Start : tag.End+1])
i = tag.End + 1
}
return b.String()
}
func normalizeToolMarkupTagTailForXML(tail string) string {
if tail == "" {
return ""
}
var b strings.Builder
b.Grow(len(tail))
for i := 0; i < len(tail); {
r, size := utf8.DecodeRuneInString(tail[i:])
if r == utf8.RuneError && size == 1 {
b.WriteByte(tail[i])
i++
continue
}
switch normalizeFullwidthASCII(r) {
case '>', '/', '=', '"', '\'':
b.WriteRune(normalizeFullwidthASCII(r))
default:
b.WriteString(tail[i : i+size])
}
i += size
}
return b.String()
}