@datalayer/agent-runtimes 1.3.10 → 1.3.11

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.
Files changed (56) hide show
  1. package/lib/api/runtimes/environments.d.ts +22 -1
  2. package/lib/api/runtimes/environments.js +31 -0
  3. package/lib/chat/ChatFloating.d.ts +8 -1
  4. package/lib/chat/ChatFloating.js +5 -2
  5. package/lib/chat/display/ButtonGlow.d.ts +9 -0
  6. package/lib/chat/display/ButtonGlow.js +60 -0
  7. package/lib/chat/display/EmptyState.js +4 -1
  8. package/lib/chat/header/ChatHeaderBase.js +4 -56
  9. package/lib/chat/header/ChatViewModeToggle.d.ts +29 -0
  10. package/lib/chat/header/ChatViewModeToggle.js +55 -0
  11. package/lib/chat/index.d.ts +1 -0
  12. package/lib/chat/index.js +1 -0
  13. package/lib/components/code-sandboxes/CodeSandboxLauncher.d.ts +8 -0
  14. package/lib/components/code-sandboxes/CodeSandboxLauncher.js +54 -5
  15. package/lib/components/code-sandboxes/codeSandboxEnvironments.d.ts +12 -1
  16. package/lib/components/code-sandboxes/codeSandboxEnvironments.js +38 -1
  17. package/lib/components/icons/ArtifactIcon.js +2 -1
  18. package/lib/examples/DecksAgent.d.ts +1 -1
  19. package/lib/examples/DecksAgent.js +1 -1
  20. package/lib/loop/core/index.d.ts +11 -2
  21. package/lib/loop/embed/LoopEmbed.js +6 -0
  22. package/lib/loop/plugins/chat/ChatView.js +14 -5
  23. package/lib/loop/plugins/page-layout/index.d.ts +36 -0
  24. package/lib/loop/plugins/page-layout/index.js +87 -7
  25. package/lib/loop/presets.d.ts +14 -0
  26. package/lib/loop/presets.js +3 -1
  27. package/lib/models/Deck.d.ts +14 -0
  28. package/lib/models/Deck.js +5 -0
  29. package/lib/models/Environment.d.ts +117 -0
  30. package/lib/models/ItemType.d.ts +1 -1
  31. package/lib/models/Runtime.d.ts +6 -0
  32. package/lib/models/SpaceItem.d.ts +2 -1
  33. package/lib/models/environments.generated.d.ts +29 -1
  34. package/lib/models/environments.generated.js +1 -1
  35. package/lib/models/index.d.ts +1 -0
  36. package/lib/models/index.js +1 -0
  37. package/lib/protocols/BrowserAgentAdapter.d.ts +9 -1
  38. package/lib/protocols/BrowserAgentAdapter.js +11 -4
  39. package/lib/runtimes/actions.d.ts +5 -0
  40. package/lib/runtimes/actions.js +19 -0
  41. package/lib/specs/agents/agents.d.ts +2 -1
  42. package/lib/specs/agents/agents.js +314 -130
  43. package/lib/specs/frontendTools.d.ts +1 -0
  44. package/lib/specs/frontendTools.js +31 -0
  45. package/lib/specs/mcpServers.js +13 -13
  46. package/lib/specs/models.js +4 -4
  47. package/lib/specs/outputs.js +9 -0
  48. package/lib/specs/skills.js +7 -7
  49. package/lib/specs/teams/teams.js +1 -1
  50. package/lib/types/outputs.d.ts +2 -0
  51. package/package.json +1 -1
  52. package/scripts/codegen/generate_mcp_servers.py +2 -2
  53. package/scripts/codegen/generate_outputs.py +2 -0
  54. package/scripts/codegen/generate_skills.py +2 -2
  55. package/scripts/codegen/__pycache__/compose.cpython-313.pyc +0 -0
  56. package/scripts/codegen/__pycache__/versioning.cpython-313.pyc +0 -0
@@ -5,7 +5,7 @@
5
5
  * Reactor plugin with a Python half of its own, and here it is mounted into
6
6
  * an agent workspace — its list in the sidebar, its view as an editor beside
7
7
  * the conversation, its commands in the palette and in a menu on the
8
- * composer, and its tools in the agent's hands. `worker-decks` writes a deck
8
+ * composer, and its tools in the agent's hands. `example-decks` writes a deck
9
9
  * as data, saves it, opens it, and steps through it while you talk.
10
10
  *
11
11
  * Everything runs in the browser: the agent on the Vercel AI harness, the
@@ -11,7 +11,7 @@ registerDecks(exampleDecks);
11
11
  // Module-level, so the embed builds its reactor once rather than on every
12
12
  // render of this component.
13
13
  const DECK_PLUGINS = [LoopDecksPlugin, DeckViewPlugin];
