diff --git a/Plugin/unraid/Tools/ai_chat_worker.php b/Plugin/unraid/Tools/ai_chat_worker.php index aefaa47..440048e 100644 --- a/Plugin/unraid/Tools/ai_chat_worker.php +++ b/Plugin/unraid/Tools/ai_chat_worker.php @@ -199,11 +199,23 @@ if ($can('retrieve')) { // — nothing had failed, so nothing in the question said failure. It retrieved the documentation // on where logs live and answered with directions to a page the operator already had open. The // question is about a run that happened, so the run itself has to be in context. -$runOutcome = $can('run_evidence') && (bool)preg_match( - '/\b(how did|how.d|did .{0,24}\b(run|go|finish|complete)|last run|latest run|last night|' - . 'go last|went last|how long did|run record|rundown|summar(y|ise|ize)|recap)\b/i', - $question -); +// Which script the question names is resolved first, and carries most of the signal: naming +// something that has a log is a far stronger indicator than any turn of phrase. Wording then only +// has to separate "how did it go" from "what does it do", which is a much smaller job than +// recognising every way an operator might ask how a run went. +// +// It was a phrase list alone to begin with, and it missed "see how the run went" — one word order +// away from "went last", which it did have. Every phrase list has that failure somewhere and +// lengthening it does not end it; requiring a named target and then accepting weak evidence does. +$namedTarget = $can('run_evidence') ? vv_ai_resolve_run_target($question) : ''; + +$runOutcome = $namedTarget !== '' + // "What is the daily orchestrator" names a target and is not about any particular run. + && !vv_ai_is_definitional($question) + && (bool)preg_match( + '/\b(logs?|ran|runs?|went|go|going|gone|finish\w*|complet\w*|fail\w*|error\w*|' + . 'last night|duration|how long|rundown|summar\w*|recap|status|results?|outcome)\b/i', + $question); // Permission first, need second: the capability decides whether live state may be attached at // all, and only then does the phrasing decide whether this particular question warrants it. @@ -244,7 +256,7 @@ if ($diagnostic) { // the daily orchestrator went while looking at the suggestions list is the ordinary case, not an // edge one, and requiring them to open the log first is asking them to do the lookup themselves. $runTarget = ($can('scoped_log') && $scope !== '') ? $scope : ''; -if ($runTarget === '' && $runOutcome) $runTarget = vv_ai_resolve_run_target($question); +if ($runTarget === '' && $runOutcome) $runTarget = $namedTarget; $scopedLog = null; if ($runTarget !== '' && vv_ai_scope_ok($runTarget)) { @@ -437,7 +449,19 @@ if ($profile === 'chat') { . "general knowledge. Prefer the user's own terminology.\n\n" : "Answer only from this material and cite the passages inline as [1], [2]. If it " . "does not contain the answer, say so plainly and name what is missing — do not " - . "fill the gap from general knowledge. Prefer the user's own terminology.\n\n"); + . "fill the gap from general knowledge. Prefer the user's own terminology.\n\n") + // The troubleshooting profile has had this rule from the start; the assistant never + // did, and the gap showed. Asked to look at a log, it offered a terminal command that + // re-runs the orchestrator — real flag, wrong answer, and it starts new work instead + // of reporting finished work. + . "The operator is reading this inside the Unraid WebGUI, not a terminal. Point them " + . "at the page, tab or panel that shows what they asked about, and name it. Give a " + . "shell command only when there is genuinely no control for it, and say so when you " + . "do.\n\n" + . "Never answer a question about how something WENT by telling them to run it. A " + . "dry run, a manual trigger or a test invocation reports on new work; they asked " + . "about work that already finished. If you cannot see that run, say you cannot see " + . "it and name where it is recorded.\n\n"; } // The operator chose General Chat and is getting the Assistant. That has to be said in the answer