Files
Agent-System-Backend/internal/runtime/material_choice_notice.go
T

56 lines
1.8 KiB
Go

package runtime
import (
"encoding/json"
"fmt"
"strings"
"unicode/utf8"
core "agent-system-core"
)
const MaterialChoiceOptionsPrefix = "[material-choice-options-v1]:"
const MaterialChoiceReadyMarker = "[material-choice-ready]"
type materialChoiceData struct {
Label string `json:"label"`
Basis string `json:"basis"`
}
// The host appends this bounded data line immediately before its ready marker.
// Model prose elsewhere in the notice cannot authorize or replace the choices.
func materialOptionsFromNotice(text string) []core.HITLChoice {
if !strings.HasSuffix(strings.TrimSpace(text), MaterialChoiceReadyMarker+"\n</system-reminder>") {
return nil
}
idx := strings.LastIndex(text, "\n"+MaterialChoiceOptionsPrefix)
if idx < 0 {
return nil
}
line := strings.TrimPrefix(text[idx+1:], MaterialChoiceOptionsPrefix)
if end := strings.IndexByte(line, '\n'); end >= 0 {
line = line[:end]
}
// Four valid UTF-8 labels (80 runes) and bases (240 runes) can exceed
// 2 KiB even though every item is individually within its limit.
if len(line) > 8192 {
return nil
}
var data []materialChoiceData
if err := json.Unmarshal([]byte(line), &data); err != nil || len(data) < 3 || len(data) > 4 {
return nil
}
choices := make([]core.HITLChoice, 0, len(data))
for i, item := range data {
label, basis := strings.TrimSpace(item.Label), strings.TrimSpace(item.Basis)
if label == "" || basis == "" || utf8.RuneCountInString(label) > 80 ||
utf8.RuneCountInString(basis) > 240 || strings.ContainsAny(label+basis, "<>\r\n") ||
strings.Contains(label+basis, "sourceId=") {
return nil
}
choices = append(choices, core.HITLChoice{ID: fmt.Sprintf("material-%d", i+1), Label: label,
Description: basis, Impact: "根据已整理材料生成" + label, Recommended: i == 0})
}
return choices
}