@vegintech/langchain-react-agent 0.0.9 → 0.0.10

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/dist/index.d.mts CHANGED
@@ -241,6 +241,8 @@ interface AgentChatProps {
241
241
  agentState?: Record<string, unknown>;
242
242
  /** Agent 状态变化回调 */
243
243
  onAgentStateChange?: (state: Record<string, unknown>) => void;
244
+ /** 是否显示调试面板,默认 false。仅在开发环境生效 */
245
+ showDebug?: boolean;
244
246
  }
245
247
  /** AgentChat 组件对外暴露的方法 */
246
248
  interface AgentChatRef {
package/dist/index.mjs CHANGED
@@ -226,7 +226,7 @@ const renderMessageContent = (message, isLastMessage, isLoading, tools, toolExec
226
226
  children: /* @__PURE__ */ jsx(ReasoningContent, { content: message.reasoningContent })
227
227
  }),
228
228
  message.content && /* @__PURE__ */ jsx("div", {
229
- style: { marginTop: message.reasoningContent ? "8px" : 0 },
229
+ style: { marginTop: message.reasoningContent ? "8px" : "3px" },
230
230
  children: /* @__PURE__ */ jsx(Streamdown, {
231
231
  components: {
232
232
  p: CustomParagraph,
@@ -377,6 +377,443 @@ const MessageList = ({ messages, isLoading = false, className = "", tools, toolE
377
377
  });
378
378
  };
379
379
  //#endregion
380
+ //#region src/components/DebugPanel.tsx
381
+ const isDevelopment = () => {
382
+ if (typeof process !== "undefined" && process.env) return process.env.NODE_ENV === "development";
383
+ const viteEnv = import.meta.env;
384
+ if (typeof import.meta !== "undefined" && viteEnv) return viteEnv.DEV === true || viteEnv.MODE === "development";
385
+ return false;
386
+ };
387
+ function DebugPanel({ messages, streamState, visible = true }) {
388
+ if (!isDevelopment() || !visible) return null;
389
+ const [isOpen, setIsOpen] = useState(false);
390
+ const [activeTab, setActiveTab] = useState("messages");
391
+ const [expandedRows, setExpandedRows] = useState(/* @__PURE__ */ new Set());
392
+ const [buttonPos, setButtonPos] = useState({
393
+ x: 0,
394
+ y: 0
395
+ });
396
+ const [isDraggingButton, setIsDraggingButton] = useState(false);
397
+ const buttonDragRef = useRef(null);
398
+ const [dialogPos, setDialogPos] = useState({
399
+ x: -400,
400
+ y: -300
401
+ });
402
+ const [isDraggingDialog, setIsDraggingDialog] = useState(false);
403
+ const dialogDragRef = useRef(null);
404
+ const handleButtonMouseDown = useCallback((e) => {
405
+ e.preventDefault();
406
+ buttonDragRef.current = {
407
+ startX: e.clientX,
408
+ startY: e.clientY,
409
+ initialX: buttonPos.x,
410
+ initialY: buttonPos.y
411
+ };
412
+ setIsDraggingButton(true);
413
+ }, [buttonPos]);
414
+ const handleDialogMouseDown = useCallback((e) => {
415
+ if (!e.target.closest(".debug-panel-header")) return;
416
+ e.preventDefault();
417
+ dialogDragRef.current = {
418
+ startX: e.clientX,
419
+ startY: e.clientY,
420
+ initialX: dialogPos.x,
421
+ initialY: dialogPos.y
422
+ };
423
+ setIsDraggingDialog(true);
424
+ }, [dialogPos]);
425
+ useEffect(() => {
426
+ const handleMouseMove = (e) => {
427
+ if (isDraggingButton && buttonDragRef.current) {
428
+ const dx = e.clientX - buttonDragRef.current.startX;
429
+ const dy = e.clientY - buttonDragRef.current.startY;
430
+ setButtonPos({
431
+ x: buttonDragRef.current.initialX + dx,
432
+ y: buttonDragRef.current.initialY + dy
433
+ });
434
+ }
435
+ if (isDraggingDialog && dialogDragRef.current) {
436
+ const dx = e.clientX - dialogDragRef.current.startX;
437
+ const dy = e.clientY - dialogDragRef.current.startY;
438
+ setDialogPos({
439
+ x: dialogDragRef.current.initialX + dx,
440
+ y: dialogDragRef.current.initialY + dy
441
+ });
442
+ }
443
+ };
444
+ const handleMouseUp = () => {
445
+ setIsDraggingButton(false);
446
+ setIsDraggingDialog(false);
447
+ buttonDragRef.current = null;
448
+ dialogDragRef.current = null;
449
+ };
450
+ if (isDraggingButton || isDraggingDialog) {
451
+ document.addEventListener("mousemove", handleMouseMove);
452
+ document.addEventListener("mouseup", handleMouseUp);
453
+ }
454
+ return () => {
455
+ document.removeEventListener("mousemove", handleMouseMove);
456
+ document.removeEventListener("mouseup", handleMouseUp);
457
+ };
458
+ }, [isDraggingButton, isDraggingDialog]);
459
+ const formatJson = (data) => {
460
+ try {
461
+ return JSON.stringify(data, null, 2);
462
+ } catch {
463
+ return String(data);
464
+ }
465
+ };
466
+ const toggleRow = (index) => {
467
+ setExpandedRows((prev) => {
468
+ const next = new Set(prev);
469
+ if (next.has(index)) next.delete(index);
470
+ else next.add(index);
471
+ return next;
472
+ });
473
+ };
474
+ const getTypeTagStyle = (type) => {
475
+ const color = {
476
+ human: {
477
+ bg: "#e6f4ff",
478
+ color: "#0958d9"
479
+ },
480
+ ai: {
481
+ bg: "#f6ffed",
482
+ color: "#389e0d"
483
+ },
484
+ tool: {
485
+ bg: "#fff7e6",
486
+ color: "#d46b08"
487
+ },
488
+ system: {
489
+ bg: "#f9f0ff",
490
+ color: "#722ed1"
491
+ },
492
+ function: {
493
+ bg: "#fff2f0",
494
+ color: "#cf1322"
495
+ }
496
+ }[type || ""] || {
497
+ bg: "#f5f5f5",
498
+ color: "#666"
499
+ };
500
+ return {
501
+ display: "inline-block",
502
+ padding: "2px 8px",
503
+ borderRadius: "4px",
504
+ fontSize: "12px",
505
+ fontWeight: 500,
506
+ background: color.bg,
507
+ color: color.color
508
+ };
509
+ };
510
+ const formatContent = (content) => {
511
+ if (!content) return "-";
512
+ return content;
513
+ };
514
+ const buttonStyle = {
515
+ position: "fixed",
516
+ right: `${20 - buttonPos.x}px`,
517
+ bottom: `${20 - buttonPos.y}px`,
518
+ width: "48px",
519
+ height: "48px",
520
+ borderRadius: "50%",
521
+ background: "#1677ff",
522
+ color: "#fff",
523
+ border: "none",
524
+ cursor: isDraggingButton ? "grabbing" : "grab",
525
+ boxShadow: "0 4px 12px rgba(0, 0, 0, 0.15)",
526
+ display: "flex",
527
+ alignItems: "center",
528
+ justifyContent: "center",
529
+ fontSize: "20px",
530
+ zIndex: 9998,
531
+ transition: isDraggingButton ? "none" : "box-shadow 0.2s",
532
+ userSelect: "none"
533
+ };
534
+ const dialogStyle = {
535
+ position: "fixed",
536
+ right: `${20 - dialogPos.x}px`,
537
+ bottom: `${80 - dialogPos.y}px`,
538
+ width: "800px",
539
+ maxWidth: "90vw",
540
+ height: "600px",
541
+ maxHeight: "85vh",
542
+ background: "#fff",
543
+ borderRadius: "12px",
544
+ boxShadow: "0 8px 32px rgba(0, 0, 0, 0.2)",
545
+ zIndex: 9999,
546
+ display: "flex",
547
+ flexDirection: "column",
548
+ overflow: "hidden",
549
+ cursor: isDraggingDialog ? "grabbing" : "default",
550
+ userSelect: "none"
551
+ };
552
+ const headerStyle = {
553
+ padding: "12px 16px",
554
+ background: "#f5f5f5",
555
+ borderBottom: "1px solid #e8e8e8",
556
+ display: "flex",
557
+ alignItems: "center",
558
+ justifyContent: "space-between",
559
+ cursor: isDraggingDialog ? "grabbing" : "grab"
560
+ };
561
+ const tabContainerStyle = {
562
+ display: "flex",
563
+ gap: "8px"
564
+ };
565
+ const getTabStyle = (isActive) => ({
566
+ padding: "6px 16px",
567
+ borderRadius: "6px",
568
+ border: "none",
569
+ background: isActive ? "#1677ff" : "transparent",
570
+ color: isActive ? "#fff" : "#666",
571
+ cursor: "pointer",
572
+ fontSize: "14px",
573
+ transition: "all 0.2s"
574
+ });
575
+ const closeButtonStyle = {
576
+ width: "28px",
577
+ height: "28px",
578
+ borderRadius: "50%",
579
+ border: "none",
580
+ background: "#ff4d4f",
581
+ color: "#fff",
582
+ cursor: "pointer",
583
+ display: "flex",
584
+ alignItems: "center",
585
+ justifyContent: "center",
586
+ fontSize: "16px",
587
+ transition: "background 0.2s"
588
+ };
589
+ const contentStyle = {
590
+ flex: 1,
591
+ overflow: "auto",
592
+ padding: "16px",
593
+ background: "#fafafa"
594
+ };
595
+ const preStyle = {
596
+ margin: 0,
597
+ padding: "12px",
598
+ background: "#f8f9fa",
599
+ color: "#333",
600
+ borderRadius: "8px",
601
+ fontSize: "12px",
602
+ fontFamily: "\"Fira Code\", \"Monaco\", \"Consolas\", monospace",
603
+ lineHeight: 1.5,
604
+ overflow: "auto",
605
+ whiteSpace: "pre-wrap",
606
+ wordBreak: "break-word",
607
+ border: "1px solid #e8e8e8"
608
+ };
609
+ const statsStyle = {
610
+ padding: "8px 12px",
611
+ background: "#e6f4ff",
612
+ borderRadius: "6px",
613
+ marginBottom: "12px",
614
+ fontSize: "13px",
615
+ color: "#0958d9"
616
+ };
617
+ const tableStyle = {
618
+ width: "100%",
619
+ borderCollapse: "collapse",
620
+ fontSize: "13px",
621
+ background: "#fff",
622
+ borderRadius: "8px",
623
+ overflow: "hidden",
624
+ boxShadow: "0 1px 2px rgba(0, 0, 0, 0.05)"
625
+ };
626
+ const tableHeaderStyle = {
627
+ background: "#f5f5f5",
628
+ fontWeight: 600,
629
+ color: "#333",
630
+ textAlign: "left",
631
+ padding: "10px 12px",
632
+ borderBottom: "1px solid #e8e8e8",
633
+ whiteSpace: "nowrap"
634
+ };
635
+ const tableCellStyle = {
636
+ padding: "10px 12px",
637
+ borderBottom: "1px solid #f0f0f0",
638
+ verticalAlign: "top"
639
+ };
640
+ const expandButtonStyle = {
641
+ width: "20px",
642
+ height: "20px",
643
+ border: "none",
644
+ background: "transparent",
645
+ cursor: "pointer",
646
+ display: "flex",
647
+ alignItems: "center",
648
+ justifyContent: "center",
649
+ fontSize: "12px",
650
+ color: "#666",
651
+ borderRadius: "4px",
652
+ transition: "background 0.2s"
653
+ };
654
+ const expandedRowStyle = { background: "#fafafa" };
655
+ const jsonContainerStyle = {
656
+ padding: "12px",
657
+ background: "#fff",
658
+ borderRadius: "6px",
659
+ margin: "8px 0",
660
+ border: "1px solid #e8e8e8"
661
+ };
662
+ return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("button", {
663
+ style: buttonStyle,
664
+ onMouseDown: handleButtonMouseDown,
665
+ onClick: () => !isDraggingButton && setIsOpen(true),
666
+ title: "打开调试面板",
667
+ children: "🐛"
668
+ }), isOpen && /* @__PURE__ */ jsxs("div", {
669
+ style: dialogStyle,
670
+ onMouseDown: handleDialogMouseDown,
671
+ children: [/* @__PURE__ */ jsxs("div", {
672
+ className: "debug-panel-header",
673
+ style: headerStyle,
674
+ children: [/* @__PURE__ */ jsxs("div", {
675
+ style: tabContainerStyle,
676
+ children: [/* @__PURE__ */ jsxs("button", {
677
+ style: getTabStyle(activeTab === "messages"),
678
+ onClick: () => setActiveTab("messages"),
679
+ children: [
680
+ "Messages (",
681
+ messages.length,
682
+ ")"
683
+ ]
684
+ }), /* @__PURE__ */ jsx("button", {
685
+ style: getTabStyle(activeTab === "state"),
686
+ onClick: () => setActiveTab("state"),
687
+ children: "State"
688
+ })]
689
+ }), /* @__PURE__ */ jsx("button", {
690
+ style: closeButtonStyle,
691
+ onClick: () => setIsOpen(false),
692
+ title: "关闭",
693
+ children: "×"
694
+ })]
695
+ }), /* @__PURE__ */ jsx("div", {
696
+ style: contentStyle,
697
+ children: activeTab === "messages" ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs("div", {
698
+ style: statsStyle,
699
+ children: [
700
+ "共 ",
701
+ messages.length,
702
+ " 条消息"
703
+ ]
704
+ }), /* @__PURE__ */ jsxs("table", {
705
+ style: tableStyle,
706
+ children: [/* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { children: [
707
+ /* @__PURE__ */ jsx("th", { style: {
708
+ ...tableHeaderStyle,
709
+ width: "30px"
710
+ } }),
711
+ /* @__PURE__ */ jsx("th", {
712
+ style: {
713
+ ...tableHeaderStyle,
714
+ width: "60px"
715
+ },
716
+ children: "类型"
717
+ }),
718
+ /* @__PURE__ */ jsx("th", {
719
+ style: tableHeaderStyle,
720
+ children: "内容"
721
+ }),
722
+ /* @__PURE__ */ jsx("th", {
723
+ style: {
724
+ ...tableHeaderStyle,
725
+ width: "100px"
726
+ },
727
+ children: "ID"
728
+ })
729
+ ] }) }), /* @__PURE__ */ jsx("tbody", { children: messages.map((msg, index) => {
730
+ const message = msg;
731
+ const isExpanded = expandedRows.has(index);
732
+ return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs("tr", {
733
+ style: {
734
+ cursor: "pointer",
735
+ transition: "background 0.2s"
736
+ },
737
+ onClick: () => toggleRow(index),
738
+ onMouseEnter: (e) => {
739
+ e.currentTarget.style.background = "#f5f5f5";
740
+ },
741
+ onMouseLeave: (e) => {
742
+ e.currentTarget.style.background = "transparent";
743
+ },
744
+ children: [
745
+ /* @__PURE__ */ jsx("td", {
746
+ style: tableCellStyle,
747
+ children: /* @__PURE__ */ jsx("button", {
748
+ style: expandButtonStyle,
749
+ onClick: (e) => {
750
+ e.stopPropagation();
751
+ toggleRow(index);
752
+ },
753
+ children: isExpanded ? "▼" : "▶"
754
+ })
755
+ }),
756
+ /* @__PURE__ */ jsx("td", {
757
+ style: tableCellStyle,
758
+ children: /* @__PURE__ */ jsx("span", {
759
+ style: getTypeTagStyle(message.type),
760
+ children: message.type || "unknown"
761
+ })
762
+ }),
763
+ /* @__PURE__ */ jsx("td", {
764
+ style: tableCellStyle,
765
+ children: /* @__PURE__ */ jsx("div", {
766
+ style: {
767
+ color: "#333",
768
+ lineHeight: 1.5,
769
+ wordBreak: "break-all"
770
+ },
771
+ children: formatContent(message.content)
772
+ })
773
+ }),
774
+ /* @__PURE__ */ jsx("td", {
775
+ style: {
776
+ ...tableCellStyle,
777
+ color: "#999",
778
+ fontSize: "12px"
779
+ },
780
+ children: message.id?.slice(-8) || "-"
781
+ })
782
+ ]
783
+ }, index), isExpanded && /* @__PURE__ */ jsx("tr", {
784
+ style: expandedRowStyle,
785
+ children: /* @__PURE__ */ jsx("td", {
786
+ colSpan: 4,
787
+ style: {
788
+ padding: 0,
789
+ borderBottom: "1px solid #e8e8e8"
790
+ },
791
+ children: /* @__PURE__ */ jsx("div", {
792
+ style: jsonContainerStyle,
793
+ children: /* @__PURE__ */ jsx("pre", {
794
+ style: {
795
+ ...preStyle,
796
+ margin: 0,
797
+ maxHeight: "300px",
798
+ overflow: "auto"
799
+ },
800
+ children: formatJson(message)
801
+ })
802
+ })
803
+ })
804
+ })] });
805
+ }) })]
806
+ })] }) : /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs("div", {
807
+ style: statsStyle,
808
+ children: ["State 键数量: ", Object.keys(streamState).length]
809
+ }), /* @__PURE__ */ jsx("pre", {
810
+ style: preStyle,
811
+ children: formatJson(streamState)
812
+ })] })
813
+ })]
814
+ })] });
815
+ }
816
+ //#endregion
380
817
  //#region src/hooks/useInterrupt.tsx
