@adecore/agents-react 0.36.0 → 0.37.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/chat/chat-client.d.ts +5 -0
- package/dist/chat/chat-client.js +91 -20
- package/dist/chat/index.d.ts +1 -0
- package/dist/chat/index.js +2 -1
- package/dist/chat/logic/picker-entries.js +11 -6
- package/dist/chat/logic/scrubber.d.ts +4 -2
- package/dist/chat/logic/scrubber.js +3 -3
- package/dist/chat/pending-prompts.d.ts +15 -0
- package/dist/chat/pending-prompts.js +93 -0
- package/dist/chat/reading-width.js +6 -2
- package/dist/chat/ui/PromptComposer.d.ts +2 -2
- package/dist/chat/ui/PromptComposer.js +92 -98
- package/dist/chat/ui/SubagentTimeline.js +128 -182
- package/dist/chat/ui/Timeline.js +86 -60
- package/dist/chat/ui/code-lines.d.ts +5 -0
- package/dist/chat/ui/code-lines.js +37 -0
- package/dist/chat/ui/composer/use-pending-requests.d.ts +2 -2
- package/dist/chat/ui/composer/use-pending-requests.js +29 -37
- package/dist/chat/ui/highlighter.d.ts +1 -1
- package/dist/chat/ui/highlighter.js +4 -2
- package/dist/locales/en/agent-chat.d.ts +1 -0
- package/dist/locales/en/agent-chat.js +1 -0
- package/dist/locales/nl/agent-chat.d.ts +1 -0
- package/dist/locales/nl/agent-chat.js +1 -0
- package/dist/prompts/logic/subjects.d.ts +5 -0
- package/dist/prompts/ui/PromptCard.js +1 -1
- package/dist/prompts/ui/PromptView.js +104 -95
- package/dist/state/chats.d.ts +4 -0
- package/dist/state/chats.js +84 -48
- package/dist/theme.css +1 -1
- package/package.json +8 -8
- package/src/chat/chat-client.ts +92 -21
- package/src/chat/index.ts +2 -0
- package/src/chat/logic/picker-entries.ts +6 -4
- package/src/chat/logic/scrubber.ts +8 -6
- package/src/chat/pending-prompts.ts +108 -0
- package/src/chat/reading-width.ts +9 -2
- package/src/chat/ui/PromptComposer.tsx +10 -7
- package/src/chat/ui/SubagentTimeline.tsx +1 -24
- package/src/chat/ui/Timeline.tsx +66 -40
- package/src/chat/ui/code-lines.ts +37 -0
- package/src/chat/ui/composer/use-pending-requests.ts +13 -21
- package/src/chat/ui/highlighter.ts +4 -3
- package/src/locales/en/agent-chat.ts +1 -0
- package/src/locales/nl/agent-chat.ts +1 -0
- package/src/prompts/logic/subjects.ts +4 -1
- package/src/prompts/ui/PromptCard.tsx +1 -1
- package/src/prompts/ui/PromptView.tsx +7 -1
- package/src/state/chats.ts +63 -18
- package/src/theme.css +1 -1
package/dist/chat/ui/Timeline.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { c as _c } from "react/compiler-runtime";
|
|
2
2
|
import { memo, useCallback, useEffect, useLayoutEffect, useMemo, useReducer, useRef, useState } from 'react';
|
|
3
3
|
import { useTranslation } from 'react-i18next';
|
|
4
|
-
import { useVirtualizer } from '@tanstack/react-virtual';
|
|
4
|
+
import { defaultRangeExtractor, useVirtualizer } from '@tanstack/react-virtual';
|
|
5
5
|
import clsx from 'clsx';
|
|
6
6
|
import { LoaderCircle } from 'lucide-react';
|
|
7
7
|
import { useForkedTurns } from '../forks.js';
|
|
@@ -409,7 +409,8 @@ export function Timeline({
|
|
|
409
409
|
const visuals = useChatRow(chatId, row_3 => row_3?.visuals);
|
|
410
410
|
const forkedTurns = useForkedTurns(chatId);
|
|
411
411
|
const info = useChatRow(chatId, row_4 => row_4?.info ?? null);
|
|
412
|
-
const
|
|
412
|
+
const historyPending = useChatRow(chatId, row_5 => row_5?.historyPending === true);
|
|
413
|
+
const cursor = useChatRow(chatId, row_6 => row_6?.history?.cursor ?? null);
|
|
413
414
|
const scope = useChatScope();
|
|
414
415
|
const {
|
|
415
416
|
id: scopeId,
|
|
@@ -456,9 +457,6 @@ export function Timeline({
|
|
|
456
457
|
});
|
|
457
458
|
const [loadingEarlier, setLoadingEarlier] = useState(false);
|
|
458
459
|
const loadingEarlierRef = useRef(false);
|
|
459
|
-
// The row being read and where it stood, taken after every render, so a page going in above puts it back.
|
|
460
|
-
const anchorRef = useRef(null);
|
|
461
|
-
const headRef = useRef(undefined);
|
|
462
460
|
const loadEarlier = useCallback(() => {
|
|
463
461
|
if (cursor === null || loadingEarlierRef.current) {
|
|
464
462
|
return;
|
|
@@ -490,9 +488,10 @@ export function Timeline({
|
|
|
490
488
|
const heldFrom = cursor === null ? null : items?.[order?.[0] ?? '']?.createdAt ?? null;
|
|
491
489
|
const rows = useMemo(() => withTimedRows(threadRows, timedRowsOf(cards, drawsVisuals ? visuals ?? [] : null, heldFrom)), [threadRows, cards, drawsVisuals, visuals, heldFrom]);
|
|
492
490
|
const welcomes = useHostWelcome(chatId);
|
|
491
|
+
const loadingHistory = historyPending && (info !== null && (info.usage.turns > 0 || info.activeTurnId !== null) || (order?.length ?? 0) > 0);
|
|
493
492
|
const empty = rows.length === 0;
|
|
494
493
|
// A chat that took a turn before is one whose thread has not come in yet, not one to greet.
|
|
495
|
-
const welcome = welcomes && empty && (info === null || info.usage.turns === 0 && info.activeTurnId === null);
|
|
494
|
+
const welcome = !loadingHistory && welcomes && empty && (info === null || info.usage.turns === 0 && info.activeTurnId === null);
|
|
496
495
|
const marks = useMemo(() => bookmarkRows(rows, bookmarks ?? [], items ?? {}), [rows, bookmarks, items]);
|
|
497
496
|
const ticks = useMemo(() => ticksOf(rows, marks), [rows, marks]);
|
|
498
497
|
// A message a jump is on its way to; it may first have to open the turn its reply folded into.
|
|
@@ -519,7 +518,7 @@ export function Timeline({
|
|
|
519
518
|
} : null
|
|
520
519
|
}), [revealBlock, flash, keyOf, chatId]);
|
|
521
520
|
// Whether the thread's text clears the strip depends on the width of the view, which only the thread's own frame tells.
|
|
522
|
-
|
|
521
|
+
useLayoutEffect(() => {
|
|
523
522
|
const element = frameRef.current;
|
|
524
523
|
if (element === null || typeof ResizeObserver === 'undefined') {
|
|
525
524
|
return;
|
|
@@ -555,14 +554,32 @@ export function Timeline({
|
|
|
555
554
|
useEffect(() => registerTimeline(chatId, scrollRef.current, enabled => {
|
|
556
555
|
followRef.current = enabled;
|
|
557
556
|
}, () => coveredHeightRef.current), [chatId]);
|
|
557
|
+
const [measuredThread, setMeasuredThread] = useState(null);
|
|
558
|
+
const initialLayout = measuredThread !== keyOf(chatId);
|
|
559
|
+
const [, settleLayout] = useReducer(count => count + 1, 0);
|
|
560
|
+
// Changing this callback invalidates every cached measurement, including on a scroll.
|
|
561
|
+
const getItemKey = useCallback(index => rows[index].id, [rows]);
|
|
558
562
|
// Nothing here builds with the React Compiler, so its memoization rule has nothing to break.
|
|
559
563
|
// oxlint-disable-next-line react/incompatible-library
|
|
560
564
|
const virtualizer = useVirtualizer({
|
|
561
|
-
count: rows.length,
|
|
565
|
+
count: loadingHistory ? 0 : rows.length,
|
|
562
566
|
getScrollElement: () => scrollRef.current,
|
|
563
567
|
estimateSize: () => ESTIMATED_ROW_PX,
|
|
564
|
-
getItemKey
|
|
568
|
+
getItemKey,
|
|
565
569
|
overscan: 8,
|
|
570
|
+
anchorTo: 'end',
|
|
571
|
+
// Include the end before the first pin, so its actual heights are known before revealing it.
|
|
572
|
+
rangeExtractor: range => {
|
|
573
|
+
const indexes = defaultRangeExtractor(range);
|
|
574
|
+
if (!initialLayout) {
|
|
575
|
+
return indexes;
|
|
576
|
+
}
|
|
577
|
+
const tail = Math.max(8, Math.ceil(frame.height / ESTIMATED_ROW_PX));
|
|
578
|
+
return [...new Set([...indexes, ...Array.from({
|
|
579
|
+
length: Math.min(tail, range.count)
|
|
580
|
+
}, (_, index_0) => range.count - 1 - index_0)])].sort((left, right) => left - right);
|
|
581
|
+
},
|
|
582
|
+
measureElement: (element_1, entry) => Math.round(entry?.borderBoxSize?.[0]?.blockSize ?? element_1.offsetHeight),
|
|
566
583
|
scrollPaddingEnd: coveredHeight
|
|
567
584
|
});
|
|
568
585
|
/*
|
|
@@ -572,42 +589,34 @@ export function Timeline({
|
|
|
572
589
|
* A word that does not add a line moves nothing, so the thread does not listen to the words.
|
|
573
590
|
*/
|
|
574
591
|
const totalSize = virtualizer.getTotalSize();
|
|
592
|
+
const virtualRows = virtualizer.getVirtualItems();
|
|
575
593
|
useLayoutEffect(() => {
|
|
576
|
-
|
|
577
|
-
if (!followRef.current || element_1 === null) {
|
|
594
|
+
if (!initialLayout || empty || loadingHistory || frame.height === 0) {
|
|
578
595
|
return;
|
|
579
596
|
}
|
|
580
|
-
//
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
height: element_1.scrollHeight,
|
|
585
|
-
viewport: element_1.clientHeight
|
|
586
|
-
};
|
|
587
|
-
}, [rows.length, totalSize, composerHeight, frame.height]);
|
|
588
|
-
// A page that went in above moves every row down by what it measures; the reader stays on the row they were on.
|
|
589
|
-
useLayoutEffect(() => {
|
|
590
|
-
const element_2 = scrollRef.current;
|
|
591
|
-
const head = order?.[0];
|
|
592
|
-
const moved = head !== headRef.current;
|
|
593
|
-
headRef.current = head;
|
|
594
|
-
if (element_2 === null) {
|
|
597
|
+
// Ref measurements can change offsets after render. Commit those offsets before the first paint.
|
|
598
|
+
const measured = virtualizer.getVirtualItems();
|
|
599
|
+
if (virtualRows.length !== measured.length || virtualRows.some((row_7, index_1) => row_7.key !== measured[index_1]?.key || row_7.start !== measured[index_1]?.start || row_7.size !== measured[index_1]?.size)) {
|
|
600
|
+
settleLayout();
|
|
595
601
|
return;
|
|
596
602
|
}
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
+
if (measured.at(-1)?.index === rows.length - 1) {
|
|
604
|
+
setMeasuredThread(keyOf(chatId));
|
|
605
|
+
}
|
|
606
|
+
}, [initialLayout, empty, loadingHistory, frame.height, virtualRows, virtualizer, rows.length, keyOf, chatId]);
|
|
607
|
+
useLayoutEffect(() => {
|
|
608
|
+
const element_2 = scrollRef.current;
|
|
609
|
+
if (!followRef.current || element_2 === null) {
|
|
603
610
|
return;
|
|
604
611
|
}
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
612
|
+
// The composer is in the scroll flow, so its measured height is part of this end position.
|
|
613
|
+
element_2.scrollTop = element_2.scrollHeight;
|
|
614
|
+
scrollGeometry.current = {
|
|
615
|
+
top: element_2.scrollTop,
|
|
616
|
+
height: element_2.scrollHeight,
|
|
617
|
+
viewport: element_2.clientHeight
|
|
609
618
|
};
|
|
610
|
-
});
|
|
619
|
+
}, [rows.length, totalSize, composerHeight, frame.height]);
|
|
611
620
|
// Close to the top, the page before goes in; again after each page that left too little above the reader.
|
|
612
621
|
useEffect(() => {
|
|
613
622
|
const element_3 = scrollRef.current;
|
|
@@ -621,12 +630,15 @@ export function Timeline({
|
|
|
621
630
|
const showsScrubber = frame.column && onMainAgent && ticks.length >= SCRUBBER_MIN_TICKS;
|
|
622
631
|
const readingWidth = useChatPreferences(preferences => preferences.readingWidth);
|
|
623
632
|
const paddingLeft = threadPaddingLeft(frame.width, showsScrubber, readingMeasure(readingWidth));
|
|
624
|
-
|
|
625
|
-
* Where each message starts, from the virtualizer's measurements (an estimate for a row it never
|
|
626
|
-
* drew), so reading the scroll position costs no layout.
|
|
627
|
-
*/
|
|
633
|
+
// The virtualizer materializes measurements on access; binary searches need only a few message starts.
|
|
628
634
|
const measurements = virtualizer.measurementsCache;
|
|
629
|
-
const starts =
|
|
635
|
+
const starts = {
|
|
636
|
+
length: ticks.length,
|
|
637
|
+
at: index_2 => {
|
|
638
|
+
const tick = ticks.at(index_2);
|
|
639
|
+
return tick === undefined ? undefined : measurements[tick.rowIndex]?.start ?? tick.rowIndex * ESTIMATED_ROW_PX;
|
|
640
|
+
}
|
|
641
|
+
};
|
|
630
642
|
const scrollTop = virtualizer.scrollOffset ?? 0;
|
|
631
643
|
const viewport = virtualizer.scrollRect?.height ?? 0;
|
|
632
644
|
const visibleHeight = Math.max(0, viewport - coveredHeight);
|
|
@@ -641,7 +653,7 @@ export function Timeline({
|
|
|
641
653
|
* The virtualizer draws again only when its range of rows changes, which a scroll inside one long
|
|
642
654
|
* row never does; the scroll itself redraws the strip once the messages in view are others.
|
|
643
655
|
*/
|
|
644
|
-
const [, redrawStrip] = useReducer(
|
|
656
|
+
const [, redrawStrip] = useReducer(count_0 => count_0 + 1, 0);
|
|
645
657
|
const stripRef = useRef({
|
|
646
658
|
starts,
|
|
647
659
|
inView
|
|
@@ -685,11 +697,11 @@ export function Timeline({
|
|
|
685
697
|
openGroup: groups.add,
|
|
686
698
|
openSubagent: subagents.add,
|
|
687
699
|
// A row already on screen stays put; the find scrolls to the match itself once it is drawn.
|
|
688
|
-
scrollToRow:
|
|
700
|
+
scrollToRow: index_3 => {
|
|
689
701
|
const top_0 = scrollRef.current?.scrollTop ?? 0;
|
|
690
702
|
const bottom = top_0 + visibleHeightRef.current;
|
|
691
|
-
if (!virtualizer.getVirtualItems().some(virtualRow_0 => virtualRow_0.index ===
|
|
692
|
-
virtualizer.scrollToIndex(
|
|
703
|
+
if (!virtualizer.getVirtualItems().some(virtualRow_0 => virtualRow_0.index === index_3 && virtualRow_0.end > top_0 && virtualRow_0.start < bottom)) {
|
|
704
|
+
virtualizer.scrollToIndex(index_3, {
|
|
693
705
|
align: 'center'
|
|
694
706
|
});
|
|
695
707
|
}
|
|
@@ -707,8 +719,8 @@ export function Timeline({
|
|
|
707
719
|
}, [searching, loadEarlier]);
|
|
708
720
|
const found = useMemo(() => searching ? ticksWithHits(ticks, chatFind.hitRows) : [], [searching, ticks, chatFind.hitRows]);
|
|
709
721
|
const foundCurrent = chatFind.currentRow === null ? null : tickOfRow(ticks, chatFind.currentRow);
|
|
710
|
-
const jumpTo =
|
|
711
|
-
const tick_0 = ticks[
|
|
722
|
+
const jumpTo = index_4 => {
|
|
723
|
+
const tick_0 = ticks[index_4];
|
|
712
724
|
if (!tick_0) {
|
|
713
725
|
return;
|
|
714
726
|
}
|
|
@@ -730,6 +742,9 @@ export function Timeline({
|
|
|
730
742
|
setSeeking(null);
|
|
731
743
|
return;
|
|
732
744
|
}
|
|
745
|
+
if (loadingHistory) {
|
|
746
|
+
return;
|
|
747
|
+
}
|
|
733
748
|
if (seeking.block) {
|
|
734
749
|
const jump = uiReplyJump(seeking.block, rows, items, turns.ids, cursor !== null);
|
|
735
750
|
if (jump.kind === 'earlier') {
|
|
@@ -748,10 +763,10 @@ export function Timeline({
|
|
|
748
763
|
}
|
|
749
764
|
return;
|
|
750
765
|
}
|
|
751
|
-
const
|
|
752
|
-
if (
|
|
766
|
+
const index_5 = rows.findIndex(row_8 => row_8.id === seeking.itemId);
|
|
767
|
+
if (index_5 !== -1) {
|
|
753
768
|
setSeeking(null);
|
|
754
|
-
showRowAtTop(virtualizer, followRef,
|
|
769
|
+
showRowAtTop(virtualizer, followRef, index_5);
|
|
755
770
|
if (seeking.options?.flash) {
|
|
756
771
|
useTimelineFlash.getState().flash(seeking.key, seeking.itemId, false);
|
|
757
772
|
}
|
|
@@ -773,8 +788,8 @@ export function Timeline({
|
|
|
773
788
|
}
|
|
774
789
|
setSeeking(null);
|
|
775
790
|
seeking.options?.onMissing?.();
|
|
776
|
-
}, [seeking, rows, items, turns, virtualizer, cursor, loadEarlier, keyOf, chatId]);
|
|
777
|
-
const waitingForThread = seeking !== null && items === undefined;
|
|
791
|
+
}, [seeking, rows, items, turns, virtualizer, cursor, loadEarlier, keyOf, chatId, loadingHistory]);
|
|
792
|
+
const waitingForThread = seeking !== null && (items === undefined || loadingHistory);
|
|
778
793
|
useEffect(() => {
|
|
779
794
|
if (!waitingForThread) {
|
|
780
795
|
return;
|
|
@@ -845,7 +860,7 @@ export function Timeline({
|
|
|
845
860
|
// The strip is memoized and draws on every scroll, so it gets one callback for its life.
|
|
846
861
|
const jumpRef = useRef(jumpTo);
|
|
847
862
|
jumpRef.current = jumpTo;
|
|
848
|
-
const pick = useCallback(
|
|
863
|
+
const pick = useCallback(index_6 => jumpRef.current(index_6), []);
|
|
849
864
|
// Read when the card asks rather than on every render, so the strip's memo holds while the thread streams.
|
|
850
865
|
const cardChat = useMemo(() => ({
|
|
851
866
|
chatId,
|
|
@@ -863,11 +878,11 @@ export function Timeline({
|
|
|
863
878
|
if (!onMainAgent) {
|
|
864
879
|
return false;
|
|
865
880
|
}
|
|
866
|
-
const
|
|
867
|
-
if (
|
|
881
|
+
const index_7 = stepMessage(starts, i => ticks[i].kind === 'person', scrollTop, direction);
|
|
882
|
+
if (index_7 === null) {
|
|
868
883
|
return false;
|
|
869
884
|
}
|
|
870
|
-
jumpTo(
|
|
885
|
+
jumpTo(index_7);
|
|
871
886
|
return true;
|
|
872
887
|
};
|
|
873
888
|
useEffect(() => registerMessageStepper(keyOf(chatId), direction_0 => stepRef.current(direction_0)), [keyOf, chatId]);
|
|
@@ -953,20 +968,31 @@ export function Timeline({
|
|
|
953
968
|
},
|
|
954
969
|
inert: overlay ? true : undefined,
|
|
955
970
|
onContextMenu: e_0 => setTarget(readTimelineTarget(e_0.target, threadRef.current, withCurrentText(rows, fullItems()))),
|
|
956
|
-
children:
|
|
971
|
+
children: loadingHistory ? /*#__PURE__*/_jsxs("div", {
|
|
972
|
+
className: "flex grow items-center justify-center gap-2 text-sm text-text-muted",
|
|
973
|
+
role: "status",
|
|
974
|
+
children: [/*#__PURE__*/_jsx(Icon, {
|
|
975
|
+
icon: LoaderCircle,
|
|
976
|
+
size: 16,
|
|
977
|
+
className: "animate-spin"
|
|
978
|
+
}), /*#__PURE__*/_jsx("span", {
|
|
979
|
+
children: t('timeline.loading')
|
|
980
|
+
})]
|
|
981
|
+
}) : welcome ? /*#__PURE__*/_jsx(WelcomeGreeting, {
|
|
957
982
|
chatId: chatId
|
|
958
983
|
}) : empty ? /*#__PURE__*/_jsx(EmptyThread, {
|
|
959
984
|
chatId: chatId
|
|
960
985
|
}) : /*#__PURE__*/_jsx("div", {
|
|
961
986
|
className: "relative w-full shrink-0",
|
|
962
987
|
style: {
|
|
963
|
-
height:
|
|
988
|
+
height: totalSize,
|
|
989
|
+
visibility: initialLayout ? 'hidden' : undefined
|
|
964
990
|
},
|
|
965
991
|
children: /*#__PURE__*/_jsx(UiReplyNavigationContext.Provider, {
|
|
966
992
|
value: uiNavigation,
|
|
967
993
|
children: /*#__PURE__*/_jsx(FindRevealContext.Provider, {
|
|
968
994
|
value: chatFind.reveal,
|
|
969
|
-
children:
|
|
995
|
+
children: virtualRows.map(virtualRow_1 => {
|
|
970
996
|
const row_12 = rows[virtualRow_1.index];
|
|
971
997
|
return /*#__PURE__*/_jsx(ThreadRow, {
|
|
972
998
|
row: row_12,
|
|
@@ -7,6 +7,11 @@ export type Tokenize<State> = (code: string, state: State | undefined) => {
|
|
|
7
7
|
lines: CodeToken[][];
|
|
8
8
|
state: State | undefined;
|
|
9
9
|
};
|
|
10
|
+
export declare class TokenCache<State> {
|
|
11
|
+
private readonly entries;
|
|
12
|
+
private size;
|
|
13
|
+
wrap(namespace: string, tokenize: Tokenize<State>): Tokenize<State>;
|
|
14
|
+
}
|
|
10
15
|
export declare class IncrementalLines<State> {
|
|
11
16
|
private readonly tokenize;
|
|
12
17
|
private source;
|
|
@@ -1,3 +1,40 @@
|
|
|
1
|
+
// Virtual rows unmount offscreen; share this budget across their languages and themes.
|
|
2
|
+
const TOKEN_CACHE_BUDGET = 4 * 1024 * 1024;
|
|
3
|
+
const TOKEN_CACHE_ENTRIES = 128;
|
|
4
|
+
export class TokenCache {
|
|
5
|
+
entries = new Map();
|
|
6
|
+
size = 0;
|
|
7
|
+
wrap(namespace, tokenize) {
|
|
8
|
+
return (code, state) => {
|
|
9
|
+
if (state !== undefined) {
|
|
10
|
+
return tokenize(code, state);
|
|
11
|
+
}
|
|
12
|
+
const key = `${namespace}\0${code}`;
|
|
13
|
+
const known = this.entries.get(key);
|
|
14
|
+
if (known !== undefined) {
|
|
15
|
+
this.entries.delete(key);
|
|
16
|
+
this.entries.set(key, known);
|
|
17
|
+
return known.result;
|
|
18
|
+
}
|
|
19
|
+
const result = tokenize(code, state);
|
|
20
|
+
// Account for tokens too, so dense code cannot fill the cache with tiny strings.
|
|
21
|
+
const cost = key.length * 2 + result.lines.reduce((sum, line) => sum + line.length * 64, 0);
|
|
22
|
+
if (cost <= TOKEN_CACHE_BUDGET) {
|
|
23
|
+
while (this.entries.size > 0 && (this.size + cost > TOKEN_CACHE_BUDGET || this.entries.size >= TOKEN_CACHE_ENTRIES)) {
|
|
24
|
+
const oldest = this.entries.keys().next().value;
|
|
25
|
+
this.size -= this.entries.get(oldest).cost;
|
|
26
|
+
this.entries.delete(oldest);
|
|
27
|
+
}
|
|
28
|
+
this.entries.set(key, {
|
|
29
|
+
result,
|
|
30
|
+
cost
|
|
31
|
+
});
|
|
32
|
+
this.size += cost;
|
|
33
|
+
}
|
|
34
|
+
return result;
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
}
|
|
1
38
|
/*
|
|
2
39
|
* The lines of a code block that grows at the end. A line that ended keeps the tokens it got, and
|
|
3
40
|
* the grammar state after it is where the next line starts, so a delta tokenizes the lines that are
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
export declare function usePendingRequests(chatId: string):
|
|
1
|
+
import type { PromptSubject } from '../../../prompts/logic/subjects.js';
|
|
2
|
+
export declare function usePendingRequests(chatId: string): PromptSubject[];
|
|
@@ -1,43 +1,35 @@
|
|
|
1
1
|
import { c as _c } from "react/compiler-runtime";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
|
|
2
|
+
import { useEffect, useState } from 'react';
|
|
3
|
+
import { useChatScope } from '../../../scope.js';
|
|
4
|
+
import { ChatPromptFeed } from '../../pending-prompts.js';
|
|
5
5
|
export function usePendingRequests(chatId) {
|
|
6
|
-
const $ = _c(
|
|
7
|
-
const
|
|
8
|
-
const order = useChatRow(chatId, _temp2);
|
|
9
|
-
const waitingBefore = useChatRow(chatId, _temp3);
|
|
6
|
+
const $ = _c(5);
|
|
7
|
+
const scope = useChatScope();
|
|
10
8
|
let t0;
|
|
11
|
-
if ($[0]
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
for (const item of waitingRequestsOf(structure && order ? {
|
|
15
|
-
structure,
|
|
16
|
-
order,
|
|
17
|
-
waitingBefore
|
|
18
|
-
} : undefined)) {
|
|
19
|
-
if (item.kind === "approval") {
|
|
20
|
-
approvals.push(item);
|
|
21
|
-
} else {
|
|
22
|
-
questions.push(item);
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
t0 = [...approvals, ...questions];
|
|
26
|
-
$[0] = order;
|
|
27
|
-
$[1] = structure;
|
|
28
|
-
$[2] = waitingBefore;
|
|
29
|
-
$[3] = t0;
|
|
9
|
+
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
|
10
|
+
t0 = [];
|
|
11
|
+
$[0] = t0;
|
|
30
12
|
} else {
|
|
31
|
-
t0 = $[
|
|
13
|
+
t0 = $[0];
|
|
32
14
|
}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
15
|
+
const [subjects, setSubjects] = useState(t0);
|
|
16
|
+
let t1;
|
|
17
|
+
let t2;
|
|
18
|
+
if ($[1] !== chatId || $[2] !== scope) {
|
|
19
|
+
t1 = () => {
|
|
20
|
+
const feed = new ChatPromptFeed(scope, chatId, setSubjects);
|
|
21
|
+
feed.start();
|
|
22
|
+
return () => feed.dispose();
|
|
23
|
+
};
|
|
24
|
+
t2 = [scope, chatId];
|
|
25
|
+
$[1] = chatId;
|
|
26
|
+
$[2] = scope;
|
|
27
|
+
$[3] = t1;
|
|
28
|
+
$[4] = t2;
|
|
29
|
+
} else {
|
|
30
|
+
t1 = $[3];
|
|
31
|
+
t2 = $[4];
|
|
32
|
+
}
|
|
33
|
+
useEffect(t1, t2);
|
|
34
|
+
return subjects;
|
|
43
35
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { CSSProperties } from 'react';
|
|
2
2
|
import type { Highlighter } from 'shiki';
|
|
3
|
-
import type
|
|
3
|
+
import { type CodeToken, type Tokenize } from './code-lines.js';
|
|
4
4
|
import { type ChatHost } from '../../host.js';
|
|
5
5
|
export type { Highlighter };
|
|
6
6
|
export type GrammarState = ReturnType<Highlighter['getLastGrammarState']>;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { c as _c } from "react/compiler-runtime";
|
|
2
|
+
import { TokenCache } from './code-lines.js';
|
|
2
3
|
import { useChatHost } from '../../host.js';
|
|
3
4
|
import { shikiThemeOf } from './code-theme.js';
|
|
4
5
|
// A plain language needs no grammar; shiki draws it in the theme's own foreground.
|
|
@@ -22,6 +23,7 @@ function createCodeHighlighter(source) {
|
|
|
22
23
|
const languageLoads = new Map();
|
|
23
24
|
const themes = new Set();
|
|
24
25
|
const themeLoads = new Map();
|
|
26
|
+
const tokens = new TokenCache();
|
|
25
27
|
const tokenizers = new Map();
|
|
26
28
|
const load = () => {
|
|
27
29
|
highlighterLoad ??= source().then(loaded => {
|
|
@@ -83,7 +85,7 @@ function createCodeHighlighter(source) {
|
|
|
83
85
|
theme
|
|
84
86
|
};
|
|
85
87
|
entry = {
|
|
86
|
-
tokenize: (code, state) => {
|
|
88
|
+
tokenize: tokens.wrap(key, (code, state) => {
|
|
87
89
|
const result = loaded.codeToTokens(code, state ? {
|
|
88
90
|
...options,
|
|
89
91
|
grammarState: state
|
|
@@ -92,7 +94,7 @@ function createCodeHighlighter(source) {
|
|
|
92
94
|
lines: result.tokens,
|
|
93
95
|
state: result.grammarState
|
|
94
96
|
};
|
|
95
|
-
},
|
|
97
|
+
}),
|
|
96
98
|
fg: loaded.getTheme(theme).fg
|
|
97
99
|
};
|
|
98
100
|
tokenizers.set(key, entry);
|
|
@@ -233,6 +233,7 @@ export default {
|
|
|
233
233
|
canRead: 'It can read',
|
|
234
234
|
worksIn: 'It works in'
|
|
235
235
|
},
|
|
236
|
+
loading: 'Loading conversation',
|
|
236
237
|
loadingEarlier: 'Loading earlier messages',
|
|
237
238
|
stripFailed: 'Could not show the messages',
|
|
238
239
|
cardFailed: 'Could not show this card',
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { ReactNode } from 'react';
|
|
2
|
+
import type { AgentKind } from '@adecore/agent-contracts';
|
|
2
3
|
import type { ChatHost } from '../../host.js';
|
|
3
4
|
import { type PendingPrompt, type PromptAction, type PromptDraft } from './prompts.js';
|
|
4
5
|
export interface HostPrompt {
|
|
@@ -12,6 +13,10 @@ export type PromptSubject = {
|
|
|
12
13
|
kind: 'chat';
|
|
13
14
|
nodeId: string;
|
|
14
15
|
item: PendingPrompt;
|
|
16
|
+
source?: {
|
|
17
|
+
label: string;
|
|
18
|
+
provider?: AgentKind;
|
|
19
|
+
};
|
|
15
20
|
} | {
|
|
16
21
|
kind: 'host';
|
|
17
22
|
nodeId: string;
|
|
@@ -120,7 +120,7 @@ export function PromptCard(t0) {
|
|
|
120
120
|
let t8;
|
|
121
121
|
if ($[12] !== meta) {
|
|
122
122
|
t8 = meta && /*#__PURE__*/_jsx("div", {
|
|
123
|
-
className: "flex flex-wrap gap-x-3 gap-y-1 text-xs text-text-muted",
|
|
123
|
+
className: "flex flex-wrap items-center gap-x-3 gap-y-1 text-xs text-text-muted",
|
|
124
124
|
children: meta
|
|
125
125
|
});
|
|
126
126
|
$[12] = meta;
|