-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathclaim-intent.ts
More file actions
129 lines (121 loc) · 4.22 KB
/
claim-intent.ts
File metadata and controls
129 lines (121 loc) · 4.22 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
/**
* Heuristic: does this user message contain a durable assertion that
* the agent should consider asserting via codememory_assert_claim?
*
* Port of plugins/claude-code/scripts/lib/claim-intent.js — keep regex
* patterns and behavior in sync. False positives (one extra reminder
* line in the system prompt) are cheap; false negatives (silent claim
* drop) are the bug we're fixing.
*/
export type ClaimKind =
| "preference"
| "decision"
| "rejection"
| "ownership"
| "location";
export interface ClaimHit {
readonly kind: ClaimKind;
readonly snippet: string;
readonly suggestion: string;
}
interface Pattern {
readonly kind: ClaimKind;
readonly re: RegExp;
readonly suggestion: string;
}
export const PATTERNS: ReadonlyArray<Pattern> = [
{
kind: "preference",
re: /\b(i|we)\s+(love|like|prefer|enjoy|favor|favour)\b[^.!?\n]{1,120}/i,
suggestion: "prefers",
},
{
kind: "preference",
re: /\b(i|we)\s+(want|need|wanna|wish|would\s+like)\s+to\b[^.!?\n]{1,120}/i,
suggestion: "wants-to",
},
{
kind: "rejection",
re: /\b(i|we)\s+(hate|dislike|reject|refuse|don'?t\s+(want|like|use)|won'?t\s+(use|ship|build))\b[^.!?\n]{1,120}/i,
suggestion: "rejected",
},
{
kind: "rejection",
re: /\b(let'?s\s+not|we'?re\s+not\s+(using|doing|shipping|building))\b[^.!?\n]{1,120}/i,
suggestion: "rejected",
},
{
kind: "decision",
re: /\b(we|our\s+(project|team|app|service))\s+(use|uses|using|deploy|deploys|deployed|run|runs|running)\b[^.!?\n]{1,120}/i,
suggestion: "uses",
},
{
kind: "ownership",
re: /\b([A-Z][a-zA-Z]+|i|we)\s+own[s]?\b[^.!?\n]{1,120}/i,
suggestion: "owns",
},
{
kind: "location",
re: /\b(lives?|located|sits?|is)\s+(at|in|under)\s+[`"']?[a-z0-9_\-./]+[`"']?/i,
suggestion: "is-located-at",
},
];
export function isPureQuestion(text: string | null | undefined): boolean {
const trimmed = String(text ?? "").trim();
if (!trimmed.endsWith("?")) return false;
const stripped = trimmed.slice(0, -1);
return !/[.!]/.test(stripped);
}
export function detectClaimIntent(text: unknown): ClaimHit | null {
if (typeof text !== "string" || text.length === 0) return null;
if (isPureQuestion(text)) return null;
for (const { kind, re, suggestion } of PATTERNS) {
const m = re.exec(text);
if (m) {
const snippet = String(m[0]).trim().replace(/\s+/g, " ");
return { kind, snippet, suggestion };
}
}
return null;
}
export function formatClaimNudge(hit: ClaimHit): string {
return [
"[code-memory] Durable user assertion detected — ACT BEFORE ANSWERING.",
"",
`Matched (${hit.kind}): "${hit.snippet}"`,
`Suggested triple: user ${hit.suggestion} "<extracted object>"`,
"",
"DEFAULT ACTION: call codememory_assert_claim NOW, in the same response,",
"BEFORE any other tool call or user-facing text.",
"",
" codememory_assert_claim(",
' subject="user",',
` predicate="${hit.suggestion}",`,
' object="<extracted object>",',
' project="<project slug>",',
' evidence_span="<verbatim user quote>"',
" )",
"",
"DO NOT skip because:",
" - the fact is already in CLAUDE.md / AGENTS.md / code (restatement",
" reinforces; assert with confidence=0.85)",
' - the wording is emotional ("love", "hate", "really want") (sentiment',
" verbs ARE preference signals when paired with a noun/tech/pattern)",
" - the user is also asking a question in the same message (handle BOTH:",
" assert first, then answer)",
' - you "are not sure of the scope" (assert with the literal object the',
" user named; refine later if contradicted)",
"",
"SKIP ONLY if ALL of these hold:",
' - the sentence is hypothetical ("if we used X..."), counterfactual,',
" or a quoted third party",
" - OR the user is asking whether they should adopt X (question, not",
" assertion)",
" - OR the user explicitly retracts it in the same message",
" - OR a higher-confidence claim with the same subject+predicate+object",
" was asserted in this session (dedupe)",
"",
'If you skip, state ONE LINE in your response: "skipped claim: <reason>".',
"Silent skips are a bug.",
].join("\n");
}