ai-lens 0.8.115 → 0.8.117
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.commithash +1 -1
- package/CHANGELOG.md +6 -0
- package/client/capture.js +27 -36
- package/package.json +1 -1
package/.commithash
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
28976f3
|
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
History of changes to the `ai-lens` CLI package on npm. New entries go on top. Format: `## X.Y.Z — YYYY-MM-DD`, followed by user-facing bullets.
|
|
4
4
|
|
|
5
|
+
## 0.8.117 — 2026-07-01
|
|
6
|
+
- fix(team-memory): never inject team memory in projects outside your `projects` filter — an unrelated repo now gets nothing, even if it's on your machine
|
|
7
|
+
|
|
8
|
+
## 0.8.116 — 2026-07-01
|
|
9
|
+
- fix(team-memory): only inject memory that is genuinely relevant to your prompt — a vague or off-topic prompt now injects nothing, instead of dumping arbitrary team conventions
|
|
10
|
+
|
|
5
11
|
## 0.8.115 — 2026-07-01
|
|
6
12
|
- feat(team-memory): inject relevant team memory per prompt (matched to what you're asking) instead of a blind dump at session start
|
|
7
13
|
- feat(team-memory): injected memory carries a hint to report it as wrong/outdated via the `ai_lens_memory_report_wrong` MCP tool
|
package/client/capture.js
CHANGED
|
@@ -1745,13 +1745,14 @@ export function maybeEmitSessionStartMemoryIndex(primary, { now = Date.now() } =
|
|
|
1745
1745
|
// exactly why the number is deferred to live tuning, not treated as final. Bounded
|
|
1746
1746
|
// blast radius (budget below + phase-N unshown-gate) keeps a mis-tuned floor from
|
|
1747
1747
|
// flooding — worst case is 1–2 extra short memories, never a dump.
|
|
1748
|
-
|
|
1749
|
-
//
|
|
1750
|
-
//
|
|
1748
|
+
// Calibrated on live prod pairs (analytics pilot, 2026-07): genuine matches score
|
|
1749
|
+
// ≫3 (specific-term prompts hit 3–13), noise clusters at 1.5–2.0. 3.0 cleanly
|
|
1750
|
+
// separates them — precision over recall BY DESIGN: silence beats a context-rotting
|
|
1751
|
+
// near-miss. Tunable down with PostHog match data if it proves too quiet.
|
|
1752
|
+
const MEMORY_MATCH_MIN_SCORE = 3.0;
|
|
1753
|
+
// Budget: never inject more than this many memories per prompt (repo OR team-general
|
|
1754
|
+
// alike) — keeps a prompt light even on a broad match.
|
|
1751
1755
|
const MEMORY_INJECT_BUDGET = 2;
|
|
1752
|
-
// Phase-1 team-general allowance (cross-repo conventions) — kept small so the very
|
|
1753
|
-
// first prompt stays light (total phase-1 items ≈ budget + this ≤ ~3–4).
|
|
1754
|
-
const MEMORY_PHASE1_TEAM_GENERAL = 2;
|
|
1755
1756
|
const MEMORY_INJECT_MAX_LEN = 1500;
|
|
1756
1757
|
const MEMORY_INJECT_HEADER = 'AI Lens team memory — relevant to this prompt (full text via ai_lens_memory_read):';
|
|
1757
1758
|
// Bound the per-session shown-set (safety valve; sessions are naturally bounded).
|
|
@@ -1852,6 +1853,14 @@ export function maybeEmitUserPromptMemoryInject(primary, { now = Date.now() } =
|
|
|
1852
1853
|
// Per-person opt-out (client-side, privacy-first): no render, no annotation.
|
|
1853
1854
|
if (existsSync(MEMORY_OPT_OUT_PATH)) return NONE;
|
|
1854
1855
|
|
|
1856
|
+
// Respect the projects filter. The primed pool is machine-GLOBAL, but a match
|
|
1857
|
+
// must NOT surface in an UNTRACKED project — an unrelated repo the user doesn't
|
|
1858
|
+
// monitor for AI Lens (e.g. a GPU/ASR build that has nothing to do with the team).
|
|
1859
|
+
// This mirrors the project_filter drop the caller applies to event shipping; it
|
|
1860
|
+
// just runs earlier here because the inject is emitted BEFORE that drop. No filter
|
|
1861
|
+
// / no project_path → monitored (inject allowed — unchanged for single-project users).
|
|
1862
|
+
if (!isProjectMonitored(primary.project_path, primary.workspace_roots, getMonitoredProjects())) return NONE;
|
|
1863
|
+
|
|
1855
1864
|
// Load the primed pool. Empty/absent cache = not eligible (server only primes
|
|
1856
1865
|
// for treatment ∧ not opt-out) ⇒ this is a clean no-op. Also enforce the same
|
|
1857
1866
|
// freshness TTL the SessionStart render used (an offline client must not match
|
|
@@ -1876,41 +1885,23 @@ export function maybeEmitUserPromptMemoryInject(primary, { now = Date.now() } =
|
|
|
1876
1885
|
|
|
1877
1886
|
if (!promptText) { commitCount(); return NONE; }
|
|
1878
1887
|
|
|
1879
|
-
const repo = entries.filter(e => e && e.delivery !== 'team');
|
|
1880
|
-
const teamGeneral = entries.filter(e => e && e.delivery === 'team');
|
|
1881
|
-
|
|
1882
1888
|
// Score with the local BM25-lite scorer over the whole pool.
|
|
1883
1889
|
const scored = scoreCandidates(promptText, entries);
|
|
1884
1890
|
const byId = new Map(entries.map(e => [e.id, e]));
|
|
1885
1891
|
const scoreOf = new Map(scored.map(s => [s.id, s.score]));
|
|
1886
1892
|
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
const tg = teamGeneral.slice(0, MEMORY_PHASE1_TEAM_GENERAL);
|
|
1900
|
-
hadTeamGeneral = tg.length > 0;
|
|
1901
|
-
// De-dupe (a team-general could also appear in topRepo if mis-tagged).
|
|
1902
|
-
const seen = new Set();
|
|
1903
|
-
picked = [...topRepo, ...tg].filter(e => e && !seen.has(e.id) && seen.add(e.id));
|
|
1904
|
-
} else {
|
|
1905
|
-
// Phase-N: surgical — only NEW (unshown) candidates crossing the threshold to
|
|
1906
|
-
// THIS prompt. No blanket team-general re-inject (already shown in phase-1).
|
|
1907
|
-
picked = scored
|
|
1908
|
-
.filter(s => s.score >= MEMORY_MATCH_MIN_SCORE && !shown[s.id])
|
|
1909
|
-
.map(s => byId.get(s.id))
|
|
1910
|
-
.filter(Boolean)
|
|
1911
|
-
.slice(0, MEMORY_INJECT_BUDGET);
|
|
1912
|
-
hadTeamGeneral = picked.some(e => e.delivery === 'team');
|
|
1913
|
-
}
|
|
1893
|
+
// Relevance-gated selection (UNIFORM across phases): inject ONLY candidates —
|
|
1894
|
+
// repo OR team-general — that clear MEMORY_MATCH_MIN_SCORE for THIS prompt and
|
|
1895
|
+
// were not already shown this session. NO unconditional team-general dump: a
|
|
1896
|
+
// low-signal prompt ("давай делай", "continue") scores ~0 → injects NOTHING.
|
|
1897
|
+
// Precision over recall BY DESIGN — silence beats context-rot. `promptIndex`
|
|
1898
|
+
// still advances via commitCount() for telemetry, but no longer gates selection.
|
|
1899
|
+
const picked = scored
|
|
1900
|
+
.filter(s => s.score >= MEMORY_MATCH_MIN_SCORE && !shown[s.id])
|
|
1901
|
+
.map(s => byId.get(s.id))
|
|
1902
|
+
.filter(Boolean)
|
|
1903
|
+
.slice(0, MEMORY_INJECT_BUDGET);
|
|
1904
|
+
const hadTeamGeneral = picked.some(e => e && e.delivery === 'team');
|
|
1914
1905
|
|
|
1915
1906
|
if (picked.length === 0) { commitCount(); return NONE; }
|
|
1916
1907
|
|