Give repair its own profile, reading what was said before and what fixed it before
Conf writing is granted to this profile alone and it is not offered as a button — making it selectable would put a write one click from any question. Its prompt leads on what it does not decide, because the resolver picks the key and the probe picks the value.
This commit is contained in:
@@ -915,6 +915,66 @@ function vv_ai_phrase_lookup(string $term, int $minSeen = 3): ?array {
|
||||
return vv_ai_phrase_aliases($minSeen)[strtolower(trim($term))] ?? null;
|
||||
}
|
||||
|
||||
// ── What the repair profile is given before it answers ───────────────────────────────────────
|
||||
// Two records of what has already happened, assembled as plain text for the prompt.
|
||||
//
|
||||
// The phrasebook half is the operator's vocabulary — and the corrections matter more than the
|
||||
// settled terms, because a term that has been corrected is one the assistant has already got
|
||||
// wrong once and would otherwise get wrong again.
|
||||
//
|
||||
// The closed-findings half is this installation's history: the same fault, and what actually
|
||||
// ended it. "Emby stopped answering last month and the address had changed" is worth more at the
|
||||
// start of a repair conversation than any amount of reasoning from first principles.
|
||||
//
|
||||
// Bounded hard. This goes into a 16k context that retrieval and a log tail are also competing
|
||||
// for, and an unbounded history would crowd out the evidence for the fault actually being
|
||||
// discussed.
|
||||
function vv_ai_repair_context(int $maxAliases = 20, int $maxFixes = 8): string {
|
||||
$out = [];
|
||||
|
||||
$aliases = vv_ai_phrase_aliases();
|
||||
if ($aliases) {
|
||||
$lines = [];
|
||||
foreach (array_slice($aliases, 0, $maxAliases, true) as $term => $a) {
|
||||
$lines[] = ' "' . $term . '" means ' . $a['target'];
|
||||
}
|
||||
$out[] = "What the operator calls things:\n" . implode("\n", $lines);
|
||||
}
|
||||
|
||||
$unsettled = vv_ai_phrase_unsettled();
|
||||
if ($unsettled) {
|
||||
$lines = [];
|
||||
foreach (array_slice($unsettled, 0, $maxAliases, true) as $term => $c) {
|
||||
$last = end($c);
|
||||
$lines[] = ' "' . $term . '" was read as ' . ($last['took_it_as'] ?: '?')
|
||||
. ' and meant ' . ($last['meant'] ?: '?');
|
||||
}
|
||||
$out[] = "Corrected before — do not repeat these:\n" . implode("\n", $lines);
|
||||
}
|
||||
|
||||
$closed = vv_ai_findings_list(['fixed', 'resolved']);
|
||||
if ($closed) {
|
||||
$lines = [];
|
||||
foreach (array_slice($closed, 0, $maxFixes) as $f) {
|
||||
$lines[] = ' ' . ($f['subject'] ?? '?') . ' / ' . ($f['ref'] ?? $f['conf_key'] ?? '?')
|
||||
. ' — ' . ($f['state'] ?? '?')
|
||||
. (!empty($f['note']) ? ': ' . mb_substr((string)$f['note'], 0, 140) : '');
|
||||
}
|
||||
$out[] = "Already dealt with on this host:\n" . implode("\n", $lines);
|
||||
}
|
||||
|
||||
$spellings = vv_ai_spellings();
|
||||
if ($spellings) {
|
||||
$lines = [];
|
||||
foreach (array_slice($spellings, 0, $maxAliases, true) as $typo => $meant) {
|
||||
$lines[] = ' "' . $typo . '" = "' . $meant . '"';
|
||||
}
|
||||
$out[] = "The operator types quickly; known shorthand:\n" . implode("\n", $lines);
|
||||
}
|
||||
|
||||
return implode("\n\n", $out);
|
||||
}
|
||||
|
||||
// ── Resolving what the operator named ────────────────────────────────────────────────────────
|
||||
// "turn off the zfs scrub", "change the emby api key" — a phrase in, an exact target out, or an
|
||||
// honest refusal with the candidates that were considered.
|
||||
|
||||
Reference in New Issue
Block a user