Quick prompt
One component, one message in, one message out. No store, no subscriptions, no acks. Useful for slash commands, inline assistants, or any "click button → ask LLM → render" interaction where the response is short enough that streaming is overkill.
This is the smallest sketch that still tells the truth: the manager
is a module level constant, lifecycle is one
useEffect, and the entire wire surface is
one useSocketEvent +
useSocketSend. Both ends are checked
against your protocol types — a wrong type
literal or a missing field will not compile, and the handler's
msg is narrowed to the matching variant
with no cast.
Live demo
Quick prompt
idleAsk the assistant something. The reply lands as a single message (no streaming, no tracking).
You are offline. Prompts you send now will be marked as not sent.
Source
import { useEffect, useState } from "react";
import {
useSocketEvent,
useSocketSend,
WebSocketManager,
} from "@luciodale/react-socket";
type TClientMsg = { type: "quick-ask"; id: string; prompt: string };
type TServerMsg = { type: "chat"; id: string; sender: string; text: string };
const manager = new WebSocketManager<TClientMsg, TServerMsg>({
url: "ws://localhost:3001/ws",
serialize: (msg) => JSON.stringify(msg),
deserialize: (raw) => JSON.parse(raw),
});
function QuickPrompt() {
const [input, setInput] = useState("");
const [replies, setReplies] = useState<{ id: string; text: string }[]>([]);
useEffect(() => {
manager.connect();
return () => manager.disconnect();
}, []);
// msg is narrowed to the "chat" variant — msg.text is typed, no cast
useSocketEvent(manager, "chat", (msg) => {
setReplies((prev) => [...prev, { id: msg.id, text: msg.text }]);
});
const { send } = useSocketSend(manager);
function ask() {
if (!input.trim()) return;
send({ type: "quick-ask", id: crypto.randomUUID(), prompt: input.trim() });
setInput("");
}
// ...render
}Move up to AI Conversation when you need streaming tokens, presets, or artifacts.