@datalayer/agent-runtimes 1.3.73 → 1.3.75

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 (72) hide show
  1. package/lib/chat/ChatFloating.d.ts +25 -2
  2. package/lib/chat/ChatFloating.js +80 -12
  3. package/lib/chat/assistant/AssistantContextMenu.d.ts +67 -0
  4. package/lib/chat/assistant/AssistantContextMenu.js +68 -0
  5. package/lib/chat/assistant/AssistantStage.d.ts +123 -5
  6. package/lib/chat/assistant/AssistantStage.js +245 -7
  7. package/lib/chat/assistant/BalloonParts.d.ts +15 -1
  8. package/lib/chat/assistant/BalloonParts.js +26 -9
  9. package/lib/chat/assistant/BalloonVisual.d.ts +65 -0
  10. package/lib/chat/assistant/BalloonVisual.js +58 -0
  11. package/lib/chat/assistant/SpeechBalloon.d.ts +68 -2
  12. package/lib/chat/assistant/SpeechBalloon.js +113 -7
  13. package/lib/chat/assistant/state.d.ts +19 -0
  14. package/lib/chat/assistant/state.js +44 -17
  15. package/lib/chat/base/ChatBase.js +51 -1
  16. package/lib/chat/indicators/TypingDots.d.ts +13 -0
  17. package/lib/chat/indicators/TypingDots.js +21 -0
  18. package/lib/chat/messages/ChatMessageList.js +1 -15
  19. package/lib/components/inspector/AgentInspector.d.ts +59 -0
  20. package/lib/components/inspector/AgentInspector.js +220 -0
  21. package/lib/components/inspector/AgentInspectorDialog.d.ts +19 -0
  22. package/lib/components/inspector/AgentInspectorDialog.js +9 -0
  23. package/lib/components/inspector/JsonTree.d.ts +24 -0
  24. package/lib/components/inspector/JsonTree.js +89 -0
  25. package/lib/components/inspector/a2aInspect.d.ts +56 -0
  26. package/lib/components/inspector/a2aInspect.js +478 -0
  27. package/lib/components/inspector/agentInspector.d.ts +179 -0
  28. package/lib/components/inspector/agentInspector.js +267 -0
  29. package/lib/components/inspector/chatInspect.d.ts +38 -0
  30. package/lib/components/inspector/chatInspect.js +65 -0
  31. package/lib/components/inspector/classify.d.ts +19 -0
  32. package/lib/components/inspector/classify.js +42 -0
  33. package/lib/components/inspector/index.d.ts +14 -0
  34. package/lib/components/inspector/index.js +18 -0
  35. package/lib/components/teams/A2ATeamGraph.d.ts +54 -3
  36. package/lib/components/teams/A2ATeamGraph.js +37 -11
  37. package/lib/components/teams/NotebookPreview.d.ts +11 -2
  38. package/lib/components/teams/NotebookPreview.js +6 -3
  39. package/lib/components/teams/NotebookPreviewView.js +9 -1
  40. package/lib/components/teams/TeamNotebook.d.ts +10 -1
  41. package/lib/components/teams/TeamNotebook.js +15 -3
  42. package/lib/components/teams/jupyterThemeVariables.d.ts +9 -0
  43. package/lib/components/teams/jupyterThemeVariables.js +441 -0
  44. package/lib/components/teams/teamConnections.d.ts +9 -1
  45. package/lib/components/teams/teamConnections.js +20 -0
  46. package/lib/components/teams/useA2ATeam.d.ts +17 -4
  47. package/lib/components/teams/useA2ATeam.js +87 -23
  48. package/lib/examples/AgentA2ATeamExample.d.ts +16 -2
  49. package/lib/examples/AgentA2ATeamExample.js +65 -13
  50. package/lib/examples/{ChatAssistantExample.d.ts → AssistantExample.d.ts} +2 -2
  51. package/lib/examples/{ChatAssistantExample.js → AssistantExample.js} +69 -7
  52. package/lib/examples/{ChatAssistantGalleryExample.d.ts → AssistantGalleryExample.d.ts} +2 -2
  53. package/lib/examples/{ChatAssistantGalleryExample.js → AssistantGalleryExample.js} +45 -13
  54. package/lib/examples/example-selector.js +4 -2
  55. package/lib/examples/exampleGroups.d.ts +9 -0
  56. package/lib/examples/exampleGroups.js +56 -0
  57. package/lib/examples/index.d.ts +1 -1
  58. package/lib/examples/index.js +1 -1
  59. package/lib/examples/main.js +3 -43
  60. package/lib/examples/utils/AssistantGalleryGrid.d.ts +6 -1
  61. package/lib/examples/utils/AssistantGalleryGrid.js +16 -3
  62. package/lib/examples/utils/assistantGallery.d.ts +51 -2
  63. package/lib/examples/utils/assistantGallery.js +32 -7
  64. package/lib/loop/apps/AppRenderer.js +1 -1
  65. package/lib/loop/core/index.d.ts +17 -0
  66. package/lib/loop/core/index.js +1 -0
  67. package/lib/loop/plugins/assistant/index.d.ts +1 -1
  68. package/lib/loop/plugins/assistant/index.js +8 -3
  69. package/lib/runtimes/browser/a2aPeer.d.ts +4 -1
  70. package/lib/types/chat.d.ts +7 -0
  71. package/package.json +1 -1
  72. package/scripts/codegen/generate_jupyter_theme_variables.mjs +57 -0
@@ -15,8 +15,9 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
15
15
  * and so are the characters clippy.js publishes, fetched when picked.
16
16
  */
17
17
  import { useEffect, useRef, useState } from 'react';
18
+ import { useAgentInspector } from '../components/inspector/agentInspector';
18
19
  import { buildReactorFromPlugins } from '@datalayer/reactor';
19
- import { Button, Heading, Text } from '@primer/react';
20
+ import { Button, Heading, Text, ToggleSwitch } from '@primer/react';
20
21
  import { Box } from '@datalayer/primer-addons';
21
22
  import { ThemedProvider } from './utils/themedProvider';
22
23
  import { ChatFloating } from '../chat';
@@ -34,6 +35,35 @@ const SERVER = ((typeof window === 'undefined'
34
35
  ? null
35
36
  : new URLSearchParams(window.location.search).get('agentRuntimesUrl')) ||
36
37
  'http://127.0.0.1:8765').replace(/\/+$/, '');
