Files
cobble/src/pages/admin/bots/[bot_id]/(hooks)/use-reply-catch-up.ts
T
tbenandClaude Opus 5.5 61098a114c Show a reply's steps, and catch up on a reply whose live push was missed
A reply that works through tools now shows its latest tool step under
"is thinking…" (not its closing note, which is the answer). While a reply
is due, the open conversation checks the session's latest messages every
few seconds (api/admin/bots/session-messages) and replays any it missed
as server:bot-message, so the thread, rail and unread all take it and the
thinking row can't stay up until a reload. MCP and custom tool steps read
in words ("Using Exa search (web search exa)").

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-19 16:28:53 +01:00

61 lines
2.1 KiB
TypeScript

import { useEffect, useRef } from "react";
import { AppData } from "@/src/data/app-data";
import type { BotMessageWithAttachments, WebSocketDataType } from "@/src/types";
import postSessionApi from "../(functions)/post-session-api";
type Params = {
session_id?: number | null;
/**
* The thread's last message is the user's, so a reply is due.
*/
awaiting_reply: boolean;
/**
* The thread's last message: only newer ones are replayed.
*/
last_message_id?: number | null;
};
/**
* While a reply is due, checks the session's latest messages every
* `AppData.BotReplyCatchUpMs`. Replies arrive live; this only catches one
* whose push was missed (the socket was down at the time), so the
* thinking row can't stay up until a reload. A missed message is replayed
* as the `server:bot-message` it would have been, so the thread, the rail
* and the unread flag all take it the usual way.
*/
export default function useReplyCatchUp({ session_id, awaiting_reply, last_message_id }: Params) {
const last_message = useRef(Number(last_message_id) || 0);
last_message.current = Number(last_message_id) || 0;
useEffect(() => {
if (!awaiting_reply || !session_id) return;
let stale = false;
const timer = setInterval(async () => {
const res = await postSessionApi<BotMessageWithAttachments>({
path: "session-messages",
body: { session_id },
}).catch(() => null);
if (stale || !res?.success || !Array.isArray(res.payload)) return;
const missed = (res.payload as BotMessageWithAttachments[]).filter(
(message) => Number(message.id) > last_message.current,
);
for (const message of missed) {
const data: WebSocketDataType = { event: "server:bot-message", data: message };
window.dispatchEvent(new CustomEvent("wsDataEvent", { detail: { data, message: data } }));
}
}, AppData.BotReplyCatchUpMs);
return () => {
stale = true;
clearInterval(timer);
};
}, [awaiting_reply, session_id]);
}