Files
wehub-resource-sync a06f331eb8
CI / benchmark (push) Has been skipped
install-script / posix-syntax (push) Successful in 6m1s
CI / build-onnx (push) Failing after 6m43s
init-smoke / dry-run (push) Failing after 15m57s
security / govulncheck (push) Has been cancelled
security / trivy-fs (push) Has been cancelled
CI / test (1.26, ubuntu-latest) (push) Has been cancelled
Scorecard supply-chain security / Scorecard analysis (push) Has been cancelled
CI / test (1.26, macos-latest) (push) Has been cancelled
CI / build-windows (push) Has been cancelled
CI / lint (push) Has been cancelled
install-script / powershell-syntax (push) Has been cancelled
install-script / install (macos-14) (push) Has been cancelled
install-script / install (ubuntu-latest) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:33:42 +08:00

212 lines
6.3 KiB
Go

// Package packstrategy implements the pluggable context-packing
// strategies the retrieval eval harness A/Bs and smart_context selects
// with. Given a ranked candidate set and a token budget, a strategy
// decides which symbols make the pack and in what order — the choice
// that, under a fixed budget, determines what the agent actually sees.
//
// Strategies:
// - top-k: rank order, greedily add whatever fits (rank-faithful).
// - density: re-order by score-per-token, then add what fits — packs
// the most signal into the budget (token efficiency).
// - file-grouped: cluster by file, densest files first, keeping a file's
// symbols together — favours coherent multi-symbol context over
// scattered high-scoring singletons.
package packstrategy
import (
"os"
"sort"
"strings"
)
// Strategy names a packing algorithm.
type Strategy string
const (
StrategyTopK Strategy = "top-k"
StrategyDensity Strategy = "density"
StrategyFileGrouped Strategy = "file-grouped"
)
// DefaultStrategy is the packing strategy used when none is configured.
// Top-k (rank-faithful) is the default: the eval harness (internal/eval/
// packeval) measures it as the strongest on P@10 / R@10 / MRR — packing
// the highest-reranked symbols first beats re-ordering by token density,
// because the rerank score already encodes relevance the budget should
// honour. It also matches the historical smart_context ordering, so the
// default is a no-op for existing callers. Override with
// GORTEX_PACK_STRATEGY to experiment (the eval can re-derive the winner).
const DefaultStrategy = StrategyTopK
// All returns every strategy, for sweeps.
func All() []Strategy {
return []Strategy{StrategyTopK, StrategyDensity, StrategyFileGrouped}
}
// Item is one ranked candidate to pack: its symbol ID, file, rank score,
// and token cost. Items are passed to Select in rank order (best first).
type Item struct {
ID string
FilePath string
Score float64
Tokens int
}
// Normalize maps a free-form / aliased strategy name to a known Strategy,
// falling back to DefaultStrategy. Recognises a few aliases for ergonomics.
func Normalize(s string) Strategy {
switch strings.ToLower(strings.TrimSpace(string(s))) {
case "top-k", "topk", "top_k", "rank":
return StrategyTopK
case "density", "dense":
return StrategyDensity
case "file-grouped", "file_grouped", "filegrouped", "file":
return StrategyFileGrouped
default:
return DefaultStrategy
}
}
// FromEnv resolves the strategy from GORTEX_PACK_STRATEGY (then
// BENCH_PACK_STRATEGY for parity with sweep tooling), falling back to
// DefaultStrategy when neither is set.
func FromEnv() Strategy {
if v := strings.TrimSpace(os.Getenv("GORTEX_PACK_STRATEGY")); v != "" {
return Normalize(v)
}
if v := strings.TrimSpace(os.Getenv("BENCH_PACK_STRATEGY")); v != "" {
return Normalize(v)
}
return DefaultStrategy
}
// Select packs items into tokenBudget per the strategy and returns the
// chosen items in delivery order. A non-positive budget means "no
// limit" — every item is returned in the strategy's order. Items with a
// non-positive token cost are treated as free (they always fit).
func Select(strategy Strategy, items []Item, tokenBudget int) []Item {
switch Normalize(string(strategy)) {
case StrategyDensity:
return selectDensity(items, tokenBudget)
case StrategyFileGrouped:
return selectFileGrouped(items, tokenBudget)
default:
return selectTopK(items, tokenBudget)
}
}
// fits reports whether adding tok to used stays within budget (budget<=0
// means unlimited).
func fits(used, tok, budget int) bool {
if budget <= 0 {
return true
}
if tok <= 0 {
return true
}
return used+tok <= budget
}
// selectTopK keeps the given rank order and greedily adds each item that
// still fits the budget (skipping an over-large item but continuing, so
// the budget is filled rather than abandoned at the first overflow).
func selectTopK(items []Item, budget int) []Item {
out := make([]Item, 0, len(items))
used := 0
for _, it := range items {
if fits(used, it.Tokens, budget) {
out = append(out, it)
used += maxInt(it.Tokens, 0)
}
}
return out
}
// selectDensity re-orders candidates by score-per-token (signal density)
// and then greedily fills the budget — the most informative tokens first.
func selectDensity(items []Item, budget int) []Item {
idx := make([]int, len(items))
for i := range items {
idx[i] = i
}
sort.SliceStable(idx, func(a, b int) bool {
da, db := density(items[idx[a]]), density(items[idx[b]])
if da != db {
return da > db
}
// Stable tie-break on original rank.
return idx[a] < idx[b]
})
out := make([]Item, 0, len(items))
used := 0
for _, i := range idx {
it := items[i]
if fits(used, it.Tokens, budget) {
out = append(out, it)
used += maxInt(it.Tokens, 0)
}
}
return out
}
// density is an item's score per token, with a floor on tokens so a
// zero-cost item doesn't divide by zero (it sorts by raw score).
func density(it Item) float64 {
t := it.Tokens
if t <= 0 {
t = 1
}
return it.Score / float64(t)
}
// selectFileGrouped clusters candidates by file, orders files by their
// summed score (densest files first), keeps each file's symbols together
// in rank order, and greedily fills the budget file by file. Coherent
// multi-symbol context beats scattered singletons for comprehension.
func selectFileGrouped(items []Item, budget int) []Item {
type group struct {
file string
sum float64
items []Item
}
order := make([]string, 0)
byFile := make(map[string]*group)
for _, it := range items {
g := byFile[it.FilePath]
if g == nil {
g = &group{file: it.FilePath}
byFile[it.FilePath] = g
order = append(order, it.FilePath)
}
g.items = append(g.items, it)
g.sum += it.Score
}
groups := make([]*group, 0, len(order))
for _, f := range order {
groups = append(groups, byFile[f])
}
// Densest files first; SliceStable keeps first-seen order on ties.
sort.SliceStable(groups, func(a, b int) bool {
return groups[a].sum > groups[b].sum
})
out := make([]Item, 0, len(items))
used := 0
for _, g := range groups {
for _, it := range g.items {
if fits(used, it.Tokens, budget) {
out = append(out, it)
used += maxInt(it.Tokens, 0)
}
}
}
return out
}
func maxInt(a, b int) int {
if a > b {
return a
}
return b
}