@djangocfg/ui-tools 2.1.336 → 2.1.337

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