MCPcopy Create free account
hub / github.com/Qinbf/groundmap / ChatPanel

Function ChatPanel

tools/debug-console/components/ChatPanel.tsx:58–489  ·  view source on GitHub ↗
({
  provider,
  model,
  system,
  toolBudget,
  mode,
  workspace,
  onOpenRef,
  onOpenNode,
}: Props)

Source from the content-addressed store, hash-verified

56 | { kind: "ref-validation"; broken: string[]; unread: string[]; downgraded?: string[] };
57
58export function ChatPanel({
59 provider,
60 model,
61 system,
62 toolBudget,
63 mode,
64 workspace,
65 onOpenRef,
66 onOpenNode,
67}: Props) {
68 const t = useT();
69 const [messages, setMessages] = useState<UIMessage[]>([]);
70 const [input, setInput] = useState("");
71 const [busy, setBusy] = useState(false);
72 const [view, setView] = useState<"chat" | "flow">("chat");
73 const scrollRef = useRef<HTMLDivElement>(null);
74 const abortRef = useRef<AbortController | null>(null);
75 // 「黏底」状态:仅当用户已经在底部时,流式增量才自动滚到底;
76 // 一旦用户往上滚查看历史,就停止自动滚动,避免被流式输出一直往下拽。
77 const stickToBottomRef = useRef(true);
78 const [showJumpToBottom, setShowJumpToBottom] = useState(false);
79
80 const latestAssistant =
81 [...messages].reverse().find((m) => m.role === "assistant") || null;
82 const hasToolCalls =
83 !!latestAssistant?.parts.some((p) => p.kind === "tool-call");
84 const latestUser =
85 [...messages].reverse().find((m) => m.role === "user") || null;
86 const latestUserText =
87 latestUser?.parts
88 .filter((p) => p.kind === "text")
89 .map((p) => (p as { text: string }).text)
90 .join("") || null;
91
92 // 流式增量到来时:只有「黏底」时才自动滚到底,否则保持用户当前阅读位置不动。
93 useEffect(() => {
94 if (!stickToBottomRef.current) return;
95 const el = scrollRef.current;
96 if (el) el.scrollTo({ top: el.scrollHeight });
97 }, [messages]);
98
99 // 监听用户滚动:距底 < 80px 视为「在底部」→ 继续黏底;往上滚则脱离黏底并显示「回到最新」。
100 const handleScroll = useCallback(() => {
101 const el = scrollRef.current;
102 if (!el) return;
103 const distanceFromBottom = el.scrollHeight - el.scrollTop - el.clientHeight;
104 const atBottom = distanceFromBottom < 80;
105 stickToBottomRef.current = atBottom;
106 setShowJumpToBottom(!atBottom);
107 }, []);
108
109 const jumpToBottom = useCallback(() => {
110 const el = scrollRef.current;
111 if (!el) return;
112 // 瞬时滚到底(非 smooth)——避免滚动动画途中 onScroll 把按钮短暂闪回。
113 el.scrollTo({ top: el.scrollHeight });
114 stickToBottomRef.current = true;
115 setShowJumpToBottom(false);

Callers

nothing calls this directly

Calls 2

useTFunction · 0.90
tFunction · 0.50

Tested by

no test coverage detected