Offer the assistant the same formatting the mesh composer has, and drop the mark lower
Colour is chosen by name and mapped to a fixed value here, so the model never writes a style property — the same closed-set rule the mesh store uses.
This commit is contained in:
@@ -915,6 +915,32 @@ if ($profile === 'chat' && vv_ai_chat_needs_varaverk($question)) {
|
||||
|
||||
if ($context !== '') $system .= "PASSAGES\n" . $context;
|
||||
|
||||
// What the transcript can render, offered rather than required.
|
||||
//
|
||||
// Appended to every profile at the single point they all pass through, so a new profile cannot
|
||||
// be added without it. The set is the one the mesh composer already offers, and the renderer
|
||||
// maps colour NAMES to fixed values — the model never writes a colour, only chooses one, so
|
||||
// nothing it emits can become a style property.
|
||||
//
|
||||
// Deliberately permissive in tone. The interesting question is whether it reaches for these at
|
||||
// all and where; an instruction to use them would answer that question by force and tell us
|
||||
// nothing. Prose stays prose.
|
||||
$system .= "\n\nFORMATTING AVAILABLE TO YOU\n"
|
||||
. "The transcript renders a small set of marks. Use them where they genuinely help a "
|
||||
. "reader — a warning that must not be skimmed, a value worth picking out of a "
|
||||
. "sentence — and not otherwise. Plain prose is the default and needs no marking.\n"
|
||||
. " **bold** emphasis\n"
|
||||
. " *italic* aside or term\n"
|
||||
. " __underline__ rarely; reserve for something that must not be missed\n"
|
||||
. " {big}…{/big} one size up\n"
|
||||
. " {small}…{/small} one size down, for asides\n"
|
||||
. " {green}…{/green} also blue, amber, red, violet, grey\n"
|
||||
. "Colour carries meaning here: green for confirmed-good, amber for caution, red for "
|
||||
. "something broken or destructive. Do not colour text decoratively — a coloured word "
|
||||
. "that means nothing costs the colours their meaning everywhere else. Code fences and "
|
||||
. "`inline code` work as before and remain the right choice for anything typed at a "
|
||||
. "shell.\n";
|
||||
|
||||
$messages = [['role' => 'system', 'content' => $system]];
|
||||
$hist = json_decode($historyJson ?: '[]', true);
|
||||
if (is_array($hist)) {
|
||||
|
||||
@@ -162,7 +162,7 @@ function vv_ai_chat_assets(): void {
|
||||
.vv-ai-chat-wrap { background:#0b0b0b; border-radius:6px; }
|
||||
.vv-ai-chat-wrap::before {
|
||||
content:''; position:absolute; inset:0; z-index:0; pointer-events:none;
|
||||
background:url('/plugins/varaverk/icons/varaverk.png') center 58%/min(84%,520px) no-repeat;
|
||||
background:url('/plugins/varaverk/icons/varaverk.png') center 74%/min(84%,520px) no-repeat;
|
||||
opacity:.032; filter:grayscale(1);
|
||||
}
|
||||
.vv-ai-empty { color:#3a3a3a; font-size:12px; text-align:center; padding:60px 20px; line-height:1.7; }
|
||||
@@ -789,12 +789,32 @@ vv_ai_profiles_script();
|
||||
+ `<pre><code>${body}</code></pre></div>`;
|
||||
}
|
||||
|
||||
// The same palette the mesh composer offers, by NAME only. The model never supplies a colour
|
||||
// value — it picks from this list and the hex is looked up here, so nothing it writes can
|
||||
// become a style property. Same closed-set principle as vv_nc_clean_style() on the server.
|
||||
const FMT_COLORS = { green:'#4caf50', blue:'#4a9eff', amber:'#ff9800',
|
||||
red:'#ef5350', violet:'#ab7df6', grey:'#bdbdbd' };
|
||||
|
||||
// ── Minimal markdown, applied strictly after escaping ────────────────
|
||||
function fmt(text) {
|
||||
let h = esc(text);
|
||||
h = h.replace(/```(\w*)\n([\s\S]*?)```/g, (m, l, c) => codeCard(l, c));
|
||||
h = h.replace(/`([^`\n]+)`/g, '<code>$1</code>');
|
||||
h = h.replace(/\*\*([^*\n]+)\*\*/g, '<strong>$1</strong>');
|
||||
|
||||
// Emphasis and size. Single-asterisk italics run after bold so ** is already consumed.
|
||||
h = h.replace(/(^|[^*])\*([^*\n]+)\*(?!\*)/g, '$1<em>$2</em>');
|
||||
h = h.replace(/__([^_\n]+)__/g, '<u>$1</u>');
|
||||
h = h.replace(/\{big\}([\s\S]*?)\{\/big\}/g, '<span style="font-size:15px">$1</span>');
|
||||
h = h.replace(/\{small\}([\s\S]*?)\{\/small\}/g, '<span style="font-size:11px">$1</span>');
|
||||
|
||||
// {green}…{/green}. An unknown name is left as written rather than guessed at — a colour
|
||||
// nobody chose is worse than a pair of braces the reader can see and ignore.
|
||||
h = h.replace(/\{(\w+)\}([\s\S]*?)\{\/\1\}/g, (m, name, inner) => {
|
||||
const c = FMT_COLORS[name.toLowerCase()];
|
||||
return c ? `<span style="color:${c}">${inner}</span>` : m;
|
||||
});
|
||||
|
||||
h = h.replace(/\[(\d+)\]/g, '<span class="vv-ai-cite" data-cite="$1">[$1]</span>');
|
||||
return h;
|
||||
}
|
||||
|
||||
@@ -260,7 +260,7 @@ function vv_nc_pane_markup(string $prefix, bool $meshDefault = false,
|
||||
it can carry the badge without competing with the text. -->
|
||||
<div style="position:relative;">
|
||||
<img src="/plugins/varaverk/icons/varaverk.png" alt="" aria-hidden="true"
|
||||
style="position:absolute;left:50%;top:58%;transform:translate(-50%,-50%);
|
||||
style="position:absolute;left:50%;top:74%;transform:translate(-50%,-50%);
|
||||
width:min(94%,520px);opacity:.038;pointer-events:none;filter:grayscale(1);
|
||||
z-index:0;">
|
||||
<div id="vv-nc-log"
|
||||
|
||||
Reference in New Issue
Block a user