@datalayer/agent-runtimes 1.3.59 → 1.3.61
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/lib/chat/ChatFloating.d.ts +11 -1
- package/lib/chat/ChatFloating.js +142 -23
- package/lib/chat/assistant/AssistantStage.d.ts +13 -5
- package/lib/chat/assistant/AssistantStage.js +5 -3
- package/lib/chat/assistant/ConversationBalloon.d.ts +71 -0
- package/lib/chat/assistant/ConversationBalloon.js +102 -0
- package/lib/chat/assistant/DecisionAsk.d.ts +31 -0
- package/lib/chat/assistant/DecisionAsk.js +96 -0
- package/lib/chat/assistant/SpeechBalloon.d.ts +17 -4
- package/lib/chat/assistant/SpeechBalloon.js +20 -14
- package/lib/chat/assistant/decisions.d.ts +104 -0
- package/lib/chat/assistant/decisions.js +161 -0
- package/lib/chat/assistant/state.d.ts +1 -1
- package/lib/chat/assistant/state.js +1 -1
- package/lib/chat/base/ChatBase.js +22 -4
- package/lib/chat/marks/toolMarks.js +2 -2
- package/lib/config/AgentConfiguration.d.ts +2 -1
- package/lib/config/AgentConfiguration.js +2 -2
- package/lib/examples/AgentDecideExample.d.ts +24 -0
- package/lib/examples/AgentDecideExample.js +73 -0
- package/lib/examples/AgentNotificationsExample.js +1 -1
- package/lib/examples/AgentSkillsExample.js +1 -1
- package/lib/examples/AgentspecsExample.js +3 -3
- package/lib/examples/ChatAssistantExample.js +12 -1
- package/lib/examples/example-selector.js +1 -0
- package/lib/examples/index.d.ts +1 -0
- package/lib/examples/index.js +1 -0
- package/lib/examples/main.js +3 -0
- package/lib/loop/apps/appspec.js +4 -4
- package/lib/loop/apps/checks.js +6 -6
- package/lib/loop/apps/rules.js +2 -2
- package/lib/loop/plugins/assistant/index.d.ts +14 -2
- package/lib/loop/plugins/assistant/index.js +22 -5
- package/lib/specs/actions.d.ts +1 -1
- package/lib/specs/actions.js +1 -1
- package/lib/specs/agents/agents.js +197 -192
- package/lib/specs/apps.js +13 -13
- package/lib/specs/appspecSchema.js +3 -3
- package/lib/specs/backendTools.d.ts +31 -0
- package/lib/specs/{tools.js → backendTools.js} +48 -48
- package/lib/specs/cogs.js +8 -7
- package/lib/specs/frames.js +5 -5
- package/lib/specs/index.d.ts +1 -1
- package/lib/specs/index.js +1 -1
- package/lib/stores/agentRuntimeStore.js +2 -2
- package/lib/stories/loop/ReferenceScreens.d.ts +6 -2
- package/lib/stories/loop/ReferenceScreens.js +63 -6
- package/lib/types/agentspecs.d.ts +7 -5
- package/lib/types/chat.d.ts +12 -0
- package/lib/types/config.d.ts +2 -2
- package/lib/types/tools.d.ts +3 -3
- package/package.json +1 -1
- package/scripts/codegen/generate_agents.py +23 -12
- package/scripts/codegen/generate_apps.py +3 -2
- package/scripts/codegen/{generate_tools.py → generate_backend_tools.py} +29 -29
- package/scripts/codegen/generate_cogs.py +2 -2
- package/scripts/codegen/generate_frames.py +2 -2
- package/lib/specs/tools.d.ts +0 -31
|
@@ -110,6 +110,16 @@ export interface ChatFloatingProps extends ChatCommonProps {
|
|
|
110
110
|
* @default 'paperclip'
|
|
111
111
|
*/
|
|
112
112
|
assistantCharacter?: string | AssistantCharacter | AssistantCharacterData;
|
|
113
|
+
/**
|
|
114
|
+
* The runtime the floating assistant asks typed decisions at — its
|
|
115
|
+
* `/api/v1/configure/inference/decisions`, as the `decide` tool asks — and
|
|
116
|
+
* the token to ask with, if it needs one: its balloon offers *Ask a
|
|
117
|
+
* decision*, answered there in plain words with its confidence.
|
|
118
|
+
*/
|
|
119
|
+
decisions?: {
|
|
120
|
+
serverUrl: string;
|
|
121
|
+
token?: string;
|
|
122
|
+
};
|
|
113
123
|
/**
|
|
114
124
|
* Callback when the user switches view mode via the header toggle.
|
|
115
125
|
* The parent component receives the new ChatViewMode value.
|
|
@@ -144,5 +154,5 @@ export interface ChatFloatingProps extends ChatCommonProps {
|
|
|
144
154
|
* ChatFloating component
|
|
145
155
|
* A floating chat window built on ChatBase
|
|
146
156
|
*/
|
|
147
|
-
export declare function ChatFloating({ endpoint, protocol: protocolProp, useStore: useStoreMode, title, description, position, defaultOpen, width, height, showHeader, showButton, showNewChatButton, showClearButton, showSettingsButton, enableKeyboardShortcuts, toggleShortcut, showPoweredBy, promptVariant, mentionableAgents, poweredByProps, clickOutsideToClose, escapeToClose, className, onSettingsClick, onNewChat, onOpen, onClose, onStateUpdate, children, brandIcon, buttonIcon, buttonTooltip, brandColor, buttonGlow, offset, animationDuration, renderToolResult, frontendTools, initialState: _initialState, suggestions, submitOnSuggestionClick, hideMessagesAfterToolUI, defaultViewMode, onViewModeChange, sidebarMountPoint, showPanelBackdrop, availableModels, showModelSelector, showToolsMenu, showSkillsMenu, showTokenUsage, showContextRing, themeVariant, themeOverrides, colorMode, runtimeId, historyEndpoint, authToken, historyAuthToken, pendingPrompt, showInformation, onInformationClick, onToolCallStart, onToolCallComplete, showToolApprovalBanner, pendingApprovals, onApproveApproval, onRejectApproval, panelProps, launching, launchingMessage, assistantCharacter, conversation, }: ChatFloatingProps): React.JSX.Element;
|
|
157
|
+
export declare function ChatFloating({ endpoint, protocol: protocolProp, useStore: useStoreMode, title, description, position, defaultOpen, width, height, showHeader, showButton, showNewChatButton, showClearButton, showSettingsButton, enableKeyboardShortcuts, toggleShortcut, showPoweredBy, promptVariant, mentionableAgents, poweredByProps, clickOutsideToClose, escapeToClose, className, onSettingsClick, onNewChat, onOpen, onClose, onStateUpdate, children, brandIcon, buttonIcon, buttonTooltip, brandColor, buttonGlow, offset, animationDuration, renderToolResult, frontendTools, initialState: _initialState, suggestions, submitOnSuggestionClick, hideMessagesAfterToolUI, defaultViewMode, onViewModeChange, sidebarMountPoint, showPanelBackdrop, availableModels, showModelSelector, showToolsMenu, showSkillsMenu, showTokenUsage, showContextRing, themeVariant, themeOverrides, colorMode, runtimeId, historyEndpoint, authToken, historyAuthToken, pendingPrompt, showInformation, onInformationClick, onToolCallStart, onToolCallComplete, showToolApprovalBanner, pendingApprovals, onApproveApproval, onRejectApproval, panelProps, launching, launchingMessage, assistantCharacter, conversation, decisions, }: ChatFloatingProps): React.JSX.Element;
|
|
148
158
|
export default ChatFloating;
|
package/lib/chat/ChatFloating.js
CHANGED
|
@@ -31,6 +31,9 @@ import { ButtonGlow } from './display/ButtonGlow';
|
|
|
31
31
|
import { useViewportDrag } from './useViewportDrag';
|
|
32
32
|
import { disabledChatViewModes, resolveMountPoint } from './viewModes';
|
|
33
33
|
import { AssistantStage } from './assistant/AssistantStage';
|
|
34
|
+
import { decisionsAskerAt } from './assistant/decisions';
|
|
35
|
+
import { DecisionAsk } from './assistant/DecisionAsk';
|
|
36
|
+
import { BalloonApprovalMessage, CONVERSATION_BALLOON_WIDTH, ConversationBalloonClose, balloonTailAt, conversationBalloonHeight, conversationBalloonSx, peekLine, } from './assistant/ConversationBalloon';
|
|
34
37
|
import { SpeechBalloon } from './assistant/SpeechBalloon';
|
|
35
38
|
import { DEFAULT_ASSISTANT_CHARACTER, } from './assistant/characters';
|
|
36
39
|
import { assistantStateOf, latestSaying, newestIsAnswer, keepAway, keptAway, ASSISTANT_WORDS, } from './assistant/state';
|
|
@@ -63,7 +66,7 @@ const clamp = (value, max) => Math.max(8, Math.min(value, Math.max(8, max)));
|
|
|
63
66
|
* ChatFloating component
|
|
64
67
|
* A floating chat window built on ChatBase
|
|
65
68
|
*/
|
|
66
|
-
export function ChatFloating({ endpoint, protocol: protocolProp, useStore: useStoreMode = true, title = 'Chat', description = 'Start a conversation with the AI agent.', position = 'bottom-right', defaultOpen = false, width = 400, height = 550, showHeader = true, showButton = true, showNewChatButton = true, showClearButton = true, showSettingsButton = false, enableKeyboardShortcuts = true, toggleShortcut = '/', showPoweredBy = true, promptVariant, mentionableAgents, poweredByProps, clickOutsideToClose = false, escapeToClose = true, className, onSettingsClick, onNewChat, onOpen, onClose, onStateUpdate, children, brandIcon, buttonIcon, buttonTooltip = 'Chat with AI', brandColor, buttonGlow = true, offset = 20, animationDuration = 200, renderToolResult, frontendTools, initialState: _initialState, suggestions, submitOnSuggestionClick = true, hideMessagesAfterToolUI = false, defaultViewMode = 'floating', onViewModeChange, sidebarMountPoint = null, showPanelBackdrop = false, availableModels, showModelSelector = false, showToolsMenu = false, showSkillsMenu = false, showTokenUsage = true, showContextRing = false, themeVariant, themeOverrides, colorMode, runtimeId, historyEndpoint, authToken, historyAuthToken, pendingPrompt, showInformation = false, onInformationClick, onToolCallStart, onToolCallComplete, showToolApprovalBanner, pendingApprovals, onApproveApproval, onRejectApproval, panelProps, launching = false, launchingMessage, assistantCharacter = DEFAULT_ASSISTANT_CHARACTER, conversation, }) {
|
|
69
|
+
export function ChatFloating({ endpoint, protocol: protocolProp, useStore: useStoreMode = true, title = 'Chat', description = 'Start a conversation with the AI agent.', position = 'bottom-right', defaultOpen = false, width = 400, height = 550, showHeader = true, showButton = true, showNewChatButton = true, showClearButton = true, showSettingsButton = false, enableKeyboardShortcuts = true, toggleShortcut = '/', showPoweredBy = true, promptVariant, mentionableAgents, poweredByProps, clickOutsideToClose = false, escapeToClose = true, className, onSettingsClick, onNewChat, onOpen, onClose, onStateUpdate, children, brandIcon, buttonIcon, buttonTooltip = 'Chat with AI', brandColor, buttonGlow = true, offset = 20, animationDuration = 200, renderToolResult, frontendTools, initialState: _initialState, suggestions, submitOnSuggestionClick = true, hideMessagesAfterToolUI = false, defaultViewMode = 'floating', onViewModeChange, sidebarMountPoint = null, showPanelBackdrop = false, availableModels, showModelSelector = false, showToolsMenu = false, showSkillsMenu = false, showTokenUsage = true, showContextRing = false, themeVariant, themeOverrides, colorMode, runtimeId, historyEndpoint, authToken, historyAuthToken, pendingPrompt, showInformation = false, onInformationClick, onToolCallStart, onToolCallComplete, showToolApprovalBanner, pendingApprovals, onApproveApproval, onRejectApproval, panelProps, launching = false, launchingMessage, assistantCharacter = DEFAULT_ASSISTANT_CHARACTER, conversation, decisions, }) {
|
|
67
70
|
// Store-based state
|
|
68
71
|
const storeIsOpen = useChatOpen();
|
|
69
72
|
const storeMessages = useChatMessages();
|
|
@@ -194,6 +197,9 @@ export function ChatFloating({ endpoint, protocol: protocolProp, useStore: useSt
|
|
|
194
197
|
},
|
|
195
198
|
}
|
|
196
199
|
: undefined;
|
|
200
|
+
const assistantDecide = useMemo(() => decisions?.serverUrl
|
|
201
|
+
? decisionsAskerAt(decisions.serverUrl, decisions.token)
|
|
202
|
+
: undefined, [decisions?.serverUrl, decisions?.token]);
|
|
197
203
|
const assistantBalloon = assistantState === 'paused'
|
|
198
204
|
? { text: ASSISTANT_WORDS.paused }
|
|
199
205
|
: balloonApproval
|
|
@@ -201,7 +207,14 @@ export function ChatFloating({ endpoint, protocol: protocolProp, useStore: useSt
|
|
|
201
207
|
: assistantState === 'waiting'
|
|
202
208
|
? { text: ASSISTANT_WORDS.waiting }
|
|
203
209
|
: unheard && saying
|
|
204
|
-
? {
|
|
210
|
+
? {
|
|
211
|
+
// A peek: the first words; the rest is in the conversation.
|
|
212
|
+
...peekLine(saying.text),
|
|
213
|
+
onDismiss: () => {
|
|
214
|
+
setHeardId(saying.id);
|
|
215
|
+
setFreshSaying(false);
|
|
216
|
+
},
|
|
217
|
+
}
|
|
205
218
|
: { text: description };
|
|
206
219
|
const balloonInsists = assistantState === 'greeting' ||
|
|
207
220
|
assistantState === 'waiting' ||
|
|
@@ -429,19 +442,23 @@ export function ChatFloating({ endpoint, protocol: protocolProp, useStore: useSt
|
|
|
429
442
|
}, [isOpen, handleToggle]);
|
|
430
443
|
/*
|
|
431
444
|
* The conversation as the assistant's balloon: above the character, its
|
|
432
|
-
*
|
|
445
|
+
* edge on the character's, never off the screen, and its tail toward the
|
|
446
|
+
* character — none when it stands beside it.
|
|
433
447
|
*/
|
|
434
|
-
const
|
|
435
|
-
|
|
436
|
-
|
|
448
|
+
const viewportWidth = typeof window === 'undefined' ? 1280 : window.innerWidth;
|
|
449
|
+
const viewportHeight = typeof window === 'undefined' ? 800 : window.innerHeight;
|
|
450
|
+
const conversationHeight = conversationBalloonHeight(viewportHeight);
|
|
451
|
+
const balloonGeometry = () => {
|
|
452
|
+
const widthPx = CONVERSATION_BALLOON_WIDTH;
|
|
453
|
+
const heightPx = conversationHeight;
|
|
437
454
|
if (stageDrag.position) {
|
|
438
455
|
// Toward the page's inside: above the character, below it, or beside
|
|
439
456
|
// it when the window is too short for either.
|
|
440
457
|
const { left, top } = stageDrag.position;
|
|
441
|
-
const onLeft = left + ASSISTANT_SIZE / 2 <
|
|
458
|
+
const onLeft = left + ASSISTANT_SIZE / 2 < viewportWidth / 2;
|
|
442
459
|
const above = top - heightPx - 16;
|
|
443
460
|
const below = top + ASSISTANT_SIZE + 16;
|
|
444
|
-
const beside = above < 8 && below + heightPx >
|
|
461
|
+
const beside = above < 8 && below + heightPx > viewportHeight - 8;
|
|
445
462
|
const x = beside
|
|
446
463
|
? onLeft
|
|
447
464
|
? left + ASSISTANT_SIZE + 16
|
|
@@ -454,17 +471,38 @@ export function ChatFloating({ endpoint, protocol: protocolProp, useStore: useSt
|
|
|
454
471
|
: above >= 8
|
|
455
472
|
? above
|
|
456
473
|
: below;
|
|
474
|
+
const placedX = clamp(x, viewportWidth - widthPx - 8);
|
|
457
475
|
return {
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
476
|
+
place: {
|
|
477
|
+
left: px(placedX),
|
|
478
|
+
top: px(clamp(y, viewportHeight - heightPx - 8)),
|
|
479
|
+
right: 'auto',
|
|
480
|
+
bottom: 'auto',
|
|
481
|
+
},
|
|
482
|
+
tail: beside
|
|
483
|
+
? { edge: 'none' }
|
|
484
|
+
: {
|
|
485
|
+
edge: above >= 8 ? 'bottom' : 'top',
|
|
486
|
+
at: balloonTailAt(left + ASSISTANT_SIZE / 2, placedX),
|
|
487
|
+
},
|
|
462
488
|
};
|
|
463
489
|
}
|
|
490
|
+
const onRight = position.endsWith('right');
|
|
491
|
+
const characterMiddle = onRight
|
|
492
|
+
? viewportWidth - offset - ASSISTANT_SIZE / 2
|
|
493
|
+
: offset + ASSISTANT_SIZE / 2;
|
|
494
|
+
const balloonLeft = onRight ? viewportWidth - offset - widthPx : offset;
|
|
495
|
+
const tail = {
|
|
496
|
+
edge: position.startsWith('bottom') ? 'bottom' : 'top',
|
|
497
|
+
at: balloonTailAt(characterMiddle, balloonLeft),
|
|
498
|
+
};
|
|
464
499
|
const corner = getPositionStyles();
|
|
465
|
-
return
|
|
466
|
-
|
|
467
|
-
|
|
500
|
+
return {
|
|
501
|
+
place: position.startsWith('bottom')
|
|
502
|
+
? { ...corner, bottom: px(offset + ASSISTANT_SIZE + 16) }
|
|
503
|
+
: { ...corner, top: px(offset + ASSISTANT_SIZE + 16) },
|
|
504
|
+
tail,
|
|
505
|
+
};
|
|
468
506
|
};
|
|
469
507
|
// Handle new chat
|
|
470
508
|
const handleNewChat = useCallback(() => {
|
|
@@ -516,6 +554,20 @@ export function ChatFloating({ endpoint, protocol: protocolProp, useStore: useSt
|
|
|
516
554
|
}, animationDuration);
|
|
517
555
|
return () => clearTimeout(timer);
|
|
518
556
|
}, [hostsConversation, isOpen, animationDuration, focusTrigger]);
|
|
557
|
+
/*
|
|
558
|
+
* The assistant's balloon opens on the newest message: the history may
|
|
559
|
+
* have grown — or arrived — while it was closed.
|
|
560
|
+
*/
|
|
561
|
+
useEffect(() => {
|
|
562
|
+
if (!assistantShown || !isOpen) {
|
|
563
|
+
return undefined;
|
|
564
|
+
}
|
|
565
|
+
const timer = setTimeout(() => {
|
|
566
|
+
const history = popupRef.current?.querySelector('[data-chat-history]');
|
|
567
|
+
history?.scrollTo?.({ top: history.scrollHeight });
|
|
568
|
+
}, animationDuration);
|
|
569
|
+
return () => clearTimeout(timer);
|
|
570
|
+
}, [assistantShown, isOpen, animationDuration]);
|
|
519
571
|
// Click outside to close
|
|
520
572
|
useEffect(() => {
|
|
521
573
|
if (!clickOutsideToClose || !isOpen)
|
|
@@ -600,8 +652,18 @@ export function ChatFloating({ endpoint, protocol: protocolProp, useStore: useSt
|
|
|
600
652
|
})
|
|
601
653
|
: undefined;
|
|
602
654
|
// Responsive dimensions
|
|
603
|
-
const
|
|
604
|
-
|
|
655
|
+
const conversationBalloon = assistantShown ? balloonGeometry() : undefined;
|
|
656
|
+
// The assistant's conversation is a balloon of its own size (T-23).
|
|
657
|
+
const popupWidth = isMobile
|
|
658
|
+
? '100%'
|
|
659
|
+
: conversationBalloon
|
|
660
|
+
? CONVERSATION_BALLOON_WIDTH
|
|
661
|
+
: width;
|
|
662
|
+
const popupHeight = isMobile
|
|
663
|
+
? '100%'
|
|
664
|
+
: conversationBalloon
|
|
665
|
+
? conversationHeight
|
|
666
|
+
: height;
|
|
605
667
|
// Mobile full-screen styles
|
|
606
668
|
const mobileStyles = isMobile
|
|
607
669
|
? {
|
|
@@ -617,6 +679,44 @@ export function ChatFloating({ endpoint, protocol: protocolProp, useStore: useSt
|
|
|
617
679
|
: {};
|
|
618
680
|
// Close button for header
|
|
619
681
|
const closeButton = (_jsx(Tooltip, { text: `Close${escapeToClose ? ' (Esc)' : ''}`, direction: "s", children: _jsx(IconButton, { icon: XIcon, "aria-label": "Close", onClick: handleToggle, variant: "invisible", size: "small" }) }));
|
|
682
|
+
/*
|
|
683
|
+
* The chat as the assistant's balloon holds it (T-23): the history and the
|
|
684
|
+
* composer, its Lexical variant, and nothing else — no header, no footer,
|
|
685
|
+
* none of the session's controls; the welcome as the first message, an
|
|
686
|
+
* approval as a message with Approve and Deny, and *Ask a decision* beside
|
|
687
|
+
* the composer when there is a runtime to ask.
|
|
688
|
+
*/
|
|
689
|
+
const assistantChat = conversationBalloon
|
|
690
|
+
? {
|
|
691
|
+
showHeader: false,
|
|
692
|
+
showPoweredBy: false,
|
|
693
|
+
promptVariant: 'lexical',
|
|
694
|
+
showModelSelector: false,
|
|
695
|
+
showToolsMenu: false,
|
|
696
|
+
showSkillsMenu: false,
|
|
697
|
+
showTokenUsage: false,
|
|
698
|
+
showContextRing: false,
|
|
699
|
+
showInformation: false,
|
|
700
|
+
showToolApprovalBanner: false,
|
|
701
|
+
showAgentsMenu: false,
|
|
702
|
+
showTurnFooter: false,
|
|
703
|
+
compact: true,
|
|
704
|
+
welcome: description,
|
|
705
|
+
backgroundColor: 'canvas.default',
|
|
706
|
+
borderRadius: 'var(--theme-radius-bubble, 16px)',
|
|
707
|
+
trailingContent: balloonApproval ? (_jsx(BalloonApprovalMessage, { approval: balloonApproval })) : undefined,
|
|
708
|
+
footerContent: assistantDecide ? (_jsx(Box, { "data-balloon-decisions": "", sx: {
|
|
709
|
+
px: 3,
|
|
710
|
+
pb: 1,
|
|
711
|
+
display: 'flex',
|
|
712
|
+
flexDirection: 'column',
|
|
713
|
+
alignItems: 'flex-end',
|
|
714
|
+
fontSize: 0,
|
|
715
|
+
'& form': { alignSelf: 'stretch' },
|
|
716
|
+
'& [data-balloon-decision="answered"]': { alignSelf: 'stretch' },
|
|
717
|
+
}, children: _jsx(DecisionAsk, { ask: assistantDecide }) })) : undefined,
|
|
718
|
+
}
|
|
719
|
+
: undefined;
|
|
620
720
|
/* The window itself; where it goes is decided below. */
|
|
621
721
|
const chatWindow = (_jsxs(Box, { ref: popupRef, className: className, sx: {
|
|
622
722
|
position: viewMode === 'panel' && !isMobile && (panelInFlow || dockedInMount)
|
|
@@ -647,8 +747,8 @@ export function ChatFloating({ endpoint, protocol: protocolProp, useStore: useSt
|
|
|
647
747
|
}
|
|
648
748
|
: getPositionStyles()
|
|
649
749
|
: {}),
|
|
650
|
-
...(
|
|
651
|
-
?
|
|
750
|
+
...(conversationBalloon
|
|
751
|
+
? conversationBalloon.place
|
|
652
752
|
: assistantMode && !isMobile
|
|
653
753
|
? getPositionStyles()
|
|
654
754
|
: {}),
|
|
@@ -742,7 +842,16 @@ export function ChatFloating({ endpoint, protocol: protocolProp, useStore: useSt
|
|
|
742
842
|
visibility: isOpen || isAnimating ? 'visible' : 'hidden',
|
|
743
843
|
pointerEvents: isOpen ? 'auto' : 'none',
|
|
744
844
|
...mobileStyles,
|
|
745
|
-
|
|
845
|
+
// The assistant's balloon: its shape and its tail toward the
|
|
846
|
+
// character, which the window's own clipping would cut off.
|
|
847
|
+
...(conversationBalloon
|
|
848
|
+
? conversationBalloonSx(conversationBalloon.tail,
|
|
849
|
+
// Out of the composer's band, or of the history's top.
|
|
850
|
+
conversationBalloon.tail.edge === 'bottom'
|
|
851
|
+
? 'canvas.subtle'
|
|
852
|
+
: 'canvas.default')
|
|
853
|
+
: {}),
|
|
854
|
+
}, "data-conversation-balloon": conversationBalloon ? '' : undefined, children: [conversationBalloon ? (_jsx(ConversationBalloonClose, { onClose: handleToggle })) : null, viewMode === 'floating-draggable' && !isMobile && (_jsx(Box, { onPointerDown: drag.onHandlePointerDown, "aria-label": "Move the chat", sx: {
|
|
746
855
|
display: 'flex',
|
|
747
856
|
alignItems: 'center',
|
|
748
857
|
justifyContent: 'center',
|
|
@@ -755,7 +864,7 @@ export function ChatFloating({ endpoint, protocol: protocolProp, useStore: useSt
|
|
|
755
864
|
borderColor: 'border.muted',
|
|
756
865
|
touchAction: 'none',
|
|
757
866
|
'&:active': { cursor: 'grabbing' },
|
|
758
|
-
}, children: _jsx(GrabberIcon, { size: 16 }) })), conversation ? (_jsxs(_Fragment, { children: [showHeader ? (_jsxs(Box, { sx: {
|
|
867
|
+
}, children: _jsx(GrabberIcon, { size: 16 }) })), conversation ? (_jsxs(_Fragment, { children: [showHeader && !conversationBalloon ? (_jsxs(Box, { sx: {
|
|
759
868
|
display: 'flex',
|
|
760
869
|
alignItems: 'center',
|
|
761
870
|
gap: 2,
|
|
@@ -771,7 +880,17 @@ export function ChatFloating({ endpoint, protocol: protocolProp, useStore: useSt
|
|
|
771
880
|
overflow: 'hidden',
|
|
772
881
|
textOverflow: 'ellipsis',
|
|
773
882
|
whiteSpace: 'nowrap',
|
|
774
|
-
}, children: title }), closeButton] })) : null, _jsx(Box, { "data-floating-conversation": true, sx: {
|
|
883
|
+
}, children: title }), closeButton] })) : null, _jsx(Box, { "data-floating-conversation": true, sx: {
|
|
884
|
+
flex: '1 1 auto',
|
|
885
|
+
minHeight: 0,
|
|
886
|
+
display: 'flex',
|
|
887
|
+
...(conversationBalloon
|
|
888
|
+
? {
|
|
889
|
+
borderRadius: 'var(--theme-radius-bubble, 16px)',
|
|
890
|
+
overflow: 'hidden',
|
|
891
|
+
}
|
|
892
|
+
: {}),
|
|
893
|
+
}, children: conversation.body })] })) : (_jsx(ChatBase, { title: title, showHeader: showHeader, useStore: useStoreMode, protocol: protocol, themeVariant: themeVariant, themeOverrides: themeOverrides, colorMode: colorMode, autoFocus: isOpen, focusTrigger: focusTrigger, launching: launching, launchingMessage: launchingMessage, brandIcon: brandIcon || _jsx(AiAgentIcon, { colored: true, size: 20 }), headerButtons: {
|
|
775
894
|
showNewChat: showNewChatButton,
|
|
776
895
|
showClear: showClearButton && messages.length > 0,
|
|
777
896
|
showSettings: showSettingsButton && !!onSettingsClick,
|
|
@@ -787,7 +906,7 @@ export function ChatFloating({ endpoint, protocol: protocolProp, useStore: useSt
|
|
|
787
906
|
...poweredByProps,
|
|
788
907
|
}, renderToolResult: renderToolResult, description: description, onStateUpdate: onStateUpdate, onNewChat: onNewChat, suggestions: suggestions, submitOnSuggestionClick: submitOnSuggestionClick, hideMessagesAfterToolUI: hideMessagesAfterToolUI, avatarConfig: {
|
|
789
908
|
showAvatars: true,
|
|
790
|
-
}, placeholder: "Type a message...", backgroundColor: "canvas.subtle", frontendTools: frontendTools, showModelSelector: showModelSelector, availableModels: availableModels, showToolsMenu: showToolsMenu, showSkillsMenu: showSkillsMenu, showTokenUsage: showTokenUsage, showContextRing: showContextRing, runtimeId: runtimeId, historyEndpoint: historyEndpoint, historyAuthToken: historyAuthToken, pendingPrompt: pendingPrompt, showInformation: showInformation, onInformationClick: onInformationClick, onToolCallStart: onToolCallStart, onToolCallComplete: onToolCallComplete, showToolApprovalBanner: showToolApprovalBanner, pendingApprovals: pendingApprovals, onApproveApproval: onApproveApproval, onRejectApproval: onRejectApproval, ...panelProps, onLoadingChange: handleLoadingChange, onDisplayItemsChange: handleDisplayItemsChange, children: children }))] }));
|
|
909
|
+
}, placeholder: "Type a message...", backgroundColor: "canvas.subtle", frontendTools: frontendTools, showModelSelector: showModelSelector, availableModels: availableModels, showToolsMenu: showToolsMenu, showSkillsMenu: showSkillsMenu, showTokenUsage: showTokenUsage, showContextRing: showContextRing, runtimeId: runtimeId, historyEndpoint: historyEndpoint, historyAuthToken: historyAuthToken, pendingPrompt: pendingPrompt, showInformation: showInformation, onInformationClick: onInformationClick, onToolCallStart: onToolCallStart, onToolCallComplete: onToolCallComplete, showToolApprovalBanner: showToolApprovalBanner, pendingApprovals: pendingApprovals, onApproveApproval: onApproveApproval, onRejectApproval: onRejectApproval, ...panelProps, ...assistantChat, onLoadingChange: handleLoadingChange, onDisplayItemsChange: handleDisplayItemsChange, children: children }))] }));
|
|
791
910
|
/*
|
|
792
911
|
* The floating popup's button. Words not yet heard make it blink for the
|
|
793
912
|
* person's attention, until the chat is opened; hovered, they show in a
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
import type { JSX, RefObject } from 'react';
|
|
18
18
|
import { type AssistantCharacter } from './characters';
|
|
19
19
|
import type { AssistantCharacterData } from './formats/types';
|
|
20
|
+
import type { DecisionAsker } from './decisions';
|
|
20
21
|
import { type AssistantAway, type AssistantState, type BalloonApproval } from './state';
|
|
21
22
|
/**
|
|
22
23
|
* Where the balloon goes so that it stays inside the window (T-23): toward
|
|
@@ -67,15 +68,17 @@ export interface AssistantStageProps {
|
|
|
67
68
|
/** Open or close the conversation. */
|
|
68
69
|
onToggle: () => void;
|
|
69
70
|
/**
|
|
70
|
-
*
|
|
71
|
-
* newest words, as the Office Assistant said them (T-23), or a welcome
|
|
72
|
-
*
|
|
73
|
-
* approval to answer there, with *Approve* and *Deny*.
|
|
71
|
+
* The peek while the conversation is closed: one short line — the agent's
|
|
72
|
+
* newest words, as the Office Assistant said them (T-23), or a welcome —
|
|
73
|
+
* that opens the conversation when clicked; `more` says it was cut;
|
|
74
|
+
* `approval`, an approval to answer there, with *Approve* and *Deny*.
|
|
74
75
|
*/
|
|
75
76
|
balloon?: {
|
|
76
77
|
text: string;
|
|
77
78
|
more?: boolean;
|
|
78
79
|
approval?: BalloonApproval;
|
|
80
|
+
/** Puts the peek away (a × beside its line); never an approval's. */
|
|
81
|
+
onDismiss?: () => void;
|
|
79
82
|
};
|
|
80
83
|
/** Show the balloon without being hovered: something new to say. */
|
|
81
84
|
insist?: boolean;
|
|
@@ -86,6 +89,11 @@ export interface AssistantStageProps {
|
|
|
86
89
|
* steps aside for, nor is the pointer working there (T-27).
|
|
87
90
|
*/
|
|
88
91
|
ownRef?: RefObject<HTMLElement | null>;
|
|
92
|
+
/**
|
|
93
|
+
* Asks a typed decision of the runtime: the balloon offers *Ask a
|
|
94
|
+
* decision*, and stays while its form or its answer is on screen.
|
|
95
|
+
*/
|
|
96
|
+
decide?: DecisionAsker;
|
|
89
97
|
}
|
|
90
|
-
export declare function AssistantStage({ character, state, size, place, stageRef, onDragStart, open, onToggle, balloon, insist, onDismiss, ownRef, }: AssistantStageProps): JSX.Element;
|
|
98
|
+
export declare function AssistantStage({ character, state, size, place, stageRef, onDragStart, open, onToggle, balloon, insist, onDismiss, ownRef, decide, }: AssistantStageProps): JSX.Element;
|
|
91
99
|
export default AssistantStage;
|
|
@@ -180,7 +180,7 @@ export function useKeepClear(stageRef, own, paused) {
|
|
|
180
180
|
}, [stageRef, own, paused]);
|
|
181
181
|
return obstructed ? 'obstacle' : pointerBusy ? 'pointer' : undefined;
|
|
182
182
|
}
|
|
183
|
-
export function AssistantStage({ character, state, size = 88, place, stageRef, onDragStart, open, onToggle, balloon, insist = false, onDismiss, ownRef, }) {
|
|
183
|
+
export function AssistantStage({ character, state, size = 88, place, stageRef, onDragStart, open, onToggle, balloon, insist = false, onDismiss, ownRef, decide, }) {
|
|
184
184
|
// A shipped one by id, a drawing contributed by a plugin (T-24), or a
|
|
185
185
|
// character read from a file (T-26).
|
|
186
186
|
const shipped = typeof character === 'string'
|
|
@@ -199,7 +199,9 @@ export function AssistantStage({ character, state, size = 88, place, stageRef, o
|
|
|
199
199
|
// Where the press began: a press that moves is a drag, not a click.
|
|
200
200
|
const pressedAt = useRef(null);
|
|
201
201
|
const aside = useKeepClear(stageRef, ownRef, menuOpen);
|
|
202
|
-
|
|
202
|
+
// A decision being asked, or its answer, keeps the balloon up.
|
|
203
|
+
const [deciding, setDeciding] = useState(false);
|
|
204
|
+
const showBalloon = !aside && !open && !!balloon && (hovered || insist || deciding);
|
|
203
205
|
return (_jsxs(Box, { ref: stageRef, "data-assistant-state": state, "data-assistant-aside": aside, sx: {
|
|
204
206
|
position: 'fixed',
|
|
205
207
|
zIndex: 1002,
|
|
@@ -277,7 +279,7 @@ export function AssistantStage({ character, state, size = 88, place, stageRef, o
|
|
|
277
279
|
'@media (prefers-reduced-motion: reduce)': {
|
|
278
280
|
'& *': { animation: 'none !important' },
|
|
279
281
|
},
|
|
280
|
-
}, onMouseEnter: () => setHovered(true), onMouseLeave: () => setHovered(false), children: [showBalloon && balloon && (_jsx(SpeechBalloon, { text: balloon.text, more: balloon.more, approval: balloon.approval, onOpen: onToggle, above: size + 8, side: balloonSide(place).side, align: balloonSide(place).align, tailAt: size / 2 })), _jsx(Box, { as: "button", type: "button", "aria-label": open ? `Close the conversation with ${name}` : `Talk to ${name}`, "aria-expanded": open, onPointerDown: (event) => {
|
|
282
|
+
}, onMouseEnter: () => setHovered(true), onMouseLeave: () => setHovered(false), children: [showBalloon && balloon && (_jsx(SpeechBalloon, { text: balloon.text, more: balloon.more, approval: balloon.approval, onDismissPeek: balloon.onDismiss, decide: decide, onDecisionActive: setDeciding, wide: deciding, onOpen: onToggle, above: size + 8, side: balloonSide(place).side, align: balloonSide(place).align, tailAt: size / 2 })), _jsx(Box, { as: "button", type: "button", "aria-label": open ? `Close the conversation with ${name}` : `Talk to ${name}`, "aria-expanded": open, onPointerDown: (event) => {
|
|
281
283
|
pressedAt.current = { x: event.clientX, y: event.clientY };
|
|
282
284
|
onDragStart(event);
|
|
283
285
|
}, onClick: (event) => {
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The floating assistant's conversation, open: a balloon over the character
|
|
3
|
+
* that holds the conversation itself — the history as the chat draws it, the
|
|
4
|
+
* welcome first, an approval as a message with *Approve* and *Deny* (T-23),
|
|
5
|
+
* the composer last — with no header and no footer, a tail toward the
|
|
6
|
+
* character, a close control, and a height that leaves the page in sight
|
|
7
|
+
* while the history scrolls inside it.
|
|
8
|
+
*
|
|
9
|
+
* Closed, the character peeks instead (`SpeechBalloon`): one short line, and
|
|
10
|
+
* what it needs to be answered.
|
|
11
|
+
*
|
|
12
|
+
* @module chat/assistant/ConversationBalloon
|
|
13
|
+
*/
|
|
14
|
+
import type { JSX } from 'react';
|
|
15
|
+
import { type BalloonApproval } from './state';
|
|
16
|
+
/** The open balloon's width, in pixels. */
|
|
17
|
+
export declare const CONVERSATION_BALLOON_WIDTH = 380;
|
|
18
|
+
/** The open balloon's tallest, in pixels, and its share of the window. */
|
|
19
|
+
export declare const CONVERSATION_BALLOON_MAX_HEIGHT = 560;
|
|
20
|
+
export declare const CONVERSATION_BALLOON_VIEWPORT_SHARE = 0.6;
|
|
21
|
+
/** The open balloon's height for a window this tall: 60% of it, 560px at most. */
|
|
22
|
+
export declare function conversationBalloonHeight(viewportHeight: number): number;
|
|
23
|
+
/**
|
|
24
|
+
* Where the open balloon's tail points: from its bottom edge (the balloon
|
|
25
|
+
* above the character) or its top edge (below it), `at` pixels from its
|
|
26
|
+
* left; none when the balloon stands beside the character.
|
|
27
|
+
*/
|
|
28
|
+
export type BalloonTail = {
|
|
29
|
+
edge: 'bottom' | 'top';
|
|
30
|
+
at: number;
|
|
31
|
+
} | {
|
|
32
|
+
edge: 'none';
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* The tail toward a character whose middle is `characterMiddle` pixels from
|
|
36
|
+
* the window's left, under or over a balloon whose left is `balloonLeft`:
|
|
37
|
+
* kept off the balloon's rounded corners.
|
|
38
|
+
*/
|
|
39
|
+
export declare function balloonTailAt(characterMiddle: number, balloonLeft: number, width?: number): number;
|
|
40
|
+
/**
|
|
41
|
+
* The open balloon's shape: the bubble's radius, and its tail — drawn in the
|
|
42
|
+
* colour of what it leaves (`tailBg`): the composer's band under the
|
|
43
|
+
* history, the history over it.
|
|
44
|
+
*/
|
|
45
|
+
export declare function conversationBalloonSx(tail: BalloonTail, tailBg?: string): Record<string, unknown>;
|
|
46
|
+
/** The open balloon's close control, over its top right corner. */
|
|
47
|
+
export declare function ConversationBalloonClose({ name, onClose, }: {
|
|
48
|
+
/** Who is talking: "Close the conversation with Paper clip". */
|
|
49
|
+
name?: string;
|
|
50
|
+
onClose: () => void;
|
|
51
|
+
}): JSX.Element;
|
|
52
|
+
/**
|
|
53
|
+
* An approval the agent waits on, as a message of the history: what it asks
|
|
54
|
+
* to do, the rule it was asked under, *Approve* and *Deny*, and how many more
|
|
55
|
+
* wait (T-23). Brought into view when it arrives.
|
|
56
|
+
*/
|
|
57
|
+
export declare function BalloonApprovalMessage({ approval, }: {
|
|
58
|
+
approval: BalloonApproval;
|
|
59
|
+
}): JSX.Element;
|
|
60
|
+
/** How many more wait, in two words: "2 more". */
|
|
61
|
+
export declare function moreWaiting(others: number): string;
|
|
62
|
+
/** How much of a message a peek says: its first words. */
|
|
63
|
+
export declare const PEEK_LIMIT = 60;
|
|
64
|
+
/**
|
|
65
|
+
* A message's first words, for a peek: cut at a word, with an ellipsis, and
|
|
66
|
+
* whether there was more.
|
|
67
|
+
*/
|
|
68
|
+
export declare function peekLine(text: string, limit?: number): {
|
|
69
|
+
text: string;
|
|
70
|
+
more: boolean;
|
|
71
|
+
};
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useRef } from 'react';
|
|
3
|
+
import { Button, IconButton, Text } from '@primer/react';
|
|
4
|
+
import { Box } from '@datalayer/primer-addons';
|
|
5
|
+
import { XIcon } from '@primer/octicons-react';
|
|
6
|
+
import { ASSISTANT_WORDS } from './state';
|
|
7
|
+
/** The open balloon's width, in pixels. */
|
|
8
|
+
export const CONVERSATION_BALLOON_WIDTH = 380;
|
|
9
|
+
/** The open balloon's tallest, in pixels, and its share of the window. */
|
|
10
|
+
export const CONVERSATION_BALLOON_MAX_HEIGHT = 560;
|
|
11
|
+
export const CONVERSATION_BALLOON_VIEWPORT_SHARE = 0.6;
|
|
12
|
+
/** The open balloon's height for a window this tall: 60% of it, 560px at most. */
|
|
13
|
+
export function conversationBalloonHeight(viewportHeight) {
|
|
14
|
+
return Math.max(240, Math.min(CONVERSATION_BALLOON_MAX_HEIGHT, Math.round(viewportHeight * CONVERSATION_BALLOON_VIEWPORT_SHARE)));
|
|
15
|
+
}
|
|
16
|
+
/** The tail's half width, in pixels. */
|
|
17
|
+
const TAIL = 7;
|
|
18
|
+
/**
|
|
19
|
+
* The tail toward a character whose middle is `characterMiddle` pixels from
|
|
20
|
+
* the window's left, under or over a balloon whose left is `balloonLeft`:
|
|
21
|
+
* kept off the balloon's rounded corners.
|
|
22
|
+
*/
|
|
23
|
+
export function balloonTailAt(characterMiddle, balloonLeft, width = CONVERSATION_BALLOON_WIDTH) {
|
|
24
|
+
return Math.min(width - 24 - TAIL, Math.max(24, characterMiddle - balloonLeft - TAIL));
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* The open balloon's shape: the bubble's radius, and its tail — drawn in the
|
|
28
|
+
* colour of what it leaves (`tailBg`): the composer's band under the
|
|
29
|
+
* history, the history over it.
|
|
30
|
+
*/
|
|
31
|
+
export function conversationBalloonSx(tail, tailBg = 'canvas.default') {
|
|
32
|
+
return {
|
|
33
|
+
borderRadius: 'var(--theme-radius-bubble, 16px)',
|
|
34
|
+
overflow: 'visible',
|
|
35
|
+
...(tail.edge === 'none'
|
|
36
|
+
? {}
|
|
37
|
+
: {
|
|
38
|
+
'&::after': {
|
|
39
|
+
content: '""',
|
|
40
|
+
position: 'absolute',
|
|
41
|
+
...(tail.edge === 'bottom'
|
|
42
|
+
? { bottom: `-${TAIL}px` }
|
|
43
|
+
: { top: `-${TAIL}px` }),
|
|
44
|
+
left: `${tail.at}px`,
|
|
45
|
+
width: `${TAIL * 2}px`,
|
|
46
|
+
height: `${TAIL * 2}px`,
|
|
47
|
+
bg: tailBg,
|
|
48
|
+
borderRight: '1px solid',
|
|
49
|
+
borderBottom: '1px solid',
|
|
50
|
+
borderColor: 'border.default',
|
|
51
|
+
transform: tail.edge === 'bottom' ? 'rotate(45deg)' : 'rotate(225deg)',
|
|
52
|
+
pointerEvents: 'none',
|
|
53
|
+
},
|
|
54
|
+
}),
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
/** The open balloon's close control, over its top right corner. */
|
|
58
|
+
export function ConversationBalloonClose({ name, onClose, }) {
|
|
59
|
+
return (_jsx(Box, { "data-conversation-balloon-close": "", sx: { position: 'absolute', top: '6px', right: '6px', zIndex: 30 }, children: _jsx(IconButton, { icon: XIcon, size: "small", variant: "invisible", "aria-label": name
|
|
60
|
+
? `Close the conversation with ${name}`
|
|
61
|
+
: 'Close the conversation', onClick: onClose, sx: { bg: 'canvas.default', borderRadius: '50%' } }) }));
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* An approval the agent waits on, as a message of the history: what it asks
|
|
65
|
+
* to do, the rule it was asked under, *Approve* and *Deny*, and how many more
|
|
66
|
+
* wait (T-23). Brought into view when it arrives.
|
|
67
|
+
*/
|
|
68
|
+
export function BalloonApprovalMessage({ approval, }) {
|
|
69
|
+
const ref = useRef(null);
|
|
70
|
+
useEffect(() => {
|
|
71
|
+
ref.current?.scrollIntoView?.({ block: 'nearest' });
|
|
72
|
+
}, [approval.id]);
|
|
73
|
+
return (_jsx(Box, { ref: ref, "data-balloon-approval": approval.id, sx: { px: 3, py: 2, display: 'flex' }, children: _jsxs(Box, { sx: {
|
|
74
|
+
maxWidth: '90%',
|
|
75
|
+
px: 3,
|
|
76
|
+
py: 2,
|
|
77
|
+
bg: 'attention.subtle',
|
|
78
|
+
border: '1px solid',
|
|
79
|
+
borderColor: 'attention.muted',
|
|
80
|
+
borderRadius: 'var(--theme-radius-bubble, 16px)',
|
|
81
|
+
fontSize: 1,
|
|
82
|
+
}, children: [_jsx(Text, { as: "p", sx: { m: 0, color: 'fg.muted', fontSize: 0 }, children: ASSISTANT_WORDS.approval }), _jsx(Text, { as: "p", sx: { m: 0, fontWeight: 'semibold' }, children: approval.asks }), approval.why ? (_jsx(Text, { as: "p", sx: { m: 0, color: 'fg.muted', fontSize: 0 }, children: approval.why })) : null, _jsxs(Box, { sx: { display: 'flex', gap: 2, mt: 2, alignItems: 'center' }, children: [_jsx(Button, { size: "small", variant: "primary", disabled: approval.deciding, onClick: approval.onApprove, children: ASSISTANT_WORDS.approve }), _jsx(Button, { size: "small", disabled: approval.deciding, onClick: approval.onDeny, children: ASSISTANT_WORDS.deny }), approval.others > 0 ? (_jsx(Text, { sx: { color: 'fg.muted', fontSize: 0 }, children: moreWaiting(approval.others) })) : null] })] }) }));
|
|
83
|
+
}
|
|
84
|
+
/** How many more wait, in two words: "2 more". */
|
|
85
|
+
export function moreWaiting(others) {
|
|
86
|
+
return `${others} more`;
|
|
87
|
+
}
|
|
88
|
+
/** How much of a message a peek says: its first words. */
|
|
89
|
+
export const PEEK_LIMIT = 60;
|
|
90
|
+
/**
|
|
91
|
+
* A message's first words, for a peek: cut at a word, with an ellipsis, and
|
|
92
|
+
* whether there was more.
|
|
93
|
+
*/
|
|
94
|
+
export function peekLine(text, limit = PEEK_LIMIT) {
|
|
95
|
+
const plain = text.replace(/\s+/g, ' ').trim();
|
|
96
|
+
if (plain.length <= limit) {
|
|
97
|
+
return { text: plain, more: false };
|
|
98
|
+
}
|
|
99
|
+
const cut = plain.slice(0, limit);
|
|
100
|
+
const atWord = cut.slice(0, Math.max(cut.lastIndexOf(' '), limit * 0.6));
|
|
101
|
+
return { text: `${atWord.trimEnd()}…`, more: true };
|
|
102
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* *Ask a decision* in the floating assistant's balloon: a small form — the
|
|
3
|
+
* situation, the question, its type (yes or no; a choice with its options
|
|
4
|
+
* listed; a score with its range) — asked of Jev through the runtime, and
|
|
5
|
+
* the answer said back in the balloon in plain words with its confidence.
|
|
6
|
+
*
|
|
7
|
+
* @module chat/assistant/DecisionAsk
|
|
8
|
+
*/
|
|
9
|
+
import type { JSX } from 'react';
|
|
10
|
+
import { type DecisionAsker } from './decisions';
|
|
11
|
+
/** The balloon's words for a decision. */
|
|
12
|
+
export declare const DECISION_WORDS: {
|
|
13
|
+
readonly ask: "Ask a decision";
|
|
14
|
+
readonly asking: "Asking…";
|
|
15
|
+
readonly submit: "Ask";
|
|
16
|
+
readonly cancel: "Cancel";
|
|
17
|
+
readonly again: "Ask another";
|
|
18
|
+
readonly types: {
|
|
19
|
+
noul: string;
|
|
20
|
+
choice: string;
|
|
21
|
+
score: string;
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
export interface DecisionAskProps {
|
|
25
|
+
/** Asks the runtime. */
|
|
26
|
+
ask: DecisionAsker;
|
|
27
|
+
/** The form or its answer is on screen: the balloon must stay. */
|
|
28
|
+
onActiveChange?: (active: boolean) => void;
|
|
29
|
+
}
|
|
30
|
+
export declare function DecisionAsk({ ask, onActiveChange, }: DecisionAskProps): JSX.Element;
|
|
31
|
+
export default DecisionAsk;
|