Offer Troubleshoot as a profile, and say plainly when it has no log
This commit is contained in:
+3
-2
@@ -69,7 +69,7 @@ buries it. `--kind=readme` is the hard filter for that case:
|
||||
bash AI/ai_query.sh --kind=readme "what is Varaverk"
|
||||
```
|
||||
|
||||
`--kind` filters on where a chunk came from — `header`, `readme`, `manual`, `template`, `doc` —
|
||||
`--kind` filters on where a chunk came from — `header`, `readme`, `manual`, `template`, `doc`, `ui` —
|
||||
and composes with `--section`. Prefer it over `--section` for "what is" and "why does this
|
||||
exist" questions, where the answer is narrative rather than a header field.
|
||||
|
||||
@@ -109,6 +109,7 @@ Roughly 2,900 chunks across ~180 files:
|
||||
| `manual` | Every `Manual-*.md` |
|
||||
| `template` | `Deployment/*.template` — the versioned conf schema |
|
||||
| `doc` | Top-level `README.md`, `Manual.md`, design notes |
|
||||
| `ui` | `Plugin/unraid/pages/readme/*.md` — the WebGUI's own help panels |
|
||||
|
||||
**Script bodies are not indexed.** Headers state intent, code states mechanism; for the
|
||||
questions this answers, intent retrieves better and costs far less.
|
||||
@@ -239,7 +240,7 @@ dock.
|
||||
| `varaverk` | 3 | yes | answers only from the index, with citations. The default. |
|
||||
| `chat` | 8 | **no** | ordinary conversation. Holds zero capabilities, deliberately. |
|
||||
| `code` | 4 | no | drafts shell for Custom Scripts; scans its own output for destructive ops |
|
||||
| `troubleshoot` | 2 | yes | reasons from an open log first, docs second. May file bug reports. |
|
||||
| `troubleshoot` | 2 | yes | reasons from evidence — an open log, or one you name. May file bug reports. |
|
||||
|
||||
Capabilities are granted per profile — retrieval, live health, run evidence, scoped log,
|
||||
incidents, conf lookup, bug filing, code scanning. `chat` holding an empty list is a guarantee,
|
||||
|
||||
@@ -444,9 +444,27 @@ if ($profile === 'chat') {
|
||||
// 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.
|
||||
// What it says it has is what it was actually given. This line used to assert a log tail
|
||||
// unconditionally, which was safe only while the profile could be reached exclusively by
|
||||
// opening one. It is now a button as well, so it is reachable with nothing attached — and
|
||||
// telling a model it holds evidence it does not hold is precisely how you get a confident
|
||||
// reading of a log that was never there, which is the one failure this profile exists to
|
||||
// avoid. Stated from $attached, so the prompt cannot drift from the inputs.
|
||||
$haveLog = isset($attached['log_tail']);
|
||||
$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"
|
||||
. "not do what they expected. "
|
||||
. ($haveLog
|
||||
? "You have the tail of the relevant log, live system state measured just now, "
|
||||
. "and documentation passages about the scripts involved.\n\n"
|
||||
: "You have NOT been given a log for this question — none was open and none was "
|
||||
. "named that resolves to one. You have live system state and documentation "
|
||||
. "passages only.\n\n"
|
||||
. "Say that plainly before anything else, and name what would fix it: open the "
|
||||
. "log on the Scheduler tab, or name the script in the question. Do not describe "
|
||||
. "what a log 'would' show, do not infer an outcome from the script's name, and "
|
||||
. "never write that you are reading or checking a log — you have none to read. "
|
||||
. "An invented reading is worse here than anywhere else, because the operator "
|
||||
. "came to this profile specifically for evidence.\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"
|
||||
|
||||
@@ -238,6 +238,9 @@ function vv_ai_chat_assets(): void {
|
||||
white-space:nowrap; flex:1; min-width:0; }
|
||||
.vv-ai-crow.active .vv-ai-crow-t { color:#9bd; }
|
||||
.vv-ai-crow-m { font-size:9px; color:#3a3a3a; font-family:monospace; flex-shrink:0; }
|
||||
.vv-ai-chat { transition:height .14s ease; }
|
||||
.vv-ai-grow { font-size:13px !important; line-height:1; padding:4px 9px !important; }
|
||||
.vv-ai-grow-on { color:#9bd !important; border-color:#2d4a6a !important; }
|
||||
.vv-ai-crow-s { font-size:9px; color:#5c7cfa; font-family:monospace; }
|
||||
.vv-ai-c .vv-ai-crow-s { color:#7a9ae0; }
|
||||
.vv-ai-crow-x { font-size:11px; color:#333; flex-shrink:0; padding:0 2px; visibility:hidden; }
|
||||
@@ -652,6 +655,36 @@ vv_ai_profiles_script();
|
||||
});
|
||||
const newBtn = $('new'); if (newBtn) newBtn.addEventListener('click', newChat);
|
||||
|
||||
// ── Expand / collapse ────────────────────────────────────────────────
|
||||
// Both heights come from the markup, so the page decides them and this only switches
|
||||
// between them. Remembered per instance: the dashboard chat and the tab's are different
|
||||
// sizes for different reasons, and a shared key would make one of them wrong.
|
||||
//
|
||||
// Scroll position is pinned to the bottom afterwards. Growing the box leaves the transcript
|
||||
// scrolled where it was, which puts the newest answer off-screen at the exact moment you
|
||||
// asked for more room to read it.
|
||||
const growBtn = $('grow');
|
||||
if (growBtn) {
|
||||
const el = chatEl();
|
||||
const base = el.dataset.h || '';
|
||||
const tall = el.dataset.hTall || '';
|
||||
const KEY = 'vv-ai-tall-' + P;
|
||||
const apply = big => {
|
||||
if (!base || !tall) return;
|
||||
el.style.height = big ? tall : base;
|
||||
growBtn.textContent = big ? '⤡' : '⤢';
|
||||
growBtn.title = big ? 'Back to the smaller view' : 'Give the conversation more room';
|
||||
growBtn.classList.toggle('vv-ai-grow-on', big);
|
||||
scroll();
|
||||
};
|
||||
growBtn.addEventListener('click', () => {
|
||||
const big = el.style.height !== tall;
|
||||
localStorage.setItem(KEY, big ? '1' : '0');
|
||||
apply(big);
|
||||
});
|
||||
if (localStorage.getItem(KEY) === '1') apply(true);
|
||||
}
|
||||
|
||||
// Surface any script error into the transcript. Without it a throw anywhere on the page is
|
||||
// invisible unless the console happens to be open, which is how a silent hang survives a
|
||||
// diagnosis session.
|
||||
@@ -759,7 +792,12 @@ vv_ai_profiles_script();
|
||||
// profile which profile button starts active
|
||||
// compact card-sized chrome, for a chat living inside a Monitor card
|
||||
// height transcript height; a fixed value in compact mode, since a card in a grid row
|
||||
// cannot grow with its content without dragging the row's other cards with it
|
||||
// cannot grow with its content without dragging the row's other cards with it.
|
||||
// Setting it also adds the expand control — a fixed height is exactly the situation
|
||||
// where you sometimes want more room, and there is nothing to expand without one.
|
||||
// tall the expanded height. Defaults to 2.5x height, which is the point where a long
|
||||
// answer stops needing a scroll for most questions without the card swallowing the
|
||||
// page it sits on
|
||||
// empty empty-state text
|
||||
// controls extra markup dropped into the composer's control strip
|
||||
function vv_ai_chat_markup(string $prefix, array $o = []): void {
|
||||
@@ -767,8 +805,21 @@ function vv_ai_chat_markup(string $prefix, array $o = []): void {
|
||||
$compact = !empty($o['compact']);
|
||||
$height = $o['height'] ?? '';
|
||||
$empty = $o['empty'] ?? 'Ask Varaverk about itself.';
|
||||
// 2.5x by default, computed here so the page can override with a value that suits its layout
|
||||
// rather than the include guessing at one it cannot see.
|
||||
$tall = $o['tall'] ?? '';
|
||||
if ($height !== '' && $tall === '' && preg_match('/^(\d+(?:\.\d+)?)(px|vh|em|rem)$/', $height, $hm)) {
|
||||
$n = (float)$hm[1] * 2.5;
|
||||
// vh is a share of the viewport, so 2.5x runs off the bottom of the screen — an expand
|
||||
// that puts the composer out of reach is worse than no expand. Clamped to something that
|
||||
// still leaves the page scrollable to its own controls.
|
||||
if ($hm[2] === 'vh') $n = min($n, 85);
|
||||
$tall = rtrim(rtrim(number_format($n, 2, '.', ''), '0'), '.') . $hm[2];
|
||||
}
|
||||
$style = $height !== '' ? ' style="height:' . htmlspecialchars($height, ENT_QUOTES)
|
||||
. ';max-height:none;"' : '';
|
||||
. ';max-height:none;"'
|
||||
. ' data-h="' . htmlspecialchars($height, ENT_QUOTES) . '"'
|
||||
. ' data-h-tall="' . htmlspecialchars($tall, ENT_QUOTES) . '"' : '';
|
||||
?>
|
||||
<div class="vv-ai-chatwrap<?= $compact ? ' vv-ai-c' : '' ?>" style="display:flex;flex-direction:column;gap:<?= $compact ? '4px' : '12px' ?>;min-width:0;">
|
||||
|
||||
@@ -789,6 +840,10 @@ function vv_ai_chat_markup(string $prefix, array $o = []): void {
|
||||
placeholder="<?= htmlspecialchars($o['placeholder'] ?? 'Ask anything — questions about this install route to the assistant on their own.', ENT_QUOTES) ?>"></textarea>
|
||||
<div class="vv-ai-ctrls">
|
||||
<?= $o['controls'] ?? '' ?>
|
||||
<?php if ($height !== ''): ?>
|
||||
<button class="vv-ai-btn ghost vv-ai-grow" id="<?= $p ?>-grow" type="button"
|
||||
title="Give the conversation more room">⤢</button>
|
||||
<?php endif; ?>
|
||||
<button class="vv-ai-btn ghost" id="<?= $p ?>-new" type="button">New</button>
|
||||
<span class="vv-ai-hint">Ctrl+Enter to send</span>
|
||||
<button class="vv-ai-btn" id="<?= $p ?>-send" type="button">Ask</button>
|
||||
|
||||
@@ -93,12 +93,19 @@ const VV_AI_PROFILES_DEF = [
|
||||
'ui' => true,
|
||||
'caps' => ['code_scan'],
|
||||
],
|
||||
// Offered as a button as well as entered by context. It was context-only on the reasoning
|
||||
// that choosing it from a dashboard produces a troubleshooting contract with nothing to
|
||||
// troubleshoot — true of the inputs, but not of the profile: name a script in the question
|
||||
// and run_evidence resolves the run record and log for it without any scope at all. The
|
||||
// prompt now states which of those it actually received rather than asserting a log, so
|
||||
// picking it with nothing open degrades to an honest "I cannot see one" instead of an
|
||||
// invented reading of a log that was never attached.
|
||||
'troubleshoot' => [
|
||||
'label' => 'Troubleshoot',
|
||||
'short' => 'Troubleshoot',
|
||||
'hint' => 'Reasons from the log you have open, then the docs. Files a bug only when the evidence shows one.',
|
||||
'hint' => 'Reasons from evidence — the log you have open, or one you name. Says so when there is none.',
|
||||
'turns' => 2,
|
||||
'ui' => false,
|
||||
'ui' => true,
|
||||
'caps' => ['retrieve', 'health', 'run_evidence', 'scoped_log', 'incidents', 'conf_lookup', 'file_bugs'],
|
||||
],
|
||||
];
|
||||
|
||||
@@ -59,6 +59,8 @@ as the GPU and UPS cards.
|
||||
| AI | Model residency, context size, VRAM, index size and staleness, tokens used today |
|
||||
| Conversations | The last `$AI_CHAT_HISTORY_MAX` chats. Click to reopen, × to delete |
|
||||
| Assistant | Ask a question without leaving the dashboard |
|
||||
| ⤢ | Expands the conversation to about two and a half times its height. Remembered |
|
||||
| Profile buttons | Which contract answers — General Chat, Varaverk Assistant, Code Sketcher, Troubleshoot |
|
||||
|
||||
---
|
||||
|
||||
@@ -93,6 +95,12 @@ Switching profile with the buttons keeps what is on screen but stops sending ear
|
||||
model. Carrying cited, retrieval-grounded answers into a mode with no retrieval makes the model
|
||||
keep referring to sources it can no longer see.
|
||||
|
||||
**Troubleshoot from here has no log open.** On the Scheduler tab it reads whatever log you have
|
||||
in front of you; picked from the dashboard there is nothing attached, so it says so and tells you
|
||||
how to give it evidence — open the log on the Scheduler tab, or name the script in the question,
|
||||
which resolves that script's run record and log on its own. What it will not do is describe a log
|
||||
it was never given.
|
||||
|
||||
## Conversations are shared with the AI tab
|
||||
|
||||
The same store backs both. Start a thread here, finish it on the AI tab, or the reverse — it is
|
||||
|
||||
Reference in New Issue
Block a user