@blade-hq/agent-react 2610.0.0-beta.5 → 2610.0.0-beta.7

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.
@@ -3,6 +3,6 @@ interface Props {
3
3
  connection: ConnectionStatus;
4
4
  className?: string;
5
5
  }
6
- /** 连接状态提示条:数据来自 SessionState.connection,正常连接时不渲染。 */
6
+ /** 连接状态提示条:短暂断线静默,超过容错时间后再逐级提示。 */
7
7
  export declare function ConnectionBanner({ connection, className }: Props): import("react/jsx-runtime").JSX.Element | null;
8
8
  export {};
@@ -24,6 +24,7 @@ declare const BladeAgent: {
24
24
  SessionHub: typeof agentClient.SessionHub;
25
25
  SessionSetupError: typeof agentClient.SessionSetupError;
26
26
  createInitialSessionState: typeof agentClient.createInitialSessionState;
27
+ reconcileOptimisticUserTurns: typeof agentClient.reconcileOptimisticUserTurns;
27
28
  toReplaySnapshot: typeof agentClient.toReplaySnapshot;
28
29
  connectEmbedded: typeof agentClient.connectEmbedded;
29
30
  isCommandEnvelope: typeof agentClient.isCommandEnvelope;
package/dist/index.js CHANGED
@@ -854,7 +854,7 @@ var X = createLucideIcon("X", [
854
854
  ]);
855
855
 
856
856
  // src/components/AgentChat.tsx
857
- import { useCallback as useCallback7, useEffect as useEffect8, useMemo as useMemo8, useState as useState12 } from "react";
857
+ import { useCallback as useCallback7, useEffect as useEffect9, useMemo as useMemo8, useState as useState13 } from "react";
858
858
 
859
859
  // src/lib/utils.ts
860
860
  function cn(...inputs) {
@@ -1052,24 +1052,74 @@ function ChatInput({
1052
1052
  }
1053
1053
 
1054
1054
  // src/components/ConnectionBanner.tsx
1055
+ import { useEffect as useEffect3, useRef as useRef3, useState as useState4 } from "react";
1055
1056
  import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
1057
+ var CONNECTION_NOTICE_DELAY_MS = 3e3;
1058
+ var CONNECTION_ERROR_DELAY_MS = 15e3;
1059
+ function useConnectionNoticePhase(connected) {
1060
+ const [phase, setPhase] = useState4("hidden");
1061
+ const connectedRef = useRef3(connected);
1062
+ const timersRef = useRef3([]);
1063
+ connectedRef.current = connected;
1064
+ useEffect3(() => {
1065
+ const clearTimers = () => {
1066
+ for (const timer of timersRef.current) clearTimeout(timer);
1067
+ timersRef.current = [];
1068
+ };
1069
+ const startGracePeriod = () => {
1070
+ clearTimers();
1071
+ setPhase("hidden");
1072
+ timersRef.current = [
1073
+ setTimeout(() => setPhase("recovering"), CONNECTION_NOTICE_DELAY_MS),
1074
+ setTimeout(() => setPhase("failed"), CONNECTION_ERROR_DELAY_MS)
1075
+ ];
1076
+ };
1077
+ if (connected) {
1078
+ clearTimers();
1079
+ setPhase("hidden");
1080
+ } else {
1081
+ startGracePeriod();
1082
+ }
1083
+ const handleForeground = () => {
1084
+ if (!connectedRef.current) startGracePeriod();
1085
+ };
1086
+ const handleVisibilityChange = () => {
1087
+ if (document.visibilityState === "visible") handleForeground();
1088
+ };
1089
+ window.addEventListener("blade:app-active", handleForeground);
1090
+ window.addEventListener("focus", handleForeground);
1091
+ window.addEventListener("pageshow", handleForeground);
1092
+ document.addEventListener("visibilitychange", handleVisibilityChange);
1093
+ return () => {
1094
+ clearTimers();
1095
+ window.removeEventListener("blade:app-active", handleForeground);
1096
+ window.removeEventListener("focus", handleForeground);
1097
+ window.removeEventListener("pageshow", handleForeground);
1098
+ document.removeEventListener("visibilitychange", handleVisibilityChange);
1099
+ };
1100
+ }, [connected]);
1101
+ return phase;
1102
+ }
1056
1103
  function ConnectionBanner({ connection, className }) {
1057
- if (connection === "connected" || connection === "connecting") {
1058
- return null;
1059
- }
1060
- const reconnecting = connection === "reconnecting";
1104
+ const hasConnectedRef = useRef3(connection === "connected" || connection === "reconnecting");
1105
+ if (connection === "connected") hasConnectedRef.current = true;
1106
+ const connected = connection === "connected";
1107
+ const phase = useConnectionNoticePhase(connected);
1108
+ if (connected || phase === "hidden") return null;
1109
+ const recovering = phase === "recovering";
1110
+ const firstConnection = !hasConnectedRef.current;
1061
1111
  return /* @__PURE__ */ jsx5("div", { className: cn("blade-chat-banner bg-[hsl(var(--background))] px-5 pt-3", className), children: /* @__PURE__ */ jsxs4(
1062
1112
  "div",
1063
1113
  {
1064
1114
  className: cn(
1065
1115
  "mx-auto flex max-w-3xl items-start gap-3 rounded-2xl border px-4 py-3",
1066
- reconnecting ? "border-amber-500/25 bg-amber-500/10 text-amber-100" : "border-rose-500/25 bg-rose-500/10 text-rose-100"
1116
+ recovering ? "border-amber-500/25 bg-amber-500/10 text-amber-100" : "border-rose-500/25 bg-rose-500/10 text-rose-100"
1067
1117
  ),
1068
1118
  children: [
1069
- /* @__PURE__ */ jsx5("span", { className: "mt-0.5 shrink-0", children: reconnecting ? /* @__PURE__ */ jsx5(LoaderCircle, { size: 14, className: "animate-spin" }) : /* @__PURE__ */ jsx5(TriangleAlert, { size: 14 }) }),
1119
+ /* @__PURE__ */ jsx5("span", { className: "mt-0.5 shrink-0", children: recovering ? /* @__PURE__ */ jsx5(LoaderCircle, { size: 14, className: "animate-spin" }) : /* @__PURE__ */ jsx5(TriangleAlert, { size: 14 }) }),
1070
1120
  /* @__PURE__ */ jsxs4("div", { className: "min-w-0", children: [
1071
- /* @__PURE__ */ jsx5("div", { className: "text-sm font-medium", children: reconnecting ? "\u8FDE\u63A5\u5DF2\u65AD\u5F00\uFF0C\u6B63\u5728\u91CD\u8FDE\u2026" : "\u8FDE\u63A5\u5DF2\u65AD\u5F00" }),
1072
- /* @__PURE__ */ jsx5("div", { className: "text-xs opacity-80", children: "\u6D88\u606F\u540C\u6B65\u53EF\u80FD\u4F1A\u5EF6\u8FDF\uFF0C\u7CFB\u7EDF\u4F1A\u7EE7\u7EED\u81EA\u52A8\u91CD\u8BD5" })
1121
+ /* @__PURE__ */ jsx5("div", { className: "text-sm font-medium", children: recovering ? firstConnection ? "\u6B63\u5728\u8FDE\u63A5\u2026" : "\u6B63\u5728\u6062\u590D\u8FDE\u63A5\u2026" : "\u6682\u65F6\u65E0\u6CD5\u8FDE\u63A5" }),
1122
+ /* @__PURE__ */ jsx5("div", { className: "text-xs opacity-80", children: recovering ? "\u6062\u590D\u540E\u4F1A\u81EA\u52A8\u540C\u6B65\u6700\u65B0\u6D88\u606F\uFF0C\u8BF7\u7A0D\u5019" : "\u8BF7\u68C0\u67E5\u7F51\u7EDC\u6216\u670D\u52A1\u72B6\u6001\uFF0C\u7CFB\u7EDF\u4F1A\u7EE7\u7EED\u81EA\u52A8\u91CD\u8BD5" })
1073
1123
  ] })
1074
1124
  ]
1075
1125
  }
@@ -1078,10 +1128,10 @@ function ConnectionBanner({ connection, className }) {
1078
1128
 
1079
1129
  // src/components/MessageList.tsx
1080
1130
  import { isHiddenInternalMessage } from "@blade-hq/agent-client";
1081
- import { useCallback as useCallback6, useEffect as useEffect7, useMemo as useMemo7, useRef as useRef7, useState as useState11 } from "react";
1131
+ import { useCallback as useCallback6, useEffect as useEffect8, useMemo as useMemo7, useRef as useRef8, useState as useState12 } from "react";
1082
1132
 
1083
1133
  // ../../node_modules/.pnpm/use-stick-to-bottom@1.1.3_react@19.2.4/node_modules/use-stick-to-bottom/dist/useStickToBottom.js
1084
- import { useCallback as useCallback3, useMemo as useMemo3, useRef as useRef3, useState as useState4 } from "react";
1134
+ import { useCallback as useCallback3, useMemo as useMemo3, useRef as useRef4, useState as useState5 } from "react";
1085
1135
  var DEFAULT_SPRING_ANIMATION = {
1086
1136
  /**
1087
1137
  * A value from 0 to 1, on how much to damp the animation.
@@ -1118,10 +1168,10 @@ globalThis.document?.addEventListener("click", () => {
1118
1168
  mouseDown = false;
1119
1169
  });
1120
1170
  var useStickToBottom = (options = {}) => {
1121
- const [escapedFromLock, updateEscapedFromLock] = useState4(false);
1122
- const [isAtBottom, updateIsAtBottom] = useState4(options.initial !== false);
1123
- const [isNearBottom, setIsNearBottom] = useState4(false);
1124
- const optionsRef = useRef3(null);
1171
+ const [escapedFromLock, updateEscapedFromLock] = useState5(false);
1172
+ const [isAtBottom, updateIsAtBottom] = useState5(options.initial !== false);
1173
+ const [isNearBottom, setIsNearBottom] = useState5(false);
1174
+ const optionsRef = useRef4(null);
1125
1175
  optionsRef.current = options;
1126
1176
  const isSelecting = useCallback3(() => {
1127
1177
  if (!mouseDown) {
@@ -1425,11 +1475,11 @@ function mergeAnimations(...animations) {
1425
1475
 
1426
1476
  // ../../node_modules/.pnpm/use-stick-to-bottom@1.1.3_react@19.2.4/node_modules/use-stick-to-bottom/dist/StickToBottom.js
1427
1477
  import * as React from "react";
1428
- import { createContext as createContext2, useContext as useContext2, useEffect as useEffect3, useImperativeHandle, useLayoutEffect, useMemo as useMemo4, useRef as useRef4 } from "react";
1478
+ import { createContext as createContext2, useContext as useContext2, useEffect as useEffect4, useImperativeHandle, useLayoutEffect, useMemo as useMemo4, useRef as useRef5 } from "react";
1429
1479
  var StickToBottomContext = createContext2(null);
1430
- var useIsomorphicLayoutEffect = typeof window !== "undefined" ? useLayoutEffect : useEffect3;
1480
+ var useIsomorphicLayoutEffect = typeof window !== "undefined" ? useLayoutEffect : useEffect4;
1431
1481
  function StickToBottom({ instance, children, resize, initial, mass, damping, stiffness, targetScrollTop: currentTargetScrollTop, contextRef, ...props }) {
1432
- const customTargetScrollTop = useRef4(null);
1482
+ const customTargetScrollTop = useRef5(null);
1433
1483
  const targetScrollTop = React.useCallback((target, elements) => {
1434
1484
  const get = context?.targetScrollTop ?? currentTargetScrollTop;
1435
1485
  return get?.(target, elements) ?? target;
@@ -1506,10 +1556,10 @@ function useStickToBottomContext() {
1506
1556
 
1507
1557
  // src/components/AssistantTurnBlock.tsx
1508
1558
  import { getTextContent, normalizeMessageContent } from "@blade-hq/agent-client";
1509
- import { useState as useState9 } from "react";
1559
+ import { useState as useState10 } from "react";
1510
1560
 
1511
1561
  // src/components/AgentLoopBlock.tsx
1512
- import { useState as useState5 } from "react";
1562
+ import { useState as useState6 } from "react";
1513
1563
 
1514
1564
  // src/components/display-utils.ts
1515
1565
  var TOOL_NAME_ALIASES = {
@@ -1641,7 +1691,7 @@ function parseAgentDescription(argumentsJson) {
1641
1691
  }
1642
1692
  }
1643
1693
  function AgentLoopBlock({ toolCall }) {
1644
- const [expanded, setExpanded] = useState5(false);
1694
+ const [expanded, setExpanded] = useState6(false);
1645
1695
  const description = parseAgentDescription(toolCall.arguments);
1646
1696
  const running = toolCall.status === "pending" || toolCall.status === "awaiting_answer";
1647
1697
  const failed = toolCall.status === "error" || toolCall.status === "cancelled";
@@ -1706,18 +1756,18 @@ function AgentLoopBlock({ toolCall }) {
1706
1756
 
1707
1757
  // src/components/MarkdownContent.tsx
1708
1758
  import {
1709
- useEffect as useEffect4,
1759
+ useEffect as useEffect5,
1710
1760
  useMemo as useMemo5,
1711
- useRef as useRef5,
1712
- useState as useState6
1761
+ useRef as useRef6,
1762
+ useState as useState7
1713
1763
  } from "react";
1714
1764
  import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
1715
1765
  var SYSTEM_REMINDER_RE = /<system-reminder>[\s\S]*?<\/system-reminder>/gi;
1716
1766
  function CodeBlockPre({ children, node: _node, ...props }) {
1717
- const preRef = useRef5(null);
1718
- const [copied, setCopied] = useState6(false);
1719
- const [language, setLanguage] = useState6("");
1720
- useEffect4(() => {
1767
+ const preRef = useRef6(null);
1768
+ const [copied, setCopied] = useState7(false);
1769
+ const [language, setLanguage] = useState7("");
1770
+ useEffect5(() => {
1721
1771
  const codeEl = preRef.current?.querySelector("code");
1722
1772
  setLanguage(codeEl?.className.match(/language-(\S+)/)?.[1] ?? "");
1723
1773
  }, []);
@@ -1788,10 +1838,10 @@ function Shimmer({ children = "\u6B63\u5728\u601D\u8003...", className }) {
1788
1838
  }
1789
1839
 
1790
1840
  // src/components/ToolCallBlock.tsx
1791
- import { useState as useState8 } from "react";
1841
+ import { useState as useState9 } from "react";
1792
1842
 
1793
1843
  // src/components/AskUserQuestionBlock.tsx
1794
- import { useEffect as useEffect5, useMemo as useMemo6, useState as useState7 } from "react";
1844
+ import { useEffect as useEffect6, useMemo as useMemo6, useState as useState8 } from "react";
1795
1845
  import { jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
1796
1846
  function AskUserQuestionBlock({
1797
1847
  data,
@@ -1801,11 +1851,11 @@ function AskUserQuestionBlock({
1801
1851
  answerData,
1802
1852
  onAnswer
1803
1853
  }) {
1804
- const [selections, setSelections] = useState7(/* @__PURE__ */ new Map());
1805
- const [customTexts, setCustomTexts] = useState7(/* @__PURE__ */ new Map());
1806
- const [usingCustom, setUsingCustom] = useState7(/* @__PURE__ */ new Set());
1807
- const [submitted, setSubmitted] = useState7(false);
1808
- useEffect5(() => {
1854
+ const [selections, setSelections] = useState8(/* @__PURE__ */ new Map());
1855
+ const [customTexts, setCustomTexts] = useState8(/* @__PURE__ */ new Map());
1856
+ const [usingCustom, setUsingCustom] = useState8(/* @__PURE__ */ new Set());
1857
+ const [submitted, setSubmitted] = useState8(false);
1858
+ useEffect6(() => {
1809
1859
  if (sessionStatus === "failed" || sessionStatus === "interrupted") {
1810
1860
  setSubmitted(false);
1811
1861
  }
@@ -2132,7 +2182,7 @@ function ToolCallBlock({
2132
2182
  sessionStatus,
2133
2183
  renderer
2134
2184
  }) {
2135
- const [expanded, setExpanded] = useState8(false);
2185
+ const [expanded, setExpanded] = useState9(false);
2136
2186
  const normalizedName = formatToolName(toolCall.name);
2137
2187
  if (renderer) {
2138
2188
  const custom = renderer(toolCall);
@@ -2234,7 +2284,7 @@ function buildAskUserPayload(argumentsJson) {
2234
2284
  // src/components/AssistantTurnBlock.tsx
2235
2285
  import { jsx as jsx11, jsxs as jsxs9 } from "react/jsx-runtime";
2236
2286
  function ThinkingBlock({ reasoning, isStreaming }) {
2237
- const [open, setOpen] = useState9(false);
2287
+ const [open, setOpen] = useState10(false);
2238
2288
  return /* @__PURE__ */ jsxs9("div", { className: "blade-chat-thinking ml-4 text-sm", children: [
2239
2289
  /* @__PURE__ */ jsxs9(
2240
2290
  "button",
@@ -2386,7 +2436,7 @@ var RenderErrorBoundary = class extends Component {
2386
2436
  };
2387
2437
 
2388
2438
  // src/components/PostChatFollowupBlock.tsx
2389
- import { useCallback as useCallback5, useEffect as useEffect6, useRef as useRef6, useState as useState10 } from "react";
2439
+ import { useCallback as useCallback5, useEffect as useEffect7, useRef as useRef7, useState as useState11 } from "react";
2390
2440
  import { Fragment as Fragment2, jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
2391
2441
  function emitInteraction(callback, event) {
2392
2442
  try {
@@ -2409,7 +2459,7 @@ function ArtifactCard({
2409
2459
  onArtifactOpened
2410
2460
  }) {
2411
2461
  const client = useBladeClient();
2412
- const [downloading, setDownloading] = useState10(false);
2462
+ const [downloading, setDownloading] = useState11(false);
2413
2463
  const name = artifact.label || basename(artifact.target);
2414
2464
  if (artifact.kind === "link") {
2415
2465
  return /* @__PURE__ */ jsxs11(
@@ -2511,15 +2561,15 @@ function ResultFeedback({
2511
2561
  onFeedbackSaved
2512
2562
  }) {
2513
2563
  const client = useBladeClient();
2514
- const [saved, setSaved] = useState10(savedFeedback ?? null);
2515
- const [helpful, setHelpful] = useState10(savedFeedback?.helpful ?? null);
2516
- const [reason, setReason] = useState10(savedFeedback?.reason ?? null);
2517
- const [saving, setSaving] = useState10(false);
2518
- const [saveError, setSaveError] = useState10(false);
2519
- const reportedShown = useRef6(false);
2520
- const latestChoice = useRef6(null);
2564
+ const [saved, setSaved] = useState11(savedFeedback ?? null);
2565
+ const [helpful, setHelpful] = useState11(savedFeedback?.helpful ?? null);
2566
+ const [reason, setReason] = useState11(savedFeedback?.reason ?? null);
2567
+ const [saving, setSaving] = useState11(false);
2568
+ const [saveError, setSaveError] = useState11(false);
2569
+ const reportedShown = useRef7(false);
2570
+ const latestChoice = useRef7(null);
2521
2571
  const eligible = followup.feedback_eligible === true && Boolean(sessionId) && !isViewer;
2522
- useEffect6(() => {
2572
+ useEffect7(() => {
2523
2573
  if (!eligible || reportedShown.current) return;
2524
2574
  reportedShown.current = true;
2525
2575
  emitInteraction(onInteraction, {
@@ -2528,7 +2578,7 @@ function ResultFeedback({
2528
2578
  assistantEntryId: followup.assistant_entry_id
2529
2579
  });
2530
2580
  }, [eligible, followup.assistant_entry_id, onInteraction, sessionId]);
2531
- useEffect6(() => {
2581
+ useEffect7(() => {
2532
2582
  if (!savedFeedback || latestChoice.current) return;
2533
2583
  setSaved(savedFeedback);
2534
2584
  setHelpful(savedFeedback.helpful);
@@ -2640,14 +2690,14 @@ function PostChatFollowupBlock({
2640
2690
  savedFeedback,
2641
2691
  onFeedbackSaved
2642
2692
  }) {
2643
- const [expanded, setExpanded] = useState10(false);
2644
- const adopted = useRef6(/* @__PURE__ */ new Set());
2645
- const reportedSuggestions = useRef6(false);
2646
- const reportedArtifacts = useRef6(/* @__PURE__ */ new Set());
2647
- const openedArtifacts = useRef6(/* @__PURE__ */ new Set());
2693
+ const [expanded, setExpanded] = useState11(false);
2694
+ const adopted = useRef7(/* @__PURE__ */ new Set());
2695
+ const reportedSuggestions = useRef7(false);
2696
+ const reportedArtifacts = useRef7(/* @__PURE__ */ new Set());
2697
+ const openedArtifacts = useRef7(/* @__PURE__ */ new Set());
2648
2698
  const artifacts = followup.final_artifacts ?? [];
2649
2699
  const visibleArtifacts = expanded ? artifacts : artifacts.slice(0, 3);
2650
- useEffect6(() => {
2700
+ useEffect7(() => {
2651
2701
  if (!reportedSuggestions.current && followup.suggestions.length > 0) {
2652
2702
  reportedSuggestions.current = true;
2653
2703
  emitInteraction(onInteraction, {
@@ -2916,7 +2966,7 @@ function MessageList({
2916
2966
  blocks.push({
2917
2967
  type: "message",
2918
2968
  message,
2919
- key: message.entry_id ?? `${message.role}-${blocks.length}`
2969
+ key: message.render_id ?? message.entry_id ?? `${message.role}-${blocks.length}`
2920
2970
  });
2921
2971
  }
2922
2972
  flushAssistant();
@@ -3021,8 +3071,8 @@ function MessageList({
3021
3071
  }
3022
3072
  function AutoScrollOnUserSend({ userMessageCount }) {
3023
3073
  const { scrollToBottom } = useStickToBottomContext();
3024
- const previousCountRef = useRef7(userMessageCount);
3025
- useEffect7(() => {
3074
+ const previousCountRef = useRef8(userMessageCount);
3075
+ useEffect8(() => {
3026
3076
  if (userMessageCount > previousCountRef.current) {
3027
3077
  scrollToBottom("instant");
3028
3078
  }
@@ -3032,9 +3082,9 @@ function AutoScrollOnUserSend({ userMessageCount }) {
3032
3082
  }
3033
3083
  function ScrollToBottomButton() {
3034
3084
  const { isAtBottom, scrollToBottom } = useStickToBottomContext();
3035
- const [visible, setVisible] = useState11(false);
3036
- const hideTimerRef = useRef7(null);
3037
- useEffect7(() => {
3085
+ const [visible, setVisible] = useState12(false);
3086
+ const hideTimerRef = useRef8(null);
3087
+ useEffect8(() => {
3038
3088
  if (isAtBottom) {
3039
3089
  if (!hideTimerRef.current) {
3040
3090
  hideTimerRef.current = setTimeout(() => {
@@ -3185,8 +3235,8 @@ function isUnauthorizedError(error) {
3185
3235
  return error instanceof BladeApiError && error.status === 401;
3186
3236
  }
3187
3237
  function LoginCard({ client, onLoggedIn }) {
3188
- const [loggingIn, setLoggingIn] = useState12(false);
3189
- const [loginError, setLoginError] = useState12(null);
3238
+ const [loggingIn, setLoggingIn] = useState13(false);
3239
+ const [loginError, setLoginError] = useState13(null);
3190
3240
  const handleLogin = async () => {
3191
3241
  setLoggingIn(true);
3192
3242
  setLoginError(null);
@@ -3218,8 +3268,8 @@ function LoginCard({ client, onLoggedIn }) {
3218
3268
  }
3219
3269
  function AgentChat(props) {
3220
3270
  const client = useBladeClient();
3221
- const [attempt, setAttempt] = useState12(0);
3222
- const [needLogin, setNeedLogin] = useState12(() => !client.hasToken());
3271
+ const [attempt, setAttempt] = useState13(0);
3272
+ const [needLogin, setNeedLogin] = useState13(() => !client.hasToken());
3223
3273
  if (needLogin) {
3224
3274
  return /* @__PURE__ */ jsx17(
3225
3275
  "div",
@@ -3261,12 +3311,12 @@ function ChatSessionView({
3261
3311
  onSessionCreated
3262
3312
  });
3263
3313
  const replay = useReplay(session);
3264
- const [stopRequested, setStopRequested] = useState12(false);
3265
- const [inputText, setInputText] = useState12("");
3266
- const [resultFeedback, setResultFeedback] = useState12([]);
3314
+ const [stopRequested, setStopRequested] = useState13(false);
3315
+ const [inputText, setInputText] = useState13("");
3316
+ const [resultFeedback, setResultFeedback] = useState13([]);
3267
3317
  const resolvedSessionId = session?.sessionId;
3268
3318
  const isViewer = state?.viewerRole === "viewer";
3269
- useEffect8(() => {
3319
+ useEffect9(() => {
3270
3320
  setResultFeedback([]);
3271
3321
  if (!resolvedSessionId || isViewer) return;
3272
3322
  let cancelled = false;
@@ -3301,12 +3351,12 @@ function ChatSessionView({
3301
3351
  saved
3302
3352
  ]);
3303
3353
  }, []);
3304
- useEffect8(() => {
3354
+ useEffect9(() => {
3305
3355
  if (session) {
3306
3356
  onSessionReady?.(session);
3307
3357
  }
3308
3358
  }, [session, onSessionReady]);
3309
- useEffect8(() => {
3359
+ useEffect9(() => {
3310
3360
  if (!session) return;
3311
3361
  const offAttach = session.on("attachRequested", ({ label, content }) => {
3312
3362
  setInputText((prev) => `${prev ? `${prev}
@@ -3322,12 +3372,12 @@ ${content}`);
3322
3372
  offInsert();
3323
3373
  };
3324
3374
  }, [session]);
3325
- useEffect8(() => {
3375
+ useEffect9(() => {
3326
3376
  if (isUnauthorizedError(error)) {
3327
3377
  onUnauthorized();
3328
3378
  }
3329
3379
  }, [error, onUnauthorized]);
3330
- useEffect8(() => {
3380
+ useEffect9(() => {
3331
3381
  if (!session || !commands) return;
3332
3382
  const unsubscribes = Object.entries(commands).map(
3333
3383
  ([action, handler]) => session.onCommand(action, (payload) => handler(payload))
@@ -3398,10 +3448,10 @@ ${content}`);
3398
3448
  }
3399
3449
 
3400
3450
  // src/components/LlmChat.tsx
3401
- import { useEffect as useEffect9, useMemo as useMemo9, useState as useState14 } from "react";
3451
+ import { useEffect as useEffect10, useMemo as useMemo9, useState as useState15 } from "react";
3402
3452
 
3403
3453
  // src/components/LlmAdvancedSettings.tsx
3404
- import { useState as useState13 } from "react";
3454
+ import { useState as useState14 } from "react";
3405
3455
  import { jsx as jsx18, jsxs as jsxs16 } from "react/jsx-runtime";
3406
3456
  var FIELDS = [
3407
3457
  { id: "baseURL", label: "\u6A21\u578B\u670D\u52A1\u5730\u5740", placeholder: "http://\u5185\u7F51\u5730\u5740/v1" },
@@ -3448,8 +3498,8 @@ function writeOverride(settings, baseURL, override) {
3448
3498
  }
3449
3499
  function LlmAdvancedSettingsBar({ settings, defaults, override, onChange }) {
3450
3500
  const normalized = normalizeAdvanced(settings);
3451
- const [open, setOpen] = useState13(false);
3452
- const [draft, setDraft] = useState13(override);
3501
+ const [open, setOpen] = useState14(false);
3502
+ const [draft, setDraft] = useState14(override);
3453
3503
  if (!normalized) return null;
3454
3504
  const fields = FIELDS.filter((field) => normalized[field.id]);
3455
3505
  const dirty = Object.keys(override).length > 0;
@@ -3532,11 +3582,11 @@ function LlmChat({
3532
3582
  onOverrideChange,
3533
3583
  ...options
3534
3584
  }) {
3535
- const [override, setOverride] = useState14(() => readOverride(advanced, options.baseURL));
3585
+ const [override, setOverride] = useState15(() => readOverride(advanced, options.baseURL));
3536
3586
  const effective = { ...options, ...override };
3537
3587
  const { messages, isStreaming, error, send, stop, reset } = useLlmChat(effective);
3538
- const [inputText, setInputText] = useState14("");
3539
- const [stopRequested, setStopRequested] = useState14(false);
3588
+ const [inputText, setInputText] = useState15("");
3589
+ const [stopRequested, setStopRequested] = useState15(false);
3540
3590
  const handle = useMemo9(
3541
3591
  () => ({
3542
3592
  insertText: (text) => setInputText((prev) => prev ? `${prev}
@@ -3546,7 +3596,7 @@ ${text}` : text),
3546
3596
  }),
3547
3597
  [send, reset]
3548
3598
  );
3549
- useEffect9(() => {
3599
+ useEffect10(() => {
3550
3600
  onReady?.(handle);
3551
3601
  }, [handle, onReady]);
3552
3602
  return /* @__PURE__ */ jsx19(