@datalayer/agent-runtimes 1.3.25 → 1.3.27
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/messages/ChatMessages.d.ts +4 -4
- package/lib/chat/messages/ChatMessages.js +17 -17
- package/lib/config/AgentConfiguration.js +1 -1
- package/lib/examples/example-selector.js +1 -1
- package/lib/loop/apps/AppRenderer.js +8 -1
- package/lib/loop/apps/checks.d.ts +6 -1
- package/lib/loop/apps/checks.js +17 -0
- package/lib/loop/embed/LoopEmbed.js +14 -1
- package/lib/loop/plugins/chat/ChatView.js +9 -6
- package/lib/loop/plugins/chat/index.d.ts +19 -0
- package/lib/loop/presets.d.ts +5 -1
- package/lib/loop/presets.js +4 -2
- package/lib/protocols/A2AAdapter.d.ts +1 -1
- package/lib/specs/uiPlugins.d.ts +6 -1
- package/lib/specs/uiPlugins.js +471 -0
- package/lib/stores/chatStore.d.ts +11 -11
- package/lib/stores/chatStore.js +34 -34
- package/lib/stores/index.d.ts +1 -1
- package/lib/stores/index.js +1 -1
- package/lib/types/agentspecs.d.ts +33 -0
- package/lib/types/index.d.ts +1 -1
- package/lib/types/index.js +1 -1
- package/lib/types/{extensions.d.ts → uiPlugins.d.ts} +49 -49
- package/lib/types/{extensions.js → uiPlugins.js} +8 -8
- package/lib/{extensions/A2UIExtension.d.ts → ui-plugins/A2UIPlugin.d.ts} +7 -7
- package/lib/{extensions/A2UIExtension.js → ui-plugins/A2UIPlugin.js} +4 -4
- package/lib/{extensions/MCPUIExtension.d.ts → ui-plugins/MCPUIPlugin.d.ts} +9 -9
- package/lib/{extensions/MCPUIExtension.js → ui-plugins/MCPUIPlugin.js} +6 -6
- package/lib/ui-plugins/UIPluginRegistry.d.ts +65 -0
- package/lib/{extensions/ExtensionRegistry.js → ui-plugins/UIPluginRegistry.js} +32 -32
- package/lib/ui-plugins/index.d.ts +9 -0
- package/lib/ui-plugins/index.js +12 -0
- package/package.json +1 -1
- package/scripts/codegen/generate_agents.py +6 -6
- package/scripts/codegen/generate_ui_plugins.py +64 -4
- package/lib/extensions/ExtensionRegistry.d.ts +0 -65
- package/lib/extensions/index.d.ts +0 -9
- package/lib/extensions/index.js +0 -12
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import React from 'react';
|
|
8
8
|
import type { ChatMessage } from '../../types/messages';
|
|
9
|
-
import type {
|
|
9
|
+
import type { UIPluginRegistry } from '../../ui-plugins/UIPluginRegistry';
|
|
10
10
|
/**
|
|
11
11
|
* ChatMessages props
|
|
12
12
|
*/
|
|
@@ -26,11 +26,11 @@ export interface ChatMessagesProps {
|
|
|
26
26
|
autoScroll?: boolean;
|
|
27
27
|
/** Custom class name */
|
|
28
28
|
className?: string;
|
|
29
|
-
/** Optional
|
|
30
|
-
|
|
29
|
+
/** Optional plugin registry (defaults to store value) */
|
|
30
|
+
uiPluginRegistry?: UIPluginRegistry;
|
|
31
31
|
}
|
|
32
32
|
/**
|
|
33
33
|
* Chat Messages component
|
|
34
34
|
*/
|
|
35
|
-
export declare function ChatMessages({ messageRenderer, activityRenderer, showTimestamps, showAvatars, autoScroll, className,
|
|
35
|
+
export declare function ChatMessages({ messageRenderer, activityRenderer, showTimestamps, showAvatars, autoScroll, className, uiPluginRegistry: uiPluginRegistryProp, }: ChatMessagesProps): React.JSX.Element;
|
|
36
36
|
export default ChatMessages;
|
|
@@ -14,14 +14,14 @@ import { Text, RelativeTime } from '@primer/react';
|
|
|
14
14
|
import { Box, useThemeStore, getColorPalette } from '@datalayer/primer-addons';
|
|
15
15
|
import { PersonIcon, ToolsIcon } from '@primer/octicons-react';
|
|
16
16
|
import { AiAgentIcon } from '@datalayer/icons-react';
|
|
17
|
-
import { useChatMessages,
|
|
17
|
+
import { useChatMessages, useChatUIPluginRegistry, } from '../../stores/chatStore';
|
|
18
18
|
/**
|
|
19
19
|
* Chat Messages component
|
|
20
20
|
*/
|
|
21
|
-
export function ChatMessages({ messageRenderer, activityRenderer, showTimestamps = true, showAvatars = true, autoScroll = true, className,
|
|
21
|
+
export function ChatMessages({ messageRenderer, activityRenderer, showTimestamps = true, showAvatars = true, autoScroll = true, className, uiPluginRegistry: uiPluginRegistryProp, }) {
|
|
22
22
|
const messages = useChatMessages();
|
|
23
|
-
const
|
|
24
|
-
const
|
|
23
|
+
const storeUIPluginRegistry = useChatUIPluginRegistry();
|
|
24
|
+
const uiPluginRegistry = uiPluginRegistryProp ?? storeUIPluginRegistry;
|
|
25
25
|
const containerRef = useRef(null);
|
|
26
26
|
const lastMessageRef = useRef(null);
|
|
27
27
|
// Resolve a light color from the current user theme palette so the
|
|
@@ -40,12 +40,12 @@ export function ChatMessages({ messageRenderer, activityRenderer, showTimestamps
|
|
|
40
40
|
if (messageRenderer) {
|
|
41
41
|
return messageRenderer(message);
|
|
42
42
|
}
|
|
43
|
-
// Check
|
|
44
|
-
if (
|
|
45
|
-
const messageRenderers =
|
|
46
|
-
const
|
|
47
|
-
if (
|
|
48
|
-
return
|
|
43
|
+
// Check plugin registry for custom renderer
|
|
44
|
+
if (uiPluginRegistry) {
|
|
45
|
+
const messageRenderers = uiPluginRegistry.getMessageRenderers();
|
|
46
|
+
const pluginRenderer = messageRenderers.find(r => r.canRender(message));
|
|
47
|
+
if (pluginRenderer) {
|
|
48
|
+
return pluginRenderer.render({
|
|
49
49
|
message,
|
|
50
50
|
isStreaming: false,
|
|
51
51
|
});
|
|
@@ -86,7 +86,7 @@ export function ChatMessages({ messageRenderer, activityRenderer, showTimestamps
|
|
|
86
86
|
? 'You'
|
|
87
87
|
: message.role === 'assistant'
|
|
88
88
|
? 'Assistant'
|
|
89
|
-
: 'System' }), showTimestamps && message.createdAt && (_jsx(RelativeTime, { datetime: message.createdAt.toISOString(), sx: { fontSize: 0, color: 'fg.muted' } }))] }), _jsx(Box, { sx: { fontSize: 1, lineHeight: 1.5 }, children: renderMessageContent(message, activityRenderer,
|
|
89
|
+
: 'System' }), showTimestamps && message.createdAt && (_jsx(RelativeTime, { datetime: message.createdAt.toISOString(), sx: { fontSize: 0, color: 'fg.muted' } }))] }), _jsx(Box, { sx: { fontSize: 1, lineHeight: 1.5 }, children: renderMessageContent(message, activityRenderer, uiPluginRegistry ?? undefined) })] })] }, message.id));
|
|
90
90
|
};
|
|
91
91
|
if (messages.length === 0) {
|
|
92
92
|
return (_jsxs(Box, { className: className, sx: {
|
|
@@ -107,7 +107,7 @@ export function ChatMessages({ messageRenderer, activityRenderer, showTimestamps
|
|
|
107
107
|
/**
|
|
108
108
|
* Render message content based on type
|
|
109
109
|
*/
|
|
110
|
-
function renderMessageContent(message, activityRenderer,
|
|
110
|
+
function renderMessageContent(message, activityRenderer, uiPluginRegistry) {
|
|
111
111
|
const { content } = message;
|
|
112
112
|
// Simple string content
|
|
113
113
|
if (typeof content === 'string') {
|
|
@@ -115,14 +115,14 @@ function renderMessageContent(message, activityRenderer, extensionRegistry) {
|
|
|
115
115
|
}
|
|
116
116
|
// Array of content parts
|
|
117
117
|
if (Array.isArray(content)) {
|
|
118
|
-
return (_jsx(Box, { sx: { display: 'flex', flexDirection: 'column', gap: 2 }, children: content.map((part, index) => renderContentPart(part, index, activityRenderer,
|
|
118
|
+
return (_jsx(Box, { sx: { display: 'flex', flexDirection: 'column', gap: 2 }, children: content.map((part, index) => renderContentPart(part, index, activityRenderer, uiPluginRegistry)) }));
|
|
119
119
|
}
|
|
120
120
|
return null;
|
|
121
121
|
}
|
|
122
122
|
/**
|
|
123
123
|
* Render individual content part
|
|
124
124
|
*/
|
|
125
|
-
function renderContentPart(part, index, activityRenderer,
|
|
125
|
+
function renderContentPart(part, index, activityRenderer, uiPluginRegistry) {
|
|
126
126
|
switch (part.type) {
|
|
127
127
|
case 'text':
|
|
128
128
|
return (_jsx(Text, { sx: { whiteSpace: 'pre-wrap' }, children: part.text }, index));
|
|
@@ -168,9 +168,9 @@ function renderContentPart(part, index, activityRenderer, extensionRegistry) {
|
|
|
168
168
|
data: part.data,
|
|
169
169
|
}) }, index));
|
|
170
170
|
}
|
|
171
|
-
// Check
|
|
172
|
-
if (
|
|
173
|
-
const renderer =
|
|
171
|
+
// Check plugin registry
|
|
172
|
+
if (uiPluginRegistry) {
|
|
173
|
+
const renderer = uiPluginRegistry.getActivityRenderer(part.activityType || 'unknown');
|
|
174
174
|
if (renderer) {
|
|
175
175
|
return (_jsx(Box, { children: renderer.render({
|
|
176
176
|
activityType: part.activityType || 'unknown',
|
|
@@ -75,7 +75,7 @@ export const EXAMPLE_ENTRIES = [
|
|
|
75
75
|
makeEntry('A2UiRestaurantExample', () => import('./A2UiRestaurantExample'), 'A2UI restaurant flow example.'),
|
|
76
76
|
makeEntry('A2UiViewerExample', () => import('./A2UiViewerExample'), 'A2UI viewer integration example.'),
|
|
77
77
|
makeEntry('A2UiJupyterOutputExample', () => import('./A2UiJupyterOutputExample'), 'One Jupyter execution shown twice: raw kernel outputs, and the A2UI surface the server converter makes of them.'),
|
|
78
|
-
makeEntry('A2UiAgentExample', () => import('./A2UiAgentExample'), 'A2UI Agent with built-in chat component and Python A2UI
|
|
78
|
+
makeEntry('A2UiAgentExample', () => import('./A2UiAgentExample'), 'A2UI Agent with built-in chat component and Python A2UI UI plugin surface.'),
|
|
79
79
|
makeEntry('AgUiAgenticExample', () => import('./AgUiAgenticExample'), 'AG-UI agentic workflow example.'),
|
|
80
80
|
makeEntry('AgUiBackendToolRenderingExample', () => import('./AgUiBackendToolRenderingExample'), 'AG-UI backend tool rendering example.'),
|
|
81
81
|
makeEntry('AgUiHaikuGenUiExample', () => import('./AgUiHaikuGenUiExample'), 'AG-UI generative UI Haiku example.'),
|
|
@@ -135,6 +135,13 @@ export function AppRenderer({ app, plugins = NO_PLUGINS, instance, ...embed }) {
|
|
|
135
135
|
targetFixed: true,
|
|
136
136
|
// Applications first (LOOP T-12): an application's conversation wears
|
|
137
137
|
// the `loop` theme; a host may say otherwise.
|
|
138
|
-
themeVariant: "loop",
|
|
138
|
+
themeVariant: "loop",
|
|
139
|
+
// Its own face, name and welcome in the chat (T-08); no counters: a
|
|
140
|
+
// person using an application is not asking about tokens.
|
|
141
|
+
presence: {
|
|
142
|
+
name: app.name,
|
|
143
|
+
face: app.emoji,
|
|
144
|
+
welcome: app.interface.welcome || app.description,
|
|
145
|
+
}, showTokenUsage: false, datalayerCreatePayload: datalayerCreatePayload, ...embed, plugins: allPlugins }));
|
|
139
146
|
}
|
|
140
147
|
export default AppRenderer;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AppSpec } from '../../types/agentspecs';
|
|
1
|
+
import type { AppSpec, ComponentSpec } from '../../types/agentspecs';
|
|
2
2
|
export declare const NOT_READY = "Not ready";
|
|
3
3
|
export declare const NEEDS_ATTENTION = "Needs attention";
|
|
4
4
|
export declare const PASSES = "Passes the instant checks";
|
|
@@ -9,6 +9,11 @@ export interface AppCheck {
|
|
|
9
9
|
attention: string[];
|
|
10
10
|
setup: string[];
|
|
11
11
|
}
|
|
12
|
+
/**
|
|
13
|
+
* The component a layout names (LOOP C-13), from the catalogs of the enabled
|
|
14
|
+
* UI plugins, by the name a surface gives it.
|
|
15
|
+
*/
|
|
16
|
+
export declare const componentNamed: (name: string) => ComponentSpec | undefined;
|
|
12
17
|
/** The Guards the runtime executes (agent-runtimes `loop/apps/guards.py`). */
|
|
13
18
|
export declare const EXECUTED_GUARDS: readonly string[];
|
|
14
19
|
/** The instant checks of an application as an editor holds it. */
|
package/lib/loop/apps/checks.js
CHANGED
|
@@ -29,6 +29,7 @@ import { getCog } from '../../specs/cogs';
|
|
|
29
29
|
import { getFrame } from '../../specs/frames';
|
|
30
30
|
import { getGate } from '../../specs/gates';
|
|
31
31
|
import { GUARD_CATALOGUE } from '../../specs/guards';
|
|
32
|
+
import { getComponent } from '../../specs/uiPlugins';
|
|
32
33
|
import { MCP_SERVER_LIBRARY } from '../../specs/mcpServers';
|
|
33
34
|
import { getMemory } from '../../specs/memory';
|
|
34
35
|
import { getModel } from '../../specs/models';
|
|
@@ -47,6 +48,11 @@ const idOf = (ref) => {
|
|
|
47
48
|
const at = ref.lastIndexOf(':');
|
|
48
49
|
return at > 0 && ref.slice(at + 1).includes('.') ? ref.slice(0, at) : ref;
|
|
49
50
|
};
|
|
51
|
+
/**
|
|
52
|
+
* The component a layout names (LOOP C-13), from the catalogs of the enabled
|
|
53
|
+
* UI plugins, by the name a surface gives it.
|
|
54
|
+
*/
|
|
55
|
+
export const componentNamed = (name) => getComponent(name);
|
|
50
56
|
const own = (record, key) => Object.prototype.hasOwnProperty.call(record, key) ? record[key] : undefined;
|
|
51
57
|
const ACTIONS = {
|
|
52
58
|
write: 'create or change things',
|
|
@@ -175,6 +181,17 @@ function referenceProblems(app) {
|
|
|
175
181
|
if (app.model && !getModel(app.model)) {
|
|
176
182
|
missing('model', app.model);
|
|
177
183
|
}
|
|
184
|
+
// The components it may use, and those its surface uses, are the catalog's (C-13).
|
|
185
|
+
for (const name of app.interface.components ?? []) {
|
|
186
|
+
if (!componentNamed(name)) {
|
|
187
|
+
problems.push(`There is no component named “${name}” in the catalog.`);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
for (const node of app.interface.surface?.components ?? []) {
|
|
191
|
+
if (!componentNamed(String(node.component))) {
|
|
192
|
+
problems.push(`The surface's “${String(node.id)}” is a “${String(node.component)}”, which the catalog does not have.`);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
178
195
|
const judge = app.decision?.judgmentModel;
|
|
179
196
|
if (judge) {
|
|
180
197
|
const model = getModel(judge);
|
|
@@ -66,6 +66,10 @@ export function LoopEmbed({ agentId = '', showHeader = false, chatHeaderActions,
|
|
|
66
66
|
preset.datalayerAgentSpecId,
|
|
67
67
|
preset.targetFixed,
|
|
68
68
|
preset.themeVariant,
|
|
69
|
+
preset.presence?.name,
|
|
70
|
+
preset.presence?.face,
|
|
71
|
+
preset.presence?.welcome,
|
|
72
|
+
preset.showTokenUsage,
|
|
69
73
|
// By its content: an application's spec written inline is a new object each render.
|
|
70
74
|
JSON.stringify(preset.datalayerCreatePayload ?? null),
|
|
71
75
|
preset.defaultEditor,
|
|
@@ -126,6 +130,15 @@ export function LoopEmbed({ agentId = '', showHeader = false, chatHeaderActions,
|
|
|
126
130
|
*/
|
|
127
131
|
useReactor(reactor);
|
|
128
132
|
const shell = (_jsx(LoopWorkspace, { serverUrl: preset.serverUrl ?? '', agentId: agentId, reactor: reactor, manageReactor: false, showViewSelector: preset.showViewSelector, showHeader: showHeader, chatHeaderActions: chatHeaderActions, headerActions: headerActions, headerContainer: headerContainer }));
|
|
129
|
-
return (_jsx(QueryClientProvider, { client: internalQueryClient, children: frameTitle !== undefined ? (_jsx(WindowFrame, { title: frameTitle, height: frameHeight, children: shell })) : (
|
|
133
|
+
return (_jsx(QueryClientProvider, { client: internalQueryClient, children: frameTitle !== undefined ? (_jsx(WindowFrame, { title: frameTitle, height: frameHeight, children: shell })) : (
|
|
134
|
+
// Filling its host, whatever the host is: in a flex row it used to
|
|
135
|
+
// shrink to the chat's own width and leave the rest of the frame bare.
|
|
136
|
+
_jsx(Box, { sx: {
|
|
137
|
+
height: '100%',
|
|
138
|
+
minHeight: 0,
|
|
139
|
+
width: '100%',
|
|
140
|
+
flex: '1 1 auto',
|
|
141
|
+
minWidth: 0,
|
|
142
|
+
}, children: shell })) }));
|
|
130
143
|
}
|
|
131
144
|
export default LoopEmbed;
|
|
@@ -722,6 +722,7 @@ export default function ChatView({ workspace }) {
|
|
|
722
722
|
})), [suggestions]);
|
|
723
723
|
/* The icon its spec asked for, at the size the empty state draws. */
|
|
724
724
|
const BrandIcon = agentIcon(spec?.icon);
|
|
725
|
+
const presence = config?.presence;
|
|
725
726
|
/* And the team's, for the level above it. */
|
|
726
727
|
const TeamIcon = agentIcon(team?.team.icon);
|
|
727
728
|
/*
|
|
@@ -1290,7 +1291,7 @@ export default function ChatView({ workspace }) {
|
|
|
1290
1291
|
onSelectAgent: id => team?.select(id),
|
|
1291
1292
|
// On unless the host said otherwise: a public page turns the counters
|
|
1292
1293
|
// off, because they answer questions a visitor is not asking.
|
|
1293
|
-
showTokenUsage: chatExtras.showTokenUsage ?? true,
|
|
1294
|
+
showTokenUsage: chatExtras.showTokenUsage ?? config?.showTokenUsage ?? true,
|
|
1294
1295
|
showContextRing: true,
|
|
1295
1296
|
agentUsage: contextUsage ?? undefined,
|
|
1296
1297
|
showModelSelector: true,
|
|
@@ -1423,7 +1424,7 @@ export default function ChatView({ workspace }) {
|
|
|
1423
1424
|
nothing about this one. The empty state is the first thing a
|
|
1424
1425
|
person sees and the only place the agent introduces itself.
|
|
1425
1426
|
*/
|
|
1426
|
-
title: member?.name ?? spec?.name ?? agentId, description: spec?.description,
|
|
1427
|
+
title: presence?.name ?? member?.name ?? spec?.name ?? agentId, description: presence?.welcome ?? spec?.description,
|
|
1427
1428
|
/*
|
|
1428
1429
|
Two sizes, because it is drawn in two places.
|
|
1429
1430
|
|
|
@@ -1435,13 +1436,15 @@ export default function ChatView({ workspace }) {
|
|
|
1435
1436
|
// Big enough to read as the agent's mark rather than as
|
|
1436
1437
|
// punctuation before its name, and still short enough not to
|
|
1437
1438
|
// set the header's height.
|
|
1438
|
-
brandIcon: _jsx(BrandIcon, { size: 20 }), emptyState: {
|
|
1439
|
-
|
|
1439
|
+
brandIcon: presence?.face ? (_jsx("span", { "aria-hidden": true, style: { fontSize: 20, lineHeight: 1 }, children: presence.face })) : (_jsx(BrandIcon, { size: 20 })), emptyState: {
|
|
1440
|
+
// An application's own face, large: the thing a person's eye
|
|
1441
|
+
// lands on first (LOOP T-08).
|
|
1442
|
+
icon: presence?.face ? (_jsx("span", { "aria-hidden": true, style: { fontSize: 48, lineHeight: 1 }, children: presence.face })) : (_jsx(BrandIcon, { size: 48 })),
|
|
1440
1443
|
// `ChatEmptyState` reads its heading from here and nowhere
|
|
1441
1444
|
// else — the `title` above reaches the header only — so
|
|
1442
1445
|
// without this the agent introduced itself as "Start a
|
|
1443
1446
|
// conversation".
|
|
1444
|
-
title: member?.name ?? spec?.name ?? agentId,
|
|
1447
|
+
title: presence?.name ?? member?.name ?? spec?.name ?? agentId,
|
|
1445
1448
|
/*
|
|
1446
1449
|
Two levels when there is a team: the team first — its name,
|
|
1447
1450
|
what it is for, what it can be asked — and under it the
|
|
@@ -1600,7 +1603,7 @@ export default function ChatView({ workspace }) {
|
|
|
1600
1603
|
// A host example's own tool-result renderer, when it feeds one
|
|
1601
1604
|
// through the extras channel — the A2UI examples draw their
|
|
1602
1605
|
// surface here. Wins over the notebook surfaces in ChatBase.
|
|
1603
|
-
renderToolResult: chatExtras.renderToolResult, showTurnFooter: chatExtras.showTokenUsage ?? true, onContextSnapshot: handleContextSnapshot, onLoadingChange: handleLoadingChange, onItemsChange: handleMessagesChange, onDisplayItemsChange: handleDisplayItemsChange, enableStreaming: true }) }), besideChat && !promptHidden ? prompt : null] }) }));
|
|
1606
|
+
renderToolResult: chatExtras.renderToolResult, showTurnFooter: chatExtras.showTokenUsage ?? config?.showTokenUsage ?? true, onContextSnapshot: handleContextSnapshot, onLoadingChange: handleLoadingChange, onItemsChange: handleMessagesChange, onDisplayItemsChange: handleDisplayItemsChange, enableStreaming: true }) }), besideChat && !promptHidden ? prompt : null] }) }));
|
|
1604
1607
|
// Off when the host asked for the menu alone: the composer's suggestions
|
|
1605
1608
|
// control carries the same openers (`suggestions` above).
|
|
1606
1609
|
const chipsEl = config?.suggestionLabels !== false && chatSuggestions.length > 0 ? (_jsx(Box, { "aria-label": "Suggested prompts", sx: { display: 'flex', flexWrap: 'wrap', gap: 2, px: 2, pb: '6px' }, children: chatSuggestions.map(item => (_jsx(Box, { as: "button", type: "button",
|
|
@@ -1,4 +1,12 @@
|
|
|
1
1
|
/** What a host may set on the chat. */
|
|
2
|
+
/** Who is answering, as the person meets them. */
|
|
3
|
+
export interface ChatPresence {
|
|
4
|
+
name: string;
|
|
5
|
+
/** An emoji: its face where only an icon goes. */
|
|
6
|
+
face?: string;
|
|
7
|
+
/** What it says before anyone writes. */
|
|
8
|
+
welcome?: string;
|
|
9
|
+
}
|
|
2
10
|
export type ChatPluginConfig = {
|
|
3
11
|
/**
|
|
4
12
|
* The theme the conversation wears, by name: the person's unless said. An
|
|
@@ -6,6 +14,17 @@ export type ChatPluginConfig = {
|
|
|
6
14
|
* the theme's bubbles, pills and colours whatever the page around it wears.
|
|
7
15
|
*/
|
|
8
16
|
themeVariant?: string;
|
|
17
|
+
/**
|
|
18
|
+
* Who is answering, as the person meets them (LOOP T-08): a name, a face
|
|
19
|
+
* and a welcome, in place of the agent's id and a generic icon. An
|
|
20
|
+
* application sets its own.
|
|
21
|
+
*/
|
|
22
|
+
presence?: ChatPresence;
|
|
23
|
+
/**
|
|
24
|
+
* Whether the counters — tokens, context — are shown under the prompt.
|
|
25
|
+
* On unless said: a person using an application is not asking.
|
|
26
|
+
*/
|
|
27
|
+
showTokenUsage?: boolean;
|
|
9
28
|
/**
|
|
10
29
|
* What the empty prompt says.
|
|
11
30
|
*
|
package/lib/loop/presets.d.ts
CHANGED
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
*/
|
|
22
22
|
import { type PluginRef } from '@datalayer/reactor';
|
|
23
23
|
import { type AgentsConfig, type SandboxTarget } from './plugins/agents';
|
|
24
|
-
import { type ChatPluginConfig } from './plugins/chat';
|
|
24
|
+
import { type ChatPluginConfig, type ChatPresence } from './plugins/chat';
|
|
25
25
|
import { type PageSize } from './plugins/page-layout';
|
|
26
26
|
export type LoopPresetOptions = {
|
|
27
27
|
/** Where the agent runtimes service is. */
|
|
@@ -128,6 +128,10 @@ export type LoopPresetOptions = {
|
|
|
128
128
|
targetFixed?: boolean;
|
|
129
129
|
/** The theme the conversation wears, by name; the person's unless said. */
|
|
130
130
|
themeVariant?: string;
|
|
131
|
+
/** Who is answering, as the person meets them (LOOP T-08). */
|
|
132
|
+
presence?: ChatPresence;
|
|
133
|
+
/** Whether the counters are shown under the prompt; on unless said. */
|
|
134
|
+
showTokenUsage?: boolean;
|
|
131
135
|
/**
|
|
132
136
|
* The agentspec the local agent is created from, by id.
|
|
133
137
|
*
|
package/lib/loop/presets.js
CHANGED
|
@@ -31,7 +31,7 @@ import { ShellPlugin } from './plugins/shell';
|
|
|
31
31
|
import { PromptPlugin } from './plugins/prompt';
|
|
32
32
|
import { AgentspecsPlugin } from './plugins/agentspecs';
|
|
33
33
|
import { AgentsPlugin, } from './plugins/agents';
|
|
34
|
-
import { ChatPlugin } from './plugins/chat';
|
|
34
|
+
import { ChatPlugin, } from './plugins/chat';
|
|
35
35
|
import { ChatHeaderPlugin } from './plugins/chat-header';
|
|
36
36
|
import { A2uiSurfacePlugin } from './plugins/a2ui-surface';
|
|
37
37
|
import { ChatViewPlugin } from './plugins/chat-view';
|
|
@@ -52,7 +52,7 @@ import { LoopPageLayoutPlugin } from './plugins/page-layout';
|
|
|
52
52
|
* be installed or signed into, and the switches a demonstration wants are off.
|
|
53
53
|
*/
|
|
54
54
|
export function loopPlugins(options = {}) {
|
|
55
|
-
const { serverUrl, target = 'browser', defaultEditor = 'notebook', showViewSelector = true, hideChatHeader = false, chatHeaderButtons = false, promptPlacement, autoFocusPrompt = true, suggestionLabels = true, fullScreenTopOffset = 0, showAgentVariants = false, agentSummary = true, teamId, teamPicker = true, pageLayout = false, pageLayoutTurnPanel = 'below', pageLayoutPrompt = 'docked', pageLayoutPromptAnchor = 'top', pageLayoutSize, pageLayoutTurnPanelFooter = 'full', localAgent, localAgentSpec, datalayerAgentSpecId, datalayerCreatePayload, targetFixed, themeVariant, floatingPrompt = false, editorSelector = false, editors = true, graph = false, commandPalette = false, pluginsPanel = false, windowFrame = false, firstPromptHook, } = options;
|
|
55
|
+
const { serverUrl, target = 'browser', defaultEditor = 'notebook', showViewSelector = true, hideChatHeader = false, chatHeaderButtons = false, promptPlacement, autoFocusPrompt = true, suggestionLabels = true, fullScreenTopOffset = 0, showAgentVariants = false, agentSummary = true, teamId, teamPicker = true, pageLayout = false, pageLayoutTurnPanel = 'below', pageLayoutPrompt = 'docked', pageLayoutPromptAnchor = 'top', pageLayoutSize, pageLayoutTurnPanelFooter = 'full', localAgent, localAgentSpec, datalayerAgentSpecId, datalayerCreatePayload, targetFixed, themeVariant, presence, showTokenUsage, floatingPrompt = false, editorSelector = false, editors = true, graph = false, commandPalette = false, pluginsPanel = false, windowFrame = false, firstPromptHook, } = options;
|
|
56
56
|
return [
|
|
57
57
|
// The chat owns the editor beside it, so which one opens is its
|
|
58
58
|
// configuration rather than the workspace's.
|
|
@@ -69,6 +69,8 @@ export function loopPlugins(options = {}) {
|
|
|
69
69
|
suggestionLabels,
|
|
70
70
|
fullScreenTopOffset,
|
|
71
71
|
themeVariant,
|
|
72
|
+
presence,
|
|
73
|
+
showTokenUsage,
|
|
72
74
|
}),
|
|
73
75
|
// The composer and the title bar are plugins of their own: the chat
|
|
74
76
|
// assembles their props, these render them. In the preset by default —
|
|
@@ -8,7 +8,7 @@ import { BaseProtocolAdapter } from './BaseProtocolAdapter';
|
|
|
8
8
|
export interface A2AAdapterConfig extends ProtocolAdapterConfig {
|
|
9
9
|
/** Agent URL for .well-known/agent-card.json discovery */
|
|
10
10
|
agentUrl?: string;
|
|
11
|
-
/** Enable A2UI
|
|
11
|
+
/** Enable the A2UI UI plugin */
|
|
12
12
|
enableA2UI?: boolean;
|
|
13
13
|
}
|
|
14
14
|
/**
|
package/lib/specs/uiPlugins.d.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* This file is AUTO-GENERATED from YAML specifications.
|
|
7
7
|
* DO NOT EDIT MANUALLY - run 'make specs' to regenerate.
|
|
8
8
|
*/
|
|
9
|
-
import type { UIPluginSpec } from '../types/agentspecs';
|
|
9
|
+
import type { ComponentSpec, UIPluginSpec } from '../types/agentspecs';
|
|
10
10
|
export declare const A2UI_UI_PLUGIN_0_0_1: UIPluginSpec;
|
|
11
11
|
export declare const MCP_APPS_UI_PLUGIN_0_0_1: UIPluginSpec;
|
|
12
12
|
export declare const MCP_UI_UI_PLUGIN_0_0_1: UIPluginSpec;
|
|
@@ -14,3 +14,8 @@ export declare const UI_PLUGIN_CATALOGUE: Record<string, UIPluginSpec>;
|
|
|
14
14
|
/** The plugin an agent spec's `uiPlugin` names, or undefined. */
|
|
15
15
|
export declare function getUIPlugin(pluginId: string): UIPluginSpec | undefined;
|
|
16
16
|
export declare function listUIPlugins(): UIPluginSpec[];
|
|
17
|
+
/** The visual components the enabled UI plugins render, by the name a surface gives them (LOOP C-13). */
|
|
18
|
+
export declare const COMPONENT_CATALOGUE: Record<string, ComponentSpec>;
|
|
19
|
+
/** The component a layout names, or undefined. */
|
|
20
|
+
export declare function getComponent(name: string): ComponentSpec | undefined;
|
|
21
|
+
export declare function listComponents(): ComponentSpec[];
|