@yeaft/webchat-agent 1.0.61 → 1.0.63

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.
@@ -0,0 +1,15 @@
1
+ const DEFAULT_AGENT_HEARTBEAT_TIMEOUT_MS = 180000;
2
+
3
+ function parsePositiveInt(value, fallback) {
4
+ const n = Number(value);
5
+ return Number.isFinite(n) && n > 0 ? n : fallback;
6
+ }
7
+
8
+ export const AGENT_HEARTBEAT_TIMEOUT_MS = parsePositiveInt(
9
+ process.env.YEAFT_AGENT_HEARTBEAT_TIMEOUT_MS || process.env.AGENT_HEARTBEAT_TIMEOUT_MS,
10
+ DEFAULT_AGENT_HEARTBEAT_TIMEOUT_MS,
11
+ );
12
+
13
+ export function shouldReconnectForHeartbeat(lastPongAt, now = Date.now(), timeoutMs = AGENT_HEARTBEAT_TIMEOUT_MS) {
14
+ return Number.isFinite(lastPongAt) && lastPongAt > 0 && (now - lastPongAt) > timeoutMs;
15
+ }
@@ -1,5 +1,6 @@
1
1
  import WebSocket from 'ws';
2
2
  import ctx from '../context.js';
3
+ import { shouldReconnectForHeartbeat } from './heartbeat-policy.js';
3
4
 
4
5
  export function startAgentHeartbeat() {
5
6
  stopAgentHeartbeat();
@@ -16,8 +17,9 @@ export function startAgentHeartbeat() {
16
17
  if (!ctx.ws || ctx.ws.readyState !== WebSocket.OPEN) return;
17
18
 
18
19
  // 检查上次 pong 是否超时
19
- const sincePong = Date.now() - ctx.lastPongAt;
20
- if (sincePong > 45000) {
20
+ const now = Date.now();
21
+ const sincePong = now - ctx.lastPongAt;
22
+ if (shouldReconnectForHeartbeat(ctx.lastPongAt, now)) {
21
23
  console.warn(`[Heartbeat] No pong for ${Math.round(sincePong / 1000)}s, reconnecting...`);
22
24
  ctx.ws.terminate();
23
25
  return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yeaft/webchat-agent",
3
- "version": "1.0.61",
3
+ "version": "1.0.63",
4
4
  "description": "Remote worker agent for Yeaft Web Code Agent — connects the native Yeaft engine, CLI providers, and workbench tools",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -266,15 +266,18 @@ export function buildRelevantScopes({ sessionId, chatId, vpId, extra } = {}) {
266
266
  scopes.push(`chat/${chatId}`);
267
267
  if (vpId) scopes.push(`chat/${chatId}/vp/${vpId}`);
268
268
  } else if (sessionId) {
269
- // Read both legacy `group/<id>` and new `session/<id>` scopes so recall
270
- // works regardless of which path the writers used for a given session.
271
- // (Writers still emit `group/<id>` for back-compat; migration may have
272
- // rewritten on-disk data to `session/<id>`.)
269
+ // Read every persisted Session spelling that can exist on disk. Current
270
+ // Dream writers use `sessions/<id>`; older readers/writers used singular
271
+ // `session/<id>` or legacy `group/<id>`. SQLite FTS is scope-filtered, so
272
+ // omitting any spelling makes valid indexed memory invisible.
273
+ scopes.push(`sessions/${sessionId}`);
274
+ scopes.push(`sessions/${sessionId}/user`);
273
275
  scopes.push(`session/${sessionId}`);
274
276
  scopes.push(`session/${sessionId}/user`);
275
277
  scopes.push(`group/${sessionId}`);
276
278
  scopes.push(`group/${sessionId}/user`);
277
279
  if (vpId) {
280
+ scopes.push(`sessions/${sessionId}/vp/${vpId}`);
278
281
  scopes.push(`session/${sessionId}/vp/${vpId}`);
279
282
  scopes.push(`group/${sessionId}/vp/${vpId}`);
280
283
  }
@@ -4821,6 +4821,12 @@ export function __testAppendTurnToSessionHistory(...args) {
4821
4821
  * Backwards-compat: when neither field is set, defaults to `vpId='default'`
4822
4822
  * which matches the pre-v0.1.754 behavior.
4823
4823
  */
4824
+ function resolveDreamTriggerSessionId(msg = {}) {
4825
+ return typeof msg.sessionId === 'string' && msg.sessionId
4826
+ ? msg.sessionId
4827
+ : (typeof msg.groupId === 'string' && msg.groupId ? msg.groupId : null);
4828
+ }
4829
+
4824
4830
  export function normalizeDreamResult(result) {
4825
4831
  const sessions = Array.isArray(result?.sessions) ? result.sessions : [];
4826
4832
  const targets = Array.isArray(result?.targets) ? result.targets : [];
@@ -4869,7 +4875,7 @@ export async function handleYeaftDreamTrigger(msg = {}) {
4869
4875
  // route the error event back to the right row and the per-group
4870
4876
  // "Run dream now" button would stay stuck on "Running…" forever
4871
4877
  // (review feedback from PR #757).
4872
- const sessionId = typeof msg.sessionId === 'string' && msg.sessionId ? msg.sessionId : null;
4878
+ const sessionId = resolveDreamTriggerSessionId(msg);
4873
4879
  const vpId = !sessionId ? (msg.vpId || 'default') : null;
4874
4880
  const tag = sessionId ? { sessionId } : { vpId };
4875
4881
 
@@ -5924,6 +5930,7 @@ export const __testHooks = {
5924
5930
  return getVpStatusBroker().transition(status);
5925
5931
  },
5926
5932
  decorateSessionsWithRuntimeState,
5933
+ resolveDreamTriggerSessionId,
5927
5934
  async loadProjectRuntime(workDir) {
5928
5935
  return loadProjectRuntime(workDir);
5929
5936
  },