92 lines
2.7 KiB
Go
92 lines
2.7 KiB
Go
package cognitive
|
|
|
|
import (
|
|
"errors"
|
|
"sort"
|
|
"strings"
|
|
|
|
"git.cin.su/m/Assistant/contracts/capability"
|
|
)
|
|
|
|
var ErrInvalidContextBudget = errors.New("context budget must be positive")
|
|
|
|
type ContextCandidate struct {
|
|
Excerpt ContextExcerpt
|
|
Relevance int
|
|
}
|
|
|
|
type ContextCompileInput struct {
|
|
Candidates []ContextCandidate
|
|
DataPolicy capability.DataPolicy
|
|
MaxBytes int
|
|
}
|
|
|
|
type ContextOmission struct {
|
|
ID ContextExcerptID
|
|
Reason string
|
|
}
|
|
|
|
type ContextBundle struct {
|
|
Excerpts []ContextExcerpt
|
|
Omissions []ContextOmission
|
|
Bytes int
|
|
}
|
|
|
|
// CompileContext deterministically selects permitted, relevant excerpts for a
|
|
// gateway request. It carries no provider identity and performs no I/O.
|
|
func CompileContext(input ContextCompileInput) (ContextBundle, error) {
|
|
if input.MaxBytes <= 0 {
|
|
return ContextBundle{}, ErrInvalidContextBudget
|
|
}
|
|
candidates := append([]ContextCandidate(nil), input.Candidates...)
|
|
sort.SliceStable(candidates, func(i, j int) bool {
|
|
if candidates[i].Relevance != candidates[j].Relevance {
|
|
return candidates[i].Relevance > candidates[j].Relevance
|
|
}
|
|
return string(candidates[i].Excerpt.ID) < string(candidates[j].Excerpt.ID)
|
|
})
|
|
bundle := ContextBundle{Excerpts: []ContextExcerpt{}, Omissions: []ContextOmission{}}
|
|
seen := make(map[ContextExcerptID]struct{}, len(candidates))
|
|
for _, candidate := range candidates {
|
|
excerpt := candidate.Excerpt
|
|
if _, ok := seen[excerpt.ID]; ok {
|
|
bundle.Omissions = append(bundle.Omissions, ContextOmission{ID: excerpt.ID, Reason: "duplicate"})
|
|
continue
|
|
}
|
|
seen[excerpt.ID] = struct{}{}
|
|
reason := permittedContextReason(excerpt, input.DataPolicy)
|
|
if reason != "" {
|
|
bundle.Omissions = append(bundle.Omissions, ContextOmission{ID: excerpt.ID, Reason: reason})
|
|
continue
|
|
}
|
|
if strings.TrimSpace(excerpt.Text) == "" {
|
|
bundle.Omissions = append(bundle.Omissions, ContextOmission{ID: excerpt.ID, Reason: "empty"})
|
|
continue
|
|
}
|
|
bytes := len([]byte(excerpt.Text))
|
|
if bundle.Bytes+bytes > input.MaxBytes {
|
|
bundle.Omissions = append(bundle.Omissions, ContextOmission{ID: excerpt.ID, Reason: "budget"})
|
|
continue
|
|
}
|
|
bundle.Excerpts = append(bundle.Excerpts, excerpt)
|
|
bundle.Bytes += bytes
|
|
}
|
|
return bundle, nil
|
|
}
|
|
|
|
func permittedContextReason(excerpt ContextExcerpt, policy capability.DataPolicy) string {
|
|
if excerpt.Sensitivity == SensitivitySecret {
|
|
return "secret"
|
|
}
|
|
if excerpt.Sensitivity == SensitivityUnknown {
|
|
return "unknown_sensitivity"
|
|
}
|
|
if policy == capability.DataPolicyExternalMessageOnly {
|
|
return "policy_message_only"
|
|
}
|
|
if policy == capability.DataPolicyExternalMinimizedContext && excerpt.Sensitivity != SensitivityPublic {
|
|
return "policy_public_only"
|
|
}
|
|
return ""
|
|
}
|