@datalayer/agent-runtimes 1.3.89 → 1.3.91
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/Agent.js +2 -18
- package/lib/AgentDocument.js +5 -55
- package/lib/AgentNode.js +31 -208
- package/lib/AgentNotebook.js +5 -59
- package/lib/agent-node/AgentNodeGallery.js +23 -111
- package/lib/agents/AgentDetails.js +36 -274
- package/lib/agents/AgentRuntimeChat.js +1 -8
- package/lib/chat/Chat.js +7 -46
- package/lib/chat/ChatFloating.js +15 -100
- package/lib/chat/ChatInline.js +5 -47
- package/lib/chat/ChatPopupStandalone.js +5 -53
- package/lib/chat/ChatSidebar.js +4 -51
- package/lib/chat/ChatStandalone.js +4 -45
- package/lib/chat/EphemeralSurfaceControl.js +5 -25
- package/lib/chat/assistant/AssistantContextMenu.d.ts +8 -0
- package/lib/chat/assistant/AssistantContextMenu.js +17 -1
- package/lib/chat/assistant/AssistantStage.js +6 -25
- package/lib/chat/assistant/BalloonParts.js +8 -40
- package/lib/chat/assistant/BalloonVisual.js +2 -2
- package/lib/chat/assistant/ConversationBalloon.js +2 -11
- package/lib/chat/assistant/DecisionAsk.js +3 -3
- package/lib/chat/assistant/SandboxDetailsDialog.js +3 -17
- package/lib/chat/assistant/SpeechBalloon.js +14 -78
- package/lib/chat/base/ChatBase.js +37 -172
- package/lib/chat/display/EmptyState.js +7 -35
- package/lib/chat/display/FloatingBrandButton.js +4 -34
- package/lib/chat/display/PoweredByTag.js +3 -14
- package/lib/chat/document/EphemeralDocument.js +3 -18
- package/lib/chat/header/ChatHeader.js +1 -17
- package/lib/chat/header/ChatHeaderBase.js +2 -24
- package/lib/chat/header/ChatViewModeToggle.js +7 -29
- package/lib/chat/indicators/McpStatusIndicator.js +3 -12
- package/lib/chat/indicators/SandboxStatusIndicator.js +6 -34
- package/lib/chat/indicators/SkillsStatusIndicator.js +3 -12
- package/lib/chat/indicators/TypingDots.js +1 -11
- package/lib/chat/messages/ChatMessageList.js +58 -185
- package/lib/chat/messages/ChatMessages.js +15 -79
- package/lib/chat/messages/FormSubmissionMessage.js +2 -33
- package/lib/chat/messages/NotebookToolSurfaces.js +12 -41
- package/lib/chat/messages/TurnFooter.js +4 -10
- package/lib/chat/notebook/EphemeralNotebook.js +2 -10
- package/lib/chat/parts/ReasoningPart.js +2 -16
- package/lib/chat/parts/TextPart.js +2 -12
- package/lib/chat/parts/ToolPart.js +16 -90
- package/lib/chat/presence/Presence.js +5 -33
- package/lib/chat/prompt/FloatingCard.js +1 -13
- package/lib/chat/prompt/InputPrompt.js +1 -6
- package/lib/chat/prompt/InputPromptBase.js +4 -17
- package/lib/chat/prompt/InputPromptLexical.js +44 -45
- package/lib/chat/prompt/InputPromptText.js +1 -1
- package/lib/chat/prompt/footer/InPromptFooter.js +1 -8
- package/lib/chat/prompt/menus/AgentsMenu.js +1 -1
- package/lib/chat/prompt/menus/InlineAgentsMenu.js +1 -1
- package/lib/chat/prompt/menus/ModelSelector.js +1 -5
- package/lib/chat/prompt/menus/SkillsMenu.js +3 -30
- package/lib/chat/prompt/menus/SuggestionsMenu.js +1 -1
- package/lib/chat/prompt/menus/ToolsMenu.js +4 -48
- package/lib/chat/prompt/plugins/AgentMentionPlugin.js +2 -9
- package/lib/chat/prompt/plugins/CommandPlugin.js +2 -9
- package/lib/chat/prompt/plugins/MentionChip.js +1 -15
- package/lib/chat/prompt/stack.js +1 -19
- package/lib/chat/tools/A2AAgentDialog.js +9 -42
- package/lib/chat/tools/SubagentActivity.js +5 -22
- package/lib/chat/tools/ToolApprovalBanner.js +4 -34
- package/lib/chat/tools/ToolApprovalDialog.js +4 -19
- package/lib/chat/tools/ToolCallDisplay.js +12 -97
- package/lib/chat/usage/ContextPie.js +4 -45
- package/lib/chat/words.d.ts +7 -0
- package/lib/chat/words.js +12 -0
- package/lib/components/a2ui/datalayer/Chart.js +4 -10
- package/lib/components/a2ui/datalayer/Chat.js +2 -10
- package/lib/components/a2ui/datalayer/Download.js +1 -1
- package/lib/components/a2ui/datalayer/Evidence.js +1 -15
- package/lib/components/a2ui/datalayer/FileUpload.js +1 -12
- package/lib/components/a2ui/datalayer/Table.js +9 -17
- package/lib/components/a2ui/datalayer/formWidgets.js +3 -2
- package/lib/components/a2ui/datalayer/parts.js +1 -16
- package/lib/components/a2ui/styles.js +16 -5
- package/lib/components/agents/AgentSummary.js +1 -51
- package/lib/components/cards/NotificationEventCard.js +6 -72
- package/lib/components/cards/OutputCard.js +4 -48
- package/lib/components/cards/ToolApprovalCard.js +2 -35
- package/lib/components/code-sandboxes/CodeSandboxCellVariables.js +1 -1
- package/lib/components/code-sandboxes/CodeSandboxEnvironmentSelect.js +4 -14
- package/lib/components/code-sandboxes/CodeSandboxPicker.js +16 -21
- package/lib/components/code-sandboxes/CodeSandboxVariables.js +2 -2
- package/lib/components/scheduler/ScheduleMenu.js +5 -10
- package/lib/components/specs/SpecPayloadPreview.js +1 -26
- package/lib/components/teams/A2ATeamGraph.d.ts +4 -3
- package/lib/components/teams/A2ATeamGraph.js +25 -71
- package/lib/components/teams/AnswerSurfacesView.js +2 -2
- package/lib/components/teams/NotebookPreview.js +1 -10
- package/lib/components/teams/NotebookPreviewView.js +2 -3
- package/lib/components/teams/SceneTranscript.js +3 -17
- package/lib/components/teams/SceneView.js +1 -8
- package/lib/components/teams/TeamNotebook.js +5 -13
- package/lib/components/teams/TeamNotebookView.js +2 -12
- package/lib/components/teams/index.d.ts +1 -0
- package/lib/components/teams/index.js +1 -0
- package/lib/components/teams/useBalloonRoom.d.ts +39 -0
- package/lib/components/teams/useBalloonRoom.js +89 -0
- package/lib/config/AgentConfiguration.js +22 -225
- package/lib/context/ContextDistribution.js +7 -41
- package/lib/context/ContextInspector.js +9 -107
- package/lib/context/ContextPanel.js +11 -86
- package/lib/context/ContextUsage.js +6 -34
- package/lib/context/CostTracker.js +7 -42
- package/lib/context/MessageHistory.js +3 -37
- package/lib/context/TurnGraphChart.js +9 -41
- package/lib/examples/A2UiAgentExample.js +6 -108
- package/lib/examples/A2UiComponentsGalleryExample.js +1 -1
- package/lib/examples/A2UiContactCardExample.js +1 -1
- package/lib/examples/A2UiJupyterOutputExample.js +25 -125
- package/lib/examples/A2UiRestaurantExample.js +1 -1
- package/lib/examples/A2UiViewerExample.js +1 -1
- package/lib/examples/AgUiAgenticExample.js +3 -35
- package/lib/examples/AgUiBackendToolRenderingExample.js +2 -25
- package/lib/examples/AgUiHaikuGenUiExample.js +2 -32
- package/lib/examples/AgUiHumanInTheLoopExample.js +5 -59
- package/lib/examples/AgUiSharedStateExample.js +6 -56
- package/lib/examples/AgUiToolsBasedGenUiExample.js +25 -120
- package/lib/examples/AgentA2AExample.js +1 -15
- package/lib/examples/AgentA2ATeamExample.js +6 -30
- package/lib/examples/AgentCheckpointsExample.js +11 -145
- package/lib/examples/AgentCodeSandboxExample.js +5 -108
- package/lib/examples/AgentCodeSandboxesExample.js +3 -30
- package/lib/examples/AgentCodemodeExample.js +9 -85
- package/lib/examples/AgentCompactionExample.js +3 -64
- package/lib/examples/AgentDecideExample.js +1 -13
- package/lib/examples/AgentEvalsExample.js +5 -60
- package/lib/examples/AgentGuardrailsExample.js +4 -28
- package/lib/examples/AgentHooksExample.js +1 -1
- package/lib/examples/AgentInferenceProviderExample.js +5 -96
- package/lib/examples/AgentMCPExample.js +7 -105
- package/lib/examples/AgentMemoryExample.js +5 -74
- package/lib/examples/AgentMonitoringExample.js +7 -53
- package/lib/examples/AgentNotificationsExample.js +3 -61
- package/lib/examples/AgentOtelExample.js +3 -72
- package/lib/examples/AgentOutputsExample.js +6 -81
- package/lib/examples/AgentParametersExample.js +2 -37
- package/lib/examples/AgentSkillsExample.js +3 -45
- package/lib/examples/AgentSubagentsExample.js +6 -56
- package/lib/examples/AgentToolApprovalsExample.js +1 -11
- package/lib/examples/AgentTriggersExample.js +29 -239
- package/lib/examples/AgentspecsExample.js +6 -60
- package/lib/examples/AssistantExample.js +5 -5
- package/lib/examples/AssistantGalleryExample.js +8 -65
- package/lib/examples/CellExample.js +1 -6
- package/lib/examples/ChatCustomExample.js +2 -31
- package/lib/examples/ChatExample.js +1 -9
- package/lib/examples/ChatStandaloneExample.js +3 -37
- package/lib/examples/CopilotKitLexicalExample.js +1 -24
- package/lib/examples/DecksAgent.js +1 -1
- package/lib/examples/DocumentPageAgent.js +1 -1
- package/lib/examples/HomeExample.js +14 -62
- package/lib/examples/Lexical2Example.js +3 -32
- package/lib/examples/LexicalAgentExample.js +2 -34
- package/lib/examples/LexicalAgentSidebarExample.js +3 -34
- package/lib/examples/LoopAppComputerExample.js +1 -1
- package/lib/examples/LoopShellExample.js +2 -2
- package/lib/examples/LoopStrategyExample.js +15 -87
- package/lib/examples/LoopWorkspaceEmbed.js +2 -18
- package/lib/examples/LoopWorkspaceExample.js +2 -2
- package/lib/examples/NotebookAgentExample.js +2 -33
- package/lib/examples/NotebookAgentSidebarExample.js +3 -46
- package/lib/examples/NotebookCollaborationExample.js +1 -31
- package/lib/examples/NotebookExample.js +1 -18
- package/lib/examples/NotebookPageAgent.js +1 -1
- package/lib/examples/ScenesExample.js +5 -24
- package/lib/examples/VoiceChatExample.js +1 -1
- package/lib/examples/components/AuthRequiredView.js +1 -7
- package/lib/examples/components/ErrorView.js +1 -8
- package/lib/examples/components/ExampleErrorBoundary.js +1 -14
- package/lib/examples/components/FooterMetrics.js +1 -7
- package/lib/examples/components/Header.js +12 -51
- package/lib/examples/components/HeaderControls.js +1 -9
- package/lib/examples/components/LexicalEditor.js +1 -8
- package/lib/examples/components/MainContent.js +1 -13
- package/lib/examples/components/MockFileBrowser.js +4 -40
- package/lib/examples/components/SessionTabs.js +1 -1
- package/lib/examples/components/TimeTravel.js +1 -13
- package/lib/examples/main.js +13 -81
- package/lib/examples/scenes/A2UiComponentsGalleryScene.js +3 -34
- package/lib/examples/scenes/A2UiContactCardScene.js +3 -35
- package/lib/examples/scenes/A2UiRestaurantScene.js +3 -53
- package/lib/examples/scenes/A2UiViewerScene.js +3 -34
- package/lib/examples/utils/AssistantGalleryGrid.js +6 -35
- package/lib/examples2/DatalayerNotebookExample.js +3 -33
- package/lib/examples2/NativeNavigationExample.js +4 -10
- package/lib/examples2/NotebookMutationsKernel.js +2 -1
- package/lib/examples2/NotebookMutationsServiceManager.js +2 -1
- package/lib/examples2/ReactRouterExample.js +14 -42
- package/lib/hooks/useToolApprovals.d.ts +2 -34
- package/lib/hooks/useToolApprovals.js +1 -64
- package/lib/identity/AgentIdentity.js +17 -62
- package/lib/identity/IdentityConnect.js +13 -59
- package/lib/identity/OAuthCallback.js +6 -44
- package/lib/lexical/ChatInlinePlugin.js +6 -14
- package/lib/loop/apps/AppFeedback.js +12 -3
- package/lib/loop/apps/AppRenderer.d.ts +4 -3
- package/lib/loop/apps/AppRenderer.js +11 -12
- package/lib/loop/apps/appspec.js +6 -3
- package/lib/loop/apps/feedback.d.ts +3 -2
- package/lib/loop/apps/feedback.js +4 -2
- package/lib/loop/core/index.d.ts +19 -0
- package/lib/loop/core/index.js +27 -0
- package/lib/loop/embed/AppEmbed.d.ts +1 -1
- package/lib/loop/embed/AppEmbed.js +2 -1
- package/lib/loop/embed/LoopEmbed.js +1 -7
- package/lib/loop/embed/embedConfig.d.ts +3 -3
- package/lib/loop/embed/embedConfig.js +2 -3
- package/lib/loop/embed/embedTheme.d.ts +4 -4
- package/lib/loop/embed/embedTheme.js +11 -7
- package/lib/loop/plugins/a2a-sidebar/A2ASidebar.js +7 -34
- package/lib/loop/plugins/a2ui/A2uiView.js +4 -12
- package/lib/loop/plugins/a2ui-surface/InlineSurface.js +1 -16
- package/lib/loop/plugins/a2ui-surface/SurfaceToolResult.js +2 -12
- package/lib/loop/plugins/agents/AnonymousKeyBadge.js +3 -2
- package/lib/loop/plugins/agents/SandboxSelector.js +3 -7
- package/lib/loop/plugins/agents/SandboxView.js +4 -27
- package/lib/loop/plugins/agents/TeamMemberPicker.js +2 -2
- package/lib/loop/plugins/agentspecs/AgentspecPicker.js +3 -2
- package/lib/loop/plugins/app-activity/AppActivity.js +1 -1
- package/lib/loop/plugins/app-computer/AppComputer.js +32 -27
- package/lib/loop/plugins/app-elements/AppElements.js +2 -31
- package/lib/loop/plugins/app-page/AppPage.js +26 -8
- package/lib/loop/plugins/app-rules/AppRulesCard.js +4 -20
- package/lib/loop/plugins/assistant/index.js +1 -13
- package/lib/loop/plugins/chat/ChatView.js +89 -130
- package/lib/loop/plugins/checkpoints-sidebar/CheckpointsSidebar.js +2 -13
- package/lib/loop/plugins/decks/DeckSurface.js +2 -2
- package/lib/loop/plugins/document/DocumentView.js +4 -12
- package/lib/loop/plugins/document-toolbar/SandboxStatusItem.js +3 -8
- package/lib/loop/plugins/graph/GraphView.js +2 -2
- package/lib/loop/plugins/input-prompt/ComposerView.js +1 -1
- package/lib/loop/plugins/notebook/NotebookView.js +3 -11
- package/lib/loop/plugins/page-layout/SplitLayout.js +11 -34
- package/lib/loop/plugins/page-layout/TurnPanel.js +9 -35
- package/lib/loop/plugins/shell/useEditorPreviews.js +3 -2
- package/lib/loop/plugins/subagent-activity/SubagentPulse.js +1 -13
- package/lib/loop/plugins/window-frame/WindowFrame.js +10 -44
- package/lib/loop/plugins/window-frame/index.js +1 -1
- package/lib/loop/shell/LoopWorkspace.js +34 -77
- package/lib/loop/shell/PluginToggles.js +4 -15
- package/lib/loop/shell/SidebarRail.js +8 -40
- package/lib/loop/shell/ViewSwitcher.js +4 -24
- package/lib/loop-main.js +2 -3
- package/lib/mcp/McpServerManager.js +6 -37
- package/lib/portable/index.d.ts +11 -0
- package/lib/portable/index.js +20 -0
- package/lib/protocols/AGUIAdapter.js +2 -2
- package/lib/protocols/BaseProtocolAdapter.d.ts +2 -0
- package/lib/protocols/BaseProtocolAdapter.js +4 -0
- package/lib/specs/apps.js +6 -0
- package/lib/specs/appspecSchema.js +11 -4
- package/lib/stories/loop/ReferenceScreens.js +17 -91
- package/lib/stories/loop/pictures-main.js +1 -1
- package/lib/types/agentspecs.d.ts +5 -2
- package/lib/types/protocol.d.ts +2 -0
- package/lib/utils/approvals.d.ts +59 -0
- package/lib/utils/approvals.js +101 -0
- package/lib/voice/VoiceInput.js +3 -39
- package/package.json +2 -2
- package/lib/shims/primerAddonsBox.d.ts +0 -1
- package/lib/shims/primerAddonsBox.js +0 -7
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Copyright (c) 2025-2026 Datalayer, Inc.
|
|
3
3
|
* Distributed under the terms of the Modified BSD License.
|
|
4
4
|
*/
|
|
5
|
-
import { getThemeConfig,
|
|
5
|
+
import { getThemeConfig, loopFontFamily, scopeThemeCss, THEME_SCOPE_ATTRIBUTE, themeAccentVars, } from '@datalayer/primer-addons';
|
|
6
6
|
/** One mode's properties, with the theme's face replaced by the host's. */
|
|
7
7
|
function withFace(styles, font, own) {
|
|
8
8
|
if (!font || !own) {
|
|
@@ -20,18 +20,22 @@ function faceOf(variant, styles) {
|
|
|
20
20
|
}
|
|
21
21
|
return typeof styles.fontFamily === 'string' ? styles.fontFamily : '';
|
|
22
22
|
}
|
|
23
|
-
/**
|
|
24
|
-
|
|
23
|
+
/**
|
|
24
|
+
* The accent over a theme, whichever theme (T-05, T-30; every theme since
|
|
25
|
+
* 2026-10-07); none when neither the application nor the host names one —
|
|
26
|
+
* the theme's own colours.
|
|
27
|
+
*/
|
|
28
|
+
const accentOver = (accent, which) => (accent ? themeAccentVars(accent, which) : {});
|
|
25
29
|
/**
|
|
26
30
|
* The theme as the embed wears it — `loop`, or the one the application
|
|
27
|
-
* names (T-30) — with the application's accent over
|
|
31
|
+
* names (T-30) — with the application's accent over it in both modes
|
|
28
32
|
* (T-05), and the host's face when it named one.
|
|
29
33
|
*/
|
|
30
34
|
export function embedThemeStyles({ accent, font = '', variant = 'loop', }) {
|
|
31
35
|
const base = getThemeConfig(variant).themeStyles;
|
|
32
36
|
const mode = (which) => {
|
|
33
37
|
const theme = base[which];
|
|
34
|
-
return withFace({ ...theme, ...accentOver(
|
|
38
|
+
return withFace({ ...theme, ...accentOver(accent, which) }, font, faceOf(variant, theme));
|
|
35
39
|
};
|
|
36
40
|
return {
|
|
37
41
|
...base,
|
|
@@ -43,7 +47,7 @@ export function embedThemeStyles({ accent, font = '', variant = 'loop', }) {
|
|
|
43
47
|
* The same accent and face laid over the conversation's own theme (T-05,
|
|
44
48
|
* D-11): the chat sets its theme again inside it, which would put the
|
|
45
49
|
* theme's colours and face back over what the embed set around it. The
|
|
46
|
-
* accent's properties in each mode (over
|
|
50
|
+
* accent's properties in each mode (over any theme), and, when the host
|
|
47
51
|
* named a face, every property of the theme that names its own.
|
|
48
52
|
*/
|
|
49
53
|
export function embedThemeOverrides({ accent, font = '', variant = 'loop', }) {
|
|
@@ -51,7 +55,7 @@ export function embedThemeOverrides({ accent, font = '', variant = 'loop', }) {
|
|
|
51
55
|
const mode = (which) => {
|
|
52
56
|
const theme = base[which];
|
|
53
57
|
const faced = Object.fromEntries(Object.entries(withFace(theme, font, faceOf(variant, theme))).filter(([name, value]) => typeof value === 'string' && value !== theme[name]));
|
|
54
|
-
return { ...faced, ...accentOver(
|
|
58
|
+
return { ...faced, ...accentOver(accent, which) };
|
|
55
59
|
};
|
|
56
60
|
return { light: mode('light'), dark: mode('dark') };
|
|
57
61
|
}
|
|
@@ -100,14 +100,14 @@ const STATUS_LABEL = {
|
|
|
100
100
|
function StatusBadge({ status, }) {
|
|
101
101
|
switch (status) {
|
|
102
102
|
case 'done':
|
|
103
|
-
return (_jsx(Box, {
|
|
103
|
+
return (_jsx(Box, { color: "success.fg", display: "flex", children: _jsx(CheckCircleIcon, {}) }));
|
|
104
104
|
case 'stopped':
|
|
105
|
-
return (_jsx(Box, {
|
|
105
|
+
return (_jsx(Box, { color: "attention.fg", display: "flex", children: _jsx(AlertIcon, {}) }));
|
|
106
106
|
case 'failed':
|
|
107
|
-
return (_jsx(Box, {
|
|
107
|
+
return (_jsx(Box, { color: "danger.fg", display: "flex", children: _jsx(AlertIcon, {}) }));
|
|
108
108
|
case 'launching':
|
|
109
109
|
case 'working':
|
|
110
|
-
return (_jsx(Box, {
|
|
110
|
+
return (_jsx(Box, { color: "accent.fg", display: "flex", children: _jsx(DependabotIcon, {}) }));
|
|
111
111
|
default:
|
|
112
112
|
return _jsx(BroadcastIcon, {});
|
|
113
113
|
}
|
|
@@ -120,13 +120,7 @@ function LaunchChip({ launch, }) {
|
|
|
120
120
|
: launch === 'local'
|
|
121
121
|
? DeviceDesktopIcon
|
|
122
122
|
: BroadcastIcon;
|
|
123
|
-
return (_jsxs(Box, { sx: {
|
|
124
|
-
display: 'inline-flex',
|
|
125
|
-
alignItems: 'center',
|
|
126
|
-
gap: 1,
|
|
127
|
-
fontSize: 0,
|
|
128
|
-
color: 'fg.muted',
|
|
129
|
-
}, children: [_jsx(Icon, { size: 12 }), _jsx(Text, { sx: { fontSize: 0 }, children: launch })] }));
|
|
123
|
+
return (_jsxs(Box, { display: "inline-flex", alignItems: "center", gap: 1, fontSize: 0, color: "fg.muted", children: [_jsx(Icon, { size: 12 }), _jsx(Text, { sx: { fontSize: 0 }, children: launch })] }));
|
|
130
124
|
}
|
|
131
125
|
function SectionHeading({ children }) {
|
|
132
126
|
return (_jsx(Heading, { as: "h4", sx: { fontSize: 1, mb: 2 }, children: children }));
|
|
@@ -142,30 +136,9 @@ export function A2ASidebar(_props) {
|
|
|
142
136
|
const [shown, setShown] = useState(null);
|
|
143
137
|
const activeOverA2A = activeKey !== null &&
|
|
144
138
|
(activity[activeKey] ?? []).some(event => event.transport === 'a2a');
|
|
145
|
-
return (_jsxs(Box, { "data-a2a-sidebar": true,
|
|
146
|
-
height: A2A_ACTIVE_PANEL_HEIGHT,
|
|
147
|
-
display: 'flex',
|
|
148
|
-
alignItems: 'center',
|
|
149
|
-
justifyContent: 'center',
|
|
150
|
-
border: '1px solid',
|
|
151
|
-
borderColor: 'border.muted',
|
|
152
|
-
borderRadius: 2,
|
|
153
|
-
bg: 'canvas.default',
|
|
154
|
-
}, children: _jsx(Text, { sx: { fontSize: 0, color: 'fg.muted', m: 0 }, children: "No A2A agent running" }) }))] }), _jsxs(Box, { children: [_jsx(SectionHeading, { children: "Remote agents" }), agents.length === 0 ? (_jsx(Text, { as: "p", sx: { fontSize: 0, color: 'fg.muted', m: 0 }, children: "This agent declares no A2A agents." })) : (_jsx(Timeline, { children: agents.map(agent => {
|
|
139
|
+
return (_jsxs(Box, { "data-a2a-sidebar": true, display: "flex", flexDirection: "column", gap: 4, children: [_jsxs(Box, { display: "flex", alignItems: "center", gap: 2, children: [_jsx(BroadcastIcon, { size: 16 }), _jsx(Heading, { as: "h3", sx: { fontSize: 2, m: 0, flex: 1 }, children: "A2A agents" }), _jsx(Label, { variant: "accent", children: agents.length })] }), _jsxs(Box, { children: [_jsx(SectionHeading, { children: "Running now" }), activeKey && activeOverA2A ? (_jsx(SubagentChatPanel, { toolCallId: activeKey, height: A2A_ACTIVE_PANEL_HEIGHT })) : (_jsx(Box, { "data-a2a-sidebar-idle": true, height: A2A_ACTIVE_PANEL_HEIGHT, display: "flex", alignItems: "center", justifyContent: "center", border: "1px solid", borderColor: "border.muted", borderRadius: 2, bg: "canvas.default", children: _jsx(Text, { sx: { fontSize: 0, color: 'fg.muted', m: 0 }, children: "No A2A agent running" }) }))] }), _jsxs(Box, { children: [_jsx(SectionHeading, { children: "Remote agents" }), agents.length === 0 ? (_jsx(Text, { as: "p", sx: { fontSize: 0, color: 'fg.muted', m: 0 }, children: "This agent declares no A2A agents." })) : (_jsx(Timeline, { children: agents.map(agent => {
|
|
155
140
|
const status = STATUS_LABEL[agent.status];
|
|
156
|
-
return (_jsxs(Timeline.Item, { "data-a2a-agent": agent.name, children: [_jsx(Timeline.Badge, { children: _jsx(StatusBadge, { status: agent.status }) }), _jsxs(Timeline.Body, { children: [_jsxs(Box, { sx: {
|
|
157
|
-
display: 'flex',
|
|
158
|
-
alignItems: 'center',
|
|
159
|
-
gap: 2,
|
|
160
|
-
mb: 1,
|
|
161
|
-
flexWrap: 'wrap',
|
|
162
|
-
}, children: [_jsx(Text, { sx: { fontWeight: 'bold', fontSize: 1 }, children: agent.name }), _jsx(Label, { variant: status.variant, size: "small", children: status.text }), _jsx(LaunchChip, { launch: agent.launch })] }), agent.description ? (_jsx(Text, { as: "p", sx: { fontSize: 0, color: 'fg.muted', mt: 0, mb: 1 }, children: agent.description })) : null, _jsxs(Box, { sx: {
|
|
163
|
-
display: 'flex',
|
|
164
|
-
flexDirection: 'column',
|
|
165
|
-
gap: '2px',
|
|
166
|
-
fontSize: 0,
|
|
167
|
-
color: 'fg.muted',
|
|
168
|
-
}, children: [agent.card?.name ? (_jsxs(Text, { sx: { fontSize: 0 }, children: ["Card: ", agent.card.name, agent.card.version ? ` v${agent.card.version}` : ''] })) : agent.ref ? (_jsx(Text, { sx: { fontSize: 0, fontFamily: 'mono' }, children: agent.ref })) : null, agent.url ? (_jsx(Link, { as: "button", type: "button", "data-a2a-card-button": agent.name, onClick: () => setShown(agent), sx: {
|
|
141
|
+
return (_jsxs(Timeline.Item, { "data-a2a-agent": agent.name, children: [_jsx(Timeline.Badge, { children: _jsx(StatusBadge, { status: agent.status }) }), _jsxs(Timeline.Body, { children: [_jsxs(Box, { display: "flex", alignItems: "center", gap: 2, mb: 1, flexWrap: "wrap", children: [_jsx(Text, { sx: { fontWeight: 'bold', fontSize: 1 }, children: agent.name }), _jsx(Label, { variant: status.variant, size: "small", children: status.text }), _jsx(LaunchChip, { launch: agent.launch })] }), agent.description ? (_jsx(Text, { as: "p", sx: { fontSize: 0, color: 'fg.muted', mt: 0, mb: 1 }, children: agent.description })) : null, _jsxs(Box, { display: "flex", flexDirection: "column", gap: "2px", fontSize: 0, color: "fg.muted", children: [agent.card?.name ? (_jsxs(Text, { sx: { fontSize: 0 }, children: ["Card: ", agent.card.name, agent.card.version ? ` v${agent.card.version}` : ''] })) : agent.ref ? (_jsx(Text, { sx: { fontSize: 0, fontFamily: 'mono' }, children: agent.ref })) : null, agent.url ? (_jsx(Link, { as: "button", type: "button", "data-a2a-card-button": agent.name, onClick: () => setShown(agent), sx: {
|
|
169
142
|
fontSize: 0,
|
|
170
143
|
fontFamily: 'mono',
|
|
171
144
|
overflow: 'hidden',
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
3
|
-
import { Box
|
|
3
|
+
import { Box } from '@datalayer/primer-addons';
|
|
4
|
+
import { Text } from '@primer/react';
|
|
4
5
|
import { MessageProcessor, } from '@a2ui/web_core/v0_9';
|
|
5
6
|
import { useSignalValue } from '@datalayer/reactor/react';
|
|
6
7
|
import { A2uiSurfaceComposed, datalayerCatalog, } from '../../../components/a2ui';
|
|
@@ -80,17 +81,8 @@ export default function A2uiView({ workspace }) {
|
|
|
80
81
|
if (surfaces.length === 0) {
|
|
81
82
|
return (_jsx(Centered, { children: _jsx(Text, { children: "Nothing has run yet. Ask for something that executes code and the result appears here as a surface rather than as output." }) }));
|
|
82
83
|
}
|
|
83
|
-
return (_jsx(Box, {
|
|
84
|
+
return (_jsx(Box, { height: "100%", overflowY: "auto", px: 4, py: 3, style: INHERIT_THEME, children: surfaces.map(surface => (_jsx(A2uiSurfaceComposed, { surface: surface }, surface.id))) }));
|
|
84
85
|
}
|
|
85
86
|
function Centered({ children }) {
|
|
86
|
-
return (_jsx(Box, {
|
|
87
|
-
height: '100%',
|
|
88
|
-
display: 'flex',
|
|
89
|
-
alignItems: 'center',
|
|
90
|
-
justifyContent: 'center',
|
|
91
|
-
color: 'fg.muted',
|
|
92
|
-
fontSize: 1,
|
|
93
|
-
px: 4,
|
|
94
|
-
textAlign: 'center',
|
|
95
|
-
}, children: children }));
|
|
87
|
+
return (_jsx(Box, { height: "100%", display: "flex", alignItems: "center", justifyContent: "center", color: "fg.muted", fontSize: 1, px: 4, textAlign: "center", children: children }));
|
|
96
88
|
}
|
|
@@ -79,21 +79,6 @@ export function InlineSurface({ messages, onAction, validationError, data, catal
|
|
|
79
79
|
display: 'flex',
|
|
80
80
|
flexDirection: 'column',
|
|
81
81
|
gap: 2,
|
|
82
|
-
}, children: [notice ? (_jsx(Box, { role: "alert",
|
|
83
|
-
px: 3,
|
|
84
|
-
py: 2,
|
|
85
|
-
borderRadius: 2,
|
|
86
|
-
bg: 'danger.subtle',
|
|
87
|
-
border: '1px solid',
|
|
88
|
-
borderColor: 'danger.muted',
|
|
89
|
-
color: 'danger.fg',
|
|
90
|
-
fontSize: 1,
|
|
91
|
-
}, children: notice })) : null, surfaces.map(surface => (_jsx(Box, { sx: {
|
|
92
|
-
border: '1px solid',
|
|
93
|
-
borderColor: 'border.default',
|
|
94
|
-
borderRadius: 2,
|
|
95
|
-
p: 3,
|
|
96
|
-
bg: 'canvas.default',
|
|
97
|
-
}, children: _jsx(A2uiSurfaceComposed, { surface: surface }) }, surface.id)))] }) }));
|
|
82
|
+
}, children: [notice ? (_jsx(Box, { role: "alert", px: 3, py: 2, borderRadius: 2, bg: "danger.subtle", border: "1px solid", borderColor: "danger.muted", color: "danger.fg", fontSize: 1, children: notice })) : null, surfaces.map(surface => (_jsx(Box, { border: "1px solid", borderColor: "border.default", borderRadius: 2, p: 3, bg: "canvas.default", children: _jsx(A2uiSurfaceComposed, { surface: surface }) }, surface.id)))] }) }));
|
|
98
83
|
}
|
|
99
84
|
export default InlineSurface;
|
|
@@ -56,18 +56,8 @@ export function SurfaceToolResult({ context, send, onRendered, onSubmitted, }) {
|
|
|
56
56
|
}
|
|
57
57
|
}, [parsed, title, send, onSubmitted]);
|
|
58
58
|
if (!parsed?.messages || parsed.messages.length === 0) {
|
|
59
|
-
return (_jsxs(Box, { sx: {
|
|
60
|
-
border: '1px solid',
|
|
61
|
-
borderColor: 'border.default',
|
|
62
|
-
borderRadius: 2,
|
|
63
|
-
px: 3,
|
|
64
|
-
py: 2,
|
|
65
|
-
bg: 'canvas.default',
|
|
66
|
-
display: 'flex',
|
|
67
|
-
alignItems: 'center',
|
|
68
|
-
gap: 2,
|
|
69
|
-
}, children: [_jsx(Spinner, { size: "small" }), _jsx(Text, { sx: { fontSize: 1, color: 'fg.muted' }, children: "Rendering A2UI surface..." })] }));
|
|
59
|
+
return (_jsxs(Box, { border: "1px solid", borderColor: "border.default", borderRadius: 2, px: 3, py: 2, bg: "canvas.default", display: "flex", alignItems: "center", gap: 2, children: [_jsx(Spinner, { size: "small" }), _jsx(Text, { sx: { fontSize: 1, color: 'fg.muted' }, children: "Rendering A2UI surface..." })] }));
|
|
70
60
|
}
|
|
71
|
-
return (_jsxs(Box, {
|
|
61
|
+
return (_jsxs(Box, { display: "flex", flexDirection: "column", gap: 2, children: [_jsx(Text, { sx: { fontWeight: 'bold' }, children: title }), _jsx(InlineSurface, { messages: parsed.messages, onAction: handleAction, validationError: validationError, catalog: catalog })] }));
|
|
72
62
|
}
|
|
73
63
|
export default SurfaceToolResult;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { Box
|
|
2
|
+
import { Box } from '@datalayer/primer-addons';
|
|
3
|
+
import { Text } from '@primer/react';
|
|
3
4
|
/* Both by file rather than through their barrels. The barrels reach the
|
|
4
5
|
sign-in form and the whole in-page harness, and a plugin that only draws a
|
|
5
6
|
countdown should not put either in the graph of every host that mounts
|
|
@@ -18,7 +19,7 @@ import { targetRunsAgentInPage } from './switchable';
|
|
|
18
19
|
* that lives.
|
|
19
20
|
*/
|
|
20
21
|
export function AnonymousKeyHeaderBadge({ workspace, }) {
|
|
21
|
-
return (_jsx(Box, {
|
|
22
|
+
return (_jsx(Box, { order: 1, display: "inline-flex", alignItems: "center", children: _jsx(AnonymousKeyBadge, { workspace: workspace }) }));
|
|
22
23
|
}
|
|
23
24
|
export function AnonymousKeyBadge({ workspace, }) {
|
|
24
25
|
const session = useAnonymousSession();
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useCallback, useState } from 'react';
|
|
3
|
-
import { Box
|
|
3
|
+
import { Box } from '@datalayer/primer-addons';
|
|
4
|
+
import { SegmentedControl, Spinner, Text } from '@primer/react';
|
|
4
5
|
import { KernelIndicator } from '@datalayer/jupyter-react/kernel-indicator';
|
|
5
6
|
import { useSignalValue } from '@datalayer/reactor/react';
|
|
6
7
|
import { IDLE_SANDBOX_SNAPSHOT_SIGNAL, sandboxIndicatorState, } from '../../core';
|
|
@@ -37,12 +38,7 @@ export function SandboxSelector(_props) {
|
|
|
37
38
|
return null;
|
|
38
39
|
}
|
|
39
40
|
const index = Math.max(0, SANDBOX_TARGETS.indexOf(target));
|
|
40
|
-
return (_jsxs(Box, {
|
|
41
|
-
width: 16,
|
|
42
|
-
flexShrink: 0,
|
|
43
|
-
display: 'flex',
|
|
44
|
-
justifyContent: 'center',
|
|
45
|
-
}, children: moving ? _jsx(Spinner, { size: "small" }) : null }), _jsx(KernelIndicator, { state: sandboxIndicatorState(snapshot.state, status?.execution_state, status?.is_executing), kernelId: snapshot.kernelId ?? status?.kernel_id, kernelName: status?.kernel_name, serverUrl: snapshot.jupyterUrl ?? status?.jupyter_url, websocketUrl: toWebsocketUrl(snapshot.jupyterUrl ?? status?.jupyter_url),
|
|
41
|
+
return (_jsxs(Box, { display: "flex", alignItems: "center", gap: 2, minWidth: 0, children: [_jsx(Box, { width: 16, flexShrink: 0, display: "flex", justifyContent: "center", children: moving ? _jsx(Spinner, { size: "small" }) : null }), _jsx(KernelIndicator, { state: sandboxIndicatorState(snapshot.state, status?.execution_state, status?.is_executing), kernelId: snapshot.kernelId ?? status?.kernel_id, kernelName: status?.kernel_name, serverUrl: snapshot.jupyterUrl ?? status?.jupyter_url, websocketUrl: toWebsocketUrl(snapshot.jupyterUrl ?? status?.jupyter_url),
|
|
46
42
|
/*
|
|
47
43
|
The target that was chosen, not the variant last reported.
|
|
48
44
|
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { Box
|
|
2
|
+
import { Box } from '@datalayer/primer-addons';
|
|
3
|
+
import { Label, Text } from '@primer/react';
|
|
3
4
|
import { useSignalValue } from '@datalayer/reactor/react';
|
|
4
5
|
import { useSandboxService } from './useSandboxService';
|
|
5
6
|
function Row({ label, value }) {
|
|
6
|
-
return (_jsxs(Box, {
|
|
7
|
+
return (_jsxs(Box, { display: "flex", gap: 3, py: 1, fontSize: 1, children: [_jsx(Text, { sx: { color: 'fg.muted', minWidth: '140px' }, children: label }), _jsx(Text, { sx: { fontFamily: 'mono', wordBreak: 'break-all' }, children: value || _jsx(Text, { sx: { color: 'fg.subtle' }, children: "\u2014" }) })] }));
|
|
7
8
|
}
|
|
8
9
|
export default function SandboxView(_props) {
|
|
9
10
|
const service = useSandboxService();
|
|
@@ -15,29 +16,5 @@ export default function SandboxView(_props) {
|
|
|
15
16
|
: snapshot.state === 'error'
|
|
16
17
|
? 'danger'
|
|
17
18
|
: 'attention';
|
|
18
|
-
return (_jsxs(Box, {
|
|
19
|
-
mt: 3,
|
|
20
|
-
p: 3,
|
|
21
|
-
bg: 'attention.subtle',
|
|
22
|
-
borderRadius: 2,
|
|
23
|
-
fontSize: 1,
|
|
24
|
-
}, children: "No sandbox is attached. Views that need one \u2014 the notebook, the document \u2014 stay unavailable until there is a kernel to bind to." })) : null, lastExecution ? (_jsxs(Box, { sx: { mt: 4 }, children: [_jsx(Text, { sx: { fontSize: 2, fontWeight: 'bold' }, children: "Last execution" }), _jsx(Box, { sx: {
|
|
25
|
-
mt: 2,
|
|
26
|
-
p: 2,
|
|
27
|
-
bg: 'canvas.subtle',
|
|
28
|
-
borderRadius: 2,
|
|
29
|
-
fontFamily: 'mono',
|
|
30
|
-
fontSize: 0,
|
|
31
|
-
whiteSpace: 'pre-wrap',
|
|
32
|
-
}, children: lastExecution.code }), lastExecution.stdout ? (_jsx(Box, { sx: {
|
|
33
|
-
mt: 1,
|
|
34
|
-
fontFamily: 'mono',
|
|
35
|
-
fontSize: 0,
|
|
36
|
-
whiteSpace: 'pre-wrap',
|
|
37
|
-
}, children: lastExecution.stdout })) : null, lastExecution.error ? (_jsx(Box, { sx: {
|
|
38
|
-
mt: 1,
|
|
39
|
-
color: 'danger.fg',
|
|
40
|
-
fontFamily: 'mono',
|
|
41
|
-
fontSize: 0,
|
|
42
|
-
}, children: lastExecution.error })) : null] })) : null] }));
|
|
19
|
+
return (_jsxs(Box, { height: "100%", overflowY: "auto", px: 4, py: 3, children: [_jsxs(Box, { display: "flex", alignItems: "center", gap: 2, mb: 3, children: [_jsx(Text, { sx: { fontSize: 3, fontWeight: 'bold' }, children: "Code Sandbox" }), _jsx(Label, { variant: tone, children: snapshot.state })] }), _jsx(Row, { label: "Variant", value: snapshot.variant }), _jsx(Row, { label: "Kernel", value: status?.kernel_name ?? snapshot.kernelId }), _jsx(Row, { label: "Kernel id", value: snapshot.kernelId }), _jsx(Row, { label: "Jupyter server", value: snapshot.jupyterUrl }), _jsx(Row, { label: "Execution state", value: status?.execution_state }), snapshot.state !== 'running' ? (_jsx(Box, { mt: 3, p: 3, bg: "attention.subtle", borderRadius: 2, fontSize: 1, children: "No sandbox is attached. Views that need one \u2014 the notebook, the document \u2014 stay unavailable until there is a kernel to bind to." })) : null, lastExecution ? (_jsxs(Box, { mt: 4, children: [_jsx(Text, { sx: { fontSize: 2, fontWeight: 'bold' }, children: "Last execution" }), _jsx(Box, { mt: 2, p: 2, bg: "canvas.subtle", borderRadius: 2, fontFamily: "mono", fontSize: 0, whiteSpace: "pre-wrap", children: lastExecution.code }), lastExecution.stdout ? (_jsx(Box, { mt: 1, fontFamily: "mono", fontSize: 0, whiteSpace: "pre-wrap", children: lastExecution.stdout })) : null, lastExecution.error ? (_jsx(Box, { mt: 1, color: "danger.fg", fontFamily: "mono", fontSize: 0, children: lastExecution.error })) : null] })) : null] }));
|
|
43
20
|
}
|
|
@@ -42,10 +42,10 @@ function TeamMemberMenu({ selection, }) {
|
|
|
42
42
|
// than an id pointing at an icon would.
|
|
43
43
|
, { ...anchorProps, "aria-labelledby": undefined, icon: AiAgentIcon, "aria-label": active
|
|
44
44
|
? `Talking to ${active.name}. Choose another agent.`
|
|
45
|
-
: 'Choose an agent', variant: "invisible", size: "small" })), children: _jsx(Box, {
|
|
45
|
+
: 'Choose an agent', variant: "invisible", size: "small" })), children: _jsx(Box, { width: 440, maxWidth: "calc(100vw - 16px)", children: _jsxs(ActionList, { selectionVariant: "single", role: "listbox", "aria-label": `Agents in ${selection.team.name}`, children: [_jsx(ActionList.GroupHeading, { children: selection.team.name }), selection.members.map(member => (_jsxs(ActionList.Item, { selected: member.id === selectedId, onSelect: () => {
|
|
46
46
|
selection.select(member.id);
|
|
47
47
|
setOpen(false);
|
|
48
|
-
}, children: [_jsx(ActionList.LeadingVisual, { children: _jsx(MemberIcon, { icon: member.icon }) }), _jsxs(Box, { as: "span",
|
|
48
|
+
}, children: [_jsx(ActionList.LeadingVisual, { children: _jsx(MemberIcon, { icon: member.icon }) }), _jsxs(Box, { as: "span", display: "flex", alignItems: "center", gap: 2, children: [member.name, member.isSupervisor ? (_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: "supervisor" })) : null] }), member.description ? (_jsx(ActionList.Description, { variant: "block",
|
|
49
49
|
/* Wrapped and breakable. `minWidth: 0` is the load-bearing
|
|
50
50
|
one: a grid item defaults to `min-content`, so without it
|
|
51
51
|
the description refuses to be narrower than its longest
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useCallback, useEffect, useState } from 'react';
|
|
3
|
-
import {
|
|
3
|
+
import { Box } from '@datalayer/primer-addons';
|
|
4
|
+
import { ActionList, ActionMenu, Spinner } from '@primer/react';
|
|
4
5
|
import { getAgentspecs } from '../../../specs/agents';
|
|
5
6
|
export function AgentspecPicker({ workspace, }) {
|
|
6
7
|
const [agents, setAgents] = useState([]);
|
|
@@ -85,6 +86,6 @@ export function AgentspecPicker({ workspace, }) {
|
|
|
85
86
|
*/
|
|
86
87
|
return null;
|
|
87
88
|
}
|
|
88
|
-
return (_jsxs(Box, {
|
|
89
|
+
return (_jsxs(Box, { display: "flex", alignItems: "center", gap: 1, children: [switching ? _jsx(Spinner, { size: "small" }) : null, _jsxs(ActionMenu, { children: [_jsxs(ActionMenu.Button, { variant: "invisible", size: "small", children: [current?.emoji ? `${current.emoji} ` : '', label] }), _jsx(ActionMenu.Overlay, { width: "medium", children: _jsx(ActionList, { selectionVariant: "single", children: agents.map(agent => (_jsxs(ActionList.Item, { selected: agent.id === active, onSelect: () => void choose(agent.id), children: [agent.emoji ? `${agent.emoji} ` : '', agent.name || agent.id, agent.description ? (_jsx(ActionList.Description, { variant: "block", children: agent.description })) : null] }, agent.id))) }) })] })] }));
|
|
89
90
|
}
|
|
90
91
|
export default AgentspecPicker;
|
|
@@ -40,7 +40,7 @@ function useRead(load, key, when = true) {
|
|
|
40
40
|
function Session({ context, session, }) {
|
|
41
41
|
const [open, setOpen] = useState(false);
|
|
42
42
|
const entries = useRead(() => readSession(context, session.sessionUid), `${session.sessionUid}:${context.token}`, open);
|
|
43
|
-
return (_jsxs(Box, { as: "details", onToggle: (event) => setOpen(event.currentTarget.open),
|
|
43
|
+
return (_jsxs(Box, { as: "details", onToggle: (event) => setOpen(event.currentTarget.open), borderTop: "1px solid", borderColor: "border.muted", py: 2, children: [_jsxs(Box, { as: "summary", cursor: "pointer", fontSize: 1, children: [session.createdAt ? (_jsx(RelativeTime, { datetime: session.createdAt })) : ('A session'), session.version ? ` · version ${session.version}` : '', entries.value ? ` · ${sessionSentence(entries.value)}` : ''] }), !open ? null : entries.loading ? (_jsx(Spinner, { size: "small" })) : entries.error ? (_jsx(Text, { role: "alert", sx: { fontSize: 1 }, children: entries.error })) : (_jsx(Box, { as: "ol", pl: 3, mt: 2, mb: 0, fontSize: 1, children: (entries.value ?? []).map(entry => (_jsxs(Box, { as: "li", mb: 1, children: [_jsx(Label, { sx: { mr: 2 }, children: RECORD_KIND_WORDS[entry.kind] ?? entry.kind }), entry.summary] }, entry.uid))) }))] }));
|
|
44
44
|
}
|
|
45
45
|
export function AppActivity({ appUid }) {
|
|
46
46
|
const token = useIAMStore(state => state.token) ?? '';
|
|
@@ -5,7 +5,8 @@ import { Box } from '@datalayer/primer-addons';
|
|
|
5
5
|
import { signal } from '@datalayer/reactor';
|
|
6
6
|
import { useContributions, useSignalValue } from '@datalayer/reactor/react';
|
|
7
7
|
import { useIAMStore } from '@datalayer/core/lib/state/substates/IAMState';
|
|
8
|
-
import {
|
|
8
|
+
import { useChatWords } from '../../../chat/ChatLanguage';
|
|
9
|
+
import { LoopChatTurn, agentServerOf, noRuntimeSaid, IDLE_SANDBOX_SNAPSHOT, } from '../../core';
|
|
9
10
|
import { COMPUTER_PARTS, COMPUTER_WORDS, computerParts, downloadComputerFile, handBackComputer, hasComputer, listComputerFiles, parentOf, partsOff, readComputer, runOnComputer, takeOverComputer, terminalEntries, } from '../../apps/computer';
|
|
10
11
|
const NO_TURN = signal({ id: 0, status: 'idle' });
|
|
11
12
|
const NO_CONVERSATION = signal([]);
|
|
@@ -20,19 +21,11 @@ const MONO = {
|
|
|
20
21
|
function Parts({ app }) {
|
|
21
22
|
const parts = computerParts(app);
|
|
22
23
|
const off = partsOff(parts);
|
|
23
|
-
return (_jsxs(Box, { "data-testid": "computer-parts", children: [_jsx(Box, {
|
|
24
|
+
return (_jsxs(Box, { "data-testid": "computer-parts", children: [_jsx(Box, { display: "flex", gap: 1, flexWrap: "wrap", mb: 1, children: COMPUTER_PARTS.map(part => (_jsxs(Label, { variant: parts[part] ? 'success' : 'secondary', "data-part": part, "data-on": parts[part] ? 'true' : 'false', children: [COMPUTER_WORDS.part[part], ":", ' ', parts[part] ? COMPUTER_WORDS.on : COMPUTER_WORDS.off] }, part))) }), off.length > 0 && off.length < COMPUTER_PARTS.length ? (_jsx(Text, { as: "p", sx: { fontSize: 0, color: 'fg.muted', m: 0 }, children: COMPUTER_WORDS.offSaid(off) })) : null] }));
|
|
24
25
|
}
|
|
25
26
|
function Terminal({ conversation, }) {
|
|
26
27
|
const entries = terminalEntries(conversation);
|
|
27
|
-
return (_jsxs(Box, { "data-testid": "computer-terminal", children: [_jsx(Heading, { as: "h4", sx: { fontSize: 1, mt: 3, mb: 1 }, children: COMPUTER_WORDS.terminal }), entries.length === 0 ? (_jsx(Text, { as: "p", sx: { fontSize: 1, color: 'fg.muted', m: 0 }, children: COMPUTER_WORDS.nothingRan })) : (_jsx(Box, { sx: {
|
|
28
|
-
bg: 'canvas.inset',
|
|
29
|
-
border: '1px solid',
|
|
30
|
-
borderColor: 'border.muted',
|
|
31
|
-
borderRadius: 2,
|
|
32
|
-
p: 2,
|
|
33
|
-
maxHeight: 320,
|
|
34
|
-
overflow: 'auto',
|
|
35
|
-
}, children: entries.map((entry, index) => (_jsxs(Box, { sx: { mb: 2 }, children: [_jsx(Text, { as: "p", sx: { ...MONO, fontWeight: 'semibold' }, children: `$ ${entry.tool}${entry.command ? `: ${entry.command}` : ''}` }), entry.output === undefined ? (_jsx(Spinner, { size: "small" })) : (_jsx(Text, { as: "pre", sx: { ...MONO, color: 'fg.muted' }, children: entry.output }))] }, index))) }))] }));
|
|
28
|
+
return (_jsxs(Box, { "data-testid": "computer-terminal", children: [_jsx(Heading, { as: "h4", sx: { fontSize: 1, mt: 3, mb: 1 }, children: COMPUTER_WORDS.terminal }), entries.length === 0 ? (_jsx(Text, { as: "p", sx: { fontSize: 1, color: 'fg.muted', m: 0 }, children: COMPUTER_WORDS.nothingRan })) : (_jsx(Box, { bg: "canvas.inset", border: "1px solid", borderColor: "border.muted", borderRadius: 2, p: 2, maxHeight: 320, overflow: "auto", children: entries.map((entry, index) => (_jsxs(Box, { mb: 2, children: [_jsx(Text, { as: "p", sx: { ...MONO, fontWeight: 'semibold' }, children: `$ ${entry.tool}${entry.command ? `: ${entry.command}` : ''}` }), entry.output === undefined ? (_jsx(Spinner, { size: "small" })) : (_jsx(Text, { as: "pre", sx: { ...MONO, color: 'fg.muted' }, children: entry.output }))] }, index))) }))] }));
|
|
36
29
|
}
|
|
37
30
|
function save(blob, name) {
|
|
38
31
|
const url = URL.createObjectURL(blob);
|
|
@@ -70,15 +63,7 @@ function Files({ context, state, ended, }) {
|
|
|
70
63
|
state.started,
|
|
71
64
|
ended,
|
|
72
65
|
]);
|
|
73
|
-
return (_jsxs(Box, { "data-testid": "computer-files", children: [_jsxs(Heading, { as: "h4", sx: { fontSize: 1, mt: 3, mb: 1 }, children: [COMPUTER_WORDS.files, path !== '.' ? (_jsx(Text, { sx: { fontWeight: 'normal', color: 'fg.muted' }, children: ` · ${path}` })) : null] }), !state.started ? (_jsx(Text, { as: "p", sx: { fontSize: 1, color: 'fg.muted', m: 0 }, children: COMPUTER_WORDS.notStarted })) : error ? (_jsx(Text, { as: "p", sx: { fontSize: 1, color: 'danger.fg', m: 0 }, children: error })) : !entries ? (_jsx(Spinner, { size: "small" })) : (_jsxs(Box, { as: "ul",
|
|
74
|
-
display: 'flex',
|
|
75
|
-
alignItems: 'center',
|
|
76
|
-
gap: 2,
|
|
77
|
-
fontSize: 1,
|
|
78
|
-
py: 1,
|
|
79
|
-
borderTop: '1px solid',
|
|
80
|
-
borderColor: 'border.muted',
|
|
81
|
-
}, children: entry.type === 'directory' ? (_jsx(Button, { size: "small", variant: "invisible", onClick: () => setPath(entry.path), children: `${entry.name}/` })) : (_jsxs(_Fragment, { children: [_jsx(Text, { sx: { flex: 1, fontFamily: MONO_FACE, fontSize: 0 }, children: entry.name }), _jsx(Text, { sx: { color: 'fg.muted', fontSize: 0 }, children: `${entry.size.toLocaleString('en')} bytes` }), _jsx(Button, { size: "small", "aria-label": `${COMPUTER_WORDS.download} ${entry.name}`, onClick: () => {
|
|
66
|
+
return (_jsxs(Box, { "data-testid": "computer-files", children: [_jsxs(Heading, { as: "h4", sx: { fontSize: 1, mt: 3, mb: 1 }, children: [COMPUTER_WORDS.files, path !== '.' ? (_jsx(Text, { sx: { fontWeight: 'normal', color: 'fg.muted' }, children: ` · ${path}` })) : null] }), !state.started ? (_jsx(Text, { as: "p", sx: { fontSize: 1, color: 'fg.muted', m: 0 }, children: COMPUTER_WORDS.notStarted })) : error ? (_jsx(Text, { as: "p", sx: { fontSize: 1, color: 'danger.fg', m: 0 }, children: error })) : !entries ? (_jsx(Spinner, { size: "small" })) : (_jsxs(Box, { as: "ul", listStyle: "none", p: 0, m: 0, children: [path !== '.' ? (_jsx(Box, { as: "li", children: _jsx(Button, { size: "small", variant: "invisible", onClick: () => setPath(parentOf(path)), children: COMPUTER_WORDS.up }) })) : null, entries.length === 0 ? (_jsx(Text, { as: "p", sx: { fontSize: 1, color: 'fg.muted', m: 0 }, children: COMPUTER_WORDS.emptyDirectory })) : null, entries.map(entry => (_jsx(Box, { as: "li", "data-path": entry.path, display: "flex", alignItems: "center", gap: 2, fontSize: 1, py: 1, borderTop: "1px solid", borderColor: "border.muted", children: entry.type === 'directory' ? (_jsx(Button, { size: "small", variant: "invisible", onClick: () => setPath(entry.path), children: `${entry.name}/` })) : (_jsxs(_Fragment, { children: [_jsx(Text, { sx: { flex: 1, fontFamily: MONO_FACE, fontSize: 0 }, children: entry.name }), _jsx(Text, { sx: { color: 'fg.muted', fontSize: 0 }, children: `${entry.size.toLocaleString('en')} bytes` }), _jsx(Button, { size: "small", "aria-label": `${COMPUTER_WORDS.download} ${entry.name}`, onClick: () => {
|
|
82
67
|
downloadComputerFile(context, entry.path).then(blob => save(blob, entry.name), (failed) => setError(failed instanceof Error
|
|
83
68
|
? failed.message
|
|
84
69
|
: String(failed)));
|
|
@@ -109,7 +94,7 @@ function YourTerminal({ context }) {
|
|
|
109
94
|
setRunning(false);
|
|
110
95
|
});
|
|
111
96
|
};
|
|
112
|
-
return (_jsxs(Box, { "data-testid": "computer-your-terminal",
|
|
97
|
+
return (_jsxs(Box, { "data-testid": "computer-your-terminal", mt: 2, children: [outputs.map((each, index) => (_jsxs(Box, { mb: 2, children: [_jsx(Text, { as: "p", sx: { ...MONO, fontWeight: 'semibold' }, children: `>>> ${each.code}` }), _jsx(Text, { as: "pre", sx: { ...MONO, color: 'fg.muted' }, children: [each.output.stdout, each.output.stderr, each.output.error]
|
|
113
98
|
.filter(Boolean)
|
|
114
99
|
.join('\n') })] }, index))), _jsx(Textarea, { "aria-label": COMPUTER_WORDS.yourCode, placeholder: COMPUTER_WORDS.yourCode, value: code, onChange: event => setCode(event.target.value), sx: { width: '100%', fontFamily: MONO_FACE }, rows: 3 }), _jsx(Button, { size: "small", sx: { mt: 1 }, disabled: running || !code.trim(), onClick: run, children: COMPUTER_WORDS.run })] }));
|
|
115
100
|
}
|
|
@@ -125,9 +110,23 @@ export function AppComputer({ app, workspace, }) {
|
|
|
125
110
|
setEnded(turn.id);
|
|
126
111
|
}
|
|
127
112
|
}, [settled, turn.id]);
|
|
128
|
-
const
|
|
113
|
+
const chatText = useChatWords();
|
|
114
|
+
/*
|
|
115
|
+
* The runtime its agent is on, or nothing while none is assigned: then the
|
|
116
|
+
* computer is asked nothing and says why, rather than asking the host's
|
|
117
|
+
* server (on a hosted page, the page's own origin). Outside a workspace
|
|
118
|
+
* there is none either.
|
|
119
|
+
*/
|
|
120
|
+
const serverUrl = workspace
|
|
121
|
+
? agentServerOf(workspace.sandbox, workspace.serverUrl)
|
|
122
|
+
: undefined;
|
|
123
|
+
const noRuntime = serverUrl === undefined
|
|
124
|
+
? noRuntimeSaid(workspace?.sandbox ?? IDLE_SANDBOX_SNAPSHOT, chatText)
|
|
125
|
+
: undefined;
|
|
129
126
|
const agentId = workspace?.agentId || app.id;
|
|
130
|
-
const context = useMemo(() =>
|
|
127
|
+
const context = useMemo(() => serverUrl === undefined
|
|
128
|
+
? undefined
|
|
129
|
+
: { serverUrl, agentId, token: token || undefined }, [serverUrl, agentId, token]);
|
|
131
130
|
const parts = computerParts(app);
|
|
132
131
|
const [state, setState] = useState();
|
|
133
132
|
const [error, setError] = useState('');
|
|
@@ -141,6 +140,9 @@ export function AppComputer({ app, workspace, }) {
|
|
|
141
140
|
};
|
|
142
141
|
}, []);
|
|
143
142
|
const read = useCallback(() => {
|
|
143
|
+
if (!context) {
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
144
146
|
readComputer(context).then(found => {
|
|
145
147
|
if (alive.current) {
|
|
146
148
|
setState(found);
|
|
@@ -151,11 +153,14 @@ export function AppComputer({ app, workspace, }) {
|
|
|
151
153
|
}, [context]);
|
|
152
154
|
const used = hasComputer(parts);
|
|
153
155
|
useEffect(() => {
|
|
154
|
-
if (used &&
|
|
156
|
+
if (used && context) {
|
|
155
157
|
read();
|
|
156
158
|
}
|
|
157
|
-
}, [used,
|
|
159
|
+
}, [used, context, read, ended]);
|
|
158
160
|
const act = (step) => {
|
|
161
|
+
if (!context) {
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
159
164
|
setBusy(true);
|
|
160
165
|
step(context).then(() => {
|
|
161
166
|
if (alive.current) {
|
|
@@ -170,10 +175,10 @@ export function AppComputer({ app, workspace, }) {
|
|
|
170
175
|
});
|
|
171
176
|
};
|
|
172
177
|
const me = Boolean(state?.yours);
|
|
173
|
-
return (_jsxs(Box, { "data-testid": "app-computer", children: [_jsx(Heading, { as: "h3", sx: { fontSize: 2, mb: 2 }, children: COMPUTER_WORDS.title }), _jsx(Parts, { app: app }), !used ? (_jsx(Text, { as: "p", sx: { fontSize: 1, color: 'fg.muted', m: 0, mt: 1 }, children: COMPUTER_WORDS.none })) : (_jsxs(_Fragment, { children: [_jsx(Text, { as: "p", sx: { fontSize: 0, color: 'fg.muted', m: 0, mt: 1 }, children: COMPUTER_WORDS.noBrowser }),
|
|
178
|
+
return (_jsxs(Box, { "data-testid": "app-computer", children: [_jsx(Heading, { as: "h3", sx: { fontSize: 2, mb: 2 }, children: COMPUTER_WORDS.title }), _jsx(Parts, { app: app }), !used ? (_jsx(Text, { as: "p", sx: { fontSize: 1, color: 'fg.muted', m: 0, mt: 1 }, children: COMPUTER_WORDS.none })) : (_jsxs(_Fragment, { children: [_jsx(Text, { as: "p", sx: { fontSize: 0, color: 'fg.muted', m: 0, mt: 1 }, children: COMPUTER_WORDS.noBrowser }), noRuntime ? (_jsx(Text, { as: "p", role: "status", sx: { fontSize: 1, color: 'fg.default', m: 0, mt: 2 }, children: noRuntime })) : null, error ? (_jsx(Text, { as: "p", sx: { fontSize: 1, color: 'danger.fg', m: 0, mt: 2 }, children: error })) : null, state && context ? (_jsxs(Box, { mt: 2, "data-testid": "computer-holder", children: [_jsx(Text, { as: "p", sx: { fontSize: 1, m: 0, mb: 1 }, children: !state.held
|
|
174
179
|
? COMPUTER_WORDS.agentHas
|
|
175
180
|
: me
|
|
176
181
|
? COMPUTER_WORDS.youHave
|
|
177
|
-
: COMPUTER_WORDS.someoneHas }), !state.held ? (_jsx(Button, { size: "small", disabled: busy, onClick: () => act(takeOverComputer), children: COMPUTER_WORDS.takeOver })) : me ? (_jsxs(_Fragment, { children: [_jsx(Button, { size: "small", variant: "primary", disabled: busy, onClick: () => act(handBackComputer), children: COMPUTER_WORDS.handBack }), _jsx(YourTerminal, { context: context })] })) : null] })) : null, _jsx(Terminal, { conversation: conversation }), state ? (_jsx(Files, { context: context, state: state, ended: ended })) : null] }))] }));
|
|
182
|
+
: COMPUTER_WORDS.someoneHas }), !state.held ? (_jsx(Button, { size: "small", disabled: busy, onClick: () => act(takeOverComputer), children: COMPUTER_WORDS.takeOver })) : me ? (_jsxs(_Fragment, { children: [_jsx(Button, { size: "small", variant: "primary", disabled: busy, onClick: () => act(handBackComputer), children: COMPUTER_WORDS.handBack }), _jsx(YourTerminal, { context: context })] })) : null] })) : null, _jsx(Terminal, { conversation: conversation }), state && context ? (_jsx(Files, { context: context, state: state, ended: ended })) : null] }))] }));
|
|
178
183
|
}
|
|
179
184
|
export default AppComputer;
|
|
@@ -36,13 +36,7 @@ function ElementBody({ element, send, }) {
|
|
|
36
36
|
, { messages: parsed.messages, onAction: onAction, catalog: catalog }, JSON.stringify(element.shows)));
|
|
37
37
|
}
|
|
38
38
|
function ElementHeader({ element }) {
|
|
39
|
-
return (_jsxs(Box, { sx: {
|
|
40
|
-
display: 'flex',
|
|
41
|
-
alignItems: 'center',
|
|
42
|
-
justifyContent: 'space-between',
|
|
43
|
-
gap: 2,
|
|
44
|
-
mb: 2,
|
|
45
|
-
}, children: [_jsx(Text, { as: "h2", sx: { fontSize: 2, fontWeight: 'bold', m: 0 }, children: element.title }), _jsx(IconButton, { icon: XIcon, variant: "invisible", size: "small", "aria-label": `Close ${element.title}`, onClick: () => closeLoopElement(element.id) })] }));
|
|
39
|
+
return (_jsxs(Box, { display: "flex", alignItems: "center", justifyContent: "space-between", gap: 2, mb: 2, children: [_jsx(Text, { as: "h2", sx: { fontSize: 2, fontWeight: 'bold', m: 0 }, children: element.title }), _jsx(IconButton, { icon: XIcon, variant: "invisible", size: "small", "aria-label": `Close ${element.title}`, onClick: () => closeLoopElement(element.id) })] }));
|
|
46
40
|
}
|
|
47
41
|
/** Every element open in a side panel or on a page, drawn where it belongs. */
|
|
48
42
|
export function AppElements({ workspace, }) {
|
|
@@ -51,29 +45,6 @@ export function AppElements({ workspace, }) {
|
|
|
51
45
|
const send = workspace?.viewControls.send;
|
|
52
46
|
if (panels.length === 0 && page === null)
|
|
53
47
|
return null;
|
|
54
|
-
return (_jsxs(_Fragment, { children: [panels.length > 0 ? (_jsx(Box, { as: "aside", "aria-label": "Side panel",
|
|
55
|
-
position: 'absolute',
|
|
56
|
-
top: 0,
|
|
57
|
-
right: 0,
|
|
58
|
-
bottom: 0,
|
|
59
|
-
width: `min(${APP_PANEL_WIDTH}px, 100%)`,
|
|
60
|
-
zIndex: 1,
|
|
61
|
-
overflowY: 'auto',
|
|
62
|
-
borderLeft: '1px solid',
|
|
63
|
-
borderColor: 'border.default',
|
|
64
|
-
bg: 'canvas.subtle',
|
|
65
|
-
boxShadow: 'shadow.medium',
|
|
66
|
-
p: 3,
|
|
67
|
-
display: 'flex',
|
|
68
|
-
flexDirection: 'column',
|
|
69
|
-
gap: 3,
|
|
70
|
-
}, children: panels.map(element => (_jsxs(Box, { as: "section", "aria-label": element.title, children: [_jsx(ElementHeader, { element: element }), _jsx(ElementBody, { element: element, send: send })] }, element.id))) })) : null, page !== null ? (_jsxs(Box, { role: "dialog", "aria-label": page.title, sx: {
|
|
71
|
-
position: 'absolute',
|
|
72
|
-
inset: 0,
|
|
73
|
-
zIndex: 2,
|
|
74
|
-
overflowY: 'auto',
|
|
75
|
-
bg: 'canvas.default',
|
|
76
|
-
p: [3, 4],
|
|
77
|
-
}, children: [_jsx(ElementHeader, { element: page }), _jsx(ElementBody, { element: page, send: send })] })) : null] }));
|
|
48
|
+
return (_jsxs(_Fragment, { children: [panels.length > 0 ? (_jsx(Box, { as: "aside", "aria-label": "Side panel", position: "absolute", top: 0, right: 0, bottom: 0, width: `min(${APP_PANEL_WIDTH}px, 100%)`, zIndex: 1, overflowY: "auto", borderLeft: "1px solid", borderColor: "border.default", bg: "canvas.subtle", boxShadow: "shadow.medium", p: 3, display: "flex", flexDirection: "column", gap: 3, children: panels.map(element => (_jsxs(Box, { as: "section", "aria-label": element.title, children: [_jsx(ElementHeader, { element: element }), _jsx(ElementBody, { element: element, send: send })] }, element.id))) })) : null, page !== null ? (_jsxs(Box, { role: "dialog", "aria-label": page.title, position: "absolute", inset: 0, zIndex: 2, overflowY: "auto", bg: "canvas.default", p: [3, 4], children: [_jsx(ElementHeader, { element: page }), _jsx(ElementBody, { element: page, send: send })] })) : null] }));
|
|
78
49
|
}
|
|
79
50
|
export default AppElements;
|
|
@@ -5,7 +5,8 @@ import { Box } from '@datalayer/primer-addons';
|
|
|
5
5
|
import { signal } from '@datalayer/reactor';
|
|
6
6
|
import { useContributions, useSignalValue } from '@datalayer/reactor/react';
|
|
7
7
|
import { catalogOfBlocks } from '../../../components/a2ui';
|
|
8
|
-
import {
|
|
8
|
+
import { useChatWords } from '../../../chat/ChatLanguage';
|
|
9
|
+
import { LoopCanvasBlock, LoopChatTurn, agentServerOf, noRuntimeSaid, } from '../../core';
|
|
9
10
|
import { InlineSurface, SURFACE_CATALOG_ID, } from '../a2ui-surface/InlineSurface';
|
|
10
11
|
import { useOwnComponents } from '../a2ui-surface/ownComponents';
|
|
11
12
|
import { appPageAction, appPageData, appPageMessages, pageInputsOf, pageOf, } from './appPageModel';
|
|
@@ -73,12 +74,25 @@ export function AppPage({ app, workspace }) {
|
|
|
73
74
|
...outputsData(outputs),
|
|
74
75
|
}), [app, turn, conversation, outputs]);
|
|
75
76
|
const token = useIAMStore(state => state.token) ?? '';
|
|
76
|
-
const
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
77
|
+
const chatText = useChatWords();
|
|
78
|
+
/*
|
|
79
|
+
* Where its page runs: the runtime its agent is on, or nothing while none
|
|
80
|
+
* is assigned — then a run is not sent and the page says why, rather than
|
|
81
|
+
* reaching for the host's server (on a hosted page, the page's own origin).
|
|
82
|
+
*/
|
|
83
|
+
const pageServer = agentServerOf(workspace.sandbox, workspace.serverUrl);
|
|
84
|
+
const pageContext = useRef(null);
|
|
85
|
+
pageContext.current =
|
|
86
|
+
pageServer === undefined
|
|
87
|
+
? null
|
|
88
|
+
: {
|
|
89
|
+
serverUrl: pageServer,
|
|
90
|
+
agentId: workspace.agentId || app.id,
|
|
91
|
+
token: token || undefined,
|
|
92
|
+
};
|
|
93
|
+
const noRuntime = useRef('');
|
|
94
|
+
noRuntime.current =
|
|
95
|
+
pageServer === undefined ? noRuntimeSaid(workspace.sandbox, chatText) : '';
|
|
82
96
|
const pageSession = useRef(null);
|
|
83
97
|
const pageRunning = useRef(false);
|
|
84
98
|
const pageNext = useRef(null);
|
|
@@ -96,6 +110,10 @@ export function AppPage({ app, workspace }) {
|
|
|
96
110
|
const next = pageNext.current;
|
|
97
111
|
pageNext.current = null;
|
|
98
112
|
const context = pageContext.current;
|
|
113
|
+
if (!context) {
|
|
114
|
+
setRefusal(noRuntime.current);
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
99
117
|
try {
|
|
100
118
|
pageSession.current ??= openPageSession(context);
|
|
101
119
|
const turn = await runPageIn(context, await pageSession.current, next);
|
|
@@ -201,7 +219,7 @@ export function AppPage({ app, workspace }) {
|
|
|
201
219
|
}
|
|
202
220
|
}
|
|
203
221
|
}, [app, runPage]);
|
|
204
|
-
return (_jsx(Box, { "data-testid": "app-page",
|
|
222
|
+
return (_jsx(Box, { "data-testid": "app-page", height: "100%", minHeight: 0, overflow: "auto", p: 3, children: 'problem' in drawing ? (_jsx(Box, { role: "status", color: "fg.muted", fontSize: 1, children: drawing.problem })) : (_jsx(InlineSurface
|
|
205
223
|
// A new list of blocks is a new surface, drawn with it.
|
|
206
224
|
, { messages: messages, data: data, onAction: onAction, validationError: refusal, catalog: drawing.catalog, ...(page ? { onSurface } : {}) }, drawnWith)) }));
|
|
207
225
|
}
|