38
+ /** The agent the assistant talks to on that server. */
39
+ const AGENT_ID = 'assistant';
40
+ /**
41
+ * Make sure the server has the assistant's agent: `npm run examples` starts
42
+ * the server with none, so the page creates it from the
43
+ * `example-agentic-chat` spec the first time, over AG-UI, the spec's own
44
+ * protocol.
45
+ */
46
+ async function ensureAssistantAgent() {
47
+ const found = await fetch(`${SERVER}/api/v1/agents/${AGENT_ID}`);
48
+ if (found.ok) {
49
+ return;
50
+ }
51
+ if (found.status !== 404) {
52
+ throw new Error(`The server could not say whether the ${AGENT_ID} agent exists (${found.status}).`);
53
+ }
54
+ const created = await fetch(`${SERVER}/api/v1/agents`, {
55
+ method: 'POST',
56
+ headers: { 'content-type': 'application/json' },
57
+ body: JSON.stringify({
58
+ name: AGENT_ID,
59
+ agent_spec_id: 'example-agentic-chat',
60
+ transport: 'ag-ui',
61
+ }),
62
+ });
63
+ if (!created.ok && created.status !== 409) {
64
+ throw new Error(`The server could not create the ${AGENT_ID} agent (${created.status}).`);
65
+ }
66
+ }
37
67
  /** The plugins this page enables: Datalayer's characters and the owl's. */
38
68
  const reactor = buildReactorFromPlugins([
39
69
  AssistantCharactersPlugin,
@@ -66,15 +96,28 @@ async function readPicked(files) {
66
96
  soundsJs: soundsJs ? await soundsJs.text() : undefined,
67
97
  });
68
98
  }
