@djangocfg/ui-tools 2.1.444 → 2.1.445

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": "@djangocfg/ui-tools",
3
- "version": "2.1.444",
3
+ "version": "2.1.445",
4
4
  "description": "Heavy React tools with lazy loading - for Electron, Vite, CRA, Next.js apps",
5
5
  "keywords": [
6
6
  "ui-tools",
@@ -334,8 +334,8 @@
334
334
  "test:watch": "vitest"
335
335
  },
336
336
  "peerDependencies": {
337
- "@djangocfg/i18n": "^2.1.444",
338
- "@djangocfg/ui-core": "^2.1.444",
337
+ "@djangocfg/i18n": "^2.1.445",
338
+ "@djangocfg/ui-core": "^2.1.445",
339
339
  "consola": "^3.4.2",
340
340
  "lodash-es": "^4.18.1",
341
341
  "lucide-react": "^0.545.0",
@@ -418,9 +418,9 @@
418
418
  "@maplibre/maplibre-gl-geocoder": "^1.7.0"
419
419
  },
420
420
  "devDependencies": {
421
- "@djangocfg/i18n": "^2.1.444",
422
- "@djangocfg/typescript-config": "^2.1.444",
423
- "@djangocfg/ui-core": "^2.1.444",
421
+ "@djangocfg/i18n": "^2.1.445",
422
+ "@djangocfg/typescript-config": "^2.1.445",
423
+ "@djangocfg/ui-core": "^2.1.445",
424
424
  "@types/lodash-es": "^4.17.12",
425
425
  "@types/mapbox__mapbox-gl-draw": "^1.4.8",
426
426
  "@types/node": "^25.2.3",
@@ -272,6 +272,16 @@ export function useChat(config: UseChatConfig): UseChatReturn {
272
272
  let serverMessageId: string | null = null;
273
273
  let chunkCount = 0;
274
274
  let charsReceived = 0;
275
+ // Tracks whether the stream already delivered a TERMINAL event
276
+ // (`message_end` or `error`) via handleEvent. Guards the manual-finalize
277
+ // below. Without it, the finalize reads `stateRef.current.isStreaming` —
278
+ // a snapshot NOT updated synchronously after a `dispatch` — so right
279
+ // after a STREAM_ERROR it still sees `isStreaming: true` and fires a
280
+ // spurious STREAM_DONE, whose reducer clears `state.error`. Net effect:
281
+ // the error is set then wiped in the same tick and the ErrorBanner never
282
+ // paints. `sawTerminal` is a closure flag, so it reflects the truth the
283
+ // ref can't. See @dev/web2/chat/reports/COMPARE-new-vs-old-chat-error-handling.md (layer 3).
284
+ let sawTerminal = false;
275
285
  const t0 = performance.now();
276
286
 
277
287
  try {
@@ -311,8 +321,12 @@ export function useChat(config: UseChatConfig): UseChatReturn {
311
321
  }
312
322
  tokenBuffer.flush();
313
323
 
314
- // If transport never emitted message_end, finalize manually.
315
- if (stateRef.current.isStreaming) {
324
+ // If transport never emitted a terminal event (message_end / error),
325
+ // finalize manually. Gated on `sawTerminal` — NOT on
326
+ // `stateRef.current.isStreaming`, which is a stale snapshot right after
327
+ // a STREAM_ERROR dispatch and would otherwise fire a STREAM_DONE that
328
+ // wipes `state.error`.
329
+ if (!sawTerminal && stateRef.current.isStreaming) {
316
330
  dispatch({ type: 'STREAM_DONE', id: targetId });
317
331
  }
318
332
 
@@ -397,6 +411,7 @@ export function useChat(config: UseChatConfig): UseChatReturn {
397
411
  log.tools.info('call_end', { toolId: ev.toolId, status: ev.status });
398
412
  return;
399
413
  case 'message_end':
414
+ sawTerminal = true;
400
415
  tokenBuffer.flush();
401
416
  dispatch({
402
417
  type: 'STREAM_DONE',
@@ -440,6 +455,7 @@ export function useChat(config: UseChatConfig): UseChatReturn {
440
455
  });
441
456
  return;
442
457
  case 'error':
458
+ sawTerminal = true;
443
459
  tokenBuffer.flush();
444
460
  dispatch({
445
461
  type: 'STREAM_ERROR',