@datalayer/agent-runtimes 1.3.74 → 1.3.78
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/agents/AgentDetails.d.ts +16 -2
- package/lib/agents/AgentDetails.js +381 -272
- package/lib/chat/ChatFloating.d.ts +27 -1
- package/lib/chat/ChatFloating.js +97 -13
- package/lib/chat/assistant/AgentDetailsDialog.d.ts +21 -0
- package/lib/chat/assistant/AgentDetailsDialog.js +19 -0
- package/lib/chat/assistant/AssistantContextMenu.d.ts +67 -0
- package/lib/chat/assistant/AssistantContextMenu.js +68 -0
- package/lib/chat/assistant/AssistantStage.d.ts +144 -4
- package/lib/chat/assistant/AssistantStage.js +280 -10
- package/lib/chat/assistant/BalloonParts.d.ts +33 -5
- package/lib/chat/assistant/BalloonParts.js +66 -44
- package/lib/chat/assistant/BalloonVisual.d.ts +10 -2
- package/lib/chat/assistant/BalloonVisual.js +4 -3
- package/lib/chat/assistant/SandboxDetailsDialog.d.ts +44 -0
- package/lib/chat/assistant/SandboxDetailsDialog.js +214 -0
- package/lib/chat/assistant/SpeechBalloon.d.ts +54 -6
- package/lib/chat/assistant/SpeechBalloon.js +73 -22
- package/lib/chat/assistant/assistantDetails.d.ts +84 -0
- package/lib/chat/assistant/assistantDetails.js +140 -0
- package/lib/chat/assistant/formats/files.d.ts +23 -0
- package/lib/chat/assistant/formats/files.js +48 -0
- package/lib/chat/assistant/formats/index.d.ts +2 -0
- package/lib/chat/assistant/formats/index.js +1 -0
- package/lib/chat/assistant/state.d.ts +7 -14
- package/lib/chat/assistant/state.js +21 -20
- package/lib/chat/assistant/toolLine.d.ts +16 -0
- package/lib/chat/assistant/toolLine.js +46 -0
- package/lib/chat/base/ChatBase.js +71 -1
- package/lib/chat/base/loopMessage.d.ts +37 -0
- package/lib/chat/base/loopMessage.js +37 -0
- package/lib/chat/indicators/TypingDots.d.ts +13 -0
- package/lib/chat/indicators/TypingDots.js +21 -0
- package/lib/chat/messages/ChatMarkdown.d.ts +16 -0
- package/lib/chat/messages/ChatMarkdown.js +18 -0
- package/lib/chat/messages/ChatMessageList.d.ts +8 -1
- package/lib/chat/messages/ChatMessageList.js +25 -33
- package/lib/chat/styles/streamdownStyles.js +3 -1
- package/lib/chat/tools/ToolCallDisplay.d.ts +8 -1
- package/lib/chat/tools/ToolCallDisplay.js +8 -7
- package/lib/components/code-sandboxes/CodeSandboxCellVariablesDialog.js +5 -11
- package/lib/components/code-sandboxes/CodeSandboxVariables.d.ts +8 -0
- package/lib/components/code-sandboxes/CodeSandboxVariables.js +17 -11
- package/lib/components/inspector/AgentInspector.d.ts +59 -0
- package/lib/components/inspector/AgentInspector.js +220 -0
- package/lib/components/inspector/AgentInspectorDialog.d.ts +19 -0
- package/lib/components/inspector/AgentInspectorDialog.js +9 -0
- package/lib/components/inspector/JsonTree.d.ts +24 -0
- package/lib/components/inspector/JsonTree.js +89 -0
- package/lib/components/inspector/a2aInspect.d.ts +56 -0
- package/lib/components/inspector/a2aInspect.js +478 -0
- package/lib/components/inspector/agentInspector.d.ts +179 -0
- package/lib/components/inspector/agentInspector.js +267 -0
- package/lib/components/inspector/chatInspect.d.ts +38 -0
- package/lib/components/inspector/chatInspect.js +65 -0
- package/lib/components/inspector/classify.d.ts +19 -0
- package/lib/components/inspector/classify.js +42 -0
- package/lib/components/inspector/index.d.ts +14 -0
- package/lib/components/inspector/index.js +18 -0
- package/lib/components/teams/A2ATeamGraph.d.ts +69 -1
- package/lib/components/teams/A2ATeamGraph.js +277 -37
- package/lib/components/teams/NotebookPreviewView.js +9 -1
- package/lib/components/teams/TeamNotebook.d.ts +3 -1
- package/lib/components/teams/TeamNotebook.js +3 -3
- package/lib/components/teams/TeamNotebookView.js +15 -0
- package/lib/components/teams/jupyterThemeVariables.d.ts +9 -0
- package/lib/components/teams/jupyterThemeVariables.js +441 -0
- package/lib/components/teams/teamConnections.d.ts +9 -1
- package/lib/components/teams/teamConnections.js +20 -0
- package/lib/components/teams/teamNotebookKernel.d.ts +3 -0
- package/lib/components/teams/teamNotebookKernel.js +17 -0
- package/lib/components/teams/useA2ATeam.d.ts +20 -3
- package/lib/components/teams/useA2ATeam.js +108 -23
- package/lib/examples/AgentA2ATeamExample.d.ts +13 -0
- package/lib/examples/AgentA2ATeamExample.js +67 -13
- package/lib/examples/AssistantExample.js +65 -26
- package/lib/examples/AssistantGalleryExample.js +2 -1
- package/lib/examples/exampleGroups.d.ts +1 -1
- package/lib/examples/exampleGroups.js +1 -1
- package/lib/examples/utils/assistantGallery.d.ts +7 -6
- package/lib/examples/utils/assistantGallery.js +23 -8
- package/lib/jupyter/exec/Python.d.ts +0 -1
- package/lib/jupyter/exec/Python.js +0 -32
- package/lib/jupyter/exec/Snippets.d.ts +4 -12
- package/lib/jupyter/exec/Snippets.js +0 -8
- package/lib/loop/apps/AppFeedback.js +3 -1
- package/lib/loop/apps/AppKept.d.ts +22 -0
- package/lib/loop/apps/AppKept.js +36 -0
- package/lib/loop/apps/AppRenderer.d.ts +11 -1
- package/lib/loop/apps/AppRenderer.js +22 -4
- package/lib/loop/apps/checks.d.ts +7 -0
- package/lib/loop/apps/checks.js +39 -0
- package/lib/loop/apps/index.d.ts +3 -0
- package/lib/loop/apps/index.js +3 -0
- package/lib/loop/apps/kept.d.ts +30 -0
- package/lib/loop/apps/kept.js +52 -0
- package/lib/loop/apps/records.d.ts +12 -4
- package/lib/loop/apps/records.js +13 -5
- package/lib/loop/apps/saved.d.ts +30 -0
- package/lib/loop/apps/saved.js +40 -0
- package/lib/loop/core/index.d.ts +17 -0
- package/lib/loop/core/index.js +1 -0
- package/lib/loop/embed/AppEmbed.d.ts +8 -1
- package/lib/loop/embed/AppEmbed.js +4 -4
- package/lib/loop/embed/LoopEmbed.d.ts +6 -1
- package/lib/loop/embed/LoopEmbed.js +4 -2
- package/lib/loop/embed/element.js +1 -1
- package/lib/loop/plugins/agents/DatalayerAgentBridge.js +12 -6
- package/lib/loop/plugins/agents/browserService.d.ts +7 -1
- package/lib/loop/plugins/agents/browserService.js +4 -0
- package/lib/loop/plugins/agents/plugin.d.ts +16 -0
- package/lib/loop/plugins/agents/switchable.d.ts +3 -0
- package/lib/loop/plugins/agents/switchable.js +1 -0
- package/lib/loop/plugins/app-activity/index.js +3 -0
- package/lib/loop/plugins/app-computer/index.js +3 -0
- package/lib/loop/plugins/app-rules/AppRulesCard.d.ts +5 -0
- package/lib/loop/plugins/app-rules/AppRulesCard.js +25 -6
- package/lib/loop/plugins/app-rules/index.js +3 -0
- package/lib/loop/plugins/assistant/index.d.ts +7 -2
- package/lib/loop/plugins/assistant/index.js +58 -4
- package/lib/loop/plugins/assistant-characters/index.d.ts +7 -0
- package/lib/loop/plugins/assistant-characters/index.js +17 -0
- package/lib/loop/plugins/chat/ChatView.js +4 -1
- package/lib/loop/plugins/page-layout/SplitLayout.d.ts +2 -1
- package/lib/loop/plugins/page-layout/SplitLayout.js +4 -0
- package/lib/loop/presets.d.ts +4 -0
- package/lib/loop/presets.js +3 -1
- package/lib/loop/shell/LoopWorkspace.d.ts +7 -0
- package/lib/loop/shell/LoopWorkspace.js +5 -4
- package/lib/loop/shell/SidebarRail.d.ts +53 -0
- package/lib/loop/shell/SidebarRail.js +74 -0
- package/lib/loop/shell/index.d.ts +2 -0
- package/lib/loop/shell/index.js +2 -0
- package/lib/loop/shell/paneMotion.d.ts +21 -0
- package/lib/loop/shell/paneMotion.js +37 -0
- package/lib/runtimes/browser/a2aPeer.d.ts +4 -1
- package/lib/specs/apps.js +8 -5
- package/lib/specs/uiPlugins.js +529 -0
- package/lib/types/agentspecs.d.ts +5 -3
- package/lib/types/chat.d.ts +12 -0
- package/package.json +2 -2
- package/scripts/codegen/generate_jupyter_theme_variables.mjs +57 -0
- package/scripts/codegen/generate_ui_plugins.py +112 -2
|
@@ -23,6 +23,10 @@ import { type AssistantCharacter } from './assistant/characters';
|
|
|
23
23
|
import type { AssistantCharacterData } from './assistant/formats/types';
|
|
24
24
|
import { type AssistantSaying } from './assistant/state';
|
|
25
25
|
import { type PresenceState } from './presence/presenceStatus';
|
|
26
|
+
import type { AgentInspectorSink } from '../components/inspector/agentInspector';
|
|
27
|
+
import type { AssistantMenuItem } from './assistant/AssistantContextMenu';
|
|
28
|
+
import type { AssistantAbout } from './assistant/AssistantStage';
|
|
29
|
+
import { type AssistantSandbox } from './assistant/assistantDetails';
|
|
26
30
|
import type { ChatCommonProps, ChatViewMode, ThemeOverrides } from '../types';
|
|
27
31
|
/**
|
|
28
32
|
* A conversation the host draws in the floating window, in place of the
|
|
@@ -172,6 +176,28 @@ export interface ChatFloatingProps extends ChatCommonProps {
|
|
|
172
176
|
* own props (`protocol`, `suggestions`, …) are then not read.
|
|
173
177
|
*/
|
|
174
178
|
conversation?: FloatingConversation;
|
|
179
|
+
/**
|
|
180
|
+
* The Agent Inspector's sink: the chat records its agent's turns and tool
|
|
181
|
+
* calls there, and the assistant's menu offers *Inspect the agent…*.
|
|
182
|
+
*/
|
|
183
|
+
inspector?: AgentInspectorSink | null;
|
|
184
|
+
/** The balloon's display, changed from the assistant's menu. */
|
|
185
|
+
onBalloonDisplayChange?: (display: BalloonDisplay) => void;
|
|
186
|
+
/** Opens the host's character picker, from the assistant's menu. */
|
|
187
|
+
onChangeCharacter?: () => void;
|
|
188
|
+
/**
|
|
189
|
+
* What the assistant's menu's *About* and *Agent Details…* say. The
|
|
190
|
+
* chat's own agent (its id and runtime, from `endpoint`) is described
|
|
191
|
+
* without it.
|
|
192
|
+
*/
|
|
193
|
+
about?: AssistantAbout;
|
|
194
|
+
/**
|
|
195
|
+
* The agent's code sandbox, for *Code Sandbox Details…*. Without it, the
|
|
196
|
+
* sandbox the agent's runtime reports (its codemode status), if any.
|
|
197
|
+
*/
|
|
198
|
+
sandbox?: AssistantSandbox;
|
|
199
|
+
/** The host's own entries of the assistant's menu. */
|
|
200
|
+
contextMenu?: readonly AssistantMenuItem[];
|
|
175
201
|
/**
|
|
176
202
|
* Its voice (VOICE.md V1): push-to-talk in the composer, heard on the
|
|
177
203
|
* device; with `output: 'always'`, its answers said by Datalayer's speech
|
|
@@ -184,5 +210,5 @@ export interface ChatFloatingProps extends ChatCommonProps {
|
|
|
184
210
|
* ChatFloating component
|
|
185
211
|
* A floating chat window built on ChatBase
|
|
186
212
|
*/
|
|
187
|
-
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, balloonDisplay, expandTarget, conversation, decisions, voice, }: ChatFloatingProps): React.JSX.Element;
|
|
213
|
+
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, balloonDisplay: balloonDisplayGiven, expandTarget, conversation, decisions, voice, inspector, onBalloonDisplayChange, onChangeCharacter, about, sandbox, contextMenu, }: ChatFloatingProps): React.JSX.Element;
|
|
188
214
|
export default ChatFloating;
|
package/lib/chat/ChatFloating.js
CHANGED
|
@@ -40,10 +40,12 @@ import { ConversationBalloonHeader, CurrentBalloonBody, } from './assistant/Ball
|
|
|
40
40
|
import { DEFAULT_BALLOON_DISPLAY, conversationCount, newestToolLine, toolLineText, } from './assistant/toolLine';
|
|
41
41
|
import { SpeechBalloon } from './assistant/SpeechBalloon';
|
|
42
42
|
import { DEFAULT_ASSISTANT_CHARACTER, } from './assistant/characters';
|
|
43
|
-
import { assistantStateOf,
|
|
43
|
+
import { assistantStateOf, latestSaying, newestIsAnswer, keepAway, keptAway, ASSISTANT_WORDS, } from './assistant/state';
|
|
44
44
|
import { presenceState, presenceToolOf, } from './presence/presenceStatus';
|
|
45
45
|
import { useChatOpen, useChatMessages, useChatStore, } from '../stores/chatStore';
|
|
46
46
|
import { useChatKeyboardShortcuts, getShortcutDisplay, } from '@datalayer/core/lib/hooks';
|
|
47
|
+
import { assistantSandboxOf, } from './assistant/assistantDetails';
|
|
48
|
+
import { useAgentRuntimeCodemodeStatus } from '../stores/agentRuntimeStore';
|
|
47
49
|
/**
|
|
48
50
|
* Hook to detect mobile viewport
|
|
49
51
|
*/
|
|
@@ -70,7 +72,20 @@ const clamp = (value, max) => Math.max(8, Math.min(value, Math.max(8, max)));
|
|
|
70
72
|
* ChatFloating component
|
|
71
73
|
* A floating chat window built on ChatBase
|
|
72
74
|
*/
|
|
73
|
-
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, balloonDisplay = DEFAULT_BALLOON_DISPLAY, expandTarget, conversation, decisions, voice, }) {
|
|
75
|
+
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, balloonDisplay: balloonDisplayGiven = DEFAULT_BALLOON_DISPLAY, expandTarget, conversation, decisions, voice, inspector, onBalloonDisplayChange, onChangeCharacter, about, sandbox, contextMenu, }) {
|
|
76
|
+
// The chat's own send, once it can: what a suggestion in the balloon sends.
|
|
77
|
+
const chatControls = useRef(null);
|
|
78
|
+
const [suggestionPrompt, setSuggestionPrompt] = useState();
|
|
79
|
+
const [speechMuted, setSpeechMuted] = useState(false);
|
|
80
|
+
// The balloon's display, as the assistant's menu chose it; the host's
|
|
81
|
+
// until then, and again when the host changes it.
|
|
82
|
+
const [chosenDisplay, setChosenDisplay] = useState();
|
|
83
|
+
useEffect(() => setChosenDisplay(undefined), [balloonDisplayGiven]);
|
|
84
|
+
const balloonDisplay = chosenDisplay ?? balloonDisplayGiven;
|
|
85
|
+
const changeBalloonDisplay = useCallback((next) => {
|
|
86
|
+
setChosenDisplay(next);
|
|
87
|
+
onBalloonDisplayChange?.(next);
|
|
88
|
+
}, [onBalloonDisplayChange]);
|
|
74
89
|
// Store-based state
|
|
75
90
|
const storeIsOpen = useChatOpen();
|
|
76
91
|
const storeMessages = useChatMessages();
|
|
@@ -137,6 +152,8 @@ export function ChatFloating({ endpoint, protocol: protocolProp, useStore: useSt
|
|
|
137
152
|
const [ownTool, setOwnTool] = useState();
|
|
138
153
|
const [messageCount, setMessageCount] = useState(0);
|
|
139
154
|
// The conversation's messages, listed in the closed `history` balloon.
|
|
155
|
+
// The chat's own items — its messages and tool calls — as it holds them:
|
|
156
|
+
// the balloon draws them with the chat's components.
|
|
140
157
|
const [ownHistory, setOwnHistory] = useState([]);
|
|
141
158
|
/*
|
|
142
159
|
* Its voice (VOICE.md V1): the answers said by the speech service, as
|
|
@@ -176,7 +193,7 @@ export function ChatFloating({ endpoint, protocol: protocolProp, useStore: useSt
|
|
|
176
193
|
window.removeEventListener('keydown', unlock);
|
|
177
194
|
};
|
|
178
195
|
}, [speaker]);
|
|
179
|
-
useSpokenAnswers(voiceItems, chatBusy, !!speaker, speaker);
|
|
196
|
+
useSpokenAnswers(voiceItems, chatBusy, !!speaker && !speechMuted, speaker);
|
|
180
197
|
const stopSpeaking = useCallback(() => speaker?.stop(), [speaker]);
|
|
181
198
|
const mouthLevel = useMemo(() => (speaker ? () => speaker.level() : undefined), [speaker]);
|
|
182
199
|
const [arriving, setArriving] = useState(false);
|
|
@@ -260,7 +277,16 @@ export function ChatFloating({ endpoint, protocol: protocolProp, useStore: useSt
|
|
|
260
277
|
// The tool line, while its call runs or its turn goes on (T-23).
|
|
261
278
|
const toolSaid = toolLine && (toolLine.phase === 'running' || atWork) ? toolLine : undefined;
|
|
262
279
|
// Current: what is said now — thinking until the answer's words arrive.
|
|
263
|
-
|
|
280
|
+
// The words as written (markdown, drawn by the chat's markdown), or cut
|
|
281
|
+
// to fit with the whole kept for *more*.
|
|
282
|
+
const currentWords = atWork && !answering
|
|
283
|
+
? 'Thinking…'
|
|
284
|
+
: (saying?.more ? saying.text : saying?.markdown) || undefined;
|
|
285
|
+
const currentWhole = atWork && !answering
|
|
286
|
+
? undefined
|
|
287
|
+
: saying?.more
|
|
288
|
+
? saying.markdown
|
|
289
|
+
: undefined;
|
|
264
290
|
// History: the closed balloon lists the conversation, not its newest line.
|
|
265
291
|
const listedHistory = !showsCurrent && !conversation && ownHistory.length > 0
|
|
266
292
|
? ownHistory
|
|
@@ -290,6 +316,7 @@ export function ChatFloating({ endpoint, protocol: protocolProp, useStore: useSt
|
|
|
290
316
|
? // Current: the words as they are written, whole.
|
|
291
317
|
{
|
|
292
318
|
text: currentWords ?? description,
|
|
319
|
+
fullText: currentWhole,
|
|
293
320
|
more: saying?.more,
|
|
294
321
|
speaking: answering && atWork,
|
|
295
322
|
busy: atWork,
|
|
@@ -318,6 +345,28 @@ export function ChatFloating({ endpoint, protocol: protocolProp, useStore: useSt
|
|
|
318
345
|
!!toolSaid ||
|
|
319
346
|
(showsCurrent && atWork) ||
|
|
320
347
|
(unheard && (assistantState === 'speaking' || freshSaying));
|
|
348
|
+
// The chat's suggestions, in the balloon while it waits for a question:
|
|
349
|
+
// one clicked is sent as the prompt, as if typed.
|
|
350
|
+
const balloonSuggestions = useMemo(() => conversation || !suggestions?.length
|
|
351
|
+
? undefined
|
|
352
|
+
: suggestions.map(suggestion => ({
|
|
353
|
+
label: suggestion.title,
|
|
354
|
+
prompt: suggestion.message,
|
|
355
|
+
})), [conversation, suggestions]);
|
|
356
|
+
const sendSuggestion = useCallback((suggestion) => {
|
|
357
|
+
if (chatControls.current) {
|
|
358
|
+
chatControls.current.send(suggestion.prompt);
|
|
359
|
+
}
|
|
360
|
+
else {
|
|
361
|
+
// Not able to send yet: sent once it is.
|
|
362
|
+
setSuggestionPrompt(suggestion.prompt);
|
|
363
|
+
}
|
|
364
|
+
}, []);
|
|
365
|
+
const panelOnSendReady = panelProps?.onSendReady;
|
|
366
|
+
const handleSendReady = useCallback(controls => {
|
|
367
|
+
chatControls.current = controls;
|
|
368
|
+
panelOnSendReady?.(controls);
|
|
369
|
+
}, [panelOnSendReady]);
|
|
321
370
|
const panelOnLoadingChange = panelProps?.onLoadingChange;
|
|
322
371
|
const panelOnDisplayItemsChange = panelProps?.onDisplayItemsChange;
|
|
323
372
|
const handleLoadingChange = useCallback((loading) => {
|
|
@@ -336,12 +385,7 @@ export function ChatFloating({ endpoint, protocol: protocolProp, useStore: useSt
|
|
|
336
385
|
? previous
|
|
337
386
|
: line);
|
|
338
387
|
setMessageCount(conversationCount(items));
|
|
339
|
-
|
|
340
|
-
setOwnHistory(previous => previous.length === listed.length &&
|
|
341
|
-
previous.every((message, index) => message.id === listed[index].id &&
|
|
342
|
-
message.text === listed[index].text)
|
|
343
|
-
? previous
|
|
344
|
-
: listed);
|
|
388
|
+
setOwnHistory(items);
|
|
345
389
|
setVoiceItems(items);
|
|
346
390
|
const said = latestSaying(items);
|
|
347
391
|
setSaying(previous => previous?.id === said?.id && previous?.text === said?.text
|
|
@@ -505,6 +549,34 @@ export function ChatFloating({ endpoint, protocol: protocolProp, useStore: useSt
|
|
|
505
549
|
showSkillsMenu,
|
|
506
550
|
showTokenUsage,
|
|
507
551
|
]);
|
|
552
|
+
// What the assistant's menu says of the agent (*Agent Details…*): the
|
|
553
|
+
// host's words first, the chat's own agent and runtime under them.
|
|
554
|
+
const runtimeBase = endpoint?.match(/^(.*?)\/api\/v1\//)?.[1];
|
|
555
|
+
const agentAbout = useMemo(() => about || protocol?.agentId
|
|
556
|
+
? {
|
|
557
|
+
name: title,
|
|
558
|
+
protocol: protocol?.type,
|
|
559
|
+
url: protocol?.endpoint,
|
|
560
|
+
agentId: protocol?.agentId,
|
|
561
|
+
apiBase: runtimeBase,
|
|
562
|
+
...about,
|
|
563
|
+
}
|
|
564
|
+
: undefined, [about, protocol, title, runtimeBase]);
|
|
565
|
+
// Its sandbox (*Code Sandbox Details…*): the host's, or what its runtime
|
|
566
|
+
// reports.
|
|
567
|
+
const codemodeStatus = useAgentRuntimeCodemodeStatus();
|
|
568
|
+
const agentSandbox = useMemo(() => sandbox ??
|
|
569
|
+
assistantSandboxOf(codemodeStatus
|
|
570
|
+
?.sandbox, { agentId: protocol?.agentId, serverUrl: runtimeBase }) ??
|
|
571
|
+
// An agent on a runtime can always have one: offered before it runs.
|
|
572
|
+
(protocol?.agentId && runtimeBase
|
|
573
|
+
? {
|
|
574
|
+
kind: 'runtime',
|
|
575
|
+
status: 'not running',
|
|
576
|
+
agentId: protocol.agentId,
|
|
577
|
+
serverUrl: runtimeBase,
|
|
578
|
+
}
|
|
579
|
+
: undefined), [sandbox, codemodeStatus, protocol?.agentId, runtimeBase]);
|
|
508
580
|
// Clear messages when endpoint/protocol changes (e.g., switching examples)
|
|
509
581
|
useEffect(() => {
|
|
510
582
|
clearStoreMessages();
|
|
@@ -1021,9 +1093,9 @@ export function ChatFloating({ endpoint, protocol: protocolProp, useStore: useSt
|
|
|
1021
1093
|
...poweredByProps,
|
|
1022
1094
|
}, renderToolResult: renderToolResult, description: description, onStateUpdate: onStateUpdate, onNewChat: onNewChat, suggestions: suggestions, submitOnSuggestionClick: submitOnSuggestionClick, hideMessagesAfterToolUI: hideMessagesAfterToolUI, avatarConfig: {
|
|
1023
1095
|
showAvatars: true,
|
|
1024
|
-
}, 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, voice: voice, voiceSpeaking: speakerState.speaking, onStopSpeaking: speaker ? stopSpeaking : undefined, ...panelProps, ...assistantChat, onLoadingChange: handleLoadingChange, onDisplayItemsChange: handleDisplayItemsChange, children: conversationBalloon && currentOpen ? (
|
|
1096
|
+
}, 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 ?? suggestionPrompt, inspector: inspector, showInformation: showInformation, onInformationClick: onInformationClick, onToolCallStart: onToolCallStart, onToolCallComplete: onToolCallComplete, showToolApprovalBanner: showToolApprovalBanner, pendingApprovals: pendingApprovals, onApproveApproval: onApproveApproval, onRejectApproval: onRejectApproval, voice: voice, voiceSpeaking: speakerState.speaking, onStopSpeaking: speaker ? stopSpeaking : undefined, ...panelProps, ...assistantChat, onLoadingChange: handleLoadingChange, onDisplayItemsChange: handleDisplayItemsChange, onSendReady: handleSendReady, children: conversationBalloon && currentOpen ? (
|
|
1025
1097
|
// Current: the one thing said or done now, over the composer.
|
|
1026
|
-
_jsx(Box, { sx: { px: 3, pt: 3, pb: 2, overflow: 'hidden' }, children: _jsx(CurrentBalloonBody, { text: toolSaid ? undefined : (currentWords ?? description), tool: toolSaid, busy: atWork, speaking: answering && atWork }) })) : (children) }))] }));
|
|
1098
|
+
_jsx(Box, { sx: { px: 3, pt: 3, pb: 2, overflow: 'hidden' }, children: _jsx(CurrentBalloonBody, { text: toolSaid ? undefined : (currentWords ?? description), fullText: toolSaid ? undefined : currentWhole, tool: toolSaid, busy: atWork, speaking: answering && atWork, waiting: atWork && !answering }) })) : (children) }))] }));
|
|
1027
1099
|
/*
|
|
1028
1100
|
* The floating popup's button. Words not yet heard make it blink for the
|
|
1029
1101
|
* person's attention, until the chat is opened; hovered, they show in a
|
|
@@ -1071,7 +1143,19 @@ export function ChatFloating({ endpoint, protocol: protocolProp, useStore: useSt
|
|
|
1071
1143
|
left: px(stageDrag.position.left),
|
|
1072
1144
|
top: px(stageDrag.position.top),
|
|
1073
1145
|
}
|
|
1074
|
-
: getPositionStyles(), stageRef: stageRef, onDragStart: stageDrag.onHandlePointerDown, open: isOpen, onToggle: handleToggle, balloon: assistantBalloon, balloonDisplay: balloonDisplay, expandTarget: expandTarget, insist: balloonInsists, onDismiss: dismissAssistant, ownRef: popupRef, mouthLevel: mouthLevel
|
|
1146
|
+
: getPositionStyles(), stageRef: stageRef, onDragStart: stageDrag.onHandlePointerDown, open: isOpen, onToggle: handleToggle, balloon: assistantBalloon, balloonDisplay: balloonDisplay, expandTarget: expandTarget, insist: balloonInsists, onDismiss: dismissAssistant, ownRef: popupRef, mouthLevel: mouthLevel, suggestions: balloonSuggestions, onSuggestion: sendSuggestion, inspector: inspector, onBalloonDisplayChange: changeBalloonDisplay, onStop: chatBusy && chatControls.current
|
|
1147
|
+
? () => chatControls.current?.stop()
|
|
1148
|
+
: undefined, onNewChat: !conversation && showNewChatButton ? handleNewChat : undefined, onClear: !conversation && useStoreMode ? handleClear : undefined, onChangeCharacter: onChangeCharacter, speech: speaker
|
|
1149
|
+
? {
|
|
1150
|
+
muted: speechMuted,
|
|
1151
|
+
onToggle: () => {
|
|
1152
|
+
if (!speechMuted) {
|
|
1153
|
+
speaker.stop();
|
|
1154
|
+
}
|
|
1155
|
+
setSpeechMuted(!speechMuted);
|
|
1156
|
+
},
|
|
1157
|
+
}
|
|
1158
|
+
: undefined, onResetPosition: stageDrag.position ? stageDrag.reset : undefined, about: agentAbout, sandbox: agentSandbox, contextMenu: contextMenu })), showButton && !isOpen && !assistantShown && (_jsx(Box, { sx: {
|
|
1075
1159
|
...getPositionStyles(),
|
|
1076
1160
|
}, children: _jsxs(Box, { sx: {
|
|
1077
1161
|
position: 'relative',
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* *Agent Details…*, from the assistant's menu: the agent's `AgentDetails`
|
|
3
|
+
* in a dialog over the page. On an agent-runtimes server it reads what that
|
|
4
|
+
* server says of the agent (its spec, MCP servers, codemode, context); an
|
|
5
|
+
* agent in the page, or a peer known by its A2A card, is described by what
|
|
6
|
+
* its host knows: its Appspec, model and where it runs.
|
|
7
|
+
*
|
|
8
|
+
* Loaded when it is first opened, never with the character.
|
|
9
|
+
*
|
|
10
|
+
* @module chat/assistant/AgentDetailsDialog
|
|
11
|
+
*/
|
|
12
|
+
import type { JSX } from 'react';
|
|
13
|
+
import type { AssistantAbout } from './AssistantStage';
|
|
14
|
+
export type AgentDetailsDialogProps = {
|
|
15
|
+
about: AssistantAbout;
|
|
16
|
+
/** The character's name, when the agent has none of its own. */
|
|
17
|
+
name: string;
|
|
18
|
+
onClose: () => void;
|
|
19
|
+
};
|
|
20
|
+
export declare function AgentDetailsDialog({ about, name, onClose, }: AgentDetailsDialogProps): JSX.Element;
|
|
21
|
+
export default AgentDetailsDialog;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useMemo } from 'react';
|
|
3
|
+
import { Dialog } from '@primer/react';
|
|
4
|
+
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
|
5
|
+
import { AgentDetails } from '../../agents/AgentDetails';
|
|
6
|
+
export function AgentDetailsDialog({ about, name, onClose, }) {
|
|
7
|
+
// AgentDetails reads the runtime through react-query; a page that shows
|
|
8
|
+
// only a character has no client of its own.
|
|
9
|
+
const queries = useMemo(() => new QueryClient(), []);
|
|
10
|
+
const onRuntime = Boolean(about.agentId && about.apiBase);
|
|
11
|
+
return (_jsx(Dialog, { title: `${about.name ?? name} · Agent Details`, onClose: onClose, width: "xlarge", height: "large", children: _jsx("div", { "data-assistant-agent-details": "", children: _jsx(QueryClientProvider, { client: queries, children: _jsx(AgentDetails, { name: about.name ?? name, protocol: about.protocol ?? (onRuntime ? 'agent-runtimes' : 'browser'), url: about.url ?? '', messageCount: 0, agentId: about.agentId, apiBase: about.apiBase, onBack: onClose, showBackHeader: false, showUsage: onRuntime, padded: false, runtime: onRuntime, summary: {
|
|
12
|
+
spec: about.spec,
|
|
13
|
+
model: about.model,
|
|
14
|
+
where: about.where,
|
|
15
|
+
description: about.description,
|
|
16
|
+
skills: about.skills,
|
|
17
|
+
} }) }) }) }));
|
|
18
|
+
}
|
|
19
|
+
export default AgentDetailsDialog;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The assistant's own menu (LOOP T-27): right-click the character — or
|
|
3
|
+
* Shift+F10 or the ContextMenu key while it has the focus, or a long press on
|
|
4
|
+
* a touch screen — and a menu opens where the pointer is, with what applies
|
|
5
|
+
* to this agent on this page: inspect it, open the conversation, the
|
|
6
|
+
* balloon's display, the suggestions, stop the turn, a new conversation,
|
|
7
|
+
* another character, its voice, send it away, put it back, about it. Esc or
|
|
8
|
+
* a click outside closes it.
|
|
9
|
+
*
|
|
10
|
+
* Its entries are composed from what the host passes ({@link
|
|
11
|
+
* AssistantMenuItem}s): a host or a plugin adds its own (`contextMenu`; in
|
|
12
|
+
* the LOOP workspace, the `loop.assistant.menu` contribution point).
|
|
13
|
+
*
|
|
14
|
+
* @module chat/assistant/AssistantContextMenu
|
|
15
|
+
*/
|
|
16
|
+
import type { JSX, RefObject } from 'react';
|
|
17
|
+
import type { Icon } from '@primer/octicons-react';
|
|
18
|
+
/** One entry of the assistant's menu. */
|
|
19
|
+
export type AssistantMenuItem = {
|
|
20
|
+
/** Stable id: `inspect`, `stop`, a plugin's own. */
|
|
21
|
+
id: string;
|
|
22
|
+
label: string;
|
|
23
|
+
/** Said under the label, smaller. */
|
|
24
|
+
description?: string;
|
|
25
|
+
/** An octicon, before the label. */
|
|
26
|
+
icon?: Icon;
|
|
27
|
+
onSelect: () => void;
|
|
28
|
+
/**
|
|
29
|
+
* Checkable: `true` or `false` makes it one of a choice — the entries of
|
|
30
|
+
* its group are a radio group, one checked.
|
|
31
|
+
*/
|
|
32
|
+
checked?: boolean;
|
|
33
|
+
disabled?: boolean;
|
|
34
|
+
/** The group it is listed in, by its heading; ungrouped entries come first. */
|
|
35
|
+
group?: string;
|
|
36
|
+
/** Drawn as a danger: send away. */
|
|
37
|
+
danger?: boolean;
|
|
38
|
+
};
|
|
39
|
+
/** The entries by group, in the order their first entry came. */
|
|
40
|
+
export declare function menuGroups(items: readonly AssistantMenuItem[]): {
|
|
41
|
+
group: string | undefined;
|
|
42
|
+
items: AssistantMenuItem[];
|
|
43
|
+
}[];
|
|
44
|
+
/** Whether a key opens the menu: Shift+F10, or the ContextMenu key. */
|
|
45
|
+
export declare function opensContextMenu(event: {
|
|
46
|
+
key: string;
|
|
47
|
+
shiftKey: boolean;
|
|
48
|
+
}): boolean;
|
|
49
|
+
/** How long a touch is held before the menu opens, in ms. */
|
|
50
|
+
export declare const LONG_PRESS_MS = 550;
|
|
51
|
+
export type AssistantContextMenuProps = {
|
|
52
|
+
/** Where it opens, in the window's coordinates; closed when `null`. */
|
|
53
|
+
at: {
|
|
54
|
+
x: number;
|
|
55
|
+
y: number;
|
|
56
|
+
} | null;
|
|
57
|
+
items: readonly AssistantMenuItem[];
|
|
58
|
+
/** It closed: Esc, a click outside, or an entry chosen. */
|
|
59
|
+
onClose: () => void;
|
|
60
|
+
/** Where the focus goes back to once it closes. */
|
|
61
|
+
returnFocusRef?: RefObject<HTMLElement | null>;
|
|
62
|
+
/** Its name, for a screen reader: `Paper clip's menu`. */
|
|
63
|
+
label: string;
|
|
64
|
+
};
|
|
65
|
+
/** The menu, anchored at a point of the window. */
|
|
66
|
+
export declare function AssistantContextMenu({ at, items, onClose, returnFocusRef, label, }: AssistantContextMenuProps): JSX.Element | null;
|
|
67
|
+
export default AssistantContextMenu;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useRef } from 'react';
|
|
3
|
+
import { createPortal } from 'react-dom';
|
|
4
|
+
import { ActionList, ActionMenu } from '@primer/react';
|
|
5
|
+
/** The entries by group, in the order their first entry came. */
|
|
6
|
+
export function menuGroups(items) {
|
|
7
|
+
const groups = [];
|
|
8
|
+
for (const item of items) {
|
|
9
|
+
const found = groups.find(group => group.group === item.group);
|
|
10
|
+
if (found) {
|
|
11
|
+
found.items.push(item);
|
|
12
|
+
}
|
|
13
|
+
else {
|
|
14
|
+
groups.push({ group: item.group, items: [item] });
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
// The ungrouped come first.
|
|
18
|
+
return [
|
|
19
|
+
...groups.filter(group => group.group === undefined),
|
|
20
|
+
...groups.filter(group => group.group !== undefined),
|
|
21
|
+
];
|
|
22
|
+
}
|
|
23
|
+
/** Whether a key opens the menu: Shift+F10, or the ContextMenu key. */
|
|
24
|
+
export function opensContextMenu(event) {
|
|
25
|
+
return event.key === 'ContextMenu' || (event.key === 'F10' && event.shiftKey);
|
|
26
|
+
}
|
|
27
|
+
/** How long a touch is held before the menu opens, in ms. */
|
|
28
|
+
export const LONG_PRESS_MS = 550;
|
|
29
|
+
/** The menu, anchored at a point of the window. */
|
|
30
|
+
export function AssistantContextMenu({ at, items, onClose, returnFocusRef, label, }) {
|
|
31
|
+
const anchor = useRef(null);
|
|
32
|
+
const open = at !== null;
|
|
33
|
+
useEffect(() => {
|
|
34
|
+
if (!open) {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
// A scroll moves what it was opened on: it closes.
|
|
38
|
+
const close = () => onClose();
|
|
39
|
+
window.addEventListener('scroll', close, true);
|
|
40
|
+
return () => window.removeEventListener('scroll', close, true);
|
|
41
|
+
}, [open, onClose]);
|
|
42
|
+
if (!at || typeof document === 'undefined') {
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
const groups = menuGroups(items);
|
|
46
|
+
return (_jsxs(_Fragment, { children: [createPortal(_jsx("div", { ref: anchor, "aria-hidden": "true", "data-assistant-menu-anchor": "", style: {
|
|
47
|
+
position: 'fixed',
|
|
48
|
+
left: at.x,
|
|
49
|
+
top: at.y,
|
|
50
|
+
width: 1,
|
|
51
|
+
height: 1,
|
|
52
|
+
pointerEvents: 'none',
|
|
53
|
+
} }), document.body), _jsx(ActionMenu, { open: true, anchorRef: anchor, onOpenChange: next => {
|
|
54
|
+
if (!next) {
|
|
55
|
+
onClose();
|
|
56
|
+
requestAnimationFrame(() => returnFocusRef?.current?.focus());
|
|
57
|
+
}
|
|
58
|
+
}, children: _jsx(ActionMenu.Overlay, { width: "auto", "data-assistant-menu": "", children: _jsx(ActionList, { "aria-label": label, children: groups.map(({ group, items: entries }, index) => {
|
|
59
|
+
const choice = entries.some(item => item.checked !== undefined);
|
|
60
|
+
const list = entries.map(item => (_jsxs(ActionList.Item, { "data-assistant-menu-item": item.id, disabled: item.disabled, variant: item.danger ? 'danger' : 'default', ...(choice ? { selected: !!item.checked } : {}), onSelect: () => {
|
|
61
|
+
item.onSelect();
|
|
62
|
+
onClose();
|
|
63
|
+
requestAnimationFrame(() => returnFocusRef?.current?.focus());
|
|
64
|
+
}, children: [item.icon && (_jsx(ActionList.LeadingVisual, { children: _jsx(item.icon, {}) })), item.label, item.description && (_jsx(ActionList.Description, { variant: "block", children: item.description }))] }, item.id)));
|
|
65
|
+
return (_jsxs(ActionList.Group, { ...(choice ? { selectionVariant: 'single' } : {}), children: [group && (_jsx(ActionList.GroupHeading, { children: group })), list] }, group ?? `ungrouped-${index}`));
|
|
66
|
+
}) }) }) })] }));
|
|
67
|
+
}
|
|
68
|
+
export default AssistantContextMenu;
|
|
@@ -8,6 +8,17 @@
|
|
|
8
8
|
* working: it steps aside — out of sight and out of the pointer's way — until
|
|
9
9
|
* the place is clear again.
|
|
10
10
|
*
|
|
11
|
+
* Right-clicked — or Shift+F10 or the ContextMenu key while it has the
|
|
12
|
+
* focus, or a long press — it opens its own menu where the pointer is
|
|
13
|
+
* (`AssistantContextMenu`): what the host passes applies — *Inspect the
|
|
14
|
+
* agent…* (the Agent Inspector, in a dialog loaded then), the conversation,
|
|
15
|
+
* the balloon's display, the suggestions, *Stop*, a new conversation,
|
|
16
|
+
* another character, its voice, send it away, its place, about it — and
|
|
17
|
+
* what a host or a plugin adds (`contextMenu`).
|
|
18
|
+
*
|
|
19
|
+
* Given suggestions, its balloon offers them while it waits for a question
|
|
20
|
+
* (idle, or greeting): one clicked is sent as the prompt (`onSuggestion`).
|
|
21
|
+
*
|
|
11
22
|
* Its motions are one set for every character, by the parts each drawing
|
|
12
23
|
* names (`assistant-body`, `-pupils`, `-lids`, `-mouth`), and nothing moves
|
|
13
24
|
* for a reader who asks the system for reduced motion.
|
|
@@ -16,11 +27,73 @@
|
|
|
16
27
|
*/
|
|
17
28
|
import type { JSX, ReactNode, RefObject } from 'react';
|
|
18
29
|
import { type AssistantCharacter } from './characters';
|
|
30
|
+
import { type BalloonSuggestion } from './SpeechBalloon';
|
|
31
|
+
import { type AssistantMenuItem } from './AssistantContextMenu';
|
|
32
|
+
import type { AgentInspectorSink } from '../../components/inspector/agentInspector';
|
|
33
|
+
import type { AssistantSandbox } from './assistantDetails';
|
|
19
34
|
import { type BalloonExpandTarget, type BalloonVisual } from './BalloonVisual';
|
|
20
35
|
import type { AssistantCharacterData } from './formats/types';
|
|
21
36
|
import type { DecisionAsker } from './decisions';
|
|
22
|
-
import type
|
|
23
|
-
import
|
|
37
|
+
import { type BalloonDisplay, type BalloonToolLine } from './toolLine';
|
|
38
|
+
import type { DisplayItem } from '../../types/chat';
|
|
39
|
+
import { type AssistantAway, type AssistantState, type BalloonApproval } from './state';
|
|
40
|
+
/** What the assistant's *About* says. */
|
|
41
|
+
export type AssistantAbout = {
|
|
42
|
+
/** The agent's name, or its application's. */
|
|
43
|
+
name?: string;
|
|
44
|
+
/** Its spec or application id, with its version. */
|
|
45
|
+
spec?: string;
|
|
46
|
+
/** Its model. */
|
|
47
|
+
model?: string;
|
|
48
|
+
/** Where it runs: `in your browser`, `on a runtime`. */
|
|
49
|
+
where?: string;
|
|
50
|
+
/** What it does, in a sentence: its card's or its spec's description. */
|
|
51
|
+
description?: string;
|
|
52
|
+
/** What it can do: its card's skills. */
|
|
53
|
+
skills?: string[];
|
|
54
|
+
/**
|
|
55
|
+
* The agent on an agent-runtimes server, and that server: *Agent
|
|
56
|
+
* Details…* then reads its spec, MCP servers and codemode there.
|
|
57
|
+
*/
|
|
58
|
+
agentId?: string;
|
|
59
|
+
apiBase?: string;
|
|
60
|
+
/** How it is reached (`a2a`, `ag-ui`, …) and where. */
|
|
61
|
+
protocol?: string;
|
|
62
|
+
url?: string;
|
|
63
|
+
};
|
|
64
|
+
/**
|
|
65
|
+
* The entries of the assistant's menu, composed from what the host passes:
|
|
66
|
+
* each shows when what it does is there to do.
|
|
67
|
+
*/
|
|
68
|
+
export declare function assistantMenuItems(options: {
|
|
69
|
+
name: string;
|
|
70
|
+
open: boolean;
|
|
71
|
+
onToggle: () => void;
|
|
72
|
+
onDismiss: (away: AssistantAway) => void;
|
|
73
|
+
/** The conversation entry's label; `false` leaves it out. */
|
|
74
|
+
conversationLabel?: string | false;
|
|
75
|
+
inspect?: () => void;
|
|
76
|
+
/** Opens *Agent Details…*: offered where the host describes the agent. */
|
|
77
|
+
agentDetails?: () => void;
|
|
78
|
+
/** Opens *Code Sandbox Details…*: offered where the agent has a sandbox. */
|
|
79
|
+
sandboxDetails?: () => void;
|
|
80
|
+
balloonDisplay?: BalloonDisplay;
|
|
81
|
+
onBalloonDisplayChange?: (display: BalloonDisplay) => void;
|
|
82
|
+
suggestions?: readonly BalloonSuggestion[];
|
|
83
|
+
onSuggestion?: (suggestion: BalloonSuggestion) => void;
|
|
84
|
+
busy?: boolean;
|
|
85
|
+
onStop?: () => void;
|
|
86
|
+
onNewChat?: () => void;
|
|
87
|
+
onClear?: () => void;
|
|
88
|
+
onChangeCharacter?: () => void;
|
|
89
|
+
speech?: {
|
|
90
|
+
muted: boolean;
|
|
91
|
+
onToggle: () => void;
|
|
92
|
+
};
|
|
93
|
+
onResetPosition?: () => void;
|
|
94
|
+
about?: () => void;
|
|
95
|
+
extra?: readonly AssistantMenuItem[];
|
|
96
|
+
}): AssistantMenuItem[];
|
|
24
97
|
/**
|
|
25
98
|
* Where the balloon goes so that it stays inside the window (T-23): toward
|
|
26
99
|
* the middle of the page from whichever half the character stands in, and
|
|
@@ -69,6 +142,17 @@ export interface AssistantStageProps {
|
|
|
69
142
|
open: boolean;
|
|
70
143
|
/** Open or close the conversation. */
|
|
71
144
|
onToggle: () => void;
|
|
145
|
+
/**
|
|
146
|
+
* What a click on the character does, when it is not `onToggle`: a team's
|
|
147
|
+
* member shows and hides its balloon, and its menu's conversation entry
|
|
148
|
+
* (*Ask Sales*) still does `onToggle`.
|
|
149
|
+
*/
|
|
150
|
+
onCharacterClick?: () => void;
|
|
151
|
+
/**
|
|
152
|
+
* A key pressed on the focused character, after its own (the menu's):
|
|
153
|
+
* a team's member moves with the arrow keys.
|
|
154
|
+
*/
|
|
155
|
+
onCharacterKeyDown?: (event: React.KeyboardEvent<HTMLElement>) => void;
|
|
72
156
|
/**
|
|
73
157
|
* The peek while the conversation is closed: one short line — the agent's
|
|
74
158
|
* newest words, as the Office Assistant said them (T-23), or a welcome —
|
|
@@ -77,6 +161,8 @@ export interface AssistantStageProps {
|
|
|
77
161
|
*/
|
|
78
162
|
balloon?: {
|
|
79
163
|
text: string;
|
|
164
|
+
/** The words uncut, when `text` was cut to fit: *more* shows them. */
|
|
165
|
+
fullText?: string;
|
|
80
166
|
more?: boolean;
|
|
81
167
|
approval?: BalloonApproval;
|
|
82
168
|
/** Puts the peek away (a × beside its line); never an approval's. */
|
|
@@ -93,7 +179,7 @@ export interface AssistantStageProps {
|
|
|
93
179
|
* The conversation's messages (`history`): the balloon lists them all,
|
|
94
180
|
* counted and scrolled, rather than the newest line alone.
|
|
95
181
|
*/
|
|
96
|
-
history?: readonly
|
|
182
|
+
history?: readonly DisplayItem[];
|
|
97
183
|
/**
|
|
98
184
|
* The large visual `attachment` is the compact form of (a notebook):
|
|
99
185
|
* the balloon offers *Expand*, and draws it large — into
|
|
@@ -121,6 +207,49 @@ export interface AssistantStageProps {
|
|
|
121
207
|
balloonDisplay?: BalloonDisplay;
|
|
122
208
|
/** Show the balloon without being hovered: something new to say. */
|
|
123
209
|
insist?: boolean;
|
|
210
|
+
/**
|
|
211
|
+
* What the person may ask: chips in the balloon while it waits for a
|
|
212
|
+
* question (idle or greeting), and a group of its menu. One chosen is sent
|
|
213
|
+
* as the prompt with `onSuggestion`.
|
|
214
|
+
*/
|
|
215
|
+
suggestions?: readonly BalloonSuggestion[];
|
|
216
|
+
onSuggestion?: (suggestion: BalloonSuggestion) => void;
|
|
217
|
+
/** The Agent Inspector's sink: its menu offers *Inspect the agent…*. */
|
|
218
|
+
inspector?: AgentInspectorSink | null;
|
|
219
|
+
/** The agent whose own record the inspector shows, of a shared sink (a team's member). */
|
|
220
|
+
inspectAgent?: string;
|
|
221
|
+
/**
|
|
222
|
+
* What its menu calls the conversation's entry, which does `onToggle`;
|
|
223
|
+
* `false` leaves it out, where there is no conversation to open (a team's
|
|
224
|
+
* member that is asked by another). Unsaid: *Open / Close the conversation*.
|
|
225
|
+
*/
|
|
226
|
+
conversationLabel?: string | false;
|
|
227
|
+
/** The balloon's display changes from its menu: *Balloon: History / Current*. */
|
|
228
|
+
onBalloonDisplayChange?: (display: BalloonDisplay) => void;
|
|
229
|
+
/** Stops the turn: offered in its menu while it is at work. */
|
|
230
|
+
onStop?: () => void;
|
|
231
|
+
/** Starts a new conversation, from its menu. */
|
|
232
|
+
onNewChat?: () => void;
|
|
233
|
+
/** Clears the conversation, from its menu. */
|
|
234
|
+
onClear?: () => void;
|
|
235
|
+
/** Opens the host's character picker, from its menu. */
|
|
236
|
+
onChangeCharacter?: () => void;
|
|
237
|
+
/** Its voice, muted or not, from its menu. */
|
|
238
|
+
speech?: {
|
|
239
|
+
muted: boolean;
|
|
240
|
+
onToggle: () => void;
|
|
241
|
+
};
|
|
242
|
+
/** Puts it back where it started, after a drag: offered in its menu. */
|
|
243
|
+
onResetPosition?: () => void;
|
|
244
|
+
/** What its menu's *About* and *Agent Details…* say. */
|
|
245
|
+
about?: AssistantAbout;
|
|
246
|
+
/**
|
|
247
|
+
* The agent's code sandbox, when it has one: its menu offers *Code
|
|
248
|
+
* Sandbox Details…* — where it runs, and its variables.
|
|
249
|
+
*/
|
|
250
|
+
sandbox?: AssistantSandbox;
|
|
251
|
+
/** The host's or a plugin's own entries of its menu. */
|
|
252
|
+
contextMenu?: readonly AssistantMenuItem[];
|
|
124
253
|
/** Send it away (T-27): for the page, for the session, or for good. */
|
|
125
254
|
onDismiss: (away: AssistantAway) => void;
|
|
126
255
|
/**
|
|
@@ -145,6 +274,17 @@ export interface AssistantStageProps {
|
|
|
145
274
|
* and its neighbours, not a page somebody is working on.
|
|
146
275
|
*/
|
|
147
276
|
stayPut?: boolean;
|
|
277
|
+
/**
|
|
278
|
+
* The agent's own name, used in place of the character's by its menu and
|
|
279
|
+
* its *Send … away*: `Sales`, where the character is a paper clip.
|
|
280
|
+
*/
|
|
281
|
+
agentName?: string;
|
|
282
|
+
/**
|
|
283
|
+
* The figure's accessible name, in place of *Talk to <character>*:
|
|
284
|
+
* `Sales (in your browser)`. Given this or `agentName`, the character's
|
|
285
|
+
* name describes the figure instead (`aria-describedby`).
|
|
286
|
+
*/
|
|
287
|
+
label?: string;
|
|
148
288
|
}
|
|
149
289
|
/** The openings of the mouth, by level: shut, a little, half, wide. */
|
|
150
290
|
export declare function mouthOpening(level: number): 0 | 1 | 2 | 3;
|
|
@@ -153,5 +293,5 @@ export declare function mouthOpening(level: number): 0 | 1 | 2 | 3;
|
|
|
153
293
|
* `data-assistant-mouth`, each frame, without drawing the character again.
|
|
154
294
|
*/
|
|
155
295
|
export declare function useMouth(stageRef: RefObject<HTMLElement | null>, mouthLevel: (() => number) | undefined, speaking: boolean): void;
|
|
156
|
-
export declare function AssistantStage({ character, state, size, place, stageRef, onDragStart, open, onToggle, balloon, insist, onDismiss, ownRef, decide, mouthLevel, stayPut, balloonDisplay, expandTarget, expandOnArrival, }: AssistantStageProps): JSX.Element;
|
|
296
|
+
export declare function AssistantStage({ character, state, size, place, stageRef, onDragStart, open, onToggle, onCharacterClick, onCharacterKeyDown, balloon, insist, onDismiss, ownRef, decide, mouthLevel, stayPut, balloonDisplay, expandTarget, expandOnArrival, suggestions, onSuggestion, inspector, inspectAgent, conversationLabel, onBalloonDisplayChange, onStop, onNewChat, onClear, onChangeCharacter, speech, onResetPosition, about, sandbox, contextMenu, agentName, label, }: AssistantStageProps): JSX.Element;
|
|
157
297
|
export default AssistantStage;
|