File size: 2,496 Bytes
8d3471e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
package claude

import (
	"encoding/json"
	"fmt"
	"strings"
)

const (
	maxClaudeRawPromptChars = 1024
	omittedBinaryMarker     = "[omitted_binary_payload]"
)

func formatClaudeUnknownBlockForPrompt(block map[string]any) string {
	if block == nil {
		return ""
	}
	safe := sanitizeClaudeBlockForPrompt(block)
	raw := strings.TrimSpace(formatClaudeBlockRaw(safe))
	if raw == "" {
		return ""
	}
	if len(raw) > maxClaudeRawPromptChars {
		return raw[:maxClaudeRawPromptChars] + "...(truncated)"
	}
	return raw
}

func sanitizeClaudeBlockForPrompt(block map[string]any) map[string]any {
	out := cloneMap(block)
	for k, v := range out {
		if looksLikeBinaryFieldName(k) {
			out[k] = omittedBinaryMarker
			continue
		}
		switch inner := v.(type) {
		case map[string]any:
			out[k] = sanitizeClaudeBlockForPrompt(inner)
		case []any:
			out[k] = sanitizeClaudeArrayForPrompt(inner)
		case string:
			out[k] = sanitizeClaudeStringForPrompt(k, inner)
		}
	}
	return out
}

func sanitizeClaudeArrayForPrompt(items []any) []any {
	out := make([]any, 0, len(items))
	for _, item := range items {
		switch v := item.(type) {
		case map[string]any:
			out = append(out, sanitizeClaudeBlockForPrompt(v))
		case []any:
			out = append(out, sanitizeClaudeArrayForPrompt(v))
		default:
			out = append(out, v)
		}
	}
	return out
}

func sanitizeClaudeStringForPrompt(key, value string) string {
	trimmed := strings.TrimSpace(value)
	if trimmed == "" {
		return ""
	}
	if looksLikeBinaryFieldName(key) || looksLikeBase64Payload(trimmed) {
		return omittedBinaryMarker
	}
	if len(trimmed) > maxClaudeRawPromptChars {
		return trimmed[:maxClaudeRawPromptChars] + "...(truncated)"
	}
	return trimmed
}

func looksLikeBinaryFieldName(name string) bool {
	n := strings.ToLower(strings.TrimSpace(name))
	return n == "data" || n == "bytes" || n == "base64" || n == "inline_data" || n == "inlinedata"
}

func looksLikeBase64Payload(v string) bool {
	if len(v) < 512 {
		return false
	}
	compact := strings.TrimRight(v, "=")
	if compact == "" {
		return false
	}
	for _, ch := range compact {
		if (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9') || ch == '+' || ch == '/' || ch == '-' || ch == '_' {
			continue
		}
		return false
	}
	return true
}

//nolint:unused // helper kept for compatibility with upcoming sanitize pipeline.
func marshalCompactJSON(v any) string {
	b, err := json.Marshal(v)
	if err != nil {
		return strings.TrimSpace(fmt.Sprintf("%v", v))
	}
	return string(b)
}