Add a troubleshooting profile with the scoped log, and a deterministic conf-key lookup
This commit is contained in:
@@ -88,7 +88,7 @@ require_once dirname(__DIR__) . '/include/ai.php';
|
||||
if ($jobFile === '' || $question === '') exit(1);
|
||||
if (!preg_match('#/[0-9a-f]{32}\.json$#', $jobFile)) exit(1);
|
||||
|
||||
$profile = in_array($profile, ['varaverk', 'chat', 'code'], true) ? $profile : 'varaverk';
|
||||
$profile = in_array($profile, ['varaverk', 'chat', 'code', 'troubleshoot'], true) ? $profile : 'varaverk';
|
||||
|
||||
function jw(string $f, array $d): void {
|
||||
file_put_contents($f, json_encode($d));
|
||||
@@ -104,7 +104,7 @@ $sources = [];
|
||||
$context = '';
|
||||
$tRetrieve = 0.0;
|
||||
|
||||
if ($profile === 'varaverk') {
|
||||
if ($profile === 'varaverk' || $profile === 'troubleshoot') {
|
||||
jw($jobFile, ['status' => 'retrieving']);
|
||||
|
||||
// A definitional question with no explicit filter goes to the narrative docs. Left alone,
|
||||
@@ -143,11 +143,14 @@ if ($profile === 'varaverk') {
|
||||
// supposed to do; only the logs and the current config say what it actually did. Attached only
|
||||
// when the question is asking why something failed — otherwise it is a few thousand tokens of
|
||||
// noise competing with the retrieved passages for a context budget that is already tight.
|
||||
$diagnostic = $profile === 'varaverk' && (bool)preg_match(
|
||||
// The troubleshooting profile is diagnostic by definition — the operator opened a log and asked
|
||||
// about it, which is a clearer signal than any phrasing test. For the assistant it stays a
|
||||
// keyword gate, since most of its questions are not about failures.
|
||||
$diagnostic = $profile === 'troubleshoot' || ($profile === 'varaverk' && (bool)preg_match(
|
||||
'/\b(why|fail(ed|ing|ure)?|error|broken?|not work|isn.t work|wrong|stuck|hang|'
|
||||
. 'never runs?|didn.t|won.t|debug|troubleshoot|diagnos)/i',
|
||||
$question
|
||||
);
|
||||
));
|
||||
|
||||
$diagBlock = '';
|
||||
if ($diagnostic) {
|
||||
@@ -171,6 +174,42 @@ if ($diagnostic) {
|
||||
}
|
||||
}
|
||||
|
||||
// The troubleshooting profile gets the actual tail of the one log the operator is looking at,
|
||||
// warnings and ordinary lines alike. The fleet-wide WARN/ERROR sweep above cannot answer "why
|
||||
// did this one stop" — the last line a script printed before dying is usually not labelled.
|
||||
$scopedLog = null;
|
||||
if ($profile === 'troubleshoot' && $scope !== '') {
|
||||
$scopedLog = vv_ai_scoped_log($scope, 120);
|
||||
if ($scopedLog['ok']) {
|
||||
$diagBlock .= 'LOG: ' . $scopedLog['path']
|
||||
. ' (' . $scopedLog['total'] . " lines total, newest last)\n"
|
||||
. implode("\n", $scopedLog['tail']) . "\n\n";
|
||||
} else {
|
||||
$diagBlock .= "LOG: none found for " . $scope . " — it may never have run.\n\n";
|
||||
}
|
||||
}
|
||||
|
||||
// Where a named conf key really lives, resolved before the model sees the question. Deterministic
|
||||
// so the answer cannot be a guess: the operator may be certain a setting is in master.conf when
|
||||
// it is in the host conf, and the useful reply names the file and line rather than not finding it.
|
||||
if ($profile === 'varaverk' || $profile === 'troubleshoot') {
|
||||
$seen = [];
|
||||
if (preg_match_all('/\b([A-Z][A-Z0-9_]{4,})\b/', $question, $km)) {
|
||||
foreach (array_slice(array_unique($km[1]), 0, 4) as $k) {
|
||||
$hit = vv_ai_find_conf_key($k);
|
||||
if (!$hit['ok']) continue;
|
||||
$seen[] = '- ' . $k . ' is set in ' . $hit['file'] . ' at line ' . $hit['line']
|
||||
. ($hit['commented'] ? ' (commented out, so it is NOT active)' : '')
|
||||
. ': ' . $hit['text'];
|
||||
}
|
||||
}
|
||||
if ($seen) {
|
||||
$diagBlock .= "WHERE THESE SETTINGS ACTUALLY LIVE (looked up just now, authoritative)\n"
|
||||
. implode("\n", $seen) . "\n"
|
||||
. "If this is a different file from the one they have open, say so plainly.\n\n";
|
||||
}
|
||||
}
|
||||
|
||||
// One prompt per profile. Explicit profiles rather than an automatic router: misclassifying a
|
||||
// Varaverk question as chat produces a confident invention about the user's system, which is
|
||||
// precisely what retrieval exists to prevent. The user always knows which contract is in force,
|
||||
@@ -196,6 +235,26 @@ if ($profile === 'chat') {
|
||||
. "knowledge freely — Linux, scripting, hardware, whatever comes up. The restriction "
|
||||
. "is only about the specifics of THIS installation.\n\n";
|
||||
|
||||
} elseif ($profile === 'troubleshoot') {
|
||||
// Different inputs and a different refusal rule from the assistant, which is what earns it a
|
||||
// profile of its own. The assistant's contract is "answer only from the passages, refuse if
|
||||
// absent" — exactly wrong here, where the evidence is a log that is not in the index and
|
||||
// never should be. This one reasons from the log first and the documentation second.
|
||||
$system = "You are helping the operator work out why something on their Varaverk server did "
|
||||
. "not do what they expected. You have the tail of the relevant log, live system "
|
||||
. "state measured just now, and documentation passages about the scripts involved.\n\n"
|
||||
. "HOW TO ANSWER\n"
|
||||
. "Lead with what the log actually shows. Quote the line that matters. Then say what "
|
||||
. "it means, using the documentation to explain what the script was trying to do.\n\n"
|
||||
. "Say plainly when the log does not explain it. \"The log ends at X with no error, "
|
||||
. "so it was killed or is still running\" is a real and useful answer. Do not "
|
||||
. "manufacture a cause to have one — a wrong cause sends someone to fix the wrong "
|
||||
. "thing, which is worse than no answer.\n\n"
|
||||
. "Distinguish what you observed from what you inferred. The log is evidence; "
|
||||
. "anything beyond it is a hypothesis and should be labelled as one.\n\n"
|
||||
. "Do not suggest editing conf files by hand. Settings on this page have controls, "
|
||||
. "and the operator is reading this inside the WebGUI. Name the control.\n\n";
|
||||
|
||||
} elseif ($profile === 'code') {
|
||||
$system = "You are drafting a short shell script for the operator of an Unraid server, to be "
|
||||
. "saved as a Varaverk Custom Script. Assume bash on Unraid: GNU coreutils, paths "
|
||||
|
||||
Reference in New Issue
Block a user