@djangocfg/ui-tools 2.1.336 → 2.1.338

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,14 @@
1
+ 'use strict';
2
+
3
+ var chunk5T4K3VUV_cjs = require('./chunk-5T4K3VUV.cjs');
4
+ require('./chunk-B5AWZOHJ.cjs');
5
+ require('./chunk-OLISEQHS.cjs');
6
+
7
+
8
+
9
+ Object.defineProperty(exports, "ChatRoot", {
10
+ enumerable: true,
11
+ get: function () { return chunk5T4K3VUV_cjs.ChatRoot; }
12
+ });
13
+ //# sourceMappingURL=ChatRoot-BT3CLXI4.cjs.map
14
+ //# sourceMappingURL=ChatRoot-BT3CLXI4.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":[],"names":[],"mappings":"","file":"ChatRoot-IIYQEWUU.mjs"}
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"ChatRoot-BT3CLXI4.cjs"}
@@ -0,0 +1,5 @@
1
+ export { ChatRoot } from './chunk-QE25H6DP.mjs';
2
+ import './chunk-2ZLKZ5VR.mjs';
3
+ import './chunk-N2XQF2OL.mjs';
4
+ //# sourceMappingURL=ChatRoot-R5YQTOLP.mjs.map
5
+ //# sourceMappingURL=ChatRoot-R5YQTOLP.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":[],"names":[],"mappings":"","file":"ChatRoot-UUKTYM4N.cjs"}
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"ChatRoot-R5YQTOLP.mjs"}
@@ -4,6 +4,7 @@ var chunkB5AWZOHJ_cjs = require('./chunk-B5AWZOHJ.cjs');
4
4
  var chunkOLISEQHS_cjs = require('./chunk-OLISEQHS.cjs');
5
5
  var react = require('react');
6
6
  var lib = require('@djangocfg/ui-core/lib');
7
+ var consola = require('consola');
7
8
  var hooks = require('@djangocfg/ui-core/hooks');
8
9
  var zustand = require('zustand');
9
10
  var middleware = require('zustand/middleware');
@@ -296,6 +297,32 @@ function createId(prefix = "m") {
296
297
  return `${prefix}_${Date.now().toString(36)}_${counter.toString(36)}_${Math.random().toString(36).slice(2, 8)}`;
297
298
  }
298
299
  chunkOLISEQHS_cjs.__name(createId, "createId");
300
+ var SCOPES = ["bootstrap", "transport", "stream", "lifecycle", "tools", "error"];
301
+ var cache = /* @__PURE__ */ new Map();
302
+ function buildLogger(enabled) {
303
+ const root = consola.consola.withTag("chat");
304
+ const subs = Object.fromEntries(
305
+ SCOPES.map((scope) => [scope, root.withTag(scope)])
306
+ );
307
+ if (!enabled) {
308
+ for (const scope of SCOPES) {
309
+ if (scope === "error") continue;
310
+ subs[scope].level = -999;
311
+ }
312
+ }
313
+ return { ...subs, enabled };
314
+ }
315
+ chunkOLISEQHS_cjs.__name(buildLogger, "buildLogger");
316
+ function getChatLogger(debug) {
317
+ const enabled = debug ?? lib.isDev;
318
+ let logger = cache.get(enabled);
319
+ if (!logger) {
320
+ logger = buildLogger(enabled);
321
+ cache.set(enabled, logger);
322
+ }
323
+ return logger;
324
+ }
325
+ chunkOLISEQHS_cjs.__name(getChatLogger, "getChatLogger");
299
326
 
300
327
  // src/tools/Chat/core/markdown.ts
