@blade-hq/agent-react 2610.0.0-beta.33 → 2610.0.0-beta.35
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/components/ChatInput.d.ts +4 -1
- package/dist/components/ChatSurface.d.ts +8 -1
- package/dist/components/MessageList.d.ts +7 -1
- package/dist/components/display-utils.d.ts +2 -0
- package/dist/embed/entry.d.ts +5 -0
- package/dist/index.js +302 -178
- package/dist/index.js.map +1 -1
- package/dist/style.full.css +1 -1
- package/package.json +2 -2
- package/public-api.md +69 -1
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 useEffect12, useMemo as useMemo8, useState as
|
|
1147
|
+
import { useCallback as useCallback8, useEffect as useEffect12, 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 { 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,31 @@ 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
|
+
void queueKey;
|
|
1639
|
+
const canSend = trimmed.length > 0 && (!isStreaming || sendMode === "queue");
|
|
1635
1640
|
const handleSend = async () => {
|
|
1636
1641
|
if (!canSend) return;
|
|
1642
|
+
if (isStreaming && sendMode === "queue") {
|
|
1643
|
+
if (onAppend) onAppend(trimmed);
|
|
1644
|
+
onValueChange("");
|
|
1645
|
+
return;
|
|
1646
|
+
}
|
|
1647
|
+
if (isStreaming && sendMode === "direct") {
|
|
1648
|
+
if (!onAppend) return;
|
|
1649
|
+
onAppend(trimmed);
|
|
1650
|
+
onValueChange("");
|
|
1651
|
+
return;
|
|
1652
|
+
}
|
|
1637
1653
|
const accepted = await onSend(trimmed);
|
|
1638
1654
|
if (!accepted) return;
|
|
1639
1655
|
onValueChange("");
|
|
@@ -1649,57 +1665,56 @@ function ChatInput({
|
|
|
1649
1665
|
void handleSend();
|
|
1650
1666
|
}
|
|
1651
1667
|
};
|
|
1652
|
-
return /* @__PURE__ */
|
|
1653
|
-
/* @__PURE__ */ jsx5(
|
|
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
|
-
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",
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
] }) });
|
|
1668
|
+
return /* @__PURE__ */ jsxs4("div", { className: cn("blade-chat-input border-t border-[hsl(var(--border))] py-3", className), children: [
|
|
1669
|
+
/* @__PURE__ */ jsx5("div", { className: "mx-auto mb-2 flex max-w-[748px] items-center justify-between px-1 text-xs text-[hsl(var(--muted-foreground))]", children: /* @__PURE__ */ jsxs4("fieldset", { className: "flex items-center gap-1 rounded-md border border-[hsl(var(--border))] p-0.5", children: [
|
|
1670
|
+
/* @__PURE__ */ jsx5("legend", { className: "sr-only", children: "\u53D1\u9001\u65B9\u5F0F" }),
|
|
1671
|
+
/* @__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" }),
|
|
1672
|
+
/* @__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" })
|
|
1673
|
+
] }) }),
|
|
1674
|
+
/* @__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: [
|
|
1675
|
+
/* @__PURE__ */ jsx5(
|
|
1676
|
+
"textarea",
|
|
1677
|
+
{
|
|
1678
|
+
value,
|
|
1679
|
+
onChange: (event) => onValueChange(event.target.value),
|
|
1680
|
+
onKeyDown: handleKeyDown,
|
|
1681
|
+
onInput: (event) => {
|
|
1682
|
+
const el = event.currentTarget;
|
|
1683
|
+
el.style.height = "auto";
|
|
1684
|
+
el.style.height = `${Math.min(el.scrollHeight, 192)}px`;
|
|
1685
|
+
},
|
|
1686
|
+
rows: 1,
|
|
1687
|
+
placeholder,
|
|
1688
|
+
"aria-label": "\u804A\u5929\u8F93\u5165",
|
|
1689
|
+
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)]"
|
|
1690
|
+
}
|
|
1691
|
+
),
|
|
1692
|
+
isStreaming ? /* @__PURE__ */ jsxs4(Fragment, { children: [
|
|
1693
|
+
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,
|
|
1694
|
+
/* @__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" }) })
|
|
1695
|
+
] }) : /* @__PURE__ */ jsx5(
|
|
1696
|
+
"button",
|
|
1697
|
+
{
|
|
1698
|
+
type: "button",
|
|
1699
|
+
onClick: handleSend,
|
|
1700
|
+
disabled: !canSend,
|
|
1701
|
+
"aria-label": "\u53D1\u9001\u6D88\u606F",
|
|
1702
|
+
title: "\u53D1\u9001\u6D88\u606F",
|
|
1703
|
+
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",
|
|
1704
|
+
children: /* @__PURE__ */ jsx5(ArrowUp, { size: 15 })
|
|
1705
|
+
}
|
|
1706
|
+
)
|
|
1707
|
+
] })
|
|
1708
|
+
] });
|
|
1694
1709
|
}
|
|
1695
1710
|
|
|
1696
1711
|
// src/components/ConnectionBanner.tsx
|
|
1697
|
-
import { useEffect as useEffect5, useRef as useRef5, useState as
|
|
1712
|
+
import { useEffect as useEffect5, useRef as useRef5, useState as useState6 } from "react";
|
|
1698
1713
|
import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
1699
1714
|
var CONNECTION_NOTICE_DELAY_MS = 3e3;
|
|
1700
1715
|
var CONNECTION_ERROR_DELAY_MS = 15e3;
|
|
1701
1716
|
function useConnectionNoticePhase(connected) {
|
|
1702
|
-
const [phase, setPhase] =
|
|
1717
|
+
const [phase, setPhase] = useState6("hidden");
|
|
1703
1718
|
const connectedRef = useRef5(connected);
|
|
1704
1719
|
const timersRef = useRef5([]);
|
|
1705
1720
|
connectedRef.current = connected;
|
|
@@ -1770,10 +1785,10 @@ function ConnectionBanner({ connection, className }) {
|
|
|
1770
1785
|
|
|
1771
1786
|
// src/components/MessageList.tsx
|
|
1772
1787
|
import { isHiddenInternalMessage } from "@blade-hq/agent-client";
|
|
1773
|
-
import { useCallback as useCallback7, useEffect as useEffect11, useMemo as useMemo7, useRef as useRef12, useState as
|
|
1788
|
+
import { useCallback as useCallback7, useEffect as useEffect11, useMemo as useMemo7, useRef as useRef12, useState as useState14 } from "react";
|
|
1774
1789
|
|
|
1775
1790
|
// ../../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 useRef6, useState as
|
|
1791
|
+
import { useCallback as useCallback4, useMemo as useMemo3, useRef as useRef6, useState as useState7 } from "react";
|
|
1777
1792
|
var DEFAULT_SPRING_ANIMATION = {
|
|
1778
1793
|
/**
|
|
1779
1794
|
* A value from 0 to 1, on how much to damp the animation.
|
|
@@ -1810,9 +1825,9 @@ globalThis.document?.addEventListener("click", () => {
|
|
|
1810
1825
|
mouseDown = false;
|
|
1811
1826
|
});
|
|
1812
1827
|
var useStickToBottom = (options = {}) => {
|
|
1813
|
-
const [escapedFromLock, updateEscapedFromLock] =
|
|
1814
|
-
const [isAtBottom, updateIsAtBottom] =
|
|
1815
|
-
const [isNearBottom, setIsNearBottom] =
|
|
1828
|
+
const [escapedFromLock, updateEscapedFromLock] = useState7(false);
|
|
1829
|
+
const [isAtBottom, updateIsAtBottom] = useState7(options.initial !== false);
|
|
1830
|
+
const [isNearBottom, setIsNearBottom] = useState7(false);
|
|
1816
1831
|
const optionsRef = useRef6(null);
|
|
1817
1832
|
optionsRef.current = options;
|
|
1818
1833
|
const isSelecting = useCallback4(() => {
|
|
@@ -2203,10 +2218,10 @@ import {
|
|
|
2203
2218
|
getTextContent,
|
|
2204
2219
|
normalizeMessageContent
|
|
2205
2220
|
} from "@blade-hq/agent-client";
|
|
2206
|
-
import { useEffect as useEffect9, useRef as useRef10, useState as
|
|
2221
|
+
import { useEffect as useEffect9, useRef as useRef10, useState as useState12 } from "react";
|
|
2207
2222
|
|
|
2208
2223
|
// src/components/AgentLoopBlock.tsx
|
|
2209
|
-
import { useState as
|
|
2224
|
+
import { useState as useState8 } from "react";
|
|
2210
2225
|
import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
2211
2226
|
function parseAgentDescription(argumentsJson) {
|
|
2212
2227
|
try {
|
|
@@ -2217,7 +2232,7 @@ function parseAgentDescription(argumentsJson) {
|
|
|
2217
2232
|
}
|
|
2218
2233
|
}
|
|
2219
2234
|
function AgentLoopBlock({ toolCall }) {
|
|
2220
|
-
const [expanded, setExpanded] =
|
|
2235
|
+
const [expanded, setExpanded] = useState8(false);
|
|
2221
2236
|
const description = parseAgentDescription(toolCall.arguments);
|
|
2222
2237
|
const running = toolCall.status === "pending" || toolCall.status === "awaiting_answer";
|
|
2223
2238
|
const failed = toolCall.status === "error" || toolCall.status === "cancelled";
|
|
@@ -2271,7 +2286,7 @@ import {
|
|
|
2271
2286
|
useEffect as useEffect7,
|
|
2272
2287
|
useMemo as useMemo5,
|
|
2273
2288
|
useRef as useRef8,
|
|
2274
|
-
useState as
|
|
2289
|
+
useState as useState9
|
|
2275
2290
|
} from "react";
|
|
2276
2291
|
import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
2277
2292
|
var SYSTEM_REMINDER_RE = /<system-reminder>[\s\S]*?<\/system-reminder>/gi;
|
|
@@ -2289,8 +2304,8 @@ function normalizeAdjacentUrlFormatting(value) {
|
|
|
2289
2304
|
}
|
|
2290
2305
|
function CodeBlockPre({ children, node: _node, ...props }) {
|
|
2291
2306
|
const preRef = useRef8(null);
|
|
2292
|
-
const [copied, setCopied] =
|
|
2293
|
-
const [language, setLanguage] =
|
|
2307
|
+
const [copied, setCopied] = useState9(false);
|
|
2308
|
+
const [language, setLanguage] = useState9("");
|
|
2294
2309
|
useEffect7(() => {
|
|
2295
2310
|
const codeEl = preRef.current?.querySelector("code");
|
|
2296
2311
|
setLanguage(codeEl?.className.match(/language-(\S+)/)?.[1] ?? "");
|
|
@@ -2362,10 +2377,10 @@ function Shimmer({ children = "\u6B63\u5728\u601D\u8003...", className }) {
|
|
|
2362
2377
|
}
|
|
2363
2378
|
|
|
2364
2379
|
// src/components/ToolCallBlock.tsx
|
|
2365
|
-
import { useState as
|
|
2380
|
+
import { useState as useState11 } from "react";
|
|
2366
2381
|
|
|
2367
2382
|
// src/components/AskUserQuestionBlock.tsx
|
|
2368
|
-
import { useEffect as useEffect8, useMemo as useMemo6, useRef as useRef9, useState as
|
|
2383
|
+
import { useEffect as useEffect8, useMemo as useMemo6, useRef as useRef9, useState as useState10 } from "react";
|
|
2369
2384
|
import { jsx as jsx10, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
2370
2385
|
var CUSTOM_TEXTAREA_MAX_HEIGHT = 160;
|
|
2371
2386
|
function resizeCustomTextarea(textarea) {
|
|
@@ -2404,11 +2419,11 @@ function AskUserQuestionBlock({
|
|
|
2404
2419
|
answerData,
|
|
2405
2420
|
onAnswer
|
|
2406
2421
|
}) {
|
|
2407
|
-
const [selections, setSelections] =
|
|
2408
|
-
const [customTexts, setCustomTexts] =
|
|
2409
|
-
const [usingCustom, setUsingCustom] =
|
|
2410
|
-
const [note, setNote] =
|
|
2411
|
-
const [submitted, setSubmitted] =
|
|
2422
|
+
const [selections, setSelections] = useState10(/* @__PURE__ */ new Map());
|
|
2423
|
+
const [customTexts, setCustomTexts] = useState10(/* @__PURE__ */ new Map());
|
|
2424
|
+
const [usingCustom, setUsingCustom] = useState10(/* @__PURE__ */ new Set());
|
|
2425
|
+
const [note, setNote] = useState10("");
|
|
2426
|
+
const [submitted, setSubmitted] = useState10(false);
|
|
2412
2427
|
useEffect8(() => {
|
|
2413
2428
|
if (sessionStatus === "failed" || sessionStatus === "interrupted") {
|
|
2414
2429
|
setSubmitted(false);
|
|
@@ -2798,7 +2813,7 @@ function normalizeOptionItem(value) {
|
|
|
2798
2813
|
}
|
|
2799
2814
|
|
|
2800
2815
|
// src/components/ToolCallBlock.tsx
|
|
2801
|
-
import { Fragment, jsx as jsx11, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
2816
|
+
import { Fragment as Fragment2, jsx as jsx11, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
2802
2817
|
function resolveAskQuestionState({
|
|
2803
2818
|
toolStatus,
|
|
2804
2819
|
hasAnswerData,
|
|
@@ -2820,12 +2835,12 @@ function ToolCallBlock({
|
|
|
2820
2835
|
isActiveQuestion,
|
|
2821
2836
|
renderer
|
|
2822
2837
|
}) {
|
|
2823
|
-
const [expanded, setExpanded] =
|
|
2838
|
+
const [expanded, setExpanded] = useState11(false);
|
|
2824
2839
|
const normalizedName = formatToolName(toolCall.name);
|
|
2825
2840
|
if (renderer) {
|
|
2826
2841
|
const custom = renderer(toolCall);
|
|
2827
2842
|
if (custom !== null && custom !== void 0) {
|
|
2828
|
-
return /* @__PURE__ */ jsx11(
|
|
2843
|
+
return /* @__PURE__ */ jsx11(Fragment2, { children: custom });
|
|
2829
2844
|
}
|
|
2830
2845
|
}
|
|
2831
2846
|
if (normalizedName === "AskUserQuestion") {
|
|
@@ -2908,7 +2923,7 @@ function ToolCallBlock({
|
|
|
2908
2923
|
/* @__PURE__ */ jsx11("div", { className: "mb-3 font-mono text-[11px] text-[hsl(var(--foreground))]", children: normalizedName }),
|
|
2909
2924
|
/* @__PURE__ */ jsx11("div", { className: "mb-1 text-[10px] uppercase tracking-wider text-[hsl(var(--muted-foreground))]", children: "\u53C2\u6570" }),
|
|
2910
2925
|
/* @__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(
|
|
2926
|
+
toolCall.result != null && /* @__PURE__ */ jsxs9(Fragment2, { children: [
|
|
2912
2927
|
/* @__PURE__ */ jsx11("div", { className: "mb-1 mt-3 text-[10px] uppercase tracking-wider text-[hsl(var(--muted-foreground))]", children: "\u7ED3\u679C" }),
|
|
2913
2928
|
/* @__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
2929
|
] })
|
|
@@ -2930,7 +2945,7 @@ function buildAskUserPayload(argumentsJson) {
|
|
|
2930
2945
|
// src/components/AssistantTurnBlock.tsx
|
|
2931
2946
|
import { jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
2932
2947
|
function ThinkingBlock({ reasoning, isStreaming }) {
|
|
2933
|
-
const [open, setOpen] =
|
|
2948
|
+
const [open, setOpen] = useState12(false);
|
|
2934
2949
|
if (!isStreaming) return null;
|
|
2935
2950
|
return /* @__PURE__ */ jsxs10("div", { className: "blade-chat-thinking text-xs", children: [
|
|
2936
2951
|
/* @__PURE__ */ jsxs10(
|
|
@@ -3200,7 +3215,7 @@ function AssistantTurnBlock({
|
|
|
3200
3215
|
)
|
|
3201
3216
|
);
|
|
3202
3217
|
const activeQuestionId = questionToolCalls.filter((toolCall) => toolCall.status === "pending").at(-1)?.id;
|
|
3203
|
-
const [displayMode, setDisplayMode] =
|
|
3218
|
+
const [displayMode, setDisplayMode] = useState12(
|
|
3204
3219
|
() => isStreaming || hasActionableToolCall ? "detail" : "compact"
|
|
3205
3220
|
);
|
|
3206
3221
|
const userSelectedDisplayModeRef = useRef10(false);
|
|
@@ -3213,7 +3228,7 @@ function AssistantTurnBlock({
|
|
|
3213
3228
|
}, [hasActionableToolCall, isStreaming]);
|
|
3214
3229
|
const effectiveMode = resolveTurnDisplayMode({ isStreaming, displayMode });
|
|
3215
3230
|
const executionDurationMs = getExecutionDurationMs({ messages, isStreaming });
|
|
3216
|
-
const [clock, setClock] =
|
|
3231
|
+
const [clock, setClock] = useState12(() => Date.now());
|
|
3217
3232
|
const hasLiveStartTime = messages.some(
|
|
3218
3233
|
(message) => message.timestamp != null && Number.isFinite(Date.parse(message.timestamp))
|
|
3219
3234
|
);
|
|
@@ -3392,7 +3407,7 @@ function collectMemoryRefs(messages) {
|
|
|
3392
3407
|
return [...refs.values()];
|
|
3393
3408
|
}
|
|
3394
3409
|
function MemoryRefsHint({ refs }) {
|
|
3395
|
-
const [expanded, setExpanded] =
|
|
3410
|
+
const [expanded, setExpanded] = useState12(false);
|
|
3396
3411
|
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
3412
|
return /* @__PURE__ */ jsxs10("div", { className: "blade-chat-memory-refs ml-1 w-full max-w-[680px]", children: [
|
|
3398
3413
|
/* @__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 +3542,8 @@ var RenderErrorBoundary = class extends Component {
|
|
|
3527
3542
|
};
|
|
3528
3543
|
|
|
3529
3544
|
// src/components/PostChatFollowupBlock.tsx
|
|
3530
|
-
import { useCallback as useCallback6, useEffect as useEffect10, useRef as useRef11, useState as
|
|
3531
|
-
import { Fragment as
|
|
3545
|
+
import { useCallback as useCallback6, useEffect as useEffect10, useRef as useRef11, useState as useState13 } from "react";
|
|
3546
|
+
import { Fragment as Fragment3, jsx as jsx14, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
3532
3547
|
function emitInteraction(callback, event) {
|
|
3533
3548
|
try {
|
|
3534
3549
|
callback?.(event);
|
|
@@ -3547,7 +3562,7 @@ function ArtifactCard({
|
|
|
3547
3562
|
onArtifactOpened
|
|
3548
3563
|
}) {
|
|
3549
3564
|
const client = useBladeClient();
|
|
3550
|
-
const [downloading, setDownloading] =
|
|
3565
|
+
const [downloading, setDownloading] = useState13(false);
|
|
3551
3566
|
const name = artifact.label || basename(artifact.target);
|
|
3552
3567
|
if (artifact.kind === "link") {
|
|
3553
3568
|
return /* @__PURE__ */ jsxs12(
|
|
@@ -3653,11 +3668,11 @@ function ResultFeedback({
|
|
|
3653
3668
|
onFeedbackSaved
|
|
3654
3669
|
}) {
|
|
3655
3670
|
const client = useBladeClient();
|
|
3656
|
-
const [saved, setSaved] =
|
|
3657
|
-
const [helpful, setHelpful] =
|
|
3658
|
-
const [reason, setReason] =
|
|
3659
|
-
const [saving, setSaving] =
|
|
3660
|
-
const [saveError, setSaveError] =
|
|
3671
|
+
const [saved, setSaved] = useState13(savedFeedback ?? null);
|
|
3672
|
+
const [helpful, setHelpful] = useState13(savedFeedback?.helpful ?? null);
|
|
3673
|
+
const [reason, setReason] = useState13(savedFeedback?.reason ?? null);
|
|
3674
|
+
const [saving, setSaving] = useState13(false);
|
|
3675
|
+
const [saveError, setSaveError] = useState13(false);
|
|
3661
3676
|
const reportedShown = useRef11(false);
|
|
3662
3677
|
const latestChoice = useRef11(null);
|
|
3663
3678
|
const eligible = followup.feedback_eligible === true && Boolean(sessionId) && !isViewer;
|
|
@@ -3782,7 +3797,7 @@ function PostChatFollowupBlock({
|
|
|
3782
3797
|
savedFeedback,
|
|
3783
3798
|
onFeedbackSaved
|
|
3784
3799
|
}) {
|
|
3785
|
-
const [expanded, setExpanded] =
|
|
3800
|
+
const [expanded, setExpanded] = useState13(false);
|
|
3786
3801
|
const adopted = useRef11(/* @__PURE__ */ new Set());
|
|
3787
3802
|
const reportedSuggestions = useRef11(false);
|
|
3788
3803
|
const reportedArtifacts = useRef11(/* @__PURE__ */ new Set());
|
|
@@ -3842,7 +3857,7 @@ function PostChatFollowupBlock({
|
|
|
3842
3857
|
"\u672C\u8F6E\u5C0F\u7ED3"
|
|
3843
3858
|
] }),
|
|
3844
3859
|
followup.recaption ? /* @__PURE__ */ jsx14("p", { className: "text-[13px] leading-5", children: followup.recaption }) : null,
|
|
3845
|
-
artifacts.length > 0 ? /* @__PURE__ */ jsxs12(
|
|
3860
|
+
artifacts.length > 0 ? /* @__PURE__ */ jsxs12(Fragment3, { children: [
|
|
3846
3861
|
/* @__PURE__ */ jsx14("div", { className: "grid max-w-full grid-cols-3 gap-1.5", children: visibleArtifacts.map((artifact, artifactIndex) => /* @__PURE__ */ jsx14(
|
|
3847
3862
|
ArtifactCard,
|
|
3848
3863
|
{
|
|
@@ -4098,10 +4113,19 @@ function MessageList({
|
|
|
4098
4113
|
isViewer = false,
|
|
4099
4114
|
onFollowupInteraction,
|
|
4100
4115
|
resultFeedbackByEntry = /* @__PURE__ */ new Map(),
|
|
4101
|
-
onResultFeedbackSaved
|
|
4116
|
+
onResultFeedbackSaved,
|
|
4117
|
+
historyPaging
|
|
4102
4118
|
}) {
|
|
4103
|
-
const
|
|
4119
|
+
const visibleRootMessages = messages.filter((message) => {
|
|
4120
|
+
if ((message.loop_name ?? "root") !== "root") return false;
|
|
4121
|
+
if (isHiddenInternalMessage(message)) return false;
|
|
4122
|
+
if (message.kind === "context") return false;
|
|
4123
|
+
return message.role !== "tool" || getPlanningDividerKind(message) !== null;
|
|
4124
|
+
});
|
|
4125
|
+
const userMessages = visibleRootMessages.filter((message) => isUserMessage(message));
|
|
4104
4126
|
const latestUserMessage = userMessages.at(-1);
|
|
4127
|
+
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() : "";
|
|
4128
|
+
const latestPromptPreview = latestPromptText.length > 80 ? `${latestPromptText.slice(0, 80)}\u2026` : latestPromptText;
|
|
4105
4129
|
const shouldPinLatestUser = latestUserMessage != null && (latestUserMessage.entry_id == null || latestUserMessage.entry_id.startsWith("local-user-"));
|
|
4106
4130
|
const renderBlocks = useMemo7(() => {
|
|
4107
4131
|
const visible = messages.filter((message) => {
|
|
@@ -4186,78 +4210,91 @@ function MessageList({
|
|
|
4186
4210
|
initial: "instant",
|
|
4187
4211
|
resize: "instant",
|
|
4188
4212
|
children: [
|
|
4189
|
-
/* @__PURE__ */ jsx17(StickToBottom.Content, { className: "blade-chat-messages-scroll", children: /* @__PURE__ */
|
|
4190
|
-
|
|
4191
|
-
|
|
4192
|
-
|
|
4193
|
-
|
|
4194
|
-
|
|
4195
|
-
|
|
4196
|
-
|
|
4197
|
-
|
|
4198
|
-
|
|
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
|
-
);
|
|
4213
|
+
/* @__PURE__ */ jsx17(StickToBottom.Content, { className: "blade-chat-messages-scroll", children: /* @__PURE__ */ jsxs15("div", { className: "blade-chat-messages-content mx-auto max-w-[748px]", children: [
|
|
4214
|
+
historyPaging && (historyPaging.hasOlder || historyPaging.loading) ? /* @__PURE__ */ jsx17(LoadOlderSentinel, { ...historyPaging }) : null,
|
|
4215
|
+
isStreaming && latestUserMessage && latestPromptPreview ? /* @__PURE__ */ jsx17(
|
|
4216
|
+
"button",
|
|
4217
|
+
{
|
|
4218
|
+
type: "button",
|
|
4219
|
+
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",
|
|
4220
|
+
onClick: () => Array.from(document.querySelectorAll("[data-entry-id]")).find((el) => el.dataset.entryId === latestUserMessage.entry_id)?.scrollIntoView({ behavior: "smooth", block: "start" }),
|
|
4221
|
+
"aria-label": "\u8DF3\u8F6C\u5230\u5F53\u524D\u63D0\u95EE",
|
|
4222
|
+
children: latestPromptPreview
|
|
4256
4223
|
}
|
|
4257
|
-
|
|
4258
|
-
|
|
4259
|
-
|
|
4260
|
-
|
|
4224
|
+
) : null,
|
|
4225
|
+
/* @__PURE__ */ jsxs15("div", { className: "flex min-w-0 flex-col", children: [
|
|
4226
|
+
renderBlocks.length === 0 ? emptyState ?? /* @__PURE__ */ jsxs15("div", { className: "blade-chat-empty", children: [
|
|
4227
|
+
/* @__PURE__ */ jsx17(MessageSquare, { size: 40, strokeWidth: 1.5 }),
|
|
4228
|
+
/* @__PURE__ */ jsx17("span", { className: "text-base font-medium", children: "\u5F00\u59CB\u5BF9\u8BDD" }),
|
|
4229
|
+
/* @__PURE__ */ jsx17("span", { className: "text-sm opacity-60", children: "\u5728\u4E0B\u65B9\u8F93\u5165\u6D88\u606F\u5F00\u59CB\u804A\u5929" })
|
|
4230
|
+
] }) : renderBlocks.map((block) => {
|
|
4231
|
+
if (block.type === "message") {
|
|
4232
|
+
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);
|
|
4233
|
+
}
|
|
4234
|
+
if (block.type === "assistant_turn") {
|
|
4235
|
+
const blockFeedback = block.messages.map(
|
|
4236
|
+
(message) => message.entry_id ? resultFeedbackByEntry.get(message.entry_id) : void 0
|
|
4237
|
+
).find((feedback) => feedback != null);
|
|
4238
|
+
const hasActiveFollowup = Boolean(
|
|
4239
|
+
postChatFollowup && block.messages.some(
|
|
4240
|
+
(message) => message.entry_id === postChatFollowup.assistant_entry_id
|
|
4241
|
+
)
|
|
4242
|
+
);
|
|
4243
|
+
return /* @__PURE__ */ jsx17("div", { "data-entry-id": block.messages[0]?.entry_id, children: /* @__PURE__ */ jsxs15(
|
|
4244
|
+
RenderErrorBoundary,
|
|
4245
|
+
{
|
|
4246
|
+
label: "\u52A9\u624B\u6D88\u606F",
|
|
4247
|
+
details: block.key,
|
|
4248
|
+
resetKey: getMessageResetSignature(block.messages),
|
|
4249
|
+
children: [
|
|
4250
|
+
/* @__PURE__ */ jsx17(
|
|
4251
|
+
AssistantTurnBlock,
|
|
4252
|
+
{
|
|
4253
|
+
messages: block.messages,
|
|
4254
|
+
isStreaming: block.isStreaming,
|
|
4255
|
+
askAnswers,
|
|
4256
|
+
onAnswer,
|
|
4257
|
+
sessionStatus,
|
|
4258
|
+
toolCallRenderer,
|
|
4259
|
+
hidePlanUpdateTools,
|
|
4260
|
+
sessionId
|
|
4261
|
+
}
|
|
4262
|
+
),
|
|
4263
|
+
blockFeedback && !hasActiveFollowup ? /* @__PURE__ */ jsx17(HistoricalResultFeedback, { feedback: blockFeedback }) : null,
|
|
4264
|
+
hasActiveFollowup && postChatFollowup ? /* @__PURE__ */ jsx17(
|
|
4265
|
+
PostChatFollowupBlock,
|
|
4266
|
+
{
|
|
4267
|
+
followup: postChatFollowup,
|
|
4268
|
+
sessionId,
|
|
4269
|
+
onSuggestion,
|
|
4270
|
+
isViewer,
|
|
4271
|
+
onInteraction: onFollowupInteraction,
|
|
4272
|
+
savedFeedback: blockFeedback,
|
|
4273
|
+
onFeedbackSaved: onResultFeedbackSaved
|
|
4274
|
+
}
|
|
4275
|
+
) : null
|
|
4276
|
+
]
|
|
4277
|
+
}
|
|
4278
|
+
) }, block.key);
|
|
4279
|
+
}
|
|
4280
|
+
if (block.type === "compaction") {
|
|
4281
|
+
return /* @__PURE__ */ jsxs15(
|
|
4282
|
+
"div",
|
|
4283
|
+
{
|
|
4284
|
+
className: "flex items-center gap-2 text-xs text-[hsl(var(--muted-foreground))]",
|
|
4285
|
+
children: [
|
|
4286
|
+
/* @__PURE__ */ jsx17(Layers, { size: 12 }),
|
|
4287
|
+
/* @__PURE__ */ jsx17("span", { children: "\u4E0A\u4E0B\u6587\u5DF2\u538B\u7F29" })
|
|
4288
|
+
]
|
|
4289
|
+
},
|
|
4290
|
+
block.key
|
|
4291
|
+
);
|
|
4292
|
+
}
|
|
4293
|
+
return /* @__PURE__ */ jsx17(PlanningDivider, { kind: block.kind }, block.key);
|
|
4294
|
+
}),
|
|
4295
|
+
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
|
|
4296
|
+
] })
|
|
4297
|
+
] }) }),
|
|
4261
4298
|
/* @__PURE__ */ jsx17(
|
|
4262
4299
|
PinLatestUserMessage,
|
|
4263
4300
|
{
|
|
@@ -4274,6 +4311,76 @@ function MessageList({
|
|
|
4274
4311
|
)
|
|
4275
4312
|
] });
|
|
4276
4313
|
}
|
|
4314
|
+
function LoadOlderSentinel({
|
|
4315
|
+
hasOlder,
|
|
4316
|
+
loading,
|
|
4317
|
+
loadOlder
|
|
4318
|
+
}) {
|
|
4319
|
+
const { contentRef, scrollRef } = useStickToBottomContext();
|
|
4320
|
+
const sentinelRef = useRef12(null);
|
|
4321
|
+
const stateRef = useRef12({ hasOlder, loading, loadOlder });
|
|
4322
|
+
stateRef.current = { hasOlder, loading, loadOlder };
|
|
4323
|
+
useEffect11(() => {
|
|
4324
|
+
const sentinel = sentinelRef.current;
|
|
4325
|
+
const scroller = scrollRef.current;
|
|
4326
|
+
if (!sentinel || !scroller || typeof IntersectionObserver === "undefined") return;
|
|
4327
|
+
let entered = false;
|
|
4328
|
+
let disposed = false;
|
|
4329
|
+
const firstVisible = () => {
|
|
4330
|
+
const top = scroller.getBoundingClientRect().top;
|
|
4331
|
+
for (const row of contentRef.current?.querySelectorAll("[data-entry-id]") ?? []) {
|
|
4332
|
+
const rect = row.getBoundingClientRect();
|
|
4333
|
+
if (rect.bottom >= top) return { id: row.dataset.entryId, offset: rect.top - top };
|
|
4334
|
+
}
|
|
4335
|
+
return null;
|
|
4336
|
+
};
|
|
4337
|
+
const load = async () => {
|
|
4338
|
+
if (disposed || !stateRef.current.hasOlder || stateRef.current.loading) return;
|
|
4339
|
+
const commitSnapshot = { anchor: null, height: scroller.scrollHeight };
|
|
4340
|
+
let advanced = false;
|
|
4341
|
+
try {
|
|
4342
|
+
advanced = await stateRef.current.loadOlder(() => {
|
|
4343
|
+
commitSnapshot.anchor = firstVisible();
|
|
4344
|
+
commitSnapshot.height = scroller.scrollHeight;
|
|
4345
|
+
});
|
|
4346
|
+
} catch {
|
|
4347
|
+
return;
|
|
4348
|
+
}
|
|
4349
|
+
if (disposed) return;
|
|
4350
|
+
await new Promise((resolve) => requestAnimationFrame(() => resolve()));
|
|
4351
|
+
if (disposed) return;
|
|
4352
|
+
const anchor = commitSnapshot.anchor;
|
|
4353
|
+
const heightBefore = commitSnapshot.height;
|
|
4354
|
+
const anchored = anchor?.id ? Array.from(contentRef.current?.querySelectorAll("[data-entry-id]") ?? []).find((row) => row.dataset.entryId === anchor.id) : null;
|
|
4355
|
+
if (anchored && anchor) {
|
|
4356
|
+
scroller.scrollTop += anchored.getBoundingClientRect().top - scroller.getBoundingClientRect().top - anchor.offset;
|
|
4357
|
+
} else {
|
|
4358
|
+
scroller.scrollTop += scroller.scrollHeight - heightBefore;
|
|
4359
|
+
}
|
|
4360
|
+
if (!disposed && advanced && stateRef.current.hasOlder && !stateRef.current.loading && scroller.scrollHeight <= scroller.clientHeight) {
|
|
4361
|
+
await load();
|
|
4362
|
+
}
|
|
4363
|
+
};
|
|
4364
|
+
const observer = new IntersectionObserver(
|
|
4365
|
+
([entry]) => {
|
|
4366
|
+
if (!entry?.isIntersecting) {
|
|
4367
|
+
entered = false;
|
|
4368
|
+
return;
|
|
4369
|
+
}
|
|
4370
|
+
if (entered) return;
|
|
4371
|
+
entered = true;
|
|
4372
|
+
void load();
|
|
4373
|
+
},
|
|
4374
|
+
{ root: scroller, rootMargin: "160px 0px 0px" }
|
|
4375
|
+
);
|
|
4376
|
+
observer.observe(sentinel);
|
|
4377
|
+
return () => {
|
|
4378
|
+
disposed = true;
|
|
4379
|
+
observer.disconnect();
|
|
4380
|
+
};
|
|
4381
|
+
}, [contentRef, scrollRef]);
|
|
4382
|
+
return /* @__PURE__ */ jsx17("div", { ref: sentinelRef, "data-history-sentinel": true, className: "flex h-6 items-center justify-center", children: loading ? /* @__PURE__ */ jsx17("span", { className: "text-xs text-[hsl(var(--muted-foreground))]", children: "\u6B63\u5728\u52A0\u8F7D\u66F4\u65E9\u6D88\u606F\u2026" }) : null });
|
|
4383
|
+
}
|
|
4277
4384
|
function PinLatestUserMessage({
|
|
4278
4385
|
userMessageCount,
|
|
4279
4386
|
shouldPinLatestUser,
|
|
@@ -4320,7 +4427,7 @@ function PinLatestUserMessage({
|
|
|
4320
4427
|
}
|
|
4321
4428
|
function ScrollToBottomButton() {
|
|
4322
4429
|
const { isAtBottom, scrollToBottom } = useStickToBottomContext();
|
|
4323
|
-
const [visible, setVisible] =
|
|
4430
|
+
const [visible, setVisible] = useState14(false);
|
|
4324
4431
|
const hideTimerRef = useRef12(null);
|
|
4325
4432
|
useEffect11(() => {
|
|
4326
4433
|
if (isAtBottom) {
|
|
@@ -4399,6 +4506,7 @@ function ChatSurface({
|
|
|
4399
4506
|
onInputChange,
|
|
4400
4507
|
onSuggestion,
|
|
4401
4508
|
onSend,
|
|
4509
|
+
onAppend,
|
|
4402
4510
|
onStop,
|
|
4403
4511
|
sessionStatus,
|
|
4404
4512
|
askAnswers,
|
|
@@ -4411,6 +4519,7 @@ function ChatSurface({
|
|
|
4411
4519
|
beforeInput,
|
|
4412
4520
|
showPlanUpdates = false,
|
|
4413
4521
|
planRevealRevision = 0,
|
|
4522
|
+
historyPaging,
|
|
4414
4523
|
banner
|
|
4415
4524
|
}) {
|
|
4416
4525
|
return /* @__PURE__ */ jsxs16(
|
|
@@ -4447,7 +4556,8 @@ function ChatSurface({
|
|
|
4447
4556
|
isViewer,
|
|
4448
4557
|
resultFeedbackByEntry,
|
|
4449
4558
|
onResultFeedbackSaved,
|
|
4450
|
-
onFollowupInteraction
|
|
4559
|
+
onFollowupInteraction,
|
|
4560
|
+
historyPaging
|
|
4451
4561
|
}
|
|
4452
4562
|
),
|
|
4453
4563
|
showPlanUpdates ? /* @__PURE__ */ jsx18(
|
|
@@ -4467,10 +4577,12 @@ function ChatSurface({
|
|
|
4467
4577
|
value: inputText,
|
|
4468
4578
|
onValueChange: onInputChange,
|
|
4469
4579
|
onSend,
|
|
4580
|
+
onAppend,
|
|
4470
4581
|
onStop,
|
|
4471
4582
|
isStreaming,
|
|
4472
4583
|
isStopping,
|
|
4473
4584
|
placeholder,
|
|
4585
|
+
queueKey: sessionId,
|
|
4474
4586
|
className: classNames?.chatInput
|
|
4475
4587
|
}
|
|
4476
4588
|
),
|
|
@@ -4481,13 +4593,13 @@ function ChatSurface({
|
|
|
4481
4593
|
}
|
|
4482
4594
|
|
|
4483
4595
|
// src/components/AgentChat.tsx
|
|
4484
|
-
import { Fragment as
|
|
4596
|
+
import { Fragment as Fragment4, jsx as jsx19, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
4485
4597
|
function isUnauthorizedError(error) {
|
|
4486
4598
|
return error instanceof BladeApiError && error.status === 401;
|
|
4487
4599
|
}
|
|
4488
4600
|
function LoginCard({ client, onLoggedIn }) {
|
|
4489
|
-
const [loggingIn, setLoggingIn] =
|
|
4490
|
-
const [loginError, setLoginError] =
|
|
4601
|
+
const [loggingIn, setLoggingIn] = useState15(false);
|
|
4602
|
+
const [loginError, setLoginError] = useState15(null);
|
|
4491
4603
|
const handleLogin = async () => {
|
|
4492
4604
|
setLoggingIn(true);
|
|
4493
4605
|
setLoginError(null);
|
|
@@ -4519,8 +4631,8 @@ function LoginCard({ client, onLoggedIn }) {
|
|
|
4519
4631
|
}
|
|
4520
4632
|
function AgentChat(props) {
|
|
4521
4633
|
const client = useBladeClient();
|
|
4522
|
-
const [attempt, setAttempt] =
|
|
4523
|
-
const [needLogin, setNeedLogin] =
|
|
4634
|
+
const [attempt, setAttempt] = useState15(0);
|
|
4635
|
+
const [needLogin, setNeedLogin] = useState15(() => !client.hasToken());
|
|
4524
4636
|
if (needLogin) {
|
|
4525
4637
|
return /* @__PURE__ */ jsx19(
|
|
4526
4638
|
"div",
|
|
@@ -4557,7 +4669,7 @@ function ChatSessionView({
|
|
|
4557
4669
|
onUnauthorized
|
|
4558
4670
|
}) {
|
|
4559
4671
|
const client = useBladeClient();
|
|
4560
|
-
const [planRevealRevisions, setPlanRevealRevisions] =
|
|
4672
|
+
const [planRevealRevisions, setPlanRevealRevisions] = useState15(
|
|
4561
4673
|
() => /* @__PURE__ */ new Map()
|
|
4562
4674
|
);
|
|
4563
4675
|
const handleSessionConnected = useCallback8((connectedSession) => {
|
|
@@ -4578,9 +4690,9 @@ function ChatSessionView({
|
|
|
4578
4690
|
onSessionConnected: handleSessionConnected
|
|
4579
4691
|
});
|
|
4580
4692
|
const replay = useReplay(session);
|
|
4581
|
-
const [stopRequested, setStopRequested] =
|
|
4582
|
-
const [inputText, setInputText] =
|
|
4583
|
-
const [resultFeedback, setResultFeedback] =
|
|
4693
|
+
const [stopRequested, setStopRequested] = useState15(false);
|
|
4694
|
+
const [inputText, setInputText] = useState15("");
|
|
4695
|
+
const [resultFeedback, setResultFeedback] = useState15([]);
|
|
4584
4696
|
const resolvedSessionId = session?.sessionId;
|
|
4585
4697
|
const isViewer = state?.viewerRole === "viewer";
|
|
4586
4698
|
useEffect12(() => {
|
|
@@ -4676,7 +4788,7 @@ ${content}`);
|
|
|
4676
4788
|
slots,
|
|
4677
4789
|
placeholder,
|
|
4678
4790
|
connection: state?.connection ?? "connecting",
|
|
4679
|
-
banner: /* @__PURE__ */ jsxs17(
|
|
4791
|
+
banner: /* @__PURE__ */ jsxs17(Fragment4, { children: [
|
|
4680
4792
|
/* @__PURE__ */ jsx19(
|
|
4681
4793
|
ReplayBar,
|
|
4682
4794
|
{
|
|
@@ -4697,11 +4809,23 @@ ${content}`);
|
|
|
4697
4809
|
isStreaming,
|
|
4698
4810
|
showPlanUpdates: true,
|
|
4699
4811
|
planRevealRevision,
|
|
4812
|
+
historyPaging: session && state ? {
|
|
4813
|
+
hasOlder: session.hasOlderHistory,
|
|
4814
|
+
loading: state.loadingOlder,
|
|
4815
|
+
loadOlder: async (beforeCommit) => {
|
|
4816
|
+
const before = session.getState().nextBefore;
|
|
4817
|
+
await session.loadOlderHistory({ beforeCommit });
|
|
4818
|
+
return before !== session.getState().nextBefore;
|
|
4819
|
+
}
|
|
4820
|
+
} : void 0,
|
|
4700
4821
|
isStopping,
|
|
4701
4822
|
inputText,
|
|
4702
4823
|
onInputChange: setInputText,
|
|
4703
4824
|
onSuggestion: setInputText,
|
|
4704
4825
|
onSend: handleSend,
|
|
4826
|
+
onAppend: (text) => {
|
|
4827
|
+
void session?.queue(text);
|
|
4828
|
+
},
|
|
4705
4829
|
onStop: handleStop,
|
|
4706
4830
|
sessionStatus: state?.status ?? void 0,
|
|
4707
4831
|
askAnswers: state?.askAnswers,
|
|
@@ -4718,10 +4842,10 @@ ${content}`);
|
|
|
4718
4842
|
}
|
|
4719
4843
|
|
|
4720
4844
|
// src/components/LlmChat.tsx
|
|
4721
|
-
import { useEffect as useEffect13, useMemo as useMemo9, useState as
|
|
4845
|
+
import { useEffect as useEffect13, useMemo as useMemo9, useState as useState17 } from "react";
|
|
4722
4846
|
|
|
4723
4847
|
// src/components/LlmAdvancedSettings.tsx
|
|
4724
|
-
import { useState as
|
|
4848
|
+
import { useState as useState16 } from "react";
|
|
4725
4849
|
import { jsx as jsx20, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
4726
4850
|
var FIELDS = [
|
|
4727
4851
|
{ id: "baseURL", label: "\u6A21\u578B\u670D\u52A1\u5730\u5740", placeholder: "http://\u5185\u7F51\u5730\u5740/v1" },
|
|
@@ -4768,8 +4892,8 @@ function writeOverride(settings, baseURL, override) {
|
|
|
4768
4892
|
}
|
|
4769
4893
|
function LlmAdvancedSettingsBar({ settings, defaults, override, onChange }) {
|
|
4770
4894
|
const normalized = normalizeAdvanced(settings);
|
|
4771
|
-
const [open, setOpen] =
|
|
4772
|
-
const [draft, setDraft] =
|
|
4895
|
+
const [open, setOpen] = useState16(false);
|
|
4896
|
+
const [draft, setDraft] = useState16(override);
|
|
4773
4897
|
if (!normalized) return null;
|
|
4774
4898
|
const fields = FIELDS.filter((field) => normalized[field.id]);
|
|
4775
4899
|
const dirty = Object.keys(override).length > 0;
|
|
@@ -4852,11 +4976,11 @@ function LlmChat({
|
|
|
4852
4976
|
onOverrideChange,
|
|
4853
4977
|
...options
|
|
4854
4978
|
}) {
|
|
4855
|
-
const [override, setOverride] =
|
|
4979
|
+
const [override, setOverride] = useState17(() => readOverride(advanced, options.baseURL));
|
|
4856
4980
|
const effective = { ...options, ...override };
|
|
4857
4981
|
const { messages, isStreaming, error, send, stop, reset } = useLlmChat(effective);
|
|
4858
|
-
const [inputText, setInputText] =
|
|
4859
|
-
const [stopRequested, setStopRequested] =
|
|
4982
|
+
const [inputText, setInputText] = useState17("");
|
|
4983
|
+
const [stopRequested, setStopRequested] = useState17(false);
|
|
4860
4984
|
const handle = useMemo9(
|
|
4861
4985
|
() => ({
|
|
4862
4986
|
insertText: (text) => setInputText((prev) => prev ? `${prev}
|
|
@@ -5013,7 +5137,7 @@ function ContextGroupCard({ contexts, className }) {
|
|
|
5013
5137
|
}
|
|
5014
5138
|
|
|
5015
5139
|
// src/components/SessionMemoryToggle.tsx
|
|
5016
|
-
import { useCallback as useCallback9, useEffect as useEffect14, useRef as useRef13, useState as
|
|
5140
|
+
import { useCallback as useCallback9, useEffect as useEffect14, useRef as useRef13, useState as useState18, useSyncExternalStore as useSyncExternalStore2 } from "react";
|
|
5017
5141
|
import { jsx as jsx24, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
5018
5142
|
var saveStates = /* @__PURE__ */ new WeakMap();
|
|
5019
5143
|
function getSaveState(client, sessionId) {
|
|
@@ -5071,7 +5195,7 @@ function SessionMemoryToggle({
|
|
|
5071
5195
|
getSaving,
|
|
5072
5196
|
getSaving
|
|
5073
5197
|
);
|
|
5074
|
-
const [draftEnabled, setDraftEnabled] =
|
|
5198
|
+
const [draftEnabled, setDraftEnabled] = useState18(enabled);
|
|
5075
5199
|
const activeSessionIdRef = useRef13(sessionId);
|
|
5076
5200
|
activeSessionIdRef.current = sessionId;
|
|
5077
5201
|
useEffect14(() => {
|