@datalayer/agent-runtimes 1.3.30 → 1.3.33
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.js +40 -8
- package/lib/chat/assistant/AssistantStage.d.ts +26 -7
- package/lib/chat/assistant/AssistantStage.js +115 -8
- package/lib/chat/assistant/SpeechBalloon.js +7 -3
- package/lib/chat/assistant/characters.d.ts +32 -1
- package/lib/chat/assistant/characters.js +180 -15
- package/lib/chat/assistant/state.d.ts +28 -0
- package/lib/chat/assistant/state.js +31 -0
- package/lib/chat/base/ChatBase.js +34 -19
- package/lib/chat/base/modelChoice.d.ts +27 -1
- package/lib/chat/base/modelChoice.js +29 -15
- package/lib/chat/prompt/InputPrompt.d.ts +7 -1
- package/lib/chat/prompt/InputPrompt.js +2 -2
- package/lib/chat/prompt/InputPromptBase.js +1 -1
- package/lib/chat/prompt/menus/ModelSelector.d.ts +13 -1
- package/lib/chat/prompt/menus/ModelSelector.js +17 -5
- package/lib/chat/useViewportDrag.d.ts +9 -1
- package/lib/chat/useViewportDrag.js +4 -4
- package/lib/components/a2ui/index.d.ts +2 -0
- package/lib/components/a2ui/index.js +2 -0
- package/lib/components/a2ui/visibility.d.ts +15 -0
- package/lib/components/a2ui/visibility.js +24 -0
- package/lib/components/a2ui/visibleWhen.d.ts +17 -0
- package/lib/components/a2ui/visibleWhen.js +54 -0
- package/lib/examples/ChatAssistantExample.d.ts +4 -0
- package/lib/examples/ChatAssistantExample.js +26 -5
- package/lib/examples/utils/owlCharacterPlugin.d.ts +7 -0
- package/lib/examples/utils/owlCharacterPlugin.js +44 -0
- package/lib/loop/apps/AppFeedback.d.ts +27 -0
- package/lib/loop/apps/AppFeedback.js +78 -0
- package/lib/loop/apps/AppRenderer.js +17 -2
- package/lib/loop/apps/appspec.js +6 -3
- package/lib/loop/apps/checks.d.ts +10 -2
- package/lib/loop/apps/checks.js +21 -10
- package/lib/loop/apps/feedback.d.ts +51 -0
- package/lib/loop/apps/feedback.js +61 -0
- package/lib/loop/apps/index.d.ts +2 -0
- package/lib/loop/apps/index.js +2 -0
- package/lib/loop/apps/rules.d.ts +14 -0
- package/lib/loop/apps/rules.js +24 -0
- package/lib/loop/core/canvasBlocks.d.ts +16 -0
- package/lib/loop/core/canvasBlocks.js +13 -0
- package/lib/loop/core/index.d.ts +7 -0
- package/lib/loop/core/index.js +3 -0
- package/lib/loop/index.d.ts +1 -1
- package/lib/loop/plugins/a2ui/A2uiView.js +2 -3
- package/lib/loop/plugins/a2ui-surface/InlineSurface.d.ts +4 -2
- package/lib/loop/plugins/a2ui-surface/InlineSurface.js +3 -4
- package/lib/loop/plugins/app-page/AppPage.js +1 -1
- package/lib/loop/plugins/app-page/{appPage.d.ts → appPageModel.d.ts} +1 -1
- package/lib/loop/plugins/app-page/index.d.ts +1 -1
- package/lib/loop/plugins/app-page/index.js +2 -2
- package/lib/loop/plugins/canvas-blocks/index.d.ts +63 -0
- package/lib/loop/plugins/canvas-blocks/index.js +118 -0
- package/lib/loop/plugins/chat/ChatView.js +7 -3
- package/lib/loop/plugins/chat/turnState.d.ts +5 -2
- package/lib/loop/plugins/chat/turnState.js +2 -1
- package/lib/specs/actions.js +1 -0
- package/lib/specs/agents/agents.js +16 -4
- package/lib/specs/apps.js +21 -10
- package/lib/specs/appspecSchema.js +13 -7
- package/lib/specs/models.d.ts +1 -1
- package/lib/specs/models.js +8 -8
- package/lib/specs/tools.d.ts +1 -0
- package/lib/specs/tools.js +19 -0
- package/lib/stories/loop/LoopReference.stories.d.ts +21 -0
- package/lib/stories/loop/LoopReference.stories.js +31 -0
- package/lib/stories/loop/ReferenceScreens.d.ts +53 -0
- package/lib/stories/loop/ReferenceScreens.js +256 -0
- package/lib/stories/loop/pictures-main.d.ts +2 -0
- package/lib/stories/loop/pictures-main.js +75 -0
- package/lib/types/agentspecs.d.ts +6 -1
- package/lib/types/chat.d.ts +5 -0
- package/lib/types/config.d.ts +8 -0
- package/package.json +9 -6
- package/scripts/check-cloudflare-models.py +2 -2
- package/scripts/codegen/generate_apps.py +2 -1
- package/scripts/codegen/generate_models.py +4 -4
- /package/lib/loop/plugins/app-page/{appPage.js → appPageModel.js} +0 -0
|
@@ -60,3 +60,31 @@ export declare const ASSISTANT_AWAY_KEY = "datalayer-assistant-away";
|
|
|
60
60
|
export declare function keptAway(): AssistantAway;
|
|
61
61
|
/** Keep the choice where it lasts as long as it says; `none` forgets it. */
|
|
62
62
|
export declare function keepAway(away: AssistantAway): void;
|
|
63
|
+
/** A box on the screen, as `getBoundingClientRect` gives it. */
|
|
64
|
+
export interface ScreenBox {
|
|
65
|
+
left: number;
|
|
66
|
+
top: number;
|
|
67
|
+
right: number;
|
|
68
|
+
bottom: number;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* What the assistant never sits over (T-27): an open dialog or overlay —
|
|
72
|
+
* Primer's `Dialog`, an `ActionMenu` or `SelectPanel` overlay, a native
|
|
73
|
+
* `<dialog>` — and the composer of a chat.
|
|
74
|
+
*/
|
|
75
|
+
export declare const ASSISTANT_OBSTACLES: string;
|
|
76
|
+
/** How near the pointer works, in pixels, before the assistant steps aside. */
|
|
77
|
+
export declare const POINTER_ROOM = 24;
|
|
78
|
+
/** How long the pointer stays away before the assistant comes back, in ms. */
|
|
79
|
+
export declare const POINTER_CALM_MS = 1500;
|
|
80
|
+
/** Whether two boxes share any area, the first grown by `margin`. */
|
|
81
|
+
export declare function boxesMeet(a: ScreenBox, b: ScreenBox, margin?: number): boolean;
|
|
82
|
+
/**
|
|
83
|
+
* Whether the pointer at `point` works where the assistant stands: over it,
|
|
84
|
+
* or within `POINTER_ROOM` of it — a press beside it is aimed at what it
|
|
85
|
+
* hides or crowds.
|
|
86
|
+
*/
|
|
87
|
+
export declare function pointerNear(box: ScreenBox, point: {
|
|
88
|
+
x: number;
|
|
89
|
+
y: number;
|
|
90
|
+
}, room?: number): boolean;
|
|
@@ -114,3 +114,34 @@ export function keepAway(away) {
|
|
|
114
114
|
// Without storage the choice holds for the page.
|
|
115
115
|
}
|
|
116
116
|
}
|
|
117
|
+
/**
|
|
118
|
+
* What the assistant never sits over (T-27): an open dialog or overlay —
|
|
119
|
+
* Primer's `Dialog`, an `ActionMenu` or `SelectPanel` overlay, a native
|
|
120
|
+
* `<dialog>` — and the composer of a chat.
|
|
121
|
+
*/
|
|
122
|
+
export const ASSISTANT_OBSTACLES = [
|
|
123
|
+
'[role="dialog"]',
|
|
124
|
+
'[role="alertdialog"]',
|
|
125
|
+
'dialog[open]',
|
|
126
|
+
'[class*="prc-Overlay-Overlay"]',
|
|
127
|
+
'[data-chat-composer]',
|
|
128
|
+
].join(', ');
|
|
129
|
+
/** How near the pointer works, in pixels, before the assistant steps aside. */
|
|
130
|
+
export const POINTER_ROOM = 24;
|
|
131
|
+
/** How long the pointer stays away before the assistant comes back, in ms. */
|
|
132
|
+
export const POINTER_CALM_MS = 1500;
|
|
133
|
+
/** Whether two boxes share any area, the first grown by `margin`. */
|
|
134
|
+
export function boxesMeet(a, b, margin = 0) {
|
|
135
|
+
return (a.left - margin < b.right &&
|
|
136
|
+
b.left < a.right + margin &&
|
|
137
|
+
a.top - margin < b.bottom &&
|
|
138
|
+
b.top < a.bottom + margin);
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Whether the pointer at `point` works where the assistant stands: over it,
|
|
142
|
+
* or within `POINTER_ROOM` of it — a press beside it is aimed at what it
|
|
143
|
+
* hides or crowds.
|
|
144
|
+
*/
|
|
145
|
+
export function pointerNear(box, point, room = POINTER_ROOM) {
|
|
146
|
+
return boxesMeet(box, { left: point.x, top: point.y, right: point.x, bottom: point.y }, room);
|
|
147
|
+
}
|
|
@@ -1400,7 +1400,7 @@ showToolApprovalBanner = true, pendingApprovals: pendingApprovalsProp, onApprove
|
|
|
1400
1400
|
* four are current.
|
|
1401
1401
|
*/
|
|
1402
1402
|
const catalogued = Object.values(AI_MODEL_CATALOGUE)
|
|
1403
|
-
// A typed-
|
|
1403
|
+
// A typed-decision model answers typed questions, not a chat.
|
|
1404
1404
|
.filter(model => model.available && isChatModel(model))
|
|
1405
1405
|
.map(model => ({
|
|
1406
1406
|
id: model.id,
|
|
@@ -2124,9 +2124,13 @@ showToolApprovalBanner = true, pendingApprovals: pendingApprovalsProp, onApprove
|
|
|
2124
2124
|
const store = useConversationStore.getState();
|
|
2125
2125
|
const currentlyFetching = store.isFetching(historyScopeId);
|
|
2126
2126
|
const storedMessages = store.getMessages(historyScopeId);
|
|
2127
|
-
// 1) Fast local hydration for view switches in the same browser session
|
|
2127
|
+
// 1) Fast local hydration for view switches in the same browser session:
|
|
2128
|
+
// only into an empty conversation. The saved copy holds messages, not
|
|
2129
|
+
// tool calls, and this effect runs again on every change of the socket's
|
|
2130
|
+
// state — put over a live conversation, it erased its tool cards, a
|
|
2131
|
+
// pending approval among them, at the socket's first retry.
|
|
2128
2132
|
if (storedMessages.length > 0) {
|
|
2129
|
-
setDisplayItems(storedMessages);
|
|
2133
|
+
setDisplayItems(prev => (prev.length > 0 ? prev : storedMessages));
|
|
2130
2134
|
setHistoryLoaded(true);
|
|
2131
2135
|
}
|
|
2132
2136
|
if (currentlyFetching) {
|
|
@@ -2384,16 +2388,24 @@ showToolApprovalBanner = true, pendingApprovals: pendingApprovalsProp, onApprove
|
|
|
2384
2388
|
const incomingId = event.message.id;
|
|
2385
2389
|
const currentId = currentAssistantMessageRef.current?.id;
|
|
2386
2390
|
const isNewMessage = !currentId || (incomingId && incomingId !== currentId);
|
|
2387
|
-
if (
|
|
2391
|
+
if (currentId && !isNewMessage) {
|
|
2392
|
+
/*
|
|
2393
|
+
* The message to write to is the one current now, as the event
|
|
2394
|
+
* arrives — not whichever the ref names when React gets round
|
|
2395
|
+
* to running the updater. A whole answer in one network chunk
|
|
2396
|
+
* queues every delta's updater in the same task, and the turn's
|
|
2397
|
+
* end clears the ref before any of them runs: read lazily, all
|
|
2398
|
+
* but the first found nothing to update, and the conversation
|
|
2399
|
+
* and the balloon showed only the answer's first word.
|
|
2400
|
+
*/
|
|
2401
|
+
const rawContent = event.message.content;
|
|
2402
|
+
const sanitizedContent = typeof rawContent === 'string'
|
|
2403
|
+
? sanitizeAssistantContent(rawContent)
|
|
2404
|
+
: (rawContent ?? '');
|
|
2388
2405
|
setDisplayItems(prev => {
|
|
2389
2406
|
const newItems = [...prev];
|
|
2390
|
-
const idx = newItems.findIndex(item => !isToolCallMessage(item) &&
|
|
2391
|
-
item.id === currentAssistantMessageRef.current?.id);
|
|
2407
|
+
const idx = newItems.findIndex(item => !isToolCallMessage(item) && item.id === currentId);
|
|
2392
2408
|
if (idx >= 0 && !isToolCallMessage(newItems[idx])) {
|
|
2393
|
-
const rawContent = event.message?.content;
|
|
2394
|
-
const sanitizedContent = typeof rawContent === 'string'
|
|
2395
|
-
? sanitizeAssistantContent(rawContent)
|
|
2396
|
-
: (rawContent ?? '');
|
|
2397
2409
|
newItems[idx] = {
|
|
2398
2410
|
...newItems[idx],
|
|
2399
2411
|
content: sanitizedContent,
|
|
@@ -2401,14 +2413,8 @@ showToolApprovalBanner = true, pendingApprovals: pendingApprovalsProp, onApprove
|
|
|
2401
2413
|
}
|
|
2402
2414
|
return newItems;
|
|
2403
2415
|
});
|
|
2404
|
-
if (useStoreMode
|
|
2405
|
-
|
|
2406
|
-
const sanitizedContent = typeof rawContent === 'string'
|
|
2407
|
-
? sanitizeAssistantContent(rawContent)
|
|
2408
|
-
: (rawContent ?? '');
|
|
2409
|
-
useChatStore
|
|
2410
|
-
.getState()
|
|
2411
|
-
.updateMessage(currentAssistantMessageRef.current.id, {
|
|
2416
|
+
if (useStoreMode) {
|
|
2417
|
+
useChatStore.getState().updateMessage(currentId, {
|
|
2412
2418
|
content: sanitizedContent,
|
|
2413
2419
|
});
|
|
2414
2420
|
}
|
|
@@ -3096,6 +3102,7 @@ showToolApprovalBanner = true, pendingApprovals: pendingApprovalsProp, onApprove
|
|
|
3096
3102
|
// The same reset the header's + performs, for a host whose controls
|
|
3097
3103
|
// live outside this component — the LOOP prompt's + reaches it here.
|
|
3098
3104
|
newChat: handleNewChat,
|
|
3105
|
+
thread: () => threadIdRef.current,
|
|
3099
3106
|
});
|
|
3100
3107
|
return () => {
|
|
3101
3108
|
onSendReady(null);
|
|
@@ -3490,7 +3497,15 @@ showToolApprovalBanner = true, pendingApprovals: pendingApprovalsProp, onApprove
|
|
|
3490
3497
|
promptHistory: configQuery.data?.promptHistory, showTokenUsage: showTokenUsage, showContextRing: showContextRing, agentUsage: agentUsage, showModelSelector: showModelSelector, showToolsMenu: showToolsMenu, showSkillsMenu: showSkillsMenu, codemodeEnabled: codemodeEnabled, onToggleCodemode: onToggleCodemode, isA2AProtocol: isA2AProtocol, showAgentsMenu: showAgentsMenu, agents: footerAgents, selectedAgentId: selectedAgentId ?? footerAgents[0]?.id, onSelectAgent: onSelectAgent, hasConfigData: !!configQuery.data, hasSkillsData: !!skillsQuery.data,
|
|
3491
3498
|
// So the bar can tell "not here yet" from "not coming": a chat whose
|
|
3492
3499
|
// agent has no config endpoint waits for ever otherwise.
|
|
3493
|
-
configLoading: configQuery.isLoading, models: offeredModels,
|
|
3500
|
+
configLoading: configQuery.isLoading, models: offeredModels,
|
|
3501
|
+
// Listed apart and read-only: a typed-decision model is never the
|
|
3502
|
+
// agent's model.
|
|
3503
|
+
decisions: configQuery.data
|
|
3504
|
+
? {
|
|
3505
|
+
models: configQuery.data.decisionModels,
|
|
3506
|
+
note: configQuery.data.decisionsNote,
|
|
3507
|
+
}
|
|
3508
|
+
: undefined, selectedModel: selectedModel, onModelSelect: setSelectedModel, availableTools: builtinTools, mcpServers: filteredMcpServers, enabledMcpTools: enabledMcpTools, enabledMcpToolCount: getEnabledMcpToolNames().length, onToggleMcpTool: toggleMcpTool, onToggleAllMcpServerTools: toggleAllMcpServerTools, approvedMcpTools: approvedMcpTools, onToggleMcpToolApproval: toggleMcpToolApproval, skills: skillsQuery.data?.skills || [], skillsLoading: !!skillsQuery.isLoading, enabledSkills: enabledSkills, onToggleSkill: toggleSkill, onToggleAllSkills: toggleAllSkills, approvedSkills: approvedSkills, onToggleSkillApproval: toggleSkillApproval, apiBase: indicatorApiBase, authToken: protocol?.authToken, mcpStatusData: effectiveMcpStatusData })) : null;
|
|
3494
3509
|
// Shared header element. It is rendered either at the top of the chat (when
|
|
3495
3510
|
// no ephemeral notebook is shown) or INSIDE the chat body column (when the
|
|
3496
3511
|
// notebook is visible) so the header always follows the chat body across all
|
|
@@ -57,9 +57,28 @@ export type ServerCatalogueModel = {
|
|
|
57
57
|
name?: string;
|
|
58
58
|
available?: boolean;
|
|
59
59
|
missing_env_vars?: string[];
|
|
60
|
-
reason?: string;
|
|
60
|
+
reason?: string | null;
|
|
61
61
|
warning?: string | null;
|
|
62
62
|
};
|
|
63
|
+
/**
|
|
64
|
+
* The typed-decision models a runtime lists apart (Jev).
|
|
65
|
+
*
|
|
66
|
+
* They answer a decision's typed questions, not a conversation: the menu
|
|
67
|
+
* shows them read-only, under their own heading, with `note` saying so, and
|
|
68
|
+
* never offers one as the agent's model.
|
|
69
|
+
*/
|
|
70
|
+
export type Decisions = {
|
|
71
|
+
models: ModelConfig[];
|
|
72
|
+
note: string;
|
|
73
|
+
};
|
|
74
|
+
/** The runtime's `/configure/models` answer, as far as the chat reads it. */
|
|
75
|
+
export type ServerCatalogue = {
|
|
76
|
+
models?: ServerCatalogueModel[];
|
|
77
|
+
source?: string;
|
|
78
|
+
note?: string;
|
|
79
|
+
decision_models: ServerCatalogueModel[];
|
|
80
|
+
decisions_note: string;
|
|
81
|
+
};
|
|
63
82
|
/**
|
|
64
83
|
* The server's catalogue in the chat's shape.
|
|
65
84
|
*
|
|
@@ -73,3 +92,10 @@ export declare function readServerCatalogue(payload: {
|
|
|
73
92
|
source?: string;
|
|
74
93
|
note?: string;
|
|
75
94
|
} | null | undefined): ModelConfig[];
|
|
95
|
+
/**
|
|
96
|
+
* The typed-decision models of the runtime's answer, in the chat's shape.
|
|
97
|
+
*
|
|
98
|
+
* Read apart from `readServerCatalogue`, so no list a chat picks its model
|
|
99
|
+
* from ever holds one.
|
|
100
|
+
*/
|
|
101
|
+
export declare function readServerDecisions(payload: ServerCatalogue): Decisions;
|
|
@@ -51,19 +51,33 @@ export function initialModelId(offered, preferred) {
|
|
|
51
51
|
* its spec was known went to the first row — Alibaba, and its missing key.
|
|
52
52
|
*/
|
|
53
53
|
export function readServerCatalogue(payload) {
|
|
54
|
-
return (payload?.models ?? []).map(
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
54
|
+
return (payload?.models ?? []).map(readServerModel);
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* The typed-decision models of the runtime's answer, in the chat's shape.
|
|
58
|
+
*
|
|
59
|
+
* Read apart from `readServerCatalogue`, so no list a chat picks its model
|
|
60
|
+
* from ever holds one.
|
|
61
|
+
*/
|
|
62
|
+
export function readServerDecisions(payload) {
|
|
63
|
+
return {
|
|
64
|
+
models: payload.decision_models.map(readServerModel),
|
|
65
|
+
note: payload.decisions_note,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
/** One row of the runtime's answer, in the chat's shape. */
|
|
69
|
+
function readServerModel(model) {
|
|
70
|
+
const missing = model.missing_env_vars ?? [];
|
|
71
|
+
const reason = model.reason ??
|
|
72
|
+
(missing.length > 0 ? `Set ${missing.join(', ')}` : undefined) ??
|
|
73
|
+
model.warning ??
|
|
74
|
+
undefined;
|
|
75
|
+
return {
|
|
76
|
+
id: model.id,
|
|
77
|
+
name: model.name ?? model.id,
|
|
78
|
+
isAvailable: model.available !== false,
|
|
79
|
+
...(reason && model.available === false
|
|
80
|
+
? { unavailableReason: reason }
|
|
81
|
+
: {}),
|
|
82
|
+
};
|
|
69
83
|
}
|
|
@@ -16,6 +16,7 @@ import type { PromptSuggestion } from './menus/SuggestionsMenu';
|
|
|
16
16
|
import type { MentionableAgent } from './plugins/AgentMentionPlugin';
|
|
17
17
|
/** One agent the footer may offer. */
|
|
18
18
|
import type { FooterAgent } from '../../types/chat';
|
|
19
|
+
import type { Decisions } from '../base/modelChoice';
|
|
19
20
|
export type { FooterAgent };
|
|
20
21
|
/** Where the prompt stands: in the flow, or in a draggable card over it. */
|
|
21
22
|
export type InputPromptPlacement = 'docked' | 'floating';
|
|
@@ -187,6 +188,11 @@ export interface InputPromptProps {
|
|
|
187
188
|
*/
|
|
188
189
|
configLoading?: boolean;
|
|
189
190
|
models?: ModelConfig[];
|
|
191
|
+
/**
|
|
192
|
+
* The typed-decision models the runtime lists apart (Jev): shown read-only
|
|
193
|
+
* under the models, never one to pick. See `modelChoice`'s `Decisions`.
|
|
194
|
+
*/
|
|
195
|
+
decisions?: Decisions;
|
|
190
196
|
selectedModel?: string;
|
|
191
197
|
onModelSelect?: (modelId: string) => void;
|
|
192
198
|
availableTools?: BuiltinTool[];
|
|
@@ -214,4 +220,4 @@ export interface InputPromptProps {
|
|
|
214
220
|
/** Pre-fetched MCP status from WebSocket — bypasses REST polling */
|
|
215
221
|
mcpStatusData?: McpToolsetsStatusResponse | null;
|
|
216
222
|
}
|
|
217
|
-
export declare function InputPrompt({ input, setInput, isLoading, kernelStatus, connectionConfirmed, placeholder, typingSuggestions, autoFocus, focusTrigger, padding, placement, floatingAnchor, draggable, container, footerExtras, leadingPanel, trailingPanel, onSend, onStop, disableInputPrompt, promptVariant, mentionableAgents, promptHistory, headerContent, showAgentsMenu, showInlineAgentsMenu, agents, selectedAgentId, onSelectAgent, showTokenUsage, showContextRing, agentUsage, showModelSelector, showToolsMenu, showSkillsMenu, showSuggestionsMenu, suggestions, codemodeEnabled, onToggleCodemode, isA2AProtocol, hasConfigData, hasSkillsData, configLoading, models, selectedModel, onModelSelect, availableTools, mcpServers, enabledMcpTools, enabledMcpToolCount, onToggleMcpTool, onToggleAllMcpServerTools, approvedMcpTools, onToggleMcpToolApproval, skills, skillsLoading, enabledSkills, onToggleSkill, onToggleAllSkills, approvedSkills, onToggleSkillApproval, apiBase, authToken, mcpStatusData, }: InputPromptProps): import("react").JSX.Element;
|
|
223
|
+
export declare function InputPrompt({ input, setInput, isLoading, kernelStatus, connectionConfirmed, placeholder, typingSuggestions, autoFocus, focusTrigger, padding, placement, floatingAnchor, draggable, container, footerExtras, leadingPanel, trailingPanel, onSend, onStop, disableInputPrompt, promptVariant, mentionableAgents, promptHistory, headerContent, showAgentsMenu, showInlineAgentsMenu, agents, selectedAgentId, onSelectAgent, showTokenUsage, showContextRing, agentUsage, showModelSelector, showToolsMenu, showSkillsMenu, showSuggestionsMenu, suggestions, codemodeEnabled, onToggleCodemode, isA2AProtocol, hasConfigData, hasSkillsData, configLoading, models, decisions, selectedModel, onModelSelect, availableTools, mcpServers, enabledMcpTools, enabledMcpToolCount, onToggleMcpTool, onToggleAllMcpServerTools, approvedMcpTools, onToggleMcpToolApproval, skills, skillsLoading, enabledSkills, onToggleSkill, onToggleAllSkills, approvedSkills, onToggleSkillApproval, apiBase, authToken, mcpStatusData, }: InputPromptProps): import("react").JSX.Element;
|
|
@@ -29,7 +29,7 @@ const EMPTY_ID_SET = new Set();
|
|
|
29
29
|
// ---------------------------------------------------------------------------
|
|
30
30
|
// Component
|
|
31
31
|
// ---------------------------------------------------------------------------
|
|
32
|
-
export function InputPrompt({ input, setInput, isLoading, kernelStatus, connectionConfirmed, placeholder, typingSuggestions, autoFocus, focusTrigger, padding, placement, floatingAnchor = 'bottom', draggable = false, container, footerExtras, leadingPanel, trailingPanel, onSend, onStop, disableInputPrompt = false, promptVariant, mentionableAgents, promptHistory, headerContent, showAgentsMenu = false, showInlineAgentsMenu = true, agents = [], selectedAgentId, onSelectAgent, showTokenUsage, showContextRing = false, agentUsage, showModelSelector, showToolsMenu, showSkillsMenu, showSuggestionsMenu = true, suggestions, codemodeEnabled, onToggleCodemode, isA2AProtocol, hasConfigData, hasSkillsData, configLoading = false, models = [], selectedModel = '', onModelSelect = () => { }, availableTools = [], mcpServers = [], enabledMcpTools = EMPTY_TOOL_MAP, enabledMcpToolCount = 0, onToggleMcpTool = () => { }, onToggleAllMcpServerTools = () => { }, approvedMcpTools = EMPTY_TOOL_MAP, onToggleMcpToolApproval = () => { }, skills = [], skillsLoading = false, enabledSkills = EMPTY_ID_SET, onToggleSkill = () => { }, onToggleAllSkills = () => { }, approvedSkills = EMPTY_ID_SET, onToggleSkillApproval = () => { }, apiBase, authToken, mcpStatusData, }) {
|
|
32
|
+
export function InputPrompt({ input, setInput, isLoading, kernelStatus, connectionConfirmed, placeholder, typingSuggestions, autoFocus, focusTrigger, padding, placement, floatingAnchor = 'bottom', draggable = false, container, footerExtras, leadingPanel, trailingPanel, onSend, onStop, disableInputPrompt = false, promptVariant, mentionableAgents, promptHistory, headerContent, showAgentsMenu = false, showInlineAgentsMenu = true, agents = [], selectedAgentId, onSelectAgent, showTokenUsage, showContextRing = false, agentUsage, showModelSelector, showToolsMenu, showSkillsMenu, showSuggestionsMenu = true, suggestions, codemodeEnabled, onToggleCodemode, isA2AProtocol, hasConfigData, hasSkillsData, configLoading = false, models = [], decisions, selectedModel = '', onModelSelect = () => { }, availableTools = [], mcpServers = [], enabledMcpTools = EMPTY_TOOL_MAP, enabledMcpToolCount = 0, onToggleMcpTool = () => { }, onToggleAllMcpServerTools = () => { }, approvedMcpTools = EMPTY_TOOL_MAP, onToggleMcpToolApproval = () => { }, skills = [], skillsLoading = false, enabledSkills = EMPTY_ID_SET, onToggleSkill = () => { }, onToggleAllSkills = () => { }, approvedSkills = EMPTY_ID_SET, onToggleSkillApproval = () => { }, apiBase, authToken, mcpStatusData, }) {
|
|
33
33
|
const isKernelBusy = kernelStatus === 'busy';
|
|
34
34
|
/*
|
|
35
35
|
* Each menu is offered when it is switched on *and* has something behind it.
|
|
@@ -143,7 +143,7 @@ export function InputPrompt({ input, setInput, isLoading, kernelStatus, connecti
|
|
|
143
143
|
minHeight: 36,
|
|
144
144
|
bordered: true,
|
|
145
145
|
subtle: true,
|
|
146
|
-
content: (_jsx(_Fragment, { children: anyOffered || extrasOffered || suggestionsOffered ? (_jsxs(_Fragment, { children: [agentsOffered && (_jsx(AgentsMenu, { agents: agents, selectedAgentId: selectedAgentId, onSelectAgent: onSelectAgent })), toolsOffered && (_jsx(ToolsMenu, { codemodeEnabled: codemodeEnabled, onToggleCodemode: onToggleCodemode, mcpServers: mcpServers, enabledMcpTools: enabledMcpTools, enabledMcpToolCount: enabledMcpToolCount, onToggleMcpTool: onToggleMcpTool, onToggleAllMcpServerTools: onToggleAllMcpServerTools, approvedMcpTools: approvedMcpTools, onToggleMcpToolApproval: onToggleMcpToolApproval, availableTools: availableTools })), skillsOffered && (_jsx(SkillsMenu, { skills: skills, skillsLoading: skillsLoading, enabledSkills: enabledSkills, onToggleSkill: onToggleSkill, onToggleAllSkills: onToggleAllSkills, approvedSkills: approvedSkills, onToggleSkillApproval: onToggleSkillApproval })), modelsOffered && (_jsx(ModelSelector, { models: models, selectedModel: selectedModel, onModelSelect: onModelSelect, isA2AProtocol: isA2AProtocol })), suggestionsOffered && (_jsx(SuggestionsMenu, { suggestions: suggestionItems, onPick: text => {
|
|
146
|
+
content: (_jsx(_Fragment, { children: anyOffered || extrasOffered || suggestionsOffered ? (_jsxs(_Fragment, { children: [agentsOffered && (_jsx(AgentsMenu, { agents: agents, selectedAgentId: selectedAgentId, onSelectAgent: onSelectAgent })), toolsOffered && (_jsx(ToolsMenu, { codemodeEnabled: codemodeEnabled, onToggleCodemode: onToggleCodemode, mcpServers: mcpServers, enabledMcpTools: enabledMcpTools, enabledMcpToolCount: enabledMcpToolCount, onToggleMcpTool: onToggleMcpTool, onToggleAllMcpServerTools: onToggleAllMcpServerTools, approvedMcpTools: approvedMcpTools, onToggleMcpToolApproval: onToggleMcpToolApproval, availableTools: availableTools })), skillsOffered && (_jsx(SkillsMenu, { skills: skills, skillsLoading: skillsLoading, enabledSkills: enabledSkills, onToggleSkill: onToggleSkill, onToggleAllSkills: onToggleAllSkills, approvedSkills: approvedSkills, onToggleSkillApproval: onToggleSkillApproval })), modelsOffered && (_jsx(ModelSelector, { models: models, decisions: decisions, selectedModel: selectedModel, onModelSelect: onModelSelect, isA2AProtocol: isA2AProtocol })), suggestionsOffered && (_jsx(SuggestionsMenu, { suggestions: suggestionItems, onPick: text => {
|
|
147
147
|
setInput(text);
|
|
148
148
|
setPickedFocus(n => n + 1);
|
|
149
149
|
} })), extrasOffered && (_jsx(Box, { sx: {
|
|
@@ -192,7 +192,7 @@ export function InputPromptBase({ variant = 'lexical', placeholder = 'Ask anythi
|
|
|
192
192
|
, {
|
|
193
193
|
// Named so the turn-end refocus can ask whether the caret is already
|
|
194
194
|
// somewhere inside this prompt before it reaches for it.
|
|
195
|
-
ref: containerRef, onFocusCapture: () => {
|
|
195
|
+
ref: containerRef, "data-chat-composer": "", onFocusCapture: () => {
|
|
196
196
|
if (selfFocused.current) {
|
|
197
197
|
selfFocused.current = false;
|
|
198
198
|
return;
|
|
@@ -1,6 +1,18 @@
|
|
|
1
1
|
import type { ModelConfig } from '../../../types';
|
|
2
|
-
|
|
2
|
+
import type { Decisions } from '../../base/modelChoice';
|
|
3
|
+
/**
|
|
4
|
+
* The typed-decision models, read-only under the models.
|
|
5
|
+
*
|
|
6
|
+
* A decision asks them through `/decisions`; an agent cannot run on one, so
|
|
7
|
+
* no row here selects anything. Each says so, in the runtime's sentence, and
|
|
8
|
+
* why it cannot be used when it cannot — the same rule as the models above.
|
|
9
|
+
*/
|
|
10
|
+
export declare function DecisionsGroup({ decisions }: {
|
|
11
|
+
decisions: Decisions;
|
|
12
|
+
}): import("react").JSX.Element;
|
|
13
|
+
export declare function ModelSelector({ models, decisions, selectedModel, onModelSelect, isA2AProtocol, }: {
|
|
3
14
|
models: ModelConfig[];
|
|
15
|
+
decisions?: Decisions;
|
|
4
16
|
selectedModel: string;
|
|
5
17
|
onModelSelect: (modelId: string) => void;
|
|
6
18
|
isA2AProtocol: boolean;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
/*
|
|
3
3
|
* Copyright (c) 2025-2026 Datalayer, Inc.
|
|
4
4
|
* Distributed under the terms of the Modified BSD License.
|
|
@@ -11,7 +11,19 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
11
11
|
import { Text, Button, ActionMenu, ActionList, Tooltip } from '@primer/react';
|
|
12
12
|
import { Box } from '@datalayer/primer-addons';
|
|
13
13
|
import { AiModelIcon } from '@primer/octicons-react';
|
|
14
|
-
|
|
14
|
+
/**
|
|
15
|
+
* The typed-decision models, read-only under the models.
|
|
16
|
+
*
|
|
17
|
+
* A decision asks them through `/decisions`; an agent cannot run on one, so
|
|
18
|
+
* no row here selects anything. Each says so, in the runtime's sentence, and
|
|
19
|
+
* why it cannot be used when it cannot — the same rule as the models above.
|
|
20
|
+
*/
|
|
21
|
+
export function DecisionsGroup({ decisions }) {
|
|
22
|
+
return (_jsxs(ActionList.Group, { selectionVariant: false, children: [_jsx(ActionList.GroupHeading, { children: "Decisions" }), decisions.models.map(model => (_jsxs(ActionList.Item, { disabled: true, sx: { color: 'fg.muted' }, children: [model.name, _jsx(ActionList.Description, { variant: "block", children: model.isAvailable === false
|
|
23
|
+
? `${model.unavailableReason ?? 'Not usable here'} · ${decisions.note}`
|
|
24
|
+
: decisions.note })] }, model.id)))] }));
|
|
25
|
+
}
|
|
26
|
+
export function ModelSelector({ models, decisions, selectedModel, onModelSelect, isA2AProtocol, }) {
|
|
15
27
|
const active = models.find(model => model.id === selectedModel);
|
|
16
28
|
/*
|
|
17
29
|
* A count, not a name — the same trigger as tools, skills, agents and
|
|
@@ -28,7 +40,7 @@ export function ModelSelector({ models, selectedModel, onModelSelect, isA2AProto
|
|
|
28
40
|
alignItems: 'flex-end',
|
|
29
41
|
}, children: [_jsxs(ActionMenu, { children: [_jsx(ActionMenu.Anchor, { children: _jsx(Tooltip, { text: `Model — ${summary}`, direction: "n", children: _jsx(Button, { type: "button", variant: "invisible", size: "small", "aria-label": `Model — ${summary}`, leadingVisual: AiModelIcon, disabled: isA2AProtocol, sx: isA2AProtocol
|
|
30
42
|
? { opacity: 0.5, cursor: 'not-allowed' }
|
|
31
|
-
: undefined, children: _jsx(Text, { sx: { fontSize: 0 }, children: models.length }) }) }) }), _jsx(ActionMenu.Overlay, { side: "outside-top", align: "end", children:
|
|
32
|
-
|
|
33
|
-
|
|
43
|
+
: undefined, children: _jsx(Text, { sx: { fontSize: 0 }, children: models.length }) }) }) }), _jsx(ActionMenu.Overlay, { side: "outside-top", align: "end", children: _jsxs(ActionList, { selectionVariant: "single", children: [models.map(modelItem => (_jsxs(ActionList.Item, { selected: selectedModel === modelItem.id, onSelect: () => onModelSelect(modelItem.id), disabled: modelItem.isAvailable === false || isA2AProtocol, sx: modelItem.isAvailable === false
|
|
44
|
+
? { color: 'fg.muted' }
|
|
45
|
+
: undefined, children: [modelItem.name, modelItem.isAvailable === false && (_jsx(ActionList.Description, { variant: "block", children: modelItem.unavailableReason ?? 'Missing API key' }))] }, modelItem.id))), decisions && decisions.models.length > 0 && (_jsxs(_Fragment, { children: [_jsx(ActionList.Divider, {}), _jsx(DecisionsGroup, { decisions: decisions })] }))] }) })] }), isA2AProtocol && (_jsx(Text, { sx: { fontSize: 0, color: 'attention.fg', mt: 1 }, children: "A2A: Model set by agent config" }))] }));
|
|
34
46
|
}
|
|
@@ -3,7 +3,15 @@ export type DragPosition = {
|
|
|
3
3
|
left: number;
|
|
4
4
|
top: number;
|
|
5
5
|
} | null;
|
|
6
|
-
export
|
|
6
|
+
export interface ViewportDragOptions {
|
|
7
|
+
/**
|
|
8
|
+
* Keep the whole box inside the viewport, not only a margin of it: the
|
|
9
|
+
* floating assistant's character, whose balloon and conversation open
|
|
10
|
+
* from where it stands (LOOP T-23).
|
|
11
|
+
*/
|
|
12
|
+
whole?: boolean;
|
|
13
|
+
}
|
|
14
|
+
export declare function useViewportDrag(boxRef: React.RefObject<HTMLElement | null>, { whole }?: ViewportDragOptions): {
|
|
7
15
|
position: DragPosition;
|
|
8
16
|
onHandlePointerDown: (event: React.PointerEvent<HTMLElement>) => void;
|
|
9
17
|
reset: () => void;
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
import { useCallback, useRef, useState } from 'react';
|
|
18
18
|
/** How much of the box must stay inside the viewport. */
|
|
19
19
|
const MARGIN = 24;
|
|
20
|
-
export function useViewportDrag(boxRef) {
|
|
20
|
+
export function useViewportDrag(boxRef, { whole = false } = {}) {
|
|
21
21
|
const [position, setPosition] = useState(null);
|
|
22
22
|
/* Where the pointer took hold, so the box moves by the pointer's delta
|
|
23
23
|
rather than snapping its corner to the cursor. */
|
|
@@ -39,8 +39,8 @@ export function useViewportDrag(boxRef) {
|
|
|
39
39
|
if (!grip.current) {
|
|
40
40
|
return;
|
|
41
41
|
}
|
|
42
|
-
const left = Math.min(Math.max(moved.clientX - grip.current.dx, MARGIN - rect.width), window.innerWidth - MARGIN);
|
|
43
|
-
const top = Math.min(Math.max(moved.clientY - grip.current.dy, 0), window.innerHeight - MARGIN);
|
|
42
|
+
const left = Math.min(Math.max(moved.clientX - grip.current.dx, whole ? 0 : MARGIN - rect.width), window.innerWidth - (whole ? rect.width : MARGIN));
|
|
43
|
+
const top = Math.min(Math.max(moved.clientY - grip.current.dy, 0), window.innerHeight - (whole ? rect.height : MARGIN));
|
|
44
44
|
setPosition({ left, top });
|
|
45
45
|
};
|
|
46
46
|
const up = () => {
|
|
@@ -53,7 +53,7 @@ export function useViewportDrag(boxRef) {
|
|
|
53
53
|
handle.addEventListener('pointerup', up);
|
|
54
54
|
handle.addEventListener('pointercancel', up);
|
|
55
55
|
event.preventDefault();
|
|
56
|
-
}, [boxRef]);
|
|
56
|
+
}, [boxRef, whole]);
|
|
57
57
|
/** Back to wherever the box starts: called when the mode changes. */
|
|
58
58
|
const reset = useCallback(() => setPosition(null), []);
|
|
59
59
|
return { position, onHandlePointerDown, reset };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What `visible_when` is, without the renderer: the key and the rule, for
|
|
3
|
+
* whatever writes or checks a surface (the Studio's Canvas) as well as for
|
|
4
|
+
* what draws it (`visibleWhen`).
|
|
5
|
+
*
|
|
6
|
+
* @module components/a2ui/visibility
|
|
7
|
+
*/
|
|
8
|
+
/** The key any block may carry to be shown only under a condition. */
|
|
9
|
+
export declare const VISIBLE_WHEN = "visible_when";
|
|
10
|
+
/**
|
|
11
|
+
* Whether a block whose condition resolved to `value` is shown: `true`, or a
|
|
12
|
+
* value that is not empty. `false`, `''`, `0`, `null`, an empty list, or
|
|
13
|
+
* nothing published at the path yet hide it.
|
|
14
|
+
*/
|
|
15
|
+
export declare function isShown(value: unknown): boolean;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2025-2026 Datalayer, Inc.
|
|
3
|
+
* Distributed under the terms of the Modified BSD License.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* What `visible_when` is, without the renderer: the key and the rule, for
|
|
7
|
+
* whatever writes or checks a surface (the Studio's Canvas) as well as for
|
|
8
|
+
* what draws it (`visibleWhen`).
|
|
9
|
+
*
|
|
10
|
+
* @module components/a2ui/visibility
|
|
11
|
+
*/
|
|
12
|
+
/** The key any block may carry to be shown only under a condition. */
|
|
13
|
+
export const VISIBLE_WHEN = 'visible_when';
|
|
14
|
+
/**
|
|
15
|
+
* Whether a block whose condition resolved to `value` is shown: `true`, or a
|
|
16
|
+
* value that is not empty. `false`, `''`, `0`, `null`, an empty list, or
|
|
17
|
+
* nothing published at the path yet hide it.
|
|
18
|
+
*/
|
|
19
|
+
export function isShown(value) {
|
|
20
|
+
if (Array.isArray(value)) {
|
|
21
|
+
return value.length > 0;
|
|
22
|
+
}
|
|
23
|
+
return Boolean(value);
|
|
24
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type ReactComponentImplementation } from '@a2ui/react/v0_9';
|
|
2
|
+
import { Catalog } from '@a2ui/web_core/v0_9';
|
|
3
|
+
/**
|
|
4
|
+
* Whether a node's resolved properties let it be drawn: no condition, or one
|
|
5
|
+
* that holds. A2UI resolves a dynamic property to a binding whether the block
|
|
6
|
+
* gave it or not; a path's is writable, and its value may be nothing yet,
|
|
7
|
+
* which hides the block. A literal or a function call that resolved to
|
|
8
|
+
* nothing is a block without a condition.
|
|
9
|
+
*/
|
|
10
|
+
export declare function nodeIsShown(props: Record<string, unknown>): boolean;
|
|
11
|
+
/** A component, its schema declaring `visible_when`, drawn behind the guard. */
|
|
12
|
+
export declare function withVisibleWhen(component: ReactComponentImplementation): ReactComponentImplementation;
|
|
13
|
+
/**
|
|
14
|
+
* The catalog Datalayer's renderer draws from: A2UI's basic catalog, under
|
|
15
|
+
* its own id — the payloads name it — with `visible_when` on every component.
|
|
16
|
+
*/
|
|
17
|
+
export declare const datalayerCatalog: Catalog<ReactComponentImplementation, import("@a2ui/web_core/v0_9").FunctionImplementation>;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { basicCatalog, useSignalValue, } from '@a2ui/react/v0_9';
|
|
3
|
+
import { Catalog, DynamicBooleanSchema, ResolvedBinding, isWritable, } from '@a2ui/web_core/v0_9';
|
|
4
|
+
import { VISIBLE_WHEN, isShown } from './visibility';
|
|
5
|
+
/**
|
|
6
|
+
* Whether a node's resolved properties let it be drawn: no condition, or one
|
|
7
|
+
* that holds. A2UI resolves a dynamic property to a binding whether the block
|
|
8
|
+
* gave it or not; a path's is writable, and its value may be nothing yet,
|
|
9
|
+
* which hides the block. A literal or a function call that resolved to
|
|
10
|
+
* nothing is a block without a condition.
|
|
11
|
+
*/
|
|
12
|
+
export function nodeIsShown(props) {
|
|
13
|
+
const condition = props[VISIBLE_WHEN];
|
|
14
|
+
if (!(condition instanceof ResolvedBinding)) {
|
|
15
|
+
throw new Error(`${VISIBLE_WHEN} resolved to ${String(condition)}, not a binding: the catalog's schema does not declare it.`);
|
|
16
|
+
}
|
|
17
|
+
if (isWritable(condition)) {
|
|
18
|
+
return isShown(condition.value);
|
|
19
|
+
}
|
|
20
|
+
return condition.value === undefined || isShown(condition.value);
|
|
21
|
+
}
|
|
22
|
+
const VISIBLE_WHEN_SCHEMA = DynamicBooleanSchema.describe('REF:#/$defs/DynamicBoolean|Datalayer: the block is shown only while this is true or not empty — a path the application publishes.').optional();
|
|
23
|
+
/** A component, its schema declaring `visible_when`, drawn behind the guard. */
|
|
24
|
+
export function withVisibleWhen(component) {
|
|
25
|
+
const View = component.view;
|
|
26
|
+
if (!View) {
|
|
27
|
+
throw new Error(`${component.name} has no node view: visible_when is read from the node, and A2uiSurface draws through it.`);
|
|
28
|
+
}
|
|
29
|
+
// A zod object: what every basic component's schema is.
|
|
30
|
+
const schema = component.schema;
|
|
31
|
+
if (!schema.shape || typeof schema.extend !== 'function') {
|
|
32
|
+
throw new Error(`${component.name}'s schema is not an object: visible_when cannot be declared on it.`);
|
|
33
|
+
}
|
|
34
|
+
if (VISIBLE_WHEN in schema.shape) {
|
|
35
|
+
throw new Error(`${component.name} already declares ${VISIBLE_WHEN}.`);
|
|
36
|
+
}
|
|
37
|
+
const Guarded = ({ node, buildChild }) => {
|
|
38
|
+
const props = useSignalValue(node.props);
|
|
39
|
+
return nodeIsShown(props) ? (_jsx(View, { node: node, buildChild: buildChild })) : null;
|
|
40
|
+
};
|
|
41
|
+
Guarded.displayName = `${component.name}.visibleWhen`;
|
|
42
|
+
return {
|
|
43
|
+
...component,
|
|
44
|
+
schema: schema.extend({ [VISIBLE_WHEN]: VISIBLE_WHEN_SCHEMA }),
|
|
45
|
+
// A2uiSurface draws through the view; `render` is only its fallback for
|
|
46
|
+
// a component without one, which this one is not.
|
|
47
|
+
view: Guarded,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* The catalog Datalayer's renderer draws from: A2UI's basic catalog, under
|
|
52
|
+
* its own id — the payloads name it — with `visible_when` on every component.
|
|
53
|
+
*/
|
|
54
|
+
export const datalayerCatalog = new Catalog(basicCatalog.id, basicCatalog.protocolVersion, [...basicCatalog.components.values()].map(withVisibleWhen), [...basicCatalog.functions.values()], basicCatalog.themeSchema, basicCatalog.instructions);
|
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
* The floating assistant (LOOP T-21 to T-27): the chat as a character on the
|
|
3
3
|
* page, after the Office Assistant — Datalayer's own characters, chosen
|
|
4
4
|
* here, acting out what the agent does and speaking in a balloon.
|
|
5
|
+
*
|
|
6
|
+
* The characters offered are what the enabled plugins contribute to
|
|
7
|
+
* `loop.assistant.character` (T-24): Datalayer's four, and an owl from a
|
|
8
|
+
* small example plugin (`utils/owlCharacterPlugin`).
|
|
5
9
|
*/
|
|
6
10
|
import React from 'react';
|
|
7
11
|
declare const ChatAssistantExample: React.FC;
|