| 1 | // Activation: whether a fact's body rides the session-context background |
| 2 | // snapshot (pinned) or stays retrieval-only (relevant), plus legacy defaults. |
| 3 | package memory |
| 4 | |
| 5 | import "strings" |
| 6 | |
| 7 | // Activation controls how a fact reaches the model, orthogonal to Scope: |
| 8 | // scope says where a fact may be used, activation says whether its body rides |
| 9 | // the current session-context snapshot (pinned) or is retrieval-only (relevant). |
| 10 | type Activation string |
| 11 | |
| 12 | const ( |
| 13 | ActivationRelevant Activation = "relevant" // retrieval-only: index + recall |
| 14 | ActivationPinned Activation = "pinned" // body loads into session-context |
| 15 | ) |
| 16 | |
| 17 | // NormalizeActivation validates a persisted or requested activation. Empty and |
| 18 | // unknown values return "" (unset) so ResolveActivation can apply the |
| 19 | // legacy-aware default instead of silently inventing an explicit choice. |
| 20 | func NormalizeActivation(s string) Activation { |
| 21 | switch Activation(strings.ToLower(strings.TrimSpace(s))) { |
| 22 | case ActivationRelevant: |
| 23 | return ActivationRelevant |
| 24 | case ActivationPinned: |
| 25 | return ActivationPinned |
| 26 | } |
| 27 | return "" |
| 28 | } |
| 29 | |
| 30 | // ResolveActivation defaults an unset activation. Legacy global user/feedback |
| 31 | // facts predate the field and were always loaded as stable guidance, so they |
| 32 | // resolve to pinned until a rewrite records an explicit choice; everything |
| 33 | // else is relevant. |
| 34 | func ResolveActivation(m Memory) Activation { |
| 35 | if a := NormalizeActivation(string(m.Activation)); a != "" { |
| 36 | return a |
| 37 | } |
| 38 | if NormalizeFactScope(string(m.Scope)) == FactScopeGlobal { |
| 39 | if t := NormalizeType(string(m.Type)); t == TypeUser || t == TypeFeedback { |
| 40 | return ActivationPinned |
| 41 | } |
| 42 | } |
| 43 | return ActivationRelevant |
| 44 | } |
| 45 |