69
- const ChatAssistantExample = () => {
99
+ const AssistantExample = () => {
70
100
  const [character, setCharacter] = useState('paperclip');
71
101
  // A character chosen by id is the one its plugin contributes.
72
102
  const drawn = typeof character === 'string'
73
103
  ? assistantCharacterNamed(reactor, character)
74
104
  : character;
75
105
  const [loadError, setLoadError] = useState();
106
+ // The agent on the server, made if it is not there yet.
107
+ const [agentReady, setAgentReady] = useState(false);
108
+ const [agentError, setAgentError] = useState();
109
+ useEffect(() => {
110
+ let cancelled = false;
111
+ ensureAssistantAgent().then(() => !cancelled && setAgentReady(true), error => !cancelled &&
112
+ setAgentError(`${error instanceof Error ? error.message : String(error)} The assistant talks to an agent-runtimes server at ${SERVER}.`));
113
+ return () => {
114
+ cancelled = true;
115
+ };
116
+ }, []);
76
117
  // How the balloon shows the conversation (T-23): history, or current.
77
118
  const [balloon, setBalloon] = useState('history');
119
+ // What the agent does, for the menu's *Inspect the agent…*.
120
+ const { sink: inspector } = useAgentInspector();
78
121
  // Pixel, the test sprite, read once through the clippy.js reader.
79
122
  const [pixel, setPixel] = useState();
80
123
  useEffect(() => {
@@ -131,13 +174,15 @@ const ChatAssistantExample = () => {
131
174
  };
132
175
  const isClippyJs = typeof character !== 'string' &&
133
176
  Object.values(clippyJs).includes(character);
134
- return (_jsx(ThemedProvider, { children: _jsxs(Box, { sx: { minHeight: '100vh', bg: 'canvas.default', p: 4 }, children: [_jsxs(Box, { sx: { maxWidth: 720, mx: 'auto' }, children: [_jsx(Heading, { as: "h1", sx: { mb: 2 }, children: "Chat Assistant" }), _jsx(Text, { as: "p", sx: { color: 'fg.muted', mb: 3 }, children: "The chat as a character on the page. It greets you, acts out what the agent is doing, and says the agent\u2019s words in a balloon while the conversation is closed. Click it to talk, drag it to move it, hover it to send it away." }), _jsxs(Box, { sx: { display: 'flex', gap: 2, flexWrap: 'wrap' }, children: [CATALOGUE.map(option => (_jsx(Button, { variant: option.id === character ? 'primary' : 'default', onClick: () => {
177
+ return (_jsx(ThemedProvider, { children: _jsxs(Box, { sx: { minHeight: '100vh', bg: 'canvas.default', p: 4 }, children: [_jsxs(Box, { sx: { maxWidth: 720, mx: 'auto' }, children: [_jsx(Heading, { as: "h1", sx: { mb: 2 }, children: "Assistant" }), _jsx(Text, { as: "p", sx: { color: 'fg.muted', mb: 3 }, children: "The chat as a character on the page. It greets you, acts out what the agent is doing, and says the agent\u2019s words in a balloon while the conversation is closed. Click it to talk, drag it to move it, hover it to send it away." }), _jsxs(Box, { sx: { display: 'flex', gap: 2, flexWrap: 'wrap' }, children: [CATALOGUE.map(option => (_jsx(Button, { variant: option.id === character ? 'primary' : 'default', onClick: () => {
135
178
  setCharacter(option.id);
136
179
  setLoadError(undefined);
137
180
  }, "aria-pressed": option.id === character, "data-assistant-character": option.id, children: option.name }, option.id))), pixel && (_jsxs(Button, { variant: character === pixel ? 'primary' : 'default', onClick: () => {
138
181
  setCharacter(pixel);
139
182
  setLoadError(undefined);
140
- }, "aria-pressed": character === pixel, "data-assistant-character": "sprite", children: [pixel.name, " (sprite)"] }))] }), _jsxs(Box, { as: "section", sx: { mt: 4 }, children: [_jsx(Heading, { as: "h2", sx: { fontSize: 2, mb: 1 }, children: "The balloon" }), _jsxs(Text, { as: "p", sx: { color: 'fg.muted', mb: 2 }, children: [_jsx("strong", { children: "History" }), ": open, the whole conversation, counted in its header, the composer last. ", _jsx("strong", { children: "Current" }), ": only what it says or does now \u2014 the answer as it is written, or the tool it calls (\u201CUsing current_time\u2026\u201D) \u2014 in one compact balloon. Either way, a tool call is said in the balloon."] }), _jsx(Box, { sx: { display: 'flex', gap: 2 }, children: ['history', 'current'].map(option => (_jsx(Button, { variant: option === balloon ? 'primary' : 'default', "aria-pressed": option === balloon, "data-assistant-balloon-choice": option, onClick: () => setBalloon(option), children: option === 'history' ? 'History' : 'Current' }, option))) })] }), _jsxs(Box, { as: "section", sx: { mt: 4 }, children: [_jsx(Heading, { as: "h2", sx: { fontSize: 2, mb: 1 }, children: "The clippy.js characters" }), _jsxs(Text, { as: "p", sx: { color: 'fg.muted', mb: 2 }, children: ["Fetched when picked from the", ' ', _jsxs("code", { children: ["clippyjs@", CLIPPY_JS_VERSION] }), " package on jsDelivr and read as data by the same reader. They are not in this repository: clippy.js\u2019s licence covers its code only, and the characters are Microsoft\u2019s."] }), _jsx(Box, { sx: { display: 'flex', gap: 2, flexWrap: 'wrap' }, children: CLIPPY_JS_CHARACTERS.map(name => {
183
+ }, "aria-pressed": character === pixel, "data-assistant-character": "sprite", children: [pixel.name, " (sprite)"] }))] }), _jsxs(Box, { as: "section", sx: { mt: 4 }, children: [_jsx(Heading, { as: "h2", sx: { fontSize: 2, mb: 1 }, children: "The balloon" }), _jsxs(Text, { as: "p", sx: { color: 'fg.muted', mb: 2 }, children: [_jsx("strong", { children: "History" }), ": the whole conversation, counted in its header \u2014 closed, every message listed and scrolled; open, the composer last. ", _jsx("strong", { children: "Current" }), ": only what it says or does now \u2014 the answer as it is written, or the tool it calls (\u201CUsing current_time\u2026\u201D) \u2014 in one compact balloon. Either way, a tool call is said in the balloon."] }), _jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 2 }, "data-assistant-balloon-toggle": "", children: [_jsx(Text, { id: "assistant-balloon-history", sx: { fontWeight: 'semibold' }, children: "History" }), _jsx(ToggleSwitch, { "aria-labelledby": "assistant-balloon-history", size: "small", checked: balloon === 'history',
184
+ // Controlled, Primer's switch flips only through its click.
185
+ onClick: () => setBalloon(balloon === 'history' ? 'current' : 'history') }), _jsx(Text, { "aria-live": "polite", "data-toggle-state": "", sx: { color: 'fg.muted' }, children: balloon === 'history' ? 'History' : 'Current' })] })] }), _jsxs(Box, { as: "section", sx: { mt: 4 }, children: [_jsx(Heading, { as: "h2", sx: { fontSize: 2, mb: 1 }, children: "The clippy.js characters" }), _jsxs(Text, { as: "p", sx: { color: 'fg.muted', mb: 2 }, children: ["Fetched when picked from the", ' ', _jsxs("code", { children: ["clippyjs@", CLIPPY_JS_VERSION] }), " package on jsDelivr and read as data by the same reader. They are not in this repository: clippy.js\u2019s licence covers its code only, and the characters are Microsoft\u2019s."] }), _jsx(Box, { sx: { display: 'flex', gap: 2, flexWrap: 'wrap' }, children: CLIPPY_JS_CHARACTERS.map(name => {
141
186
  const picked = clippyJs[name] !== undefined && character === clippyJs[name];
142
187
  return (_jsx(Button, { variant: picked ? 'primary' : 'default', onClick: () => void pickClippyJs(name), disabled: fetching !== undefined, "aria-pressed": picked, "data-assistant-character": `clippy-js-${name.toLowerCase()}`, children: fetching === name ? `${name}…` : name }, name));
143
188
  }) })] }), _jsxs(Box, { as: "section", sx: { mt: 4 }, children: [_jsx(Heading, { as: "h2", sx: { fontSize: 2, mb: 1 }, children: "A character you bring" }), _jsxs(Text, { as: "p", sx: { color: 'fg.muted', mb: 2 }, children: ["The characters of Microsoft Office \u2014 Clippy, Merlin, Links and the others \u2014 are Microsoft\u2019s. Load only a character file you have the right to use: a Microsoft Agent ", _jsx("code", { children: ".acs" }), " file, or a clippy.js character\u2019s ", _jsx("code", { children: "agent.js" }), " and map image. It is read in this page and sent nowhere."] }), _jsx("input", { type: "file", multiple: true, accept: ".acs,.js,.png,.gif,.webp,.jpg,.jpeg", "aria-label": "Character files", onChange: async (event) => {
@@ -154,8 +199,25 @@ const ChatAssistantExample = () => {
154
199
  }
155
200
  } }), loadError && (_jsx(Text, { as: "p", role: "alert", sx: { color: 'danger.fg', mt: 2 }, children: loadError })), typeof character !== 'string' &&
156
201
  character !== pixel &&
157
- !isClippyJs && (_jsxs(Text, { as: "p", sx: { mt: 2 }, children: ["Playing ", character.name, "."] }))] })] }), _jsx(ChatFloating, { defaultViewMode: "assistant", assistantCharacter: drawn, balloonDisplay: balloon, protocol: "vercel-ai", endpoint: `${SERVER}/api/v1/vercel-ai/assistant`, title: "Assistant", description: "Hello! Ask me anything about this page.", position: "bottom-right", useStore: false,
202
+ !isClippyJs && (_jsxs(Text, { as: "p", sx: { mt: 2 }, children: ["Playing ", character.name, "."] }))] })] }), agentError && (_jsx(Box, { sx: { maxWidth: 720, mx: 'auto', mt: 3 }, children: _jsx(Text, { as: "p", role: "alert", sx: { color: 'danger.fg' }, children: agentError }) })), agentReady && (_jsx(ChatFloating, { defaultViewMode: "assistant", assistantCharacter: drawn, balloonDisplay: balloon, protocol: "ag-ui", endpoint: `${SERVER}/api/v1/ag-ui/${AGENT_ID}/`, title: "Assistant", description: "Hello! Ask me anything about this page.", position: "bottom-right", useStore: false,
158
203
  // Ask a decision beside the composer: Jev, through this server.
159
- decisions: { serverUrl: SERVER } }, typeof character === 'string' ? character : character.sprite)] }) }));
204
+ decisions: { serverUrl: SERVER },
205
+ // Right-click the character: its menu.
206
+ inspector: inspector, onBalloonDisplayChange: setBalloon, onChangeCharacter: () => document
207
+ .querySelector('[data-assistant-character]')
208
+ ?.focus(), about: {
209
+ name: 'Assistant',
210
+ spec: AGENT_ID,
211
+ where: `on a runtime, ${new URL(SERVER).host}`,
212
+ }, suggestions: [
213
+ {
214
+ title: 'What is on this page?',
215
+ message: 'What is on this page?',
216
+ },
217
+ {
218
+ title: 'Tell me a joke',
219
+ message: 'Tell me a short joke about accountants.',
220
+ },
221
+ ] }, typeof character === 'string' ? character : character.sprite))] }) }));
160
222
  };
161
- export default ChatAssistantExample;
223
+ export default AssistantExample;
@@ -13,5 +13,5 @@
13
13
  * Static data, no agent: it opens without a server or an account.
14
14
  */
15
15
  import React from 'react';
16
- declare const ChatAssistantGalleryExample: React.FC;
17
- export default ChatAssistantGalleryExample;
16
+ declare const AssistantGalleryExample: React.FC;
17
+ export default AssistantGalleryExample;
@@ -18,17 +18,17 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
18
18
  * Static data, no agent: it opens without a server or an account.
19
19
  */
20
20
  import { useEffect, useRef, useState } from 'react';
21
- import { Button, Checkbox, FormControl, Heading, SegmentedControl, Text, } from '@primer/react';
21
+ import { Button, Checkbox, FormControl, Heading, SegmentedControl, Text, ToggleSwitch, } from '@primer/react';
22
22
  import { Box, DatalayerThemeProvider, themeConfigs, } from '@datalayer/primer-addons';
23
23
  import { ThemedProvider } from './utils/themedProvider';
24
24
  import { useExampleThemeStore } from './utils/themeStore';
25
25
  import { AssistantStage } from '../chat/assistant/AssistantStage';
26
26
  import { useViewportDrag } from '../chat/useViewportDrag';
27
- import { AssistantGalleryGrid, GalleryBalloons, GalleryNotebook, GalleryObstacle, Still, useGalleryCharacters, } from './utils/AssistantGalleryGrid';
28
- import { GALLERY_POSES, GALLERY_POSE_LABELS, SAMPLE_NOTEBOOK_SAYING, balloonForPose, sampleApproval, sampleSaying, sampleToolLine, stateOfPose, } from './utils/assistantGallery';
27
+ import { AssistantGalleryGrid, GalleryBalloons, GalleryNotebook, GalleryObstacle, galleryNotebookVisual, Still, useGalleryCharacters, } from './utils/AssistantGalleryGrid';
28
+ import { GALLERY_POSES, GALLERY_POSE_LABELS, SAMPLE_NOTEBOOK_SAYING, balloonForPose, sampleApproval, sampleHistory, sampleSaying, sampleToolLine, stateOfPose, } from './utils/assistantGallery';
29
29
  import { CLIPPY_JS_VERSION, useClippyJsCharacters, } from './utils/clippyJsCharacters';
30
30
  const STAGE_SIZE = 96;
31
- const PANEL_HEIGHT = 520;
31
+ const PANEL_HEIGHT = 640;
32
32
  const LEAVE_MS = 700;
33
33
  const ARRIVE_MS = 1900;
34
34
  const AWAY_WORDS = {
@@ -38,7 +38,7 @@ const AWAY_WORDS = {
38
38
  always: 'for good',
39
39
  };
40
40
  /** One colour mode's panel, with the character on its own stage. */
41
- function ModePanel({ mode, character, pose, presence, balloon, insist, onToggle, onDismiss, onCallBack, away, replay, display, }) {
41
+ function ModePanel({ mode, character, pose, presence, balloon, insist, onToggle, onDismiss, onCallBack, away, replay, display, expandTarget, }) {
42
42
  const panelRef = useRef(null);
43
43
  const stageRef = useRef(null);
44
44
  const drag = useViewportDrag(stageRef, { whole: true });
@@ -84,13 +84,19 @@ function ModePanel({ mode, character, pose, presence, balloon, insist, onToggle,
84
84
  position: 'absolute',
85
85
  left: spot.left,
86
86
  top: spot.top + STAGE_SIZE / 2 - 16,
87
- }, children: [_jsxs(Button, { size: "small", onClick: onCallBack, "data-gallery-call-back": "", children: ["Call ", character.name, " back"] }), _jsxs(Text, { as: "p", sx: { fontSize: 0, color: 'fg.muted', mt: 1 }, children: ["Sent away ", AWAY_WORDS[away], "."] })] })) : (_jsx(AssistantStage, { character: character.character, state: state, size: STAGE_SIZE, place: { position: 'absolute', left: spot.left, top: spot.top }, stageRef: stageRef, onDragStart: drag.onHandlePointerDown, open: false, onToggle: onToggle, balloon: presence === 'here' ? balloon : undefined, balloonDisplay: display, insist: insist, onDismiss: onDismiss }, `${character.id}-${replay}`)), pose === 'aside' && presence === 'here' && (_jsx(GalleryObstacle, { sx: {
87
+ }, children: [_jsxs(Button, { size: "small", onClick: onCallBack, "data-gallery-call-back": "", children: ["Call ", character.name, " back"] }), _jsxs(Text, { as: "p", sx: { fontSize: 0, color: 'fg.muted', mt: 1 }, children: ["Sent away ", AWAY_WORDS[away], "."] })] })) : (_jsx(AssistantStage, { character: character.character, state: state, size: STAGE_SIZE, place: { position: 'absolute', left: spot.left, top: spot.top }, stageRef: stageRef, onDragStart: drag.onHandlePointerDown, open: false, onToggle: onToggle, balloon: presence === 'here' ? balloon : undefined, balloonDisplay: display, expandTarget: expandTarget, insist: insist, onDismiss: onDismiss }, `${character.id}-${replay}`)), pose === 'aside' && presence === 'here' && (_jsx(GalleryObstacle, { sx: {
88
88
  left: spot.left - 12,
89
89
  top: spot.top - 12,
90
90
  width: STAGE_SIZE + 24,
91
91
  height: STAGE_SIZE + 24,
92
92
  } }))] }));
93
93
  }
94
+ /** A two-way choice as a Primer toggle: its label, the switch, what is on. */
95
+ function GalleryToggle({ id, label, on, onChange, state, ...rest }) {
96
+ return (_jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 2 }, ...rest, children: [_jsx(Text, { id: id, sx: { fontSize: 1, fontWeight: 'semibold' }, children: label }), _jsx(ToggleSwitch, { "aria-labelledby": id, size: "small", checked: on,
97
+ // Controlled, Primer's switch flips only through its click.
98
+ onClick: () => onChange(!on) }), _jsx(Text, { "aria-live": "polite", "data-toggle-state": "", sx: { fontSize: 1, color: 'fg.muted' }, children: state })] }));
99
+ }
94
100
  /** The panels in the modes asked, each in the examples' theme. */
