feat(web): add orchestrator command system in chat interface (#521)
All checks were successful
ci/woodpecker/push/web Pipeline was successful

Co-authored-by: Jason Woltje <jason@diversecanvas.com>
Co-committed-by: Jason Woltje <jason@diversecanvas.com>
This commit was merged in pull request #521.
This commit is contained in:
2026-02-26 03:39:00 +00:00
committed by jason.woltje
parent 859dcfc4b7
commit b110c469c4
6 changed files with 1119 additions and 8 deletions

View File

@@ -3,6 +3,7 @@
import { useCallback, useEffect, useRef, useImperativeHandle, forwardRef, useState } from "react";
import { useAuth } from "@/lib/auth/auth-context";
import { useChat } from "@/hooks/useChat";
import { useOrchestratorCommands } from "@/hooks/useOrchestratorCommands";
import { useWebSocket } from "@/hooks/useWebSocket";
import { MessageList } from "./MessageList";
import { ChatInput, type ModelId, DEFAULT_TEMPERATURE, DEFAULT_MAX_TOKENS } from "./ChatInput";
@@ -79,6 +80,7 @@ export const Chat = forwardRef<ChatRef, ChatProps>(function Chat(
abortStream,
loadConversation,
startNewConversation,
setMessages,
clearError,
} = useChat({
model: selectedModel,
@@ -89,6 +91,8 @@ export const Chat = forwardRef<ChatRef, ChatProps>(function Chat(
const { isConnected: isWsConnected } = useWebSocket(user?.id ?? "", "", {});
const { isCommand, executeCommand } = useOrchestratorCommands();
const messagesEndRef = useRef<HTMLDivElement>(null);
const inputRef = useRef<HTMLTextAreaElement>(null);
const [loadingQuip, setLoadingQuip] = useState<string | null>(null);
@@ -192,9 +196,27 @@ export const Chat = forwardRef<ChatRef, ChatProps>(function Chat(
const handleSendMessage = useCallback(
async (content: string) => {
if (isCommand(content)) {
// Add user message immediately
const userMessage: Message = {
id: `user-${Date.now().toString()}-${Math.random().toString(36).slice(2, 8)}`,
role: "user",
content: content.trim(),
createdAt: new Date().toISOString(),
};
setMessages((prev) => [...prev, userMessage]);
// Execute orchestrator command
const result = await executeCommand(content);
if (result) {
setMessages((prev) => [...prev, result]);
}
return;
}
await sendMessage(content);
},
[sendMessage]
[isCommand, executeCommand, setMessages, sendMessage]
);
const handleSuggestionClick = useCallback((prompt: string): void => {