Let the assistant propose what to remember, and the operator decide what is kept

This commit is contained in:
Gmer4Lfe
2026-08-10 22:00:42 -04:00
parent 57f3bf2807
commit 29e0daf80d
4 changed files with 293 additions and 0 deletions
+38
View File
@@ -96,6 +96,7 @@ if (PHP_SAPI !== 'cli') {
}
require_once dirname(__DIR__) . '/include/ai.php';
require_once dirname(__DIR__) . '/include/ai_memory_learn.php';
// ── explain mode ─────────────────────────────────────────────────────────────────────────────
// Answers "what would this question be given, and why" without asking the model anything. Every
@@ -761,6 +762,22 @@ if (trim($mem['assisted']) !== '') {
. trim($mem['assisted']) . "\n\n";
}
// Asking for the candidate inside the same call rather than making a second one. A follow-up
// "was anything here worth remembering" would cost another 25-75s on every question to answer
// "no" most of the time. The marker is stripped from the answer before it is shown, so the
// mechanism never appears in the transcript.
if (vv_ai_mem_learn_enabled()) {
$system .= "REMEMBERING SOMETHING\n"
. "If this exchange established a durable, non-obvious fact about THIS installation — "
. "a hardware quirk, a deliberate setting, something the operator corrected you on — "
. "then after your answer, on its own final line, write:\n"
. "MEMORY: <one short sentence>\n"
. "Rules: one line, under 200 characters, stated as fact with no hedging. Not a "
. "summary of your answer, not a restatement of the question, not anything already "
. "written above in what you know. Most exchanges warrant nothing — when in doubt, "
. "leave the line out entirely.\n\n";
}
if (trim($mem['learned']) !== '') {
$system .= "NOTES YOU WROTE EARLIER, KEPT BY THE OPERATOR\n"
. "These were proposed by you on previous turns and approved for keeping. They are "
@@ -932,6 +949,27 @@ fclose($fh);
$answer = trim($answer);
$thinking = trim($thinking);
// Pull the candidate out before anything else looks at the answer — the code scan, the transcript
// and the token ledger all see the text without it. Matched only at the very end, so a MEMORY:
// mentioned mid-answer while explaining this feature is not mistaken for one being filed.
if (vv_ai_mem_learn_enabled() && $answer !== '') {
if (preg_match('/\n[ \t]*MEMORY:[ \t]*(.+?)[ \t]*$/s', "\n" . $answer, $mm)) {
$candidate = trim(preg_replace('/\s+/', ' ', $mm[1]));
$answer = trim(preg_replace('/\n[ \t]*MEMORY:[ \t]*.+?[ \t]*$/s', '', "\n" . $answer));
if ($candidate !== '') {
$r = vv_ai_mem_propose($candidate, [
'profile' => $profile,
'asked' => $question,
]);
wlog(sprintf('memory candidate %s: %s',
$r['ok'] ? ($r['state'] === 'accepted' ? 'auto-accepted' : 'filed')
: ('rejected (' . ($r['error'] ?? '?') . ')'),
mb_substr($candidate, 0, 80)));
}
}
}
if ($answer === '') {
jw($jobFile, ['status' => 'error',
'error' => 'The model returned no answer' . ($thinking !== '' ? ' (only reasoning)' : ''),