@pactor-app/chat 1.2.0 → 1.3.0
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.cjs +145 -96
- package/dist/index.d.cts +5 -1
- package/dist/index.d.ts +5 -1
- package/dist/index.js +128 -79
- package/package.json +6 -6
- package/styles.css +61 -35
package/dist/index.d.ts
CHANGED
|
@@ -410,9 +410,13 @@ interface ChatInput {
|
|
|
410
410
|
*/
|
|
411
411
|
contexts?: ChatContextItem[];
|
|
412
412
|
}
|
|
413
|
+
/** 传输层发送选项 */
|
|
414
|
+
interface ChatTransportSendOptions {
|
|
415
|
+
signal?: AbortSignal;
|
|
416
|
+
}
|
|
413
417
|
/** Chat 传输层:发送输入,返回流式事件 */
|
|
414
418
|
interface ChatTransport {
|
|
415
|
-
send(input: ChatInput): AsyncIterable<ChatEvent>;
|
|
419
|
+
send(input: ChatInput, options?: ChatTransportSendOptions): AsyncIterable<ChatEvent>;
|
|
416
420
|
}
|
|
417
421
|
/** runChatTurn 的可选定制(id 生成等,测试可注入确定性 id) */
|
|
418
422
|
interface RunChatTurnOptions {
|
package/dist/index.js
CHANGED
|
@@ -431,6 +431,16 @@ function pairToolTraces(parts) {
|
|
|
431
431
|
}
|
|
432
432
|
|
|
433
433
|
// src/transport.ts
|
|
434
|
+
function markCancelled(store, messageId) {
|
|
435
|
+
const message = store.getMessage(messageId);
|
|
436
|
+
if (!message) {
|
|
437
|
+
return;
|
|
438
|
+
}
|
|
439
|
+
const parts = message.parts.map(
|
|
440
|
+
(part) => "status" in part && (part.status === "streaming" || part.status === "pending") ? { ...part, status: "ready" } : part
|
|
441
|
+
);
|
|
442
|
+
store.updateMessage(messageId, { status: "cancelled", parts });
|
|
443
|
+
}
|
|
434
444
|
async function runChatTurn(store, transport, input, options = {}) {
|
|
435
445
|
const userMessageId = options.userMessageId ?? createChatId("msg");
|
|
436
446
|
const assistantMessageId = options.assistantMessageId ?? createChatId("msg");
|
|
@@ -453,15 +463,15 @@ async function runChatTurn(store, transport, input, options = {}) {
|
|
|
453
463
|
createdAt: Date.now()
|
|
454
464
|
});
|
|
455
465
|
try {
|
|
456
|
-
for await (const event of transport.send(input)) {
|
|
466
|
+
for await (const event of transport.send(input, { signal: options.signal })) {
|
|
457
467
|
if (options.signal?.aborted) {
|
|
458
|
-
store
|
|
468
|
+
markCancelled(store, assistantMessageId);
|
|
459
469
|
return { userMessageId, assistantMessageId };
|
|
460
470
|
}
|
|
461
471
|
applyChatEvent(store, { ...event, messageId: assistantMessageId });
|
|
462
472
|
}
|
|
463
473
|
if (options.signal?.aborted) {
|
|
464
|
-
store
|
|
474
|
+
markCancelled(store, assistantMessageId);
|
|
465
475
|
return { userMessageId, assistantMessageId };
|
|
466
476
|
}
|
|
467
477
|
const message = store.getMessage(assistantMessageId);
|
|
@@ -796,8 +806,8 @@ import { useRenderer as useRenderer4 } from "@pactor-app/runtime";
|
|
|
796
806
|
import {
|
|
797
807
|
Component as Component3,
|
|
798
808
|
isValidElement,
|
|
799
|
-
useRef as
|
|
800
|
-
useState as
|
|
809
|
+
useRef as useRef13,
|
|
810
|
+
useState as useState15,
|
|
801
811
|
useSyncExternalStore as useSyncExternalStore2
|
|
802
812
|
} from "react";
|
|
803
813
|
|
|
@@ -862,10 +872,10 @@ import { MarkdownRenderer as MarkdownRenderer2 } from "@pactor-app/markdown";
|
|
|
862
872
|
import { DslRenderer as DslRenderer2, useRenderer as useRenderer3 } from "@pactor-app/runtime";
|
|
863
873
|
import {
|
|
864
874
|
Component as Component2,
|
|
865
|
-
useEffect as
|
|
875
|
+
useEffect as useEffect3,
|
|
866
876
|
useMemo,
|
|
867
|
-
useRef as
|
|
868
|
-
useState as
|
|
877
|
+
useRef as useRef4,
|
|
878
|
+
useState as useState5
|
|
869
879
|
} from "react";
|
|
870
880
|
|
|
871
881
|
// src/view/PartRenderer.tsx
|
|
@@ -873,6 +883,43 @@ import { Icon } from "@pactor-app/ui/components";
|
|
|
873
883
|
import { MarkdownRenderer } from "@pactor-app/markdown";
|
|
874
884
|
import { DslRenderer, useRenderer as useRenderer2 } from "@pactor-app/runtime";
|
|
875
885
|
|
|
886
|
+
// src/hooks/use-throttled-value.ts
|
|
887
|
+
import { useEffect as useEffect2, useRef as useRef3, useState as useState4 } from "react";
|
|
888
|
+
function useThrottledValue(value, intervalMs, enabled) {
|
|
889
|
+
const [shown, setShown] = useState4(value);
|
|
890
|
+
const lastUpdateRef = useRef3(0);
|
|
891
|
+
const timerRef = useRef3(void 0);
|
|
892
|
+
useEffect2(() => {
|
|
893
|
+
if (!enabled) {
|
|
894
|
+
if (timerRef.current) {
|
|
895
|
+
clearTimeout(timerRef.current);
|
|
896
|
+
timerRef.current = void 0;
|
|
897
|
+
}
|
|
898
|
+
setShown(value);
|
|
899
|
+
return;
|
|
900
|
+
}
|
|
901
|
+
const now = Date.now();
|
|
902
|
+
const elapsed = now - lastUpdateRef.current;
|
|
903
|
+
if (elapsed >= intervalMs) {
|
|
904
|
+
lastUpdateRef.current = now;
|
|
905
|
+
setShown(value);
|
|
906
|
+
return;
|
|
907
|
+
}
|
|
908
|
+
timerRef.current = setTimeout(() => {
|
|
909
|
+
lastUpdateRef.current = Date.now();
|
|
910
|
+
setShown(value);
|
|
911
|
+
timerRef.current = void 0;
|
|
912
|
+
}, intervalMs - elapsed);
|
|
913
|
+
return () => {
|
|
914
|
+
if (timerRef.current) {
|
|
915
|
+
clearTimeout(timerRef.current);
|
|
916
|
+
timerRef.current = void 0;
|
|
917
|
+
}
|
|
918
|
+
};
|
|
919
|
+
}, [value, intervalMs, enabled]);
|
|
920
|
+
return enabled ? shown : value;
|
|
921
|
+
}
|
|
922
|
+
|
|
876
923
|
// src/view/chrome/artifact-card.tsx
|
|
877
924
|
function buildArtifactCardFragment(artifact) {
|
|
878
925
|
return {
|
|
@@ -1119,7 +1166,8 @@ function SmoothText({ content, streaming }) {
|
|
|
1119
1166
|
}
|
|
1120
1167
|
function SmoothMarkdown({ content, streaming }) {
|
|
1121
1168
|
const shown = useSmoothStreamText(content, streaming);
|
|
1122
|
-
|
|
1169
|
+
const throttled = useThrottledValue(shown, 100, streaming);
|
|
1170
|
+
return /* @__PURE__ */ jsx3(MarkdownRenderer, { content: throttled });
|
|
1123
1171
|
}
|
|
1124
1172
|
function PartRenderer({ part, runtime, scope, streaming = false, onOpenArtifact }) {
|
|
1125
1173
|
switch (part.type) {
|
|
@@ -1331,13 +1379,13 @@ function ArtifactPanel({
|
|
|
1331
1379
|
className
|
|
1332
1380
|
}) {
|
|
1333
1381
|
const runtime = useArtifactRuntime(safeRegistry, user);
|
|
1334
|
-
const closeRef =
|
|
1382
|
+
const closeRef = useRef4(onClose);
|
|
1335
1383
|
closeRef.current = onClose;
|
|
1336
|
-
|
|
1384
|
+
useEffect3(() => {
|
|
1337
1385
|
setChatChromeHandlers({ panelClose: () => closeRef.current?.() });
|
|
1338
1386
|
}, []);
|
|
1339
|
-
const panelRef =
|
|
1340
|
-
const [width, setWidth] =
|
|
1387
|
+
const panelRef = useRef4(null);
|
|
1388
|
+
const [width, setWidth] = useState5(null);
|
|
1341
1389
|
const handleResizeStart = (event) => {
|
|
1342
1390
|
event.preventDefault();
|
|
1343
1391
|
const panel = panelRef.current;
|
|
@@ -1414,18 +1462,18 @@ function ArtifactPanel({
|
|
|
1414
1462
|
// src/view/ChatView.tsx
|
|
1415
1463
|
import { Icon as Icon9 } from "@pactor-app/ui/components";
|
|
1416
1464
|
import { Registry as Registry3 } from "@pactor-app/core";
|
|
1417
|
-
import { useEffect as
|
|
1465
|
+
import { useEffect as useEffect9, useMemo as useMemo3, useRef as useRef11, useState as useState13, useSyncExternalStore } from "react";
|
|
1418
1466
|
|
|
1419
1467
|
// src/view/Composer.tsx
|
|
1420
1468
|
import { Icon as Icon6 } from "@pactor-app/ui/components";
|
|
1421
|
-
import { useLayoutEffect as useLayoutEffect3, useMemo as useMemo2, useRef as
|
|
1469
|
+
import { useLayoutEffect as useLayoutEffect3, useMemo as useMemo2, useRef as useRef7, useState as useState9 } from "react";
|
|
1422
1470
|
|
|
1423
1471
|
// src/view/AnchoredPopover.tsx
|
|
1424
1472
|
import {
|
|
1425
|
-
useEffect as
|
|
1473
|
+
useEffect as useEffect4,
|
|
1426
1474
|
useLayoutEffect as useLayoutEffect2,
|
|
1427
|
-
useRef as
|
|
1428
|
-
useState as
|
|
1475
|
+
useRef as useRef5,
|
|
1476
|
+
useState as useState6
|
|
1429
1477
|
} from "react";
|
|
1430
1478
|
import { jsx as jsx6 } from "react/jsx-runtime";
|
|
1431
1479
|
function AnchoredPopover({
|
|
@@ -1436,8 +1484,8 @@ function AnchoredPopover({
|
|
|
1436
1484
|
role = "dialog",
|
|
1437
1485
|
sideOffset = 8
|
|
1438
1486
|
}) {
|
|
1439
|
-
const ref =
|
|
1440
|
-
const [position, setPosition] =
|
|
1487
|
+
const ref = useRef5(null);
|
|
1488
|
+
const [position, setPosition] = useState6(null);
|
|
1441
1489
|
useLayoutEffect2(() => {
|
|
1442
1490
|
const element = ref.current;
|
|
1443
1491
|
if (!element) return;
|
|
@@ -1456,7 +1504,7 @@ function AnchoredPopover({
|
|
|
1456
1504
|
}
|
|
1457
1505
|
);
|
|
1458
1506
|
}, [anchorRect, sideOffset]);
|
|
1459
|
-
|
|
1507
|
+
useEffect4(() => {
|
|
1460
1508
|
const onKeyDown = (event) => {
|
|
1461
1509
|
if (event.key !== "Escape") return;
|
|
1462
1510
|
const element = ref.current;
|
|
@@ -1504,7 +1552,7 @@ function AnchoredPopover({
|
|
|
1504
1552
|
|
|
1505
1553
|
// src/view/ModelChip.tsx
|
|
1506
1554
|
import { Icon as Icon4 } from "@pactor-app/ui/components";
|
|
1507
|
-
import { useEffect as
|
|
1555
|
+
import { useEffect as useEffect5, useRef as useRef6, useState as useState7 } from "react";
|
|
1508
1556
|
|
|
1509
1557
|
// src/view/chrome/model-select.tsx
|
|
1510
1558
|
function buildModelSelectFragment(props) {
|
|
@@ -1536,8 +1584,8 @@ function ModelChip({
|
|
|
1536
1584
|
model,
|
|
1537
1585
|
onModelChange
|
|
1538
1586
|
}) {
|
|
1539
|
-
const chipRef =
|
|
1540
|
-
const [anchor, setAnchor] =
|
|
1587
|
+
const chipRef = useRef6(null);
|
|
1588
|
+
const [anchor, setAnchor] = useState7(null);
|
|
1541
1589
|
const currentOption = models.find((option) => option.value === model) ?? models[0];
|
|
1542
1590
|
return /* @__PURE__ */ jsxs3(Fragment4, { children: [
|
|
1543
1591
|
/* @__PURE__ */ jsxs3(
|
|
@@ -1588,9 +1636,9 @@ function ModelSelect({
|
|
|
1588
1636
|
model,
|
|
1589
1637
|
onModelChange
|
|
1590
1638
|
}) {
|
|
1591
|
-
const changeRef =
|
|
1639
|
+
const changeRef = useRef6(onModelChange);
|
|
1592
1640
|
changeRef.current = onModelChange;
|
|
1593
|
-
|
|
1641
|
+
useEffect5(() => {
|
|
1594
1642
|
setChatChromeHandlers({
|
|
1595
1643
|
modelChange: (value) => changeRef.current?.(value)
|
|
1596
1644
|
});
|
|
@@ -1818,7 +1866,7 @@ function buildComposerFragment(props) {
|
|
|
1818
1866
|
}
|
|
1819
1867
|
|
|
1820
1868
|
// src/view/context-sources.tsx
|
|
1821
|
-
import { useEffect as
|
|
1869
|
+
import { useEffect as useEffect6, useState as useState8 } from "react";
|
|
1822
1870
|
import { jsx as jsx9, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
1823
1871
|
function sourceCacheKey(source) {
|
|
1824
1872
|
return `${source.service ?? ""}:${JSON.stringify(source.params ?? {})}`;
|
|
@@ -1854,8 +1902,8 @@ function ContextSourceList({
|
|
|
1854
1902
|
cache,
|
|
1855
1903
|
onSelect
|
|
1856
1904
|
}) {
|
|
1857
|
-
const [resolutions, setResolutions] =
|
|
1858
|
-
|
|
1905
|
+
const [resolutions, setResolutions] = useState8([]);
|
|
1906
|
+
useEffect6(() => {
|
|
1859
1907
|
let cancelled = false;
|
|
1860
1908
|
const initial = sources.map(
|
|
1861
1909
|
(source) => source.items ? { status: "ready", items: source.items } : { status: "loading" }
|
|
@@ -1955,12 +2003,12 @@ function Composer({
|
|
|
1955
2003
|
composerFooter,
|
|
1956
2004
|
hideToolbar = false
|
|
1957
2005
|
}) {
|
|
1958
|
-
const [text, setText] =
|
|
1959
|
-
const [dragOver, setDragOver] =
|
|
1960
|
-
const inputRef =
|
|
1961
|
-
const fileInputRef =
|
|
1962
|
-
const plusButtonRef =
|
|
1963
|
-
const composingRef =
|
|
2006
|
+
const [text, setText] = useState9("");
|
|
2007
|
+
const [dragOver, setDragOver] = useState9(false);
|
|
2008
|
+
const inputRef = useRef7(null);
|
|
2009
|
+
const fileInputRef = useRef7(null);
|
|
2010
|
+
const plusButtonRef = useRef7(null);
|
|
2011
|
+
const composingRef = useRef7(false);
|
|
1964
2012
|
const modelChipEnabled = models !== void 0 && models.length > 0;
|
|
1965
2013
|
const mentionSources = useMemo2(
|
|
1966
2014
|
() => contextSources?.filter((source) => source.trigger === "@") ?? [],
|
|
@@ -1972,9 +2020,9 @@ function Composer({
|
|
|
1972
2020
|
);
|
|
1973
2021
|
const builtinMentionEnabled = onMentionTrigger === void 0 && mentionSources.length > 0;
|
|
1974
2022
|
const builtinPlusEnabled = onPlusMenu === void 0 && plusSources.length > 0;
|
|
1975
|
-
const [mentionState, setMentionState] =
|
|
1976
|
-
const [plusAnchor, setPlusAnchor] =
|
|
1977
|
-
const sourceCacheRef =
|
|
2023
|
+
const [mentionState, setMentionState] = useState9(null);
|
|
2024
|
+
const [plusAnchor, setPlusAnchor] = useState9(null);
|
|
2025
|
+
const sourceCacheRef = useRef7(null);
|
|
1978
2026
|
if (sourceCacheRef.current === null) {
|
|
1979
2027
|
sourceCacheRef.current = /* @__PURE__ */ new Map();
|
|
1980
2028
|
}
|
|
@@ -2008,7 +2056,7 @@ function Composer({
|
|
|
2008
2056
|
onSend?.(value);
|
|
2009
2057
|
setText("");
|
|
2010
2058
|
};
|
|
2011
|
-
const sendRef =
|
|
2059
|
+
const sendRef = useRef7(send);
|
|
2012
2060
|
sendRef.current = send;
|
|
2013
2061
|
useLayoutEffect3(() => {
|
|
2014
2062
|
setChatChromeHandlers({ composerSubmit: () => sendRef.current() });
|
|
@@ -2427,15 +2475,15 @@ function EmptyState({
|
|
|
2427
2475
|
}
|
|
2428
2476
|
|
|
2429
2477
|
// src/view/MessageBubble.tsx
|
|
2430
|
-
import { useRef as
|
|
2478
|
+
import { useRef as useRef10, useState as useState12 } from "react";
|
|
2431
2479
|
|
|
2432
2480
|
// src/view/ActivityTrace.tsx
|
|
2433
2481
|
import { Icon as Icon7 } from "@pactor-app/ui/components";
|
|
2434
2482
|
import { MarkdownRenderer as MarkdownRenderer3 } from "@pactor-app/markdown";
|
|
2435
|
-
import { useEffect as
|
|
2483
|
+
import { useEffect as useEffect7, useRef as useRef8, useState as useState10 } from "react";
|
|
2436
2484
|
import { Fragment as Fragment8, jsx as jsx12, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
2437
2485
|
function usePinnedCollapse(autoOpen) {
|
|
2438
|
-
const [state, setState] =
|
|
2486
|
+
const [state, setState] = useState10("auto");
|
|
2439
2487
|
const open = state === "auto" ? autoOpen : state === "pinned-open";
|
|
2440
2488
|
const toggle = () => {
|
|
2441
2489
|
setState(open ? "pinned-closed" : "pinned-open");
|
|
@@ -2461,8 +2509,8 @@ function statusText(message, mode, toolCount) {
|
|
|
2461
2509
|
}
|
|
2462
2510
|
function useElapsedSeconds(startedAt, active) {
|
|
2463
2511
|
const compute = () => Math.max(0, Math.floor((Date.now() - startedAt) / 1e3));
|
|
2464
|
-
const [elapsed, setElapsed] =
|
|
2465
|
-
|
|
2512
|
+
const [elapsed, setElapsed] = useState10(compute);
|
|
2513
|
+
useEffect7(() => {
|
|
2466
2514
|
if (!active) {
|
|
2467
2515
|
setElapsed(compute());
|
|
2468
2516
|
return;
|
|
@@ -2513,7 +2561,7 @@ function formatDetail(value) {
|
|
|
2513
2561
|
}
|
|
2514
2562
|
}
|
|
2515
2563
|
function TraceRow({ entry }) {
|
|
2516
|
-
const [open, setOpen] =
|
|
2564
|
+
const [open, setOpen] = useState10(false);
|
|
2517
2565
|
const summary = summarizeArgs(entry.args);
|
|
2518
2566
|
return /* @__PURE__ */ jsxs8(
|
|
2519
2567
|
"div",
|
|
@@ -2550,6 +2598,7 @@ function ThinkingCard({
|
|
|
2550
2598
|
answerPhase
|
|
2551
2599
|
}) {
|
|
2552
2600
|
const partStreaming = part.status === "streaming";
|
|
2601
|
+
const shown = useThrottledValue(part.content, 120, partStreaming);
|
|
2553
2602
|
const { open, toggle } = usePinnedCollapse(partStreaming && !answerPhase);
|
|
2554
2603
|
return /* @__PURE__ */ jsxs8(
|
|
2555
2604
|
"div",
|
|
@@ -2572,7 +2621,7 @@ function ThinkingCard({
|
|
|
2572
2621
|
]
|
|
2573
2622
|
}
|
|
2574
2623
|
),
|
|
2575
|
-
open && /* @__PURE__ */ jsx12("div", { className: "pactor-chat-thinking__body", children: /* @__PURE__ */ jsx12(MarkdownRenderer3, { content: part.content }) })
|
|
2624
|
+
open && /* @__PURE__ */ jsx12("div", { className: "pactor-chat-thinking__body", children: partStreaming ? /* @__PURE__ */ jsx12("div", { className: "pactor-chat-thinking__text", children: shown }) : /* @__PURE__ */ jsx12(MarkdownRenderer3, { content: part.content }) })
|
|
2576
2625
|
]
|
|
2577
2626
|
}
|
|
2578
2627
|
);
|
|
@@ -2586,7 +2635,7 @@ function ActivityTrace({ message }) {
|
|
|
2586
2635
|
);
|
|
2587
2636
|
const answerPhase = mode === "responding" || !streaming;
|
|
2588
2637
|
const { open, toggle } = usePinnedCollapse(!answerPhase);
|
|
2589
|
-
const mountTimeRef =
|
|
2638
|
+
const mountTimeRef = useRef8(0);
|
|
2590
2639
|
if (mountTimeRef.current === 0) {
|
|
2591
2640
|
mountTimeRef.current = Date.now();
|
|
2592
2641
|
}
|
|
@@ -2634,7 +2683,7 @@ function ActivityTrace({ message }) {
|
|
|
2634
2683
|
|
|
2635
2684
|
// src/view/MessageActions.tsx
|
|
2636
2685
|
import { Icon as Icon8 } from "@pactor-app/ui/components";
|
|
2637
|
-
import { useEffect as
|
|
2686
|
+
import { useEffect as useEffect8, useRef as useRef9, useState as useState11 } from "react";
|
|
2638
2687
|
|
|
2639
2688
|
// src/view/chrome/message-actions.tsx
|
|
2640
2689
|
function buildMessageActionsFragment(args) {
|
|
@@ -2760,13 +2809,13 @@ function MessageActions({
|
|
|
2760
2809
|
callService,
|
|
2761
2810
|
onMessageAction
|
|
2762
2811
|
}) {
|
|
2763
|
-
const [copied, setCopied] =
|
|
2764
|
-
const dispatchRef =
|
|
2812
|
+
const [copied, setCopied] = useState11(false);
|
|
2813
|
+
const dispatchRef = useRef9(
|
|
2765
2814
|
() => {
|
|
2766
2815
|
}
|
|
2767
2816
|
);
|
|
2768
|
-
const visibleActionsRef =
|
|
2769
|
-
|
|
2817
|
+
const visibleActionsRef = useRef9([]);
|
|
2818
|
+
useEffect8(() => {
|
|
2770
2819
|
setMessageActionDispatcher(message.id, (actionId) => {
|
|
2771
2820
|
const action = visibleActionsRef.current.find((a) => a.id === actionId);
|
|
2772
2821
|
if (action) {
|
|
@@ -2880,7 +2929,7 @@ function MessageEditForm({
|
|
|
2880
2929
|
onConfirm,
|
|
2881
2930
|
onCancel
|
|
2882
2931
|
}) {
|
|
2883
|
-
const [text, setText] =
|
|
2932
|
+
const [text, setText] = useState12(initialText);
|
|
2884
2933
|
const confirm = () => {
|
|
2885
2934
|
const value = text.trim();
|
|
2886
2935
|
if (!value) {
|
|
@@ -2944,7 +2993,7 @@ function MessageBubble({
|
|
|
2944
2993
|
onMessageAction,
|
|
2945
2994
|
onOpenArtifact
|
|
2946
2995
|
}) {
|
|
2947
|
-
const [editing, setEditing] =
|
|
2996
|
+
const [editing, setEditing] = useState12(false);
|
|
2948
2997
|
const bubbleScope = {
|
|
2949
2998
|
conversation: scope?.conversation ?? {},
|
|
2950
2999
|
message: { id: message.id },
|
|
@@ -2952,7 +3001,7 @@ function MessageBubble({
|
|
|
2952
3001
|
};
|
|
2953
3002
|
const streaming = message.status === "streaming";
|
|
2954
3003
|
const live = message.status === "pending" || message.status === "streaming";
|
|
2955
|
-
const wasLiveRef =
|
|
3004
|
+
const wasLiveRef = useRef10(live);
|
|
2956
3005
|
if (live) {
|
|
2957
3006
|
wasLiveRef.current = true;
|
|
2958
3007
|
}
|
|
@@ -3087,8 +3136,8 @@ function ChatView({
|
|
|
3087
3136
|
() => ({ conversation: { id: conversationId }, params }),
|
|
3088
3137
|
[conversationId, params]
|
|
3089
3138
|
);
|
|
3090
|
-
const notifiedArtifactsRef =
|
|
3091
|
-
|
|
3139
|
+
const notifiedArtifactsRef = useRef11(/* @__PURE__ */ new Set());
|
|
3140
|
+
useEffect9(() => {
|
|
3092
3141
|
if (!onArtifact) {
|
|
3093
3142
|
return;
|
|
3094
3143
|
}
|
|
@@ -3107,7 +3156,7 @@ function ChatView({
|
|
|
3107
3156
|
});
|
|
3108
3157
|
}
|
|
3109
3158
|
}, [messages, onArtifact]);
|
|
3110
|
-
const abortRef =
|
|
3159
|
+
const abortRef = useRef11(null);
|
|
3111
3160
|
const { containerRef, isFollowing, scrollToBottom } = useChatAutoScroll({
|
|
3112
3161
|
messageCount: messages.length,
|
|
3113
3162
|
lastContentLength: lastContentLength(messages),
|
|
@@ -3118,7 +3167,7 @@ function ChatView({
|
|
|
3118
3167
|
model,
|
|
3119
3168
|
onModelChange
|
|
3120
3169
|
});
|
|
3121
|
-
const [contextChips, setContextChips] =
|
|
3170
|
+
const [contextChips, setContextChips] = useState13([]);
|
|
3122
3171
|
const handleContextChipsChange = (chips) => {
|
|
3123
3172
|
setContextChips(chips);
|
|
3124
3173
|
onContextsChange?.(chips);
|
|
@@ -3150,11 +3199,11 @@ function ChatView({
|
|
|
3150
3199
|
abortRef.current?.abort();
|
|
3151
3200
|
abortRef.current = null;
|
|
3152
3201
|
};
|
|
3153
|
-
const handleSendRef =
|
|
3202
|
+
const handleSendRef = useRef11(handleSend);
|
|
3154
3203
|
handleSendRef.current = handleSend;
|
|
3155
|
-
const onOpenArtifactRef =
|
|
3204
|
+
const onOpenArtifactRef = useRef11(onOpenArtifact);
|
|
3156
3205
|
onOpenArtifactRef.current = onOpenArtifact;
|
|
3157
|
-
|
|
3206
|
+
useEffect9(() => {
|
|
3158
3207
|
setChatChromeHandlers({
|
|
3159
3208
|
sendSuggestion: (text) => handleSendRef.current(text),
|
|
3160
3209
|
openArtifact: (artifact) => onOpenArtifactRef.current?.(artifact)
|
|
@@ -3261,7 +3310,7 @@ function ChatView({
|
|
|
3261
3310
|
|
|
3262
3311
|
// src/view/WorkspaceHeader.tsx
|
|
3263
3312
|
import { Icon as Icon10 } from "@pactor-app/ui/components";
|
|
3264
|
-
import { useEffect as
|
|
3313
|
+
import { useEffect as useEffect10, useRef as useRef12, useState as useState14 } from "react";
|
|
3265
3314
|
|
|
3266
3315
|
// src/export-markdown.ts
|
|
3267
3316
|
var ROLE_LABELS = {
|
|
@@ -3358,10 +3407,10 @@ function WorkspaceHeader({
|
|
|
3358
3407
|
onTitleChange
|
|
3359
3408
|
}) {
|
|
3360
3409
|
const hasActions = headerActions !== void 0 && headerActions.length > 0;
|
|
3361
|
-
const [overrideTitle, setOverrideTitle] =
|
|
3362
|
-
const [editing, setEditing] =
|
|
3363
|
-
const [draft, setDraft] =
|
|
3364
|
-
const prevTitleRef =
|
|
3410
|
+
const [overrideTitle, setOverrideTitle] = useState14(null);
|
|
3411
|
+
const [editing, setEditing] = useState14(false);
|
|
3412
|
+
const [draft, setDraft] = useState14("");
|
|
3413
|
+
const prevTitleRef = useRef12(title);
|
|
3365
3414
|
if (prevTitleRef.current !== title) {
|
|
3366
3415
|
prevTitleRef.current = title;
|
|
3367
3416
|
if (overrideTitle !== null) {
|
|
@@ -3369,7 +3418,7 @@ function WorkspaceHeader({
|
|
|
3369
3418
|
}
|
|
3370
3419
|
}
|
|
3371
3420
|
const displayTitle = overrideTitle ?? title;
|
|
3372
|
-
const [theme, setTheme] =
|
|
3421
|
+
const [theme, setTheme] = useState14(readCurrentTheme);
|
|
3373
3422
|
const commitTitle = () => {
|
|
3374
3423
|
setEditing(false);
|
|
3375
3424
|
const next = draft.trim();
|
|
@@ -3396,9 +3445,9 @@ function WorkspaceHeader({
|
|
|
3396
3445
|
store.clear();
|
|
3397
3446
|
onClear?.();
|
|
3398
3447
|
};
|
|
3399
|
-
const handlersRef =
|
|
3448
|
+
const handlersRef = useRef12({ handleExport, handleTheme, handleClear });
|
|
3400
3449
|
handlersRef.current = { handleExport, handleTheme, handleClear };
|
|
3401
|
-
|
|
3450
|
+
useEffect10(() => {
|
|
3402
3451
|
setChatChromeHandlers({
|
|
3403
3452
|
headerAction: (name) => {
|
|
3404
3453
|
const handlers2 = handlersRef.current;
|
|
@@ -3582,12 +3631,12 @@ function ChatComposition({
|
|
|
3582
3631
|
onArtifact,
|
|
3583
3632
|
onOpenArtifact
|
|
3584
3633
|
}) {
|
|
3585
|
-
const storeRef =
|
|
3634
|
+
const storeRef = useRef13(null);
|
|
3586
3635
|
if (storeRef.current === null) {
|
|
3587
3636
|
storeRef.current = services.store ?? services.storeFactory?.() ?? new ConversationStore();
|
|
3588
3637
|
}
|
|
3589
3638
|
const store = storeRef.current;
|
|
3590
|
-
const artifactStoreRef =
|
|
3639
|
+
const artifactStoreRef = useRef13(null);
|
|
3591
3640
|
if (artifactStoreRef.current === null) {
|
|
3592
3641
|
artifactStoreRef.current = services.artifactStore ?? new ArtifactStore();
|
|
3593
3642
|
}
|
|
@@ -3611,7 +3660,7 @@ function ChatComposition({
|
|
|
3611
3660
|
artifactStore.open(next);
|
|
3612
3661
|
}
|
|
3613
3662
|
};
|
|
3614
|
-
const [attachments, setAttachments] =
|
|
3663
|
+
const [attachments, setAttachments] = useState15([]);
|
|
3615
3664
|
const handleAttachFiles = services.onAttachFiles ? (files) => {
|
|
3616
3665
|
void Promise.resolve(services.onAttachFiles(files)).then(
|
|
3617
3666
|
(created) => {
|
|
@@ -3848,7 +3897,7 @@ function createChatWorkspace(services) {
|
|
|
3848
3897
|
|
|
3849
3898
|
// src/view/Chat.tsx
|
|
3850
3899
|
import { createComponentRegistry, Icon as Icon11, RailTooltip } from "@pactor-app/ui/components";
|
|
3851
|
-
import { Fragment as Fragment10, useEffect as
|
|
3900
|
+
import { Fragment as Fragment10, useEffect as useEffect11, useRef as useRef14 } from "react";
|
|
3852
3901
|
|
|
3853
3902
|
// src/view/chrome/menu.tsx
|
|
3854
3903
|
function buildSidebarMenuFragment(props) {
|
|
@@ -3936,13 +3985,13 @@ function ChatSidebarMenu({
|
|
|
3936
3985
|
onMenuSelect
|
|
3937
3986
|
}) {
|
|
3938
3987
|
const drawer = useSidebarDrawer();
|
|
3939
|
-
const menuRef =
|
|
3988
|
+
const menuRef = useRef14(menu);
|
|
3940
3989
|
menuRef.current = menu;
|
|
3941
|
-
const selectRef =
|
|
3990
|
+
const selectRef = useRef14(onMenuSelect);
|
|
3942
3991
|
selectRef.current = onMenuSelect;
|
|
3943
|
-
const drawerRef =
|
|
3992
|
+
const drawerRef = useRef14(drawer);
|
|
3944
3993
|
drawerRef.current = drawer;
|
|
3945
|
-
|
|
3994
|
+
useEffect11(() => {
|
|
3946
3995
|
setChatChromeHandlers({
|
|
3947
3996
|
menuSelect: (key) => {
|
|
3948
3997
|
const item = menuRef.current.find((entry) => entry.key === key);
|
|
@@ -4040,7 +4089,7 @@ function Chat({
|
|
|
4040
4089
|
onMenuSelect
|
|
4041
4090
|
}) {
|
|
4042
4091
|
const services = useChatServices();
|
|
4043
|
-
|
|
4092
|
+
useEffect11(() => {
|
|
4044
4093
|
if (!services) {
|
|
4045
4094
|
console.warn(
|
|
4046
4095
|
"[@pactor-app/chat] Chat \u672A\u68C0\u6D4B\u5230 ChatServicesProvider\uFF1A\u8BF7\u5728\u5E94\u7528\u6839\u90E8\u4EE5 <ChatServicesProvider> \u6CE8\u5165 transport \u7B49\u670D\u52A1"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pactor-app/chat",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "Pactor chat: AI message rendering protocol (message model, streaming reducer, safe registry, capability action) and chat runtime view (ChatView / MessageBubble / PartRenderer / Composer / chat layout)",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pactor",
|
|
@@ -49,11 +49,11 @@
|
|
|
49
49
|
"access": "public"
|
|
50
50
|
},
|
|
51
51
|
"dependencies": {
|
|
52
|
-
"@pactor-app/core": "1.
|
|
53
|
-
"@pactor-app/
|
|
54
|
-
"@pactor-app/permission": "1.
|
|
55
|
-
"@pactor-app/
|
|
56
|
-
"@pactor-app/
|
|
52
|
+
"@pactor-app/core": "1.3.0",
|
|
53
|
+
"@pactor-app/ui": "1.3.0",
|
|
54
|
+
"@pactor-app/permission": "1.3.0",
|
|
55
|
+
"@pactor-app/markdown": "1.3.0",
|
|
56
|
+
"@pactor-app/runtime": "1.3.0"
|
|
57
57
|
},
|
|
58
58
|
"peerDependencies": {
|
|
59
59
|
"react": ">=18"
|