@datalayer/agent-runtimes 1.3.58 → 1.3.60
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/chat/ChatFloating.d.ts +11 -1
- package/lib/chat/ChatFloating.js +6 -2
- package/lib/chat/assistant/AssistantStage.d.ts +7 -1
- package/lib/chat/assistant/AssistantStage.js +5 -3
- package/lib/chat/assistant/DecisionAsk.d.ts +31 -0
- package/lib/chat/assistant/DecisionAsk.js +96 -0
- package/lib/chat/assistant/SpeechBalloon.d.ts +11 -2
- package/lib/chat/assistant/SpeechBalloon.js +5 -4
- package/lib/chat/assistant/decisions.d.ts +104 -0
- package/lib/chat/assistant/decisions.js +161 -0
- package/lib/chat/marks/toolMarks.js +2 -2
- package/lib/config/AgentConfiguration.d.ts +2 -1
- package/lib/config/AgentConfiguration.js +2 -2
- package/lib/examples/AgentDecideExample.d.ts +24 -0
- package/lib/examples/AgentDecideExample.js +73 -0
- package/lib/examples/AgentNotificationsExample.js +1 -1
- package/lib/examples/AgentSkillsExample.js +1 -1
- package/lib/examples/AgentspecsExample.js +3 -3
- package/lib/examples/ChatAssistantGalleryExample.d.ts +12 -0
- package/lib/examples/ChatAssistantGalleryExample.js +181 -0
- package/lib/examples/example-selector.js +2 -0
- package/lib/examples/index.d.ts +2 -0
- package/lib/examples/index.js +2 -0
- package/lib/examples/main.js +5 -0
- package/lib/examples/utils/AssistantGalleryGrid.d.ts +53 -0
- package/lib/examples/utils/AssistantGalleryGrid.js +123 -0
- package/lib/examples/utils/assistantGallery.d.ts +42 -0
- package/lib/examples/utils/assistantGallery.js +102 -0
- package/lib/examples/utils/testSpriteCharacter.d.ts +9 -0
- package/lib/examples/utils/testSpriteCharacter.js +60 -0
- package/lib/loop/apps/appspec.js +4 -4
- package/lib/loop/apps/checks.js +6 -6
- package/lib/loop/apps/rules.js +2 -2
- package/lib/loop/plugins/assistant/index.d.ts +14 -2
- package/lib/loop/plugins/assistant/index.js +13 -4
- package/lib/specs/actions.d.ts +1 -1
- package/lib/specs/actions.js +1 -1
- package/lib/specs/agents/agents.js +197 -192
- package/lib/specs/apps.js +13 -13
- package/lib/specs/appspecSchema.js +3 -3
- package/lib/specs/backendTools.d.ts +31 -0
- package/lib/specs/{tools.js → backendTools.js} +48 -48
- package/lib/specs/cogs.js +8 -7
- package/lib/specs/frames.js +5 -5
- package/lib/specs/index.d.ts +1 -1
- package/lib/specs/index.js +1 -1
- package/lib/stores/agentRuntimeStore.js +2 -2
- package/lib/stories/loop/pictures-main.js +16 -1
- package/lib/types/agentspecs.d.ts +7 -5
- package/lib/types/config.d.ts +2 -2
- package/lib/types/tools.d.ts +3 -3
- package/package.json +1 -1
- package/scripts/codegen/generate_agents.py +23 -12
- package/scripts/codegen/generate_apps.py +3 -2
- package/scripts/codegen/{generate_tools.py → generate_backend_tools.py} +29 -29
- package/scripts/codegen/generate_cogs.py +2 -2
- package/scripts/codegen/generate_frames.py +2 -2
- package/lib/specs/tools.d.ts +0 -31
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/*
|
|
3
|
+
* Copyright (c) 2025-2026 Datalayer, Inc.
|
|
4
|
+
* Distributed under the terms of the Modified BSD License.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Decide: typed decisions asked of Jev (`cloudflare:wrk/typesafe/jev`), the
|
|
8
|
+
* typed-decision model, from the chat and from the floating assistant.
|
|
9
|
+
*
|
|
10
|
+
* The *Decide* application of the catalogue (agentspecs `apps/decide.yaml`)
|
|
11
|
+
* in the LOOP workspace, on the Local target: its agent — `example-simple`
|
|
12
|
+
* with the `decide` tool — runs on the local agent-runtimes server, and
|
|
13
|
+
* answers a question about a text by asking a typed decision. The floating
|
|
14
|
+
* assistant beside it offers *Ask a decision* in its balloon: the situation,
|
|
15
|
+
* the question and its type, asked through the same server's
|
|
16
|
+
* `/api/v1/configure/inference/decisions`, the route that asks as `decide`
|
|
17
|
+
* does, with the same token.
|
|
18
|
+
*
|
|
19
|
+
* The server needs ai-inference: start it with
|
|
20
|
+
* `AGENT_RUNTIMES_INFERENCE_PROVIDER_OVERRIDE=datalayer`,
|
|
21
|
+
* `DATALAYER_AI_INFERENCE_URL=https://r1.datalayer.run` and
|
|
22
|
+
* `DATALAYER_AI_INFERENCE_API_KEY` set from `DATALAYER_API_KEY`. Another
|
|
23
|
+
* server than `http://localhost:8765` is named with `?agentRuntimesUrl=`.
|
|
24
|
+
*
|
|
25
|
+
* @module examples/AgentDecideExample
|
|
26
|
+
*/
|
|
27
|
+
import { useMemo } from 'react';
|
|
28
|
+
import { configurePlugin } from '@datalayer/reactor';
|
|
29
|
+
import { Heading, Text } from '@primer/react';
|
|
30
|
+
import { Box, setupPrimerPortals } from '@datalayer/primer-addons';
|
|
31
|
+
import { ThemedProvider } from './utils/themedProvider';
|
|
32
|
+
import { resolveExampleAgentRuntimesUrl } from './utils/useExampleAgentRuntimesUrl';
|
|
33
|
+
import { AppRenderer, appDatalayerCreatePayload, } from '../loop/apps/AppRenderer';
|
|
34
|
+
import { AssistantCharactersPlugin } from '../loop/plugins/assistant-characters';
|
|
35
|
+
import { LoopAssistantPlugin } from '../loop/plugins/assistant';
|
|
36
|
+
import { APP_CATALOGUE } from '../specs/apps';
|
|
37
|
+
setupPrimerPortals();
|
|
38
|
+
/** The local server: `?agentRuntimesUrl=` when given, else the examples' own. */
|
|
39
|
+
function serverUrlOf() {
|
|
40
|
+
const named = typeof window === 'undefined'
|
|
41
|
+
? null
|
|
42
|
+
: new URLSearchParams(window.location.search).get('agentRuntimesUrl');
|
|
43
|
+
return resolveExampleAgentRuntimesUrl('local', named ?? undefined);
|
|
44
|
+
}
|
|
45
|
+
const AgentDecideExample = () => {
|
|
46
|
+
const app = APP_CATALOGUE['decide'];
|
|
47
|
+
const serverUrl = useMemo(serverUrlOf, []);
|
|
48
|
+
// Made once: a new plugin on a render restarts the workspace.
|
|
49
|
+
const plugins = useMemo(() => [
|
|
50
|
+
AssistantCharactersPlugin,
|
|
51
|
+
configurePlugin(LoopAssistantPlugin, {
|
|
52
|
+
app: app.interface.assistant ?? undefined,
|
|
53
|
+
decisions: { serverUrl },
|
|
54
|
+
}),
|
|
55
|
+
], [app, serverUrl]);
|
|
56
|
+
// The Local agent is the application's: created under its id with its
|
|
57
|
+
// spec, so that the server runs its instructions, its tool and its rule.
|
|
58
|
+
const localAgent = useMemo(() => ({ createPayload: appDatalayerCreatePayload(app) }), [app]);
|
|
59
|
+
return (_jsx(ThemedProvider, { children: _jsxs(Box, { sx: {
|
|
60
|
+
height: '100vh',
|
|
61
|
+
minHeight: 0,
|
|
62
|
+
display: 'flex',
|
|
63
|
+
bg: 'canvas.default',
|
|
64
|
+
}, children: [_jsx(Box, { sx: { flex: 1, minWidth: 0, minHeight: 0 }, children: _jsx(AppRenderer, { app: app, serverUrl: serverUrl, target: "local", localAgent: localAgent, plugins: plugins }) }), _jsxs(Box, { as: "aside", sx: {
|
|
65
|
+
width: 320,
|
|
66
|
+
flexShrink: 0,
|
|
67
|
+
p: 3,
|
|
68
|
+
borderLeft: '1px solid',
|
|
69
|
+
borderColor: 'border.default',
|
|
70
|
+
overflowY: 'auto',
|
|
71
|
+
}, children: [_jsxs(Heading, { as: "h2", sx: { fontSize: 2, mb: 2 }, children: [app.emoji, " Decide"] }), _jsx(Text, { as: "p", sx: { fontSize: 1, mb: 2 }, children: "Typed decisions asked of Jev, the typed-decision model: yes or no with its probability, one of named options, or a score, each with its confidence." }), _jsxs(Text, { as: "p", sx: { fontSize: 1, mb: 2 }, children: [_jsx("strong", { children: "In the chat" }), ": ask \u201CIs this ticket urgent? \u2018Help! My payouts have been failing for 3 days.\u2019\u201D Its agent calls the ", _jsx("code", { children: "decide" }), " tool, a read it does without asking."] }), _jsxs(Text, { as: "p", sx: { fontSize: 1, mb: 2 }, children: [_jsx("strong", { children: "From the assistant" }), ": hover the character below and choose ", _jsx("em", { children: "Ask a decision" }), " \u2014 the situation, the question, and its type. The answer comes back in its balloon."] }), _jsxs(Text, { as: "p", sx: { fontSize: 0, color: 'fg.muted' }, children: ["Runs on the local agent-runtimes server at ", serverUrl, ", which asks Jev through ai-inference."] })] })] }) }));
|
|
72
|
+
};
|
|
73
|
+
export default AgentDecideExample;
|
|
@@ -602,7 +602,7 @@ githubClientId, kaggleToken, }) => {
|
|
|
602
602
|
setGoal(spec.goal || '');
|
|
603
603
|
setSystemPrompt(spec.systemPrompt || spec.goal || DEFAULT_SYSTEM_PROMPT);
|
|
604
604
|
setSystemPromptCodemodeAddons(spec.systemPromptCodemodeAddons || '');
|
|
605
|
-
setTools(spec.
|
|
605
|
+
setTools(spec.backendTools || []);
|
|
606
606
|
setSandboxVariant(spec.sandboxVariant || '');
|
|
607
607
|
if (spec.model) {
|
|
608
608
|
setModel(spec.model);
|
|
@@ -650,7 +650,7 @@ githubClientId, kaggleToken, }) => {
|
|
|
650
650
|
protocol: normalizedProtocol,
|
|
651
651
|
systemPrompt: systemPrompt || undefined,
|
|
652
652
|
systemPromptCodemodeAddons: systemPromptCodemodeAddons || undefined,
|
|
653
|
-
tools,
|
|
653
|
+
backendTools: tools,
|
|
654
654
|
sandboxVariant: sandboxVariant || undefined,
|
|
655
655
|
skills: selectedSkills,
|
|
656
656
|
mcpServers: selectedMcpServers.map(server => ({
|
|
@@ -786,7 +786,7 @@ githubClientId, kaggleToken, }) => {
|
|
|
786
786
|
model: model,
|
|
787
787
|
system_prompt: systemPrompt || DEFAULT_SYSTEM_PROMPT,
|
|
788
788
|
system_prompt_codemode_addons: systemPromptCodemodeAddons || undefined,
|
|
789
|
-
|
|
789
|
+
backend_tools: tools,
|
|
790
790
|
sandbox_variant: sandboxVariant || undefined,
|
|
791
791
|
enable_skills: enableSkills,
|
|
792
792
|
enable_codemode: enableCodemode,
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Every representation of the floating assistant, as a gallery (LOOP T-21
|
|
3
|
+
* to T-27): each character — Datalayer's four, the owl an example plugin
|
|
4
|
+
* contributes to `loop.assistant.character`, and a test sprite read through
|
|
5
|
+
* the clippy.js reader — in each state it acts, stepped aside, with its
|
|
6
|
+
* balloon, in light and dark, moving or still.
|
|
7
|
+
*
|
|
8
|
+
* Static data, no agent: it opens without a server or an account.
|
|
9
|
+
*/
|
|
10
|
+
import React from 'react';
|
|
11
|
+
declare const ChatAssistantGalleryExample: React.FC;
|
|
12
|
+
export default ChatAssistantGalleryExample;
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
/*
|
|
3
|
+
* Copyright (c) 2025-2026 Datalayer, Inc.
|
|
4
|
+
* Distributed under the terms of the Modified BSD License.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Every representation of the floating assistant, as a gallery (LOOP T-21
|
|
8
|
+
* to T-27): each character — Datalayer's four, the owl an example plugin
|
|
9
|
+
* contributes to `loop.assistant.character`, and a test sprite read through
|
|
10
|
+
* the clippy.js reader — in each state it acts, stepped aside, with its
|
|
11
|
+
* balloon, in light and dark, moving or still.
|
|
12
|
+
*
|
|
13
|
+
* Static data, no agent: it opens without a server or an account.
|
|
14
|
+
*/
|
|
15
|
+
import { useEffect, useRef, useState } from 'react';
|
|
16
|
+
import { Button, Checkbox, FormControl, Heading, SegmentedControl, Text, } from '@primer/react';
|
|
17
|
+
import { Box, DatalayerThemeProvider, themeConfigs, } from '@datalayer/primer-addons';
|
|
18
|
+
import { ThemedProvider } from './utils/themedProvider';
|
|
19
|
+
import { useExampleThemeStore } from './utils/themeStore';
|
|
20
|
+
import { AssistantStage } from '../chat/assistant/AssistantStage';
|
|
21
|
+
import { useViewportDrag } from '../chat/useViewportDrag';
|
|
22
|
+
import { AssistantGalleryGrid, GalleryObstacle, Still, useGalleryCharacters, } from './utils/AssistantGalleryGrid';
|
|
23
|
+
import { GALLERY_POSES, GALLERY_POSE_LABELS, balloonForPose, sampleApproval, sampleSaying, stateOfPose, } from './utils/assistantGallery';
|
|
24
|
+
const STAGE_SIZE = 96;
|
|
25
|
+
const PANEL_HEIGHT = 420;
|
|
26
|
+
const LEAVE_MS = 700;
|
|
27
|
+
const ARRIVE_MS = 1900;
|
|
28
|
+
const AWAY_WORDS = {
|
|
29
|
+
none: '',
|
|
30
|
+
page: 'for now',
|
|
31
|
+
session: 'for this session',
|
|
32
|
+
always: 'for good',
|
|
33
|
+
};
|
|
34
|
+
/** One colour mode's panel, with the character on its own stage. */
|
|
35
|
+
function ModePanel({ mode, character, pose, presence, balloon, insist, onToggle, onDismiss, onCallBack, away, replay, }) {
|
|
36
|
+
const panelRef = useRef(null);
|
|
37
|
+
const stageRef = useRef(null);
|
|
38
|
+
const drag = useViewportDrag(stageRef, { whole: true });
|
|
39
|
+
// Where it stands in the panel: the drag's viewport place, made the
|
|
40
|
+
// panel's own once, so a scroll does not move it.
|
|
41
|
+
const [spot, setSpot] = useState({ left: 48, top: PANEL_HEIGHT - 150 });
|
|
42
|
+
useEffect(() => {
|
|
43
|
+
const panel = panelRef.current;
|
|
44
|
+
if (drag.position && panel) {
|
|
45
|
+
const box = panel.getBoundingClientRect();
|
|
46
|
+
setSpot({
|
|
47
|
+
left: drag.position.left - box.left,
|
|
48
|
+
top: drag.position.top - box.top,
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
}, [drag.position]);
|
|
52
|
+
const state = presence === 'leaving'
|
|
53
|
+
? 'goodbye'
|
|
54
|
+
: presence === 'arriving'
|
|
55
|
+
? 'greeting'
|
|
56
|
+
: stateOfPose(pose);
|
|
57
|
+
return (_jsxs(Box, { ref: panelRef, "data-gallery-mode": mode, sx: {
|
|
58
|
+
position: 'relative',
|
|
59
|
+
flex: '1 1 320px',
|
|
60
|
+
minWidth: 0,
|
|
61
|
+
height: PANEL_HEIGHT,
|
|
62
|
+
bg: 'canvas.default',
|
|
63
|
+
color: 'fg.default',
|
|
64
|
+
border: '1px solid',
|
|
65
|
+
borderColor: 'border.default',
|
|
66
|
+
borderRadius: 2,
|
|
67
|
+
overflow: 'visible',
|
|
68
|
+
}, children: [_jsx(Text, { sx: {
|
|
69
|
+
position: 'absolute',
|
|
70
|
+
top: 2,
|
|
71
|
+
left: 3,
|
|
72
|
+
fontSize: 0,
|
|
73
|
+
fontWeight: 600,
|
|
74
|
+
color: 'fg.muted',
|
|
75
|
+
textTransform: 'uppercase',
|
|
76
|
+
letterSpacing: '0.04em',
|
|
77
|
+
}, children: mode }), presence === 'away' ? (_jsxs(Box, { sx: {
|
|
78
|
+
position: 'absolute',
|
|
79
|
+
left: spot.left,
|
|
80
|
+
top: spot.top + STAGE_SIZE / 2 - 16,
|
|
81
|
+
}, 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, insist: insist, onDismiss: onDismiss }, `${character.id}-${replay}`)), pose === 'aside' && presence === 'here' && (_jsx(GalleryObstacle, { sx: {
|
|
82
|
+
left: spot.left - 12,
|
|
83
|
+
top: spot.top - 12,
|
|
84
|
+
width: STAGE_SIZE + 24,
|
|
85
|
+
height: STAGE_SIZE + 24,
|
|
86
|
+
} }))] }));
|
|
87
|
+
}
|
|
88
|
+
/** The panels in the modes asked, each in the examples' theme. */
|
|
89
|
+
function InModes({ modes, stacked = false, children, }) {
|
|
90
|
+
const { theme } = useExampleThemeStore();
|
|
91
|
+
const config = themeConfigs[theme] ?? themeConfigs.loop;
|
|
92
|
+
const shown = modes === 'both' ? ['light', 'dark'] : [modes];
|
|
93
|
+
return (_jsx(Box, { sx: {
|
|
94
|
+
display: 'flex',
|
|
95
|
+
flexDirection: stacked ? 'column' : 'row',
|
|
96
|
+
gap: 3,
|
|
97
|
+
flexWrap: 'wrap',
|
|
98
|
+
}, 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))) }));
|
|
99
|
+
}
|
|
100
|
+
const ChatAssistantGalleryExample = () => {
|
|
101
|
+
const { characters, problem } = useGalleryCharacters();
|
|
102
|
+
const [characterId, setCharacterId] = useState('paperclip');
|
|
103
|
+
const [pose, setPose] = useState('idle');
|
|
104
|
+
const [view, setView] = useState('stage');
|
|
105
|
+
const [modes, setModes] = useState('both');
|
|
106
|
+
const [still, setStill] = useState(false);
|
|
107
|
+
const [saying, setSaying] = useState();
|
|
108
|
+
const [said, setSaid] = useState(0);
|
|
109
|
+
const [decision, setDecision] = useState();
|
|
110
|
+
const [presence, setPresence] = useState('here');
|
|
111
|
+
const [away, setAway] = useState('none');
|
|
112
|
+
const [replay, setReplay] = useState(0);
|
|
113
|
+
const character = characters.find(entry => entry.id === characterId) ?? characters[0];
|
|
114
|
+
// Leaving takes the goodbye's length; arriving, the greeting's.
|
|
115
|
+
useEffect(() => {
|
|
116
|
+
if (presence !== 'leaving' && presence !== 'arriving') {
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
const timer = window.setTimeout(() => setPresence(presence === 'leaving' ? 'away' : 'here'), presence === 'leaving' ? LEAVE_MS : ARRIVE_MS);
|
|
120
|
+
return () => window.clearTimeout(timer);
|
|
121
|
+
}, [presence]);
|
|
122
|
+
const sendAway = (choice) => {
|
|
123
|
+
setAway(choice);
|
|
124
|
+
setPresence('leaving');
|
|
125
|
+
};
|
|
126
|
+
const callBack = () => {
|
|
127
|
+
setAway('none');
|
|
128
|
+
setPresence('arriving');
|
|
129
|
+
};
|
|
130
|
+
const say = () => {
|
|
131
|
+
setSaying(said);
|
|
132
|
+
setSaid(said + 1);
|
|
133
|
+
};
|
|
134
|
+
const approval = sampleApproval(() => setDecision('Approved: send_reply.'), () => setDecision('Denied: send_reply.'));
|
|
135
|
+
const balloon = balloonForPose(pose, {
|
|
136
|
+
saying: saying === undefined ? undefined : sampleSaying(saying),
|
|
137
|
+
approval,
|
|
138
|
+
});
|
|
139
|
+
const insist = saying !== undefined || pose === 'waiting' || pose === 'paused';
|
|
140
|
+
return (_jsx(ThemedProvider, { children: _jsx(Box, { sx: {
|
|
141
|
+
minHeight: '100vh',
|
|
142
|
+
bg: 'canvas.default',
|
|
143
|
+
color: 'fg.default',
|
|
144
|
+
p: 4,
|
|
145
|
+
}, children: _jsxs(Box, { sx: { maxWidth: 1200, mx: 'auto' }, children: [_jsx(Heading, { as: "h1", sx: { mb: 2 }, children: "Floating 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(Box, { as: "section", "aria-label": "Gallery controls", sx: {
|
|
146
|
+
display: 'grid',
|
|
147
|
+
gap: 3,
|
|
148
|
+
mb: 4,
|
|
149
|
+
p: 3,
|
|
150
|
+
border: '1px solid',
|
|
151
|
+
borderColor: 'border.default',
|
|
152
|
+
borderRadius: 2,
|
|
153
|
+
bg: 'canvas.subtle',
|
|
154
|
+
}, children: [_jsxs(Box, { sx: {
|
|
155
|
+
display: 'flex',
|
|
156
|
+
gap: 3,
|
|
157
|
+
flexWrap: 'wrap',
|
|
158
|
+
alignItems: 'center',
|
|
159
|
+
}, children: [_jsxs(SegmentedControl, { "aria-label": "View", children: [_jsx(SegmentedControl.Button, { selected: view === 'stage', onClick: () => setView('stage'), children: "One at a time" }), _jsx(SegmentedControl.Button, { selected: view === 'grid', onClick: () => setView('grid'), "data-gallery-view": "grid", children: "Grid" })] }), _jsx(SegmentedControl, { "aria-label": "Colour mode", children: ['light', 'dark', 'both'].map(option => (_jsx(SegmentedControl.Button, { selected: modes === option, onClick: () => setModes(option), children: option === 'both'
|
|
160
|
+
? 'Side by side'
|
|
161
|
+
: option === 'light'
|
|
162
|
+
? 'Light'
|
|
163
|
+
: 'Dark' }, option))) }), _jsxs(FormControl, { children: [_jsx(Checkbox, { checked: still, onChange: event => setStill(event.target.checked) }), _jsx(FormControl.Label, { children: "Reduced motion" })] }), _jsx(Button, { onClick: () => setReplay(replay + 1), children: "Replay the motions" })] }), view === 'stage' && (_jsxs(_Fragment, { children: [_jsx(Box, { role: "group", "aria-label": "Character", sx: { display: 'flex', gap: 2, flexWrap: 'wrap' }, children: characters.map(option => (_jsx(Button, { size: "small", variant: option.id === character.id ? 'primary' : 'default', "aria-pressed": option.id === character.id, "data-gallery-character": option.id, onClick: () => setCharacterId(option.id), children: option.name }, option.id))) }), _jsx(Box, { role: "group", "aria-label": "State", sx: { display: 'flex', gap: 2, flexWrap: 'wrap' }, children: GALLERY_POSES.map(option => (_jsx(Button, { size: "small", variant: option === pose ? 'primary' : 'default', "aria-pressed": option === pose, "data-gallery-pose": option, onClick: () => {
|
|
164
|
+
setPose(option);
|
|
165
|
+
setDecision(undefined);
|
|
166
|
+
setReplay(replay + 1);
|
|
167
|
+
}, children: GALLERY_POSE_LABELS[option] }, option))) }), _jsxs(Box, { sx: {
|
|
168
|
+
display: 'flex',
|
|
169
|
+
gap: 2,
|
|
170
|
+
flexWrap: 'wrap',
|
|
171
|
+
alignItems: 'center',
|
|
172
|
+
}, children: [_jsx(Button, { onClick: say, "data-gallery-say": "", children: "Say something" }), 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] })), _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 })) })) : (_jsx(InModes, { modes: modes, stacked: true, children: mode => (_jsx(Box, { "data-gallery-mode": mode, sx: {
|
|
173
|
+
bg: 'canvas.default',
|
|
174
|
+
border: '1px solid',
|
|
175
|
+
borderColor: 'border.default',
|
|
176
|
+
borderRadius: 2,
|
|
177
|
+
p: 2,
|
|
178
|
+
overflowX: 'auto',
|
|
179
|
+
}, children: _jsx(AssistantGalleryGrid, { characters: characters }, replay) })) })) })] }) }) }));
|
|
180
|
+
};
|
|
181
|
+
export default ChatAssistantGalleryExample;
|
|
@@ -88,6 +88,7 @@ export const EXAMPLE_ENTRIES = [
|
|
|
88
88
|
makeEntry('DecksAgent', () => import('./DecksAgent'), 'A deck beside the chat: the decks plugin in a Loop, and an agent that writes presentations as data.'),
|
|
89
89
|
makeEntry('CellExample', () => import('./CellExample'), 'Simple cell example.'),
|
|
90
90
|
makeEntry('ChatAssistantExample', () => import('./ChatAssistantExample'), 'The floating assistant: the chat as a character on the page.'),
|
|
91
|
+
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.'),
|
|
91
92
|
makeEntry('ChatCustomExample', () => import('./ChatCustomExample'), 'Custom chat experience composition example.'),
|
|
92
93
|
makeEntry('ChatExample', () => import('./ChatExample'), 'Baseline chat integration example.'),
|
|
93
94
|
makeEntry('ChatStandaloneExample', () => import('./ChatStandaloneExample'), 'Standalone chat component usage example.'),
|
|
@@ -97,6 +98,7 @@ export const EXAMPLE_ENTRIES = [
|
|
|
97
98
|
makeEntry('AgentCompactionExample', () => import('./AgentCompactionExample'), 'Set a context token budget and watch history compaction summarize older messages, with live from/to token and timing details.', ['example', 'agent', 'compaction', 'context', 'tokens']),
|
|
98
99
|
makeEntry('AgentCodemodeExample', () => import('./AgentCodemodeExample'), 'Code mode execution and tool orchestration example.'),
|
|
99
100
|
makeEntry('AgentCodeSandboxesExample', () => import('./AgentCodeSandboxesExample'), 'Launch sandbox-variant agent specs and compare code execution across backends.', ['example', 'agent', 'sandbox', 'codemode']),
|
|
101
|
+
makeEntry('AgentDecideExample', () => import('./AgentDecideExample'), 'Decide: typed decisions asked of Jev — yes or no, a choice, a score — from the chat, where the agent calls decide, and from the floating assistant’s Ask a decision.', ['example', 'agent', 'loop', 'app', 'decisions', 'jev', 'assistant']),
|
|
100
102
|
makeEntry('AgentEvalsExample', () => import('./AgentEvalsExample'), 'Evaluation workflows for agent outputs.'),
|
|
101
103
|
makeEntry('AgentGuardrailsExample', () => import('./AgentGuardrailsExample'), 'Guardrails and safety checks for agent runs.'),
|
|
102
104
|
makeEntry('AgentHooksExample', () => import('./AgentHooksExample'), 'Pre-hooks and post-hooks lifecycle execution example.'),
|
package/lib/examples/index.d.ts
CHANGED
|
@@ -15,6 +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
19
|
export { default as ChatStandaloneExample } from './ChatStandaloneExample';
|
|
19
20
|
export { default as CopilotKitLexicalExample } from './CopilotKitLexicalExample';
|
|
20
21
|
export { default as CopilotKitNotebookExample } from './CopilotKitNotebookExample';
|
|
@@ -24,6 +25,7 @@ export { default as AgentCheckpointsExample } from './AgentCheckpointsExample';
|
|
|
24
25
|
export { default as AgentCompactionExample } from './AgentCompactionExample';
|
|
25
26
|
export { default as AgentCodemodeExample } from './AgentCodemodeExample';
|
|
26
27
|
export { default as AgentCodeSandboxesExample } from './AgentCodeSandboxesExample';
|
|
28
|
+
export { default as AgentDecideExample } from './AgentDecideExample';
|
|
27
29
|
export { default as AgentEvalsExample } from './AgentEvalsExample';
|
|
28
30
|
export { default as AgentGuardrailsExample } from './AgentGuardrailsExample';
|
|
29
31
|
export { default as AgentHooksExample } from './AgentHooksExample';
|
package/lib/examples/index.js
CHANGED
|
@@ -21,6 +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
25
|
export { default as ChatStandaloneExample } from './ChatStandaloneExample';
|
|
25
26
|
export { default as CopilotKitLexicalExample } from './CopilotKitLexicalExample';
|
|
26
27
|
export { default as CopilotKitNotebookExample } from './CopilotKitNotebookExample';
|
|
@@ -30,6 +31,7 @@ export { default as AgentCheckpointsExample } from './AgentCheckpointsExample';
|
|
|
30
31
|
export { default as AgentCompactionExample } from './AgentCompactionExample';
|
|
31
32
|
export { default as AgentCodemodeExample } from './AgentCodemodeExample';
|
|
32
33
|
export { default as AgentCodeSandboxesExample } from './AgentCodeSandboxesExample';
|
|
34
|
+
export { default as AgentDecideExample } from './AgentDecideExample';
|
|
33
35
|
export { default as AgentEvalsExample } from './AgentEvalsExample';
|
|
34
36
|
export { default as AgentGuardrailsExample } from './AgentGuardrailsExample';
|
|
35
37
|
export { default as AgentHooksExample } from './AgentHooksExample';
|
package/lib/examples/main.js
CHANGED
|
@@ -70,6 +70,9 @@ const ANONYMOUS_EXAMPLES = new Set([
|
|
|
70
70
|
// An application beside its computer, on the local agent-runtimes server:
|
|
71
71
|
// nothing allocated on Datalayer, and the machine itself needs no token.
|
|
72
72
|
'LoopAppComputerExample',
|
|
73
|
+
// Decide, on the local agent-runtimes server as above: Jev is asked
|
|
74
|
+
// through the server's ai-inference, with the server's own key.
|
|
75
|
+
'AgentDecideExample',
|
|
73
76
|
// Runs on the browser sandbox: nothing to allocate, nothing to sign into.
|
|
74
77
|
'LoopShellExample',
|
|
75
78
|
// Temporarily anonymous so the Jupyter output surface can be driven and
|
|
@@ -83,6 +86,8 @@ const ANONYMOUS_EXAMPLES = new Set([
|
|
|
83
86
|
// The floating assistant: the character, its balloon and its motions need
|
|
84
87
|
// no runtime; a conversation does, and says so when there is none.
|
|
85
88
|
'ChatAssistantExample',
|
|
89
|
+
// Every character in every state, from static data: no agent at all.
|
|
90
|
+
'ChatAssistantGalleryExample',
|
|
86
91
|
]);
|
|
87
92
|
const getExampleGroup = (id) => {
|
|
88
93
|
if (id === 'AgentspecsExample' ||
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The floating assistant's characters, every one in every pose, small, for
|
|
3
|
+
* a quick visual check (LOOP T-16, T-22, T-24 to T-27): Datalayer's four and
|
|
4
|
+
* the owl as the enabled plugins contribute them to
|
|
5
|
+
* `loop.assistant.character`, and a test sprite read through the clippy.js
|
|
6
|
+
* reader. Each cell is the real `AssistantStage`, set in the grid's flow
|
|
7
|
+
* rather than fixed to the window; stepped aside is the real `useKeepClear`
|
|
8
|
+
* stepping it aside from a composer laid over the cell.
|
|
9
|
+
*
|
|
10
|
+
* @module examples/utils/AssistantGalleryGrid
|
|
11
|
+
*/
|
|
12
|
+
import type { JSX, ReactNode } from 'react';
|
|
13
|
+
import type { AssistantCharacter } from '../../chat/assistant/characters';
|
|
14
|
+
import type { AssistantCharacterData } from '../../chat/assistant/formats/types';
|
|
15
|
+
/** A character of the gallery: by id, with its name, as contributed. */
|
|
16
|
+
export interface GalleryCharacter {
|
|
17
|
+
id: string;
|
|
18
|
+
name: string;
|
|
19
|
+
character: AssistantCharacter | AssistantCharacterData;
|
|
20
|
+
/** Where it comes from, as the gallery says it. */
|
|
21
|
+
from: string;
|
|
22
|
+
}
|
|
23
|
+
/** What the enabled plugins contribute, in contribution order. */
|
|
24
|
+
export declare const CONTRIBUTED_CHARACTERS: readonly GalleryCharacter[];
|
|
25
|
+
/** The id the test sprite is shown under. */
|
|
26
|
+
export declare const SPRITE_CHARACTER_ID = "sprite";
|
|
27
|
+
/**
|
|
28
|
+
* The gallery's characters: the contributed ones at once, and the test
|
|
29
|
+
* sprite once its files are read; `ready` once they all are.
|
|
30
|
+
*/
|
|
31
|
+
export declare function useGalleryCharacters(): {
|
|
32
|
+
characters: readonly GalleryCharacter[];
|
|
33
|
+
ready: boolean;
|
|
34
|
+
problem?: string;
|
|
35
|
+
};
|
|
36
|
+
/** Its children without motion, as a reader asking for reduced motion sees them. */
|
|
37
|
+
export declare function Still({ still, children, }: {
|
|
38
|
+
still: boolean;
|
|
39
|
+
children: ReactNode;
|
|
40
|
+
}): JSX.Element;
|
|
41
|
+
/**
|
|
42
|
+
* What the assistant steps aside from (T-27): a composer laid over it. The
|
|
43
|
+
* stage's own `useKeepClear` finds it and steps aside.
|
|
44
|
+
*/
|
|
45
|
+
export declare function GalleryObstacle({ sx, }: {
|
|
46
|
+
sx?: Record<string, unknown>;
|
|
47
|
+
}): JSX.Element;
|
|
48
|
+
/** Every character in every pose: a row per character, a column per pose. */
|
|
49
|
+
export declare function AssistantGalleryGrid({ characters, size, }: {
|
|
50
|
+
characters: readonly GalleryCharacter[];
|
|
51
|
+
size?: number;
|
|
52
|
+
}): JSX.Element;
|
|
53
|
+
export default AssistantGalleryGrid;
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useRef, useState } from 'react';
|
|
3
|
+
import { Text } from '@primer/react';
|
|
4
|
+
import { Box } from '@datalayer/primer-addons';
|
|
5
|
+
import { buildReactorFromPlugins } from '@datalayer/reactor';
|
|
6
|
+
import { AssistantStage } from '../../chat/assistant/AssistantStage';
|
|
7
|
+
import { AssistantCharactersPlugin, assistantCharactersOf, } from '../../loop/plugins/assistant-characters';
|
|
8
|
+
import { OWL_CHARACTER, OwlCharacterPlugin } from './owlCharacterPlugin';
|
|
9
|
+
import { readTestSpriteCharacter } from './testSpriteCharacter';
|
|
10
|
+
import { GALLERY_POSES, GALLERY_POSE_LABELS, stateOfPose, } from './assistantGallery';
|
|
11
|
+
/** The plugins the gallery enables: Datalayer's characters and the owl's. */
|
|
12
|
+
const reactor = buildReactorFromPlugins([
|
|
13
|
+
AssistantCharactersPlugin,
|
|
14
|
+
OwlCharacterPlugin,
|
|
15
|
+
]);
|
|
16
|
+
reactor.start();
|
|
17
|
+
/** What the enabled plugins contribute, in contribution order. */
|
|
18
|
+
export const CONTRIBUTED_CHARACTERS = assistantCharactersOf(reactor).map(entry => ({
|
|
19
|
+
id: entry.id,
|
|
20
|
+
name: entry.character.name,
|
|
21
|
+
character: entry.character,
|
|
22
|
+
from: entry.id === OWL_CHARACTER.id ? 'Example plugin' : 'Datalayer',
|
|
23
|
+
}));
|
|
24
|
+
/** The id the test sprite is shown under. */
|
|
25
|
+
export const SPRITE_CHARACTER_ID = 'sprite';
|
|
26
|
+
/**
|
|
27
|
+
* The gallery's characters: the contributed ones at once, and the test
|
|
28
|
+
* sprite once its files are read; `ready` once they all are.
|
|
29
|
+
*/
|
|
30
|
+
export function useGalleryCharacters() {
|
|
31
|
+
const [sprite, setSprite] = useState();
|
|
32
|
+
const [problem, setProblem] = useState();
|
|
33
|
+
useEffect(() => {
|
|
34
|
+
let cancelled = false;
|
|
35
|
+
readTestSpriteCharacter().then(read => {
|
|
36
|
+
if (!cancelled) {
|
|
37
|
+
setSprite(read);
|
|
38
|
+
}
|
|
39
|
+
}, error => {
|
|
40
|
+
if (!cancelled) {
|
|
41
|
+
setProblem(error instanceof Error ? error.message : String(error));
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
return () => {
|
|
45
|
+
cancelled = true;
|
|
46
|
+
};
|
|
47
|
+
}, []);
|
|
48
|
+
// The object URL lives as long as the gallery does.
|
|
49
|
+
useEffect(() => () => {
|
|
50
|
+
if (sprite) {
|
|
51
|
+
URL.revokeObjectURL(sprite.sprite);
|
|
52
|
+
}
|
|
53
|
+
}, [sprite]);
|
|
54
|
+
return {
|
|
55
|
+
characters: sprite
|
|
56
|
+
? [
|
|
57
|
+
...CONTRIBUTED_CHARACTERS,
|
|
58
|
+
{
|
|
59
|
+
id: SPRITE_CHARACTER_ID,
|
|
60
|
+
name: `${sprite.name} (sprite)`,
|
|
61
|
+
character: sprite,
|
|
62
|
+
from: 'clippy.js reader',
|
|
63
|
+
},
|
|
64
|
+
]
|
|
65
|
+
: CONTRIBUTED_CHARACTERS,
|
|
66
|
+
ready: !!sprite || !!problem,
|
|
67
|
+
problem,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
/** Its children without motion, as a reader asking for reduced motion sees them. */
|
|
71
|
+
export function Still({ still, children, }) {
|
|
72
|
+
return (_jsx(Box, { "data-gallery-still": still ? '' : undefined, sx: still ? { '& *': { animation: 'none !important' } } : undefined, children: children }));
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* What the assistant steps aside from (T-27): a composer laid over it. The
|
|
76
|
+
* stage's own `useKeepClear` finds it and steps aside.
|
|
77
|
+
*/
|
|
78
|
+
export function GalleryObstacle({ sx, }) {
|
|
79
|
+
return (_jsx(Box, { "data-chat-composer": "", "aria-label": "A composer over the assistant", sx: {
|
|
80
|
+
position: 'absolute',
|
|
81
|
+
display: 'flex',
|
|
82
|
+
alignItems: 'center',
|
|
83
|
+
justifyContent: 'center',
|
|
84
|
+
border: '1px dashed',
|
|
85
|
+
borderColor: 'border.default',
|
|
86
|
+
borderRadius: 2,
|
|
87
|
+
bg: 'canvas.subtle',
|
|
88
|
+
color: 'fg.muted',
|
|
89
|
+
fontSize: 0,
|
|
90
|
+
textAlign: 'center',
|
|
91
|
+
p: 1,
|
|
92
|
+
...sx,
|
|
93
|
+
}, children: "composer" }));
|
|
94
|
+
}
|
|
95
|
+
function GalleryCell({ character, pose, size, }) {
|
|
96
|
+
const stageRef = useRef(null);
|
|
97
|
+
return (_jsxs(Box, { "data-gallery-cell": `${character.id}-${pose}`, sx: {
|
|
98
|
+
position: 'relative',
|
|
99
|
+
width: size + 16,
|
|
100
|
+
height: size + 16,
|
|
101
|
+
display: 'flex',
|
|
102
|
+
alignItems: 'center',
|
|
103
|
+
justifyContent: 'center',
|
|
104
|
+
}, children: [_jsx(AssistantStage, { character: character.character, state: stateOfPose(pose), size: size, place: { position: 'relative', zIndex: 0 }, stageRef: stageRef, onDragStart: () => undefined, open: false, onToggle: () => undefined, onDismiss: () => undefined }), pose === 'aside' && _jsx(GalleryObstacle, { sx: { inset: 0 } })] }));
|
|
105
|
+
}
|
|
106
|
+
/** Every character in every pose: a row per character, a column per pose. */
|
|
107
|
+
export function AssistantGalleryGrid({ characters, size = 48, }) {
|
|
108
|
+
return (_jsxs(Box, { as: "table", "data-assistant-gallery-grid": "", sx: {
|
|
109
|
+
borderCollapse: 'collapse',
|
|
110
|
+
color: 'fg.default',
|
|
111
|
+
'& th': {
|
|
112
|
+
fontSize: 0,
|
|
113
|
+
fontWeight: 600,
|
|
114
|
+
color: 'fg.muted',
|
|
115
|
+
px: 1,
|
|
116
|
+
py: 1,
|
|
117
|
+
textAlign: 'center',
|
|
118
|
+
whiteSpace: 'nowrap',
|
|
119
|
+
},
|
|
120
|
+
'& td': { p: 0, textAlign: 'center' },
|
|
121
|
+
}, children: [_jsx("thead", { children: _jsxs("tr", { children: [_jsx("th", {}), GALLERY_POSES.map(pose => (_jsx("th", { scope: "col", children: GALLERY_POSE_LABELS[pose] }, pose)))] }) }), _jsx("tbody", { children: characters.map(character => (_jsxs("tr", { children: [_jsxs(Box, { as: "th", scope: "row", sx: { textAlign: 'left !important', pr: '12px !important' }, children: [_jsx(Text, { sx: { display: 'block', color: 'fg.default' }, children: character.name }), _jsx(Text, { sx: { fontWeight: 400 }, children: character.from })] }), GALLERY_POSES.map(pose => (_jsx("td", { children: _jsx(GalleryCell, { character: character, pose: pose, size: size }) }, pose)))] }, character.id))) })] }));
|
|
122
|
+
}
|
|
123
|
+
export default AssistantGalleryGrid;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What the floating assistant's gallery shows (LOOP T-21 to T-27): every
|
|
3
|
+
* state a character acts (T-22), and stepped aside (T-27), with the balloon
|
|
4
|
+
* each one says — the agent's latest saying (T-23), an approval to answer,
|
|
5
|
+
* or that it is paused. Static data only: no agent, no server.
|
|
6
|
+
*
|
|
7
|
+
* @module examples/utils/assistantGallery
|
|
8
|
+
*/
|
|
9
|
+
import type { AssistantStageProps } from '../../chat/assistant/AssistantStage';
|
|
10
|
+
import { type AssistantState, type BalloonApproval } from '../../chat/assistant/state';
|
|
11
|
+
/** What the gallery poses a character in: a state, or stepped aside. */
|
|
12
|
+
export type GalleryPose = AssistantState | 'aside';
|
|
13
|
+
/** Every state, in the order an assistant lives them, then stepped aside. */
|
|
14
|
+
export declare const GALLERY_POSES: readonly ["idle", "greeting", "thinking", "working", "waiting", "speaking", "paused", "aside", "goodbye"];
|
|
15
|
+
/** How the gallery names each pose. */
|
|
16
|
+
export declare const GALLERY_POSE_LABELS: Record<GalleryPose, string>;
|
|
17
|
+
/** The state the stage acts for a pose: aside, it is idle under what covers it. */
|
|
18
|
+
export declare function stateOfPose(pose: GalleryPose): AssistantState;
|
|
19
|
+
/**
|
|
20
|
+
* What the agent said, as a conversation would hold it: each entry is read
|
|
21
|
+
* by `latestSaying`, as the floating assistant reads the chat — Markdown made
|
|
22
|
+
* plain, a long answer cut with *Open the conversation*.
|
|
23
|
+
*/
|
|
24
|
+
export declare const SAMPLE_CONVERSATIONS: readonly (readonly unknown[])[];
|
|
25
|
+
/** The saying of sample `index` (wrapping), as the balloon shows it. */
|
|
26
|
+
export declare function sampleSaying(index: number): {
|
|
27
|
+
text: string;
|
|
28
|
+
more: boolean;
|
|
29
|
+
};
|
|
30
|
+
/** The approval the gallery waits on (T-23): answered in the balloon. */
|
|
31
|
+
export declare function sampleApproval(onApprove: () => void, onDeny: () => void): BalloonApproval;
|
|
32
|
+
/**
|
|
33
|
+
* The balloon for a pose: waiting holds the approval, paused says so, and
|
|
34
|
+
* any other pose says the sample's words when asked to (`saying`).
|
|
35
|
+
*/
|
|
36
|
+
export declare function balloonForPose(pose: GalleryPose, { saying, approval, }: {
|
|
37
|
+
saying?: {
|
|
38
|
+
text: string;
|
|
39
|
+
more: boolean;
|
|
40
|
+
};
|
|
41
|
+
approval: BalloonApproval;
|
|
42
|
+
}): AssistantStageProps['balloon'];
|