95
101
  function InModes({ modes, stacked = false, children, }) {
96
102
  const { theme } = useExampleThemeStore();
@@ -103,7 +109,7 @@ function InModes({ modes, stacked = false, children, }) {
103
109
  flexWrap: 'wrap',
104
110
  }, children: shown.map(mode => (_jsx(Box, { sx: { flex: '1 1 320px', minWidth: 0 }, children: _jsx(DatalayerThemeProvider, { colorMode: mode, theme: config.primerTheme, themeStyles: config.themeStyles, children: children(mode) }) }, mode))) }));
105
111
  }
106
- const ChatAssistantGalleryExample = () => {
112
+ const AssistantGalleryExample = () => {
107
113
  const { characters: ours, problem } = useGalleryCharacters();
108
114
  const [withClippyJs, setWithClippyJs] = useState(false);
109
115
  const clippyJs = useClippyJsCharacters(withClippyJs);
@@ -123,6 +129,9 @@ const ChatAssistantGalleryExample = () => {
123
129
  const [display, setDisplay] = useState('current');
124
130
  const [toolPhase, setToolPhase] = useState();
125
131
  const [withNotebook, setWithNotebook] = useState(false);
132
+ // Where Expand draws the notebook: the area under the stage, or a dialog.
133
+ const [expandIntoPage, setExpandIntoPage] = useState(true);
134
+ const expandArea = useRef(null);
126
135
  const character = characters.find(entry => entry.id === characterId) ?? characters[0];
127
136
  // Leaving takes the goodbye's length; arriving, the greeting's.
128
137
  useEffect(() => {
@@ -145,6 +154,21 @@ const ChatAssistantGalleryExample = () => {
145
154
  setSaid(said + 1);
146
155
  };
147
156
  const approval = sampleApproval(() => setDecision('Approved: send_reply.'), () => setDecision('Denied: send_reply.'));
157
+ // History: the conversation so far, every message, as the chat holds it.
158
+ const history = display === 'history'
159
+ ? [
160
+ ...sampleHistory(saying === undefined ? said : saying + 1),
161
+ ...(withNotebook
162
+ ? [
163
+ {
164
+ id: 'notebook',
165
+ role: 'assistant',
166
+ text: SAMPLE_NOTEBOOK_SAYING,
167
+ },
168
+ ]
169
+ : []),
170
+ ]
171
+ : undefined;
148
172
  const balloon = balloonForPose(pose, {
149
173
  saying: saying === undefined
150
174
  ? withNotebook
@@ -153,7 +177,9 @@ const ChatAssistantGalleryExample = () => {
153
177
  : sampleSaying(saying),
154
178
  approval,
155
179
  tool: toolPhase ? sampleToolLine(toolPhase) : undefined,
156
- attachment: withNotebook && display === 'current' ? (_jsx(GalleryNotebook, { onOpen: () => setDecision('The notebook would open below to run.') })) : undefined,
180
+ attachment: withNotebook ? _jsx(GalleryNotebook, {}) : undefined,
181
+ visual: withNotebook ? galleryNotebookVisual() : undefined,
182
+ history,
157
183
  });
158
184
  const insist = saying !== undefined ||
159
185
  toolPhase !== undefined ||
@@ -165,7 +191,7 @@ const ChatAssistantGalleryExample = () => {
165
191
  bg: 'canvas.default',
166
192
  color: 'fg.default',
167
193
  p: 4,
168
- }, children: _jsxs(Box, { sx: { maxWidth: 1200, mx: 'auto' }, children: [_jsx(Heading, { as: "h1", sx: { mb: 2 }, children: "Chat Assistant gallery" }), _jsxs(Text, { as: "p", sx: { color: 'fg.muted', mb: 3, maxWidth: 760 }, children: ["Every character in every state the floating assistant acts, with its balloon, in light and dark. Datalayer\u2019s four and the owl are what the enabled plugins contribute to", ' ', _jsx("code", { children: "loop.assistant.character" }), "; Pixel is a test sprite of our own, read through the clippy.js reader. No agent is behind it: the words are a sample conversation."] }), _jsxs(Text, { as: "p", sx: { color: 'fg.muted', mb: 3, maxWidth: 760 }, children: ["The characters clippy.js publishes \u2014 Clippy, Merlin, Links, Rover and the others \u2014 are loaded on request from the", ' ', _jsxs("code", { children: ["clippyjs@", CLIPPY_JS_VERSION] }), " package on jsDelivr (about 15 MB) and read by the same reader. They are not in this repository: clippy.js\u2019s licence covers its code only, and the characters are Microsoft\u2019s."] }), _jsxs(Box, { as: "section", "aria-label": "Gallery controls", sx: {
194
+ }, children: _jsxs(Box, { sx: { maxWidth: 1200, mx: 'auto' }, children: [_jsx(Heading, { as: "h1", sx: { mb: 2 }, children: "Assistant gallery" }), _jsxs(Text, { as: "p", sx: { color: 'fg.muted', mb: 3, maxWidth: 760 }, children: ["Every character in every state the floating assistant acts, with its balloon, in light and dark. Datalayer\u2019s four and the owl are what the enabled plugins contribute to", ' ', _jsx("code", { children: "loop.assistant.character" }), "; Pixel is a test sprite of our own, read through the clippy.js reader. No agent is behind it: the words are a sample conversation."] }), _jsxs(Text, { as: "p", sx: { color: 'fg.muted', mb: 3, maxWidth: 760 }, children: ["The characters clippy.js publishes \u2014 Clippy, Merlin, Links, Rover and the others \u2014 are loaded on request from the", ' ', _jsxs("code", { children: ["clippyjs@", CLIPPY_JS_VERSION] }), " package on jsDelivr (about 15 MB) and read by the same reader. They are not in this repository: clippy.js\u2019s licence covers its code only, and the characters are Microsoft\u2019s."] }), _jsxs(Box, { as: "section", "aria-label": "Gallery controls", sx: {
169
195
  display: 'grid',
170
196
  gap: 3,
171
197
  mb: 4,
@@ -192,7 +218,7 @@ const ChatAssistantGalleryExample = () => {
192
218
  gap: 2,
193
219
  flexWrap: 'wrap',
194
220
  alignItems: 'center',
195
- }, children: [_jsx(SegmentedControl, { "aria-label": "Balloon", children: ['history', 'current'].map(option => (_jsx(SegmentedControl.Button, { selected: display === option, onClick: () => setDisplay(option), "data-gallery-balloon": option, children: option === 'history' ? 'History' : 'Current' }, option))) }), _jsx(Button, { onClick: say, "data-gallery-say": "", children: "Say something" }), _jsx(Button, { "data-gallery-tool": toolPhase ?? 'none', onClick: () => setToolPhase(toolPhase === undefined
221
+ }, children: [_jsx(GalleryToggle, { id: "gallery-balloon-history", label: "History", on: display === 'history', onChange: on => setDisplay(on ? 'history' : 'current'), state: display === 'history' ? 'History' : 'Current', "data-gallery-balloon-toggle": "" }), _jsx(GalleryToggle, { id: "gallery-expand-into-page", label: "Expand into the page", on: expandIntoPage, onChange: setExpandIntoPage, state: expandIntoPage ? 'The page area' : 'An overlay', "data-gallery-expand-toggle": "" }), _jsx(Button, { onClick: say, "data-gallery-say": "", children: "Say something" }), _jsx(Button, { "data-gallery-tool": toolPhase ?? 'none', onClick: () => setToolPhase(toolPhase === undefined
196
222
  ? 'running'
197
223
  : toolPhase === 'running'
198
224
  ? 'done'
@@ -204,13 +230,19 @@ const ChatAssistantGalleryExample = () => {
204
230
  ? 'Tool done'
205
231
  : toolPhase === 'done'
206
232
  ? 'Tool failed'
207
- : 'No tool' }), _jsx(Button, { "data-gallery-notebook": withNotebook ? 'on' : 'off', "aria-pressed": withNotebook, onClick: () => setWithNotebook(!withNotebook), children: withNotebook ? 'Take the notebook' : 'Give a notebook' }), saying !== undefined && (_jsx(Button, { variant: "invisible", onClick: () => setSaying(undefined), children: "Hush" })), presence === 'away' ? (_jsx(Button, { onClick: callBack, children: "Call it back" })) : (_jsx(Button, { onClick: () => sendAway('page'), disabled: presence !== 'here', "data-gallery-send-away": "", children: "Send it away" })), _jsx(Text, { sx: { color: 'fg.muted', fontSize: 1 }, children: "Drag the character to move it; hover it for its own send-away menu." }), decision && (_jsx(Text, { role: "status", sx: { fontSize: 1 }, children: decision }))] })] }))] }), problem && (_jsxs(Text, { as: "p", role: "alert", sx: { color: 'danger.fg', mb: 3 }, children: ["The test sprite could not be read: ", problem] })), clippyJs.problem && (_jsxs(Text, { as: "p", role: "alert", sx: { color: 'danger.fg', mb: 3 }, children: ["A clippy.js character could not be read: ", clippyJs.problem] })), _jsx(Still, { still: still, children: view === 'stage' ? (_jsx(InModes, { modes: modes, children: mode => (_jsx(ModePanel, { mode: mode, character: character, pose: pose, presence: presence, balloon: balloon, insist: insist, onToggle: () => saying === undefined ? say() : setSaying(undefined), onDismiss: sendAway, onCallBack: callBack, away: away, replay: replay, display: display })) })) : (_jsx(InModes, { modes: modes, stacked: true, children: mode => (_jsxs(Box, { "data-gallery-mode": mode, sx: {
233
+ : 'No tool' }), _jsx(Button, { "data-gallery-notebook": withNotebook ? 'on' : 'off', "aria-pressed": withNotebook, onClick: () => setWithNotebook(!withNotebook), children: withNotebook ? 'Take the notebook' : 'Give a notebook' }), saying !== undefined && (_jsx(Button, { variant: "invisible", onClick: () => setSaying(undefined), children: "Hush" })), presence === 'away' ? (_jsx(Button, { onClick: callBack, children: "Call it back" })) : (_jsx(Button, { onClick: () => sendAway('page'), disabled: presence !== 'here', "data-gallery-send-away": "", children: "Send it away" })), _jsx(Text, { sx: { color: 'fg.muted', fontSize: 1 }, children: "Drag the character to move it; hover it for its own send-away menu." }), decision && (_jsx(Text, { role: "status", sx: { fontSize: 1 }, children: decision }))] })] }))] }), problem && (_jsxs(Text, { as: "p", role: "alert", sx: { color: 'danger.fg', mb: 3 }, children: ["The test sprite could not be read: ", problem] })), clippyJs.problem && (_jsxs(Text, { as: "p", role: "alert", sx: { color: 'danger.fg', mb: 3 }, children: ["A clippy.js character could not be read: ", clippyJs.problem] })), _jsx(Still, { still: still, children: view === 'stage' ? (_jsx(InModes, { modes: modes, children: mode => (_jsx(ModePanel, { mode: mode, character: character, pose: pose, presence: presence, balloon: balloon, insist: insist, onToggle: () => saying === undefined ? say() : setSaying(undefined), onDismiss: sendAway, onCallBack: callBack, away: away, replay: replay, display: display, expandTarget: expandIntoPage ? expandArea : undefined })) })) : (_jsx(InModes, { modes: modes, stacked: true, children: mode => (_jsxs(Box, { "data-gallery-mode": mode, sx: {
208
234
  bg: 'canvas.default',
209
235
  border: '1px solid',
210
236
  borderColor: 'border.default',
211
237
  borderRadius: 2,
212
238
  p: 2,
213
239
  overflowX: 'auto',
214
- }, children: [_jsx(AssistantGalleryGrid, { characters: characters }, replay), _jsx(GalleryBalloons, { character: character })] })) })) })] }) }) }));
240
+ }, children: [_jsx(AssistantGalleryGrid, { characters: characters }, replay), _jsx(GalleryBalloons, { character: character })] })) })) }), view === 'stage' && expandIntoPage && (_jsxs(Box, { as: "section", "aria-label": "Expanded here", sx: {
241
+ mt: 4,
242
+ p: 3,
243
+ border: '1px dashed',
244
+ borderColor: 'border.default',
245
+ borderRadius: 2,
246
+ }, children: [_jsxs(Text, { as: "p", sx: { m: 0, mb: 2, color: 'fg.muted', fontSize: 1 }, children: ["Expanded here: what the balloon\u2019s ", _jsx("em", { children: "Expand" }), " draws large when the page names an area for it \u2014 the notebook, to edit and run on the browser sandbox. Without one, it opens in an overlay."] }), _jsx(Box, { ref: expandArea, "data-gallery-expand-target": "" })] }))] }) }) }));
215
247
  };