381
818
  /**
382
819
  * InterruptManager - 管理 Interrupt 状态的 Hook
@@ -786,7 +1223,7 @@ function injectStyles() {
786
1223
  //#endregion
787
1224
  //#region src/components/AgentChat.tsx
788
1225
  injectStyles();
789
- const AgentChat = forwardRef(({ apiUrl, assistantId, headers, threadId: externalThreadId, onThreadIdChange, className = "", tools, contexts, messageConfig, inputConfig, onError, interruptConfig, agentState, onAgentStateChange }, ref) => {
1226
+ const AgentChat = forwardRef(({ apiUrl, assistantId, headers, threadId: externalThreadId, onThreadIdChange, className = "", tools, contexts, messageConfig, inputConfig, onError, interruptConfig, agentState, onAgentStateChange, showDebug }, ref) => {
790
1227
  const [internalThreadId, setInternalThreadId] = useState(externalThreadId);
791
1228
  useEffect(() => {
792
1229
  setInternalThreadId(externalThreadId);
@@ -901,33 +1338,41 @@ const AgentChat = forwardRef(({ apiUrl, assistantId, headers, threadId: external
901
1338
  });
902
1339
  return /* @__PURE__ */ jsxs("div", {
903
1340
  className: `agent-chat-container ${className}`,
904
- children: [/* @__PURE__ */ jsx(MessageList, {
905
- messages,
906
- isLoading: stream.isLoading,
907
- className: "agent-chat-messages",
908
- tools,
909
- toolExecutions,
910
- components: messageConfig?.components,
911
- securityConfig: {
912
- allowedTags: messageConfig?.allowedTags,
913
- literalTagContent: messageConfig?.literalTagContent
914
- },
915
- loadingColor: messageConfig?.loadingColor,
916
- interruptRender,
917
- emptyState: messageConfig?.emptyState
918
- }), /* @__PURE__ */ jsx(ChatInput, {
919
- ref: chatInputRef,
920
- onSend: handleSend,
921
- onStop: handleStop,
922
- isLoading: stream.isLoading,
923
- className: "agent-chat-input",
924
- footer,
925
- skill,
926
- slotConfig,
927
- header,
928
- prefix,
929
- placeholder
930
- })]
1341
+ children: [
1342
+ /* @__PURE__ */ jsx(MessageList, {
1343
+ messages,
1344
+ isLoading: stream.isLoading,
1345
+ className: "agent-chat-messages",
1346
+ tools,
1347
+ toolExecutions,
1348
+ components: messageConfig?.components,
1349
+ securityConfig: {
1350
+ allowedTags: messageConfig?.allowedTags,
1351
+ literalTagContent: messageConfig?.literalTagContent
1352
+ },
1353
+ loadingColor: messageConfig?.loadingColor,
1354
+ interruptRender,
1355
+ emptyState: messageConfig?.emptyState
1356
+ }),
1357
+ /* @__PURE__ */ jsx(ChatInput, {
1358
+ ref: chatInputRef,
1359
+ onSend: handleSend,
1360
+ onStop: handleStop,
1361
+ isLoading: stream.isLoading,
1362
+ className: "agent-chat-input",
1363
+ footer,
1364
+ skill,
1365
+ slotConfig,
1366
+ header,
1367
+ prefix,
1368
+ placeholder
1369
+ }),
1370
+ /* @__PURE__ */ jsx(DebugPanel, {
1371
+ messages: stream.messages,
1372
+ streamState: stream.values || {},
1373
+ visible: showDebug
1374
+ })
1375
+ ]
931
1376
  });
932
1377
  });
933
1378
  AgentChat.displayName = "AgentChat";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vegintech/langchain-react-agent",
3
- "version": "0.0.9",
3
+ "version": "0.0.10",
4
4
  "description": "LangChain Agent UI component library for React",
5
5
  "license": "MIT",
6
6
  "files": [
@@ -15,13 +15,6 @@
15
15
  "publishConfig": {
16
16
  "access": "public"
17
17
  },
18
- "scripts": {
19
- "build": "vp pack",
20
- "dev": "vp pack --watch",
21
- "test": "vp test",
22
- "check": "vp check",
23
- "prepublishOnly": "vp run build"
24
- },
25
18
  "dependencies": {
26
19
  "@ant-design/x": "^2.4.0",
27
20
  "@langchain/core": "^1.1.36",
@@ -43,5 +36,11 @@
43
36
  "peerDependencies": {
44
37
  "react": ">=18.0.0",
45
38
  "react-dom": ">=18.0.0"
39
+ },
40
+ "scripts": {
41
+ "build": "vp pack",
42
+ "dev": "vp pack --watch",
43
+ "test": "vp test",
44
+ "check": "vp check"
46
45
  }
47
- }
46
+ }