mirror of
https://github.com/sipeed/picoclaw.git
synced 2026-06-12 18:08:54 +00:00
135 lines
3.0 KiB
Go
135 lines
3.0 KiB
Go
package integrationtools
|
|
|
|
import (
|
|
"fmt"
|
|
"math"
|
|
"mime"
|
|
"path/filepath"
|
|
"regexp"
|
|
"strconv"
|
|
"strings"
|
|
"unicode"
|
|
)
|
|
|
|
var (
|
|
inlineMarkdownDataURLRe = regexp.MustCompile(`!\[[^\]]*\]\((data:[^)]+)\)`)
|
|
inlineRawDataURLRe = regexp.MustCompile(`data:[^;\s]+;base64,[A-Za-z0-9+/=\r\n]+`)
|
|
)
|
|
|
|
const (
|
|
largeBase64OmittedMessage = "[Tool returned a large base64-like payload; omitted from model context.]"
|
|
inlineMediaOmittedMessage = "[Tool returned inline media content; omitted from model context.]"
|
|
)
|
|
|
|
func sanitizeToolLLMContent(text string) string {
|
|
trimmed := strings.TrimSpace(text)
|
|
if trimmed == "" {
|
|
return text
|
|
}
|
|
if inlineMarkdownDataURLRe.MatchString(trimmed) || inlineRawDataURLRe.MatchString(trimmed) {
|
|
cleaned := inlineMarkdownDataURLRe.ReplaceAllString(trimmed, "")
|
|
cleaned = inlineRawDataURLRe.ReplaceAllString(cleaned, "")
|
|
cleaned = strings.TrimSpace(cleaned)
|
|
if cleaned == "" {
|
|
return inlineMediaOmittedMessage
|
|
}
|
|
return cleaned + "\n" + inlineMediaOmittedMessage
|
|
}
|
|
if looksLikeLargeBase64Payload(trimmed) {
|
|
return largeBase64OmittedMessage
|
|
}
|
|
return text
|
|
}
|
|
|
|
func looksLikeLargeBase64Payload(text string) bool {
|
|
trimmed := strings.TrimSpace(text)
|
|
if len(trimmed) < 1024 {
|
|
return false
|
|
}
|
|
|
|
nonSpace := 0
|
|
base64Like := 0
|
|
spaceCount := 0
|
|
|
|
for _, r := range trimmed {
|
|
if unicode.IsSpace(r) {
|
|
spaceCount++
|
|
continue
|
|
}
|
|
nonSpace++
|
|
if (r >= 'A' && r <= 'Z') ||
|
|
(r >= 'a' && r <= 'z') ||
|
|
(r >= '0' && r <= '9') ||
|
|
r == '+' || r == '/' || r == '=' {
|
|
base64Like++
|
|
}
|
|
}
|
|
|
|
if nonSpace == 0 {
|
|
return false
|
|
}
|
|
|
|
ratio := float64(base64Like) / float64(nonSpace)
|
|
return ratio >= 0.97 && spaceCount <= len(trimmed)/128
|
|
}
|
|
|
|
func extensionForMIMEType(mimeType string) string {
|
|
if mimeType == "" {
|
|
return ".bin"
|
|
}
|
|
if exts, err := mime.ExtensionsByType(mimeType); err == nil && len(exts) > 0 {
|
|
return exts[0]
|
|
}
|
|
|
|
switch strings.ToLower(mimeType) {
|
|
case "image/jpeg":
|
|
return ".jpg"
|
|
case "image/png":
|
|
return ".png"
|
|
case "image/gif":
|
|
return ".gif"
|
|
case "image/webp":
|
|
return ".webp"
|
|
case "audio/wav", "audio/x-wav":
|
|
return ".wav"
|
|
case "audio/mpeg":
|
|
return ".mp3"
|
|
case "audio/ogg":
|
|
return ".ogg"
|
|
case "video/mp4":
|
|
return ".mp4"
|
|
default:
|
|
return filepath.Ext(mimeType)
|
|
}
|
|
}
|
|
|
|
func getInt64Arg(args map[string]any, key string, defaultVal int64) (int64, error) {
|
|
raw, exists := args[key]
|
|
if !exists {
|
|
return defaultVal, nil
|
|
}
|
|
|
|
switch v := raw.(type) {
|
|
case float64:
|
|
if v != math.Trunc(v) {
|
|
return 0, fmt.Errorf("%s must be an integer, got float %v", key, v)
|
|
}
|
|
if v > math.MaxInt64 || v < math.MinInt64 {
|
|
return 0, fmt.Errorf("%s value %v overflows int64", key, v)
|
|
}
|
|
return int64(v), nil
|
|
case int:
|
|
return int64(v), nil
|
|
case int64:
|
|
return v, nil
|
|
case string:
|
|
parsed, err := strconv.ParseInt(v, 10, 64)
|
|
if err != nil {
|
|
return 0, fmt.Errorf("invalid integer format for %s parameter: %w", key, err)
|
|
}
|
|
return parsed, nil
|
|
default:
|
|
return 0, fmt.Errorf("unsupported type %T for %s parameter", raw, key)
|
|
}
|
|
}
|