diff --git a/Plugin/unraid/css/varaverk.css b/Plugin/unraid/css/varaverk.css index 66e16ac..7adc7d8 100644 --- a/Plugin/unraid/css/varaverk.css +++ b/Plugin/unraid/css/varaverk.css @@ -667,37 +667,19 @@ body.vv-fullscreen #displaybox { padding-left: 1rem !important; padding-top: .5r .vv-sug-configured { color: #4caf50; font-size: 11px; } /* Info sections inside Scheduler Information panel */ /* ── Assistant dock (scheduler right panel) ────────────────────────────────────────────────── */ -#vv-ai-dock { border: 1px solid #262626; border-radius: 6px; background: #0e0e0e; - margin-top: 6px; flex-shrink: 0; } -#vv-ai-dock-bar { display: flex; align-items: center; gap: 7px; padding: 6px 8px; } -#vv-ai-dock-chip { white-space: nowrap; max-width: 240px; overflow: hidden; - text-overflow: ellipsis; } -/* The button around it is .vv-ai-chip and carries the colour, border and padding. */ +/* The frame only. Everything the dock used to style for itself — its bar, input, transcript, + question and answer rows, sources, separators, its own grow button — is the shared chat + component's now, drawn from the same rules as the AI tab and the Monitor card. What is left is + the box the panel puts it in. */ +#vv-ai-dock { border: 1px solid #262626; border-radius: 6px; background: #0e0e0e; + margin-top: 6px; flex-shrink: 0; padding: 6px 8px; } +/* The chip states profile and subject together here, and a long script name would otherwise push + the action group off the end of a narrow panel. */ +#vv-ai-dock .vv-ai-chip { max-width: 240px; overflow: hidden; text-overflow: ellipsis; } +/* Flashed when the subject moves under text already typed — see vvAiDockScope(). */ .vv-ai-chip-flash { animation: vvAiChipFlash .9s ease-out 2; } @keyframes vvAiChipFlash { 0%,100% { background:#12191d; color:#5a7a8a; } 50% { background:#2a2312; color:#d8b25a; } } -#vv-ai-dock-input { flex: 1; min-width: 0; background: #0a0a0a; border: 1px solid #262626; - border-radius: 4px; color: #c8c8c8; font-family: inherit; font-size: 12px; - padding: 5px 9px; } -#vv-ai-dock-input:focus { outline: none; border-color: #2d4a6a; } -#vv-ai-dock-body { border-bottom: 1px solid #1c1c1c; padding: 9px 10px; overflow-y: auto; - font-size: 12px; line-height: 1.55; } -/* Always present, unlike the collapse button next to it — the size of the conversation is worth - changing before there is one, when you already know the answer will be long. */ -.vv-ai-dock-grow { flex-shrink: 0; min-width: 26px; } -.vv-ai-dock-grow-on { color: #8fb0c4; border-color: #2d4a6a; background: #12191d; } -.vv-ai-dock-q { color: #8fb0c4; margin: 0 0 5px; } -.vv-ai-dock-q::before { content: '› '; color: #3a5a6a; } -.vv-ai-dock-a { color: #b8b8b8; margin: 0 0 11px; white-space: normal; } -.vv-ai-dock-a code { background: #1a1a1a; border: 1px solid #333; border-radius: 2px; - padding: 0 4px; font-size: 11px; color: #9ab; } -.vv-ai-dock-a strong { color: #ddd; } -.vv-ai-dock-wait { color: #5a5a5a; font-style: italic; } -.vv-ai-dock-err { color: #e57; } -.vv-ai-dock-src { margin-top: 6px; padding-top: 5px; border-top: 1px solid #1c1c1c; - font-size: 10px; color: #4a4a4a; font-family: monospace; } -.vv-ai-dock-sep { margin: 4px 0 9px; font-size: 10px; color: #4a4a4a; text-align: center; - border-top: 1px solid #1c1c1c; padding-top: 6px; } .vv-info-block .vv-sug-title { color: #9ab; } /* Depth switch on the help header. Outlined rather than filled — it changes what you are @@ -1208,15 +1190,11 @@ code.vv-unknown-var { color: #ff9800; background: #1f130d; } .vv-rsync-save-btn { background: #1a2e1a; border-color: #2a4a2a; color: #6aaa6a; } .vv-rsync-save-btn:hover { background: #22382a; } -/* ── AI profile picker ──────────────────────────────────────────────────────── - Global rather than emitted with the chat widget, because both surfaces that show it are - styled differently in every other respect: the Monitor card renders a full transcript from - include/ai_chat.php, the Scheduler dock renders its own one-line bar and loads none of that - stylesheet. The picker is the one control they share, so it lives where .vv-ai-dock-* already - does instead of being emitted twice. */ -/* ── Profile picker ─────────────────────────────────────────────────────── */ -/* The chip borrows the Scheduler dock's language deliberately — same muted blue, same weight, - same 10px — so the two surfaces read as one control that happens to appear in two places. */ +/* ── Profile picker ─────────────────────────────────────────────────────────── + Global rather than emitted with the chat component. It was shared out here when the Scheduler + drew its own bar and loaded none of the component's stylesheet; that is no longer true — all + three surfaces render the same markup now — but the picker is also used by the menus around it + and reads more naturally beside them than inside the component's own block. */ .vv-ai-picker { position:relative; flex-shrink:0; } .vv-ai-chip { display:inline-flex; align-items:center; gap:5px; font-size:10px; color:#5a7a8a; background:#12191d; border:1px solid #24343d; border-radius:3px; padding:3px 8px; diff --git a/Plugin/unraid/include/ai_chat.php b/Plugin/unraid/include/ai_chat.php index 2e6b7d2..69199ea 100644 --- a/Plugin/unraid/include/ai_chat.php +++ b/Plugin/unraid/include/ai_chat.php @@ -1,9 +1,9 @@ @@ -493,6 +501,12 @@ vv_ai_profiles_script(); const q = $('input').value.trim(); if (!q) return; + // A page may claim what was typed instead of asking it. The Scheduler does this once, after + // an offer is accepted, when the next thing typed is the fix being recorded rather than a + // question. Checked here rather than in a wrapper the page calls, because Ask and Ctrl+Enter + // both land here directly and a wrapper would only catch the ones routed through it. + if (o.beforeSend && o.beforeSend(q)) { $('input').value = ''; return; } + busy = true; $('send').disabled = true; addUser(q); @@ -516,7 +530,12 @@ vv_ai_profiles_script(); question: q, history: JSON.stringify(sendable()), kind: (PROFILES[profile].kind && kindEl) ? kindEl.value : '', - think: (thinkEl ? thinkEl.checked : true) ? '1' : '0', + // A checkbox where the page offers one, otherwise whatever the page decides from the + // profile, otherwise on. The Scheduler reasons only when diagnosing: working out what a + // log means is worth waiting ~15s for, and a lookup like "what does this setting do" is + // not — an inline answer that stalls reads as broken. + think: (typeof o.think === 'function' ? o.think(profile) + : thinkEl ? thinkEl.checked : true) ? '1' : '0', }); res = fetch(API, { method: 'POST', headers: POST_HEAD, body }); } catch (e) { @@ -966,7 +985,7 @@ vv_ai_profiles_script(); box.innerHTML = '
no saved conversations yet
'; return; } - // The scope is shown, not just stored. A Scheduler dock thread is about one script or log, + // The scope is shown, not just stored. A Scheduler thread is about one script or log, // and a list of titles alone makes "why does this one talk about a log I never opened" // an unanswerable question. // Tagged only when the tag says something. A scope always does; a profile does unless it diff --git a/Plugin/unraid/pages/scheduler.php b/Plugin/unraid/pages/scheduler.php index f4ed163..652026a 100644 --- a/Plugin/unraid/pages/scheduler.php +++ b/Plugin/unraid/pages/scheduler.php @@ -65,8 +65,8 @@ require_once dirname(__DIR__) . '/include/scheduler.php'; require_once dirname(__DIR__) . '/include/docs.php'; require_once dirname(__DIR__) . '/include/ai_profiles.php'; -// For vv_ai_chat_store_script() only — this page renders no chat widget. The store is shared; -// the presentation deliberately is not. +// The chat component itself now, not only the store: the assistant panel in the right-hand pane +// is an instance of it rather than a second implementation. require_once dirname(__DIR__) . '/include/ai_chat.php'; // Live values for the `$VAR` markers in pages/readme/*.md. Conf variables, plus the derived @@ -1060,49 +1060,36 @@ Still the same two servers, two households, the same media stack running itself. them: the Scheduler Info card is only on screen in the suggestions view, so a chat box living there would vanish exactly when the context — a conf, a log, a script — is most worth asking about. - At rest it is one input row. Answers expand it upward and the views above shrink to - suit, which is why vvFitRight() subtracts its height. It pushes rather than overlays - so the thing you are asking about stays on screen. Collapsing keeps the conversation. --> + It takes a share of the panel and the views above shrink to suit, which is why + vvFitRight() subtracts its height. It pushes rather than overlays, so the thing being + asked about stays on screen; ⤢ trades more of the panel for the conversation and back. --> +
- -
- -
- -
- $def): ?> - - -
-
- - - - - -
+ 'varaverk', + 'compact' => true, + 'scopeLabel' => 'Scheduler', + 'empty' => 'Ask about what is on screen.', + 'placeholder' => 'Ask about what is on screen…', + ]); ?>