fix(webchat): route slash commands through agent command fast-path
This commit is contained in:
+12
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"version": "1.0",
|
"version": "1.0",
|
||||||
"updated_at": "2026-02-18",
|
"updated_at": "2026-02-19",
|
||||||
"description": "Tracks the status of all Flynn plans and implementation phases",
|
"description": "Tracks the status of all Flynn plans and implementation phases",
|
||||||
"plans": {
|
"plans": {
|
||||||
"makefile-skills-convenience-targets": {
|
"makefile-skills-convenience-targets": {
|
||||||
@@ -5548,6 +5548,17 @@
|
|||||||
"docs/plans/state.json"
|
"docs/plans/state.json"
|
||||||
],
|
],
|
||||||
"test_status": "pnpm test:run src/channels/telegram/adapter.test.ts src/config/schema.test.ts src/gateway/handlers/services.test.ts src/cli/doctor.test.ts + pnpm typecheck passing"
|
"test_status": "pnpm test:run src/channels/telegram/adapter.test.ts src/config/schema.test.ts src/gateway/handlers/services.test.ts src/cli/doctor.test.ts + pnpm typecheck passing"
|
||||||
|
},
|
||||||
|
"webchat-slash-command-agent-fastpath-fix": {
|
||||||
|
"status": "completed",
|
||||||
|
"date": "2026-02-19",
|
||||||
|
"updated": "2026-02-19",
|
||||||
|
"summary": "Fixed WebChat slash command reliability by routing /reset, /compact, /usage, /status, and /model through agent.send command metadata fast-path instead of mixed local RPC shortcuts. This resolves /model returning unknown and keeps command behavior aligned with backend command registry.",
|
||||||
|
"files_modified": [
|
||||||
|
"src/gateway/ui/pages/chat.js",
|
||||||
|
"docs/plans/state.json"
|
||||||
|
],
|
||||||
|
"test_status": "pnpm typecheck + pnpm test:run src/commands/registry.test.ts src/commands/builtin/index.test.ts passing"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"overall_progress": {
|
"overall_progress": {
|
||||||
|
|||||||
@@ -368,6 +368,20 @@ function showSystemMessage(content) {
|
|||||||
scrollToBottom();
|
scrollToBottom();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function executeAgentSlashCommand(client, command, commandArgs = '') {
|
||||||
|
const normalizedArgs = (commandArgs ?? '').trim();
|
||||||
|
const message = normalizedArgs ? `/${command} ${normalizedArgs}` : `/${command}`;
|
||||||
|
const metadata = {
|
||||||
|
isCommand: true,
|
||||||
|
command,
|
||||||
|
...(normalizedArgs ? { commandArgs: normalizedArgs } : {}),
|
||||||
|
};
|
||||||
|
|
||||||
|
const stream = client.stream('agent.send', { message, metadata });
|
||||||
|
const done = await stream.result;
|
||||||
|
return done?.content ?? done?.text ?? '';
|
||||||
|
}
|
||||||
|
|
||||||
async function handleSlashCommand(cmd, client) {
|
async function handleSlashCommand(cmd, client) {
|
||||||
switch (cmd.type) {
|
switch (cmd.type) {
|
||||||
case 'help': {
|
case 'help': {
|
||||||
@@ -381,7 +395,7 @@ async function handleSlashCommand(cmd, client) {
|
|||||||
'| `/compact` | Ask the agent to compact context |',
|
'| `/compact` | Ask the agent to compact context |',
|
||||||
'| `/usage` | Show token usage stats |',
|
'| `/usage` | Show token usage stats |',
|
||||||
'| `/status` | Show system health |',
|
'| `/status` | Show system health |',
|
||||||
'| `/model` | Show current model info |',
|
'| `/model [tier|provider]` | Show or set model tier/provider |',
|
||||||
'',
|
'',
|
||||||
'Type `/` to see autocomplete suggestions.',
|
'Type `/` to see autocomplete suggestions.',
|
||||||
];
|
];
|
||||||
@@ -391,14 +405,9 @@ async function handleSlashCommand(cmd, client) {
|
|||||||
|
|
||||||
case 'reset': {
|
case 'reset': {
|
||||||
try {
|
try {
|
||||||
// Send reset command via metadata
|
const result = await executeAgentSlashCommand(client, 'reset');
|
||||||
const stream = client.stream('agent.send', {
|
|
||||||
message: '/reset',
|
|
||||||
metadata: { isCommand: true, command: 'reset' },
|
|
||||||
});
|
|
||||||
await stream.result;
|
|
||||||
_elements.messages.innerHTML = '';
|
_elements.messages.innerHTML = '';
|
||||||
showSystemMessage('Session reset.');
|
showSystemMessage(result || 'Session reset.');
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
showSystemMessage(`Failed to reset: ${err.message}`);
|
showSystemMessage(`Failed to reset: ${err.message}`);
|
||||||
}
|
}
|
||||||
@@ -406,33 +415,19 @@ async function handleSlashCommand(cmd, client) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case 'compact': {
|
case 'compact': {
|
||||||
// Send as a regular message — the agent will interpret the request
|
try {
|
||||||
showSystemMessage('Requesting context compaction...');
|
const result = await executeAgentSlashCommand(client, 'compact');
|
||||||
return false; // Let it pass through as a normal message
|
showSystemMessage(result || 'Compaction requested.');
|
||||||
|
} catch (err) {
|
||||||
|
showSystemMessage(`Failed to compact: ${err.message}`);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'usage': {
|
case 'usage': {
|
||||||
try {
|
try {
|
||||||
const result = await client.call('system.tokenUsage');
|
const result = await executeAgentSlashCommand(client, 'usage');
|
||||||
const sessions = result.sessions ?? [];
|
showSystemMessage(result || 'No usage data available.');
|
||||||
if (sessions.length === 0) {
|
|
||||||
showSystemMessage('No usage data available.');
|
|
||||||
} else {
|
|
||||||
const lines = ['**Token Usage**', ''];
|
|
||||||
let totalIn = 0, totalOut = 0, totalCalls = 0;
|
|
||||||
for (const s of sessions) {
|
|
||||||
totalIn += s.total?.inputTokens ?? 0;
|
|
||||||
totalOut += s.total?.outputTokens ?? 0;
|
|
||||||
totalCalls += s.total?.calls ?? 0;
|
|
||||||
}
|
|
||||||
lines.push(`**Input:** ${totalIn.toLocaleString()} tokens`);
|
|
||||||
lines.push(`**Output:** ${totalOut.toLocaleString()} tokens`);
|
|
||||||
lines.push(`**API Calls:** ${totalCalls}`);
|
|
||||||
if (sessions.length > 1) {
|
|
||||||
lines.push(`**Sessions:** ${sessions.length}`);
|
|
||||||
}
|
|
||||||
showSystemMessage(lines.join('\n'));
|
|
||||||
}
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
showSystemMessage(`Failed to fetch usage: ${err.message}`);
|
showSystemMessage(`Failed to fetch usage: ${err.message}`);
|
||||||
}
|
}
|
||||||
@@ -441,24 +436,8 @@ async function handleSlashCommand(cmd, client) {
|
|||||||
|
|
||||||
case 'status': {
|
case 'status': {
|
||||||
try {
|
try {
|
||||||
const result = await client.call('system.health');
|
const result = await executeAgentSlashCommand(client, 'status');
|
||||||
const lines = [
|
showSystemMessage(result || 'Status unavailable.');
|
||||||
'**System Status**',
|
|
||||||
'',
|
|
||||||
`**Uptime:** ${result.uptime ?? 'unknown'}`,
|
|
||||||
`**Status:** ${result.status ?? 'unknown'}`,
|
|
||||||
];
|
|
||||||
if (result.channels) {
|
|
||||||
lines.push('', '**Channels:**');
|
|
||||||
for (const ch of result.channels) {
|
|
||||||
const dot = ch.status === 'connected' ? '\\*' : '-';
|
|
||||||
lines.push(` ${dot} ${ch.name}: ${ch.status}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (result.model) {
|
|
||||||
lines.push('', `**Model:** ${result.model}`);
|
|
||||||
}
|
|
||||||
showSystemMessage(lines.join('\n'));
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
showSystemMessage(`Failed to fetch status: ${err.message}`);
|
showSystemMessage(`Failed to fetch status: ${err.message}`);
|
||||||
}
|
}
|
||||||
@@ -467,9 +446,8 @@ async function handleSlashCommand(cmd, client) {
|
|||||||
|
|
||||||
case 'model': {
|
case 'model': {
|
||||||
try {
|
try {
|
||||||
const result = await client.call('system.health');
|
const result = await executeAgentSlashCommand(client, 'model', cmd.args ?? '');
|
||||||
const model = result.model ?? result.config?.model ?? 'unknown';
|
showSystemMessage(result || 'Model info unavailable.');
|
||||||
showSystemMessage(`**Current Model:** ${model}`);
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
showSystemMessage(`Failed to fetch model info: ${err.message}`);
|
showSystemMessage(`Failed to fetch model info: ${err.message}`);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user