Files
2026-08-29 02:39:58 +03:00

128 lines
3.8 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
Lane string
ContextScopeRef string
FreshnessState string
Negative bool
}
type ContextCompileInput struct {
Candidates []ContextCandidate
DataPolicy capability.DataPolicy
MaxBytes int
TaskRef string
FocusFrameRef string
ContextScopeRef string
FreshnessRequirement string
RiskClass string
TokenBudget int
}
type ContextOmission struct {
ID ContextExcerptID
Reason string
}
type ContextBundle struct {
Excerpts []ContextExcerpt
Omissions []ContextOmission
Bytes int
Trace ContextAssemblyTrace
}
type ContextAssemblyTrace struct {
Included []ContextExcerptID
Excluded []ContextOmission
Coverage string
CompilerVersion string
}
type IterativeRetrievalRequest struct {
Query string
RemainingBytes int
Pass int
}
type IterativeRetrievalResponse struct {
Candidates []ContextCandidate
Exhausted bool
}
// 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{}{}
if input.ContextScopeRef != "" && candidate.ContextScopeRef != input.ContextScopeRef {
bundle.Omissions = append(bundle.Omissions, ContextOmission{ID: excerpt.ID, Reason: "context_scope"})
continue
}
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
bundle.Trace.Included = append(bundle.Trace.Included, excerpt.ID)
}
bundle.Trace.Excluded = append([]ContextOmission(nil), bundle.Omissions...)
bundle.Trace.CompilerVersion = "context-compiler-v2-additive"
bundle.Trace.Coverage = "BOUNDED"
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 ""
}