ai_co_discuss 0.3.0 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/web/app.js CHANGED
@@ -2,6 +2,9 @@
2
2
 
3
3
  const REFRESH_INTERVAL_MS = 60000;
4
4
  const FALLBACK_REFRESH_INTERVAL_MS = 12000;
5
+ // A poll reads the room in full only when it changed or an AI is working in it; this full read still comes at least this often.
6
+ const SAFETY_REFRESH_MS = 5 * 60 * 1000;
7
+ const WORKING_STATUSES = ["dispatched", "started"];
5
8
  const UPDATE_BATCH_MS = 100;
6
9
  const UPDATE_DRAG_RETRY_MS = 500;
7
10
  const TOAST_DURATION_MS = 3500;
@@ -57,7 +60,7 @@ const state = { rooms: [], folders: [], room: null, page: 1, pages: 1, query: ""
57
60
  snapshot_id: 0, pending_submission: null, pending_turn: null, pending_room: null, toast_timer: null,
58
61
  creation_mode: "brainstorm", creation_drafts: {}, access_notice: "", access_error: "" };
59
62
  const live_updates = { source: null, connected: false, enabled: false, timer: null, poll_timer: null,
60
- running: false, dirty: false };
63
+ running: false, dirty: false, full: false, revisions: "", refreshed_at: 0 };
61
64
  state.messages = [];
62
65
  state.message_history = null;
63
66
  state.connected = false;
@@ -847,7 +850,7 @@ async function load_message_history(room_id, version) {
847
850
  }
848
851
 
849
852
  /** Refresh a room with version guards so slower requests cannot change the active view. */
850
- async function refresh_room() {
853
+ async function refresh_room({ room: read_room = true } = {}) {
851
854
  if (state.dragged_room) return;
852
855
  const version = ++state.refresh_version;
853
856
  const folder_version = state.folder_version;
@@ -861,12 +864,13 @@ async function refresh_room() {
861
864
  set_folder_directory(directory);
862
865
  }
863
866
  if (state.room && !state.rooms.some((item) => item.id === state.room.id)) return select_room(visible_rooms()[0]?.id);
864
- if (!state.room) {
865
- if (visible_rooms().length) return select_room(visible_rooms()[0].id);
867
+ if (!state.room || !read_room) {
868
+ if (!state.room && visible_rooms().length) return select_room(visible_rooms()[0].id);
866
869
  render_rooms();
867
870
  set_connection(true);
868
871
  return;
869
872
  }
873
+ live_updates.refreshed_at = Date.now();
870
874
  const [room, result] = await Promise.all([
871
875
  request_json(`/api/rooms/${room_id}`),
872
876
  state.tab === "discussion" ? load_message_history(room_id, version) : null,
@@ -3592,8 +3596,9 @@ function bind_controls() {
3592
3596
  }
3593
3597
 
3594
3598
  /** Coalesce bursts and retain changes that arrive during a previous refresh. */
3595
- function queue_live_refresh() {
3599
+ function queue_live_refresh(full = true) {
3596
3600
  live_updates.dirty = true;
3601
+ live_updates.full ||= full;
3597
3602
  if (!live_updates.enabled || document.hidden || live_updates.running || live_updates.timer !== null) return;
3598
3603
  live_updates.timer = setTimeout(flush_live_refresh, UPDATE_BATCH_MS);
3599
3604
  }
@@ -3607,8 +3612,10 @@ async function flush_live_refresh() {
3607
3612
  return;
3608
3613
  }
3609
3614
  live_updates.dirty = false;
3615
+ const full = live_updates.full;
3616
+ live_updates.full = false;
3610
3617
  live_updates.running = true;
3611
- try { await refresh_room(); } catch { set_connection(false); }
3618
+ try { await refresh_room({ room: full }); } catch { set_connection(false); }
3612
3619
  finally {
3613
3620
  live_updates.running = false;
3614
3621
  if (live_updates.dirty) queue_live_refresh();
@@ -3620,11 +3627,30 @@ function arm_update_poll() {
3620
3627
  clearTimeout(live_updates.poll_timer);
3621
3628
  if (!live_updates.enabled || document.hidden) return;
3622
3629
  live_updates.poll_timer = setTimeout(() => {
3623
- queue_live_refresh();
3630
+ poll_live_updates();
3624
3631
  arm_update_poll();
3625
3632
  }, live_updates.connected ? REFRESH_INTERVAL_MS : FALLBACK_REFRESH_INTERVAL_MS);
3626
3633
  }
3627
3634
 
3635
+ /**
3636
+ * A timed poll first reads the site and room revisions: the room is read in full only when it changed, an AI is working
3637
+ * in it (its progress is not a revision), or the safety interval passed; a change elsewhere refreshes just the room list.
3638
+ * A site without revisions is read in full as before.
3639
+ */
3640
+ async function poll_live_updates() {
3641
+ const room_id = state.room?.id || "";
3642
+ const working = (state.room?.free?.members || []).some((member) => WORKING_STATUSES.includes(member.execution?.status));
3643
+ if (working || Date.now() - live_updates.refreshed_at >= SAFETY_REFRESH_MS) return queue_live_refresh();
3644
+ let revisions;
3645
+ try { revisions = await request_json(`/api/revisions?rooms=${encodeURIComponent(room_id)}`); }
3646
+ catch { return queue_live_refresh(); }
3647
+ const [site, room] = live_updates.revisions.split(":");
3648
+ const next_room = `${room_id}=${revisions.rooms?.[room_id] ?? ""}`;
3649
+ if (`${revisions.site}` === site && next_room === room) return;
3650
+ live_updates.revisions = `${revisions.site}:${next_room}`;
3651
+ queue_live_refresh(next_room !== room);
3652
+ }
3653
+
3628
3654
  /** Subscribe once per visible page; every connection fetches changes missed while disconnected. */
3629
3655
  function start_live_updates() {
3630
3656
  if (document.hidden) return;