301
328
  function createTokenBuffer(onFlush, windowMs = LIMITS.streamCoalesceMs) {
@@ -341,32 +368,53 @@ function useChat(config) {
341
368
  stateRef.current = state;
342
369
  const abortRef = react.useRef(null);
343
370
  const lastErrorRef = react.useRef(null);
344
- const initRef = react.useRef(false);
345
371
  const streamingMsgIdRef = react.useRef(null);
372
+ const bootstrapRef = react.useRef(null);
346
373
  const { transport, autoCreateSession = true, streaming = true, pageSize = LIMITS.pageSize } = config;
374
+ const log = getChatLogger(config.debug);
347
375
  react.useEffect(() => {
348
- if (initRef.current) return;
349
- initRef.current = true;
350
376
  let cancelled = false;
377
+ if (stateRef.current.sessionId) {
378
+ return;
379
+ }
380
+ if (config.initialSessionId || autoCreateSession) {
381
+ dispatch({ type: "HISTORY_LOAD_START" });
382
+ }
383
+ log.bootstrap.info("start", {
384
+ mode: config.initialSessionId ? "resume" : autoCreateSession ? "create" : "idle",
385
+ initialSessionId: config.initialSessionId
386
+ });
351
387
  const run = /* @__PURE__ */ chunkOLISEQHS_cjs.__name(async () => {
388
+ const t0 = performance.now();
352
389
  try {
353
390
  if (config.initialSessionId) {
354
- dispatch({
355
- type: "SESSION_SET",
356
- sessionId: config.initialSessionId
357
- });
358
- dispatch({ type: "HISTORY_LOAD_START" });
391
+ if (!cancelled) {
392
+ dispatch({
393
+ type: "SESSION_SET",
394
+ sessionId: config.initialSessionId
395
+ });
396
+ }
359
397
  const page = await transport.loadHistory(config.initialSessionId, null, pageSize);
360
- if (cancelled) return;
398
+ if (cancelled) {
399
+ log.bootstrap.debug("cancelled (post-loadHistory)");
400
+ return config.initialSessionId;
401
+ }
361
402
  dispatch({
362
403
  type: "HISTORY_LOAD_DONE",
363
404
  messages: page.messages,
364
405
  hasMore: page.hasMore,
365
406
  cursor: page.nextCursor
366
407
  });
367
- } else if (autoCreateSession) {
408
+ log.bootstrap.success("resumed", {
409
+ sessionId: config.initialSessionId,
410
+ messages: page.messages.length,
411
+ hasMore: page.hasMore,
412
+ elapsedMs: Math.round(performance.now() - t0)
413
+ });
414
+ return config.initialSessionId;
415
+ }
416
+ if (autoCreateSession) {
368
417
  const info = await transport.createSession({ metadata: config.metadata });
369
- if (cancelled) return;
370
418
  dispatch({
371
419
  type: "SESSION_SET",
372
420
  sessionId: info.sessionId,
@@ -374,19 +422,48 @@ function useChat(config) {
374
422
  hasMore: info.hasMore ?? false,
375
423
  cursor: info.cursor ?? null
376
424
  });
425
+ dispatch({
426
+ type: "HISTORY_LOAD_DONE",
427
+ messages: info.messages ?? [],
428
+ hasMore: info.hasMore ?? false,
429
+ cursor: info.cursor ?? null
430
+ });
431
+ log.bootstrap.success(cancelled ? "created (post-cancel)" : "created", {
432
+ sessionId: info.sessionId,
433
+ resumed: info.resumed ?? false,
434
+ cancelled,
435
+ elapsedMs: Math.round(performance.now() - t0)
436
+ });
437
+ return info.sessionId;
377
438
  }
439
+ log.bootstrap.debug("idle (no initialSessionId, autoCreateSession=false)");
440
+ return null;
378
441
  } catch (err) {
379
442
  const e = err instanceof Error ? err : new Error(String(err));
443
+ if (cancelled) {
444
+ log.bootstrap.debug("cancelled (in catch)", { message: e.message });
445
+ return null;
446
+ }
380
447
  lastErrorRef.current = e;
381
448
  dispatch({ type: "ERROR_SET", error: e.message });
382
449
  config.onError?.(e);
450
+ log.error.error("bootstrap failed", { message: e.message, elapsedMs: Math.round(performance.now() - t0) });
451
+ return null;
383
452
  }
384
453
  }, "run");
385
- void run();
454
+ bootstrapRef.current = run();
386
455
  return () => {
387
456
  cancelled = true;
388
457
  };
389
458
  }, []);
459
+ const awaitSession = react.useCallback(async () => {
460
+ if (stateRef.current.sessionId) return stateRef.current.sessionId;
461
+ if (bootstrapRef.current) {
462
+ const id = await bootstrapRef.current;
463
+ if (id) return id;
464
+ }
465
+ return stateRef.current.sessionId;
466
+ }, []);
390
467
  const consumeStream = react.useCallback(
391
468
  async (sessionId, content, attachments) => {
392
469
  const ctrl = new AbortController();
@@ -395,9 +472,13 @@ function useChat(config) {
395
472
  streamingMsgIdRef.current = assistantId;
396
473
  dispatch({ type: "STREAM_START", id: assistantId });
397
474
  config.onStreamStart?.(assistantId);
475
+ log.stream.info("start", { sessionId, assistantId, chars: content.length });
398
476
  const tokenBuffer = createTokenBuffer(
399
477
  (delta) => dispatch({ type: "STREAM_CHUNK", delta })
400
478
  );
479
+ let chunkCount = 0;
480
+ let charsReceived = 0;
481
+ const t0 = performance.now();
401
482
  try {
402
483
  const iterator = transport.stream(sessionId, content, {
403
484
  signal: ctrl.signal,
@@ -414,17 +495,25 @@ function useChat(config) {
414
495
  }
415
496
  const finalMsg = stateRef.current.messages.find((m) => m.id === assistantId);
416
497
  if (finalMsg) config.onMessageEnd?.(finalMsg);
498
+ log.stream.success("done", {
499
+ assistantId,
500
+ chunks: chunkCount,
501
+ chars: charsReceived,
502
+ elapsedMs: Math.round(performance.now() - t0)
503
+ });
417
504
  } catch (err) {
418
505
  tokenBuffer.close();
419
506
  if (ctrl.signal.aborted) {
420
507
  const partial = stateRef.current.messages.find((m) => m.id === assistantId)?.content ?? "";
421
508
  dispatch({ type: "STREAM_CANCELLED", id: assistantId, partialText: partial });
509
+ log.stream.warn("cancelled", { assistantId, partialChars: partial.length });
422
510
  return;
423
511
  }
424
512
  const e = err instanceof Error ? err : new Error(String(err));
425
513
  lastErrorRef.current = e;
426
514
  dispatch({ type: "STREAM_ERROR", id: assistantId, message: e.message });
427
515
  config.onError?.(e);
516
+ log.error.error("stream failed", { assistantId, message: e.message });
428
517
  } finally {
429
518
  tokenBuffer.close();
430
519
  if (abortRef.current === ctrl) abortRef.current = null;
@@ -434,13 +523,17 @@ function useChat(config) {
434
523
  switch (ev.type) {
435
524
  case "message_start":
436
525
  ev.messageId;
526
+ log.stream.debug("message_start", { messageId: ev.messageId });
437
527
  return;
438
528
  case "chunk":
439
529
  tokenBuffer.push(ev.delta);
530
+ chunkCount += 1;
531
+ charsReceived += ev.delta.length;
440
532
  return;
441
533
  case "tool_activity":
442
534
  tokenBuffer.flush();
443
535
  dispatch({ type: "STREAM_TOOL_ACTIVITY", tool: ev.tool });
536
+ log.tools.debug("activity", { tool: ev.tool, status: ev.status });
444
537
  return;
445
538
  case "tool_call_start": {
446
539
  tokenBuffer.flush();
@@ -457,6 +550,7 @@ function useChat(config) {
457
550
  messageId: assistantId,
458
551
  toolCall
459
552
  });
553
+ log.tools.info("call_start", { toolId: ev.toolId, name: ev.name });
460
554
  return;
461
555
  }
462
556
  case "tool_call_delta":
@@ -475,6 +569,7 @@ function useChat(config) {
475
569
  output: ev.output,
476
570
  status: ev.status
477
571
  });
572
+ log.tools.info("call_end", { toolId: ev.toolId, status: ev.status });
478
573
  return;
479
574
  case "message_end":
480
575
  tokenBuffer.flush();
@@ -485,6 +580,11 @@ function useChat(config) {
485
580
  tokensOut: ev.tokensOut,
486
581
  sources: ev.sources
487
582
  });
583
+ log.stream.debug("message_end", {
584
+ tokensIn: ev.tokensIn,
585
+ tokensOut: ev.tokensOut,
586
+ sources: ev.sources?.length ?? 0
587
+ });
488
588
  return;
489
589
  case "error":
490
590
  tokenBuffer.flush();
@@ -493,6 +593,7 @@ function useChat(config) {
493
593
  id: assistantId,
494
594
  message: ev.message
495
595
  });
596
+ log.error.error("stream event error", { code: ev.code, message: ev.message });
496
597
  return;
497
598
  }
498
599
  }
@@ -529,16 +630,28 @@ function useChat(config) {
529
630
  );
530
631
  const sendMessage = react.useCallback(
531
632
  async (content, attachments) => {
532
- const sessionId = stateRef.current.sessionId;
633
+ log.lifecycle.info("sendMessage", {
634
+ chars: content.length,
635
+ attachments: attachments?.length ?? 0,
636
+ hasSession: !!stateRef.current.sessionId
637
+ });
638
+ const sessionId = await awaitSession();
533
639
  if (!sessionId) {
534
640
  const e = new Error("No active session");
535
641
  lastErrorRef.current = e;
536
642
  dispatch({ type: "ERROR_SET", error: e.message });
537
643
  config.onError?.(e);
644
+ log.error.error("sendMessage aborted: no session");
645
+ return;
646
+ }
647
+ if (!content.trim() && !(attachments && attachments.length > 0)) {
648
+ log.lifecycle.debug("sendMessage skipped (empty)");
649
+ return;
650
+ }
651
+ if (stateRef.current.isStreaming) {
652
+ log.lifecycle.debug("sendMessage skipped (already streaming)");
538
653
  return;
539
654
  }
540
- if (!content.trim() && !(attachments && attachments.length > 0)) return;
541
- if (stateRef.current.isStreaming) return;
542
655
  const userMsg = {
543
656
  id: createId("u"),
544
657
  role: "user",
@@ -555,13 +668,14 @@ function useChat(config) {
555
668
  await consumeBuffered(sessionId, content, attachments);
556
669
  }
557
670
  },
558
- [streaming, consumeStream, consumeBuffered, config]
671
+ [streaming, consumeStream, consumeBuffered, config, awaitSession]
559
672
  );
560
673
  const cancelStream = react.useCallback(() => {
561
674
  abortRef.current?.abort();
562
675
  }, []);
563
676
  const regenerate = react.useCallback(
564
677
  async (messageId) => {
678
+ log.lifecycle.info("regenerate", { messageId: messageId ?? "(last)" });
565
679
  const messages = stateRef.current.messages;
566
680
  let targetUserIdx = -1;
567
681
  if (messageId) {
@@ -577,7 +691,7 @@ function useChat(config) {
577
691
  for (let i = messages.length - 1; i > targetUserIdx; i -= 1) {
578
692
  dispatch({ type: "MESSAGE_DELETE", id: messages[i].id });
579
693
  }
580
- const sessionId = stateRef.current.sessionId;
694
+ const sessionId = await awaitSession();
581
695
  if (!sessionId) return;
582
696
  if (streaming) {
583
697
  await consumeStream(sessionId, userMsg.content, userMsg.attachments);
@@ -585,7 +699,7 @@ function useChat(config) {
585
699
  await consumeBuffered(sessionId, userMsg.content, userMsg.attachments);
586
700
  }
587
701
  },
588
- [streaming, consumeStream, consumeBuffered]
702
+ [streaming, consumeStream, consumeBuffered, awaitSession]
589
703
  );
590
704
  const editMessage = react.useCallback(
591
705
  async (id, content) => {
@@ -629,6 +743,7 @@ function useChat(config) {
629
743
  }
630
744
  }, [transport, pageSize, config]);
631
745
  const newSession = react.useCallback(async () => {
746
+ log.lifecycle.info("newSession", { previous: stateRef.current.sessionId });
632
747
  abortRef.current?.abort();
633
748
  const previous = stateRef.current.sessionId;
634
749
  if (previous) {
@@ -647,11 +762,13 @@ function useChat(config) {
647
762
  hasMore: info.hasMore ?? false,
648
763
  cursor: info.cursor ?? null
649
764
  });
765
+ log.lifecycle.success("newSession ok", { sessionId: info.sessionId });
650
766
  } catch (err) {
651
767
  const e = err instanceof Error ? err : new Error(String(err));
652
768
  lastErrorRef.current = e;
653
769
  dispatch({ type: "ERROR_SET", error: e.message });
654
770
  config.onError?.(e);
771
+ log.error.error("newSession failed", { message: e.message });
655
772
  }
656
773
  }, [transport, config]);
657
774
  return {
@@ -765,14 +882,14 @@ function createAudioBus(options) {
765
882
  return noopBus();
766
883
  }
767
884
  let sounds = options.sounds;
768
- const cache = /* @__PURE__ */ new Map();
885
+ const cache2 = /* @__PURE__ */ new Map();
769
886
  const getOrCreate = /* @__PURE__ */ chunkOLISEQHS_cjs.__name((url) => {
770
- const hit = cache.get(url);
887
+ const hit = cache2.get(url);
771
888
  if (hit) return hit;
772
889
  const el = new Audio(url);
773
890
  el.preload = "auto";
774
891
  el.crossOrigin = "anonymous";
775
- cache.set(url, el);
892
+ cache2.set(url, el);
776
893
  return el;
777
894
  }, "getOrCreate");
778
895
  const resolveUrl = /* @__PURE__ */ chunkOLISEQHS_cjs.__name((event) => {
@@ -806,7 +923,7 @@ function createAudioBus(options) {
806
923
  }, "preload");
807
924
  const unlock = /* @__PURE__ */ chunkOLISEQHS_cjs.__name(() => {
808
925
  if (unlocked) return;
809
- for (const el of cache.values()) {
926
+ for (const el of cache2.values()) {
810
927
  const wasMuted = el.muted;
811
928
  el.muted = true;
812
929
  const p = el.play();
@@ -838,7 +955,7 @@ function createAudioBus(options) {
838
955
  sounds = next;
839
956
  },
840
957
  dispose() {
841
- cache.clear();
958
+ cache2.clear();
842
959
  }
843
960
  };
844
961
  }
@@ -1050,6 +1167,7 @@ function ChatProvider({
1050
1167
  autoCreateSession,
1051
1168
  streaming,
1052
1169
  audio,
1170
+ debug,
1053
1171
  children
1054
1172
  }) {
1055
1173
  const audioApi = useChatAudio(audio ?? {});
@@ -1064,6 +1182,7 @@ function ChatProvider({
1064
1182
  initialSessionId,
1065
1183
  autoCreateSession,
1066
1184
  streaming,
1185
+ debug,
1067
1186
  metadata: {
1068
1187
  locale: config.locale ?? config.prefs?.locale,
1069
1188
  slug: config.slug
@@ -2095,7 +2214,7 @@ function copy(text) {
2095
2214
  }
2096
2215
  chunkOLISEQHS_cjs.__name(copy, "copy");
2097
2216
  function ChatRoot(props) {
2098
- const { transport, config, initialSessionId, autoCreateSession, streaming, audio, className, ...slots } = props;
2217
+ const { transport, config, initialSessionId, autoCreateSession, streaming, audio, debug, className, ...slots } = props;
2099
2218
  return /* @__PURE__ */ jsxRuntime.jsx(
2100
2219
  ChatProvider,
2101
2220
  {
@@ -2105,6 +2224,7 @@ function ChatRoot(props) {
2105
2224
  autoCreateSession,
2106
2225
  streaming,
2107
2226
  audio,
2227
+ debug,
2108
2228
  children: /* @__PURE__ */ jsxRuntime.jsx(ChatRootShell, { className, slots })
2109
2229
  }
2110
2230
  );
@@ -2241,6 +2361,7 @@ exports.ToolCalls = ToolCalls;
2241
2361
  exports.createId = createId;
2242
2362
  exports.createTokenBuffer = createTokenBuffer;
2243
2363
  exports.deriveInitials = deriveInitials;
2364
+ exports.getChatLogger = getChatLogger;
2244
2365
  exports.initialState = initialState;
2245
2366
  exports.reducer = reducer;
2246
2367
  exports.resolvePersona = resolvePersona;
@@ -2253,5 +2374,5 @@ exports.useChatContextOptional = useChatContextOptional;
2253
2374
  exports.useChatHistory = useChatHistory;
2254
2375
  exports.useChatLayout = useChatLayout;
2255
2376
  exports.useChatScroll = useChatScroll;
2256
- //# sourceMappingURL=chunk-NRXYYO5V.cjs.map
2257
- //# sourceMappingURL=chunk-NRXYYO5V.cjs.map
2377
+ //# sourceMappingURL=chunk-5T4K3VUV.cjs.map
2378
+ //# sourceMappingURL=chunk-5T4K3VUV.cjs.map