fix(pet): each user's pet tells only of their own sessions
An admin/analyst's pet counted every user's sessions (live, waiting, errors) because their WebSocket carries everyone's. Server mode now marks their session/agent/event frames `mine: true|false` (scope.broadcastAudience owners, worked out once per broadcast), and GET /api/sessions?mine=1 lists only the caller's own sessions (ownSessionWhere). The pet seeds from mine=1 and skips frames marked mine: false. Developers and local mode are unchanged.
This commit is contained in:
@@ -200,6 +200,20 @@ describe("Sagi widget", () => {
|
||||
expect(within(liveChip).getByText("2")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("counts only the viewer's own sessions (another user's arrive marked mine: false)", () => {
|
||||
renderSagi();
|
||||
act(() => {
|
||||
eventBus.publish({ ...sessionMsg("mine", "active"), mine: true });
|
||||
eventBus.publish({ ...sessionMsg("theirs", "active"), mine: false });
|
||||
eventBus.publish({ ...sessionMsg("theirs-err", "error"), mine: false });
|
||||
});
|
||||
fireEvent.click(screen.getByRole("button", { name: /open sagi companion/i }));
|
||||
const panel = screen.getByRole("dialog", { name: /chat with sagi/i });
|
||||
const liveChip = within(panel).getByText("live").closest("span.rounded-full")! as HTMLElement;
|
||||
expect(within(liveChip).getByText("1")).toBeInTheDocument();
|
||||
expect(screen.queryByText(/theirs/)).toBeNull();
|
||||
});
|
||||
|
||||
it("respects the enabled preference", () => {
|
||||
localStorage.setItem("agent-dashboard-sagi-enabled", "false");
|
||||
renderSagi();
|
||||
|
||||
@@ -7,7 +7,8 @@
|
||||
* burst of the same event into one count), the pet's one-shot animation
|
||||
* "moment", and imperative controls (mute, clear alerts, pat, set thinking)
|
||||
* for the UI shell. It also greets once per browser session and makes an
|
||||
* idle pet fidget now and then.
|
||||
* idle pet fidget now and then. It only ever counts the viewer's OWN sessions
|
||||
* (`mine=1` seed, and frames marked `mine: false` skipped).
|
||||
* @author Nguyễn Ngọc Trí Vĩ <vinnt@smartgift.vn>
|
||||
*/
|
||||
/* =============================================================================
|
||||
@@ -278,7 +279,7 @@ export function useSagiBrain(): SagiBrain {
|
||||
}, GREET_DELAY_MS);
|
||||
};
|
||||
api.sessions
|
||||
.list({ status: "active", limit: 100 })
|
||||
.list({ status: "active", limit: 100, mine: true })
|
||||
.then((res) => {
|
||||
if (cancelled) return;
|
||||
update((prev) => seedSessions(prev, res.sessions, Date.now()));
|
||||
@@ -294,6 +295,9 @@ export function useSagiBrain(): SagiBrain {
|
||||
// Subscribe to the live stream and connection status.
|
||||
useEffect(() => {
|
||||
const unsubMsg = eventBus.subscribe((msg: WSMessage) => {
|
||||
// Each user's pet tells only of their own sessions: an admin/analyst
|
||||
// gets every user's, marked `mine: false` when not theirs.
|
||||
if (msg.mine === false) return;
|
||||
const prev = stateRef.current;
|
||||
const { state: next, pulse, subject } = reduceSagi(prev, msg, Date.now());
|
||||
// Most frames only move lastActivityAt, which the moods read at a 1 s
|
||||
|
||||
Reference in New Issue
Block a user