Problem
Tags only help recall today when the caller passes an explicit tag filter. For a normal query like "what did I decide about the office lease", tags are invisible to ranking — the system never recognizes the query is work/legal-related, so tag-relevant memories get no preference. There is no auto-tagging-from-text anywhere in the codebase.
Proposed solution
Two coupled pieces.
1. Infer tags from the query (hybrid)
New inferQueryTags(query, env): Promise<string[]>:
- Hashtags — reuse
extractHashtags(query) (src/index.ts:498).
- Known vocabulary —
SELECT tags FROM entries, flatten + dedupe the JSON arrays into a tag set.
- Keyword match — include any known tag appearing as a whole word in the lowercased query.
- If steps 1+3 yield anything → return (no LLM call).
- LLM fallback only when empty — mirror
scoreImportance (:479-494): env.AI.run(LLM_MODEL, …) (@cf/meta/llama-4-scout-17b-16e-instruct, :20) + readStreamText; prompt picks the relevant subset from the known-tag list; parse defensively, intersect with the known set, wrap in try/catch → [] on failure (best-effort).
Run in parallel with embedding inside recallEntries: Promise.all([embed(...), inferQueryTags(...)]). Inferred tags are a soft signal only, never a hard filter — the explicit tag param stays the only filter, so inference can never over-narrow results.
2. Soft tag boost in reranking
rerankWithTimeDecay (:392-427) gains an optional queryTags: string[] = [] param (default = no-op, so existing callers/tests are unchanged). Per match: overlap = |entry.tags ∩ queryTags|; tagBoost = overlap ? min(TAG_BOOST_MAX, 1 + overlap * TAG_BOOST_STEP) : 1.0, applied like importanceMultiplier (outside the recency ≤1.0 cap) so a tag-relevant memory can surface above a marginally-closer but irrelevant one. New constants: TAG_BOOST_STEP = 0.15, TAG_BOOST_MAX = 1.5. recallEntries passes queryTags into rerankWithTimeDecay on both paths.
Files
src/index.ts — new inferQueryTags; rerankWithTimeDecay signature + tag-boost multiplier; new constants; wire through recallEntries.
Tests / Verification
test/unit/rerank.test.ts — a tag-overlapping match outranks an equal-score non-overlapping one; queryTags=[] leaves scores unchanged.
test/integration/recall.test.ts — hashtag/keyword hit skips the LLM; empty inference exercises the LLM fallback (makeAIMock already streams a response).
npm test green.
Notes
Problem
Tags only help recall today when the caller passes an explicit
tagfilter. For a normal query like "what did I decide about the office lease", tags are invisible to ranking — the system never recognizes the query is work/legal-related, so tag-relevant memories get no preference. There is no auto-tagging-from-text anywhere in the codebase.Proposed solution
Two coupled pieces.
1. Infer tags from the query (hybrid)
New
inferQueryTags(query, env): Promise<string[]>:extractHashtags(query)(src/index.ts:498).SELECT tags FROM entries, flatten + dedupe the JSON arrays into a tag set.scoreImportance(:479-494):env.AI.run(LLM_MODEL, …)(@cf/meta/llama-4-scout-17b-16e-instruct,:20) +readStreamText; prompt picks the relevant subset from the known-tag list; parse defensively, intersect with the known set, wrap in try/catch →[]on failure (best-effort).Run in parallel with embedding inside
recallEntries:Promise.all([embed(...), inferQueryTags(...)]). Inferred tags are a soft signal only, never a hard filter — the explicittagparam stays the only filter, so inference can never over-narrow results.2. Soft tag boost in reranking
rerankWithTimeDecay(:392-427) gains an optionalqueryTags: string[] = []param (default = no-op, so existing callers/tests are unchanged). Per match:overlap = |entry.tags ∩ queryTags|;tagBoost = overlap ? min(TAG_BOOST_MAX, 1 + overlap * TAG_BOOST_STEP) : 1.0, applied likeimportanceMultiplier(outside the recency ≤1.0 cap) so a tag-relevant memory can surface above a marginally-closer but irrelevant one. New constants:TAG_BOOST_STEP = 0.15,TAG_BOOST_MAX = 1.5.recallEntriespassesqueryTagsintorerankWithTimeDecayon both paths.Files
src/index.ts— newinferQueryTags;rerankWithTimeDecaysignature + tag-boost multiplier; new constants; wire throughrecallEntries.Tests / Verification
test/unit/rerank.test.ts— a tag-overlapping match outranks an equal-score non-overlapping one;queryTags=[]leaves scores unchanged.test/integration/recall.test.ts— hashtag/keyword hit skips the LLM; empty inference exercises the LLM fallback (makeAIMockalready streams a response).npm testgreen.Notes