216
- export default ChatAssistantGalleryExample;
248
+ export default AssistantGalleryExample;
@@ -43,6 +43,8 @@ function inferTags(id) {
43
43
  tags.add('document');
44
44
  if (id.includes('Chat'))
45
45
  tags.add('chat');
46
+ if (id.startsWith('Assistant'))
47
+ tags.add('assistant');
46
48
  if (id.includes('Sandbox'))
47
49
  tags.add('sandbox');
48
50
  if (id.includes('Monitoring') || id.includes('Otel'))
@@ -87,9 +89,9 @@ export const EXAMPLE_ENTRIES = [
87
89
  makeEntry('DocumentPageAgent', () => import('./DocumentPageAgent'), 'A document as a page: floating prompt on top, an agent writing in it.'),
88
90
  makeEntry('DecksAgent', () => import('./DecksAgent'), 'A deck beside the chat: the decks plugin in a Loop, and an agent that writes presentations as data.'),
89
91
  makeEntry('CellExample', () => import('./CellExample'), 'Simple cell example.'),
90
- makeEntry('ChatAssistantExample', () => import('./ChatAssistantExample'), 'The floating assistant: the chat as a character on the page.'),
92
+ makeEntry('AssistantExample', () => import('./AssistantExample'), 'The floating assistant: the chat as a character on the page.'),
91
93
  makeEntry('VoiceChatExample', () => import('./VoiceChatExample'), 'A voice chat with the floating assistant: push-to-talk heard in the page, answers read aloud by the speech service, the mouth moving with the sound.'),
92
- makeEntry('ChatAssistantGalleryExample', () => import('./ChatAssistantGalleryExample'), 'Every representation of the floating assistant: each character in each state, its balloon, light and dark, still or moving, one at a time or as a grid.'),
94
+ makeEntry('AssistantGalleryExample', () => import('./AssistantGalleryExample'), 'Every representation of the floating assistant: each character in each state, its balloon, light and dark, still or moving, one at a time or as a grid.'),
93
95
  makeEntry('ChatCustomExample', () => import('./ChatCustomExample'), 'Custom chat experience composition example.'),
94
96
  makeEntry('ChatExample', () => import('./ChatExample'), 'Baseline chat integration example.'),
95
97
  makeEntry('ChatStandaloneExample', () => import('./ChatStandaloneExample'), 'Standalone chat component usage example.'),
@@ -0,0 +1,9 @@
1
+ /**
2
+ * The examples' groups, in the menu's order, and the group of each example
3
+ * by its id: a module of its own so the order can be tested without the
4
+ * examples shell.
5
+ *
6
+ * @module examples/exampleGroups
7
+ */
8
+ export declare const EXAMPLE_GROUP_ORDER: readonly ["Apps", "A2UI", "A2A", "AG-UI", "Assistant", "Chat", "Document", "Notebook", "Capabilities", "Cell", "CopilotKit"];
9
+ export declare const getExampleGroup: (id: string) => string;
@@ -0,0 +1,56 @@
1
+ /*
2
+ * Copyright (c) 2025-2026 Datalayer, Inc.
3
+ * Distributed under the terms of the Modified BSD License.
4
+ */
5
+ /**
6
+ * The examples' groups, in the menu's order, and the group of each example
7
+ * by its id: a module of its own so the order can be tested without the
8
+ * examples shell.
9
+ *
10
+ * @module examples/exampleGroups
11
+ */
12
+ export const EXAMPLE_GROUP_ORDER = [
13
+ 'Apps',
14
+ 'A2UI',
15
+ 'A2A',
16
+ 'AG-UI',
17
+ 'Assistant',
18
+ 'Chat',
19
+ 'Document',
20
+ 'Notebook',
21
+ 'Capabilities',
22
+ 'Cell',
23
+ 'CopilotKit',
24
+ ];
25
+ export const getExampleGroup = (id) => {
26
+ if (id === 'AgentspecsExample' ||
27
+ id.startsWith('Loop') ||
28
+ id === 'DecksAgent') {
29
+ return 'Apps';
30
+ }
31
+ if (id.startsWith('A2Ui'))
32
+ return 'A2UI';
33
+ // Agents reached over the A2A protocol: their own category, after A2UI.
34
+ if (id.startsWith('AgentA2A'))
35
+ return 'A2A';
36
+ if (id.startsWith('AgUi'))
37
+ return 'AG-UI';
38
+ if (id.startsWith('CopilotKit'))
39
+ return 'CopilotKit';
40
+ // Each remaining Agent* example demonstrates one capability of the
41
+ // runtime: checkpoints, hooks, memory, guardrails…
42
+ if (id.startsWith('Agent'))
43
+ return 'Capabilities';
44
+ // The floating assistant, and its gallery: before the chat they wrap.
45
+ if (id.startsWith('Assistant'))
46
+ return 'Assistant';
47
+ if (id.startsWith('Chat') || id === 'VoiceChatExample')
48
+ return 'Chat';
49
+ // The document examples: the ones on the Lexical editor, and the page
50
+ // with a document on it.
51
+ if (id.startsWith('Lexical') || id.startsWith('Document'))
52
+ return 'Document';
53
+ if (id.startsWith('Notebook'))
54
+ return 'Notebook';
55
+ return 'Cell';
56
+ };
@@ -15,7 +15,7 @@ export { default as AgUiHumanInTheLoopExample } from './AgUiHumanInTheLoopExampl
15
15
  export { default as AgUiSharedStateExample } from './AgUiSharedStateExample';
16
16
  export { default as AgUiToolsBasedGenUiExample } from './AgUiToolsBasedGenUiExample';
17
17
  export { default as CellExample } from './CellExample';
18
- export { default as ChatAssistantGalleryExample } from './ChatAssistantGalleryExample';
18
+ export { default as AssistantGalleryExample } from './AssistantGalleryExample';
19
19
  export { default as ChatStandaloneExample } from './ChatStandaloneExample';
20
20
  export { default as CopilotKitLexicalExample } from './CopilotKitLexicalExample';
21
21
  export { default as CopilotKitNotebookExample } from './CopilotKitNotebookExample';
@@ -21,7 +21,7 @@ export { default as AgUiHumanInTheLoopExample } from './AgUiHumanInTheLoopExampl
21
21
  export { default as AgUiSharedStateExample } from './AgUiSharedStateExample';
22
22
  export { default as AgUiToolsBasedGenUiExample } from './AgUiToolsBasedGenUiExample';
23
23
  export { default as CellExample } from './CellExample';
24
- export { default as ChatAssistantGalleryExample } from './ChatAssistantGalleryExample';
24
+ export { default as AssistantGalleryExample } from './AssistantGalleryExample';
25
25
  export { default as ChatStandaloneExample } from './ChatStandaloneExample';
26
26
  export { default as CopilotKitLexicalExample } from './CopilotKitLexicalExample';
27
27
  export { default as CopilotKitNotebookExample } from './CopilotKitNotebookExample';
@@ -27,6 +27,7 @@ import { useSimpleAuthStore } from '@datalayer/core/lib/views/otel';
27
27
  import { teardownExampleAgents } from './utils/teardownAgents';
28
28
  import { OAuthCallback } from '../identity';
29
29
  import { EXAMPLES, getExampleEntries, } from './example-selector';
30
+ import { EXAMPLE_GROUP_ORDER, getExampleGroup } from './exampleGroups';
30
31
  import { RUNTIME_TARGETS, runtimeTargetCapabilities, runtimeTargetStore, targetHasAgent, useRuntimeTargetStore, } from './utils/runtimeTargetStore';
31
32
  import { resolveExampleAgentRuntimesUrl } from './utils/useExampleAgentRuntimesUrl';
32
33
  import { isLocalUrl } from './utils/localUrl';
@@ -46,18 +47,6 @@ const DEFAULT_RUNTIMES_URL = 'https://r1.datalayer.run';
46
47
  const DEFAULT_LOCAL_JUPYTER_SERVER_URL = 'http://localhost:8888/api/jupyter-server';
47
48
  const DEFAULT_LOCAL_JUPYTER_SERVER_TOKEN = '60c1661cc408f978c309d04157af55c9588ff9557c9380e4fb50785750703da6';
48
49
  const DEFAULT_CLOUD_RUNTIME_ENVIRONMENT = 'ai-agents-env';
49
- const EXAMPLE_GROUP_ORDER = [
50
- 'Apps',
51
- 'A2UI',
52
- 'A2A',
53
- 'AG-UI',
54
- 'Chat',
55
- 'Document',
56
- 'Notebook',
57
- 'Capabilities',
58
- 'Cell',
59
- 'CopilotKit',
60
- ];
61
50
  /**
62
51
  * The examples that open without an account.
63
52
  *
@@ -88,42 +77,13 @@ const ANONYMOUS_EXAMPLES = new Set([
88
77
  'DecksAgent',
89
78
  // The floating assistant: the character, its balloon and its motions need
90
79
  // no runtime; a conversation does, and says so when there is none.
91
- 'ChatAssistantExample',
80
+ 'AssistantExample',
92
81
  // Every character in every state, from static data: no agent at all.
93
- 'ChatAssistantGalleryExample',
82
+ 'AssistantGalleryExample',
94
83
  // Voice: heard in the page, the agent on the local server, the speech
95
84
  // service named in the address.
96
85
  'VoiceChatExample',
97
86
  ]);
98
- const getExampleGroup = (id) => {
99
- if (id === 'AgentspecsExample' ||
100
- id.startsWith('Loop') ||
101
- id === 'DecksAgent') {
102
- return 'Apps';
103
- }
104
- if (id.startsWith('A2Ui'))
105
- return 'A2UI';
106
- // Agents reached over the A2A protocol: their own category, after A2UI.
107
- if (id.startsWith('AgentA2A'))
108
- return 'A2A';
109
- if (id.startsWith('AgUi'))
110
- return 'AG-UI';
111
- if (id.startsWith('CopilotKit'))
112
- return 'CopilotKit';
113
- // Each remaining Agent* example demonstrates one capability of the
114
- // runtime: checkpoints, hooks, memory, guardrails…
115
- if (id.startsWith('Agent'))
116
- return 'Capabilities';
117
- if (id.startsWith('Chat') || id === 'VoiceChatExample')
118
- return 'Chat';
119
- // The document examples: the ones on the Lexical editor, and the page
120
- // with a document on it.
121
- if (id.startsWith('Lexical') || id.startsWith('Document'))
122
- return 'Document';
123
- if (id.startsWith('Notebook'))
124
- return 'Notebook';
125
- return 'Cell';
126
- };
127
87
  const wait = (ms) => new Promise(resolve => {
128
88
  window.setTimeout(resolve, ms);
129
89
  });
@@ -46,7 +46,12 @@ export declare function GalleryNotebook({ onOpen, }: {
46
46
  onOpen?: () => void;
47
47
  }): JSX.Element;
48
48
  /**
49
- * The balloon's displays (T-23), one character: a peek of the history, the
49
+ * The sample notebook as the balloon's large visual: expanded, the notebook
50
+ * that runs and is edited on the browser sandbox (`TeamNotebook`).
51
+ */
52
+ export declare function galleryNotebookVisual(): import("../../chat/assistant/BalloonVisual").BalloonVisual;
53
+ /**
54
+ * The balloon's displays (T-23), one character: the history, every message listed, the
50
55
  * current balloon with a tool line, and with a notebook given — the same
51
56
  * read-only jupyter-react notebook as in the stage, loaded when drawn.
52
57
  */
@@ -7,8 +7,9 @@ import { AssistantStage } from '../../chat/assistant/AssistantStage';
7
7
  import { AssistantCharactersPlugin, assistantCharactersOf, } from '../../loop/plugins/assistant-characters';
8
8
  import { OWL_CHARACTER, OwlCharacterPlugin } from './owlCharacterPlugin';
9
9
  import { NotebookPreview } from '../../components/teams/NotebookPreview';
10
+ import { notebookBalloonVisual } from '../../components/teams/TeamNotebook';
10
11
  import { readTestSpriteCharacter } from './testSpriteCharacter';
11
- import { GALLERY_POSES, GALLERY_POSE_LABELS, SAMPLE_NOTEBOOK, SAMPLE_NOTEBOOK_SAYING, sampleSaying, sampleToolLine, stateOfPose, } from './assistantGallery';
12
+ import { GALLERY_POSES, GALLERY_POSE_LABELS, SAMPLE_NOTEBOOK, SAMPLE_NOTEBOOK_ARTIFACT, SAMPLE_NOTEBOOK_SAYING, sampleHistory, sampleSaying, sampleToolLine, stateOfPose, } from './assistantGallery';
12
13
  /** The plugins the gallery enables: Datalayer's characters and the owl's. */
13
14
  const reactor = buildReactorFromPlugins([
14
15
  AssistantCharactersPlugin,
@@ -127,6 +128,13 @@ export const GALLERY_NOTEBOOK_HEIGHT = 160;
127
128
  export function GalleryNotebook({ onOpen, }) {
128
129
  return (_jsx(NotebookPreview, { notebook: SAMPLE_NOTEBOOK, title: "Accounting\u2019s notebook", maxHeight: GALLERY_NOTEBOOK_HEIGHT, onOpen: onOpen }));
129
130
  }
131
+ /**
132
+ * The sample notebook as the balloon's large visual: expanded, the notebook
133
+ * that runs and is edited on the browser sandbox (`TeamNotebook`).
134
+ */
135
+ export function galleryNotebookVisual() {
136
+ return notebookBalloonVisual(SAMPLE_NOTEBOOK_ARTIFACT, 'Accounting’s notebook', 420);
137
+ }
130
138
  /** One balloon display, pictured: a character with what its balloon says. */
131
139
  function BalloonCell({ character, label, display, balloon, height, }) {
132
140
  const stageRef = useRef(null);
@@ -147,18 +155,23 @@ function BalloonCell({ character, label, display, balloon, height, }) {
147
155
  }, children: label }), _jsx(AssistantStage, { character: character.character, state: balloon.tool ? 'working' : 'speaking', size: 48, place: { position: 'absolute', left: '12px', bottom: '8px' }, stageRef: stageRef, onDragStart: () => undefined, open: false, onToggle: () => undefined, onDismiss: () => undefined, balloon: balloon, balloonDisplay: display, insist: true })] }));
