feat(dashboard): add model tier default controls and document cancel path
This commit is contained in:
@@ -698,6 +698,9 @@ When queue policy rejects/supersedes a request before execution, the server emit
|
||||
|
||||
Cancel the current agent operation.
|
||||
|
||||
Used by the web dashboard/chat stop button and channel-level `/stop` / `/cancel` command fast-paths.
|
||||
Cancellation is best-effort and stops at the next agent/tool-loop safe point.
|
||||
|
||||
### Node Methods
|
||||
|
||||
#### `node.register`
|
||||
|
||||
@@ -5807,5 +5807,29 @@
|
||||
"src/backends/native/agent.ts"
|
||||
],
|
||||
"test_status": "4/4 passing"
|
||||
},
|
||||
"dashboard-model-defaults-and-stop-controls": {
|
||||
"date": "2026-02-19",
|
||||
"summary": "Added dashboard controls for persistent model tier defaults (`agents.primary_tier`, `agents.delegation.*`) and background provider/model overrides with fallback tier (`agents.background_models.*`). Added command-registry `/stop` (alias `/cancel`), wired channel/gateway cancellation services, implemented web chat send-button stop state + `agent.cancel` wiring, and added Telegram `/stop` + `/cancel` command forwarding.",
|
||||
"files_modified": [
|
||||
"src/config/schema.ts",
|
||||
"src/gateway/handlers/config.ts",
|
||||
"src/backends/native/orchestrator.ts",
|
||||
"src/context/compaction.ts",
|
||||
"src/daemon/routing.ts",
|
||||
"src/gateway/session-bridge.ts",
|
||||
"src/commands/types.ts",
|
||||
"src/commands/builtin/index.ts",
|
||||
"src/commands/index.ts",
|
||||
"src/gateway/handlers/agent.ts",
|
||||
"src/gateway/ui/pages/chat.js",
|
||||
"src/gateway/ui/pages/dashboard.js",
|
||||
"src/channels/telegram/adapter.ts",
|
||||
"src/channels/telegram/adapter.test.ts",
|
||||
"src/commands/builtin/index.test.ts",
|
||||
"src/gateway/handlers/agent.test.ts",
|
||||
"docs/api/PROTOCOL.md"
|
||||
],
|
||||
"test_status": "pnpm test:run src/commands/builtin/index.test.ts src/channels/telegram/adapter.test.ts src/gateway/handlers/agent.test.ts src/gateway/session-bridge.test.ts src/daemon/routing.test.ts src/config/schema.test.ts src/gateway/handlers/handlers.test.ts + pnpm typecheck passing"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -692,6 +692,9 @@ function updateAssistantHealth(configData) {
|
||||
: 'not configured';
|
||||
const briefingReady = dailyBriefing && Boolean(briefingOutput?.channel && briefingOutput?.peer);
|
||||
const playbookLikeReady = announce || (memoryDaily && memoryProactive);
|
||||
const modelTier = configData?.agents?.primary_tier ?? 'default';
|
||||
const delegation = configData?.agents?.delegation ?? {};
|
||||
const backgroundModels = configData?.agents?.background_models ?? {};
|
||||
const checklistRows = [
|
||||
{ label: 'Set briefing output channel + peer', done: Boolean(briefingOutput?.channel && briefingOutput?.peer) },
|
||||
{ label: 'Enable assistant behavior profile', done: playbookLikeReady },
|
||||
@@ -704,6 +707,16 @@ function updateAssistantHealth(configData) {
|
||||
<span class="font-bold ${value ? 'text-green-500' : 'text-zinc-500'}">${value ? 'ON' : 'OFF'}</span>
|
||||
</div>
|
||||
`;
|
||||
const tierOption = (selected) => ['fast', 'default', 'complex', 'local']
|
||||
.map((tier) => `<option value="${tier}" ${selected === tier ? 'selected' : ''}>${tier}</option>`)
|
||||
.join('');
|
||||
const taskRows = [
|
||||
{ key: 'compaction', label: 'Compaction' },
|
||||
{ key: 'memory_extraction', label: 'Memory extraction' },
|
||||
{ key: 'classification', label: 'Classification' },
|
||||
{ key: 'tool_summarisation', label: 'Tool summarisation' },
|
||||
{ key: 'complex_reasoning', label: 'Complex reasoning' },
|
||||
];
|
||||
|
||||
el.innerHTML = `
|
||||
<div class="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-6 gap-2 mb-4">
|
||||
@@ -752,6 +765,60 @@ function updateAssistantHealth(configData) {
|
||||
</div>
|
||||
<div class="text-sm text-zinc-500">Executive: announce + voice + aggressive interrupt. Operator: announce + memory-first + steer backlog. Focus: reactive, quieter mode.</div>
|
||||
</div>
|
||||
<div class="mt-4 p-4 border border-zinc-800 rounded-lg bg-zinc-900">
|
||||
<div class="text-sm font-semibold text-zinc-50 mb-3">Model Tier Defaults</div>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-3 mb-4">
|
||||
<label class="flex flex-col gap-1.5">
|
||||
<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">
|
||||
${tierOption(modelTier)}
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
<div class="text-sm text-zinc-400 mb-2">Delegation tiers + background model overrides</div>
|
||||
<div class="space-y-3">
|
||||
${taskRows.map((task) => {
|
||||
const background = backgroundModels?.[task.key] ?? {};
|
||||
const delegationTier = delegation?.[task.key] ?? 'fast';
|
||||
return `
|
||||
<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="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-5 gap-2">
|
||||
<label class="flex flex-col gap-1">
|
||||
<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">
|
||||
${tierOption(delegationTier)}
|
||||
</select>
|
||||
</label>
|
||||
<label class="flex items-center gap-2 mt-5 md:mt-0">
|
||||
<input id="assist-bg-${task.key}-enabled" type="checkbox" ${background?.enabled === false ? '' : 'checked'} />
|
||||
<span class="text-xs text-zinc-400">Enable provider/model override</span>
|
||||
</label>
|
||||
<label class="flex flex-col gap-1">
|
||||
<span class="text-xs text-zinc-500">Provider</span>
|
||||
<input id="assist-bg-${task.key}-provider" type="text" value="${escapeHtml(background?.provider ?? '')}" placeholder="openai" 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" />
|
||||
</label>
|
||||
<label class="flex flex-col gap-1">
|
||||
<span class="text-xs text-zinc-500">Model</span>
|
||||
<input id="assist-bg-${task.key}-model" type="text" value="${escapeHtml(background?.model ?? '')}" placeholder="gpt-4o-mini" 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" />
|
||||
</label>
|
||||
<label class="flex flex-col gap-1">
|
||||
<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">
|
||||
${tierOption(background?.fallback_tier ?? 'fast')}
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}).join('')}
|
||||
</div>
|
||||
<div class="flex flex-wrap gap-2 mt-3">
|
||||
<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="save-model-defaults">
|
||||
Save Model Defaults
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-4 p-4 border border-zinc-800 rounded-lg bg-zinc-900">
|
||||
<div class="text-sm font-semibold text-zinc-50 mb-3">Assistant Activation Checklist</div>
|
||||
<div class="space-y-1 mb-4">
|
||||
@@ -856,6 +923,28 @@ function updateAssistantHealth(configData) {
|
||||
'automation.daily_briefing.enabled': true,
|
||||
};
|
||||
_assistantManualOverrides.add('automation.daily_briefing.enabled');
|
||||
} else if (action === 'save-model-defaults') {
|
||||
const tasks = ['compaction', 'memory_extraction', 'classification', 'tool_summarisation', 'complex_reasoning'];
|
||||
patches = {
|
||||
'agents.primary_tier': (el.querySelector('#assist-primary-tier')?.value ?? 'default'),
|
||||
};
|
||||
for (const task of tasks) {
|
||||
const delegationTier = el.querySelector(`#assist-delegation-${task}`)?.value ?? 'fast';
|
||||
const enabled = Boolean(el.querySelector(`#assist-bg-${task}-enabled`)?.checked);
|
||||
const provider = (el.querySelector(`#assist-bg-${task}-provider`)?.value ?? '').trim();
|
||||
const model = (el.querySelector(`#assist-bg-${task}-model`)?.value ?? '').trim();
|
||||
const fallbackTier = el.querySelector(`#assist-bg-${task}-fallback`)?.value ?? 'fast';
|
||||
|
||||
patches[`agents.delegation.${task}`] = delegationTier;
|
||||
patches[`agents.background_models.${task}.enabled`] = enabled;
|
||||
if (provider) {
|
||||
patches[`agents.background_models.${task}.provider`] = provider;
|
||||
}
|
||||
if (model) {
|
||||
patches[`agents.background_models.${task}.model`] = model;
|
||||
}
|
||||
patches[`agents.background_models.${task}.fallback_tier`] = fallbackTier;
|
||||
}
|
||||
}
|
||||
if (!patches) {return;}
|
||||
await applyAssistantPatch(patches, statusEl);
|
||||
|
||||
Reference in New Issue
Block a user