You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit f611f5a
Browse filesBrowse the repository at this point in the historyBrowse files
fix(memory): a note is credited only when it keeps the person's words, order and every not
groundNote used to credit a note when two thirds of its content words came from the quote. Word
overlap does not preserve an instruction: "Use npm, never pnpm" has every word of "use pnpm, never
npm", and "Disable signature verification" every word of "never disable signature verification"
(the stopword list dropped "no"/"not"). The two-thirds slack also let an antonym through ("Enable
signature verification" from "disable signature verification").
Now every content word of the note must come from the quote (only a word naming where it applies,
like "repo", may be added), in the quote's order, each negated as it is there: a not/never counts
for the next content word in its clause, two cancel, and "stop"/"avoid" negate like "don't". A note
that fails is kept unconfirmed, as before, and the agent is told which rule it broke. The remember
tool's description says the same.
Tests: the reordered, negation-dropped, negation-added, double-negated and antonym notes are not
credited; a file name stays one word. Two fixtures changed with the rule: a quote that left out
"in tests" now includes it, and "Use pnpm for scripts" (adds "scripts" to "always use pnpm") became
"Always use pnpm" in the test of an unknown kind.
constRECALL_TOOL={name: 'recall_sessions',description: 'Search THIS project\'s past sessions for relevant earlier work — their recorded outcomes (what was built/fixed/decided), the files they touched, and the conversations themselves. Use when the user refers to earlier work ("what did we do about refunds?", "did we already fix the webhook?") or when prior context would clearly help before you start. Returns cited past-session outcomes (with a matching transcript snippet when the match is deep in the conversation) and dates; treat them as memory — informative but possibly stale, so verify against the current code.',input_schema: {type: 'object',properties: {query: {type: 'string',description: 'keywords or a short question, e.g. "refund retries" or "MCP timeline rail"'}},required: ['query']}};
177
177
// Memory the person asks for (docs/levelcode-sessions-memory.md §12). The host decides whether a note can be
178
178
// credited to the person (sessionMemory.groundNote); the agent only proposes it, with their words.
179
-
constREMEMBER_TOOL={name: 'remember',description: 'Save something the user told you, so future sessions in THIS project start knowing it. Use it when the user asks you to remember something; when they correct how you work ("no, use pnpm", "don\'t mock the database") or confirm an approach that was not obvious ("yes, keep doing that"); when they state a decision or constraint (write dates as absolute dates); or when they say where something lives (a dashboard, a ticket tracker, a doc). Do NOT save what the code or git history already shows, or details of the current task. `said` MUST be the user\'s own words, copied exactly from their message — the note is credited to them only when those words are found in what they typed and the note says no more than they did; otherwise it is kept unconfirmed until they confirm it. Keep `text` short and close to their words.',input_schema: {type: 'object',properties: {kind: {type: 'string',enum: ['preference','project','reference'],description: 'preference = how the user wants you to work (corrections and confirmed approaches); project = a decision, constraint or deadline; reference = where to find something outside the code'},text: {type: 'string',description: 'the note, one sentence, in the user\'s terms, e.g. "Use pnpm, never npm, in this repo"'},said: {type: 'string',description: 'the user\'s exact words this note rests on, copied from their message'}},required: ['kind','text','said']}};
179
+
constREMEMBER_TOOL={name: 'remember',description: 'Save something the user told you, so future sessions in THIS project start knowing it. Use it when the user asks you to remember something; when they correct how you work ("no, use pnpm", "don\'t mock the database") or confirm an approach that was not obvious ("yes, keep doing that"); when they state a decision or constraint (write dates as absolute dates); or when they say where something lives (a dashboard, a ticket tracker, a doc). Do NOT save what the code or git history already shows, or details of the current task. `said` MUST be the user\'s own words, copied exactly from their message — the note is credited to them only when those words are found in what they typed and the note uses only those words, in their order, keeping every not/never; otherwise it is kept unconfirmed until they confirm it. Keep `text` short and close to their words.',input_schema: {type: 'object',properties: {kind: {type: 'string',enum: ['preference','project','reference'],description: 'preference = how the user wants you to work (corrections and confirmed approaches); project = a decision, constraint or deadline; reference = where to find something outside the code'},text: {type: 'string',description: 'the note, one sentence, in the user\'s terms, e.g. "Use pnpm, never npm, in this repo"'},said: {type: 'string',description: 'the user\'s exact words this note rests on, copied from their message'}},required: ['kind','text','said']}};
180
180
constFORGET_TOOL={name: 'forget',description: 'Remove a note or fact from this project\'s memory when the user asks you to forget it or says it is no longer true. `said` MUST be the user\'s own words asking for it, copied exactly. Removes the best match for `query` and tells you what it removed.',input_schema: {type: 'object',properties: {query: {type: 'string',description: 'words that identify the memory, e.g. "pnpm"'},said: {type: 'string',description: 'the user\'s exact words asking you to forget it'}},required: ['query','said']}};
181
181
182
182
// How much of a background command's accumulated output the sniffers re-read on each chunk. Generous
Copy file name to clipboardExpand all lines: extensions/levelcode-ai/extension.js
+4-2Lines changed: 4 additions & 2 deletions
Original file line number
Diff line number
Diff line change
@@ -1547,8 +1547,10 @@ function rememberNoteTool(note) {
1547
1547
}
1548
1548
constwhy=g.reason==='not-said' ? 'the quoted words were not found in what the user typed this run'
1549
1549
: g.reason==='adds-to-what-was-said' ? 'the note says more than the quoted words do'
1550
-
: 'the quoted words are too short to credit';
1551
-
return{verified: false,message: 'Saved as UNCONFIRMED ('+why+'). It is listed in the Memory tab and has no effect until the user confirms it there. If the user did ask for this, quote their exact words in `said` and keep the note to what they said.'};
1550
+
: g.reason==='reorders-what-was-said' ? 'the note puts the quoted words in a different order'
1551
+
: g.reason==='changes-a-not' ? 'the note drops or adds a not/never the quoted words do not have'
1552
+
: 'the quoted words are too short to credit';
1553
+
return{verified: false,message: 'Saved as UNCONFIRMED ('+why+'). It is listed in the Memory tab and has no effect until the user confirms it there. If the user did ask for this, quote their exact words in `said` and keep the note to what they said, in their order, with every not/never they used.'};
1552
1554
}
1553
1555
// The forget tool's host half: removes the best-matching note or fact, when the person's own words ask for it.
test('GROUND: quotes, case and spacing do not matter; word stems do',()=>{
37
-
assert.strictEqual(mem.groundNote({text: 'Never mock the database in tests',said: '“no, NEVER mock the database”',personWords: ['no, never mock the database in tests — it bit us']}).verified,true);
37
+
assert.strictEqual(mem.groundNote({text: 'Never mock the database in tests',said: '“no, NEVER mock the database in tests”',personWords: ['no, never mock the database in tests — it bit us']}).verified,true);
38
38
assert.strictEqual(mem.groundNote({text: 'Do not mock databases',said: 'stop mocking the database',personWords: ['please stop mocking the database']}).verified,true);
39
39
});
40
40
test('GROUND: words the person never typed are not theirs',()=>{
@@ -49,6 +49,26 @@ test('GROUND: a real quote with a new order stapled on is not theirs', () => {
49
49
constg2=mem.groundNote({text: 'Use pnpm and push straight to main without review',said: 'always use pnpm, never npm',personWords: typed});
50
50
assert.strictEqual(g2.verified,false,'half grounded is not grounded: '+g2.grounded);
51
51
});
52
+
test('GROUND: every word of the note comes from the quote; only where it applies may be added',()=>{
53
+
// "in tests" was typed, but not quoted: the note may not reach outside the quote it rests on.
54
+
assert.deepStrictEqual(mem.groundNote({text: 'Never mock the database in tests',said: 'never mock the database',personWords: ['no, never mock the database in tests']}).reason,'adds-to-what-was-said');
assert.strictEqual(mem.groundNote({text: 'Use pnpm in this repo',said: 'always use pnpm',personWords: typed}).verified,true,'"repo" says where, not what');
57
+
});
58
+
test('GROUND: the note keeps the person\'s order — the same words the other way round are another instruction',()=>{
59
+
constg=mem.groundNote({text: 'Use npm, never pnpm',said: 'Use pnpm, never npm',personWords: ['Use pnpm, never npm']});
assert.deepStrictEqual(mem.groundNote({text: 'Never push to main',said: 'push to main',personWords: ['push to main when green']}).reason,'changes-a-not');
67
+
assert.deepStrictEqual(mem.groundNote({text: 'Do not stop mocking the database',said: 'stop mocking the database',personWords: ['please stop mocking the database']}).reason,'changes-a-not','two negators cancel');
68
+
assert.deepStrictEqual(mem.groundNote({text: 'Use yarn',said: 'never use npm or yarn',personWords: ['never use npm or yarn']}).reason,'changes-a-not');
69
+
assert.strictEqual(mem.groundNote({text: 'Don\u2019t push to main',said: "don't push to main",personWords: ["don't push to main"]}).verified,true,'curly and straight apostrophes are the same not');
70
+
assert.strictEqual(mem.groundNote({text: 'Never edit package.json by hand',said: 'never edit package.json by hand',personWords: ['never edit package.json by hand']}).verified,true,'a file name is one word, not two clauses');
71
+
});
52
72
test('GROUND: a quote too short to mean anything is not enough',()=>{
assert.strictEqual(host.rememberNoteTool({kind: 'nonsense',text: 'Use pnpm for scripts',said: 'always use pnpm',personWords: typed}).verified,true,'an unknown kind is kept as a preference');
163
+
assert.strictEqual(host.rememberNoteTool({kind: 'nonsense',text: 'Always use pnpm',said: 'always use pnpm',personWords: typed}).verified,true,'an unknown kind is kept as a preference');
164
164
});
165
165
awaittestAsync('HOST: forget needs the person\'s own words, then removes the best match and names it',async()=>{
166
166
constno=host.forgetNoteTool({query: 'pnpm',said: 'forget the pnpm rule',personWords: typed});
0 commit comments