Chats hooks
React hooks for Aeontel chats.
Hooks
useChat sse
Chat with any chattable entity. Pass the entity's prefixed id —
agt_… for agents or swm_… for swarms. The API infers the entity
type from the prefix.
Thin wrapper around AI SDK's useChat — wires the Aeontel transport,
otherwise the API is identical to AI SDK's. Returns the AI SDK
useChat shape (messages, sendMessage, status, …) plus
isStreaming / isReady derivations. Manage your own input state
with useState("") — matches AI SDK v6 conventions.
AI SDK v6 message shape — two field-name traps:
-
sendMessage({ text })— NOTsendMessage({ content }). The AI SDK auto-wrapstextinto aparts: [{ type: "text", text }]array internally. Passingcontent(the OpenAI / Anthropic convention) bypasses that wrap, the request reaches the server withparts: undefined, and Zod validation 500s with"expected array, received undefined" at path [0, "parts"]. -
Rendering an incoming message — read
msg.parts, NOTmsg.content. AI SDK v6 messages have apartsarray (mixed text/function-call/function-result segments).contentdoes not exist on the message shape.TSXmsg.parts .filter((p) => p.type === "text") .map((p) => p.text) .join("");
Both traps share the same root cause: content is the standard field
name across OpenAI / Anthropic / older AI SDK versions, so the
intuitive shape is wrong. The error surfaces only at runtime; TS
accepts the wrong shape because the input/output types are broad.
useChat(id: ChatTargetId, options: UseChatOptions_ = {})const { messages, sendMessage, isStreaming } = useChat("agt_...");
const [input, setInput] = useState("");
<input
value={input}
onChange={(e) => setInput(e.target.value)}
onKeyDown={(e) => {
if (e.key === "Enter" && !isStreaming && input.trim()) {
sendMessage({ text: input }); // ✓ text — NOT content
setInput("");
}
}}
/>
// NOT m.content — that field doesn't exist on AI SDK v6 messages.
{messages.map((m) => (
<div key={m.id}>
{m.parts.filter((p) => p.type === "text").map((p) => p.text)}
</div>
))}useKickoffChat composite
Programmatic chat kickoff. Opens a thread between an agent and a
user, optionally seeded with a pre-baked opening message authored
by the agent. Wraps client.chats.kickoff and invalidates the
threads list cache on success so any open chat sidebar pops the
new thread immediately.
useKickoffChat(options?: MutationOpts<KickoffChatResponse, KickoffChatParams>)Types: KickoffChatResponse · KickoffChatParams
const kickoff = useKickoffChat();
kickoff.mutate({
workspaceId: "wsp_…",
agentId: "agt_…",
userId: "usr_…",
message: "Hi, I noticed your last invoice is due — want help?",
});