Let General Chat search the web, and only General Chat

Search is the one capability that fits the profile holding none: every other capability either
reads this installation or changes it, and chat's whole contract is that it can do neither. The
assistant deliberately does not get it — its contract is that answers come from this install's
own documents, and a web result there is an answer that looks sourced and is not. A chat question
about this machine hands off to the assistant before the search would run, so it never reaches
the internet even with the box ticked.

Off by default, and not because it is dangerous: searching sends the operator's question outside
the house, which is theirs to decide. Asked for per turn as well as enabled in conf.

Provider-agnostic, as asked — searxng, brave, tavily. Only whichever is configured here can be
verified; all three read every field by name, so a shape that changes underneath yields no
results rather than wrong ones.

The explain fixtures asserted chat holds no capabilities at all, which is exactly the guarantee
worth keeping. caps=only: now states the set rather than its emptiness, so the check still fails
the day something else is granted there.
This commit is contained in:
Gmer4Lfe
2026-08-09 22:42:43 -04:00
parent 47861b0dc3
commit 613634473a
10 changed files with 405 additions and 12 deletions
+27
View File
@@ -345,6 +345,20 @@ vv_ai_chat_markup('vv-ai', [
Varaverk Assistant only — the other profiles do not retrieve.</div>
</div>
</div>
<!-- Shown only for profiles that hold web_search, which today means General Chat alone.
Hidden rather than disabled for the others: a control that is visible and does nothing
reads as broken, and the reason it does nothing is a capability boundary that takes a
paragraph to explain. -->
<div class="vv-ai-set-r" id="vv-ai-web-row" style="display:none">
<span class="vv-ai-set-l">Web search</span>
<div>
<label class="vv-ai-toggle"><input type="checkbox" id="vv-ai-web"> search the web for
this question</label>
<div class="vv-ai-set-d" id="vv-ai-web-state">General Chat only — it is the one profile
that cannot change anything, which is why it is the one allowed to look outside. Your
question is sent to the configured search provider.</div>
</div>
</div>
<div class="vv-ai-set-r">
<span class="vv-ai-set-l">Reasoning</span>
<div>
@@ -843,14 +857,25 @@ vv_ai_chat_markup('vv-ai', [
const kind = $('vv-ai-kind');
const bits = [kind.options[kind.selectedIndex].text.replace(/ —.*$/, '')];
if (!$('vv-ai-think').checked) bits.push('no reasoning');
if ($('vv-ai-web').checked && $('vv-ai-web-row').style.display !== 'none') bits.push('web search');
$('vv-ai-set-sum').textContent = bits.join(' · ');
}
// The row follows the profile, off the same capability the server publishes. Chat is not the
// profile you land on, so this starts hidden and appears when you switch to it.
function webRowFor(profile) {
const p = (window.VvAiProfiles || {})[profile];
const row = $('vv-ai-web-row');
row.style.display = (p && p.web) ? '' : 'none';
setSummary();
}
$('vv-ai-set-t').addEventListener('click', () => {
$('vv-ai-set-t').classList.toggle('open');
$('vv-ai-set-b').classList.toggle('open');
});
$('vv-ai-kind').addEventListener('change', setSummary);
$('vv-ai-think').addEventListener('change', setSummary);
$('vv-ai-web').addEventListener('change', setSummary);
setSummary();
$('vv-ai-tok-hosts').addEventListener('click', e => {
@@ -913,9 +938,11 @@ vv_ai_chat_markup('vv-ai', [
profile: 'varaverk', // the strict profile is the one you land on
kindEl: 'vv-ai-kind',
thinkEl: 'vv-ai-think',
webEl: 'vv-ai-web',
empty: "Ask Varaverk about itself. Answers come only from this installation's own "
+ 'documentation, with sources.',
onTurn: () => { loadBanner(true); loadTokens(); },
onProfile: p => webRowFor(p),
onChats: id => { if (chatList) chatList.setActive(id); },
});