ui: add contextual tooltips to web form controls
This commit is contained in:
@@ -832,7 +832,7 @@ function updateAssistantHealth(configData) {
|
|||||||
const modelDataList = (id, provider, selected) => {
|
const modelDataList = (id, provider, selected) => {
|
||||||
const options = modelOptionsByProvider[provider] ?? [];
|
const options = modelOptionsByProvider[provider] ?? [];
|
||||||
return `
|
return `
|
||||||
<input id="${id}" list="${id}-list" value="${escapeHtml(selected ?? '')}" class="bg-zinc-950 text-zinc-50 border border-zinc-800 rounded-md px-2 py-1.5 text-sm focus:border-blue-500 outline-none" />
|
<input id="${id}" list="${id}-list" value="${escapeHtml(selected ?? '')}" class="bg-zinc-950 text-zinc-50 border border-zinc-800 rounded-md px-2 py-1.5 text-sm focus:border-blue-500 outline-none" title="Enter a model ID for the selected provider or pick one from the suggestion list." />
|
||||||
<datalist id="${id}-list">
|
<datalist id="${id}-list">
|
||||||
${options.map((model) => `<option value="${escapeHtml(model)}"></option>`).join('')}
|
${options.map((model) => `<option value="${escapeHtml(model)}"></option>`).join('')}
|
||||||
</datalist>
|
</datalist>
|
||||||
@@ -909,13 +909,13 @@ function updateAssistantHealth(configData) {
|
|||||||
<div class="p-3 border border-zinc-800 rounded-md bg-zinc-950/60">
|
<div class="p-3 border border-zinc-800 rounded-md bg-zinc-950/60">
|
||||||
<div class="text-sm text-zinc-50 mb-2">${escapeHtml(tier)} tier</div>
|
<div class="text-sm text-zinc-50 mb-2">${escapeHtml(tier)} tier</div>
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-2">
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-2">
|
||||||
<label class="flex flex-col gap-1">
|
<label class="flex flex-col gap-1" title="Provider used for this model tier.">
|
||||||
<span class="text-xs text-zinc-500">Provider</span>
|
<span class="text-xs text-zinc-500">Provider</span>
|
||||||
<select id="assist-tier-${tier}-provider" class="bg-zinc-950 text-zinc-50 border border-zinc-800 rounded-md px-2 py-1.5 text-sm focus:border-blue-500 outline-none">
|
<select id="assist-tier-${tier}-provider" class="bg-zinc-950 text-zinc-50 border border-zinc-800 rounded-md px-2 py-1.5 text-sm focus:border-blue-500 outline-none" title="Select a provider for the ${escapeHtml(tier)} tier.">
|
||||||
${providerOption(provider)}
|
${providerOption(provider)}
|
||||||
</select>
|
</select>
|
||||||
</label>
|
</label>
|
||||||
<label class="flex flex-col gap-1">
|
<label class="flex flex-col gap-1" title="Default model name for this tier.">
|
||||||
<span class="text-xs text-zinc-500">Model</span>
|
<span class="text-xs text-zinc-500">Model</span>
|
||||||
${modelDataList(`assist-tier-${tier}-model`, provider, model)}
|
${modelDataList(`assist-tier-${tier}-model`, provider, model)}
|
||||||
</label>
|
</label>
|
||||||
@@ -925,9 +925,9 @@ function updateAssistantHealth(configData) {
|
|||||||
}).join('')}
|
}).join('')}
|
||||||
</div>
|
</div>
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-3 mb-4">
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-3 mb-4">
|
||||||
<label class="flex flex-col gap-1.5">
|
<label class="flex flex-col gap-1.5" title="Main tier used when no task-specific routing rule applies.">
|
||||||
<span class="text-sm text-zinc-400">Primary tier</span>
|
<span class="text-sm text-zinc-400">Primary tier</span>
|
||||||
<select id="assist-primary-tier" class="w-full bg-zinc-950 text-zinc-50 border border-zinc-800 rounded-md px-3 py-2 text-sm focus:border-blue-500 outline-none">
|
<select id="assist-primary-tier" class="w-full bg-zinc-950 text-zinc-50 border border-zinc-800 rounded-md px-3 py-2 text-sm focus:border-blue-500 outline-none" title="Choose the default model tier for general assistant responses.">
|
||||||
${tierOption(modelTier)}
|
${tierOption(modelTier)}
|
||||||
</select>
|
</select>
|
||||||
</label>
|
</label>
|
||||||
@@ -943,23 +943,23 @@ function updateAssistantHealth(configData) {
|
|||||||
<div class="p-3 border border-zinc-800 rounded-md bg-zinc-950/60">
|
<div class="p-3 border border-zinc-800 rounded-md bg-zinc-950/60">
|
||||||
<div class="text-sm text-zinc-50 mb-2">${escapeHtml(task.label)}</div>
|
<div class="text-sm text-zinc-50 mb-2">${escapeHtml(task.label)}</div>
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-5 gap-2">
|
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-5 gap-2">
|
||||||
<label class="flex flex-col gap-1">
|
<label class="flex flex-col gap-1" title="Tier used when this task is delegated.">
|
||||||
<span class="text-xs text-zinc-500">Delegation tier</span>
|
<span class="text-xs text-zinc-500">Delegation tier</span>
|
||||||
<select id="assist-delegation-${task.key}" class="bg-zinc-950 text-zinc-50 border border-zinc-800 rounded-md px-2 py-1.5 text-sm focus:border-blue-500 outline-none">
|
<select id="assist-delegation-${task.key}" class="bg-zinc-950 text-zinc-50 border border-zinc-800 rounded-md px-2 py-1.5 text-sm focus:border-blue-500 outline-none" title="Select the tier used for ${escapeHtml(task.label.toLowerCase())} delegation.">
|
||||||
${tierOption(delegationTier)}
|
${tierOption(delegationTier)}
|
||||||
</select>
|
</select>
|
||||||
</label>
|
</label>
|
||||||
<label class="flex items-center gap-2 mt-5 md:mt-0">
|
<label class="flex items-center gap-2 mt-5 md:mt-0" title="When enabled, this task can use a custom provider/model override.">
|
||||||
<input id="assist-bg-${task.key}-enabled" type="checkbox" ${backgroundEnabled ? 'checked' : ''} />
|
<input id="assist-bg-${task.key}-enabled" type="checkbox" ${backgroundEnabled ? 'checked' : ''} title="Toggle background provider/model override for this task." />
|
||||||
<span class="text-xs text-zinc-400">Enable provider/model override</span>
|
<span class="text-xs text-zinc-400">Enable provider/model override</span>
|
||||||
</label>
|
</label>
|
||||||
<label class="flex flex-col gap-1">
|
<label class="flex flex-col gap-1" title="Provider used when override is enabled.">
|
||||||
<span class="text-xs text-zinc-500">Provider</span>
|
<span class="text-xs text-zinc-500">Provider</span>
|
||||||
<select id="assist-bg-${task.key}-provider" class="bg-zinc-950 text-zinc-50 border border-zinc-800 rounded-md px-2 py-1.5 text-sm focus:border-blue-500 outline-none">
|
<select id="assist-bg-${task.key}-provider" class="bg-zinc-950 text-zinc-50 border border-zinc-800 rounded-md px-2 py-1.5 text-sm focus:border-blue-500 outline-none" title="Pick the override provider for this task.">
|
||||||
${providerOption(draftTask.provider ?? background?.provider ?? tiers?.default?.provider ?? 'openai')}
|
${providerOption(draftTask.provider ?? background?.provider ?? tiers?.default?.provider ?? 'openai')}
|
||||||
</select>
|
</select>
|
||||||
</label>
|
</label>
|
||||||
<label class="flex flex-col gap-1">
|
<label class="flex flex-col gap-1" title="Model used when override is enabled.">
|
||||||
<span class="text-xs text-zinc-500">Model</span>
|
<span class="text-xs text-zinc-500">Model</span>
|
||||||
${modelDataList(
|
${modelDataList(
|
||||||
`assist-bg-${task.key}-model`,
|
`assist-bg-${task.key}-model`,
|
||||||
@@ -967,9 +967,9 @@ function updateAssistantHealth(configData) {
|
|||||||
draftTask.model ?? background?.model ?? '',
|
draftTask.model ?? background?.model ?? '',
|
||||||
)}
|
)}
|
||||||
</label>
|
</label>
|
||||||
<label class="flex flex-col gap-1">
|
<label class="flex flex-col gap-1" title="Tier to fall back to if the override model fails.">
|
||||||
<span class="text-xs text-zinc-500">Fallback tier</span>
|
<span class="text-xs text-zinc-500">Fallback tier</span>
|
||||||
<select id="assist-bg-${task.key}-fallback" class="bg-zinc-950 text-zinc-50 border border-zinc-800 rounded-md px-2 py-1.5 text-sm focus:border-blue-500 outline-none">
|
<select id="assist-bg-${task.key}-fallback" class="bg-zinc-950 text-zinc-50 border border-zinc-800 rounded-md px-2 py-1.5 text-sm focus:border-blue-500 outline-none" title="Choose the fallback tier for this task override.">
|
||||||
${tierOption(draftTask.fallbackTier ?? background?.fallback_tier ?? 'fast')}
|
${tierOption(draftTask.fallbackTier ?? background?.fallback_tier ?? 'fast')}
|
||||||
</select>
|
</select>
|
||||||
</label>
|
</label>
|
||||||
@@ -988,59 +988,59 @@ function updateAssistantHealth(configData) {
|
|||||||
<div class="text-sm font-semibold text-zinc-50 mb-3">Councils</div>
|
<div class="text-sm font-semibold text-zinc-50 mb-3">Councils</div>
|
||||||
<div class="text-sm text-zinc-500 mb-3">On-demand council orchestration settings and council role model tiers.</div>
|
<div class="text-sm text-zinc-500 mb-3">On-demand council orchestration settings and council role model tiers.</div>
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-3 mb-4">
|
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-3 mb-4">
|
||||||
<label class="flex items-center gap-2 mt-5 md:mt-0">
|
<label class="flex items-center gap-2 mt-5 md:mt-0" title="Enable on-demand council orchestration flows.">
|
||||||
<input id="assist-councils-enabled" type="checkbox" ${councils.enabled ? 'checked' : ''} />
|
<input id="assist-councils-enabled" type="checkbox" ${councils.enabled ? 'checked' : ''} title="Toggle council orchestration features." />
|
||||||
<span class="text-xs text-zinc-400">Enable councils</span>
|
<span class="text-xs text-zinc-400">Enable councils</span>
|
||||||
</label>
|
</label>
|
||||||
<label class="flex flex-col gap-1.5">
|
<label class="flex flex-col gap-1.5" title="Model tier for D-council agents.">
|
||||||
<span class="text-sm text-zinc-400">D model tier</span>
|
<span class="text-sm text-zinc-400">D model tier</span>
|
||||||
<select id="assist-council-d-tier" class="w-full bg-zinc-950 text-zinc-50 border border-zinc-800 rounded-md px-3 py-2 text-sm focus:border-blue-500 outline-none">
|
<select id="assist-council-d-tier" class="w-full bg-zinc-950 text-zinc-50 border border-zinc-800 rounded-md px-3 py-2 text-sm focus:border-blue-500 outline-none" title="Set the model tier for D-council roles.">
|
||||||
${tierOption(councilsD.model_tier ?? 'complex')}
|
${tierOption(councilsD.model_tier ?? 'complex')}
|
||||||
</select>
|
</select>
|
||||||
</label>
|
</label>
|
||||||
<label class="flex flex-col gap-1.5">
|
<label class="flex flex-col gap-1.5" title="Model tier for P-council agents.">
|
||||||
<span class="text-sm text-zinc-400">P model tier</span>
|
<span class="text-sm text-zinc-400">P model tier</span>
|
||||||
<select id="assist-council-p-tier" class="w-full bg-zinc-950 text-zinc-50 border border-zinc-800 rounded-md px-3 py-2 text-sm focus:border-blue-500 outline-none">
|
<select id="assist-council-p-tier" class="w-full bg-zinc-950 text-zinc-50 border border-zinc-800 rounded-md px-3 py-2 text-sm focus:border-blue-500 outline-none" title="Set the model tier for P-council roles.">
|
||||||
${tierOption(councilsP.model_tier ?? 'complex')}
|
${tierOption(councilsP.model_tier ?? 'complex')}
|
||||||
</select>
|
</select>
|
||||||
</label>
|
</label>
|
||||||
<label class="flex flex-col gap-1.5">
|
<label class="flex flex-col gap-1.5" title="Model tier used for council meta synthesis.">
|
||||||
<span class="text-sm text-zinc-400">Meta model tier</span>
|
<span class="text-sm text-zinc-400">Meta model tier</span>
|
||||||
<select id="assist-council-meta-tier" class="w-full bg-zinc-950 text-zinc-50 border border-zinc-800 rounded-md px-3 py-2 text-sm focus:border-blue-500 outline-none">
|
<select id="assist-council-meta-tier" class="w-full bg-zinc-950 text-zinc-50 border border-zinc-800 rounded-md px-3 py-2 text-sm focus:border-blue-500 outline-none" title="Set the model tier for the council meta arbiter.">
|
||||||
${tierOption(councils.meta_model_tier ?? 'complex')}
|
${tierOption(councils.meta_model_tier ?? 'complex')}
|
||||||
</select>
|
</select>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-3 mb-4">
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-3 mb-4">
|
||||||
<label class="flex flex-col gap-1.5">
|
<label class="flex flex-col gap-1.5" title="Agent ID for the D arbiter role.">
|
||||||
<span class="text-sm text-zinc-400">D arbiter agent</span>
|
<span class="text-sm text-zinc-400">D arbiter agent</span>
|
||||||
<input id="assist-council-d-arbiter" type="text" value="${escapeHtml(councilsD.arbiter_agent ?? 'council_d_arbiter')}" class="w-full bg-zinc-950 text-zinc-50 border border-zinc-800 rounded-md px-3 py-2 text-sm focus:border-blue-500 outline-none" />
|
<input id="assist-council-d-arbiter" type="text" value="${escapeHtml(councilsD.arbiter_agent ?? 'council_d_arbiter')}" class="w-full bg-zinc-950 text-zinc-50 border border-zinc-800 rounded-md px-3 py-2 text-sm focus:border-blue-500 outline-none" title="Configured agent key for the D arbiter role." />
|
||||||
</label>
|
</label>
|
||||||
<label class="flex flex-col gap-1.5">
|
<label class="flex flex-col gap-1.5" title="Agent ID for the D freethinker role.">
|
||||||
<span class="text-sm text-zinc-400">D freethinker agent</span>
|
<span class="text-sm text-zinc-400">D freethinker agent</span>
|
||||||
<input id="assist-council-d-freethinker" type="text" value="${escapeHtml(councilsD.freethinker_agent ?? 'council_d_freethinker')}" class="w-full bg-zinc-950 text-zinc-50 border border-zinc-800 rounded-md px-3 py-2 text-sm focus:border-blue-500 outline-none" />
|
<input id="assist-council-d-freethinker" type="text" value="${escapeHtml(councilsD.freethinker_agent ?? 'council_d_freethinker')}" class="w-full bg-zinc-950 text-zinc-50 border border-zinc-800 rounded-md px-3 py-2 text-sm focus:border-blue-500 outline-none" title="Configured agent key for the D freethinker role." />
|
||||||
</label>
|
</label>
|
||||||
<label class="flex flex-col gap-1.5">
|
<label class="flex flex-col gap-1.5" title="Agent ID for the P arbiter role.">
|
||||||
<span class="text-sm text-zinc-400">P arbiter agent</span>
|
<span class="text-sm text-zinc-400">P arbiter agent</span>
|
||||||
<input id="assist-council-p-arbiter" type="text" value="${escapeHtml(councilsP.arbiter_agent ?? 'council_p_arbiter')}" class="w-full bg-zinc-950 text-zinc-50 border border-zinc-800 rounded-md px-3 py-2 text-sm focus:border-blue-500 outline-none" />
|
<input id="assist-council-p-arbiter" type="text" value="${escapeHtml(councilsP.arbiter_agent ?? 'council_p_arbiter')}" class="w-full bg-zinc-950 text-zinc-50 border border-zinc-800 rounded-md px-3 py-2 text-sm focus:border-blue-500 outline-none" title="Configured agent key for the P arbiter role." />
|
||||||
</label>
|
</label>
|
||||||
<label class="flex flex-col gap-1.5">
|
<label class="flex flex-col gap-1.5" title="Agent ID for the P freethinker role.">
|
||||||
<span class="text-sm text-zinc-400">P freethinker agent</span>
|
<span class="text-sm text-zinc-400">P freethinker agent</span>
|
||||||
<input id="assist-council-p-freethinker" type="text" value="${escapeHtml(councilsP.freethinker_agent ?? 'council_p_freethinker')}" class="w-full bg-zinc-950 text-zinc-50 border border-zinc-800 rounded-md px-3 py-2 text-sm focus:border-blue-500 outline-none" />
|
<input id="assist-council-p-freethinker" type="text" value="${escapeHtml(councilsP.freethinker_agent ?? 'council_p_freethinker')}" class="w-full bg-zinc-950 text-zinc-50 border border-zinc-800 rounded-md px-3 py-2 text-sm focus:border-blue-500 outline-none" title="Configured agent key for the P freethinker role." />
|
||||||
</label>
|
</label>
|
||||||
<label class="flex flex-col gap-1.5">
|
<label class="flex flex-col gap-1.5" title="Agent ID for the meta arbiter role.">
|
||||||
<span class="text-sm text-zinc-400">Meta arbiter agent</span>
|
<span class="text-sm text-zinc-400">Meta arbiter agent</span>
|
||||||
<input id="assist-council-meta-arbiter" type="text" value="${escapeHtml(councils.meta_arbiter_agent ?? 'council_meta_arbiter')}" class="w-full bg-zinc-950 text-zinc-50 border border-zinc-800 rounded-md px-3 py-2 text-sm focus:border-blue-500 outline-none" />
|
<input id="assist-council-meta-arbiter" type="text" value="${escapeHtml(councils.meta_arbiter_agent ?? 'council_meta_arbiter')}" class="w-full bg-zinc-950 text-zinc-50 border border-zinc-800 rounded-md px-3 py-2 text-sm focus:border-blue-500 outline-none" title="Configured agent key for the council meta arbiter role." />
|
||||||
</label>
|
</label>
|
||||||
<label class="flex flex-col gap-1.5">
|
<label class="flex flex-col gap-1.5" title="Optional JSON scaffold used as council prompt template.">
|
||||||
<span class="text-sm text-zinc-400">Scaffold path (optional)</span>
|
<span class="text-sm text-zinc-400">Scaffold path (optional)</span>
|
||||||
<input id="assist-council-scaffold" type="text" value="${escapeHtml(councils.scaffold_path ?? '')}" placeholder="docs/councils/ai-council-production-scaffold.json" class="w-full bg-zinc-950 text-zinc-50 border border-zinc-800 rounded-md px-3 py-2 text-sm focus:border-blue-500 outline-none" />
|
<input id="assist-council-scaffold" type="text" value="${escapeHtml(councils.scaffold_path ?? '')}" placeholder="docs/councils/ai-council-production-scaffold.json" class="w-full bg-zinc-950 text-zinc-50 border border-zinc-800 rounded-md px-3 py-2 text-sm focus:border-blue-500 outline-none" title="Path to a scaffold JSON file under the project directory." />
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-3 mb-4">
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-3 mb-4">
|
||||||
<label class="flex flex-col gap-1.5">
|
<label class="flex flex-col gap-1.5" title="Upper bound on iterative council rounds per run.">
|
||||||
<span class="text-sm text-zinc-400">Max rounds</span>
|
<span class="text-sm text-zinc-400">Max rounds</span>
|
||||||
<input id="assist-council-max-rounds" type="number" min="1" max="6" value="${escapeHtml(String(councilsDefaults.max_rounds ?? 2))}" class="w-full bg-zinc-950 text-zinc-50 border border-zinc-800 rounded-md px-3 py-2 text-sm focus:border-blue-500 outline-none" />
|
<input id="assist-council-max-rounds" type="number" min="1" max="6" value="${escapeHtml(String(councilsDefaults.max_rounds ?? 2))}" class="w-full bg-zinc-950 text-zinc-50 border border-zinc-800 rounded-md px-3 py-2 text-sm focus:border-blue-500 outline-none" title="Use 1-6 rounds; higher values increase cost and latency." />
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-wrap gap-2">
|
<div class="flex flex-wrap gap-2">
|
||||||
@@ -1052,16 +1052,14 @@ function updateAssistantHealth(configData) {
|
|||||||
<div class="text-sm font-semibold text-zinc-50 mb-2">Council Conversations</div>
|
<div class="text-sm font-semibold text-zinc-50 mb-2">Council Conversations</div>
|
||||||
<div class="text-xs text-zinc-500 mb-3">${escapeHtml(councilSummary)}</div>
|
<div class="text-xs text-zinc-500 mb-3">${escapeHtml(councilSummary)}</div>
|
||||||
<div class="grid grid-cols-1 md:grid-cols-[1fr_auto] gap-2 mb-3">
|
<div class="grid grid-cols-1 md:grid-cols-[1fr_auto] gap-2 mb-3">
|
||||||
<input id="assist-council-task" type="text" value="${escapeHtml(_lastCouncilTask)}" placeholder="Run councils on demand: e.g. design a 2-week experiment plan..." class="w-full bg-zinc-950 text-zinc-50 border border-zinc-800 rounded-md px-3 py-2 text-sm focus:border-blue-500 outline-none" />
|
<input id="assist-council-task" type="text" value="${escapeHtml(_lastCouncilTask)}" placeholder="Run councils on demand: e.g. design a 2-week experiment plan..." class="w-full bg-zinc-950 text-zinc-50 border border-zinc-800 rounded-md px-3 py-2 text-sm focus:border-blue-500 outline-none" title="Prompt for an ad-hoc council run; use a concrete decision or planning question." />
|
||||||
<button class="px-3 py-1.5 text-sm font-medium rounded-md border border-zinc-700 bg-zinc-800 text-zinc-200 hover:bg-zinc-700 transition-colors assistant-action-btn" data-action="run-council">
|
<button class="px-3 py-1.5 text-sm font-medium rounded-md border border-zinc-700 bg-zinc-800 text-zinc-200 hover:bg-zinc-700 transition-colors assistant-action-btn" data-action="run-council">
|
||||||
Run Council
|
Run Council
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div id="assist-council-status" class="text-sm text-zinc-500 mb-3"></div>
|
<div id="assist-council-status" class="text-sm text-zinc-500 mb-3"></div>
|
||||||
<div class="max-h-72 overflow-y-auto space-y-2">
|
<div class="max-h-72 overflow-y-auto space-y-2">
|
||||||
${councilConversations.length === 0
|
${councilConversations.length === 0 ? '<div class="text-sm text-zinc-500">No conversation log yet.</div>' : councilConversations.map((turn, idx) => `
|
||||||
? '<div class="text-sm text-zinc-500">No conversation log yet.</div>'
|
|
||||||
: councilConversations.map((turn, idx) => `
|
|
||||||
<details class="border border-zinc-800 rounded-md bg-zinc-900/70 p-2">
|
<details class="border border-zinc-800 rounded-md bg-zinc-900/70 p-2">
|
||||||
<summary class="cursor-pointer text-sm text-zinc-100">
|
<summary class="cursor-pointer text-sm text-zinc-100">
|
||||||
#${idx + 1} ${escapeHtml(turn.call_id)} · ${escapeHtml(turn.agent)} @ ${escapeHtml(turn.tier)}
|
#${idx + 1} ${escapeHtml(turn.call_id)} · ${escapeHtml(turn.agent)} @ ${escapeHtml(turn.tier)}
|
||||||
@@ -1086,13 +1084,13 @@ function updateAssistantHealth(configData) {
|
|||||||
`).join('')}
|
`).join('')}
|
||||||
</div>
|
</div>
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-4">
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-4">
|
||||||
<label class="flex flex-col gap-1.5">
|
<label class="flex flex-col gap-1.5" title="Channel used for scheduled briefing messages.">
|
||||||
<span class="text-sm text-zinc-400">Briefing output channel</span>
|
<span class="text-sm text-zinc-400">Briefing output channel</span>
|
||||||
<input id="assist-brief-channel" type="text" value="${escapeHtml(briefingOutput?.channel ?? '')}" placeholder="telegram" class="w-full bg-zinc-950 text-zinc-50 border border-zinc-800 rounded-md px-3 py-2 text-sm focus:border-blue-500 outline-none" />
|
<input id="assist-brief-channel" type="text" value="${escapeHtml(briefingOutput?.channel ?? '')}" placeholder="telegram" class="w-full bg-zinc-950 text-zinc-50 border border-zinc-800 rounded-md px-3 py-2 text-sm focus:border-blue-500 outline-none" title="Set the output adapter name for daily briefing delivery." />
|
||||||
</label>
|
</label>
|
||||||
<label class="flex flex-col gap-1.5">
|
<label class="flex flex-col gap-1.5" title="Destination peer/chat ID for scheduled briefings.">
|
||||||
<span class="text-sm text-zinc-400">Briefing output peer/chat id</span>
|
<span class="text-sm text-zinc-400">Briefing output peer/chat id</span>
|
||||||
<input id="assist-brief-peer" type="text" value="${escapeHtml(briefingOutput?.peer ?? '')}" placeholder="123456789" class="w-full bg-zinc-950 text-zinc-50 border border-zinc-800 rounded-md px-3 py-2 text-sm focus:border-blue-500 outline-none" />
|
<input id="assist-brief-peer" type="text" value="${escapeHtml(briefingOutput?.peer ?? '')}" placeholder="123456789" class="w-full bg-zinc-950 text-zinc-50 border border-zinc-800 rounded-md px-3 py-2 text-sm focus:border-blue-500 outline-none" title="Set the recipient peer/chat ID for briefing delivery." />
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-wrap gap-2">
|
<div class="flex flex-wrap gap-2">
|
||||||
@@ -1446,21 +1444,21 @@ function renderServiceConfigModal() {
|
|||||||
const heartbeatSection = service.name === 'heartbeat'
|
const heartbeatSection = service.name === 'heartbeat'
|
||||||
? `
|
? `
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-2">
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-2">
|
||||||
<label class="flex flex-col gap-1">
|
<label class="flex flex-col gap-1" title="Heartbeat check interval (examples: 1m, 5m, 30s).">
|
||||||
<span class="text-xs text-zinc-500">Interval (e.g. 5m)</span>
|
<span class="text-xs text-zinc-500">Interval (e.g. 5m)</span>
|
||||||
<input id="svc-heartbeat-interval" type="text" value="${escapeHtml(String(getConfigValue('automation.heartbeat.interval', '5m')))}" class="bg-zinc-950 text-zinc-50 border border-zinc-800 rounded-md px-2 py-1.5 text-sm focus:border-blue-500 outline-none" />
|
<input id="svc-heartbeat-interval" type="text" value="${escapeHtml(String(getConfigValue('automation.heartbeat.interval', '5m')))}" class="bg-zinc-950 text-zinc-50 border border-zinc-800 rounded-md px-2 py-1.5 text-sm focus:border-blue-500 outline-none" title="How often heartbeat checks are executed." />
|
||||||
</label>
|
</label>
|
||||||
<label class="flex flex-col gap-1">
|
<label class="flex flex-col gap-1" title="Minimum wait between repeated failure notifications.">
|
||||||
<span class="text-xs text-zinc-500">Notify cooldown</span>
|
<span class="text-xs text-zinc-500">Notify cooldown</span>
|
||||||
<input id="svc-heartbeat-notify-cooldown" type="text" value="${escapeHtml(String(getConfigValue('automation.heartbeat.notify_cooldown', '30m')))}" class="bg-zinc-950 text-zinc-50 border border-zinc-800 rounded-md px-2 py-1.5 text-sm focus:border-blue-500 outline-none" />
|
<input id="svc-heartbeat-notify-cooldown" type="text" value="${escapeHtml(String(getConfigValue('automation.heartbeat.notify_cooldown', '30m')))}" class="bg-zinc-950 text-zinc-50 border border-zinc-800 rounded-md px-2 py-1.5 text-sm focus:border-blue-500 outline-none" title="Cooldown duration before sending another alert for the same issue." />
|
||||||
</label>
|
</label>
|
||||||
<label class="flex flex-col gap-1">
|
<label class="flex flex-col gap-1" title="Consecutive failed checks required before a service is marked unhealthy.">
|
||||||
<span class="text-xs text-zinc-500">Failure threshold</span>
|
<span class="text-xs text-zinc-500">Failure threshold</span>
|
||||||
<input id="svc-heartbeat-failure-threshold" type="number" min="1" max="10" value="${escapeHtml(String(getConfigValue('automation.heartbeat.failure_threshold', 2)))}" class="bg-zinc-950 text-zinc-50 border border-zinc-800 rounded-md px-2 py-1.5 text-sm focus:border-blue-500 outline-none" />
|
<input id="svc-heartbeat-failure-threshold" type="number" min="1" max="10" value="${escapeHtml(String(getConfigValue('automation.heartbeat.failure_threshold', 2)))}" class="bg-zinc-950 text-zinc-50 border border-zinc-800 rounded-md px-2 py-1.5 text-sm focus:border-blue-500 outline-none" title="Use 1 for aggressive alerting, higher values to reduce false positives." />
|
||||||
</label>
|
</label>
|
||||||
<label class="flex flex-col gap-1">
|
<label class="flex flex-col gap-1" title="Free disk space alert threshold in megabytes.">
|
||||||
<span class="text-xs text-zinc-500">Disk threshold (MB)</span>
|
<span class="text-xs text-zinc-500">Disk threshold (MB)</span>
|
||||||
<input id="svc-heartbeat-disk-threshold" type="number" min="10" value="${escapeHtml(String(getConfigValue('automation.heartbeat.disk_threshold_mb', 100)))}" class="bg-zinc-950 text-zinc-50 border border-zinc-800 rounded-md px-2 py-1.5 text-sm focus:border-blue-500 outline-none" />
|
<input id="svc-heartbeat-disk-threshold" type="number" min="10" value="${escapeHtml(String(getConfigValue('automation.heartbeat.disk_threshold_mb', 100)))}" class="bg-zinc-950 text-zinc-50 border border-zinc-800 rounded-md px-2 py-1.5 text-sm focus:border-blue-500 outline-none" title="Alert when free disk falls below this value." />
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-2">
|
<div class="mt-2">
|
||||||
@@ -1470,8 +1468,8 @@ function renderServiceConfigModal() {
|
|||||||
const selected = Array.isArray(getConfigValue('automation.heartbeat.checks', HEARTBEAT_CHECK_KEYS))
|
const selected = Array.isArray(getConfigValue('automation.heartbeat.checks', HEARTBEAT_CHECK_KEYS))
|
||||||
&& getConfigValue('automation.heartbeat.checks', HEARTBEAT_CHECK_KEYS).includes(check);
|
&& getConfigValue('automation.heartbeat.checks', HEARTBEAT_CHECK_KEYS).includes(check);
|
||||||
return `
|
return `
|
||||||
<label class="flex items-center gap-2 text-xs text-zinc-300">
|
<label class="flex items-center gap-2 text-xs text-zinc-300" title="Enable or disable the ${escapeHtml(check)} heartbeat check.">
|
||||||
<input type="checkbox" data-heartbeat-check="${check}" ${selected ? 'checked' : ''} />
|
<input type="checkbox" data-heartbeat-check="${check}" ${selected ? 'checked' : ''} title="Toggle ${escapeHtml(check)} check." />
|
||||||
<span>${escapeHtml(check)}</span>
|
<span>${escapeHtml(check)}</span>
|
||||||
</label>
|
</label>
|
||||||
`;
|
`;
|
||||||
@@ -1501,8 +1499,8 @@ function renderServiceConfigModal() {
|
|||||||
<div class="mb-3 p-3 border border-zinc-800 rounded bg-zinc-950/60">
|
<div class="mb-3 p-3 border border-zinc-800 rounded bg-zinc-950/60">
|
||||||
<div class="text-xs uppercase text-zinc-500 mb-2">Quick Settings</div>
|
<div class="text-xs uppercase text-zinc-500 mb-2">Quick Settings</div>
|
||||||
${hasQuickToggle ? `
|
${hasQuickToggle ? `
|
||||||
<label class="flex items-center gap-2 mb-2">
|
<label class="flex items-center gap-2 mb-2" title="Master on/off for this service (when available).">
|
||||||
<input id="svc-quick-enabled" type="checkbox" ${quickToggleValue ? 'checked' : ''} />
|
<input id="svc-quick-enabled" type="checkbox" ${quickToggleValue ? 'checked' : ''} title="Enable or disable this service." />
|
||||||
<span class="text-sm text-zinc-200">Enabled</span>
|
<span class="text-sm text-zinc-200">Enabled</span>
|
||||||
</label>
|
</label>
|
||||||
` : '<div class="text-xs text-zinc-500 mb-2">No quick toggle available for this service.</div>'}
|
` : '<div class="text-xs text-zinc-500 mb-2">No quick toggle available for this service.</div>'}
|
||||||
@@ -1510,7 +1508,7 @@ function renderServiceConfigModal() {
|
|||||||
</div>
|
</div>
|
||||||
<div class="mb-3 p-3 border border-zinc-800 rounded bg-zinc-950/60">
|
<div class="mb-3 p-3 border border-zinc-800 rounded bg-zinc-950/60">
|
||||||
<div class="text-xs uppercase text-zinc-500 mb-2">Advanced Patch (optional JSON)</div>
|
<div class="text-xs uppercase text-zinc-500 mb-2">Advanced Patch (optional JSON)</div>
|
||||||
<textarea id="svc-advanced-patch" rows="5" class="w-full bg-zinc-950 text-zinc-50 border border-zinc-800 rounded-md px-2 py-1.5 text-sm font-mono focus:border-blue-500 outline-none" placeholder='{"automation.heartbeat.enabled": true}'>${escapeHtml(_serviceConfigState.advancedPatch ?? '')}</textarea>
|
<textarea id="svc-advanced-patch" rows="5" class="w-full bg-zinc-950 text-zinc-50 border border-zinc-800 rounded-md px-2 py-1.5 text-sm font-mono focus:border-blue-500 outline-none" placeholder='{"automation.heartbeat.enabled": true}' title="Optional JSON object of config path/value pairs to patch on save.">${escapeHtml(_serviceConfigState.advancedPatch ?? '')}</textarea>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-center justify-between gap-2">
|
<div class="flex items-center justify-between gap-2">
|
||||||
<div id="svc-config-status" class="text-xs ${toneClass}">${escapeHtml(_serviceConfigState.status ?? '')}</div>
|
<div id="svc-config-status" class="text-xs ${toneClass}">${escapeHtml(_serviceConfigState.status ?? '')}</div>
|
||||||
|
|||||||
@@ -179,8 +179,8 @@ export const SessionsPage = {
|
|||||||
el.innerHTML = `
|
el.innerHTML = `
|
||||||
<h1 class="text-2xl font-semibold text-zinc-50 mb-6">Sessions</h1>
|
<h1 class="text-2xl font-semibold text-zinc-50 mb-6">Sessions</h1>
|
||||||
<div class="flex items-center gap-3 mb-4 flex-wrap">
|
<div class="flex items-center gap-3 mb-4 flex-wrap">
|
||||||
<label class="text-sm text-zinc-400 flex items-center gap-1.5">Frontend
|
<label class="text-sm text-zinc-400 flex items-center gap-1.5" title="Filter sessions by source channel or UI frontend.">Frontend
|
||||||
<select id="sessions-frontend-filter" class="bg-zinc-900 text-zinc-50 border border-zinc-800 rounded-lg px-3 py-1.5 text-sm outline-none focus:border-blue-500">
|
<select id="sessions-frontend-filter" class="bg-zinc-900 text-zinc-50 border border-zinc-800 rounded-lg px-3 py-1.5 text-sm outline-none focus:border-blue-500" title="Show only sessions from a specific frontend.">
|
||||||
<option value="">All</option>
|
<option value="">All</option>
|
||||||
<option value="ws">ws</option>
|
<option value="ws">ws</option>
|
||||||
<option value="tui">tui</option>
|
<option value="tui">tui</option>
|
||||||
@@ -190,11 +190,11 @@ export const SessionsPage = {
|
|||||||
<option value="mattermost">mattermost</option>
|
<option value="mattermost">mattermost</option>
|
||||||
</select>
|
</select>
|
||||||
</label>
|
</label>
|
||||||
<label class="text-sm text-zinc-400 flex items-center gap-2 cursor-pointer">
|
<label class="text-sm text-zinc-400 flex items-center gap-2 cursor-pointer" title="Include persisted sessions that are no longer active.">
|
||||||
<input id="sessions-include-inactive" type="checkbox" checked />
|
<input id="sessions-include-inactive" type="checkbox" checked title="Toggle whether inactive/persisted sessions are listed." />
|
||||||
Include inactive/persisted
|
Include inactive/persisted
|
||||||
</label>
|
</label>
|
||||||
<button id="sessions-refresh-btn" class="px-3 py-1.5 text-sm font-medium rounded-md border border-zinc-700 bg-zinc-800 text-zinc-200 hover:bg-zinc-700 transition-colors">Refresh</button>
|
<button id="sessions-refresh-btn" class="px-3 py-1.5 text-sm font-medium rounded-md border border-zinc-700 bg-zinc-800 text-zinc-200 hover:bg-zinc-700 transition-colors" title="Reload the session list from the gateway.">Refresh</button>
|
||||||
</div>
|
</div>
|
||||||
<div id="sessions-list"></div>
|
<div id="sessions-list"></div>
|
||||||
<div id="session-detail"></div>
|
<div id="session-detail"></div>
|
||||||
|
|||||||
@@ -145,41 +145,41 @@ async function loadSettings() {
|
|||||||
<h2 class="text-lg font-semibold text-zinc-50 mb-4 mt-8 pb-2 border-b border-zinc-800">Personal Assistant Mode</h2>
|
<h2 class="text-lg font-semibold text-zinc-50 mb-4 mt-8 pb-2 border-b border-zinc-800">Personal Assistant Mode</h2>
|
||||||
<div class="mb-8">
|
<div class="mb-8">
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-3 mb-4">
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-3 mb-4">
|
||||||
<label class="flex items-center gap-2.5 bg-zinc-900 border border-zinc-800 rounded-lg px-3 py-2.5 text-sm text-zinc-400 cursor-pointer min-h-[44px]">
|
<label class="flex items-center gap-2.5 bg-zinc-900 border border-zinc-800 rounded-lg px-3 py-2.5 text-sm text-zinc-400 cursor-pointer min-h-[44px]" title="When enabled, automations send short announce-style updates before full messages.">
|
||||||
<input id="assist-delivery-announce" type="checkbox" ${deliveryMode === 'announce' ? 'checked' : ''} />
|
<input id="assist-delivery-announce" type="checkbox" ${deliveryMode === 'announce' ? 'checked' : ''} title="Toggle announce delivery mode for automations." />
|
||||||
<span>Automation announce delivery mode</span>
|
<span>Automation announce delivery mode</span>
|
||||||
</label>
|
</label>
|
||||||
<label class="flex items-center gap-2.5 bg-zinc-900 border border-zinc-800 rounded-lg px-3 py-2.5 text-sm text-zinc-400 cursor-pointer min-h-[44px]">
|
<label class="flex items-center gap-2.5 bg-zinc-900 border border-zinc-800 rounded-lg px-3 py-2.5 text-sm text-zinc-400 cursor-pointer min-h-[44px]" title="Turns on the scheduled daily briefing automation.">
|
||||||
<input id="assist-daily-briefing" type="checkbox" ${dailyBriefingEnabled ? 'checked' : ''} />
|
<input id="assist-daily-briefing" type="checkbox" ${dailyBriefingEnabled ? 'checked' : ''} title="Enable or disable the daily briefing job." />
|
||||||
<span>Daily briefing enabled</span>
|
<span>Daily briefing enabled</span>
|
||||||
</label>
|
</label>
|
||||||
<label class="flex items-center gap-2.5 bg-zinc-900 border border-zinc-800 rounded-lg px-3 py-2.5 text-sm text-zinc-400 cursor-pointer min-h-[44px]">
|
<label class="flex items-center gap-2.5 bg-zinc-900 border border-zinc-800 rounded-lg px-3 py-2.5 text-sm text-zinc-400 cursor-pointer min-h-[44px]" title="Writes a daily memory summary to help long-term recall.">
|
||||||
<input id="assist-memory-daily" type="checkbox" ${dailyMemoryEnabled ? 'checked' : ''} />
|
<input id="assist-memory-daily" type="checkbox" ${dailyMemoryEnabled ? 'checked' : ''} title="Enable daily memory log extraction." />
|
||||||
<span>Daily memory logging</span>
|
<span>Daily memory logging</span>
|
||||||
</label>
|
</label>
|
||||||
<label class="flex items-center gap-2.5 bg-zinc-900 border border-zinc-800 rounded-lg px-3 py-2.5 text-sm text-zinc-400 cursor-pointer min-h-[44px]">
|
<label class="flex items-center gap-2.5 bg-zinc-900 border border-zinc-800 rounded-lg px-3 py-2.5 text-sm text-zinc-400 cursor-pointer min-h-[44px]" title="Extracts memories automatically after tool-heavy activity.">
|
||||||
<input id="assist-memory-proactive" type="checkbox" ${proactiveExtractEnabled ? 'checked' : ''} />
|
<input id="assist-memory-proactive" type="checkbox" ${proactiveExtractEnabled ? 'checked' : ''} title="Enable proactive memory extraction." />
|
||||||
<span>Proactive memory extraction</span>
|
<span>Proactive memory extraction</span>
|
||||||
</label>
|
</label>
|
||||||
<label class="flex flex-col gap-2 bg-zinc-900 border border-zinc-800 rounded-lg px-3 py-2.5 text-sm text-zinc-400">
|
<label class="flex flex-col gap-2 bg-zinc-900 border border-zinc-800 rounded-lg px-3 py-2.5 text-sm text-zinc-400" title="Minimum number of tool calls before proactive extraction runs.">
|
||||||
<span>Proactive extract tool-call threshold</span>
|
<span>Proactive extract tool-call threshold</span>
|
||||||
<input id="assist-memory-min-tools" type="number" min="0" max="50" value="${Number.isFinite(proactiveMinToolCalls) ? proactiveMinToolCalls : 1}" class="w-full bg-zinc-950 text-zinc-50 border border-zinc-800 rounded-md px-3 py-2 text-sm focus:border-blue-500 outline-none" />
|
<input id="assist-memory-min-tools" type="number" min="0" max="50" value="${Number.isFinite(proactiveMinToolCalls) ? proactiveMinToolCalls : 1}" class="w-full bg-zinc-950 text-zinc-50 border border-zinc-800 rounded-md px-3 py-2 text-sm focus:border-blue-500 outline-none" title="Set a value from 0 to 50 tool calls." />
|
||||||
</label>
|
</label>
|
||||||
<label class="flex items-center gap-2.5 bg-zinc-900 border border-zinc-800 rounded-lg px-3 py-2.5 text-sm text-zinc-400 cursor-pointer min-h-[44px]">
|
<label class="flex items-center gap-2.5 bg-zinc-900 border border-zinc-800 rounded-lg px-3 py-2.5 text-sm text-zinc-400 cursor-pointer min-h-[44px]" title="Allows the assistant to send text-to-speech voice replies.">
|
||||||
<input id="assist-tts-enabled" type="checkbox" ${ttsEnabled ? 'checked' : ''} />
|
<input id="assist-tts-enabled" type="checkbox" ${ttsEnabled ? 'checked' : ''} title="Enable voice replies through TTS." />
|
||||||
<span>TTS voice replies enabled</span>
|
<span>TTS voice replies enabled</span>
|
||||||
</label>
|
</label>
|
||||||
<label class="flex flex-col gap-2 bg-zinc-900 border border-zinc-800 rounded-lg px-3 py-2.5 text-sm text-zinc-400">
|
<label class="flex flex-col gap-2 bg-zinc-900 border border-zinc-800 rounded-lg px-3 py-2.5 text-sm text-zinc-400" title="Optional channel allowlist for TTS. Leave blank to allow all channels.">
|
||||||
<span>TTS channels (comma-separated, blank = all)</span>
|
<span>TTS channels (comma-separated, blank = all)</span>
|
||||||
<input id="assist-tts-channels" type="text" value="${escapeHtml(ttsChannelText)}" placeholder="telegram,discord,whatsapp" class="w-full bg-zinc-950 text-zinc-50 border border-zinc-800 rounded-md px-3 py-2 text-sm focus:border-blue-500 outline-none" />
|
<input id="assist-tts-channels" type="text" value="${escapeHtml(ttsChannelText)}" placeholder="telegram,discord,whatsapp" class="w-full bg-zinc-950 text-zinc-50 border border-zinc-800 rounded-md px-3 py-2 text-sm focus:border-blue-500 outline-none" title="Example: telegram,discord,whatsapp" />
|
||||||
</label>
|
</label>
|
||||||
<label class="flex flex-col gap-2 bg-zinc-900 border border-zinc-800 rounded-lg px-3 py-2.5 text-sm text-zinc-400">
|
<label class="flex flex-col gap-2 bg-zinc-900 border border-zinc-800 rounded-lg px-3 py-2.5 text-sm text-zinc-400" title="Channel used for daily briefing delivery, such as telegram or slack.">
|
||||||
<span>Briefing output channel</span>
|
<span>Briefing output channel</span>
|
||||||
<input id="assist-briefing-channel" type="text" value="${escapeHtml(briefingOutputChannel)}" placeholder="telegram" class="w-full bg-zinc-950 text-zinc-50 border border-zinc-800 rounded-md px-3 py-2 text-sm focus:border-blue-500 outline-none" />
|
<input id="assist-briefing-channel" type="text" value="${escapeHtml(briefingOutputChannel)}" placeholder="telegram" class="w-full bg-zinc-950 text-zinc-50 border border-zinc-800 rounded-md px-3 py-2 text-sm focus:border-blue-500 outline-none" title="Set the channel adapter name for briefings." />
|
||||||
</label>
|
</label>
|
||||||
<label class="flex flex-col gap-2 bg-zinc-900 border border-zinc-800 rounded-lg px-3 py-2.5 text-sm text-zinc-400">
|
<label class="flex flex-col gap-2 bg-zinc-900 border border-zinc-800 rounded-lg px-3 py-2.5 text-sm text-zinc-400" title="Destination peer/chat identifier used by the selected channel.">
|
||||||
<span>Briefing output peer/chat id</span>
|
<span>Briefing output peer/chat id</span>
|
||||||
<input id="assist-briefing-peer" type="text" value="${escapeHtml(briefingOutputPeer)}" placeholder="123456789" class="w-full bg-zinc-950 text-zinc-50 border border-zinc-800 rounded-md px-3 py-2 text-sm focus:border-blue-500 outline-none" />
|
<input id="assist-briefing-peer" type="text" value="${escapeHtml(briefingOutputPeer)}" placeholder="123456789" class="w-full bg-zinc-950 text-zinc-50 border border-zinc-800 rounded-md px-3 py-2 text-sm focus:border-blue-500 outline-none" title="Use the chat ID, channel ID, or user ID for your adapter." />
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-center gap-3 mt-2">
|
<div class="flex items-center gap-3 mt-2">
|
||||||
@@ -202,16 +202,16 @@ async function loadSettings() {
|
|||||||
<div class="mb-8">
|
<div class="mb-8">
|
||||||
<div class="flex flex-col gap-3">
|
<div class="flex flex-col gap-3">
|
||||||
<div class="bg-zinc-900 border border-zinc-800 rounded-lg p-3">
|
<div class="bg-zinc-900 border border-zinc-800 rounded-lg p-3">
|
||||||
<label class="block text-xs font-medium text-zinc-400 uppercase tracking-wide mb-2">Confirm (require approval)</label>
|
<label class="block text-xs font-medium text-zinc-400 uppercase tracking-wide mb-2" title="One glob pattern per line. Matching tools require explicit approval.">Confirm (require approval)</label>
|
||||||
<textarea id="hooks-confirm" rows="3" class="w-full bg-zinc-950 text-zinc-50 border border-zinc-800 rounded-md px-3 py-2 text-sm font-mono focus:border-blue-500 outline-none resize-y min-h-[60px]">${escapeHtml(confirmPatterns.join('\n'))}</textarea>
|
<textarea id="hooks-confirm" rows="3" class="w-full bg-zinc-950 text-zinc-50 border border-zinc-800 rounded-md px-3 py-2 text-sm font-mono focus:border-blue-500 outline-none resize-y min-h-[60px]" title="Example: tool:group:fs/**/*">${escapeHtml(confirmPatterns.join('\n'))}</textarea>
|
||||||
</div>
|
</div>
|
||||||
<div class="bg-zinc-900 border border-zinc-800 rounded-lg p-3">
|
<div class="bg-zinc-900 border border-zinc-800 rounded-lg p-3">
|
||||||
<label class="block text-xs font-medium text-zinc-400 uppercase tracking-wide mb-2">Log (allow + log)</label>
|
<label class="block text-xs font-medium text-zinc-400 uppercase tracking-wide mb-2" title="Matching tools run without approval, but each call is logged.">Log (allow + log)</label>
|
||||||
<textarea id="hooks-log" rows="3" class="w-full bg-zinc-950 text-zinc-50 border border-zinc-800 rounded-md px-3 py-2 text-sm font-mono focus:border-blue-500 outline-none resize-y min-h-[60px]">${escapeHtml(logPatterns.join('\n'))}</textarea>
|
<textarea id="hooks-log" rows="3" class="w-full bg-zinc-950 text-zinc-50 border border-zinc-800 rounded-md px-3 py-2 text-sm font-mono focus:border-blue-500 outline-none resize-y min-h-[60px]" title="Use one glob pattern per line.">${escapeHtml(logPatterns.join('\n'))}</textarea>
|
||||||
</div>
|
</div>
|
||||||
<div class="bg-zinc-900 border border-zinc-800 rounded-lg p-3">
|
<div class="bg-zinc-900 border border-zinc-800 rounded-lg p-3">
|
||||||
<label class="block text-xs font-medium text-zinc-400 uppercase tracking-wide mb-2">Silent (allow silently)</label>
|
<label class="block text-xs font-medium text-zinc-400 uppercase tracking-wide mb-2" title="Matching tools run with no prompt and no audit log entry.">Silent (allow silently)</label>
|
||||||
<textarea id="hooks-silent" rows="3" class="w-full bg-zinc-950 text-zinc-50 border border-zinc-800 rounded-md px-3 py-2 text-sm font-mono focus:border-blue-500 outline-none resize-y min-h-[60px]">${escapeHtml(silentPatterns.join('\n'))}</textarea>
|
<textarea id="hooks-silent" rows="3" class="w-full bg-zinc-950 text-zinc-50 border border-zinc-800 rounded-md px-3 py-2 text-sm font-mono focus:border-blue-500 outline-none resize-y min-h-[60px]" title="Use carefully. One glob pattern per line.">${escapeHtml(silentPatterns.join('\n'))}</textarea>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-center gap-3 mt-2">
|
<div class="flex items-center gap-3 mt-2">
|
||||||
<button id="hooks-save" class="px-4 py-2 text-sm font-medium rounded-md bg-blue-500 text-zinc-950 hover:opacity-85 transition-opacity">Save Hook Patterns</button>
|
<button id="hooks-save" class="px-4 py-2 text-sm font-medium rounded-md bg-blue-500 text-zinc-950 hover:opacity-85 transition-opacity">Save Hook Patterns</button>
|
||||||
|
|||||||
Reference in New Issue
Block a user