57c423cdb1
- ConversationView: an ended session (SessionDetail, SessionReplay pass `ended`) polls its transcript every 60 s instead of 3 s and stops rescanning sub-agents; new_event, reconnect and show still fetch at once. - Workspace: GET /api/run follows run-moving WS messages (lane run columns, session created/status change, runs_interrupted) with a 30 s fallback, instead of a blind 5 s poll. - StatusBar: session counts re-read only when a session's status/waiting/archived state changes (60 s fallback); costs re-read at most every 30 s while work is happening and every 2 min otherwise. - Dashboard recent activity: 60 s safety poll (was 10 s) plus remote import messages; WS still prepends new events. - New lib/sessionChange.ts matcher with tests.
33 lines
1.4 KiB
TypeScript
33 lines
1.4 KiB
TypeScript
/**
|
|
* @file sessionChange.ts
|
|
* @description `session_created` / `session_updated` matcher for live-refresh
|
|
* callers that care about only a few session columns. A session row is
|
|
* re-broadcast on nearly every hook (last activity, name, tokens…), so
|
|
* matching the bare message types made every such frame refetch; this one
|
|
* fires on a new session, or when the chosen key of a session actually
|
|
* changed. Each call keeps its own memory of the keys it has seen.
|
|
* @author Nguyễn Ngọc Trí Vĩ <vinnt@smartgift.vn>
|
|
*/
|
|
|
|
import type { Session, WSMessage } from "./types";
|
|
|
|
/** The columns that move a session between the active / waiting / archived counts. */
|
|
export const sessionStateKeyOf = (s: Partial<Session>): string =>
|
|
`${s.status}:${s.awaiting_input_since ? 1 : 0}:${s.archived_at ? 1 : 0}`;
|
|
|
|
export function sessionChangeMatcher(
|
|
keyOf: (s: Partial<Session>) => string = sessionStateKeyOf
|
|
): (msg: WSMessage) => boolean {
|
|
const seen = new Map<string, string>();
|
|
return (msg) => {
|
|
if (msg.type !== "session_created" && msg.type !== "session_updated") return false;
|
|
const s = msg.data as Partial<Session> | undefined;
|
|
// A frame we cannot key is taken as a change: refetching is the safe side.
|
|
if (!s || typeof s.id !== "string") return true;
|
|
const key = keyOf(s);
|
|
if (msg.type === "session_updated" && seen.get(s.id) === key) return false;
|
|
seen.set(s.id, key);
|
|
return true;
|
|
};
|
|
}
|