@blade-hq/agent-react 2610.0.0-beta.33 → 2610.0.0-beta.34
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.js
CHANGED
|
@@ -1144,7 +1144,7 @@ var X = createLucideIcon("X", [
|
|
|
1144
1144
|
]);
|
|
1145
1145
|
|
|
1146
1146
|
// src/components/AgentChat.tsx
|
|
1147
|
-
import { useCallback as useCallback8, useEffect as
|
|
1147
|
+
import { useCallback as useCallback8, useEffect as useEffect13, useMemo as useMemo8, useState as useState15 } from "react";
|
|
1148
1148
|
|
|
1149
1149
|
// src/lib/utils.ts
|
|
1150
1150
|
function cn(...inputs) {
|
|
@@ -1613,7 +1613,8 @@ function CurrentPlanPanel({
|
|
|
1613
1613
|
import { chatErrorForDisplay as chatErrorForDisplay2 } from "@blade-hq/agent-client";
|
|
1614
1614
|
|
|
1615
1615
|
// src/components/ChatInput.tsx
|
|
1616
|
-
import {
|
|
1616
|
+
import { useEffect as useEffect5, useRef as useRef5, useState as useState5 } from "react";
|
|
1617
|
+
import { Fragment, jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
1617
1618
|
function isImeCompositionKey(event) {
|
|
1618
1619
|
return event.isComposing || event.keyCode === 229;
|
|
1619
1620
|
}
|
|
@@ -1624,16 +1625,55 @@ function ChatInput({
|
|
|
1624
1625
|
value,
|
|
1625
1626
|
onValueChange,
|
|
1626
1627
|
onSend,
|
|
1628
|
+
onAppend,
|
|
1627
1629
|
onStop,
|
|
1628
1630
|
isStreaming,
|
|
1629
1631
|
isStopping = false,
|
|
1630
1632
|
placeholder = "\u8F93\u5165\u6D88\u606F\u2026",
|
|
1631
|
-
className
|
|
1633
|
+
className,
|
|
1634
|
+
queueKey
|
|
1632
1635
|
}) {
|
|
1633
1636
|
const trimmed = value.trim();
|
|
1634
|
-
const
|
|
1637
|
+
const [sendMode, setSendMode] = useState5("direct");
|
|
1638
|
+
const [promptQueue, setPromptQueue] = useState5([]);
|
|
1639
|
+
const queueSendingRef = useRef5(false);
|
|
1640
|
+
const queueBlockedRef = useRef5(false);
|
|
1641
|
+
const previousQueueKeyRef = useRef5(queueKey);
|
|
1642
|
+
useEffect5(() => {
|
|
1643
|
+
if (previousQueueKeyRef.current === queueKey) return;
|
|
1644
|
+
previousQueueKeyRef.current = queueKey;
|
|
1645
|
+
setPromptQueue([]);
|
|
1646
|
+
queueBlockedRef.current = false;
|
|
1647
|
+
}, [queueKey]);
|
|
1648
|
+
const canSend = trimmed.length > 0 && (!isStreaming || sendMode === "queue");
|
|
1649
|
+
useEffect5(() => {
|
|
1650
|
+
if (isStreaming) {
|
|
1651
|
+
queueBlockedRef.current = false;
|
|
1652
|
+
return;
|
|
1653
|
+
}
|
|
1654
|
+
if (queueBlockedRef.current || promptQueue.length === 0 || queueSendingRef.current) return;
|
|
1655
|
+
const next = promptQueue[0];
|
|
1656
|
+
queueSendingRef.current = true;
|
|
1657
|
+
Promise.resolve().then(() => onSend(next)).then((accepted) => {
|
|
1658
|
+
if (accepted) setPromptQueue((current) => current.slice(1));
|
|
1659
|
+
else queueBlockedRef.current = true;
|
|
1660
|
+
}).finally(() => {
|
|
1661
|
+
queueSendingRef.current = false;
|
|
1662
|
+
});
|
|
1663
|
+
}, [isStreaming, onSend, promptQueue]);
|
|
1635
1664
|
const handleSend = async () => {
|
|
1636
1665
|
if (!canSend) return;
|
|
1666
|
+
if (isStreaming && sendMode === "queue") {
|
|
1667
|
+
setPromptQueue((current) => [...current, trimmed]);
|
|
1668
|
+
onValueChange("");
|
|
1669
|
+
return;
|
|
1670
|
+
}
|
|
1671
|
+
if (isStreaming && sendMode === "direct") {
|
|
1672
|
+
if (!onAppend) return;
|
|
1673
|
+
onAppend(trimmed);
|
|
1674
|
+
onValueChange("");
|
|
1675
|
+
return;
|
|
1676
|
+
}
|
|
1637
1677
|
const accepted = await onSend(trimmed);
|
|
1638
1678
|
if (!accepted) return;
|
|
1639
1679
|
onValueChange("");
|
|
@@ -1649,61 +1689,73 @@ function ChatInput({
|
|
|
1649
1689
|
void handleSend();
|
|
1650
1690
|
}
|
|
1651
1691
|
};
|
|
1652
|
-
return /* @__PURE__ */
|
|
1653
|
-
/* @__PURE__ */
|
|
1654
|
-
"
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
children: /* @__PURE__ */ jsx5(ArrowUp, { size: 15 })
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1692
|
+
return /* @__PURE__ */ jsxs4("div", { className: cn("blade-chat-input border-t border-[hsl(var(--border))] py-3", className), children: [
|
|
1693
|
+
/* @__PURE__ */ jsxs4("div", { className: "mx-auto mb-2 flex max-w-[748px] items-center justify-between px-1 text-xs text-[hsl(var(--muted-foreground))]", children: [
|
|
1694
|
+
/* @__PURE__ */ jsxs4("fieldset", { className: "flex items-center gap-1 rounded-md border border-[hsl(var(--border))] p-0.5", children: [
|
|
1695
|
+
/* @__PURE__ */ jsx5("legend", { className: "sr-only", children: "\u53D1\u9001\u65B9\u5F0F" }),
|
|
1696
|
+
/* @__PURE__ */ jsx5("button", { type: "button", onClick: () => setSendMode("direct"), "aria-pressed": sendMode === "direct", disabled: isStreaming && !onAppend, className: `rounded px-2 py-1 ${sendMode === "direct" ? "bg-[hsl(var(--accent))] text-[hsl(var(--foreground))]" : ""}`, children: "\u76F4\u63A5\u63D2\u5165" }),
|
|
1697
|
+
/* @__PURE__ */ jsx5("button", { type: "button", onClick: () => setSendMode("queue"), "aria-pressed": sendMode === "queue", className: `rounded px-2 py-1 ${sendMode === "queue" ? "bg-[hsl(var(--accent))] text-[hsl(var(--foreground))]" : ""}`, children: "\u6392\u961F\u6267\u884C" })
|
|
1698
|
+
] }),
|
|
1699
|
+
promptQueue.length > 0 ? /* @__PURE__ */ jsxs4("details", { className: "relative", children: [
|
|
1700
|
+
/* @__PURE__ */ jsxs4("summary", { className: "cursor-pointer list-none rounded px-2 py-1 hover:bg-[hsl(var(--accent))]", children: [
|
|
1701
|
+
"\u5F85\u6267\u884C ",
|
|
1702
|
+
promptQueue.length,
|
|
1703
|
+
" \u6761"
|
|
1704
|
+
] }),
|
|
1705
|
+
/* @__PURE__ */ jsx5("div", { className: "absolute bottom-full right-0 z-20 mb-2 w-64 rounded-lg border border-[hsl(var(--border))] bg-[hsl(var(--card))] p-2 shadow-lg", children: promptQueue.map((item, index) => /* @__PURE__ */ jsxs4("div", { className: "flex gap-2 border-b border-[hsl(var(--border))] py-2 last:border-0", children: [
|
|
1706
|
+
/* @__PURE__ */ jsx5("span", { className: "min-w-0 flex-1 truncate", children: item }),
|
|
1707
|
+
/* @__PURE__ */ jsx5("button", { type: "button", onClick: () => setPromptQueue((current) => current.filter((_, i) => i !== index)), children: "\u53D6\u6D88" })
|
|
1708
|
+
] }, `${index}-${item}`)) })
|
|
1709
|
+
] }) : null
|
|
1710
|
+
] }),
|
|
1711
|
+
/* @__PURE__ */ jsxs4("div", { className: "blade-chat-input-inner mx-auto flex max-w-[748px] items-end gap-2 rounded-2xl border border-[hsl(var(--border))] bg-[hsl(var(--card))] px-3 py-2", children: [
|
|
1712
|
+
/* @__PURE__ */ jsx5(
|
|
1713
|
+
"textarea",
|
|
1714
|
+
{
|
|
1715
|
+
value,
|
|
1716
|
+
onChange: (event) => onValueChange(event.target.value),
|
|
1717
|
+
onKeyDown: handleKeyDown,
|
|
1718
|
+
onInput: (event) => {
|
|
1719
|
+
const el = event.currentTarget;
|
|
1720
|
+
el.style.height = "auto";
|
|
1721
|
+
el.style.height = `${Math.min(el.scrollHeight, 192)}px`;
|
|
1722
|
+
},
|
|
1723
|
+
rows: 1,
|
|
1724
|
+
placeholder,
|
|
1725
|
+
"aria-label": "\u804A\u5929\u8F93\u5165",
|
|
1726
|
+
className: "blade-chat-textarea max-h-48 min-h-[28px] flex-1 resize-none bg-transparent py-1 text-sm leading-6 text-[hsl(var(--foreground))] outline-none placeholder:text-[hsl(var(--muted-foreground)/0.6)]"
|
|
1727
|
+
}
|
|
1728
|
+
),
|
|
1729
|
+
isStreaming ? /* @__PURE__ */ jsxs4(Fragment, { children: [
|
|
1730
|
+
sendMode === "queue" ? /* @__PURE__ */ jsx5("button", { type: "button", onClick: handleSend, disabled: !canSend, "aria-label": "\u52A0\u5165\u6392\u961F", title: "\u52A0\u5165\u6392\u961F", className: "flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-[hsl(var(--primary))] text-[hsl(var(--primary-foreground))] disabled:opacity-40", children: /* @__PURE__ */ jsx5(ArrowUp, { size: 15 }) }) : null,
|
|
1731
|
+
/* @__PURE__ */ jsx5("button", { type: "button", onClick: onStop, disabled: isStopping, "aria-label": isStopping ? "\u6B63\u5728\u505C\u6B62" : "\u505C\u6B62\u56DE\u590D", title: isStopping ? "\u6B63\u5728\u505C\u6B62" : "\u505C\u6B62\u56DE\u590D", className: "flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-[hsl(var(--muted))] text-[hsl(var(--foreground))] transition-opacity hover:opacity-90 disabled:opacity-60", children: isStopping ? /* @__PURE__ */ jsx5(LoaderCircle, { size: 14, className: "animate-spin" }) : /* @__PURE__ */ jsx5(Square, { size: 12, fill: "currentColor" }) })
|
|
1732
|
+
] }) : /* @__PURE__ */ jsx5(
|
|
1733
|
+
"button",
|
|
1734
|
+
{
|
|
1735
|
+
type: "button",
|
|
1736
|
+
onClick: handleSend,
|
|
1737
|
+
disabled: !canSend,
|
|
1738
|
+
"aria-label": "\u53D1\u9001\u6D88\u606F",
|
|
1739
|
+
title: "\u53D1\u9001\u6D88\u606F",
|
|
1740
|
+
className: "flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-[hsl(var(--primary))] text-[hsl(var(--primary-foreground))] transition-opacity hover:opacity-90 disabled:cursor-not-allowed disabled:opacity-40",
|
|
1741
|
+
children: /* @__PURE__ */ jsx5(ArrowUp, { size: 15 })
|
|
1742
|
+
}
|
|
1743
|
+
)
|
|
1744
|
+
] })
|
|
1745
|
+
] });
|
|
1694
1746
|
}
|
|
1695
1747
|
|
|
1696
1748
|
// src/components/ConnectionBanner.tsx
|
|
1697
|
-
import { useEffect as
|
|
1749
|
+
import { useEffect as useEffect6, useRef as useRef6, useState as useState6 } from "react";
|
|
1698
1750
|
import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
1699
1751
|
var CONNECTION_NOTICE_DELAY_MS = 3e3;
|
|
1700
1752
|
var CONNECTION_ERROR_DELAY_MS = 15e3;
|
|
1701
1753
|
function useConnectionNoticePhase(connected) {
|
|
1702
|
-
const [phase, setPhase] =
|
|
1703
|
-
const connectedRef =
|
|
1704
|
-
const timersRef =
|
|
1754
|
+
const [phase, setPhase] = useState6("hidden");
|
|
1755
|
+
const connectedRef = useRef6(connected);
|
|
1756
|
+
const timersRef = useRef6([]);
|
|
1705
1757
|
connectedRef.current = connected;
|
|
1706
|
-
|
|
1758
|
+
useEffect6(() => {
|
|
1707
1759
|
const clearTimers = () => {
|
|
1708
1760
|
for (const timer of timersRef.current) clearTimeout(timer);
|
|
1709
1761
|
timersRef.current = [];
|
|
@@ -1743,7 +1795,7 @@ function useConnectionNoticePhase(connected) {
|
|
|
1743
1795
|
return phase;
|
|
1744
1796
|
}
|
|
1745
1797
|
function ConnectionBanner({ connection, className }) {
|
|
1746
|
-
const hasConnectedRef =
|
|
1798
|
+
const hasConnectedRef = useRef6(connection === "connected" || connection === "reconnecting");
|
|
1747
1799
|
if (connection === "connected") hasConnectedRef.current = true;
|
|
1748
1800
|
const connected = connection === "connected";
|
|
1749
1801
|
const phase = useConnectionNoticePhase(connected);
|
|
@@ -1770,10 +1822,10 @@ function ConnectionBanner({ connection, className }) {
|
|
|
1770
1822
|
|
|
1771
1823
|
// src/components/MessageList.tsx
|
|
1772
1824
|
import { isHiddenInternalMessage } from "@blade-hq/agent-client";
|
|
1773
|
-
import { useCallback as useCallback7, useEffect as
|
|
1825
|
+
import { useCallback as useCallback7, useEffect as useEffect12, useMemo as useMemo7, useRef as useRef13, useState as useState14 } from "react";
|
|
1774
1826
|
|
|
1775
1827
|
// ../../node_modules/.pnpm/use-stick-to-bottom@1.1.3_react@19.2.4/node_modules/use-stick-to-bottom/dist/useStickToBottom.js
|
|
1776
|
-
import { useCallback as useCallback4, useMemo as useMemo3, useRef as
|
|
1828
|
+
import { useCallback as useCallback4, useMemo as useMemo3, useRef as useRef7, useState as useState7 } from "react";
|
|
1777
1829
|
var DEFAULT_SPRING_ANIMATION = {
|
|
1778
1830
|
/**
|
|
1779
1831
|
* A value from 0 to 1, on how much to damp the animation.
|
|
@@ -1810,10 +1862,10 @@ globalThis.document?.addEventListener("click", () => {
|
|
|
1810
1862
|
mouseDown = false;
|
|
1811
1863
|
});
|
|
1812
1864
|
var useStickToBottom = (options = {}) => {
|
|
1813
|
-
const [escapedFromLock, updateEscapedFromLock] =
|
|
1814
|
-
const [isAtBottom, updateIsAtBottom] =
|
|
1815
|
-
const [isNearBottom, setIsNearBottom] =
|
|
1816
|
-
const optionsRef =
|
|
1865
|
+
const [escapedFromLock, updateEscapedFromLock] = useState7(false);
|
|
1866
|
+
const [isAtBottom, updateIsAtBottom] = useState7(options.initial !== false);
|
|
1867
|
+
const [isNearBottom, setIsNearBottom] = useState7(false);
|
|
1868
|
+
const optionsRef = useRef7(null);
|
|
1817
1869
|
optionsRef.current = options;
|
|
1818
1870
|
const isSelecting = useCallback4(() => {
|
|
1819
1871
|
if (!mouseDown) {
|
|
@@ -2117,11 +2169,11 @@ function mergeAnimations(...animations) {
|
|
|
2117
2169
|
|
|
2118
2170
|
// ../../node_modules/.pnpm/use-stick-to-bottom@1.1.3_react@19.2.4/node_modules/use-stick-to-bottom/dist/StickToBottom.js
|
|
2119
2171
|
import * as React from "react";
|
|
2120
|
-
import { createContext as createContext2, useContext as useContext2, useEffect as
|
|
2172
|
+
import { createContext as createContext2, useContext as useContext2, useEffect as useEffect7, useImperativeHandle, useLayoutEffect, useMemo as useMemo4, useRef as useRef8 } from "react";
|
|
2121
2173
|
var StickToBottomContext = createContext2(null);
|
|
2122
|
-
var useIsomorphicLayoutEffect = typeof window !== "undefined" ? useLayoutEffect :
|
|
2174
|
+
var useIsomorphicLayoutEffect = typeof window !== "undefined" ? useLayoutEffect : useEffect7;
|
|
2123
2175
|
function StickToBottom({ instance, children, resize, initial, mass, damping, stiffness, targetScrollTop: currentTargetScrollTop, contextRef, ...props }) {
|
|
2124
|
-
const customTargetScrollTop =
|
|
2176
|
+
const customTargetScrollTop = useRef8(null);
|
|
2125
2177
|
const targetScrollTop = React.useCallback((target, elements) => {
|
|
2126
2178
|
const get = context?.targetScrollTop ?? currentTargetScrollTop;
|
|
2127
2179
|
return get?.(target, elements) ?? target;
|
|
@@ -2203,10 +2255,10 @@ import {
|
|
|
2203
2255
|
getTextContent,
|
|
2204
2256
|
normalizeMessageContent
|
|
2205
2257
|
} from "@blade-hq/agent-client";
|
|
2206
|
-
import { useEffect as
|
|
2258
|
+
import { useEffect as useEffect10, useRef as useRef11, useState as useState12 } from "react";
|
|
2207
2259
|
|
|
2208
2260
|
// src/components/AgentLoopBlock.tsx
|
|
2209
|
-
import { useState as
|
|
2261
|
+
import { useState as useState8 } from "react";
|
|
2210
2262
|
import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
2211
2263
|
function parseAgentDescription(argumentsJson) {
|
|
2212
2264
|
try {
|
|
@@ -2217,7 +2269,7 @@ function parseAgentDescription(argumentsJson) {
|
|
|
2217
2269
|
}
|
|
2218
2270
|
}
|
|
2219
2271
|
function AgentLoopBlock({ toolCall }) {
|
|
2220
|
-
const [expanded, setExpanded] =
|
|
2272
|
+
const [expanded, setExpanded] = useState8(false);
|
|
2221
2273
|
const description = parseAgentDescription(toolCall.arguments);
|
|
2222
2274
|
const running = toolCall.status === "pending" || toolCall.status === "awaiting_answer";
|
|
2223
2275
|
const failed = toolCall.status === "error" || toolCall.status === "cancelled";
|
|
@@ -2268,10 +2320,10 @@ function AgentLoopBlock({ toolCall }) {
|
|
|
2268
2320
|
|
|
2269
2321
|
// src/components/MarkdownContent.tsx
|
|
2270
2322
|
import {
|
|
2271
|
-
useEffect as
|
|
2323
|
+
useEffect as useEffect8,
|
|
2272
2324
|
useMemo as useMemo5,
|
|
2273
|
-
useRef as
|
|
2274
|
-
useState as
|
|
2325
|
+
useRef as useRef9,
|
|
2326
|
+
useState as useState9
|
|
2275
2327
|
} from "react";
|
|
2276
2328
|
import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
2277
2329
|
var SYSTEM_REMINDER_RE = /<system-reminder>[\s\S]*?<\/system-reminder>/gi;
|
|
@@ -2288,10 +2340,10 @@ function normalizeAdjacentUrlFormatting(value) {
|
|
|
2288
2340
|
return normalized.replace(/blade-url-protected-(\d+)-marker/g, (_, index) => protectedSegments[Number(index)]);
|
|
2289
2341
|
}
|
|
2290
2342
|
function CodeBlockPre({ children, node: _node, ...props }) {
|
|
2291
|
-
const preRef =
|
|
2292
|
-
const [copied, setCopied] =
|
|
2293
|
-
const [language, setLanguage] =
|
|
2294
|
-
|
|
2343
|
+
const preRef = useRef9(null);
|
|
2344
|
+
const [copied, setCopied] = useState9(false);
|
|
2345
|
+
const [language, setLanguage] = useState9("");
|
|
2346
|
+
useEffect8(() => {
|
|
2295
2347
|
const codeEl = preRef.current?.querySelector("code");
|
|
2296
2348
|
setLanguage(codeEl?.className.match(/language-(\S+)/)?.[1] ?? "");
|
|
2297
2349
|
}, []);
|
|
@@ -2362,10 +2414,10 @@ function Shimmer({ children = "\u6B63\u5728\u601D\u8003...", className }) {
|
|
|
2362
2414
|
}
|
|
2363
2415
|
|
|
2364
2416
|
// src/components/ToolCallBlock.tsx
|
|
2365
|
-
import { useState as
|
|
2417
|
+
import { useState as useState11 } from "react";
|
|
2366
2418
|
|
|
2367
2419
|
// src/components/AskUserQuestionBlock.tsx
|
|
2368
|
-
import { useEffect as
|
|
2420
|
+
import { useEffect as useEffect9, useMemo as useMemo6, useRef as useRef10, useState as useState10 } from "react";
|
|
2369
2421
|
import { jsx as jsx10, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
2370
2422
|
var CUSTOM_TEXTAREA_MAX_HEIGHT = 160;
|
|
2371
2423
|
function resizeCustomTextarea(textarea) {
|
|
@@ -2374,12 +2426,12 @@ function resizeCustomTextarea(textarea) {
|
|
|
2374
2426
|
textarea.style.overflowY = textarea.scrollHeight > CUSTOM_TEXTAREA_MAX_HEIGHT ? "auto" : "hidden";
|
|
2375
2427
|
}
|
|
2376
2428
|
function useAutoResizeTextarea(value) {
|
|
2377
|
-
const textareaRef =
|
|
2378
|
-
|
|
2429
|
+
const textareaRef = useRef10(null);
|
|
2430
|
+
useEffect9(() => {
|
|
2379
2431
|
const textarea = textareaRef.current;
|
|
2380
2432
|
if (textarea?.value === value) resizeCustomTextarea(textarea);
|
|
2381
2433
|
}, [value]);
|
|
2382
|
-
|
|
2434
|
+
useEffect9(() => {
|
|
2383
2435
|
const textarea = textareaRef.current;
|
|
2384
2436
|
if (!textarea || typeof ResizeObserver === "undefined") return;
|
|
2385
2437
|
let previousWidth = textarea.clientWidth;
|
|
@@ -2404,12 +2456,12 @@ function AskUserQuestionBlock({
|
|
|
2404
2456
|
answerData,
|
|
2405
2457
|
onAnswer
|
|
2406
2458
|
}) {
|
|
2407
|
-
const [selections, setSelections] =
|
|
2408
|
-
const [customTexts, setCustomTexts] =
|
|
2409
|
-
const [usingCustom, setUsingCustom] =
|
|
2410
|
-
const [note, setNote] =
|
|
2411
|
-
const [submitted, setSubmitted] =
|
|
2412
|
-
|
|
2459
|
+
const [selections, setSelections] = useState10(/* @__PURE__ */ new Map());
|
|
2460
|
+
const [customTexts, setCustomTexts] = useState10(/* @__PURE__ */ new Map());
|
|
2461
|
+
const [usingCustom, setUsingCustom] = useState10(/* @__PURE__ */ new Set());
|
|
2462
|
+
const [note, setNote] = useState10("");
|
|
2463
|
+
const [submitted, setSubmitted] = useState10(false);
|
|
2464
|
+
useEffect9(() => {
|
|
2413
2465
|
if (sessionStatus === "failed" || sessionStatus === "interrupted") {
|
|
2414
2466
|
setSubmitted(false);
|
|
2415
2467
|
}
|
|
@@ -2798,7 +2850,7 @@ function normalizeOptionItem(value) {
|
|
|
2798
2850
|
}
|
|
2799
2851
|
|
|
2800
2852
|
// src/components/ToolCallBlock.tsx
|
|
2801
|
-
import { Fragment, jsx as jsx11, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
2853
|
+
import { Fragment as Fragment2, jsx as jsx11, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
2802
2854
|
function resolveAskQuestionState({
|
|
2803
2855
|
toolStatus,
|
|
2804
2856
|
hasAnswerData,
|
|
@@ -2820,12 +2872,12 @@ function ToolCallBlock({
|
|
|
2820
2872
|
isActiveQuestion,
|
|
2821
2873
|
renderer
|
|
2822
2874
|
}) {
|
|
2823
|
-
const [expanded, setExpanded] =
|
|
2875
|
+
const [expanded, setExpanded] = useState11(false);
|
|
2824
2876
|
const normalizedName = formatToolName(toolCall.name);
|
|
2825
2877
|
if (renderer) {
|
|
2826
2878
|
const custom = renderer(toolCall);
|
|
2827
2879
|
if (custom !== null && custom !== void 0) {
|
|
2828
|
-
return /* @__PURE__ */ jsx11(
|
|
2880
|
+
return /* @__PURE__ */ jsx11(Fragment2, { children: custom });
|
|
2829
2881
|
}
|
|
2830
2882
|
}
|
|
2831
2883
|
if (normalizedName === "AskUserQuestion") {
|
|
@@ -2908,7 +2960,7 @@ function ToolCallBlock({
|
|
|
2908
2960
|
/* @__PURE__ */ jsx11("div", { className: "mb-3 font-mono text-[11px] text-[hsl(var(--foreground))]", children: normalizedName }),
|
|
2909
2961
|
/* @__PURE__ */ jsx11("div", { className: "mb-1 text-[10px] uppercase tracking-wider text-[hsl(var(--muted-foreground))]", children: "\u53C2\u6570" }),
|
|
2910
2962
|
/* @__PURE__ */ jsx11("pre", { className: "overflow-x-auto whitespace-pre-wrap rounded-md bg-[hsl(var(--muted))] p-2 font-mono text-[11px] text-[hsl(var(--foreground))]", children: formatToolArgs(toolCall.arguments) }),
|
|
2911
|
-
toolCall.result != null && /* @__PURE__ */ jsxs9(
|
|
2963
|
+
toolCall.result != null && /* @__PURE__ */ jsxs9(Fragment2, { children: [
|
|
2912
2964
|
/* @__PURE__ */ jsx11("div", { className: "mb-1 mt-3 text-[10px] uppercase tracking-wider text-[hsl(var(--muted-foreground))]", children: "\u7ED3\u679C" }),
|
|
2913
2965
|
/* @__PURE__ */ jsx11("pre", { className: "max-h-[400px] overflow-auto whitespace-pre-wrap rounded-md bg-[hsl(var(--muted))] p-2 font-mono text-[11px] text-[hsl(var(--foreground))]", children: formatToolResult(toolCall.result) })
|
|
2914
2966
|
] })
|
|
@@ -2930,7 +2982,7 @@ function buildAskUserPayload(argumentsJson) {
|
|
|
2930
2982
|
// src/components/AssistantTurnBlock.tsx
|
|
2931
2983
|
import { jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
2932
2984
|
function ThinkingBlock({ reasoning, isStreaming }) {
|
|
2933
|
-
const [open, setOpen] =
|
|
2985
|
+
const [open, setOpen] = useState12(false);
|
|
2934
2986
|
if (!isStreaming) return null;
|
|
2935
2987
|
return /* @__PURE__ */ jsxs10("div", { className: "blade-chat-thinking text-xs", children: [
|
|
2936
2988
|
/* @__PURE__ */ jsxs10(
|
|
@@ -3200,12 +3252,12 @@ function AssistantTurnBlock({
|
|
|
3200
3252
|
)
|
|
3201
3253
|
);
|
|
3202
3254
|
const activeQuestionId = questionToolCalls.filter((toolCall) => toolCall.status === "pending").at(-1)?.id;
|
|
3203
|
-
const [displayMode, setDisplayMode] =
|
|
3255
|
+
const [displayMode, setDisplayMode] = useState12(
|
|
3204
3256
|
() => isStreaming || hasActionableToolCall ? "detail" : "compact"
|
|
3205
3257
|
);
|
|
3206
|
-
const userSelectedDisplayModeRef =
|
|
3207
|
-
const wasStreamingRef =
|
|
3208
|
-
|
|
3258
|
+
const userSelectedDisplayModeRef = useRef11(false);
|
|
3259
|
+
const wasStreamingRef = useRef11(isStreaming);
|
|
3260
|
+
useEffect10(() => {
|
|
3209
3261
|
if (wasStreamingRef.current && !isStreaming && !userSelectedDisplayModeRef.current) {
|
|
3210
3262
|
setDisplayMode(hasActionableToolCall ? "detail" : "compact");
|
|
3211
3263
|
}
|
|
@@ -3213,11 +3265,11 @@ function AssistantTurnBlock({
|
|
|
3213
3265
|
}, [hasActionableToolCall, isStreaming]);
|
|
3214
3266
|
const effectiveMode = resolveTurnDisplayMode({ isStreaming, displayMode });
|
|
3215
3267
|
const executionDurationMs = getExecutionDurationMs({ messages, isStreaming });
|
|
3216
|
-
const [clock, setClock] =
|
|
3268
|
+
const [clock, setClock] = useState12(() => Date.now());
|
|
3217
3269
|
const hasLiveStartTime = messages.some(
|
|
3218
3270
|
(message) => message.timestamp != null && Number.isFinite(Date.parse(message.timestamp))
|
|
3219
3271
|
);
|
|
3220
|
-
|
|
3272
|
+
useEffect10(() => {
|
|
3221
3273
|
if (!isStreaming || !hasLiveStartTime) return;
|
|
3222
3274
|
const timer = window.setInterval(() => setClock(Date.now()), 1e3);
|
|
3223
3275
|
return () => window.clearInterval(timer);
|
|
@@ -3392,7 +3444,7 @@ function collectMemoryRefs(messages) {
|
|
|
3392
3444
|
return [...refs.values()];
|
|
3393
3445
|
}
|
|
3394
3446
|
function MemoryRefsHint({ refs }) {
|
|
3395
|
-
const [expanded, setExpanded] =
|
|
3447
|
+
const [expanded, setExpanded] = useState12(false);
|
|
3396
3448
|
const label = refs.some((ref) => ref.skill_name) ? "\u53C2\u8003\u4E86\u8BE5\u6280\u80FD\u7684\u5386\u53F2\u7ECF\u9A8C" : "\u53C2\u8003\u4E86\u5386\u53F2\u7ECF\u9A8C";
|
|
3397
3449
|
return /* @__PURE__ */ jsxs10("div", { className: "blade-chat-memory-refs ml-1 w-full max-w-[680px]", children: [
|
|
3398
3450
|
/* @__PURE__ */ jsxs10("button", { type: "button", onClick: () => setExpanded((value) => !value), className: "inline-flex h-8 items-center gap-1.5 rounded-lg border border-[hsl(var(--primary)/0.22)] bg-[hsl(var(--primary)/0.07)] px-3 text-xs font-medium text-[hsl(var(--primary))]", children: [
|
|
@@ -3527,8 +3579,8 @@ var RenderErrorBoundary = class extends Component {
|
|
|
3527
3579
|
};
|
|
3528
3580
|
|
|
3529
3581
|
// src/components/PostChatFollowupBlock.tsx
|
|
3530
|
-
import { useCallback as useCallback6, useEffect as
|
|
3531
|
-
import { Fragment as
|
|
3582
|
+
import { useCallback as useCallback6, useEffect as useEffect11, useRef as useRef12, useState as useState13 } from "react";
|
|
3583
|
+
import { Fragment as Fragment3, jsx as jsx14, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
3532
3584
|
function emitInteraction(callback, event) {
|
|
3533
3585
|
try {
|
|
3534
3586
|
callback?.(event);
|
|
@@ -3547,7 +3599,7 @@ function ArtifactCard({
|
|
|
3547
3599
|
onArtifactOpened
|
|
3548
3600
|
}) {
|
|
3549
3601
|
const client = useBladeClient();
|
|
3550
|
-
const [downloading, setDownloading] =
|
|
3602
|
+
const [downloading, setDownloading] = useState13(false);
|
|
3551
3603
|
const name = artifact.label || basename(artifact.target);
|
|
3552
3604
|
if (artifact.kind === "link") {
|
|
3553
3605
|
return /* @__PURE__ */ jsxs12(
|
|
@@ -3653,15 +3705,15 @@ function ResultFeedback({
|
|
|
3653
3705
|
onFeedbackSaved
|
|
3654
3706
|
}) {
|
|
3655
3707
|
const client = useBladeClient();
|
|
3656
|
-
const [saved, setSaved] =
|
|
3657
|
-
const [helpful, setHelpful] =
|
|
3658
|
-
const [reason, setReason] =
|
|
3659
|
-
const [saving, setSaving] =
|
|
3660
|
-
const [saveError, setSaveError] =
|
|
3661
|
-
const reportedShown =
|
|
3662
|
-
const latestChoice =
|
|
3708
|
+
const [saved, setSaved] = useState13(savedFeedback ?? null);
|
|
3709
|
+
const [helpful, setHelpful] = useState13(savedFeedback?.helpful ?? null);
|
|
3710
|
+
const [reason, setReason] = useState13(savedFeedback?.reason ?? null);
|
|
3711
|
+
const [saving, setSaving] = useState13(false);
|
|
3712
|
+
const [saveError, setSaveError] = useState13(false);
|
|
3713
|
+
const reportedShown = useRef12(false);
|
|
3714
|
+
const latestChoice = useRef12(null);
|
|
3663
3715
|
const eligible = followup.feedback_eligible === true && Boolean(sessionId) && !isViewer;
|
|
3664
|
-
|
|
3716
|
+
useEffect11(() => {
|
|
3665
3717
|
if (!eligible || reportedShown.current) return;
|
|
3666
3718
|
reportedShown.current = true;
|
|
3667
3719
|
emitInteraction(onInteraction, {
|
|
@@ -3670,7 +3722,7 @@ function ResultFeedback({
|
|
|
3670
3722
|
assistantEntryId: followup.assistant_entry_id
|
|
3671
3723
|
});
|
|
3672
3724
|
}, [eligible, followup.assistant_entry_id, onInteraction, sessionId]);
|
|
3673
|
-
|
|
3725
|
+
useEffect11(() => {
|
|
3674
3726
|
if (!savedFeedback || latestChoice.current) return;
|
|
3675
3727
|
setSaved(savedFeedback);
|
|
3676
3728
|
setHelpful(savedFeedback.helpful);
|
|
@@ -3782,14 +3834,14 @@ function PostChatFollowupBlock({
|
|
|
3782
3834
|
savedFeedback,
|
|
3783
3835
|
onFeedbackSaved
|
|
3784
3836
|
}) {
|
|
3785
|
-
const [expanded, setExpanded] =
|
|
3786
|
-
const adopted =
|
|
3787
|
-
const reportedSuggestions =
|
|
3788
|
-
const reportedArtifacts =
|
|
3789
|
-
const openedArtifacts =
|
|
3837
|
+
const [expanded, setExpanded] = useState13(false);
|
|
3838
|
+
const adopted = useRef12(/* @__PURE__ */ new Set());
|
|
3839
|
+
const reportedSuggestions = useRef12(false);
|
|
3840
|
+
const reportedArtifacts = useRef12(/* @__PURE__ */ new Set());
|
|
3841
|
+
const openedArtifacts = useRef12(/* @__PURE__ */ new Set());
|
|
3790
3842
|
const artifacts = followup.final_artifacts ?? [];
|
|
3791
3843
|
const visibleArtifacts = expanded ? artifacts : artifacts.slice(0, 3);
|
|
3792
|
-
|
|
3844
|
+
useEffect11(() => {
|
|
3793
3845
|
if (!reportedSuggestions.current && followup.suggestions.length > 0) {
|
|
3794
3846
|
reportedSuggestions.current = true;
|
|
3795
3847
|
emitInteraction(onInteraction, {
|
|
@@ -3842,7 +3894,7 @@ function PostChatFollowupBlock({
|
|
|
3842
3894
|
"\u672C\u8F6E\u5C0F\u7ED3"
|
|
3843
3895
|
] }),
|
|
3844
3896
|
followup.recaption ? /* @__PURE__ */ jsx14("p", { className: "text-[13px] leading-5", children: followup.recaption }) : null,
|
|
3845
|
-
artifacts.length > 0 ? /* @__PURE__ */ jsxs12(
|
|
3897
|
+
artifacts.length > 0 ? /* @__PURE__ */ jsxs12(Fragment3, { children: [
|
|
3846
3898
|
/* @__PURE__ */ jsx14("div", { className: "grid max-w-full grid-cols-3 gap-1.5", children: visibleArtifacts.map((artifact, artifactIndex) => /* @__PURE__ */ jsx14(
|
|
3847
3899
|
ArtifactCard,
|
|
3848
3900
|
{
|
|
@@ -4100,8 +4152,16 @@ function MessageList({
|
|
|
4100
4152
|
resultFeedbackByEntry = /* @__PURE__ */ new Map(),
|
|
4101
4153
|
onResultFeedbackSaved
|
|
4102
4154
|
}) {
|
|
4103
|
-
const
|
|
4155
|
+
const visibleRootMessages = messages.filter((message) => {
|
|
4156
|
+
if ((message.loop_name ?? "root") !== "root") return false;
|
|
4157
|
+
if (isHiddenInternalMessage(message)) return false;
|
|
4158
|
+
if (message.kind === "context") return false;
|
|
4159
|
+
return message.role !== "tool" || getPlanningDividerKind(message) !== null;
|
|
4160
|
+
});
|
|
4161
|
+
const userMessages = visibleRootMessages.filter((message) => isUserMessage(message));
|
|
4104
4162
|
const latestUserMessage = userMessages.at(-1);
|
|
4163
|
+
const latestPromptText = latestUserMessage ? (typeof latestUserMessage.content === "string" ? latestUserMessage.content : latestUserMessage.content.filter((part) => part.type === "text").map((part) => part.text).join("")).replace(/\s+/g, " ").trim() : "";
|
|
4164
|
+
const latestPromptPreview = latestPromptText.length > 80 ? `${latestPromptText.slice(0, 80)}\u2026` : latestPromptText;
|
|
4105
4165
|
const shouldPinLatestUser = latestUserMessage != null && (latestUserMessage.entry_id == null || latestUserMessage.entry_id.startsWith("local-user-"));
|
|
4106
4166
|
const renderBlocks = useMemo7(() => {
|
|
4107
4167
|
const visible = messages.filter((message) => {
|
|
@@ -4186,78 +4246,90 @@ function MessageList({
|
|
|
4186
4246
|
initial: "instant",
|
|
4187
4247
|
resize: "instant",
|
|
4188
4248
|
children: [
|
|
4189
|
-
/* @__PURE__ */ jsx17(StickToBottom.Content, { className: "blade-chat-messages-scroll", children: /* @__PURE__ */
|
|
4190
|
-
|
|
4191
|
-
|
|
4192
|
-
|
|
4193
|
-
|
|
4194
|
-
|
|
4195
|
-
|
|
4196
|
-
|
|
4197
|
-
|
|
4198
|
-
if (block.type === "assistant_turn") {
|
|
4199
|
-
const blockFeedback = block.messages.map(
|
|
4200
|
-
(message) => message.entry_id ? resultFeedbackByEntry.get(message.entry_id) : void 0
|
|
4201
|
-
).find((feedback) => feedback != null);
|
|
4202
|
-
const hasActiveFollowup = Boolean(
|
|
4203
|
-
postChatFollowup && block.messages.some(
|
|
4204
|
-
(message) => message.entry_id === postChatFollowup.assistant_entry_id
|
|
4205
|
-
)
|
|
4206
|
-
);
|
|
4207
|
-
return /* @__PURE__ */ jsx17("div", { "data-entry-id": block.messages[0]?.entry_id, children: /* @__PURE__ */ jsxs15(
|
|
4208
|
-
RenderErrorBoundary,
|
|
4209
|
-
{
|
|
4210
|
-
label: "\u52A9\u624B\u6D88\u606F",
|
|
4211
|
-
details: block.key,
|
|
4212
|
-
resetKey: getMessageResetSignature(block.messages),
|
|
4213
|
-
children: [
|
|
4214
|
-
/* @__PURE__ */ jsx17(
|
|
4215
|
-
AssistantTurnBlock,
|
|
4216
|
-
{
|
|
4217
|
-
messages: block.messages,
|
|
4218
|
-
isStreaming: block.isStreaming,
|
|
4219
|
-
askAnswers,
|
|
4220
|
-
onAnswer,
|
|
4221
|
-
sessionStatus,
|
|
4222
|
-
toolCallRenderer,
|
|
4223
|
-
hidePlanUpdateTools,
|
|
4224
|
-
sessionId
|
|
4225
|
-
}
|
|
4226
|
-
),
|
|
4227
|
-
blockFeedback && !hasActiveFollowup ? /* @__PURE__ */ jsx17(HistoricalResultFeedback, { feedback: blockFeedback }) : null,
|
|
4228
|
-
hasActiveFollowup && postChatFollowup ? /* @__PURE__ */ jsx17(
|
|
4229
|
-
PostChatFollowupBlock,
|
|
4230
|
-
{
|
|
4231
|
-
followup: postChatFollowup,
|
|
4232
|
-
sessionId,
|
|
4233
|
-
onSuggestion,
|
|
4234
|
-
isViewer,
|
|
4235
|
-
onInteraction: onFollowupInteraction,
|
|
4236
|
-
savedFeedback: blockFeedback,
|
|
4237
|
-
onFeedbackSaved: onResultFeedbackSaved
|
|
4238
|
-
}
|
|
4239
|
-
) : null
|
|
4240
|
-
]
|
|
4241
|
-
}
|
|
4242
|
-
) }, block.key);
|
|
4243
|
-
}
|
|
4244
|
-
if (block.type === "compaction") {
|
|
4245
|
-
return /* @__PURE__ */ jsxs15(
|
|
4246
|
-
"div",
|
|
4247
|
-
{
|
|
4248
|
-
className: "flex items-center gap-2 text-xs text-[hsl(var(--muted-foreground))]",
|
|
4249
|
-
children: [
|
|
4250
|
-
/* @__PURE__ */ jsx17(Layers, { size: 12 }),
|
|
4251
|
-
/* @__PURE__ */ jsx17("span", { children: "\u4E0A\u4E0B\u6587\u5DF2\u538B\u7F29" })
|
|
4252
|
-
]
|
|
4253
|
-
},
|
|
4254
|
-
block.key
|
|
4255
|
-
);
|
|
4249
|
+
/* @__PURE__ */ jsx17(StickToBottom.Content, { className: "blade-chat-messages-scroll", children: /* @__PURE__ */ jsxs15("div", { className: "blade-chat-messages-content mx-auto max-w-[748px]", children: [
|
|
4250
|
+
isStreaming && latestUserMessage && latestPromptPreview ? /* @__PURE__ */ jsx17(
|
|
4251
|
+
"button",
|
|
4252
|
+
{
|
|
4253
|
+
type: "button",
|
|
4254
|
+
className: "sticky top-0 z-20 mb-4 w-full truncate rounded-2xl border border-[hsl(var(--primary)/0.2)] bg-[hsl(var(--background)/0.92)] px-4 py-3 text-left text-sm font-medium shadow-sm backdrop-blur",
|
|
4255
|
+
onClick: () => Array.from(document.querySelectorAll("[data-entry-id]")).find((el) => el.dataset.entryId === latestUserMessage.entry_id)?.scrollIntoView({ behavior: "smooth", block: "start" }),
|
|
4256
|
+
"aria-label": "\u8DF3\u8F6C\u5230\u5F53\u524D\u63D0\u95EE",
|
|
4257
|
+
children: latestPromptPreview
|
|
4256
4258
|
}
|
|
4257
|
-
|
|
4258
|
-
|
|
4259
|
-
|
|
4260
|
-
|
|
4259
|
+
) : null,
|
|
4260
|
+
/* @__PURE__ */ jsxs15("div", { className: "flex min-w-0 flex-col", children: [
|
|
4261
|
+
renderBlocks.length === 0 ? emptyState ?? /* @__PURE__ */ jsxs15("div", { className: "blade-chat-empty", children: [
|
|
4262
|
+
/* @__PURE__ */ jsx17(MessageSquare, { size: 40, strokeWidth: 1.5 }),
|
|
4263
|
+
/* @__PURE__ */ jsx17("span", { className: "text-base font-medium", children: "\u5F00\u59CB\u5BF9\u8BDD" }),
|
|
4264
|
+
/* @__PURE__ */ jsx17("span", { className: "text-sm opacity-60", children: "\u5728\u4E0B\u65B9\u8F93\u5165\u6D88\u606F\u5F00\u59CB\u804A\u5929" })
|
|
4265
|
+
] }) : renderBlocks.map((block) => {
|
|
4266
|
+
if (block.type === "message") {
|
|
4267
|
+
return /* @__PURE__ */ jsx17("div", { "data-entry-id": block.message.entry_id, children: isUserMessage(block.message) ? /* @__PURE__ */ jsx17(UserMessageBubble, { message: block.message }) : isErrorMessage(block.message) ? /* @__PURE__ */ jsx17(ErrorMessageBlock, { message: block.message }) : null }, block.key);
|
|
4268
|
+
}
|
|
4269
|
+
if (block.type === "assistant_turn") {
|
|
4270
|
+
const blockFeedback = block.messages.map(
|
|
4271
|
+
(message) => message.entry_id ? resultFeedbackByEntry.get(message.entry_id) : void 0
|
|
4272
|
+
).find((feedback) => feedback != null);
|
|
4273
|
+
const hasActiveFollowup = Boolean(
|
|
4274
|
+
postChatFollowup && block.messages.some(
|
|
4275
|
+
(message) => message.entry_id === postChatFollowup.assistant_entry_id
|
|
4276
|
+
)
|
|
4277
|
+
);
|
|
4278
|
+
return /* @__PURE__ */ jsx17("div", { "data-entry-id": block.messages[0]?.entry_id, children: /* @__PURE__ */ jsxs15(
|
|
4279
|
+
RenderErrorBoundary,
|
|
4280
|
+
{
|
|
4281
|
+
label: "\u52A9\u624B\u6D88\u606F",
|
|
4282
|
+
details: block.key,
|
|
4283
|
+
resetKey: getMessageResetSignature(block.messages),
|
|
4284
|
+
children: [
|
|
4285
|
+
/* @__PURE__ */ jsx17(
|
|
4286
|
+
AssistantTurnBlock,
|
|
4287
|
+
{
|
|
4288
|
+
messages: block.messages,
|
|
4289
|
+
isStreaming: block.isStreaming,
|
|
4290
|
+
askAnswers,
|
|
4291
|
+
onAnswer,
|
|
4292
|
+
sessionStatus,
|
|
4293
|
+
toolCallRenderer,
|
|
4294
|
+
hidePlanUpdateTools,
|
|
4295
|
+
sessionId
|
|
4296
|
+
}
|
|
4297
|
+
),
|
|
4298
|
+
blockFeedback && !hasActiveFollowup ? /* @__PURE__ */ jsx17(HistoricalResultFeedback, { feedback: blockFeedback }) : null,
|
|
4299
|
+
hasActiveFollowup && postChatFollowup ? /* @__PURE__ */ jsx17(
|
|
4300
|
+
PostChatFollowupBlock,
|
|
4301
|
+
{
|
|
4302
|
+
followup: postChatFollowup,
|
|
4303
|
+
sessionId,
|
|
4304
|
+
onSuggestion,
|
|
4305
|
+
isViewer,
|
|
4306
|
+
onInteraction: onFollowupInteraction,
|
|
4307
|
+
savedFeedback: blockFeedback,
|
|
4308
|
+
onFeedbackSaved: onResultFeedbackSaved
|
|
4309
|
+
}
|
|
4310
|
+
) : null
|
|
4311
|
+
]
|
|
4312
|
+
}
|
|
4313
|
+
) }, block.key);
|
|
4314
|
+
}
|
|
4315
|
+
if (block.type === "compaction") {
|
|
4316
|
+
return /* @__PURE__ */ jsxs15(
|
|
4317
|
+
"div",
|
|
4318
|
+
{
|
|
4319
|
+
className: "flex items-center gap-2 text-xs text-[hsl(var(--muted-foreground))]",
|
|
4320
|
+
children: [
|
|
4321
|
+
/* @__PURE__ */ jsx17(Layers, { size: 12 }),
|
|
4322
|
+
/* @__PURE__ */ jsx17("span", { children: "\u4E0A\u4E0B\u6587\u5DF2\u538B\u7F29" })
|
|
4323
|
+
]
|
|
4324
|
+
},
|
|
4325
|
+
block.key
|
|
4326
|
+
);
|
|
4327
|
+
}
|
|
4328
|
+
return /* @__PURE__ */ jsx17(PlanningDivider, { kind: block.kind }, block.key);
|
|
4329
|
+
}),
|
|
4330
|
+
sessionStatus === "interrupted" && !isStreaming ? /* @__PURE__ */ jsx17("div", { className: "flex", children: /* @__PURE__ */ jsx17("div", { className: "rounded-full border border-amber-500/30 bg-amber-500/10 px-2.5 py-1 text-[10px] font-medium uppercase tracking-[0.12em] text-amber-300", children: "\u5DF2\u4E2D\u65AD" }) }) : null
|
|
4331
|
+
] })
|
|
4332
|
+
] }) }),
|
|
4261
4333
|
/* @__PURE__ */ jsx17(
|
|
4262
4334
|
PinLatestUserMessage,
|
|
4263
4335
|
{
|
|
@@ -4280,8 +4352,8 @@ function PinLatestUserMessage({
|
|
|
4280
4352
|
targetKey
|
|
4281
4353
|
}) {
|
|
4282
4354
|
const { contentRef, scrollRef, scrollToBottom, stopScroll } = useStickToBottomContext();
|
|
4283
|
-
const previousCountRef =
|
|
4284
|
-
const spacerHeightRef =
|
|
4355
|
+
const previousCountRef = useRef13(userMessageCount);
|
|
4356
|
+
const spacerHeightRef = useRef13(0);
|
|
4285
4357
|
const getScrollElement = useCallback7(() => scrollRef.current, [scrollRef]);
|
|
4286
4358
|
const getContentElement = useCallback7(() => contentRef.current, [contentRef]);
|
|
4287
4359
|
const getTargetElement = useCallback7(() => {
|
|
@@ -4310,7 +4382,7 @@ function PinLatestUserMessage({
|
|
|
4310
4382
|
stopAutoScroll: stopScroll,
|
|
4311
4383
|
scrollToBottom
|
|
4312
4384
|
});
|
|
4313
|
-
|
|
4385
|
+
useEffect12(() => {
|
|
4314
4386
|
if (userMessageCount > previousCountRef.current && !shouldPinLatestUser) {
|
|
4315
4387
|
scrollToBottom("instant");
|
|
4316
4388
|
}
|
|
@@ -4320,9 +4392,9 @@ function PinLatestUserMessage({
|
|
|
4320
4392
|
}
|
|
4321
4393
|
function ScrollToBottomButton() {
|
|
4322
4394
|
const { isAtBottom, scrollToBottom } = useStickToBottomContext();
|
|
4323
|
-
const [visible, setVisible] =
|
|
4324
|
-
const hideTimerRef =
|
|
4325
|
-
|
|
4395
|
+
const [visible, setVisible] = useState14(false);
|
|
4396
|
+
const hideTimerRef = useRef13(null);
|
|
4397
|
+
useEffect12(() => {
|
|
4326
4398
|
if (isAtBottom) {
|
|
4327
4399
|
if (!hideTimerRef.current) {
|
|
4328
4400
|
hideTimerRef.current = setTimeout(() => {
|
|
@@ -4399,6 +4471,7 @@ function ChatSurface({
|
|
|
4399
4471
|
onInputChange,
|
|
4400
4472
|
onSuggestion,
|
|
4401
4473
|
onSend,
|
|
4474
|
+
onAppend,
|
|
4402
4475
|
onStop,
|
|
4403
4476
|
sessionStatus,
|
|
4404
4477
|
askAnswers,
|
|
@@ -4467,10 +4540,12 @@ function ChatSurface({
|
|
|
4467
4540
|
value: inputText,
|
|
4468
4541
|
onValueChange: onInputChange,
|
|
4469
4542
|
onSend,
|
|
4543
|
+
onAppend,
|
|
4470
4544
|
onStop,
|
|
4471
4545
|
isStreaming,
|
|
4472
4546
|
isStopping,
|
|
4473
4547
|
placeholder,
|
|
4548
|
+
queueKey: sessionId,
|
|
4474
4549
|
className: classNames?.chatInput
|
|
4475
4550
|
}
|
|
4476
4551
|
),
|
|
@@ -4481,13 +4556,13 @@ function ChatSurface({
|
|
|
4481
4556
|
}
|
|
4482
4557
|
|
|
4483
4558
|
// src/components/AgentChat.tsx
|
|
4484
|
-
import { Fragment as
|
|
4559
|
+
import { Fragment as Fragment4, jsx as jsx19, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
4485
4560
|
function isUnauthorizedError(error) {
|
|
4486
4561
|
return error instanceof BladeApiError && error.status === 401;
|
|
4487
4562
|
}
|
|
4488
4563
|
function LoginCard({ client, onLoggedIn }) {
|
|
4489
|
-
const [loggingIn, setLoggingIn] =
|
|
4490
|
-
const [loginError, setLoginError] =
|
|
4564
|
+
const [loggingIn, setLoggingIn] = useState15(false);
|
|
4565
|
+
const [loginError, setLoginError] = useState15(null);
|
|
4491
4566
|
const handleLogin = async () => {
|
|
4492
4567
|
setLoggingIn(true);
|
|
4493
4568
|
setLoginError(null);
|
|
@@ -4519,8 +4594,8 @@ function LoginCard({ client, onLoggedIn }) {
|
|
|
4519
4594
|
}
|
|
4520
4595
|
function AgentChat(props) {
|
|
4521
4596
|
const client = useBladeClient();
|
|
4522
|
-
const [attempt, setAttempt] =
|
|
4523
|
-
const [needLogin, setNeedLogin] =
|
|
4597
|
+
const [attempt, setAttempt] = useState15(0);
|
|
4598
|
+
const [needLogin, setNeedLogin] = useState15(() => !client.hasToken());
|
|
4524
4599
|
if (needLogin) {
|
|
4525
4600
|
return /* @__PURE__ */ jsx19(
|
|
4526
4601
|
"div",
|
|
@@ -4557,7 +4632,7 @@ function ChatSessionView({
|
|
|
4557
4632
|
onUnauthorized
|
|
4558
4633
|
}) {
|
|
4559
4634
|
const client = useBladeClient();
|
|
4560
|
-
const [planRevealRevisions, setPlanRevealRevisions] =
|
|
4635
|
+
const [planRevealRevisions, setPlanRevealRevisions] = useState15(
|
|
4561
4636
|
() => /* @__PURE__ */ new Map()
|
|
4562
4637
|
);
|
|
4563
4638
|
const handleSessionConnected = useCallback8((connectedSession) => {
|
|
@@ -4578,12 +4653,12 @@ function ChatSessionView({
|
|
|
4578
4653
|
onSessionConnected: handleSessionConnected
|
|
4579
4654
|
});
|
|
4580
4655
|
const replay = useReplay(session);
|
|
4581
|
-
const [stopRequested, setStopRequested] =
|
|
4582
|
-
const [inputText, setInputText] =
|
|
4583
|
-
const [resultFeedback, setResultFeedback] =
|
|
4656
|
+
const [stopRequested, setStopRequested] = useState15(false);
|
|
4657
|
+
const [inputText, setInputText] = useState15("");
|
|
4658
|
+
const [resultFeedback, setResultFeedback] = useState15([]);
|
|
4584
4659
|
const resolvedSessionId = session?.sessionId;
|
|
4585
4660
|
const isViewer = state?.viewerRole === "viewer";
|
|
4586
|
-
|
|
4661
|
+
useEffect13(() => {
|
|
4587
4662
|
setResultFeedback([]);
|
|
4588
4663
|
if (!resolvedSessionId || isViewer) return;
|
|
4589
4664
|
let cancelled = false;
|
|
@@ -4618,12 +4693,12 @@ function ChatSessionView({
|
|
|
4618
4693
|
saved
|
|
4619
4694
|
]);
|
|
4620
4695
|
}, []);
|
|
4621
|
-
|
|
4696
|
+
useEffect13(() => {
|
|
4622
4697
|
if (session) {
|
|
4623
4698
|
onSessionReady?.(session);
|
|
4624
4699
|
}
|
|
4625
4700
|
}, [session, onSessionReady]);
|
|
4626
|
-
|
|
4701
|
+
useEffect13(() => {
|
|
4627
4702
|
if (!session) return;
|
|
4628
4703
|
const offAttach = session.on("attachRequested", ({ label, content }) => {
|
|
4629
4704
|
setInputText((prev) => `${prev ? `${prev}
|
|
@@ -4639,12 +4714,12 @@ ${content}`);
|
|
|
4639
4714
|
offInsert();
|
|
4640
4715
|
};
|
|
4641
4716
|
}, [session]);
|
|
4642
|
-
|
|
4717
|
+
useEffect13(() => {
|
|
4643
4718
|
if (isUnauthorizedError(error)) {
|
|
4644
4719
|
onUnauthorized();
|
|
4645
4720
|
}
|
|
4646
4721
|
}, [error, onUnauthorized]);
|
|
4647
|
-
|
|
4722
|
+
useEffect13(() => {
|
|
4648
4723
|
if (!session || !commands) return;
|
|
4649
4724
|
const unsubscribes = Object.entries(commands).map(
|
|
4650
4725
|
([action, handler]) => session.onCommand(action, (payload) => handler(payload))
|
|
@@ -4676,7 +4751,7 @@ ${content}`);
|
|
|
4676
4751
|
slots,
|
|
4677
4752
|
placeholder,
|
|
4678
4753
|
connection: state?.connection ?? "connecting",
|
|
4679
|
-
banner: /* @__PURE__ */ jsxs17(
|
|
4754
|
+
banner: /* @__PURE__ */ jsxs17(Fragment4, { children: [
|
|
4680
4755
|
/* @__PURE__ */ jsx19(
|
|
4681
4756
|
ReplayBar,
|
|
4682
4757
|
{
|
|
@@ -4702,6 +4777,9 @@ ${content}`);
|
|
|
4702
4777
|
onInputChange: setInputText,
|
|
4703
4778
|
onSuggestion: setInputText,
|
|
4704
4779
|
onSend: handleSend,
|
|
4780
|
+
onAppend: (text) => {
|
|
4781
|
+
void session?.send(text, { mode: state?.mode ?? void 0 });
|
|
4782
|
+
},
|
|
4705
4783
|
onStop: handleStop,
|
|
4706
4784
|
sessionStatus: state?.status ?? void 0,
|
|
4707
4785
|
askAnswers: state?.askAnswers,
|
|
@@ -4718,10 +4796,10 @@ ${content}`);
|
|
|
4718
4796
|
}
|
|
4719
4797
|
|
|
4720
4798
|
// src/components/LlmChat.tsx
|
|
4721
|
-
import { useEffect as
|
|
4799
|
+
import { useEffect as useEffect14, useMemo as useMemo9, useState as useState17 } from "react";
|
|
4722
4800
|
|
|
4723
4801
|
// src/components/LlmAdvancedSettings.tsx
|
|
4724
|
-
import { useState as
|
|
4802
|
+
import { useState as useState16 } from "react";
|
|
4725
4803
|
import { jsx as jsx20, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
4726
4804
|
var FIELDS = [
|
|
4727
4805
|
{ id: "baseURL", label: "\u6A21\u578B\u670D\u52A1\u5730\u5740", placeholder: "http://\u5185\u7F51\u5730\u5740/v1" },
|
|
@@ -4768,8 +4846,8 @@ function writeOverride(settings, baseURL, override) {
|
|
|
4768
4846
|
}
|
|
4769
4847
|
function LlmAdvancedSettingsBar({ settings, defaults, override, onChange }) {
|
|
4770
4848
|
const normalized = normalizeAdvanced(settings);
|
|
4771
|
-
const [open, setOpen] =
|
|
4772
|
-
const [draft, setDraft] =
|
|
4849
|
+
const [open, setOpen] = useState16(false);
|
|
4850
|
+
const [draft, setDraft] = useState16(override);
|
|
4773
4851
|
if (!normalized) return null;
|
|
4774
4852
|
const fields = FIELDS.filter((field) => normalized[field.id]);
|
|
4775
4853
|
const dirty = Object.keys(override).length > 0;
|
|
@@ -4852,11 +4930,11 @@ function LlmChat({
|
|
|
4852
4930
|
onOverrideChange,
|
|
4853
4931
|
...options
|
|
4854
4932
|
}) {
|
|
4855
|
-
const [override, setOverride] =
|
|
4933
|
+
const [override, setOverride] = useState17(() => readOverride(advanced, options.baseURL));
|
|
4856
4934
|
const effective = { ...options, ...override };
|
|
4857
4935
|
const { messages, isStreaming, error, send, stop, reset } = useLlmChat(effective);
|
|
4858
|
-
const [inputText, setInputText] =
|
|
4859
|
-
const [stopRequested, setStopRequested] =
|
|
4936
|
+
const [inputText, setInputText] = useState17("");
|
|
4937
|
+
const [stopRequested, setStopRequested] = useState17(false);
|
|
4860
4938
|
const handle = useMemo9(
|
|
4861
4939
|
() => ({
|
|
4862
4940
|
insertText: (text) => setInputText((prev) => prev ? `${prev}
|
|
@@ -4866,7 +4944,7 @@ ${text}` : text),
|
|
|
4866
4944
|
}),
|
|
4867
4945
|
[send, reset]
|
|
4868
4946
|
);
|
|
4869
|
-
|
|
4947
|
+
useEffect14(() => {
|
|
4870
4948
|
onReady?.(handle);
|
|
4871
4949
|
}, [handle, onReady]);
|
|
4872
4950
|
return /* @__PURE__ */ jsx21(
|
|
@@ -5013,7 +5091,7 @@ function ContextGroupCard({ contexts, className }) {
|
|
|
5013
5091
|
}
|
|
5014
5092
|
|
|
5015
5093
|
// src/components/SessionMemoryToggle.tsx
|
|
5016
|
-
import { useCallback as useCallback9, useEffect as
|
|
5094
|
+
import { useCallback as useCallback9, useEffect as useEffect15, useRef as useRef14, useState as useState18, useSyncExternalStore as useSyncExternalStore2 } from "react";
|
|
5017
5095
|
import { jsx as jsx24, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
5018
5096
|
var saveStates = /* @__PURE__ */ new WeakMap();
|
|
5019
5097
|
function getSaveState(client, sessionId) {
|
|
@@ -5071,10 +5149,10 @@ function SessionMemoryToggle({
|
|
|
5071
5149
|
getSaving,
|
|
5072
5150
|
getSaving
|
|
5073
5151
|
);
|
|
5074
|
-
const [draftEnabled, setDraftEnabled] =
|
|
5075
|
-
const activeSessionIdRef =
|
|
5152
|
+
const [draftEnabled, setDraftEnabled] = useState18(enabled);
|
|
5153
|
+
const activeSessionIdRef = useRef14(sessionId);
|
|
5076
5154
|
activeSessionIdRef.current = sessionId;
|
|
5077
|
-
|
|
5155
|
+
useEffect15(() => {
|
|
5078
5156
|
setDraftEnabled(enabled);
|
|
5079
5157
|
}, [enabled, sessionId]);
|
|
5080
5158
|
const update = useCallback9(
|