ai_co_discuss 0.3.28 → 0.3.30
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/.agents/skills/discuss-participant/SKILL.md +3 -2
- package/backend/free_room.py +6 -1
- package/backend/server.py +3 -2
- package/docs/en/workflow.md +100 -100
- package/docs/workflow.md +100 -100
- package/package.json +1 -1
- package/runner/relay_channel.mjs +32 -7
- package/web/app.js +41 -6
- package/web/modern.css +1 -1
- package/web/modern.js +24 -22
package/web/app.js
CHANGED
|
@@ -35,6 +35,10 @@ const LOCAL_CONNECTION_KEY = "discuss-local-connection";
|
|
|
35
35
|
const LOCAL_CONNECTION_TIMEOUT_MS = 15000;
|
|
36
36
|
// A relayed launch waits this long for the paired computer before the request is kept as a pending item.
|
|
37
37
|
const RELAY_WAIT_MS = 45000;
|
|
38
|
+
// A relayed read that goes unanswered or finds the computer briefly away is asked again after these pauses; reads change nothing.
|
|
39
|
+
const RELAY_READ_RETRY_MS = [1000, 3000];
|
|
40
|
+
// After the connection drops, the page reconnects by itself after these pauses, the last one repeating until it is back.
|
|
41
|
+
const RECONNECT_DELAYS_MS = [2000, 4000, 8000, 15000, 30000];
|
|
38
42
|
const RELAY_POLL_MS = 1500;
|
|
39
43
|
const MODEL_CATALOG_TIMEOUT_MS = 35000;
|
|
40
44
|
// Without the local service, local operations go through the paired computer, encrypted so the website only sees ciphertext.
|
|
@@ -368,10 +372,24 @@ function management_error_message(room_id, error) {
|
|
|
368
372
|
return error.message;
|
|
369
373
|
}
|
|
370
374
|
|
|
371
|
-
|
|
375
|
+
let reconnect_timer = null, reconnect_attempt = 0;
|
|
376
|
+
/** Reconnect without waiting for the user, backing off while the site or the computer stays away. */
|
|
377
|
+
function schedule_reconnect() {
|
|
378
|
+
if (reconnect_timer !== null || document.hidden) return;
|
|
379
|
+
const delay = RECONNECT_DELAYS_MS[Math.min(reconnect_attempt, RECONNECT_DELAYS_MS.length - 1)];
|
|
380
|
+
reconnect_attempt += 1;
|
|
381
|
+
reconnect_timer = setTimeout(() => {
|
|
382
|
+
reconnect_timer = null;
|
|
383
|
+
if (!state.connected && !document.hidden) reconnect_live_updates({ automatic: true });
|
|
384
|
+
}, delay);
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
/** Show connection state without claiming that any AI is online; a lost connection is retried automatically. */
|
|
372
388
|
function set_connection(connected) {
|
|
373
389
|
state.connected = connected;
|
|
374
390
|
state.reconnecting = false;
|
|
391
|
+
if (connected) { clearTimeout(reconnect_timer); reconnect_timer = null; reconnect_attempt = 0; }
|
|
392
|
+
else schedule_reconnect();
|
|
375
393
|
element("connection-dot").className = `status-dot ${connected ? "connected" : "failed"}`;
|
|
376
394
|
element("connection-status").textContent = connected ? "讨论网站已连接" : "网站连接中断,可手动刷新";
|
|
377
395
|
publish_view();
|
|
@@ -2021,7 +2039,16 @@ async function relay_command(action, payload) {
|
|
|
2021
2039
|
|
|
2022
2040
|
/** Read or write one room route on the paired computer's local website, as its owner, and answer as request_json would. */
|
|
2023
2041
|
async function relay_room_request(path, payload) {
|
|
2024
|
-
|
|
2042
|
+
let answer;
|
|
2043
|
+
for (let attempt = 0; ; attempt += 1) {
|
|
2044
|
+
try { answer = await relay_exchange("room-api", { method: payload === undefined ? "GET" : "POST", path, body: payload }); break; }
|
|
2045
|
+
catch (error) {
|
|
2046
|
+
// Only reads are asked again: a write whose outcome is unconfirmed must not be sent twice.
|
|
2047
|
+
const transient = error.unconfirmed || error.offline || error instanceof TypeError;
|
|
2048
|
+
if (payload !== undefined || !transient || attempt >= RELAY_READ_RETRY_MS.length) throw error;
|
|
2049
|
+
await new Promise((resolve) => setTimeout(resolve, RELAY_READ_RETRY_MS[attempt]));
|
|
2050
|
+
}
|
|
2051
|
+
}
|
|
2025
2052
|
if (answer.status >= 400) throw Object.assign(new Error(answer.body?.error || "请求失败,请重试"), { preflight: answer.status < 500, status: answer.status });
|
|
2026
2053
|
return answer;
|
|
2027
2054
|
}
|
|
@@ -2168,7 +2195,13 @@ function relay_event_source() {
|
|
|
2168
2195
|
let frame;
|
|
2169
2196
|
try { frame = JSON.parse(event.data); } catch { return; }
|
|
2170
2197
|
if (frame.type === "change") emit("change", JSON.stringify({ rooms: frame.rooms }));
|
|
2171
|
-
if (frame.type === "presence") {
|
|
2198
|
+
if (frame.type === "presence") {
|
|
2199
|
+
// The computer coming back (after a restart, say) is read at once rather than at the next poll.
|
|
2200
|
+
const back = frame.online && state.remote_online === false;
|
|
2201
|
+
state.remote_online = Boolean(frame.online);
|
|
2202
|
+
publish_view();
|
|
2203
|
+
if (back) emit("ready");
|
|
2204
|
+
}
|
|
2172
2205
|
});
|
|
2173
2206
|
socket.addEventListener("close", () => {
|
|
2174
2207
|
clearInterval(ping);
|
|
@@ -3738,10 +3771,10 @@ function start_live_updates({ refresh = true } = {}) {
|
|
|
3738
3771
|
if (refresh) queue_live_refresh();
|
|
3739
3772
|
}
|
|
3740
3773
|
|
|
3741
|
-
/** Reopen the update stream and read the site now; used by the footer retry and
|
|
3742
|
-
async function reconnect_live_updates() {
|
|
3774
|
+
/** Reopen the update stream and read the site now; used by the footer retry and, quietly, by automatic reconnects. */
|
|
3775
|
+
async function reconnect_live_updates({ automatic = false } = {}) {
|
|
3743
3776
|
if (document.hidden) return;
|
|
3744
|
-
state.reconnecting =
|
|
3777
|
+
state.reconnecting = !automatic;
|
|
3745
3778
|
publish_view();
|
|
3746
3779
|
live_updates.source?.close();
|
|
3747
3780
|
live_updates.source = null;
|
|
@@ -3810,6 +3843,8 @@ async function initialize() {
|
|
|
3810
3843
|
else { start_live_updates(); load_admin_state(); }
|
|
3811
3844
|
});
|
|
3812
3845
|
window.addEventListener("pagehide", stop_live_updates);
|
|
3846
|
+
// The network coming back (a phone leaving a lift, a laptop waking) reconnects at once.
|
|
3847
|
+
window.addEventListener("online", () => { if (!state.connected) reconnect_live_updates({ automatic: true }); });
|
|
3813
3848
|
window.addEventListener("pageshow", start_live_updates);
|
|
3814
3849
|
}
|
|
3815
3850
|
|