Default off; unauthorized views skipped; facts preserved. Co-authored-by: Cursor <cursoragent@cursor.com>
49 lines
1.5 KiB
Go
49 lines
1.5 KiB
Go
package ctxmgr
|
|
|
|
import (
|
|
"context"
|
|
"os"
|
|
"strings"
|
|
)
|
|
|
|
// SemanticSummaryShadowEnabled reports SEMANTIC_SUMMARY_SHADOW (default off).
|
|
func SemanticSummaryShadowEnabled() bool {
|
|
v := strings.TrimSpace(os.Getenv("SEMANTIC_SUMMARY_SHADOW"))
|
|
return v == "1" || strings.EqualFold(v, "true") || strings.EqualFold(v, "yes")
|
|
}
|
|
|
|
// MaybeApplySemanticShadow optionally annotates a deterministic summary when the
|
|
// shadow flag is on. It never drops Facts; on "model" failure it keeps the
|
|
// deterministic narrative and marks freshness. Summarizer has no tool rights.
|
|
func MaybeApplySemanticShadow(ctx context.Context, sum *ChatSummary, authorizedOnly bool) *ChatSummary {
|
|
_ = ctx
|
|
if sum == nil || !SemanticSummaryShadowEnabled() {
|
|
return sum
|
|
}
|
|
if !authorizedOnly {
|
|
// Refuse to summarize unauthorized views.
|
|
out := *sum
|
|
if out.Facts == nil {
|
|
out.Facts = map[string]string{}
|
|
}
|
|
out.Facts["semantic_shadow"] = "skipped_unauthorized_view"
|
|
return &out
|
|
}
|
|
out := *sum
|
|
if out.Facts == nil {
|
|
out.Facts = map[string]string{}
|
|
}
|
|
// Deterministic shadow stub (no external LLM in unit path). Real PI can
|
|
// replace Narrative later behind the same flag; failure keeps deterministic.
|
|
shadow := strings.TrimSpace(out.Narrative)
|
|
if shadow == "" {
|
|
shadow = "(语义摘要影子:无叙事,保留事实槽位)"
|
|
} else if !strings.Contains(shadow, "[shadow]") {
|
|
shadow = "[shadow] " + shadow
|
|
}
|
|
out.Narrative = shadow
|
|
out.Facts["semantic_shadow"] = "applied"
|
|
out.Facts["semantic_shadow_freshness"] = "deterministic_fallback_ok"
|
|
return &out
|
|
}
|