148
156
  }
149
157
  /**
150
- * The balloon's displays (T-23), one character: a peek of the history, the
158
+ * The balloon's displays (T-23), one character: the history, every message listed, the
151
159
  * current balloon with a tool line, and with a notebook given — the same
152
160
  * read-only jupyter-react notebook as in the stage, loaded when drawn.
153
161
  */
154
162
  export function GalleryBalloons({ character, }) {
155
- return (_jsxs(Box, { "data-gallery-balloons": "", sx: { display: 'flex', gap: 3, flexWrap: 'wrap', mt: 3 }, children: [_jsx(BalloonCell, { character: character, label: "History", display: "history", height: 180, balloon: { ...sampleSaying(0), onDismiss: () => undefined } }), _jsx(BalloonCell, { character: character, label: "Current \u00B7 tool", display: "current", height: 180, balloon: {
163
+ return (_jsxs(Box, { "data-gallery-balloons": "", sx: { display: 'flex', gap: 3, flexWrap: 'wrap', mt: 3 }, children: [_jsx(BalloonCell, { character: character, label: "History", display: "history", height: 340, balloon: {
164
+ ...sampleSaying(1),
165
+ history: sampleHistory(2),
166
+ onDismiss: () => undefined,
167
+ } }), _jsx(BalloonCell, { character: character, label: "Current \u00B7 tool", display: "current", height: 180, balloon: {
156
168
  text: 'Using list_invoices…',
157
169
  tool: sampleToolLine('running'),
158
170
  busy: true,
159
171
  } }), _jsx(BalloonCell, { character: character, label: "Current \u00B7 notebook", display: "current", height: GALLERY_NOTEBOOK_HEIGHT + 210, balloon: {
160
172
  text: SAMPLE_NOTEBOOK_SAYING,
161
173
  attachment: _jsx(GalleryNotebook, {}),
174
+ visual: galleryNotebookVisual(),
162
175
  } })] }));
163
176
  }
164
177
  export default AssistantGalleryGrid;