feat(webchat): add slash commands, autocomplete popup, and web search button

Add 6 slash commands (/help, /reset, /compact, /usage, /status, /model)
with autocomplete popup (arrow keys, Enter/Tab/Escape navigation).
Search button toggles web search mode by prepending instruction to message.
Backend agent.send extended with metadata for server-side command routing.
This commit is contained in:
William Valentin
2026-02-10 20:45:14 -08:00
parent 7a69794418
commit 4c8ba3f20c
4 changed files with 554 additions and 18 deletions
+16 -2
View File
@@ -15,8 +15,8 @@ export interface AgentHandlerDeps {
export function createAgentHandlers(deps: AgentHandlerDeps) {
return {
'agent.send': async (request: GatewayRequest, send: SendFn): Promise<OutboundMessage | void> => {
const params = request.params as { message?: string; connectionId?: string; attachments?: GatewayAttachment[] } | undefined;
if (!params?.message) {
const params = request.params as { message?: string; connectionId?: string; attachments?: GatewayAttachment[]; metadata?: { isCommand?: boolean; command?: string } } | undefined;
if (!params?.message && !params?.metadata?.isCommand) {
return makeError(request.id, ErrorCode.InvalidRequest, 'message is required');
}
@@ -43,6 +43,20 @@ export function createAgentHandlers(deps: AgentHandlerDeps) {
return deps.laneQueue.enqueue(laneId, async () => {
deps.sessionBridge.setBusy(connectionId, true);
// Handle slash commands via metadata (mirrors daemon/routing.ts pattern)
if (params.metadata?.isCommand) {
try {
if (params.metadata.command === 'reset') {
agent.reset();
send(makeEvent(request.id, 'done', { content: 'Session reset.' }));
return;
}
} finally {
deps.sessionBridge.setBusy(connectionId, false);
deps.metrics?.endRequest(requestId);
}
}
// Set up tool use callback to emit streaming events
deps.sessionBridge.setOnToolUse(connectionId, (event) => {
if (event.type === 'start') {