Recall is the on-demand (pull) retrieval primitive behind `@memory recall`. It mirrors the quality of the per-turn push retrieval rather than the old naive whitespace split: keywords come from ExtractKeywords (stop-word filtered), and when HyDE is enabled in /config quality the query is widened thro
(query string)
| 84 | // through the same hypothesis + vector-cosine stack the system-prompt path |
| 85 | // uses. An empty query falls back to the broad memory context. |
| 86 | func (a *memoryPluginAdapter) Recall(query string) (string, error) { |
| 87 | if a.cli.memoryStore == nil { |
| 88 | return "", fmt.Errorf("memory not enabled") |
| 89 | } |
| 90 | |
| 91 | // @memory recall has no caller deadline of its own, so bound the optional |
| 92 | // HyDE hypothesis + embedding round-trips here. |
| 93 | ctx, cancel := context.WithTimeout(context.Background(), 45*time.Second) |
| 94 | defer cancel() |
| 95 | |
| 96 | q := strings.TrimSpace(query) |
| 97 | var out string |
| 98 | switch { |
| 99 | case q == "": |
| 100 | out = a.cli.memoryStore.GetMemoryContext() |
| 101 | default: |
| 102 | hints := memory.ExtractKeywords([]string{q}) |
| 103 | if len(hints) == 0 { |
| 104 | // Very short / all-stop-word queries yield no keywords; fall |
| 105 | // back to the raw fields so recall still narrows by something. |
| 106 | hints = strings.Fields(q) |
| 107 | } |
| 108 | if qcfg := quality.LoadFromEnv(); qcfg.Enabled && qcfg.HyDE.Enabled { |
| 109 | out = a.cli.memoryStore.GetRelevantContextWithHyDE(ctx, q, hints, a.cli.hydeAugmenterFor(qcfg)) |
| 110 | } else { |
| 111 | out = a.cli.memoryStore.GetRelevantContext(hints) |
| 112 | } |
| 113 | } |
| 114 | |
| 115 | if strings.TrimSpace(out) == "" { |
| 116 | return i18n.T("mem.tool.recall.empty"), nil |
| 117 | } |
| 118 | return out, nil |
| 119 | } |
| 120 | |
| 121 | // GraphMap and GraphNeighbors expose the knowledge graph as a relational VIEW of |
| 122 | // the same memory/skill data — the "what connects to this" angle that content |