14
- const DecksAgent = () => (_jsx(ThemedProvider, { children: _jsx(Box, { sx: { height: '100vh', minHeight: 0 }, children: _jsx(LoopEmbed, { target: "browser", agentId: "worker-decks",
14
+ const DecksAgent = () => (_jsx(ThemedProvider, { children: _jsx(Box, { sx: { height: '100vh', minHeight: 0 }, children: _jsx(LoopEmbed, { target: "browser", agentId: "example-decks",
15
15
  /* The deck open beside the chat from the first frame. */
16
16
  defaultEditor: "deck",
17
17
  /* The header carries the editor choice — deck, notebook, document, or
@@ -824,14 +824,23 @@ export type ChatLayoutContribution = {
824
824
  /**
825
825
  * How this layout wants the composer built.
826
826
  *
827
- * `floating-top` is a floating card anchored to the top edge rather than
827
+ * `floating-top` and `floating-bottom` are a floating card anchored to
828
+ * that edge of the layout rather than
828
829
  * the bottom — a command line over the document, sized by the card.
829
830
  * `docked-top` is that same command line standing in the flow instead: the
830
831
  * layout gives it a mount point and the composer fills it, so its width is
831
832
  * the layout's to decide and the page below starts under it rather than
832
833
  * behind it.
833
834
  */
834
- prompt?: 'docked' | 'floating' | 'floating-top' | 'docked-top';
835
+ prompt?: 'docked' | 'floating' | 'floating-top' | 'floating-bottom' | 'docked-top';
836
+ /**
837
+ * The same, live, for a layout whose stance changes while it is on
838
+ * screen — the page layout moves the composer between a floating card
839
+ * and its side panel as the person picks a display mode. Read over
840
+ * `prompt` by the chat view whenever it is given; `prompt` is then only
841
+ * the stance the layout starts in.
842
+ */
843
+ promptStance?: ReadonlySignal<'docked' | 'floating' | 'floating-top' | 'floating-bottom' | 'docked-top'>;
835
844
  };
836
845
  export declare const LoopChatLayout: import("@datalayer/reactor").ContributionPoint<ChatLayoutContribution>;
837
846
  /**
@@ -77,6 +77,12 @@ export function LoopEmbed({ agentId = '', showHeader = false, chatHeaderActions,
77
77
  preset.pageLayoutTurnPanel,
78
78
  preset.pageLayoutTurnPanelFooter,
79
79
  preset.pageLayoutPrompt,
80
+ preset.pageLayoutPromptAnchor,
81
+ // By its fields: a host that writes the size inline hands over a new
82
+ // object every render, and the reactor must not be rebuilt for that.
83
+ preset.pageLayoutSize?.format,
84
+ preset.pageLayoutSize?.width,
85
+ preset.pageLayoutSize?.height,
80
86
  preset.localAgentSpec,
81
87
  preset.floatingPrompt,
82
88
  preset.editorSelector,
@@ -4,6 +4,8 @@ import { Box, IconButton, SegmentedControl, Text, Truncate, } from '@primer/reac
4
4
  import { useColorPalette } from '@datalayer/primer-addons';
5
5
  import { ScreenFullIcon, ScreenNormalIcon } from '@primer/octicons-react';
6
6
  import { signal } from '@datalayer/reactor';
7
+ /* A signal to read when the layout publishes no live stance: the hook needs one. */
8
+ const NO_STANCE = signal(undefined);
7
9
  import { useContributions, useSignalValue, useGate, useReactorPlatform, ReactorLazy, ReactorSlot, useSlotComponents, } from '@datalayer/reactor/react';
8
10
  import { ChatBase } from '../../../chat/base/ChatBase';
9
11
  import { SUGGESTION_CHIP_WIDTH } from '../../../chat/display/EmptyState';
@@ -123,6 +125,11 @@ export default function ChatView({ workspace }) {
123
125
  its own way; first contribution wins. */
124
126
  const layoutEntries = useContributions(LoopChatLayout);
125
127
  const layout = layoutEntries[0]?.value;
128
+ // The composer's stance: live when the layout publishes one (the page
129
+ // layout, moving the composer as the display mode changes), its starting
130
+ // stance otherwise.
131
+ const liveStance = useSignalValue(layout?.promptStance ?? NO_STANCE);
132
+ const promptStance = liveStance ?? layout?.prompt;
126
133
  /* The current turn, kept for whoever shows the conversation without the
127
134
  transcript. The chat plugin contributed the feed at build; this view is
128
135
  its writer — begin on send, the reply as it arrives, end when it stops. */
@@ -1183,13 +1190,14 @@ export default function ChatView({ workspace }) {
1183
1190
  // In a draggable card over the workspace when the host asked for the
1184
1191
  // floating placement; the dragging is the prompt's own feature.
1185
1192
  placement: floatingPrompt ||
1186
- layout?.prompt === 'floating' ||
1187
- layout?.prompt === 'floating-top'
1193
+ promptStance === 'floating' ||
1194
+ promptStance === 'floating-top' ||
1195
+ promptStance === 'floating-bottom'
1188
1196
  ? 'floating'
1189
1197
  : 'docked',
1190
1198
  // Where a floating card starts: the page layout wants it over the top
1191
1199
  // of the sheet, like a document's title bar; everyone else, bottom.
1192
- floatingAnchor: layout?.prompt === 'floating-top' ? 'top' : 'bottom',
1200
+ floatingAnchor: promptStance === 'floating-top' ? 'top' : 'bottom',
1193
1201
  // The agent is working: `isLoading` disables the editor and turns the
1194
1202
  // send button into a stop — the person keeps a way out.
1195
1203
  isLoading: busy,
@@ -1206,8 +1214,9 @@ export default function ChatView({ workspace }) {
1206
1214
  // Both of the page layout's placements are that bar — one floating over
1207
1215
  // the page, one docked above it — so both take the tighter padding.
1208
1216
  padding: topPrompt ||
1209
- layout?.prompt === 'floating-top' ||
1210
- layout?.prompt === 'docked-top'
1217
+ promptStance === 'floating-top' ||
1218
+ promptStance === 'floating-bottom' ||
1219
+ promptStance === 'docked-top'
1211
1220
  ? 2
1212
1221
  : 3,
1213
1222
  promptVariant: 'lexical',
@@ -1,6 +1,9 @@
1
+ import { type PageSize } from '@datalayer/primer-addons/lib/reactor';
2
+ import type { ChatViewMode } from '../../../types/chat';
1
3
  import { type TurnPanelFooter } from './TurnPanel';
2
4
  export { pageLayoutPanelOpen, pageLayoutSheet, openPagePanel as openConversationPanel, } from '@datalayer/primer-addons/lib/reactor';
3
5
  export type { TurnPanelFooter } from './TurnPanel';
6
+ export type { PageSize, PageSizeFormat, } from '@datalayer/primer-addons/lib/reactor';
4
7
  export declare const LOOP_PAGE_LAYOUT_PLUGIN_NAME = "@datalayer/loop-plugin-page-layout";
5
8
  /** What a host may set on the page layout. */
6
9
  export type LoopPageLayoutConfig = {
@@ -22,6 +25,20 @@ export type LoopPageLayoutConfig = {
22
25
  * kept clear for it — the document application's title bar, movable.
23
26
  */
24
27
  prompt: 'docked' | 'floating';
28
+ /**
29
+ * Which edge of the page a floating composer starts at: `top` (the
30
+ * default), where a document's title bar would be, or `bottom`, where a
31
+ * chat's composer waits. Either way it is dragged from there. Only read
32
+ * with a `floating` prompt.
33
+ */
34
+ promptAnchor?: 'top' | 'bottom';
35
+ /**
36
+ * The sheet's size: free (the default) at the layout's reading width, or
37
+ * a paper — `{ format: 'letter' }`, `{ format: 'a4' }` — whose width the
38
+ * sheet takes and whose height it is at least, with a free `width` or
39
+ * `height` over either. Omitted: free.
40
+ */
41
+ pageSize?: PageSize;
25
42
  /**
26
43
  * What the turn panel draws under the reply.
27
44
  *
@@ -31,5 +48,24 @@ export type LoopPageLayoutConfig = {
31
48
  */
32
49
  turnPanelFooter: TurnPanelFooter;
33
50
  };
51
+ /**
52
+ * How the page layout shows the chat, when the composer is the floating
53
+ * card: the card itself over the page (`floating-draggable`, where it
54
+ * starts), or the conversation panel with the composer standing in it —
55
+ * beside the page (`sidebar`), over its right edge at full height
56
+ * (`floating`), or as a window in its corner (`floating-small`). The four
57
+ * modes of the chat header's toggle, which the card carries in its own
58
+ * footer. One signal for the workspace, as `pageLayoutPanelOpen` is: the
59
+ * mode is the person's, not a build's.
60
+ */
61
+ export declare const pageLayoutChatMode: import("@datalayer/reactor").Signal<ChatViewMode>;
62
+ /** Where a mode puts the composer (the band) and the conversation (the panel). */
63
+ export type PageLayoutChatPlacement = {
64
+ bandMode: 'floating' | 'panel';
65
+ panelMode: 'docked' | 'overlay' | 'popup';
66
+ };
67
+ export declare function pageLayoutForChatMode(mode: ChatViewMode): PageLayoutChatPlacement;
68
+ /** Picks a mode: the layout follows, and so does the composer's stance. */
69
+ export declare function setPageLayoutChatMode(mode: ChatViewMode): void;
34
70
  export declare const LoopPageLayoutPlugin: import("@datalayer/reactor").ReactorPlugin<LoopPageLayoutConfig, unknown, unknown>;
35
71
  export default LoopPageLayoutPlugin;
@@ -2,7 +2,8 @@ import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { CommentDiscussionIcon } from '@primer/octicons-react';
3
3
  import { definePlugin, signal } from '@datalayer/reactor';
4
4
  import { useContributions, useSignalValue } from '@datalayer/reactor/react';
5
- import { PageLayout, PagePanelToggle, } from '@datalayer/primer-addons/lib/reactor';
5
+ import { PageLayout, PagePanelToggle, openPagePanel, } from '@datalayer/primer-addons/lib/reactor';
6
+ import { ChatViewModeToggle } from '../../../chat/header/ChatViewModeToggle';
6
7
  import { LoopChatLayout, LoopChatTurn, LoopPromptPanel, LoopSlots, } from '../../core';
7
8
  import { TurnPanel } from './TurnPanel';
8
9
  /*
@@ -14,6 +15,53 @@ export { pageLayoutPanelOpen, pageLayoutSheet, openPagePanel as openConversation
14
15
  export const LOOP_PAGE_LAYOUT_PLUGIN_NAME = '@datalayer/loop-plugin-page-layout';
15
16
  /* A signal to read when no chat contributed a turn: the hook needs one. */
16
17
  const NO_TURN = signal({ id: 0, status: 'idle' });
18
+ /**
19
+ * How the page layout shows the chat, when the composer is the floating
20
+ * card: the card itself over the page (`floating-draggable`, where it
21
+ * starts), or the conversation panel with the composer standing in it —
22
+ * beside the page (`sidebar`), over its right edge at full height
23
+ * (`floating`), or as a window in its corner (`floating-small`). The four
24
+ * modes of the chat header's toggle, which the card carries in its own
25
+ * footer. One signal for the workspace, as `pageLayoutPanelOpen` is: the
26
+ * mode is the person's, not a build's.
27
+ */
28
+ export const pageLayoutChatMode = signal('floating-draggable');
29
+ /** The composer's stance for the chat view, following the mode above. */
30
+ const promptStance = signal('floating-top');
31
+ /*
32
+ * Which edge the card returns to when the mode puts it back over the page:
33
+ * the build's own `promptAnchor`, kept here because the mode is picked
34
+ * through a module-level function, as `pageLayoutChatMode` itself is. One
35
+ * page layout to a page, the assumption that signal already makes.
36
+ */
37
+ let floatingStance = 'floating-top';
38
+ export function pageLayoutForChatMode(mode) {
39
+ switch (mode) {
40
+ case 'sidebar':
41
+ return { bandMode: 'panel', panelMode: 'docked' };
42
+ case 'floating':
43
+ return { bandMode: 'panel', panelMode: 'overlay' };
44
+ case 'floating-small':
45
+ return { bandMode: 'panel', panelMode: 'popup' };
46
+ default:
47
+ return { bandMode: 'floating', panelMode: 'docked' };
48
+ }
49
+ }
50
+ /** Picks a mode: the layout follows, and so does the composer's stance. */
51
+ export function setPageLayoutChatMode(mode) {
52
+ pageLayoutChatMode.value = mode;
53
+ const { bandMode } = pageLayoutForChatMode(mode);
54
+ promptStance.value = bandMode === 'floating' ? floatingStance : 'docked-top';
55
+ // The composer went into the panel: the panel opens to show it.
56
+ if (bandMode === 'panel') {
57
+ openPagePanel();
58
+ }
59
+ }
60
+ /** The toggle in the floating composer's footer. */
61
+ function ChatModeAction() {
62
+ const mode = useSignalValue(pageLayoutChatMode);
63
+ return _jsx(ChatViewModeToggle, { value: mode, onChange: setPageLayoutChatMode });
64
+ }
17
65
  /**
18
66
  * The chat view's parts on the page layout.
19
67
  *
@@ -21,10 +69,16 @@ const NO_TURN = signal({ id: 0, status: 'idle' });
21
69
  * what the agent is doing — the turn's `activity` — is the line at the top
22
70
  * of the sheet, so the change is seen where it happens.
23
71
  */
24
- function LoopPageLayout({ parts, promptMode, }) {
72
+ function LoopPageLayout({ parts, promptMode, pageSize, }) {
25
73
  const turnEntries = useContributions(LoopChatTurn);
26
74
  const turn = useSignalValue(turnEntries[0]?.value.turn ?? NO_TURN);
27
- return (_jsx(PageLayout, { page: parts.editors, hasPage: parts.hasEditor, panel: parts.transcript, band: parts.prompt, chips: parts.chips, picker: parts.picker, transient: parts.transient, activity: turn.activity, bandMode: promptMode }));
75
+ const chatMode = useSignalValue(pageLayoutChatMode);
76
+ // The display modes are the floating card's own; a docked composer stays
77
+ // docked above the page, whatever mode was picked elsewhere.
78
+ const placement = promptMode === 'floating'
79
+ ? pageLayoutForChatMode(chatMode)
80
+ : { bandMode: 'docked', panelMode: 'docked' };
81
+ return (_jsx(PageLayout, { page: parts.editors, hasPage: parts.hasEditor, panel: parts.transcript, band: parts.prompt, chips: parts.chips, picker: parts.picker, transient: parts.transient, activity: turn.activity, bandMode: placement.bandMode, panelMode: placement.panelMode, pageSize: pageSize }));
28
82
  }
29
83
  /** The header button that opens and closes the conversation panel. */
30
84
  function ConversationToggle() {
@@ -32,7 +86,13 @@ function ConversationToggle() {
32
86
  }
33
87
  export const LoopPageLayoutPlugin = definePlugin({
34
88
  name: LOOP_PAGE_LAYOUT_PLUGIN_NAME,
35
- config: { turnPanel: 'below', turnPanelFooter: 'full', prompt: 'docked' },
89
+ config: {
90
+ turnPanel: 'below',
91
+ turnPanelFooter: 'full',
92
+ prompt: 'docked',
93
+ promptAnchor: 'top',
94
+ pageSize: undefined,
95
+ },
36
96
  displayName: 'Page layout',
37
97
  description: 'The editor — or, in the chat view, the conversation — on a centred sheet, the prompt docked above it at the same width or floating over it as a draggable card, the current turn under the prompt, the conversation in a side panel.',
38
98
  octicon: 'file',
@@ -42,15 +102,24 @@ export const LoopPageLayoutPlugin = definePlugin({
42
102
  The layout, contributed per build because the composer's stance is
43
103
  configuration: `docked-top` means the layout owns the composer's width
44
104
  — `PageLayout` gives it a mount point the width of the sheet, so the
45
- prompt and the page read as one column; `floating-top` is the draggable
105
+ prompt and the page read as one column; `floating-top` and
106
+ `floating-bottom` are the draggable
46
107
  card, sized by itself, over a strip of canvas kept clear for it. The
47
108
  component closes over the choice once, per build.
48
109
  */
49
110
  const promptMode = config.prompt;
50
- const ConfiguredLayout = (parts) => (_jsx(LoopPageLayout, { parts: parts, promptMode: promptMode }));
111
+ const pageSize = config.pageSize;
112
+ floatingStance =
113
+ config.promptAnchor === 'bottom' ? 'floating-bottom' : 'floating-top';
114
+ if (promptMode === 'floating') {
115
+ promptStance.value = floatingStance;
116
+ }
117
+ const ConfiguredLayout = (parts) => (_jsx(LoopPageLayout, { parts: parts, promptMode: promptMode, pageSize: pageSize }));
51
118
  ctx.contribute(LoopChatLayout, {
52
119
  id: 'page-layout',
53
- prompt: promptMode === 'floating' ? 'floating-top' : 'docked-top',
120
+ prompt: promptMode === 'floating' ? floatingStance : 'docked-top',
121
+ // Live only for the card: its display modes move the composer.
122
+ promptStance: promptMode === 'floating' ? promptStance : undefined,
54
123
  Component: ConfiguredLayout,
55
124
  }, { id: 'page-layout' });
56
125
  // The turn panel is configuration-dependent, so it is contributed here
@@ -73,6 +142,17 @@ export const LoopPageLayoutPlugin = definePlugin({
73
142
  slot: LoopSlots.header,
74
143
  Component: ConversationToggle,
75
144
  },
145
+ // The display modes, in the floating card's footer — and only
146
+ // there: a docked composer has none to pick.
147
+ ...(promptMode === 'floating'
148
+ ? [
149
+ {
150
+ id: 'page-layout-chat-mode',
151
+ slot: LoopSlots.promptAction,
152
+ Component: ChatModeAction,
153
+ },
154
+ ]
155
+ : []),
76
156
  ],
77
157
  };
78
158
  },
@@ -22,6 +22,7 @@
22
22
  import { type PluginRef } from '@datalayer/reactor';
23
23
  import { type AgentsConfig, type SandboxTarget } from './plugins/agents';
24
24
  import { type ChatPluginConfig } from './plugins/chat';
25
+ import { type PageSize } from './plugins/page-layout';
25
26
  export type LoopPresetOptions = {
26
27
  /** Where the agent runtimes service is. */
27
28
  serverUrl?: string;
@@ -81,6 +82,19 @@ export type LoopPresetOptions = {
81
82
  * as a draggable card over the top of the canvas.
82
83
  */
83
84
  pageLayoutPrompt?: 'docked' | 'floating';
85
+ /**
86
+ * Which edge a floating composer starts at: `top` (the default) or
87
+ * `bottom`. It is dragged from there either way. Only read with
88
+ * `pageLayoutPrompt: 'floating'`.
89
+ */
90
+ pageLayoutPromptAnchor?: 'top' | 'bottom';
91
+ /**
92
+ * The page layout's sheet: free (the default) at its reading width, or a
93
+ * paper — `{ format: 'letter' }`, `{ format: 'a4' }` — whose width it
94
+ * takes and whose height it is at least; a free `width` or `height` over
95
+ * either. Only read with `pageLayout`.
96
+ */
97
+ pageLayoutSize?: PageSize;
84
98
  /**
85
99
  * What the turn panel draws under the reply: the full turn footer
86
100
  * (counters, copy, dismiss — the default), `actions` only, or `none`.
@@ -51,7 +51,7 @@ import { LoopPageLayoutPlugin } from './plugins/page-layout';
51
51
  * be installed or signed into, and the switches a demonstration wants are off.
52
52
  */
53
53
  export function loopPlugins(options = {}) {
54
- const { serverUrl, target = 'browser', defaultEditor = 'notebook', showViewSelector = true, hideChatHeader = false, promptPlacement, autoFocusPrompt = true, fullScreenTopOffset = 0, showAgentVariants = false, agentSummary = true, teamId, teamPicker = true, pageLayout = false, pageLayoutTurnPanel = 'below', pageLayoutPrompt = 'docked', pageLayoutTurnPanelFooter = 'full', localAgent, localAgentSpec, floatingPrompt = false, editorSelector = false, editors = true, graph = false, commandPalette = false, pluginsPanel = false, windowFrame = false, firstPromptHook, } = options;
54
+ const { serverUrl, target = 'browser', defaultEditor = 'notebook', showViewSelector = true, hideChatHeader = false, promptPlacement, autoFocusPrompt = true, fullScreenTopOffset = 0, showAgentVariants = false, agentSummary = true, teamId, teamPicker = true, pageLayout = false, pageLayoutTurnPanel = 'below', pageLayoutPrompt = 'docked', pageLayoutPromptAnchor = 'top', pageLayoutSize, pageLayoutTurnPanelFooter = 'full', localAgent, localAgentSpec, floatingPrompt = false, editorSelector = false, editors = true, graph = false, commandPalette = false, pluginsPanel = false, windowFrame = false, firstPromptHook, } = options;
55
55
  return [
56
56
  // The chat owns the editor beside it, so which one opens is its
57
57
  // configuration rather than the workspace's.
@@ -127,6 +127,8 @@ export function loopPlugins(options = {}) {
127
127
  turnPanel: pageLayoutTurnPanel,
128
128
  turnPanelFooter: pageLayoutTurnPanelFooter,
129
129
  prompt: pageLayoutPrompt,
130
+ promptAnchor: pageLayoutPromptAnchor,
131
+ pageSize: pageLayoutSize,
130
132
  }),
131
133
  ]
132
134
  : []),
@@ -0,0 +1,14 @@
1
+ import { IItem } from './Item';
2
+ /**
3
+ * A deck: a presentation described as data, on the `@datalayer/decks`
4
+ * engine. `spec` is the deck specification the engine renders — the
5
+ * item's content, the way `nbformat` is a notebook's — present when the
6
+ * item was read on its own and absent in a listing.
7
+ */
8
+ export type IBaseDeck = IItem & {
9
+ spec?: any;
10
+ };
11
+ export type IDeck = IBaseDeck & {
12
+ type: 'deck';
13
+ };
14
+ export default IDeck;
@@ -0,0 +1,5 @@
1
+ /*
2
+ * Copyright (c) 2025-2026 Datalayer, Inc.
3
+ * Distributed under the terms of the Modified BSD License.
4
+ */
5
+ export {};
@@ -170,6 +170,12 @@ export interface IDatalayerEnvironment {
170
170
  * from its public page expects to find it.
171
171
  */
172
172
  fromLibrary?: boolean;
173
+ /**
174
+ * How a reader is shown an entry whose launch name is not its name: a
175
+ * Library entry is launched by its environment's uid, and shown as the
176
+ * name its owner gave it, `steps-drill`, rather than that uid (E2-19).
177
+ */
178
+ label?: string;
173
179
  }
174
180
  /**
175
181
  * A refusal, as every registry route answers one (section 10): a code, a
@@ -358,6 +364,27 @@ export interface IEnvironmentConformanceReport {
358
364
  passed: boolean;
359
365
  checks: IEnvironmentConformanceCheck[];
360
366
  }
367
+ /** One step of a build as its workflow ran it (E2-19). */
368
+ export interface IEnvironmentBuildStep {
369
+ name: string;
370
+ status: 'running' | 'succeeded' | 'failed' | 'skipped';
371
+ startedAt?: string;
372
+ finishedAt?: string;
373
+ /** For a failure: its section 10 code. */
374
+ code?: string;
375
+ message?: string;
376
+ /**
377
+ * What the step found, for a page to list rather than leave in the log:
378
+ * `{kind: 'egress_refused', subject: 'github.com'}` for a host the build
379
+ * pool's egress proxy refused.
380
+ */
381
+ findings?: IEnvironmentBuildFinding[];
382
+ }
383
+ /** One finding of a build's step (E2-19): what it found, and what about. */
384
+ export interface IEnvironmentBuildFinding {
385
+ kind: string;
386
+ subject: string;
387
+ }
361
388
  export interface IEnvironmentBuildRecord {
362
389
  uid: string;
363
390
  environmentUid: string;
@@ -367,6 +394,13 @@ export interface IEnvironmentBuildRecord {
367
394
  region: string;
368
395
  /** Counted from 1; a retry is the next attempt. */
369
396
  attempt: number;
397
+ /**
398
+ * What this build is for: `build`, or `resolve` — a build that stops once
399
+ * the version has its lock (PLAN_ENVS.md E1-26). Absent from a Runtimes
400
+ * before that, and from every build recorded before the term existed, each
401
+ * of which is a build.
402
+ */
403
+ kind?: string;
370
404
  /** The request's key, suffixed with the variant and region. */
371
405
  idempotencyKey: string;
372
406
  /** `queued` when created; see `TERMINAL_ENVIRONMENT_BUILD_STATUSES`. */
@@ -379,6 +413,28 @@ export interface IEnvironmentBuildRecord {
379
413
  * report with `passed: false` names the checks that failed and why.
380
414
  */
381
415
  conformanceReport?: IEnvironmentConformanceReport | Record<string, never>;
416
+ /**
417
+ * Whether the retry route takes this build: cancelled, or failed under a
418
+ * code another attempt can pass (section 10). Said by Runtimes with the
419
+ * build, so a page offers Retry only where it would be taken (E2-19).
420
+ * Absent from a Runtimes before 1.0.36.
421
+ */
422
+ retryable?: boolean;
423
+ /**
424
+ * The build's steps as its workflow ran them (E2-19), each kept by its
425
+ * name: `resolve`, `build`, `attest`, `smoke_test`… Absent from a Runtimes
426
+ * before 1.0.37 and from a build nothing reported for.
427
+ */
428
+ steps?: IEnvironmentBuildStep[];
429
+ /**
430
+ * What the build spent (E2-19): its minutes by the daily quota's own rule —
431
+ * from its claim to its end, or to now while it runs — and those minutes at
432
+ * its variant's rate, in credits. `metered` is false where the provider
433
+ * bills the owner's own account (D-8). Absent from a Runtimes before them.
434
+ */
435
+ buildMinutes?: number;
436
+ credits?: number;
437
+ metered?: boolean;
382
438
  cacheHit: boolean;
383
439
  correlationId: string;
384
440
  requestedBy: string;
@@ -481,6 +537,13 @@ export interface IEnvironmentPublicationRecord {
481
537
  publishedAt: string;
482
538
  updatedAt: string;
483
539
  snapshot: IEnvironmentPublicationSnapshot;
540
+ /**
541
+ * What a second of the snapshot's size class costs, priced by Runtimes when
542
+ * the publication is read (E2-15, E2-19): what a launch of it reserves by,
543
+ * since a stranger has no listing entry of it to read a rate from. Absent
544
+ * from a Runtimes before 1.0.35, and `null` for a class nothing prices.
545
+ */
546
+ burningRate?: number | null;
484
547
  /** What a conditional write names in `If-Match`. */
485
548
  etag: string;
486
549
  }
@@ -640,3 +703,57 @@ export interface IEnvironmentBuildLogPage {
640
703
  complete: boolean;
641
704
  }
642
705
  export default IEnvironment;
706
+ /** Section 13's preview limits, per owner. */
707
+ export interface IEnvironmentQuotaLimits {
708
+ concurrentBuilds: number;
709
+ buildMinutesPerDay: number;
710
+ retainedVersions: number;
711
+ storedGib: number;
712
+ }
713
+ /** What an owner stores, and how it was measured. */
714
+ export interface IEnvironmentStoredHoldings {
715
+ gib: number;
716
+ bytes: number;
717
+ source: string;
718
+ meteredArtifacts: number;
719
+ unmeteredArtifacts: number;
720
+ }
721
+ /** What an owner holds against each limit right now. */
722
+ export interface IEnvironmentQuotaHoldings {
723
+ openBuilds: number;
724
+ buildMinutesToday: number;
725
+ retainedVersions: number;
726
+ storage: IEnvironmentStoredHoldings;
727
+ }
728
+ /**
729
+ * An owner's build quotas and holdings, `GET /environment-quotas`: the numbers
730
+ * a `DL_ENV_QUOTA_EXCEEDED` refusal quotes, read before one (E2-19).
731
+ */
732
+ export interface IEnvironmentQuotas {
733
+ ownerType: 'user' | 'organization';
734
+ ownerUid: string;
735
+ limits: IEnvironmentQuotaLimits;
736
+ holdings: IEnvironmentQuotaHoldings;
737
+ }
738
+ /**
739
+ * One sandbox running a version. The caller's own carries its runtime uid,
740
+ * its digest and why it waits, if it does — the scheduler's own words, such
741
+ * as `Unschedulable: 0/6 nodes are available: 4 Insufficient cpu.`; anybody
742
+ * else's only its phase and start, so a page counts it without naming it.
743
+ */
744
+ export interface IEnvironmentVersionSandbox {
745
+ /** `Pending` or `Running`: Kubernetes' phase of the sandbox's pod. */
746
+ phase: string;
747
+ startedAt: string;
748
+ yours: boolean;
749
+ runtimeUid?: string;
750
+ digest?: string;
751
+ waiting?: string;
752
+ /** Credits a second, for the caller's own: what it burns while it runs. */
753
+ burningRate?: number;
754
+ }
755
+ /** `GET /environment-versions/{uid}/sandboxes`. */
756
+ export interface IEnvironmentVersionSandboxes {
757
+ versionUid: string;
758
+ sandboxes: IEnvironmentVersionSandbox[];
759
+ }
@@ -1,2 +1,2 @@
1
- export type IItemType = 'assignment' | 'authoring' | 'cell' | 'content' | 'credits' | 'dataset' | 'datasource' | 'document' | 'documentation' | 'environment' | 'exercise' | 'growth' | 'home' | 'invite' | 'lesson' | 'library' | 'mail' | 'management' | 'notebook' | 'onboarding' | 'organization' | 'page' | 'runtime' | 'runtime-snapshot' | 'settings' | 'share' | 'space' | 'storage' | 'success' | 'support' | 'tag' | 'team' | 'usage' | 'user' | 'undefined';
1
+ export type IItemType = 'assignment' | 'authoring' | 'cell' | 'content' | 'credits' | 'dataset' | 'datasource' | 'deck' | 'document' | 'documentation' | 'environment' | 'exercise' | 'growth' | 'home' | 'invite' | 'lesson' | 'library' | 'mail' | 'management' | 'notebook' | 'onboarding' | 'organization' | 'page' | 'runtime' | 'runtime-snapshot' | 'settings' | 'share' | 'space' | 'storage' | 'success' | 'support' | 'tag' | 'team' | 'usage' | 'user' | 'undefined';
2
2
  export default IItemType;
@@ -97,6 +97,12 @@ export interface IRuntimeRecord {
97
97
  * Runtime credits reservation expiration timestamp
98
98
  */
99
99
  expired_at?: string;
100
+ /**
101
+ * Why the runtime's pod does not run yet, in Kubernetes' own words — the
102
+ * scheduler's `Unschedulable: 0/6 nodes are available: 4 Insufficient
103
+ * cpu.`, or an image that cannot be pulled — or empty once it runs.
104
+ */
105
+ waiting?: string;
100
106
  }
101
107
  /**
102
108
  * Runtime description (UI layer).
@@ -1,9 +1,10 @@
1
1
  import { INotebook } from './Notebook';
2
2
  import { IDocument } from './Document';
3
+ import { IDeck } from './Deck';
3
4
  import { ICell } from './Cell';
4
5
  import { IEnvironment } from './Environment';
5
6
  import { ILesson } from './Lesson';
6
7
  import { IExercise } from './Exercise';
7
8
  import { IAssignment } from './Assignment';
8
- export type ISpaceItem = INotebook | ICell | IEnvironment | ILesson | IExercise | IAssignment | IDocument;
9
+ export type ISpaceItem = INotebook | ICell | IEnvironment | ILesson | IExercise | IAssignment | IDocument | IDeck;
9
10
  export default ISpaceItem;
@@ -1,7 +1,7 @@
1
1
  /** The `$id` of the JSON Schema these types are generated from. */
2
2
  export declare const ENVIRONMENT_SCHEMA_ID = "https://datalayer.io/schemas/environments/v1alpha1/environment.json";
3
3
  /** The sha256 of the schema text these types are generated from. */
4
- export declare const ENVIRONMENT_SCHEMA_SHA256 = "76eb8c80d1e27f7c6519946a6f7022b53a717ff2645d993b34aaa54dea658201";
4
+ export declare const ENVIRONMENT_SCHEMA_SHA256 = "df0f8dc57cd82b8b0a77727071cb9a084a64c099703a8b9747ebe0f0958fe8f0";
5
5
  /** The `apiVersion` an Environment document carries. */
6
6
  export declare const ENVIRONMENT_API_VERSION = "environments.datalayer.io/v1alpha1";
7
7
  /** The `kind` an Environment document carries. */
@@ -25,6 +25,8 @@ export interface BuildSecret {
25
25
  name: string;
26
26
  }
27
27
  export interface BuildSpec {
28
+ dependencyFile?: DependencyFileSpec | null;
29
+ image?: ImageSourceSpec | null;
28
30
  /** Default: `"packages"`. */
29
31
  source?: 'packages' | 'dependencyFile' | 'dockerfile' | 'image';
30
32
  }
@@ -35,12 +37,31 @@ export interface Compatibility {
35
37
  regions?: string[];
36
38
  variants?: VariantSet;
37
39
  }
40
+ /** One immutable file the Environment bakes from an external source. */
41
+ export interface ContentsBuildEntry {
42
+ path: string;
43
+ /** Pattern: `^[0-9a-f]{64}$`. */
44
+ sha256: string;
45
+ /** Minimum: 0. */
46
+ sizeBytes?: number | null;
47
+ source: string;
48
+ }
49
+ /** A `requirements.txt`, a `pyproject.toml` with its `uv.lock`, or a conda `environment.yml` (E3-01, E3-02). */
50
+ export interface DependencyFileSpec {
51
+ /** Default: `""`. */
52
+ content?: string;
53
+ /** Default: `""`. */
54
+ lockContent?: string;
55
+ /** Default: `"requirements"`. */
56
+ sourceFormat?: 'requirements' | 'pyproject' | 'conda';
57
+ }
38
58
  export interface EnvironmentSpec {
39
59
  base: Base;
40
60
  build?: BuildSpec;
41
61
  buildSecrets?: BuildSecret[];
42
62
  commands?: Commands;
43
63
  compatibility?: Compatibility;
64
+ contentsBuild?: ContentsBuildEntry[];
44
65
  /** Default: `"sandbox-contract/v1"`. */
45
66
  contract?: string;
46
67
  env?: Record<string, string>;
@@ -58,6 +79,13 @@ export interface FileEntry {
58
79
  /** Minimum: 0. */
59
80
  sizeBytes?: number | null;
60
81
  }
82
+ /** An existing OCI image, imported as the build's base (E3-04). */
83
+ export interface ImageSourceSpec {
84
+ /** Pattern: `^dlsec_[0-9A-Za-z]+$`. */
85
+ credentialSecretId?: string | null;
86
+ /** Default: `""`. */
87
+ reference?: string;
88
+ }
61
89
  export interface Language {
62
90
  name?: 'python';
63
91
  /** Pattern: `^3\.\d+$`. */
@@ -6,7 +6,7 @@
6
6
  /** The `$id` of the JSON Schema these types are generated from. */
7
7
  export const ENVIRONMENT_SCHEMA_ID = 'https://datalayer.io/schemas/environments/v1alpha1/environment.json';
8
8
  /** The sha256 of the schema text these types are generated from. */
9
- export const ENVIRONMENT_SCHEMA_SHA256 = '76eb8c80d1e27f7c6519946a6f7022b53a717ff2645d993b34aaa54dea658201';
9
+ export const ENVIRONMENT_SCHEMA_SHA256 = 'df0f8dc57cd82b8b0a77727071cb9a084a64c099703a8b9747ebe0f0958fe8f0';
10
10
  /** The `apiVersion` an Environment document carries. */
11
11
  export const ENVIRONMENT_API_VERSION = 'environments.datalayer.io/v1alpha1';
12
12
  /** The `kind` an Environment document carries. */
@@ -6,6 +6,7 @@ export * from './CodeSandboxSnapshot';
6
6
  export * from './CodeSandboxSnapshotDTO';
7
7
  export * from './Content';
8
8
  export * from './Course';
9
+ export * from './Deck';
9
10
  export * from './Document';
10
11
  export * from './Environment';
11
12
  export * from './EnvironmentDTO';