mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-11 13:52:20 +00:00
Stop the Coach inventing a /learn link
The Coach may point at a published /learn guide, but only a slug in the catalog. That was a prompt instruction with no enforcement — a model could hallucinate /learn/lower-your-cortisol and ship a dead link. Add a deterministic post-filter on the assembled reply that keeps a published slug verbatim and strips any reference whose slug is not in the catalog, tidying the prose around the removed link. Makes the catalog's impossible-by-construction claim an enforced guarantee.
This commit is contained in:
1 parent
976ecf8a75
commit
d5cb1e4ef8
3 files changed
+186
No files matched your search
@@ -90,6 +90,7 @@ import {
|
||||
findUnverifiedCoachNumbers,
|
||||
stripUnverifiedNumbers,
|
||||
} from "@/lib/ai/coach/coach-prose-grounding";
|
||||
import { scrubUnknownLearnLinks } from "@/lib/ai/coach/learn-link-guard";
|
||||
import { parseSuggestReminder } from "@/lib/ai/coach/suggest-reminder";
|
||||
import { gateSuggestion } from "@/lib/ai/coach/suggest-gate";
|
||||
import {
|
||||
@@ -768,6 +769,28 @@ Reply now as the assistant, in ${locale === "de" ? "German" : "English"}. Fetch
|
||||
}
|
||||
}
|
||||
|
||||
// v1.21.0 (NEW-C C-3) — Learn-link post-filter. The prompt instructs the
|
||||
// model to only link a published `/learn/<slug>`, but that is guidance, not
|
||||
// enforcement: a fabricated `/learn/<invented-slug>` would otherwise ship as
|
||||
// a dead link. Scrub any reference whose slug is not in the catalog (a real
|
||||
// one is kept verbatim). A blocked turn carries canned fallback prose with no
|
||||
// links, so skip it.
|
||||
if (!outbound.block && replyText.includes("/learn/")) {
|
||||
const scrubbed = scrubUnknownLearnLinks(replyText);
|
||||
if (scrubbed.dropped.length > 0) {
|
||||
replyText = scrubbed.text;
|
||||
annotate({
|
||||
action: { name: "coach.learn.link_dropped" },
|
||||
meta: {
|
||||
dropped: scrubbed.dropped.length,
|
||||
// Truncated slug tokens for ops triage — no user content.
|
||||
slugs: scrubbed.dropped.slice(0, 6),
|
||||
promptVersion: PROMPT_VERSION,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
let surfacedSuggestion: CoachSuggestion | null = null;
|
||||
if (!outbound.block && suggestParse.cadence) {
|
||||
const decision = await gateSuggestion({
|
||||
|
||||
Reference in new issue
Block a user