@yeaft/webchat-agent 1.0.668 → 1.0.669

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yeaft/webchat-agent",
3
- "version": "1.0.668",
3
+ "version": "1.0.669",
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",
@@ -181,6 +181,13 @@ export class ScheduledTaskScheduler {
181
181
  }
182
182
 
183
183
  observe(sessionId, event) {
184
+ // Stop can arrive before boot/classification creates any VP turn controller
185
+ // or terminal event. Retire those claims once their ingress has drained.
186
+ if (event.type === 'yeaft_aborted' && event.all) {
187
+ for (const [id, active] of this.runs) {
188
+ if (!sessionId || id === sessionId) active.interrupted = true;
189
+ }
190
+ }
184
191
  const active = this.runs.get(sessionId);
185
192
  if (!active) return;
186
193
  if (event.type === 'error') active.error = event.message || event.error?.message || String(event.error || 'Execution failed');
@@ -510,6 +510,36 @@ const vpAborts = new Map();
510
510
  */
511
511
  const sessionCopyEpochs = new Map();
512
512
  const modelReentryActivity = new Map();
513
+ // Pending ingress has no VP AbortController yet. Keep per-request tokens so
514
+ // Stop fences existing boot/classification awaits, not later inputs in the
515
+ // same activity epoch (or inputs belonging to another Session).
516
+ const pendingSessionIngress = new Map();
517
+
518
+ function beginSessionIngress(sessionId) {
519
+ let pending = pendingSessionIngress.get(sessionId);
520
+ if (!pending) {
521
+ pending = new Set();
522
+ pendingSessionIngress.set(sessionId, pending);
523
+ }
524
+ const ingress = {
525
+ cancelled: false,
526
+ release() {
527
+ pending.delete(ingress);
528
+ if (pending.size === 0 && pendingSessionIngress.get(sessionId) === pending) {
529
+ pendingSessionIngress.delete(sessionId);
530
+ }
531
+ },
532
+ };
533
+ pending.add(ingress);
534
+ return ingress;
535
+ }
536
+
537
+ function cancelSessionIngress(sessionId = null) {
538
+ for (const [id, pending] of pendingSessionIngress) {
539
+ if (sessionId && id !== sessionId) continue;
540
+ for (const ingress of pending) ingress.cancelled = true;
541
+ }
542
+ }
513
543
 
514
544
  function hasSessionRuntimeWork(sessionId) {
515
545
  const prefix = `${sessionId}::`;
@@ -2273,14 +2303,16 @@ function scheduleTaskResultReentry(event) {
2273
2303
 
2274
2304
  async function routeEnvelopeToVpThread(sessionId, vpId, envelope) {
2275
2305
  const releaseActivity = beginSessionActivity(sessionId);
2306
+ const ingress = beginSessionIngress(sessionId);
2276
2307
  try {
2277
- return await routeActiveEnvelopeToVpThread(sessionId, vpId, envelope);
2308
+ return await routeActiveEnvelopeToVpThread(sessionId, vpId, envelope, ingress);
2278
2309
  } finally {
2310
+ ingress.release();
2279
2311
  releaseActivity();
2280
2312
  }
2281
2313
  }
2282
2314
 
2283
- async function routeActiveEnvelopeToVpThread(sessionId, vpId, envelope) {
2315
+ async function routeActiveEnvelopeToVpThread(sessionId, vpId, envelope, ingress) {
2284
2316
  const routeStart = perfNowMs();
2285
2317
  const { text, prompt, promptParts } = buildVpPromptPayload(vpId, envelope);
2286
2318
  const runningThreads = getRunningThreads(sessionId, vpId);
@@ -2313,6 +2345,7 @@ async function routeActiveEnvelopeToVpThread(sessionId, vpId, envelope) {
2313
2345
  // promise would leave it visible in history without ever starting a turn.
2314
2346
  console.warn('[Yeaft] VP thread classification failed; starting a new thread:', err?.message || err);
2315
2347
  }
2348
+ if (ingress.cancelled) return null;
2316
2349
  const targetIsRunning = decision
2317
2350
  ? runningThreads.some((t) => t.threadId === decision.targetThreadId)
2318
2351
  : false;
@@ -5214,22 +5247,25 @@ async function runYeaftSessionSend(msg) {
5214
5247
  traceDuration('session_send.open_session', openSessionStart, { ok: !!sessionHandle });
5215
5248
 
5216
5249
  const releaseActivity = beginSessionActivity(sessionId);
5250
+ const ingress = beginSessionIngress(sessionId);
5217
5251
  try {
5218
5252
  return await dispatchAcceptedSessionSend({
5219
- msg, text, mentions, quote, sessionId, yeaftDir, perfTraceId, perfStart,
5253
+ msg, text, mentions, quote, sessionId, yeaftDir, perfTraceId, perfStart, ingress,
5220
5254
  tracePerf, traceDuration, turnConfig, sessionHandle, sessionRoot, sessionMetaForRuntime,
5221
5255
  });
5222
5256
  } finally {
5257
+ ingress.release();
5223
5258
  releaseActivity();
5224
5259
  }
5225
5260
  }
5226
5261
 
5227
5262
  async function dispatchAcceptedSessionSend({
5228
- msg, text, mentions, quote, sessionId, yeaftDir, perfTraceId, perfStart,
5263
+ msg, text, mentions, quote, sessionId, yeaftDir, perfTraceId, perfStart, ingress,
5229
5264
  tracePerf, traceDuration, turnConfig, sessionHandle, sessionRoot, sessionMetaForRuntime,
5230
5265
  }) {
5231
5266
  const ensureSessionStart = perfNowMs();
5232
5267
  await ensureSessionLoaded({ sessionMeta: sessionMetaForRuntime, perfTraceId });
5268
+ if (ingress.cancelled) return;
5233
5269
  // Runtime boot may await I/O. Re-read the claim immediately before ingress
5234
5270
  // so edits, disable, archive or deletion during boot cannot execute stale work.
5235
5271
  msg[SCHEDULED_TASK_DISPATCH_GUARD]?.();
@@ -6742,6 +6778,7 @@ export function handleYeaftAbortThread(_msg = {}) {
6742
6778
  export function handleYeaftAbortAll(msg = {}) {
6743
6779
  const sessionId = typeof msg.sessionId === 'string' && msg.sessionId ? msg.sessionId : null;
6744
6780
  const aborted = [];
6781
+ cancelSessionIngress(sessionId);
6745
6782
  if (!sessionId && currentAbortCtrl && !currentAbortCtrl.signal.aborted) {
6746
6783
  try { currentAbortCtrl.abort(); aborted.push('main'); } catch { /* best-effort */ }
6747
6784
  }