@datalayer/agent-runtimes 1.3.83 → 1.3.85
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 +5 -4
- package/lib/chat/ChatFloating.js +8 -6
- package/lib/chat/ChatLanguage.d.ts +17 -0
- package/lib/chat/ChatLanguage.js +29 -0
- package/lib/chat/assistant/AssistantStage.d.ts +4 -4
- package/lib/chat/assistant/AssistantStage.js +4 -2
- package/lib/chat/assistant/BalloonParts.d.ts +2 -1
- package/lib/chat/assistant/BalloonParts.js +12 -5
- package/lib/chat/assistant/BalloonVisual.js +3 -1
- package/lib/chat/assistant/ConversationBalloon.d.ts +1 -1
- package/lib/chat/assistant/ConversationBalloon.js +3 -2
- package/lib/chat/assistant/SpeechBalloon.d.ts +1 -1
- package/lib/chat/assistant/SpeechBalloon.js +10 -7
- package/lib/chat/assistant/toolLine.d.ts +8 -4
- package/lib/chat/assistant/toolLine.js +13 -9
- package/lib/chat/base/ChatBase.js +30 -11
- package/lib/chat/base/loopElement.d.ts +53 -0
- package/lib/chat/base/loopElement.js +78 -0
- package/lib/chat/base/loopWindow.d.ts +31 -0
- package/lib/chat/base/loopWindow.js +74 -0
- package/lib/chat/display/EmptyState.js +3 -1
- package/lib/chat/index.d.ts +2 -0
- package/lib/chat/index.js +3 -0
- package/lib/chat/messages/ChatMessages.js +3 -1
- package/lib/chat/messages/TurnFooter.js +3 -1
- package/lib/chat/prompt/InputPrompt.js +3 -1
- package/lib/chat/prompt/InputPromptLexical.js +3 -1
- package/lib/chat/prompt/footer/InPromptFooter.js +3 -1
- package/lib/chat/tools/ToolApprovalBanner.js +5 -3
- package/lib/chat/tools/ToolApprovalDialog.js +5 -3
- package/lib/chat/tools/ToolCallDisplay.js +29 -25
- package/lib/chat/words.d.ts +102 -0
- package/lib/chat/words.js +460 -0
- package/lib/components/a2ui/custom/index.d.ts +39 -0
- package/lib/components/a2ui/custom/index.js +95 -0
- package/lib/components/a2ui/custom/sandbox.d.ts +73 -0
- package/lib/components/a2ui/custom/sandbox.js +188 -0
- package/lib/components/a2ui/datalayer/FileUpload.d.ts +10 -2
- package/lib/components/a2ui/datalayer/FileUpload.js +10 -7
- package/lib/components/a2ui/datalayer/Form.d.ts +2 -0
- package/lib/components/a2ui/datalayer/Form.js +9 -2
- package/lib/components/a2ui/datalayer/formWidgets.d.ts +19 -0
- package/lib/components/a2ui/datalayer/formWidgets.js +51 -0
- package/lib/components/a2ui/datalayer/index.d.ts +1 -1
- package/lib/components/a2ui/datalayer/index.js +1 -1
- package/lib/components/a2ui/datalayer/schema.d.ts +10 -0
- package/lib/components/a2ui/datalayer/schema.js +12 -1
- package/lib/components/a2ui/index.d.ts +1 -0
- package/lib/components/a2ui/index.js +1 -0
- package/lib/components/a2ui/visibleWhen.d.ts +12 -1
- package/lib/components/a2ui/visibleWhen.js +24 -3
- package/lib/components/inspector/AgentInspector.d.ts +25 -44
- package/lib/components/inspector/AgentInspector.js +27 -215
- package/lib/components/inspector/AgentInspectorDialog.d.ts +6 -6
- package/lib/components/inspector/AgentInspectorDialog.js +2 -2
- package/lib/components/inspector/a2aSpans.d.ts +51 -0
- package/lib/components/inspector/a2aSpans.js +373 -0
- package/lib/components/inspector/agentSpans.d.ts +120 -0
- package/lib/components/inspector/agentSpans.js +253 -0
- package/lib/components/inspector/chatSpans.d.ts +36 -0
- package/lib/components/inspector/chatSpans.js +50 -0
- package/lib/components/inspector/classify.d.ts +11 -8
- package/lib/components/inspector/classify.js +23 -24
- package/lib/components/inspector/index.d.ts +7 -7
- package/lib/components/inspector/index.js +7 -7
- package/lib/components/teams/A2ATeamGraph.d.ts +4 -4
- package/lib/components/teams/SceneTranscript.d.ts +29 -0
- package/lib/components/teams/SceneTranscript.js +54 -0
- package/lib/components/teams/SceneView.d.ts +41 -0
- package/lib/components/teams/SceneView.js +28 -0
- package/lib/components/teams/index.d.ts +3 -0
- package/lib/components/teams/index.js +3 -0
- package/lib/components/teams/sceneTranscript.d.ts +74 -0
- package/lib/components/teams/sceneTranscript.js +294 -0
- package/lib/components/teams/teamConnections.d.ts +2 -2
- package/lib/components/teams/teamConnections.js +3 -3
- package/lib/components/teams/useA2ATeam.d.ts +4 -4
- package/lib/components/teams/useA2ATeam.js +50 -46
- package/lib/examples/AgentA2ATeamExample.d.ts +10 -9
- package/lib/examples/AgentA2ATeamExample.js +70 -60
- package/lib/examples/AssistantExample.js +2 -2
- package/lib/loop/apps/AppComposer.d.ts +40 -4
- package/lib/loop/apps/AppComposer.js +194 -19
- package/lib/loop/apps/AppRenderer.d.ts +21 -3
- package/lib/loop/apps/AppRenderer.js +88 -48
- package/lib/loop/apps/appspec.d.ts +13 -1
- package/lib/loop/apps/appspec.js +305 -12
- package/lib/loop/apps/checks.d.ts +14 -0
- package/lib/loop/apps/checks.js +276 -5
- package/lib/loop/apps/composer.d.ts +21 -10
- package/lib/loop/apps/composer.js +41 -8
- package/lib/loop/apps/customComponents.d.ts +41 -0
- package/lib/loop/apps/customComponents.js +260 -0
- package/lib/loop/apps/hostTools.d.ts +8 -1
- package/lib/loop/apps/hostTools.js +9 -0
- package/lib/loop/apps/index.d.ts +1 -0
- package/lib/loop/apps/index.js +1 -0
- package/lib/loop/apps/language.d.ts +68 -0
- package/lib/loop/apps/language.js +275 -0
- package/lib/loop/apps/settingsInputs.d.ts +29 -0
- package/lib/loop/apps/settingsInputs.js +147 -0
- package/lib/loop/apps/uploads.d.ts +43 -0
- package/lib/loop/apps/uploads.js +66 -0
- package/lib/loop/core/a2uiComponents.d.ts +10 -0
- package/lib/loop/core/a2uiComponents.js +15 -0
- package/lib/loop/core/index.d.ts +15 -1
- package/lib/loop/core/index.js +3 -0
- package/lib/loop/embed/AppEmbed.d.ts +25 -3
- package/lib/loop/embed/AppEmbed.js +106 -18
- package/lib/loop/embed/element.d.ts +5 -0
- package/lib/loop/embed/element.js +84 -5
- package/lib/loop/embed/embedConfig.d.ts +8 -0
- package/lib/loop/embed/embedConfig.js +18 -0
- package/lib/loop/embed/embedSession.d.ts +14 -0
- package/lib/loop/embed/embedSession.js +34 -0
- package/lib/loop/embed/hostBridge.d.ts +50 -3
- package/lib/loop/embed/hostBridge.js +22 -2
- package/lib/loop/index.d.ts +4 -3
- package/lib/loop/index.js +4 -3
- package/lib/loop/plugins/a2ui-surface/InlineSurface.d.ts +7 -1
- package/lib/loop/plugins/a2ui-surface/InlineSurface.js +7 -2
- package/lib/loop/plugins/a2ui-surface/SurfaceToolResult.js +4 -1
- package/lib/loop/plugins/a2ui-surface/ownComponents.d.ts +6 -0
- package/lib/loop/plugins/a2ui-surface/ownComponents.js +30 -0
- package/lib/loop/plugins/app-components/index.d.ts +26 -0
- package/lib/loop/plugins/app-components/index.js +56 -0
- package/lib/loop/plugins/app-elements/AppElements.d.ts +27 -0
- package/lib/loop/plugins/app-elements/AppElements.js +79 -0
- package/lib/loop/plugins/app-elements/index.d.ts +20 -0
- package/lib/loop/plugins/app-elements/index.js +43 -0
- package/lib/loop/plugins/app-page/AppPage.d.ts +9 -0
- package/lib/loop/plugins/app-page/AppPage.js +106 -8
- package/lib/loop/plugins/app-page/appPageModel.d.ts +17 -1
- package/lib/loop/plugins/app-page/appPageModel.js +122 -4
- package/lib/loop/plugins/app-page/index.d.ts +1 -0
- package/lib/loop/plugins/app-page/index.js +1 -0
- package/lib/loop/plugins/app-page/pageRun.d.ts +46 -0
- package/lib/loop/plugins/app-page/pageRun.js +111 -0
- package/lib/loop/plugins/assistant/index.js +8 -6
- package/lib/loop/plugins/chat/ChatView.js +16 -6
- package/lib/loop/plugins/chat/index.d.ts +1 -1
- package/lib/loop/plugins/chat/index.js +2 -1
- package/lib/models/PageTag.d.ts +1 -1
- package/lib/protocols/BrowserAgentAdapter.d.ts +8 -6
- package/lib/protocols/BrowserAgentAdapter.js +13 -10
- package/lib/runtimes/browser/a2aPeer.d.ts +2 -1
- package/lib/runtimes/browser/protocol.d.ts +1 -1
- package/lib/specs/actions.js +78 -1
- package/lib/specs/apps.d.ts +5 -0
- package/lib/specs/apps.js +1518 -216
- package/lib/specs/appspecSchema.js +630 -3
- package/lib/specs/teams/teams.d.ts +3 -0
- package/lib/specs/teams/teams.js +249 -0
- package/lib/specs/uiPlugins.js +6 -1
- package/lib/types/agentspecs.d.ts +200 -1
- package/lib/types/chat.d.ts +6 -5
- package/lib/types/teams.d.ts +13 -2
- package/package.json +2 -2
- package/scripts/codegen/generate_apps.py +20 -2
- package/scripts/codegen/generate_teams.py +15 -2
- package/lib/components/inspector/JsonTree.d.ts +0 -24
- package/lib/components/inspector/JsonTree.js +0 -89
- package/lib/components/inspector/a2aInspect.d.ts +0 -56
- package/lib/components/inspector/a2aInspect.js +0 -478
- package/lib/components/inspector/agentInspector.d.ts +0 -179
- package/lib/components/inspector/agentInspector.js +0 -267
- package/lib/components/inspector/chatInspect.d.ts +0 -38
- package/lib/components/inspector/chatInspect.js +0 -65
|
@@ -23,7 +23,7 @@ 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 {
|
|
26
|
+
import type { OtelLiveTracer } from '@datalayer/core/lib/otel/live';
|
|
27
27
|
import type { AssistantMenuItem } from './assistant/AssistantContextMenu';
|
|
28
28
|
import type { AssistantAbout } from './assistant/AssistantStage';
|
|
29
29
|
import { type AssistantSandbox } from './assistant/assistantDetails';
|
|
@@ -177,10 +177,11 @@ export interface ChatFloatingProps extends ChatCommonProps {
|
|
|
177
177
|
*/
|
|
178
178
|
conversation?: FloatingConversation;
|
|
179
179
|
/**
|
|
180
|
-
* The Agent Inspector's
|
|
181
|
-
* calls there, and the assistant's menu offers *Inspect the
|
|
180
|
+
* The Agent Inspector's tracer: the chat records its agent's turns and
|
|
181
|
+
* tool calls there as spans, and the assistant's menu offers *Inspect the
|
|
182
|
+
* agent…*.
|
|
182
183
|
*/
|
|
183
|
-
inspector?:
|
|
184
|
+
inspector?: OtelLiveTracer | null;
|
|
184
185
|
/** The balloon's display, changed from the assistant's menu. */
|
|
185
186
|
onBalloonDisplayChange?: (display: BalloonDisplay) => void;
|
|
186
187
|
/** Opens the host's character picker, from the assistant's menu. */
|
package/lib/chat/ChatFloating.js
CHANGED
|
@@ -40,12 +40,13 @@ 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, latestSaying, newestIsAnswer, keepAway, keptAway,
|
|
43
|
+
import { assistantStateOf, latestSaying, newestIsAnswer, keepAway, keptAway, } 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
47
|
import { assistantSandboxOf, } from './assistant/assistantDetails';
|
|
48
48
|
import { useAgentRuntimeCodemodeStatus } from '../stores/agentRuntimeStore';
|
|
49
|
+
import { useChatWords } from './ChatLanguage';
|
|
49
50
|
/**
|
|
50
51
|
* Hook to detect mobile viewport
|
|
51
52
|
*/
|
|
@@ -73,6 +74,7 @@ const clamp = (value, max) => Math.max(8, Math.min(value, Math.max(8, max)));
|
|
|
73
74
|
* A floating chat window built on ChatBase
|
|
74
75
|
*/
|
|
75
76
|
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, }) {
|
|
77
|
+
const chatText = useChatWords();
|
|
76
78
|
// The chat's own send, once it can: what a suggestion in the balloon sends.
|
|
77
79
|
const chatControls = useRef(null);
|
|
78
80
|
const [suggestionPrompt, setSuggestionPrompt] = useState();
|
|
@@ -280,7 +282,7 @@ export function ChatFloating({ endpoint, protocol: protocolProp, useStore: useSt
|
|
|
280
282
|
// The words as written (markdown, drawn by the chat's markdown), or cut
|
|
281
283
|
// to fit with the whole kept for *more*.
|
|
282
284
|
const currentWords = atWork && !answering
|
|
283
|
-
?
|
|
285
|
+
? chatText.thinking
|
|
284
286
|
: (saying?.more ? saying.text : saying?.markdown) || undefined;
|
|
285
287
|
const currentWhole = atWork && !answering
|
|
286
288
|
? undefined
|
|
@@ -293,7 +295,7 @@ export function ChatFloating({ endpoint, protocol: protocolProp, useStore: useSt
|
|
|
293
295
|
: undefined;
|
|
294
296
|
const withHistory = (said) => listedHistory ? { ...said, history: listedHistory } : said;
|
|
295
297
|
const assistantBalloon = assistantState === 'paused'
|
|
296
|
-
? { text:
|
|
298
|
+
? { text: chatText.paused }
|
|
297
299
|
: speakerState.sentence
|
|
298
300
|
? // Heard: the sentence being said is the one in the balloon (VO-26).
|
|
299
301
|
{ text: speakerState.sentence }
|
|
@@ -301,14 +303,14 @@ export function ChatFloating({ endpoint, protocol: protocolProp, useStore: useSt
|
|
|
301
303
|
? { text: speakerState.refused }
|
|
302
304
|
: balloonApproval
|
|
303
305
|
? withHistory({
|
|
304
|
-
text:
|
|
306
|
+
text: chatText.waitingForYou,
|
|
305
307
|
approval: balloonApproval,
|
|
306
308
|
})
|
|
307
309
|
: assistantState === 'waiting'
|
|
308
|
-
? { text:
|
|
310
|
+
? { text: chatText.waitingOpen }
|
|
309
311
|
: toolSaid
|
|
310
312
|
? withHistory({
|
|
311
|
-
text: toolLineText(toolSaid),
|
|
313
|
+
text: toolLineText(toolSaid, chatText),
|
|
312
314
|
tool: toolSaid,
|
|
313
315
|
busy: atWork,
|
|
314
316
|
})
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The language the chat speaks in (LOOP P-26): the one its host says — the
|
|
3
|
+
* `language` of `AppRenderer` and of the embed — else the browser's.
|
|
4
|
+
*
|
|
5
|
+
* @module chat/ChatLanguage
|
|
6
|
+
*/
|
|
7
|
+
import { type JSX, type ReactNode } from 'react';
|
|
8
|
+
import { type ChatWords } from './words';
|
|
9
|
+
/** The chat in a language its host says; the browser's when it says none. */
|
|
10
|
+
export declare function ChatLanguage({ language, children, }: {
|
|
11
|
+
language?: string;
|
|
12
|
+
children?: ReactNode;
|
|
13
|
+
}): JSX.Element;
|
|
14
|
+
/** The language the chat speaks: the host's, else the browser's, else English. */
|
|
15
|
+
export declare function useChatLanguage(): string;
|
|
16
|
+
/** The chat's own words, in the language it speaks. */
|
|
17
|
+
export declare function useChatWords(): ChatWords;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
/*
|
|
3
|
+
* Copyright (c) 2025-2026 Datalayer, Inc.
|
|
4
|
+
* Distributed under the terms of the Modified BSD License.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* The language the chat speaks in (LOOP P-26): the one its host says — the
|
|
8
|
+
* `language` of `AppRenderer` and of the embed — else the browser's.
|
|
9
|
+
*
|
|
10
|
+
* @module chat/ChatLanguage
|
|
11
|
+
*/
|
|
12
|
+
import { createContext, useContext, useMemo, } from 'react';
|
|
13
|
+
import { preferredLanguages } from '../loop/apps/language';
|
|
14
|
+
import { CHAT_WORDS, chatLanguage } from './words';
|
|
15
|
+
/** The language the host says, as BCP 47 tags it; unsaid, the browser's. */
|
|
16
|
+
const ChatLanguageContext = createContext(undefined);
|
|
17
|
+
/** The chat in a language its host says; the browser's when it says none. */
|
|
18
|
+
export function ChatLanguage({ language, children, }) {
|
|
19
|
+
return (_jsx(ChatLanguageContext.Provider, { value: language || undefined, children: children }));
|
|
20
|
+
}
|
|
21
|
+
/** The language the chat speaks: the host's, else the browser's, else English. */
|
|
22
|
+
export function useChatLanguage() {
|
|
23
|
+
const said = useContext(ChatLanguageContext);
|
|
24
|
+
return useMemo(() => chatLanguage(said ? [said] : preferredLanguages()), [said]);
|
|
25
|
+
}
|
|
26
|
+
/** The chat's own words, in the language it speaks. */
|
|
27
|
+
export function useChatWords() {
|
|
28
|
+
return CHAT_WORDS[useChatLanguage()];
|
|
29
|
+
}
|
|
@@ -30,7 +30,7 @@ import type { JSX, ReactNode, RefObject } from 'react';
|
|
|
30
30
|
import { type AssistantCharacter } from './characters';
|
|
31
31
|
import { type BalloonSuggestion } from './SpeechBalloon';
|
|
32
32
|
import { type AssistantMenuItem } from './AssistantContextMenu';
|
|
33
|
-
import type {
|
|
33
|
+
import type { OtelLiveTracer } from '@datalayer/core/lib/otel/live';
|
|
34
34
|
import type { AssistantSandbox } from './assistantDetails';
|
|
35
35
|
import { type BalloonExpandTarget, type BalloonVisual } from './BalloonVisual';
|
|
36
36
|
import type { AssistantCharacterData } from './formats/types';
|
|
@@ -220,9 +220,9 @@ export interface AssistantStageProps {
|
|
|
220
220
|
*/
|
|
221
221
|
suggestions?: readonly BalloonSuggestion[];
|
|
222
222
|
onSuggestion?: (suggestion: BalloonSuggestion) => void;
|
|
223
|
-
/** The Agent Inspector's
|
|
224
|
-
inspector?:
|
|
225
|
-
/** The agent whose own
|
|
223
|
+
/** The Agent Inspector's tracer: its menu offers *Inspect the agent…*. */
|
|
224
|
+
inspector?: OtelLiveTracer | null;
|
|
225
|
+
/** The agent whose own spans the inspector shows, of a shared tracer (a team's member). */
|
|
226
226
|
inspectAgent?: string;
|
|
227
227
|
/**
|
|
228
228
|
* What its menu calls the conversation's entry, which does `onToggle`;
|
|
@@ -12,6 +12,7 @@ import { BalloonExpandContext, ExpandedVisual, focusExpanded, } from './BalloonV
|
|
|
12
12
|
import { SpriteCharacter } from './SpriteCharacter';
|
|
13
13
|
import { conversationCount, } from './toolLine';
|
|
14
14
|
import { ASSISTANT_OBSTACLES, POINTER_CALM_MS, mouthOpening, boxesMeet, pointerNear, } from './state';
|
|
15
|
+
import { useChatWords } from '../ChatLanguage';
|
|
15
16
|
/** The motions, by the state the stage is in. */
|
|
16
17
|
const MOTIONS = {
|
|
17
18
|
'@keyframes assistantFloat': {
|
|
@@ -362,6 +363,7 @@ export function useMouth(stageRef, mouthLevel, speaking) {
|
|
|
362
363
|
}, [stageRef, mouthLevel, speaking]);
|
|
363
364
|
}
|
|
364
365
|
export function AssistantStage({ character, state, size = 88, place, stageRef, onDragStart, open, onToggle, onCharacterClick, onCharacterKeyDown, balloon, insist = false, onDismiss, ownRef, decide, mouthLevel, stayPut = false, balloonDisplay = 'history', expandTarget, expandOnArrival = false, suggestions, onSuggestion, inspector, inspectAgent, conversationLabel, onBalloonDisplayChange, onStop, onNewChat, onClear, onChangeCharacter, speech, onResetPosition, about, sandbox, contextMenu, agentName, label, }) {
|
|
366
|
+
const chatText = useChatWords();
|
|
365
367
|
// A shipped one by id, a drawing contributed by a plugin (T-24), or a
|
|
366
368
|
// character read from a file (T-26).
|
|
367
369
|
const shipped = typeof character === 'string'
|
|
@@ -456,7 +458,7 @@ export function AssistantStage({ character, state, size = 88, place, stageRef, o
|
|
|
456
458
|
const historyVisual = balloonDisplay !== 'current' && history && history.length > 0
|
|
457
459
|
? {
|
|
458
460
|
id: 'balloon-history',
|
|
459
|
-
title: conversationHeaderText(conversationCount(history)),
|
|
461
|
+
title: conversationHeaderText(conversationCount(history), chatText),
|
|
460
462
|
shrink: true,
|
|
461
463
|
render: () => (_jsx(BalloonHistoryLarge, { history: history, tool: balloon?.tool, attachment: balloon?.attachment })),
|
|
462
464
|
}
|
|
@@ -643,7 +645,7 @@ export function AssistantStage({ character, state, size = 88, place, stageRef, o
|
|
|
643
645
|
bg: 'canvas.default',
|
|
644
646
|
borderRadius: '50%',
|
|
645
647
|
boxShadow: 'shadow.small',
|
|
646
|
-
} }) }), _jsx(ActionMenu.Overlay, { width: "auto", children: _jsx(ActionList, { children: AWAY_CHOICES.map(choice => (_jsx(ActionList.Item, { "data-assistant-away": choice.away, onSelect: () => onDismiss(choice.away), children: choice.label }, choice.away))) }) })] }) })), _jsx(AssistantContextMenu, { at: menuAt, items: menuItems, onClose: closeMenu, returnFocusRef: characterRef, label: `${name}\u2019s menu` }), inspecting && (_jsx(Suspense, { fallback: null, children: _jsx(AgentInspectorDialog, {
|
|
648
|
+
} }) }), _jsx(ActionMenu.Overlay, { width: "auto", children: _jsx(ActionList, { children: AWAY_CHOICES.map(choice => (_jsx(ActionList.Item, { "data-assistant-away": choice.away, onSelect: () => onDismiss(choice.away), children: choice.label }, choice.away))) }) })] }) })), _jsx(AssistantContextMenu, { at: menuAt, items: menuItems, onClose: closeMenu, returnFocusRef: characterRef, label: `${name}\u2019s menu` }), inspecting && (_jsx(Suspense, { fallback: null, children: _jsx(AgentInspectorDialog, { tracer: inspector ?? null, agent: inspectAgent, title: `${about?.name ?? name} \u00b7 Agent Inspector`, onClose: () => {
|
|
647
649
|
setInspecting(false);
|
|
648
650
|
characterRef.current?.focus();
|
|
649
651
|
} }) })), detailing === 'agent' && about && (_jsx(Suspense, { fallback: null, children: _jsx(AgentDetailsDialog, { about: about, name: name, onClose: () => {
|
|
@@ -10,6 +10,7 @@ import type { JSX, ReactNode } from 'react';
|
|
|
10
10
|
import { type ChatDensity } from '../messages/ChatMarkdown';
|
|
11
11
|
import type { DisplayItem } from '../../types/chat';
|
|
12
12
|
import { type BalloonToolLine } from './toolLine';
|
|
13
|
+
import { type ChatWords } from '../words';
|
|
13
14
|
/**
|
|
14
15
|
* The conversation's items in the balloon, drawn by the chat's own
|
|
15
16
|
* components (`ChatMessageList`): markdown, code blocks, tool calls and
|
|
@@ -46,7 +47,7 @@ export declare function BalloonNow({ busy }: {
|
|
|
46
47
|
busy?: boolean;
|
|
47
48
|
}): JSX.Element;
|
|
48
49
|
/** How the `history` balloon names itself: "Conversation · 6". */
|
|
49
|
-
export declare function conversationHeaderText(count: number): string;
|
|
50
|
+
export declare function conversationHeaderText(count: number, chatText?: ChatWords): string;
|
|
50
51
|
/**
|
|
51
52
|
* The `history` balloon's header: what it holds — the conversation, and how
|
|
52
53
|
* many messages — over the scrolled history and the composer.
|
|
@@ -7,6 +7,8 @@ import { ChatMessageList } from '../messages/ChatMessageList';
|
|
|
7
7
|
import { ChatMarkdown } from '../messages/ChatMarkdown';
|
|
8
8
|
import { agentRuntimeStore } from '../../stores/agentRuntimeStore';
|
|
9
9
|
import { toolAnnouncement, displayItemOfLine, } from './toolLine';
|
|
10
|
+
import { useChatWords } from '../ChatLanguage';
|
|
11
|
+
import { ENGLISH_CHAT_WORDS } from '../words';
|
|
10
12
|
/** Out of sight, still heard. */
|
|
11
13
|
const VISUALLY_HIDDEN = {
|
|
12
14
|
position: 'absolute',
|
|
@@ -64,10 +66,11 @@ export function BalloonToolCall({ line, waiting = false, }) {
|
|
|
64
66
|
* starts and once when it ends, never while it runs nor while words stream.
|
|
65
67
|
*/
|
|
66
68
|
export function ToolLineAnnouncer({ line, }) {
|
|
69
|
+
const chatText = useChatWords();
|
|
67
70
|
const last = useRef(undefined);
|
|
68
71
|
const [said, setSaid] = useState('');
|
|
69
72
|
useEffect(() => {
|
|
70
|
-
const words = toolAnnouncement(line, last.current);
|
|
73
|
+
const words = toolAnnouncement(line, last.current, chatText);
|
|
71
74
|
if (line && words) {
|
|
72
75
|
last.current = { id: line.id, phase: line.phase };
|
|
73
76
|
setSaid(words);
|
|
@@ -80,6 +83,7 @@ export function ToolLineAnnouncer({ line, }) {
|
|
|
80
83
|
* agent is at work — still for a reader who asks for reduced motion.
|
|
81
84
|
*/
|
|
82
85
|
export function BalloonNow({ busy = false }) {
|
|
86
|
+
const chatText = useChatWords();
|
|
83
87
|
return (_jsxs(Box, { as: "span", "data-balloon-now": busy ? 'busy' : '', sx: {
|
|
84
88
|
display: 'inline-flex',
|
|
85
89
|
alignItems: 'center',
|
|
@@ -105,17 +109,20 @@ export function BalloonNow({ busy = false }) {
|
|
|
105
109
|
'@media (prefers-reduced-motion: reduce)': {
|
|
106
110
|
'& [data-balloon-now-dot]': { animation: 'none' },
|
|
107
111
|
},
|
|
108
|
-
}, children: [_jsx(Box, { as: "span", "data-balloon-now-dot": "", "aria-hidden": "true" }),
|
|
112
|
+
}, children: [_jsx(Box, { as: "span", "data-balloon-now-dot": "", "aria-hidden": "true" }), chatText.now] }));
|
|
109
113
|
}
|
|
110
114
|
/** How the `history` balloon names itself: "Conversation · 6". */
|
|
111
|
-
export function conversationHeaderText(count) {
|
|
112
|
-
return count > 0
|
|
115
|
+
export function conversationHeaderText(count, chatText = ENGLISH_CHAT_WORDS) {
|
|
116
|
+
return count > 0
|
|
117
|
+
? `${chatText.conversation} · ${count}`
|
|
118
|
+
: chatText.conversation;
|
|
113
119
|
}
|
|
114
120
|
/**
|
|
115
121
|
* The `history` balloon's header: what it holds — the conversation, and how
|
|
116
122
|
* many messages — over the scrolled history and the composer.
|
|
117
123
|
*/
|
|
118
124
|
export function ConversationBalloonHeader({ count, }) {
|
|
125
|
+
const chatText = useChatWords();
|
|
119
126
|
return (_jsx(Box, { "data-balloon-header": "", sx: {
|
|
120
127
|
flexShrink: 0,
|
|
121
128
|
display: 'flex',
|
|
@@ -130,7 +137,7 @@ export function ConversationBalloonHeader({ count, }) {
|
|
|
130
137
|
bg: 'canvas.default',
|
|
131
138
|
borderTopLeftRadius: 'var(--theme-radius-bubble, 16px)',
|
|
132
139
|
borderTopRightRadius: 'var(--theme-radius-bubble, 16px)',
|
|
133
|
-
}, children: _jsx(Text, { sx: { fontSize: 0, fontWeight: 'semibold', color: 'fg.muted' }, children: conversationHeaderText(count) }) }));
|
|
140
|
+
}, children: _jsx(Text, { sx: { fontSize: 0, fontWeight: 'semibold', color: 'fg.muted' }, children: conversationHeaderText(count, chatText) }) }));
|
|
134
141
|
}
|
|
135
142
|
/**
|
|
136
143
|
* What the `current` balloon holds: *Now*, then the one thing being said or
|
|
@@ -4,6 +4,7 @@ import { createPortal } from 'react-dom';
|
|
|
4
4
|
import { Button, Dialog, IconButton } from '@primer/react';
|
|
5
5
|
import { Box } from '@datalayer/primer-addons';
|
|
6
6
|
import { ScreenFullIcon, ScreenNormalIcon, XIcon, } from '@primer/octicons-react';
|
|
7
|
+
import { useChatWords } from '../ChatLanguage';
|
|
7
8
|
/**
|
|
8
9
|
* Expands the visual of the balloon it is in: what its compact form (a
|
|
9
10
|
* notebook's preview) calls when it is clicked. None outside such a balloon.
|
|
@@ -15,7 +16,8 @@ export function useBalloonExpand() {
|
|
|
15
16
|
}
|
|
16
17
|
/** The balloon's *Expand* button. */
|
|
17
18
|
export function BalloonExpandButton({ title, onExpand, }) {
|
|
18
|
-
|
|
19
|
+
const chatText = useChatWords();
|
|
20
|
+
return (_jsx(Button, { size: "small", variant: "invisible", leadingVisual: ScreenFullIcon, "aria-label": chatText.expandWhat(title), "data-balloon-expand": "", onClick: onExpand, sx: { alignSelf: 'flex-start', px: 1 }, children: chatText.expand }));
|
|
19
21
|
}
|
|
20
22
|
/** How large the dialog is when no target is named: most of the window. */
|
|
21
23
|
export const EXPANDED_DIALOG_SIZE = { width: '80vw', height: '80vh' };
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* @module chat/assistant/ConversationBalloon
|
|
13
13
|
*/
|
|
14
14
|
import type { JSX } from 'react';
|
|
15
|
-
import {
|
|
15
|
+
import type { BalloonApproval } from './state';
|
|
16
16
|
/** The open balloon's width, in pixels. */
|
|
17
17
|
export declare const CONVERSATION_BALLOON_WIDTH = 380;
|
|
18
18
|
/** The open balloon's tallest, in pixels, and its share of the window. */
|
|
@@ -3,7 +3,7 @@ import { useEffect, useRef } from 'react';
|
|
|
3
3
|
import { Button, IconButton, Text } from '@primer/react';
|
|
4
4
|
import { Box } from '@datalayer/primer-addons';
|
|
5
5
|
import { XIcon } from '@primer/octicons-react';
|
|
6
|
-
import {
|
|
6
|
+
import { useChatWords } from '../ChatLanguage';
|
|
7
7
|
/** The open balloon's width, in pixels. */
|
|
8
8
|
export const CONVERSATION_BALLOON_WIDTH = 380;
|
|
9
9
|
/** The open balloon's tallest, in pixels, and its share of the window. */
|
|
@@ -71,6 +71,7 @@ export function ConversationBalloonClose({ name, onClose, }) {
|
|
|
71
71
|
* wait (T-23). Brought into view when it arrives.
|
|
72
72
|
*/
|
|
73
73
|
export function BalloonApprovalMessage({ approval, }) {
|
|
74
|
+
const chatText = useChatWords();
|
|
74
75
|
const ref = useRef(null);
|
|
75
76
|
useEffect(() => {
|
|
76
77
|
ref.current?.scrollIntoView?.({ block: 'nearest' });
|
|
@@ -84,7 +85,7 @@ export function BalloonApprovalMessage({ approval, }) {
|
|
|
84
85
|
borderColor: 'attention.muted',
|
|
85
86
|
borderRadius: 'var(--theme-radius-bubble, 16px)',
|
|
86
87
|
fontSize: 1,
|
|
87
|
-
}, children: [_jsx(Text, { as: "p", sx: { m: 0, color: 'fg.muted', fontSize: 0 }, children:
|
|
88
|
+
}, children: [_jsx(Text, { as: "p", sx: { m: 0, color: 'fg.muted', fontSize: 0 }, children: chatText.waitingForYou }), _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: chatText.approve }), _jsx(Button, { size: "small", disabled: approval.deciding, onClick: approval.onDeny, children: chatText.deny }), approval.others > 0 ? (_jsx(Text, { sx: { color: 'fg.muted', fontSize: 0 }, children: chatText.moreWaiting(approval.others) })) : null] })] }) }));
|
|
88
89
|
}
|
|
89
90
|
/** How many more wait, in two words: "2 more". */
|
|
90
91
|
export function moreWaiting(others) {
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
* @module chat/assistant/SpeechBalloon
|
|
27
27
|
*/
|
|
28
28
|
import type { JSX, ReactNode } from 'react';
|
|
29
|
-
import {
|
|
29
|
+
import type { BalloonApproval } from './state';
|
|
30
30
|
import type { DisplayItem } from '../../types/chat';
|
|
31
31
|
import type { DecisionAsker } from './decisions';
|
|
32
32
|
import { type BalloonDisplay, type BalloonToolLine } from './toolLine';
|
|
@@ -3,16 +3,16 @@ import { useEffect, useRef, useState } from 'react';
|
|
|
3
3
|
import { Button, IconButton, Text } from '@primer/react';
|
|
4
4
|
import { Box } from '@datalayer/primer-addons';
|
|
5
5
|
import { XIcon } from '@primer/octicons-react';
|
|
6
|
-
import { ASSISTANT_WORDS } from './state';
|
|
7
|
-
import { moreWaiting } from './ConversationBalloon';
|
|
8
6
|
import { DecisionAsk } from './DecisionAsk';
|
|
9
7
|
import { BalloonChatItems, BalloonToolCall, CurrentBalloonBody, ToolLineAnnouncer, conversationHeaderText, } from './BalloonParts';
|
|
10
8
|
import { conversationCount, withToolCall, } from './toolLine';
|
|
11
9
|
import { BalloonExpandButton } from './BalloonVisual';
|
|
12
10
|
import { ScreenFullIcon } from '@primer/octicons-react';
|
|
11
|
+
import { useChatWords } from '../ChatLanguage';
|
|
13
12
|
/** The suggestions, as chips: each sends its prompt. */
|
|
14
13
|
export function BalloonSuggestions({ suggestions, onSuggestion, }) {
|
|
15
|
-
|
|
14
|
+
const chatText = useChatWords();
|
|
15
|
+
return (_jsx(Box, { role: "group", "aria-label": chatText.suggestions, "data-balloon-suggestions": "", sx: { display: 'flex', flexWrap: 'wrap', gap: 1, mt: 2 }, children: suggestions.map(suggestion => (_jsx(Button, { size: "small", "data-balloon-suggestion": suggestion.label, "aria-label": `Ask: ${suggestion.prompt}`, title: suggestion.prompt, onClick: () => onSuggestion(suggestion), sx: { borderRadius: 999 }, children: suggestion.label }, suggestion.label))) }));
|
|
16
16
|
}
|
|
17
17
|
/** How tall the listed conversation grows before it scrolls, in pixels. */
|
|
18
18
|
export const BALLOON_HISTORY_MAX_HEIGHT = 220;
|
|
@@ -29,9 +29,11 @@ export const BALLOON_HISTORY_WITH_ATTACHMENT_MAX_HEIGHT = 120;
|
|
|
29
29
|
* scrolled there.
|
|
30
30
|
*/
|
|
31
31
|
export function BalloonHistoryLarge({ history, tool, attachment, }) {
|
|
32
|
-
|
|
32
|
+
const chatText = useChatWords();
|
|
33
|
+
return (_jsxs(Box, { role: "log", "aria-label": chatText.conversation, "data-balloon-history-large": "", sx: { display: 'flex', flexDirection: 'column', gap: 2 }, children: [_jsx(BalloonChatItems, { items: withToolCall(history, tool), density: "comfortable" }), attachment ? _jsx(Box, { children: attachment }) : null] }));
|
|
33
34
|
}
|
|
34
35
|
function BalloonHistory({ history, onOpen, maxHeight = BALLOON_HISTORY_MAX_HEIGHT, onExpand, tool, waiting = false, }) {
|
|
36
|
+
const chatText = useChatWords();
|
|
35
37
|
const listRef = useRef(null);
|
|
36
38
|
const newest = history[history.length - 1]?.id;
|
|
37
39
|
useEffect(() => {
|
|
@@ -67,7 +69,7 @@ function BalloonHistory({ history, onOpen, maxHeight = BALLOON_HISTORY_MAX_HEIGH
|
|
|
67
69
|
fontWeight: 'semibold',
|
|
68
70
|
color: 'fg.muted',
|
|
69
71
|
'&:hover': { textDecoration: 'underline' },
|
|
70
|
-
}, children: conversationHeaderText(conversationCount(history)) }), onExpand ? (_jsx(IconButton, { icon: ScreenFullIcon, size: "small", variant: "invisible", "aria-label":
|
|
72
|
+
}, children: conversationHeaderText(conversationCount(history), chatText) }), onExpand ? (_jsx(IconButton, { icon: ScreenFullIcon, size: "small", variant: "invisible", "aria-label": chatText.expandConversation, "data-balloon-history-expand": "", onClick: onExpand, sx: { position: 'absolute', top: '4px', right: '28px' } })) : null, _jsx(Box, { ref: listRef, role: "log", "aria-label": chatText.conversation, "data-balloon-history-list": "", sx: {
|
|
71
73
|
maxHeight,
|
|
72
74
|
overflowY: 'auto',
|
|
73
75
|
display: 'flex',
|
|
@@ -76,6 +78,7 @@ function BalloonHistory({ history, onOpen, maxHeight = BALLOON_HISTORY_MAX_HEIGH
|
|
|
76
78
|
}, children: _jsx(BalloonChatItems, { items: withToolCall(history, tool), waiting: waiting }) })] }));
|
|
77
79
|
}
|
|
78
80
|
export function SpeechBalloon({ text, more = false, onOpen, above, side = 'above', align, tailAt, approval, decide, onDecisionActive, wide = false, onDismissPeek, display = 'history', tool, speaking = false, busy = false, attachment, history, onExpand, expandTitle, suggestions, onSuggestion, waiting = false, fullText, onExpandHistory, }) {
|
|
81
|
+
const chatText = useChatWords();
|
|
79
82
|
// *more*: the words whole, when they were cut or overflow their lines.
|
|
80
83
|
const [whole, setWhole] = useState(false);
|
|
81
84
|
const [overflowing, setOverflowing] = useState(false);
|
|
@@ -175,7 +178,7 @@ export function SpeechBalloon({ text, more = false, onOpen, above, side = 'above
|
|
|
175
178
|
textAlign: 'left',
|
|
176
179
|
cursor: 'pointer',
|
|
177
180
|
'&:hover': { textDecoration: 'underline' },
|
|
178
|
-
}, children: _jsx(Box, { as: "span", role: "status", "aria-live": "polite", children: text }) })), onDismissPeek && !approval ? (_jsx(IconButton, { icon: XIcon, size: "small", variant: "invisible", "aria-label":
|
|
181
|
+
}, children: _jsx(Box, { as: "span", role: "status", "aria-live": "polite", children: text }) })), onDismissPeek && !approval ? (_jsx(IconButton, { icon: XIcon, size: "small", variant: "invisible", "aria-label": chatText.dismiss, "data-balloon-dismiss": "", onClick: onDismissPeek, sx: { mt: '-4px', mr: '-8px', flexShrink: 0 } })) : null] }), current && !approval && !tool && (cut || overflowing || whole) ? (_jsx(Box, { as: "button", type: "button", "aria-expanded": whole, "data-balloon-whole": whole ? 'less' : 'more', onClick: () => setWhole(!whole), sx: {
|
|
179
182
|
m: 0,
|
|
180
183
|
mt: 1,
|
|
181
184
|
p: 0,
|
|
@@ -186,6 +189,6 @@ export function SpeechBalloon({ text, more = false, onOpen, above, side = 'above
|
|
|
186
189
|
fontSize: 0,
|
|
187
190
|
cursor: 'pointer',
|
|
188
191
|
'&:hover': { textDecoration: 'underline' },
|
|
189
|
-
}, children: whole ?
|
|
192
|
+
}, children: whole ? chatText.showLess : chatText.showMore })) : null, !current && !listed && waiting ? (_jsx(Box, { "data-balloon-waiting": "", sx: { mt: 1 }, children: _jsx(BalloonChatItems, { items: [], waiting: true }) })) : null, approval && (_jsxs(Box, { "data-balloon-approval": approval.id, sx: { mt: 1 }, children: [_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 }, children: [_jsx(Button, { size: "small", variant: "primary", disabled: approval.deciding, onClick: approval.onApprove, children: chatText.approve }), _jsx(Button, { size: "small", disabled: approval.deciding, onClick: approval.onDeny, children: chatText.deny })] }), approval.others > 0 ? (_jsx(Text, { as: "p", sx: { m: 0, mt: 1, color: 'fg.muted', fontSize: 0 }, children: chatText.moreWaiting(approval.others) })) : null] })), offered && onSuggestion ? (_jsx(BalloonSuggestions, { suggestions: offered, onSuggestion: onSuggestion })) : null, attachment ? (_jsxs(Box, { "data-balloon-attachment": "", sx: { mt: 2, display: 'flex', flexDirection: 'column', gap: 1 }, children: [attachment, onExpand ? (_jsx(BalloonExpandButton, { title: expandTitle ?? chatText.theVisual, onExpand: onExpand })) : null] })) : null, !current ? _jsx(ToolLineAnnouncer, { line: tool }) : null, decide && _jsx(DecisionAsk, { ask: decide, onActiveChange: onDecisionActive })] }));
|
|
190
193
|
}
|
|
191
194
|
export default SpeechBalloon;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { DisplayItem, ToolCallMessage } from '../../types/chat';
|
|
2
|
+
import { type ChatWords } from '../words';
|
|
2
3
|
/**
|
|
3
4
|
* How the balloon shows the conversation: `history`, every message,
|
|
4
5
|
* scrolled, the composer last; `current`, only what it says or does now, in
|
|
@@ -32,14 +33,17 @@ export interface BalloonToolLine {
|
|
|
32
33
|
* prefix (`odoo__list_invoices` is `list_invoices`).
|
|
33
34
|
*/
|
|
34
35
|
export declare function toolDisplayName(tool: string): string;
|
|
35
|
-
/**
|
|
36
|
-
|
|
36
|
+
/**
|
|
37
|
+
* The three parts a tool line is said in: before the name, the name, after
|
|
38
|
+
* it — in the chat's language (P-26), English unless said.
|
|
39
|
+
*/
|
|
40
|
+
export declare function toolLineParts(line: BalloonToolLine, chatText?: ChatWords): {
|
|
37
41
|
before: string;
|
|
38
42
|
name: string;
|
|
39
43
|
after: string;
|
|
40
44
|
};
|
|
41
45
|
/** A tool line in plain words: "Using list_invoices…". */
|
|
42
|
-
export declare function toolLineText(line: BalloonToolLine): string;
|
|
46
|
+
export declare function toolLineText(line: BalloonToolLine, chatText?: ChatWords): string;
|
|
43
47
|
/**
|
|
44
48
|
* The tool line of the conversation's newest item, when that item is a tool
|
|
45
49
|
* call: running until it is complete or failed. Once words follow it, the
|
|
@@ -62,7 +66,7 @@ export declare function toolLineOfStep(step: ToolStep, name?: string): BalloonTo
|
|
|
62
66
|
export declare function toolAnnouncement(line: BalloonToolLine | undefined, previous: {
|
|
63
67
|
id: string;
|
|
64
68
|
phase: ToolLinePhase;
|
|
65
|
-
} | undefined): string | undefined;
|
|
69
|
+
} | undefined, chatText?: ChatWords): string | undefined;
|
|
66
70
|
/**
|
|
67
71
|
* How many messages the conversation holds, as the `history` balloon's
|
|
68
72
|
* header counts them: the person's and the agent's, not the tool calls.
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
* @module chat/assistant/toolLine
|
|
12
12
|
*/
|
|
13
13
|
import { BACKEND_TOOL_CATALOG } from '../../specs/backendTools';
|
|
14
|
+
import { ENGLISH_CHAT_WORDS } from '../words';
|
|
14
15
|
/** The two displays, in the Appspec's order (`interface.balloon`). */
|
|
15
16
|
export const BALLOON_DISPLAYS = [
|
|
16
17
|
'history',
|
|
@@ -41,23 +42,26 @@ export function toolDisplayName(tool) {
|
|
|
41
42
|
const at = tool.indexOf('__');
|
|
42
43
|
return at > 0 ? tool.slice(at + 2) : tool;
|
|
43
44
|
}
|
|
44
|
-
/**
|
|
45
|
-
|
|
45
|
+
/**
|
|
46
|
+
* The three parts a tool line is said in: before the name, the name, after
|
|
47
|
+
* it — in the chat's language (P-26), English unless said.
|
|
48
|
+
*/
|
|
49
|
+
export function toolLineParts(line, chatText = ENGLISH_CHAT_WORDS) {
|
|
46
50
|
if (line.phase === 'running' && line.words) {
|
|
47
51
|
return { before: '', name: '', after: line.words };
|
|
48
52
|
}
|
|
49
53
|
switch (line.phase) {
|
|
50
54
|
case 'running':
|
|
51
|
-
return {
|
|
55
|
+
return { ...chatText.toolRunning, name: line.name };
|
|
52
56
|
case 'done':
|
|
53
|
-
return {
|
|
57
|
+
return { ...chatText.toolDone, name: line.name };
|
|
54
58
|
case 'failed':
|
|
55
|
-
return {
|
|
59
|
+
return { ...chatText.toolFailedLine, name: line.name };
|
|
56
60
|
}
|
|
57
61
|
}
|
|
58
62
|
/** A tool line in plain words: "Using list_invoices…". */
|
|
59
|
-
export function toolLineText(line) {
|
|
60
|
-
const { before, name, after } = toolLineParts(line);
|
|
63
|
+
export function toolLineText(line, chatText = ENGLISH_CHAT_WORDS) {
|
|
64
|
+
const { before, name, after } = toolLineParts(line, chatText);
|
|
61
65
|
return `${before}${name}${after}`;
|
|
62
66
|
}
|
|
63
67
|
/**
|
|
@@ -96,14 +100,14 @@ export function toolLineOfStep(step, name = toolDisplayName(step.name)) {
|
|
|
96
100
|
* What a screen reader hears of a tool line: once when the call starts and
|
|
97
101
|
* once when it ends — a new id or a new phase — never while it runs.
|
|
98
102
|
*/
|
|
99
|
-
export function toolAnnouncement(line, previous) {
|
|
103
|
+
export function toolAnnouncement(line, previous, chatText = ENGLISH_CHAT_WORDS) {
|
|
100
104
|
if (!line) {
|
|
101
105
|
return undefined;
|
|
102
106
|
}
|
|
103
107
|
if (previous && previous.id === line.id && previous.phase === line.phase) {
|
|
104
108
|
return undefined;
|
|
105
109
|
}
|
|
106
|
-
return toolLineText(line);
|
|
110
|
+
return toolLineText(line, chatText);
|
|
107
111
|
}
|
|
108
112
|
/**
|
|
109
113
|
* How many messages the conversation holds, as the `history` balloon's
|
|
@@ -58,10 +58,13 @@ const EphemeralDocument = React.lazy(() => import('../document/EphemeralDocument
|
|
|
58
58
|
default: m.EphemeralDocument,
|
|
59
59
|
})));
|
|
60
60
|
import { useNotebookTools } from '../../tools/adapters/agent-runtimes/notebookHooks';
|
|
61
|
-
import {
|
|
62
|
-
import {
|
|
61
|
+
import { useAgentInspectorTracer } from '../../components/inspector/agentSpans';
|
|
62
|
+
import { chatSpanRecorder, } from '../../components/inspector/chatSpans';
|
|
63
63
|
import { loopMessageChange, speakerOf, withLoopMessage } from './loopMessage';
|
|
64
64
|
import { loopStepOf, withLoopStep } from './loopStep';
|
|
65
|
+
import { applyLoopElement, loopElementChange } from './loopElement';
|
|
66
|
+
import { loopWindowMessage, tellLoopWindow } from './loopWindow';
|
|
67
|
+
import { useChatWords } from '../ChatLanguage';
|
|
65
68
|
// Tracks pending prompts already auto-sent for a given conversation scope.
|
|
66
69
|
// This prevents layout-driven unmount/remount cycles from re-sending prompts.
|
|
67
70
|
const sentPendingPromptKeys = new Set();
|
|
@@ -526,6 +529,7 @@ runtimeId, thread, historyEndpoint, historyAuthToken: _historyAuthToken,
|
|
|
526
529
|
pendingPrompt, contextSnapshot: externalContextSnapshot, mcpStatusData, sandboxStatusData,
|
|
527
530
|
// Tool approval banner
|
|
528
531
|
showToolApprovalBanner = true, pendingApprovals: pendingApprovalsProp, onApproveApproval: onApproveApprovalProp, onRejectApproval: onRejectApprovalProp, }) {
|
|
532
|
+
const chatText = useChatWords();
|
|
529
533
|
useEffect(() => {
|
|
530
534
|
setupPrimerPortals();
|
|
531
535
|
}, []);
|
|
@@ -1606,22 +1610,22 @@ showToolApprovalBanner = true, pendingApprovals: pendingApprovalsProp, onApprove
|
|
|
1606
1610
|
onToolCallStartRef.current = onToolCallStart;
|
|
1607
1611
|
const onToolCallCompleteRef = useRef(onToolCallComplete);
|
|
1608
1612
|
onToolCallCompleteRef.current = onToolCallComplete;
|
|
1609
|
-
// The Agent Inspector: the turns and tool calls,
|
|
1610
|
-
const inspectorFromContext =
|
|
1611
|
-
const
|
|
1613
|
+
// The Agent Inspector: the turns and tool calls, as spans, as they happen.
|
|
1614
|
+
const inspectorFromContext = useAgentInspectorTracer();
|
|
1615
|
+
const inspectorTracer = inspectorGiven ?? inspectorFromContext;
|
|
1612
1616
|
const inspectorActorRef = useRef('Agent');
|
|
1613
1617
|
inspectorActorRef.current =
|
|
1614
1618
|
(typeof title === 'string' && title) || activeAgentId || 'Agent';
|
|
1615
1619
|
const recorderRef = useRef(null);
|
|
1616
|
-
if (
|
|
1620
|
+
if (inspectorTracer && recorderRef.current?.tracer !== inspectorTracer) {
|
|
1617
1621
|
recorderRef.current = {
|
|
1618
|
-
|
|
1619
|
-
recorder:
|
|
1622
|
+
tracer: inspectorTracer,
|
|
1623
|
+
recorder: chatSpanRecorder(inspectorTracer, () => inspectorActorRef.current, {
|
|
1620
1624
|
frontendTools: () => (frontendToolsRef.current ?? []).map(tool => tool.name),
|
|
1621
1625
|
}),
|
|
1622
1626
|
};
|
|
1623
1627
|
}
|
|
1624
|
-
else if (!
|
|
1628
|
+
else if (!inspectorTracer) {
|
|
1625
1629
|
recorderRef.current = null;
|
|
1626
1630
|
}
|
|
1627
1631
|
const inspectAnswerRef = useRef('');
|
|
@@ -2724,6 +2728,20 @@ showToolApprovalBanner = true, pendingApprovals: pendingApprovalsProp, onApprove
|
|
|
2724
2728
|
setDisplayItems(prev => withLoopStep(prev, step));
|
|
2725
2729
|
break;
|
|
2726
2730
|
}
|
|
2731
|
+
// What its code tells the page it sits in, outside the
|
|
2732
|
+
// conversation (LOOP P-25): handed to whoever listens.
|
|
2733
|
+
const windowMessage = loopWindowMessage(event.activity);
|
|
2734
|
+
if (windowMessage) {
|
|
2735
|
+
tellLoopWindow(windowMessage.data);
|
|
2736
|
+
break;
|
|
2737
|
+
}
|
|
2738
|
+
// An element its code opened in a side panel or on a page of its
|
|
2739
|
+
// own, changed or closed (LOOP P-18): kept for whoever draws them.
|
|
2740
|
+
const element = loopElementChange(event.activity);
|
|
2741
|
+
if (element) {
|
|
2742
|
+
applyLoopElement(element);
|
|
2743
|
+
break;
|
|
2744
|
+
}
|
|
2727
2745
|
// An application's code changed a message it sent: its author
|
|
2728
2746
|
// said, or the message taken away (LOOP P-15).
|
|
2729
2747
|
const change = loopMessageChange(event.activity);
|
|
@@ -3009,7 +3027,7 @@ showToolApprovalBanner = true, pendingApprovals: pendingApprovalsProp, onApprove
|
|
|
3009
3027
|
}
|
|
3010
3028
|
},
|
|
3011
3029
|
onError: (error) => {
|
|
3012
|
-
const errorContent =
|
|
3030
|
+
const errorContent = chatText.error(error.message);
|
|
3013
3031
|
setDisplayItems(prev => prev.map(item => item.id === assistantMessageId
|
|
3014
3032
|
? { ...item, content: errorContent }
|
|
3015
3033
|
: item));
|
|
@@ -3061,7 +3079,7 @@ showToolApprovalBanner = true, pendingApprovals: pendingApprovalsProp, onApprove
|
|
|
3061
3079
|
catch (err) {
|
|
3062
3080
|
if (err.name !== 'AbortError') {
|
|
3063
3081
|
console.error('[ChatBase] Send error:', err);
|
|
3064
|
-
const errorMessage = createAssistantMessage(
|
|
3082
|
+
const errorMessage = createAssistantMessage(chatText.error(err.message));
|
|
3065
3083
|
setDisplayItems(prev => [...prev, errorMessage]);
|
|
3066
3084
|
setError(err);
|
|
3067
3085
|
}
|
|
@@ -3094,6 +3112,7 @@ showToolApprovalBanner = true, pendingApprovals: pendingApprovalsProp, onApprove
|
|
|
3094
3112
|
getEnabledMcpToolNames,
|
|
3095
3113
|
getEnabledSkillIds,
|
|
3096
3114
|
noteThreadStarted,
|
|
3115
|
+
chatText,
|
|
3097
3116
|
]);
|
|
3098
3117
|
// Send pending prompt once history loaded and adapter/handler available
|
|
3099
3118
|
useEffect(() => {
|