@datalayer/agent-runtimes 1.3.89 → 1.3.90
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/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/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/AppRenderer.d.ts +4 -3
- package/lib/loop/apps/AppRenderer.js +11 -12
- package/lib/loop/apps/appspec.js +6 -3
- 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 +5 -21
- package/lib/loop/plugins/app-elements/AppElements.js +2 -31
- package/lib/loop/plugins/app-page/AppPage.js +1 -1
- 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 +40 -106
- 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
|
@@ -13,50 +13,16 @@ export function WindowFrame({ children, title, height, slotProps = {}, }) {
|
|
|
13
13
|
* actions and fills them in when the workspace registers one.
|
|
14
14
|
*/
|
|
15
15
|
const actions = useOptionalSlotComponents(WINDOW_ACTIONS_SLOT);
|
|
16
|
-
return (_jsxs(Box, {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
borderColor: 'border.default',
|
|
27
|
-
bg: 'canvas.default',
|
|
28
|
-
// Lifted off the field, so the workspace reads as a thing sitting on
|
|
29
|
-
// the page rather than a hole cut into it.
|
|
30
|
-
boxShadow: '0 24px 60px -28px rgba(0, 0, 0, 0.55)',
|
|
31
|
-
}, children: [_jsxs(Box, { sx: {
|
|
32
|
-
display: 'flex',
|
|
33
|
-
alignItems: 'center',
|
|
34
|
-
gap: 2,
|
|
35
|
-
px: 3,
|
|
36
|
-
py: 2,
|
|
37
|
-
borderBottom: '1px solid',
|
|
38
|
-
borderColor: 'border.default',
|
|
39
|
-
bg: 'canvas.subtle',
|
|
40
|
-
// The bar may be the page's first line of type as well as its
|
|
41
|
-
// chrome, so it takes a second row on a narrow screen rather than
|
|
42
|
-
// shedding its actions off the edge.
|
|
43
|
-
flexWrap: 'wrap',
|
|
44
|
-
rowGap: 2,
|
|
45
|
-
// Never squeezed by the body beside it.
|
|
46
|
-
flex: '0 0 auto',
|
|
47
|
-
}, children: [_jsx(Box, { sx: {
|
|
48
|
-
display: 'flex',
|
|
49
|
-
alignItems: 'center',
|
|
50
|
-
gap: '6px',
|
|
51
|
-
mr: 1,
|
|
52
|
-
flexShrink: 0,
|
|
53
|
-
}, children: _jsx(ReactorSlot, { slot: WINDOW_CONTROLS_SLOT, props: slotProps }) }), _jsx(Box, { sx: { minWidth: 0, flex: '1 1 auto' }, children: title }), actions.length > 0 ? (_jsx(Box, { sx: {
|
|
54
|
-
display: 'flex',
|
|
55
|
-
alignItems: 'center',
|
|
56
|
-
gap: 2,
|
|
57
|
-
flexShrink: 0,
|
|
58
|
-
ml: 'auto',
|
|
59
|
-
}, children: _jsx(ReactorSlot, { slot: WINDOW_ACTIONS_SLOT, props: slotProps }) })) : null] }), _jsx(Box, { sx: height === undefined
|
|
16
|
+
return (_jsxs(Box, { position: "relative", borderRadius: "14px", overflow: "hidden", border: "1px solid", borderColor: "border.default", bg: "canvas.default",
|
|
17
|
+
// Lifted off the field, so the workspace reads as a thing sitting on
|
|
18
|
+
// the page rather than a hole cut into it.
|
|
19
|
+
boxShadow: "0 24px 60px -28px rgba(0, 0, 0, 0.55)", height: height === undefined ? '100%' : undefined, display: height === undefined ? 'flex' : undefined, flexDirection: height === undefined ? 'column' : undefined, children: [_jsxs(Box, { display: "flex", alignItems: "center", gap: 2, px: 3, py: 2, borderBottom: "1px solid", borderColor: "border.default", bg: "canvas.subtle",
|
|
20
|
+
// The bar may be the page's first line of type as well as its
|
|
21
|
+
// chrome, so it takes a second row on a narrow screen rather than
|
|
22
|
+
// shedding its actions off the edge.
|
|
23
|
+
flexWrap: "wrap", rowGap: 2,
|
|
24
|
+
// Never squeezed by the body beside it.
|
|
25
|
+
flex: "0 0 auto", children: [_jsx(Box, { display: "flex", alignItems: "center", gap: "6px", mr: 1, flexShrink: 0, children: _jsx(ReactorSlot, { slot: WINDOW_CONTROLS_SLOT, props: slotProps }) }), _jsx(Box, { minWidth: 0, flex: "1 1 auto", children: title }), actions.length > 0 ? (_jsx(Box, { display: "flex", alignItems: "center", gap: 2, flexShrink: 0, ml: "auto", children: _jsx(ReactorSlot, { slot: WINDOW_ACTIONS_SLOT, props: slotProps }) })) : null] }), _jsx(Box, { sx: height === undefined
|
|
60
26
|
? { flex: '1 1 auto', minHeight: 0 }
|
|
61
27
|
: { height, minHeight: 0 }, children: children })] }));
|
|
62
28
|
}
|
|
@@ -48,7 +48,7 @@ export const WINDOW_FRAME_PLUGIN_NAME = '@datalayer/loop-plugin-window-frame';
|
|
|
48
48
|
* controls can switch this plugin off and fill the slot itself.
|
|
49
49
|
*/
|
|
50
50
|
function WindowControls() {
|
|
51
|
-
return (_jsx(_Fragment, { children: ['danger.emphasis', 'attention.emphasis', 'success.emphasis'].map(token => (_jsx(Box, {
|
|
51
|
+
return (_jsx(_Fragment, { children: ['danger.emphasis', 'attention.emphasis', 'success.emphasis'].map(token => (_jsx(Box, { width: 10, height: 10, borderRadius: "50%", bg: token }, token))) }));
|
|
52
52
|
}
|
|
53
53
|
export const WindowFramePlugin = definePlugin({
|
|
54
54
|
name: WINDOW_FRAME_PLUGIN_NAME,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
3
3
|
import { createPortal } from 'react-dom';
|
|
4
|
-
import { Box } from '@primer
|
|
4
|
+
import { Box } from '@datalayer/primer-addons';
|
|
5
5
|
import { buildReactorFromPlugins, onView, } from '@datalayer/reactor';
|
|
6
6
|
import { ReactorSlot, ReactorViewHost, useContributions, useReactorEvent, useSlotComponents, useReactor, } from '@datalayer/reactor/react';
|
|
7
7
|
import { LoopCommand, LoopSlots, LoopViewType, canOpenView, createPromptChannel, parseCommand, loopSurfaceId, } from '../core';
|
|
@@ -168,82 +168,39 @@ function WorkspaceBody({ serverUrl, agentId: initialAgentId, conversationId, mod
|
|
|
168
168
|
through the context: the plugin needs a DOM node and nothing else, and
|
|
169
169
|
the shell should not have to publish one to be found.
|
|
170
170
|
*/
|
|
171
|
-
, { "data-loop-workspace": "",
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
two lines tall is legible, a compressed one is not.
|
|
204
|
-
*/
|
|
205
|
-
flexWrap: 'wrap',
|
|
206
|
-
gap: 2,
|
|
207
|
-
px: compact ? 2 : 3,
|
|
208
|
-
py: 2,
|
|
209
|
-
borderBottom: '1px solid',
|
|
210
|
-
borderColor: 'border.default',
|
|
211
|
-
flex: '0 0 auto',
|
|
212
|
-
}, children: headerControls })) : null, _jsxs(Box, { sx: { flex: '1 1 auto', minHeight: 0, display: 'flex' }, children: [_jsx(Box, { sx: {
|
|
213
|
-
flex: '1 1 auto',
|
|
214
|
-
minWidth: 0,
|
|
215
|
-
minHeight: 0,
|
|
216
|
-
position: 'relative',
|
|
217
|
-
}, children: _jsx(ReactorViewHost, { point: LoopViewType, active: effectiveViewType, props: { viewType: effectiveViewType, workspace }, fallback: _jsx(Centered, { children: "Loading\u2026" }), empty: _jsx(Centered, { children: "No view is available yet." }), errorFallback: error => (_jsxs(Centered, { children: ["This view failed to load: ", error.message] })) }) }), sidebar.length > 0 && sidebarRail && !compact ? (_jsx(SidebarRail, { components: sidebar, props: { workspace }, width: SIDEBAR_WIDTH })) : sidebar.length > 0 ? (_jsx(Box, { as: "aside", sx: {
|
|
218
|
-
flex: '0 0 auto',
|
|
219
|
-
// Wide enough for a plugin's name, its description and a switch
|
|
220
|
-
// on one line. The panel truncates to the same number, and takes
|
|
221
|
-
// it from `SIDEBAR_WIDTH` so the two cannot drift.
|
|
222
|
-
width: compact ? '100%' : `${SIDEBAR_WIDTH}px`,
|
|
223
|
-
minWidth: 0,
|
|
224
|
-
// On the trailing edge: the work is what a person reads first,
|
|
225
|
-
// and the switches belong beside it rather than in front of it.
|
|
226
|
-
borderLeft: compact ? 'none' : '1px solid',
|
|
227
|
-
borderTop: compact ? '1px solid' : 'none',
|
|
228
|
-
borderColor: 'border.default',
|
|
229
|
-
bg: 'canvas.subtle',
|
|
230
|
-
overflowY: 'auto',
|
|
231
|
-
// The shell's chrome, not the plugins': a contributed panel
|
|
232
|
-
// should not have to guess how far its host keeps things from
|
|
233
|
-
// the edge, and two of them would guess differently.
|
|
234
|
-
px: 3,
|
|
235
|
-
py: 3,
|
|
236
|
-
}, children: _jsx(ReactorSlot, { slot: LoopSlots.sidebar, props: { workspace } }) })) : null] }), _jsxs(Box, { sx: { flex: '0 0 auto' }, children: [_jsx(ReactorSlot, { slot: LoopSlots.footer, props: { workspace } }), _jsx(ReactorSlot, { slot: LoopSlots.status, props: { workspace } })] }), _jsx(ReactorSlot, { slot: LoopSlots.root, props: { workspace } })] }));
|
|
171
|
+
, { "data-loop-workspace": "", display: "flex", flexDirection: "column", height: "100%", minHeight: 0,
|
|
172
|
+
// The containing block for anything in the root slot that positions
|
|
173
|
+
// itself absolutely — the floating prompt does. Without this it would
|
|
174
|
+
// resolve against whatever ancestor happens to be positioned, and
|
|
175
|
+
// float over the host's page instead of over the workspace.
|
|
176
|
+
position: "relative", bg: "canvas.default", color: "fg.default", children: [showHeader && headerContainer
|
|
177
|
+
? createPortal(_jsx(Box, { display: "flex", alignItems: "center", flexWrap: "wrap", gap: 2, children: headerControls }), headerContainer)
|
|
178
|
+
: null, showHeader && headerContainer === undefined ? (_jsx(Box, { as: "header", display: "flex", alignItems: "center",
|
|
179
|
+
// In a column there is no room for a row: the header wraps rather
|
|
180
|
+
// than pushing the model chip off the edge.
|
|
181
|
+
justifyContent: compact ? 'flex-start' : 'space-between',
|
|
182
|
+
/*
|
|
183
|
+
Allowed to wrap at any width.
|
|
184
|
+
|
|
185
|
+
`nowrap` meant the row absorbed whatever a plugin put in it by
|
|
186
|
+
squeezing everything else — a sandbox failure message, a long
|
|
187
|
+
agent name — instead of taking a second line. The controls stayed
|
|
188
|
+
on one row and got narrower, which is the wrong trade: a header
|
|
189
|
+
two lines tall is legible, a compressed one is not.
|
|
190
|
+
*/
|
|
191
|
+
flexWrap: "wrap", gap: 2, px: compact ? 2 : 3, py: 2, borderBottom: "1px solid", borderColor: "border.default", flex: "0 0 auto", children: headerControls })) : null, _jsxs(Box, { flex: "1 1 auto", minHeight: 0, display: "flex", children: [_jsx(Box, { flex: "1 1 auto", minWidth: 0, minHeight: 0, position: "relative", children: _jsx(ReactorViewHost, { point: LoopViewType, active: effectiveViewType, props: { viewType: effectiveViewType, workspace }, fallback: _jsx(Centered, { children: "Loading\u2026" }), empty: _jsx(Centered, { children: "No view is available yet." }), errorFallback: error => (_jsxs(Centered, { children: ["This view failed to load: ", error.message] })) }) }), sidebar.length > 0 && sidebarRail && !compact ? (_jsx(SidebarRail, { components: sidebar, props: { workspace }, width: SIDEBAR_WIDTH })) : sidebar.length > 0 ? (_jsx(Box, { as: "aside", flex: "0 0 auto",
|
|
192
|
+
// Wide enough for a plugin's name, its description and a switch
|
|
193
|
+
// on one line. The panel truncates to the same number, and takes
|
|
194
|
+
// it from `SIDEBAR_WIDTH` so the two cannot drift.
|
|
195
|
+
width: compact ? '100%' : `${SIDEBAR_WIDTH}px`, minWidth: 0,
|
|
196
|
+
// On the trailing edge: the work is what a person reads first,
|
|
197
|
+
// and the switches belong beside it rather than in front of it.
|
|
198
|
+
borderLeft: compact ? 'none' : '1px solid', borderTop: compact ? '1px solid' : 'none', borderColor: "border.default", bg: "canvas.subtle", overflowY: "auto",
|
|
199
|
+
// The shell's chrome, not the plugins': a contributed panel
|
|
200
|
+
// should not have to guess how far its host keeps things from
|
|
201
|
+
// the edge, and two of them would guess differently.
|
|
202
|
+
px: 3, py: 3, children: _jsx(ReactorSlot, { slot: LoopSlots.sidebar, props: { workspace } }) })) : null] }), _jsxs(Box, { flex: "0 0 auto", children: [_jsx(ReactorSlot, { slot: LoopSlots.footer, props: { workspace } }), _jsx(ReactorSlot, { slot: LoopSlots.status, props: { workspace } })] }), _jsx(ReactorSlot, { slot: LoopSlots.root, props: { workspace } })] }));
|
|
237
203
|
}
|
|
238
204
|
function Centered({ children }) {
|
|
239
|
-
return (_jsx(Box, {
|
|
240
|
-
height: '100%',
|
|
241
|
-
display: 'flex',
|
|
242
|
-
alignItems: 'center',
|
|
243
|
-
justifyContent: 'center',
|
|
244
|
-
color: 'fg.muted',
|
|
245
|
-
fontSize: 1,
|
|
246
|
-
px: 3,
|
|
247
|
-
textAlign: 'center',
|
|
248
|
-
}, children: children }));
|
|
205
|
+
return (_jsx(Box, { height: "100%", display: "flex", alignItems: "center", justifyContent: "center", color: "fg.muted", fontSize: 1, px: 3, textAlign: "center", children: children }));
|
|
249
206
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useCallback, useSyncExternalStore } from 'react';
|
|
3
|
-
import { Box
|
|
3
|
+
import { Box } from '@datalayer/primer-addons';
|
|
4
|
+
import { Text } from '@primer/react';
|
|
4
5
|
import { useReactorPlatform } from '@datalayer/reactor/react';
|
|
5
6
|
/** Trim the package scope so the list reads as names rather than paths. */
|
|
6
7
|
function shortName(name) {
|
|
@@ -21,21 +22,9 @@ export function PluginToggles({ locked = [], title = 'Plugins', }) {
|
|
|
21
22
|
reactor.disable(name);
|
|
22
23
|
}
|
|
23
24
|
}, [reactor]);
|
|
24
|
-
return (_jsxs(Box, { sx: {
|
|
25
|
-
p: 3,
|
|
26
|
-
borderBottom: '1px solid',
|
|
27
|
-
borderColor: 'border.default',
|
|
28
|
-
bg: 'canvas.subtle',
|
|
29
|
-
}, children: [_jsx(Text, { sx: { fontSize: 0, fontWeight: 'bold', color: 'fg.muted' }, children: title }), _jsx(Box, { sx: { display: 'flex', flexWrap: 'wrap', gap: 3, mt: 2 }, children: reactor.listPlugins().map(name => {
|
|
25
|
+
return (_jsxs(Box, { p: 3, borderBottom: "1px solid", borderColor: "border.default", bg: "canvas.subtle", children: [_jsx(Text, { sx: { fontSize: 0, fontWeight: 'bold', color: 'fg.muted' }, children: title }), _jsx(Box, { display: "flex", flexWrap: "wrap", gap: 3, mt: 2, children: reactor.listPlugins().map(name => {
|
|
30
26
|
const isLocked = locked.includes(name);
|
|
31
|
-
return (_jsxs(Box, { as: "label",
|
|
32
|
-
display: 'inline-flex',
|
|
33
|
-
alignItems: 'center',
|
|
34
|
-
gap: 1,
|
|
35
|
-
fontSize: 1,
|
|
36
|
-
cursor: isLocked ? 'not-allowed' : 'pointer',
|
|
37
|
-
opacity: isLocked ? 0.6 : 1,
|
|
38
|
-
}, children: [_jsx("input", { type: "checkbox", checked: reactor.isEnabled(name), disabled: isLocked, onChange: event => toggle(name, event.target.checked) }), shortName(name)] }, name));
|
|
27
|
+
return (_jsxs(Box, { as: "label", display: "inline-flex", alignItems: "center", gap: 1, fontSize: 1, cursor: isLocked ? 'not-allowed' : 'pointer', opacity: isLocked ? 0.6 : 1, children: [_jsx("input", { type: "checkbox", checked: reactor.isEnabled(name), disabled: isLocked, onChange: event => toggle(name, event.target.checked) }), shortName(name)] }, name));
|
|
39
28
|
}) })] }));
|
|
40
29
|
}
|
|
41
30
|
export default PluginToggles;
|
|
@@ -23,51 +23,19 @@ export function SidebarRail({ components, props, width, }) {
|
|
|
23
23
|
const [chosen, setChosen] = useState(items[0]?.id ?? null);
|
|
24
24
|
// A panel that left the slot is no longer chosen.
|
|
25
25
|
const open = items.some(item => item.id === chosen) ? chosen : null;
|
|
26
|
-
return (_jsxs(Box, { as: "aside", "data-loop-rail-sidebar": "",
|
|
27
|
-
display: open ? 'block' : 'none',
|
|
28
|
-
width: `${width}px`,
|
|
29
|
-
minWidth: 0,
|
|
30
|
-
borderLeft: 'var(--theme-hairline, 1px) solid',
|
|
31
|
-
borderColor: 'border.default',
|
|
32
|
-
overflowY: 'auto',
|
|
33
|
-
px: 3,
|
|
34
|
-
py: 3,
|
|
35
|
-
}, children: components.map(component => {
|
|
26
|
+
return (_jsxs(Box, { as: "aside", "data-loop-rail-sidebar": "", flex: "0 0 auto", display: "flex", minHeight: 0, children: [_jsx(Box, { "data-loop-rail-panel": open ?? undefined, display: open ? 'block' : 'none', width: `${width}px`, minWidth: 0, borderLeft: "var(--theme-hairline, 1px) solid", borderColor: "border.default", overflowY: "auto", px: 3, py: 3, children: components.map(component => {
|
|
36
27
|
const { Component } = component;
|
|
37
28
|
const shown = component.id === open;
|
|
38
29
|
return (_jsx(Box, { id: `loop-rail-panel-${component.id}`, role: "region", "aria-label": railItemsOf([component])[0].label, hidden: !shown, sx: shown ? paneOpening('right') : undefined, children: _jsx(Component, { ...props }) }, component.id));
|
|
39
|
-
}) }), _jsx(Box, { as: "nav", "aria-label": "Panels",
|
|
40
|
-
width: `${RAIL_WIDTH}px`,
|
|
41
|
-
flex: `0 0 ${RAIL_WIDTH}px`,
|
|
42
|
-
display: 'flex',
|
|
43
|
-
flexDirection: 'column',
|
|
44
|
-
alignItems: 'center',
|
|
45
|
-
gap: 1,
|
|
46
|
-
py: 2,
|
|
47
|
-
borderLeft: 'var(--theme-hairline, 1px) solid',
|
|
48
|
-
borderColor: 'border.default',
|
|
49
|
-
}, children: items.map(item => {
|
|
30
|
+
}) }), _jsx(Box, { as: "nav", "aria-label": "Panels", width: `${RAIL_WIDTH}px`, flex: `0 0 ${RAIL_WIDTH}px`, display: "flex", flexDirection: "column", alignItems: "center", gap: 1, py: 2, borderLeft: "var(--theme-hairline, 1px) solid", borderColor: "border.default", children: items.map(item => {
|
|
50
31
|
const Icon = item.icon;
|
|
51
32
|
const active = item.id === open;
|
|
52
|
-
return (_jsx(Box, { as: "button", type: "button", "data-loop-rail-item": item.id, "aria-label": item.label, title: item.label, "aria-pressed": active, "aria-controls": `loop-rail-panel-${item.id}`, onClick: () => setChosen(railChoiceAfter(open, item.id)),
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
p: 0,
|
|
59
|
-
border: 'none',
|
|
60
|
-
borderRadius: 2,
|
|
61
|
-
cursor: 'pointer',
|
|
62
|
-
// One weight, no colour: the ink, quieter when not chosen.
|
|
63
|
-
color: active ? 'fg.default' : 'fg.muted',
|
|
64
|
-
bg: active ? 'neutral.muted' : 'transparent',
|
|
65
|
-
'&:hover': { color: 'fg.default', bg: 'neutral.subtle' },
|
|
66
|
-
'&:focus-visible': {
|
|
67
|
-
outline: '2px solid',
|
|
68
|
-
outlineColor: 'var(--focus-outlineColor, #0969da)',
|
|
69
|
-
outlineOffset: '1px',
|
|
70
|
-
},
|
|
33
|
+
return (_jsx(Box, { as: "button", type: "button", "data-loop-rail-item": item.id, "aria-label": item.label, title: item.label, "aria-pressed": active, "aria-controls": `loop-rail-panel-${item.id}`, onClick: () => setChosen(railChoiceAfter(open, item.id)), width: 32, height: 32, display: "inline-flex", alignItems: "center", justifyContent: "center", p: 0, border: "none", borderRadius: 2, cursor: "pointer",
|
|
34
|
+
// One weight, no colour: the ink, quieter when not chosen.
|
|
35
|
+
color: active ? 'fg.default' : 'fg.muted', bg: active ? 'neutral.muted' : 'transparent', hover: { color: 'fg.default', bg: 'neutral.subtle' }, focusVisible: {
|
|
36
|
+
outline: '2px solid',
|
|
37
|
+
outlineColor: 'var(--focus-outlineColor, #0969da)',
|
|
38
|
+
outlineOffset: '1px',
|
|
71
39
|
}, children: _jsx(Icon, { size: 16 }) }, item.id));
|
|
72
40
|
}) })] }));
|
|
73
41
|
}
|
|
@@ -1,19 +1,13 @@
|
|
|
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 { Tooltip } from '@primer/react';
|
|
3
4
|
import { canOpenView, } from '../core';
|
|
4
5
|
export function ViewSwitcher({ views, workspace, compact = false, }) {
|
|
5
6
|
// One choice is not a choice.
|
|
6
7
|
if (views.length < 2) {
|
|
7
8
|
return null;
|
|
8
9
|
}
|
|
9
|
-
return (_jsx(Box, { role: "tablist", "aria-label": "Workspace views",
|
|
10
|
-
display: 'inline-flex',
|
|
11
|
-
alignItems: 'center',
|
|
12
|
-
bg: 'neutral.muted',
|
|
13
|
-
borderRadius: '6px',
|
|
14
|
-
p: '2px',
|
|
15
|
-
gap: '1px',
|
|
16
|
-
}, children: views.map(entry => {
|
|
10
|
+
return (_jsx(Box, { role: "tablist", "aria-label": "Workspace views", display: "inline-flex", alignItems: "center", bg: "neutral.muted", borderRadius: "6px", p: "2px", gap: "1px", children: views.map(entry => {
|
|
17
11
|
const view = entry.value;
|
|
18
12
|
const open = canOpenView(view, workspace);
|
|
19
13
|
const active = workspace.activeViewType === view.viewType;
|
|
@@ -24,20 +18,6 @@ export function ViewSwitcher({ views, workspace, compact = false, }) {
|
|
|
24
18
|
const label = open
|
|
25
19
|
? view.title
|
|
26
20
|
: `${view.title} — ${view.unavailableReason?.(workspace) ?? 'unavailable'}`;
|
|
27
|
-
return (_jsx(Tooltip, { text: label, direction: "n", children: _jsxs(Box, { as: "button", role: "tab", "aria-selected": active, "aria-disabled": !open, onClick: () => open && workspace.setActiveViewType(view.viewType),
|
|
28
|
-
display: 'inline-flex',
|
|
29
|
-
alignItems: 'center',
|
|
30
|
-
gap: 1,
|
|
31
|
-
border: 'none',
|
|
32
|
-
borderRadius: '5px',
|
|
33
|
-
px: 2,
|
|
34
|
-
py: '4px',
|
|
35
|
-
fontSize: 0,
|
|
36
|
-
cursor: open ? 'pointer' : 'not-allowed',
|
|
37
|
-
opacity: open ? 1 : 0.5,
|
|
38
|
-
bg: active ? 'canvas.default' : 'transparent',
|
|
39
|
-
color: active ? 'fg.default' : 'fg.muted',
|
|
40
|
-
boxShadow: active ? 'shadow.small' : 'none',
|
|
41
|
-
}, children: [Icon ? _jsx(Icon, { size: 14 }) : null, compact && Icon ? null : view.title] }) }, view.viewType));
|
|
21
|
+
return (_jsx(Tooltip, { text: label, direction: "n", children: _jsxs(Box, { as: "button", role: "tab", "aria-selected": active, "aria-disabled": !open, onClick: () => open && workspace.setActiveViewType(view.viewType), display: "inline-flex", alignItems: "center", gap: 1, border: "none", borderRadius: "5px", px: 2, py: "4px", fontSize: 0, cursor: open ? 'pointer' : 'not-allowed', opacity: open ? 1 : 0.5, bg: active ? 'canvas.default' : 'transparent', color: active ? 'fg.default' : 'fg.muted', boxShadow: active ? 'shadow.small' : 'none', children: [Icon ? _jsx(Icon, { size: 14 }) : null, compact && Icon ? null : view.title] }) }, view.viewType));
|
|
42
22
|
}) }));
|
|
43
23
|
}
|
package/lib/loop-main.js
CHANGED
|
@@ -31,8 +31,7 @@ if (globals['__webpack_public_path__'] === undefined) {
|
|
|
31
31
|
import { StrictMode, useEffect, useState } from 'react';
|
|
32
32
|
import { createRoot } from 'react-dom/client';
|
|
33
33
|
import { QueryClientProvider } from '@tanstack/react-query';
|
|
34
|
-
import { Box } from '@primer
|
|
35
|
-
import { DatalayerThemeProvider, setupPrimerPortals, themeConfigs, useSystemColorMode, useThemeStore, } from '@datalayer/primer-addons';
|
|
34
|
+
import { Box, DatalayerThemeProvider, setupPrimerPortals, themeConfigs, useSystemColorMode, useThemeStore, } from '@datalayer/primer-addons';
|
|
36
35
|
import { configurePlugin } from '@datalayer/reactor';
|
|
37
36
|
import { LoopWorkspace } from './loop/shell/LoopWorkspace';
|
|
38
37
|
import { ChatPlugin } from './loop/plugins/chat';
|
|
@@ -113,7 +112,7 @@ function LoopPage() {
|
|
|
113
112
|
const serverUrl = window.location.origin;
|
|
114
113
|
void resolveSession(serverUrl).then(setSession);
|
|
115
114
|
}, []);
|
|
116
|
-
return (_jsx(DatalayerThemeProvider, { colorMode: resolvedMode, theme: themeConfig.primerTheme, themeStyles: themeConfig.themeStyles, children: _jsx(QueryClientProvider, { client: internalQueryClient, children: _jsx(Box, {
|
|
115
|
+
return (_jsx(DatalayerThemeProvider, { colorMode: resolvedMode, theme: themeConfig.primerTheme, themeStyles: themeConfig.themeStyles, children: _jsx(QueryClientProvider, { client: internalQueryClient, children: _jsx(Box, { height: "100vh", overflow: "hidden", children: session ? (_jsx(LoopWorkspace, { serverUrl: session.serverUrl, agentId: session.agentId, conversationId: session.conversationId, model: session.model, sandbox: session.sandbox, initialViewType: session.view,
|
|
117
116
|
// The notebook and document plugins depend on the sandbox, so
|
|
118
117
|
// the reactor pulls it in; it is named here only to be told which
|
|
119
118
|
// server it talks to.
|
|
@@ -256,52 +256,21 @@ export function McpServerManager({ baseUrl, agentId, enableCodemode = false, sel
|
|
|
256
256
|
}, [selectedServers, onSelectedServersChange]);
|
|
257
257
|
const isLoading = catalogQuery.isLoading;
|
|
258
258
|
const isMutating = enableMutation.isPending || disableMutation.isPending;
|
|
259
|
-
return (_jsxs(Box, { sx: { display:
|
|
260
|
-
|
|
261
|
-
alignItems: 'center',
|
|
262
|
-
justifyContent: 'space-between',
|
|
263
|
-
}, children: [_jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 2 }, children: [_jsx(ToolsIcon, { size: 16 }), _jsx(Text, { sx: { fontWeight: 'semibold' }, children: "MCP Server Management" })] }), _jsx(IconButton, { icon: SyncIcon, "aria-label": "Refresh server lists", size: "small", onClick: handleRefresh, disabled: isLoading || isMutating })] }), error && (_jsx(Flash, { variant: "danger", children: _jsx(Text, { sx: { fontSize: 1 }, children: error }) })), enableCodemode && (_jsx(Flash, { variant: "default", children: _jsxs(Text, { sx: { fontSize: 0 }, children: [_jsx("strong", { children: "Codemode enabled:" }), " Adding or removing MCP servers will regenerate the Codemode tool registry."] }) })), isLoading && (_jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 2, py: 3 }, children: [_jsx(Spinner, { size: "small" }), _jsx(Text, { sx: { color: 'fg.muted' }, children: "Loading MCP servers..." })] })), !isLoading && assignedConfigServers.length > 0 && (_jsxs(Box, { sx: { display: 'flex', flexDirection: 'column', gap: 2 }, children: [_jsxs(Text, { sx: { fontWeight: 'semibold', fontSize: 1 }, children: ["Assigned Configured Servers (", assignedConfigServers.length, ")"] }), _jsx(Text, { sx: { color: 'fg.muted', fontSize: 0 }, children: "These servers are from ~/.datalayer/mcp.json and assigned to this agent." }), _jsx(Box, { sx: { display: 'flex', flexDirection: 'column', gap: 2 }, children: assignedConfigServers.map(server => (_jsx(ServerCard, { server: server, variant: "config", disabled: disabled, isSelected: true, onSelect: onSelectedServersChange ? handleServerSelect : undefined, onRemove: () => handleRemoveServer(server.id, true) }, server.id))) })] })), !isLoading && assignedCatalogServers.length > 0 && (_jsxs(Box, { sx: { display: 'flex', flexDirection: 'column', gap: 2 }, children: [_jsxs(Text, { sx: { fontWeight: 'semibold', fontSize: 1 }, children: ["Assigned Catalog Servers (", assignedCatalogServers.length, ")"] }), _jsx(Box, { sx: { display: 'flex', flexDirection: 'column', gap: 2 }, children: assignedCatalogServers.map(server => (_jsx(ServerCard, { server: server, variant: "active", disabled: disabled || isMutating, isSelected: true, onSelect: onSelectedServersChange ? handleServerSelect : undefined, onRemove: () => handleDisableServer(server.id), isRemoving: disableMutation.isPending &&
|
|
264
|
-
disableMutation.variables === server.id }, server.id))) })] })), !isLoading && (_jsxs(Box, { sx: { display: 'flex', flexDirection: 'column', gap: 2 }, children: [_jsxs(Text, { sx: { fontWeight: 'semibold', fontSize: 1 }, children: ["Available from Catalog (", availableCatalogServers.length, ")"] }), availableCatalogServers.length > 3 && (_jsx(TextInput, { leadingVisual: SearchIcon, placeholder: "Search servers...", value: searchQuery, onChange: e => setSearchQuery(e.target.value), sx: { width: '100%' } })), filteredCatalogServers.length === 0 ? (_jsx(Text, { sx: { color: 'fg.muted', fontSize: 1 }, children: searchQuery
|
|
259
|
+
return (_jsxs(Box, { display: "flex", flexDirection: "column", gap: 4, children: [_jsxs(Box, { display: "flex", alignItems: "center", justifyContent: "space-between", children: [_jsxs(Box, { display: "flex", alignItems: "center", gap: 2, children: [_jsx(ToolsIcon, { size: 16 }), _jsx(Text, { sx: { fontWeight: 'semibold' }, children: "MCP Server Management" })] }), _jsx(IconButton, { icon: SyncIcon, "aria-label": "Refresh server lists", size: "small", onClick: handleRefresh, disabled: isLoading || isMutating })] }), error && (_jsx(Flash, { variant: "danger", children: _jsx(Text, { sx: { fontSize: 1 }, children: error }) })), enableCodemode && (_jsx(Flash, { variant: "default", children: _jsxs(Text, { sx: { fontSize: 0 }, children: [_jsx("strong", { children: "Codemode enabled:" }), " Adding or removing MCP servers will regenerate the Codemode tool registry."] }) })), isLoading && (_jsxs(Box, { display: "flex", alignItems: "center", gap: 2, py: 3, children: [_jsx(Spinner, { size: "small" }), _jsx(Text, { sx: { color: 'fg.muted' }, children: "Loading MCP servers..." })] })), !isLoading && assignedConfigServers.length > 0 && (_jsxs(Box, { display: "flex", flexDirection: "column", gap: 2, children: [_jsxs(Text, { sx: { fontWeight: 'semibold', fontSize: 1 }, children: ["Assigned Configured Servers (", assignedConfigServers.length, ")"] }), _jsx(Text, { sx: { color: 'fg.muted', fontSize: 0 }, children: "These servers are from ~/.datalayer/mcp.json and assigned to this agent." }), _jsx(Box, { display: "flex", flexDirection: "column", gap: 2, children: assignedConfigServers.map(server => (_jsx(ServerCard, { server: server, variant: "config", disabled: disabled, isSelected: true, onSelect: onSelectedServersChange ? handleServerSelect : undefined, onRemove: () => handleRemoveServer(server.id, true) }, server.id))) })] })), !isLoading && assignedCatalogServers.length > 0 && (_jsxs(Box, { display: "flex", flexDirection: "column", gap: 2, children: [_jsxs(Text, { sx: { fontWeight: 'semibold', fontSize: 1 }, children: ["Assigned Catalog Servers (", assignedCatalogServers.length, ")"] }), _jsx(Box, { display: "flex", flexDirection: "column", gap: 2, children: assignedCatalogServers.map(server => (_jsx(ServerCard, { server: server, variant: "active", disabled: disabled || isMutating, isSelected: true, onSelect: onSelectedServersChange ? handleServerSelect : undefined, onRemove: () => handleDisableServer(server.id), isRemoving: disableMutation.isPending &&
|
|
260
|
+
disableMutation.variables === server.id }, server.id))) })] })), !isLoading && (_jsxs(Box, { display: "flex", flexDirection: "column", gap: 2, children: [_jsxs(Text, { sx: { fontWeight: 'semibold', fontSize: 1 }, children: ["Available from Catalog (", availableCatalogServers.length, ")"] }), availableCatalogServers.length > 3 && (_jsx(TextInput, { leadingVisual: SearchIcon, placeholder: "Search servers...", value: searchQuery, onChange: e => setSearchQuery(e.target.value), sx: { width: '100%' } })), filteredCatalogServers.length === 0 ? (_jsx(Text, { sx: { color: 'fg.muted', fontSize: 1 }, children: searchQuery
|
|
265
261
|
? 'No servers match your search.'
|
|
266
|
-
: 'All catalog servers are already enabled.' })) : (_jsx(Box, {
|
|
262
|
+
: 'All catalog servers are already enabled.' })) : (_jsx(Box, { display: "flex", flexDirection: "column", gap: 2, children: filteredCatalogServers.map(server => (_jsx(ServerCard, { server: server, variant: "catalog", disabled: disabled || isMutating, onAdd: () => handleEnableServer(server.id), isAdding: enableMutation.isPending &&
|
|
267
263
|
enableMutation.variables === server.id }, server.id))) }))] }))] }));
|
|
268
264
|
}
|
|
269
265
|
function ServerCard({ server, variant, disabled = false, isSelected = false, onSelect, onAdd, onRemove, isAdding = false, isRemoving = false, }) {
|
|
270
266
|
// Check availability based on isAvailable field from the server
|
|
271
267
|
const isAvailable = server.isAvailable !== false;
|
|
272
268
|
const missingEnvVars = !isAvailable && server.requiredEnvVars && server.requiredEnvVars.length > 0;
|
|
273
|
-
return (_jsxs(Box, {
|
|
274
|
-
display: 'flex',
|
|
275
|
-
alignItems: 'flex-start',
|
|
276
|
-
gap: 2,
|
|
277
|
-
padding: 2,
|
|
278
|
-
borderRadius: 2,
|
|
279
|
-
backgroundColor: 'canvas.subtle',
|
|
280
|
-
border: '1px solid',
|
|
281
|
-
borderColor: isSelected ? 'accent.emphasis' : 'border.default',
|
|
282
|
-
opacity: disabled || !isAvailable ? 0.6 : 1,
|
|
283
|
-
cursor: onSelect && !disabled && isAvailable ? 'pointer' : 'default',
|
|
284
|
-
}, onClick: () => {
|
|
269
|
+
return (_jsxs(Box, { display: "flex", alignItems: "flex-start", gap: 2, padding: 2, borderRadius: 2, backgroundColor: "canvas.subtle", border: "1px solid", borderColor: isSelected ? 'accent.emphasis' : 'border.default', opacity: disabled || !isAvailable ? 0.6 : 1, cursor: onSelect && !disabled && isAvailable ? 'pointer' : 'default', onClick: () => {
|
|
285
270
|
if (onSelect && !disabled && isAvailable) {
|
|
286
271
|
onSelect(server, !isSelected);
|
|
287
272
|
}
|
|
288
|
-
}, children: [_jsx(Box, { sx: {
|
|
289
|
-
display: 'flex',
|
|
290
|
-
alignItems: 'center',
|
|
291
|
-
justifyContent: 'center',
|
|
292
|
-
width: 32,
|
|
293
|
-
height: 32,
|
|
294
|
-
borderRadius: 2,
|
|
295
|
-
backgroundColor: variant === 'config' ? 'attention.subtle' : 'accent.subtle',
|
|
296
|
-
flexShrink: 0,
|
|
297
|
-
}, children: _jsx(ServerIcon, { size: 16 }) }), _jsxs(Box, { sx: { flex: 1, minWidth: 0 }, children: [_jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 2, mb: 1 }, children: [_jsx(Text, { sx: { fontWeight: 'semibold', fontSize: 1 }, children: server.name }), variant === 'active' && (_jsx(Label, { variant: "success", size: "small", children: "Active" })), variant === 'config' && (_jsx(Label, { variant: "attention", size: "small", children: "Config" })), !isAvailable && (_jsx(Label, { variant: "danger", size: "small", children: "Missing env vars" })), isSelected && (_jsxs(Label, { variant: "accent", size: "small", children: [_jsx(CheckIcon, { size: 12 }), " Selected"] }))] }), server.description && (_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted', mb: 1 }, children: server.description })), missingEnvVars && (_jsxs(Box, { sx: {
|
|
298
|
-
fontSize: 0,
|
|
299
|
-
color: 'danger.fg',
|
|
300
|
-
mb: 1,
|
|
301
|
-
p: 1,
|
|
302
|
-
bg: 'danger.subtle',
|
|
303
|
-
borderRadius: 1,
|
|
304
|
-
}, children: [_jsx(Text, { sx: { fontWeight: 'semibold', display: 'block', mb: 1 }, children: "Missing environment variables:" }), server.requiredEnvVars.map(envVar => (_jsx(Text, { as: "code", sx: {
|
|
273
|
+
}, children: [_jsx(Box, { display: "flex", alignItems: "center", justifyContent: "center", width: 32, height: 32, borderRadius: 2, backgroundColor: variant === 'config' ? 'attention.subtle' : 'accent.subtle', flexShrink: 0, children: _jsx(ServerIcon, { size: 16 }) }), _jsxs(Box, { flex: 1, minWidth: 0, children: [_jsxs(Box, { display: "flex", alignItems: "center", gap: 2, mb: 1, children: [_jsx(Text, { sx: { fontWeight: 'semibold', fontSize: 1 }, children: server.name }), variant === 'active' && (_jsx(Label, { variant: "success", size: "small", children: "Active" })), variant === 'config' && (_jsx(Label, { variant: "attention", size: "small", children: "Config" })), !isAvailable && (_jsx(Label, { variant: "danger", size: "small", children: "Missing env vars" })), isSelected && (_jsxs(Label, { variant: "accent", size: "small", children: [_jsx(CheckIcon, { size: 12 }), " Selected"] }))] }), server.description && (_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted', mb: 1 }, children: server.description })), missingEnvVars && (_jsxs(Box, { fontSize: 0, color: "danger.fg", mb: 1, p: 1, bg: "danger.subtle", borderRadius: 1, children: [_jsx(Text, { sx: { fontWeight: 'semibold', display: 'block', mb: 1 }, children: "Missing environment variables:" }), server.requiredEnvVars.map(envVar => (_jsx(Text, { as: "code", sx: {
|
|
305
274
|
display: 'inline-block',
|
|
306
275
|
mr: 1,
|
|
307
276
|
mb: 1,
|
|
@@ -317,7 +286,7 @@ function ServerCard({ server, variant, disabled = false, isSelected = false, onS
|
|
|
317
286
|
overflow: 'hidden',
|
|
318
287
|
textOverflow: 'ellipsis',
|
|
319
288
|
whiteSpace: 'nowrap',
|
|
320
|
-
}, children: ["Tools: ", server.tools.map(t => t.name).join(', ')] })), server.transport && (_jsxs(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: ["Transport: ", server.transport] }))] }), _jsxs(Box, {
|
|
289
|
+
}, children: ["Tools: ", server.tools.map(t => t.name).join(', ')] })), server.transport && (_jsxs(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: ["Transport: ", server.transport] }))] }), _jsxs(Box, { display: "flex", alignItems: "center", gap: 1, flexShrink: 0, children: [variant === 'catalog' && onAdd && (_jsx(Button, { variant: "primary", size: "small", leadingVisual: isAdding ? Spinner : PlusIcon, onClick: e => {
|
|
321
290
|
e.stopPropagation();
|
|
322
291
|
onAdd();
|
|
323
292
|
}, disabled: disabled || !isAvailable || isAdding, children: "Add" })), variant === 'active' && onRemove && (_jsx(Button, { variant: "danger", size: "small", leadingVisual: isRemoving ? Spinner : TrashIcon, onClick: e => {
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What any JavaScript runtime can import from Agent Runtimes: no React, DOM,
|
|
3
|
+
* Jupyter or Node built-in. Re-exports only; the mobile app reaches Agent
|
|
4
|
+
* Runtimes through this entry alone.
|
|
5
|
+
*
|
|
6
|
+
* @module portable
|
|
7
|
+
*/
|
|
8
|
+
export { messageOfApproval, normalizeApproval, whyAsked, type ApprovalArgs, type ApprovalRecord, type MessageAsked, } from '../utils/approvals';
|
|
9
|
+
export { AGUIAdapter, type AGUIAdapterConfig } from '../protocols/AGUIAdapter';
|
|
10
|
+
export { createActivityMessage, createAssistantMessage, createUserMessage, generateMessageId, type ChatMessage, type ChatMessageDelta, type ChatMessageInput, type ChatThread, type ContentPart, type MessageRole, type ToolCallStatus, } from '../types/messages';
|
|
11
|
+
export type { ProtocolAdapterConfig, ProtocolConnectionState, ProtocolEvent, ProtocolEventHandler, } from '../types/protocol';
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2025-2026 Datalayer, Inc.
|
|
3
|
+
* Distributed under the terms of the Modified BSD License.
|
|
4
|
+
*/
|
|
5
|
+
/*
|
|
6
|
+
* Copyright (c) 2026 Datalayer, Inc.
|
|
7
|
+
* Distributed under the terms of the Modified BSD License.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* What any JavaScript runtime can import from Agent Runtimes: no React, DOM,
|
|
11
|
+
* Jupyter or Node built-in. Re-exports only; the mobile app reaches Agent
|
|
12
|
+
* Runtimes through this entry alone.
|
|
13
|
+
*
|
|
14
|
+
* @module portable
|
|
15
|
+
*/
|
|
16
|
+
export { messageOfApproval, normalizeApproval, whyAsked, } from '../utils/approvals';
|
|
17
|
+
// The AG-UI stream client and the messages it builds; a phone passes a
|
|
18
|
+
// streaming `fetch` in the adapter's config.
|
|
19
|
+
export { AGUIAdapter } from '../protocols/AGUIAdapter';
|
|
20
|
+
export { createActivityMessage, createAssistantMessage, createUserMessage, generateMessageId, } from '../types/messages';
|
|
@@ -99,7 +99,7 @@ export class AGUIAdapter extends BaseProtocolAdapter {
|
|
|
99
99
|
// e.g., http://localhost:8765/api/v1/ag-ui/default -> http://localhost:8765/api/v1/ag-ui/terminate
|
|
100
100
|
const baseUrl = new URL(this.aguiConfig.baseUrl);
|
|
101
101
|
const terminateUrl = `${baseUrl.origin}/api/v1/ag-ui/terminate`;
|
|
102
|
-
const response = await
|
|
102
|
+
const response = await this.fetchOf()(terminateUrl, {
|
|
103
103
|
method: 'POST',
|
|
104
104
|
headers: {
|
|
105
105
|
'Content-Type': 'application/json',
|
|
@@ -205,7 +205,7 @@ export class AGUIAdapter extends BaseProtocolAdapter {
|
|
|
205
205
|
console.log('[AGUIAdapter] Sending with identities:', options.identities.map(i => i.provider));
|
|
206
206
|
}
|
|
207
207
|
try {
|
|
208
|
-
const response = await
|
|
208
|
+
const response = await this.fetchOf()(this.aguiConfig.baseUrl, {
|
|
209
209
|
method: 'POST',
|
|
210
210
|
headers: this.buildHeaders({
|
|
211
211
|
Accept: 'text/event-stream',
|
|
@@ -70,6 +70,8 @@ export declare abstract class BaseProtocolAdapter implements ProtocolAdapter {
|
|
|
70
70
|
* Build headers for HTTP requests
|
|
71
71
|
*/
|
|
72
72
|
protected buildHeaders(additionalHeaders?: Record<string, string>): Record<string, string>;
|
|
73
|
+
/** The fetch the caller gave, else the global one; read per call so a test can stub the global. */
|
|
74
|
+
protected fetchOf(): typeof fetch;
|
|
73
75
|
/**
|
|
74
76
|
* Create abort signal with timeout
|
|
75
77
|
*/
|
|
@@ -110,6 +110,10 @@ export class BaseProtocolAdapter {
|
|
|
110
110
|
}
|
|
111
111
|
return { ...headers, ...additionalHeaders };
|
|
112
112
|
}
|
|
113
|
+
/** The fetch the caller gave, else the global one; read per call so a test can stub the global. */
|
|
114
|
+
fetchOf() {
|
|
115
|
+
return this.config.fetch ?? ((input, init) => fetch(input, init));
|
|
116
|
+
}
|
|
113
117
|
/**
|
|
114
118
|
* Create abort signal with timeout
|
|
115
119
|
*/
|
package/lib/specs/apps.js
CHANGED
|
@@ -3515,6 +3515,7 @@ export const APP_SOURCES = {
|
|
|
3515
3515
|
},
|
|
3516
3516
|
],
|
|
3517
3517
|
interface: {
|
|
3518
|
+
accent: 'green',
|
|
3518
3519
|
welcome: "Ask me for a report from the books: open invoices, aged balances, a trial balance or a customer's ledger. I read Odoo; I change nothing.",
|
|
3519
3520
|
starters: [
|
|
3520
3521
|
{
|
|
@@ -3869,6 +3870,7 @@ export const APP_SOURCES = {
|
|
|
3869
3870
|
agent: 'jupyter-data-analyst:0.0.1',
|
|
3870
3871
|
contents: ['The dataset under investigation'],
|
|
3871
3872
|
interface: {
|
|
3873
|
+
accent: 'green',
|
|
3872
3874
|
components: [
|
|
3873
3875
|
'Card',
|
|
3874
3876
|
'Column',
|
|
@@ -4230,6 +4232,7 @@ export const APP_SOURCES = {
|
|
|
4230
4232
|
},
|
|
4231
4233
|
],
|
|
4232
4234
|
interface: {
|
|
4235
|
+
accent: 'green',
|
|
4233
4236
|
welcome: 'I sort your mail and draft the replies. I ask before I send, and I never delete.',
|
|
4234
4237
|
starters: [
|
|
4235
4238
|
{
|
|
@@ -4321,6 +4324,7 @@ export const APP_SOURCES = {
|
|
|
4321
4324
|
'The Models page: how each model is billed (standard or credits) and who hosts it',
|
|
4322
4325
|
],
|
|
4323
4326
|
interface: {
|
|
4327
|
+
accent: 'green',
|
|
4324
4328
|
components: [
|
|
4325
4329
|
'Card',
|
|
4326
4330
|
'Column',
|
|
@@ -5247,6 +5251,7 @@ export const APP_SOURCES = {
|
|
|
5247
5251
|
agent: 'jupyter-data-analyst:0.0.1',
|
|
5248
5252
|
contents: ['The benchmark run: task results, traces, cost and latency'],
|
|
5249
5253
|
interface: {
|
|
5254
|
+
accent: 'green',
|
|
5250
5255
|
components: [
|
|
5251
5256
|
'Card',
|
|
5252
5257
|
'Column',
|
|
@@ -5354,6 +5359,7 @@ export const APP_SOURCES = {
|
|
|
5354
5359
|
agent: 'jupyter-data-analyst:0.0.1',
|
|
5355
5360
|
contents: ['Order history', 'Supplier price lists', 'Delivery records'],
|
|
5356
5361
|
interface: {
|
|
5362
|
+
accent: 'green',
|
|
5357
5363
|
components: [
|
|
5358
5364
|
'Card',
|
|
5359
5365
|
'Column',
|
|
@@ -435,9 +435,16 @@ export const APPSPEC_SCHEMA = {
|
|
|
435
435
|
description: "`chat`, `page` or `split`; the kind's own when unsaid",
|
|
436
436
|
},
|
|
437
437
|
accent: {
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
438
|
+
anyOf: [
|
|
439
|
+
{
|
|
440
|
+
$ref: '#/$defs/Accent',
|
|
441
|
+
},
|
|
442
|
+
{
|
|
443
|
+
type: 'null',
|
|
444
|
+
},
|
|
445
|
+
],
|
|
446
|
+
default: null,
|
|
447
|
+
description: "The application's one colour, over whichever theme it runs in; unsaid, it wears the theme's own colours",
|
|
441
448
|
},
|
|
442
449
|
theme: {
|
|
443
450
|
anyOf: [
|
|
@@ -449,7 +456,7 @@ export const APPSPEC_SCHEMA = {
|
|
|
449
456
|
},
|
|
450
457
|
],
|
|
451
458
|
default: null,
|
|
452
|
-
description: "The theme it runs in by default, at its address, embedded, in the Studio's Preview and as an example: a `variant` and, optionally, a colour `mode`. The person's own when unsaid. Its `accent
|
|
459
|
+
description: "The theme it runs in by default, at its address, embedded, in the Studio's Preview and as an example: a `variant` and, optionally, a colour `mode`. The person's own when unsaid. Its `accent`, when it names one, colours it, whichever theme it is",
|
|
453
460
|
},
|
|
454
461
|
welcome: {
|
|
455
462
|
default: '',
|