@datalayer/agent-runtimes 1.3.28 → 1.3.30
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/AgentNode.js +14 -33
- package/lib/chat/ChatFloating.d.ts +12 -2
- package/lib/chat/ChatFloating.js +196 -25
- package/lib/chat/assistant/AssistantStage.d.ts +70 -0
- package/lib/chat/assistant/AssistantStage.js +192 -0
- package/lib/chat/assistant/SpeechBalloon.d.ts +26 -0
- package/lib/chat/assistant/SpeechBalloon.js +46 -0
- package/lib/chat/assistant/SpriteCharacter.d.ts +26 -0
- package/lib/chat/assistant/SpriteCharacter.js +73 -0
- package/lib/chat/assistant/characters.d.ts +30 -0
- package/lib/chat/assistant/characters.js +41 -0
- package/lib/chat/assistant/formats/acs.d.ts +88 -0
- package/lib/chat/assistant/formats/acs.js +493 -0
- package/lib/chat/assistant/formats/agentCompression.d.ts +5 -0
- package/lib/chat/assistant/formats/agentCompression.js +92 -0
- package/lib/chat/assistant/formats/blobs.d.ts +6 -0
- package/lib/chat/assistant/formats/blobs.js +52 -0
- package/lib/chat/assistant/formats/clippy.d.ts +21 -0
- package/lib/chat/assistant/formats/clippy.js +167 -0
- package/lib/chat/assistant/formats/index.d.ts +13 -0
- package/lib/chat/assistant/formats/index.js +15 -0
- package/lib/chat/assistant/formats/objectLiteral.d.ts +23 -0
- package/lib/chat/assistant/formats/objectLiteral.js +233 -0
- package/lib/chat/assistant/formats/stateAnimations.d.ts +16 -0
- package/lib/chat/assistant/formats/stateAnimations.js +115 -0
- package/lib/chat/assistant/formats/types.d.ts +56 -0
- package/lib/chat/assistant/formats/types.js +11 -0
- package/lib/chat/assistant/state.d.ts +62 -0
- package/lib/chat/assistant/state.js +116 -0
- package/lib/chat/base/ChatBase.js +41 -32
- package/lib/chat/base/modelChoice.d.ts +13 -0
- package/lib/chat/base/modelChoice.js +13 -0
- package/lib/chat/header/ChatViewModeToggle.js +6 -3
- package/lib/{loop/plugins/chat → chat/presence}/Presence.js +1 -1
- package/lib/{loop/plugins/chat → chat/presence}/presenceStatus.d.ts +7 -1
- package/lib/{loop/plugins/chat → chat/presence}/presenceStatus.js +18 -0
- package/lib/chat/viewModes.d.ts +6 -0
- package/lib/chat/viewModes.js +10 -1
- package/lib/examples/ChatAssistantExample.d.ts +8 -0
- package/lib/examples/ChatAssistantExample.js +59 -0
- package/lib/examples/example-selector.js +1 -0
- package/lib/examples/main.js +3 -0
- package/lib/loop/apps/AppRenderer.d.ts +34 -2
- package/lib/loop/apps/AppRenderer.js +96 -29
- package/lib/loop/apps/agent.d.ts +15 -0
- package/lib/loop/apps/agent.js +42 -0
- package/lib/loop/apps/appspec.d.ts +5 -1
- package/lib/loop/apps/appspec.js +21 -1
- package/lib/loop/apps/checks.js +3 -1
- package/lib/loop/apps/index.d.ts +1 -0
- package/lib/loop/apps/index.js +1 -0
- package/lib/loop/core/index.d.ts +23 -0
- package/lib/loop/core/index.js +1 -0
- package/lib/loop/embed/AppEmbed.d.ts +42 -0
- package/lib/loop/embed/AppEmbed.js +205 -0
- package/lib/loop/embed/datalayer-app.d.ts +1 -0
- package/lib/loop/embed/datalayer-app.js +16 -0
- package/lib/loop/embed/element.d.ts +57 -0
- package/lib/loop/embed/element.js +405 -0
- package/lib/loop/embed/embedConfig.d.ts +120 -0
- package/lib/loop/embed/embedConfig.js +148 -0
- package/lib/loop/embed/embedTheme.d.ts +24 -0
- package/lib/loop/embed/embedTheme.js +83 -0
- package/lib/loop/index.d.ts +6 -2
- package/lib/loop/index.js +8 -2
- package/lib/loop/plugins/a2ui-surface/InlineSurface.d.ts +21 -3
- package/lib/loop/plugins/a2ui-surface/InlineSurface.js +34 -6
- package/lib/loop/plugins/agent-capacity/index.d.ts +4 -0
- package/lib/loop/plugins/agent-capacity/index.js +3 -1
- package/lib/loop/plugins/agents/switchable.d.ts +7 -0
- package/lib/loop/plugins/agents/switchable.js +91 -88
- package/lib/loop/plugins/app-page/AppPage.d.ts +16 -0
- package/lib/loop/plugins/app-page/AppPage.js +53 -0
- package/lib/loop/plugins/app-page/appPage.d.ts +180 -0
- package/lib/loop/plugins/app-page/appPage.js +443 -0
- package/lib/loop/plugins/app-page/index.d.ts +8 -0
- package/lib/loop/plugins/app-page/index.js +34 -0
- package/lib/loop/plugins/assistant-characters/index.d.ts +30 -0
- package/lib/loop/plugins/assistant-characters/index.js +41 -0
- package/lib/loop/plugins/chat/ChatView.js +50 -39
- package/lib/loop/plugins/chat/index.d.ts +1 -1
- package/lib/loop/plugins/page-layout/SplitLayout.d.ts +31 -0
- package/lib/loop/plugins/page-layout/SplitLayout.js +129 -0
- package/lib/loop/plugins/page-layout/index.d.ts +13 -0
- package/lib/loop/plugins/page-layout/index.js +15 -2
- package/lib/loop/presets.d.ts +12 -0
- package/lib/loop/presets.js +5 -3
- package/lib/specs/actions.js +14 -0
- package/lib/specs/agents/agents.js +4 -0
- package/lib/specs/apps.d.ts +13 -1
- package/lib/specs/apps.js +2715 -373
- package/lib/specs/appspecSchema.js +21 -3
- package/lib/types/agentspecs.d.ts +21 -1
- package/lib/types/chat.d.ts +1 -1
- package/lib/types/config.d.ts +12 -0
- package/package.json +2 -1
- package/scripts/codegen/generate_agents.py +50 -2
- package/scripts/codegen/generate_apps.py +36 -6
- /package/lib/{loop/plugins/chat → chat/presence}/Presence.d.ts +0 -0
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2025-2026 Datalayer, Inc.
|
|
3
|
+
* Distributed under the terms of the Modified BSD License.
|
|
4
|
+
*/
|
|
5
|
+
import { APP_ACCENTS, APP_EMBED_MODES } from '../apps/appspec';
|
|
6
|
+
/** The element's name: the one a host writes. */
|
|
7
|
+
export const EMBED_TAG = 'datalayer-app';
|
|
8
|
+
/** Where the script is served on a Datalayer origin; the stylesheet beside it. */
|
|
9
|
+
export const EMBED_SCRIPT_PATH = '/embed/datalayer-app.js';
|
|
10
|
+
export const EMBED_STYLESHEET_PATH = '/embed/datalayer-app.css';
|
|
11
|
+
/**
|
|
12
|
+
* The element's attributes, each in a sentence — what the documentation and
|
|
13
|
+
* the element's own refusals say.
|
|
14
|
+
*/
|
|
15
|
+
export const EMBED_ATTRIBUTES = {
|
|
16
|
+
app: 'The application’s id on Datalayer.',
|
|
17
|
+
origin: 'Where Datalayer is; the origin the script was loaded from by default.',
|
|
18
|
+
token: 'An embed token for an application that is not public, issued to your server for each visit.',
|
|
19
|
+
spec: 'The address of an Appspec (YAML or JSON) to run, in place of `app`.',
|
|
20
|
+
mode: 'inline, bubble, panel or assistant; the Appspec’s `deployment.embedded.mode` by default, then inline.',
|
|
21
|
+
accent: 'green, rose, sky, lime, sun or violet; the Appspec’s `interface.accent` by default.',
|
|
22
|
+
theme: 'light, dark or auto (the visitor’s system); auto by default.',
|
|
23
|
+
font: 'A CSS font family for the application’s text; Inter, then the system’s sans-serif, by default.',
|
|
24
|
+
server: 'An agent-runtimes server the application’s agent runs on; a Datalayer runtime by default.',
|
|
25
|
+
api: 'Datalayer’s API, where an application is read with its token; the platform’s by default.',
|
|
26
|
+
height: 'The height of an inline application, in pixels; 640 by default.',
|
|
27
|
+
};
|
|
28
|
+
/** Every attribute the element watches. */
|
|
29
|
+
export const EMBED_OBSERVED_ATTRIBUTES = Object.keys(EMBED_ATTRIBUTES);
|
|
30
|
+
/**
|
|
31
|
+
* What a host may set from its own stylesheet, on the element or above it
|
|
32
|
+
* (D-11): the accent, the face and the mode. An attribute says the same and
|
|
33
|
+
* wins over the variable.
|
|
34
|
+
*/
|
|
35
|
+
export const EMBED_HOST_VARIABLES = {
|
|
36
|
+
accent: '--datalayer-app-accent',
|
|
37
|
+
font: '--datalayer-app-font',
|
|
38
|
+
theme: '--datalayer-app-theme',
|
|
39
|
+
};
|
|
40
|
+
export const EMBED_COLOR_MODES = ['light', 'dark', 'auto'];
|
|
41
|
+
/**
|
|
42
|
+
* The four modes (D-07), and the chat they float in: a **bubble** is the
|
|
43
|
+
* round button that opens a popup — the copilot pattern; a **panel** is the
|
|
44
|
+
* conversation at the page's right edge, at full height; the **assistant** is
|
|
45
|
+
* the character that speaks in a balloon (§6.9). **Inline** has no chat of
|
|
46
|
+
* its own to float: the application, its page and its conversation, sit in
|
|
47
|
+
* the host's page where the element is.
|
|
48
|
+
*/
|
|
49
|
+
export const EMBED_FLOATING_VIEWS = {
|
|
50
|
+
bubble: 'floating-small',
|
|
51
|
+
panel: 'panel',
|
|
52
|
+
assistant: 'assistant',
|
|
53
|
+
};
|
|
54
|
+
/** The chat a mode floats in; none for inline. */
|
|
55
|
+
export function floatingViewOf(mode) {
|
|
56
|
+
return mode === 'inline' ? undefined : EMBED_FLOATING_VIEWS[mode];
|
|
57
|
+
}
|
|
58
|
+
/** A value the element refuses, said in a sentence for the page to show. */
|
|
59
|
+
export class EmbedAttributeError extends Error {
|
|
60
|
+
constructor(message) {
|
|
61
|
+
super(message);
|
|
62
|
+
this.name = 'EmbedAttributeError';
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
const listed = (values) => `${values.slice(0, -1).join(', ')} or ${values[values.length - 1]}`;
|
|
66
|
+
function oneOf(value, allowed, what) {
|
|
67
|
+
const text = value?.trim();
|
|
68
|
+
if (!text) {
|
|
69
|
+
return undefined;
|
|
70
|
+
}
|
|
71
|
+
if (!allowed.includes(text)) {
|
|
72
|
+
throw new EmbedAttributeError(`datalayer-app: "${text}" is not ${what}; it is ${listed(allowed)}.`);
|
|
73
|
+
}
|
|
74
|
+
return text;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* A font family a host names, checked: names, quotes, commas and spaces, as
|
|
78
|
+
* a `font-family` is written — nothing that could close the declaration or
|
|
79
|
+
* fetch anything (`;`, braces, `url(`).
|
|
80
|
+
*/
|
|
81
|
+
export function checkedFont(value) {
|
|
82
|
+
const text = value?.trim() ?? '';
|
|
83
|
+
if (!text) {
|
|
84
|
+
return '';
|
|
85
|
+
}
|
|
86
|
+
if (!/^[\w\s,"'.-]+$/u.test(text)) {
|
|
87
|
+
throw new EmbedAttributeError(`datalayer-app: the font "${text}" is not a font family; write it as a CSS font-family is written, such as "Georgia, serif".`);
|
|
88
|
+
}
|
|
89
|
+
return text;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* What the element shows and how, from what the host wrote and what the
|
|
93
|
+
* application says: an attribute first, then the host's CSS variable, then
|
|
94
|
+
* the Appspec, then the default. A value that is not one is refused with a
|
|
95
|
+
* sentence (`EmbedAttributeError`), never quietly replaced.
|
|
96
|
+
*/
|
|
97
|
+
export function embedLookOf(inputs, app) {
|
|
98
|
+
const { attributes, variables = {} } = inputs;
|
|
99
|
+
const mode = oneOf(attributes.mode, APP_EMBED_MODES, 'a mode') ??
|
|
100
|
+
app?.deployment?.embedded?.mode ??
|
|
101
|
+
'inline';
|
|
102
|
+
const accent = oneOf(attributes.accent, APP_ACCENTS, 'an accent') ??
|
|
103
|
+
oneOf(variables.accent, APP_ACCENTS, 'an accent') ??
|
|
104
|
+
app?.interface?.accent ??
|
|
105
|
+
'green';
|
|
106
|
+
const colorMode = oneOf(attributes.theme, EMBED_COLOR_MODES, 'a theme') ??
|
|
107
|
+
oneOf(variables.theme, EMBED_COLOR_MODES, 'a theme') ??
|
|
108
|
+
'auto';
|
|
109
|
+
const font = checkedFont(attributes.font) || checkedFont(variables.font);
|
|
110
|
+
return { mode, accent, colorMode, font };
|
|
111
|
+
}
|
|
112
|
+
/** The height of an inline application, in pixels. */
|
|
113
|
+
export function inlineHeightOf(value) {
|
|
114
|
+
const height = Number.parseInt(value ?? '', 10);
|
|
115
|
+
return Number.isFinite(height) && height >= 240 ? height : 640;
|
|
116
|
+
}
|
|
117
|
+
const attributeValue = (value) => value
|
|
118
|
+
.replace(/&/g, '&')
|
|
119
|
+
.replace(/"/g, '"')
|
|
120
|
+
.replace(/</g, '<')
|
|
121
|
+
.replace(/>/g, '>');
|
|
122
|
+
/**
|
|
123
|
+
* The snippet a host pastes (D-08): one script tag and one element. A public
|
|
124
|
+
* application needs no token; a private one takes the token its owner was
|
|
125
|
+
* issued for it, written as given, so the snippet works for as long as the
|
|
126
|
+
* token lives — a host's own page writes the one its server is issued for
|
|
127
|
+
* each visit.
|
|
128
|
+
*/
|
|
129
|
+
export function embedSnippetOf(options) {
|
|
130
|
+
const origin = options.origin.replace(/\/+$/, '');
|
|
131
|
+
const attributes = [
|
|
132
|
+
['app', options.app],
|
|
133
|
+
['origin', origin],
|
|
134
|
+
['mode', options.mode],
|
|
135
|
+
['accent', options.accent],
|
|
136
|
+
['theme', options.theme],
|
|
137
|
+
['font', options.font ? checkedFont(options.font) : undefined],
|
|
138
|
+
['token', options.token],
|
|
139
|
+
];
|
|
140
|
+
const written = attributes
|
|
141
|
+
.filter((entry) => Boolean(entry[1]))
|
|
142
|
+
.map(([name, value]) => ` ${name}="${attributeValue(value)}"`)
|
|
143
|
+
.join('');
|
|
144
|
+
return [
|
|
145
|
+
`<script src="${attributeValue(origin + EMBED_SCRIPT_PATH)}" async></script>`,
|
|
146
|
+
`<${EMBED_TAG}${written}></${EMBED_TAG}>`,
|
|
147
|
+
].join('\n');
|
|
148
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { type ThemeStyles } from '@datalayer/primer-addons';
|
|
2
|
+
import type { AppAccent } from '../../types/agentspecs';
|
|
3
|
+
/**
|
|
4
|
+
* The `loop` theme as the embed wears it: the application's accent over it
|
|
5
|
+
* in both modes (T-05), and the host's face when it named one.
|
|
6
|
+
*/
|
|
7
|
+
export declare function embedThemeStyles({ accent, font, }: {
|
|
8
|
+
accent: AppAccent;
|
|
9
|
+
font?: string;
|
|
10
|
+
}): ThemeStyles;
|
|
11
|
+
/**
|
|
12
|
+
* The element's own stylesheet, written into its shadow root.
|
|
13
|
+
*
|
|
14
|
+
* `all: initial` on the host: nothing the host page sets — a font, a colour,
|
|
15
|
+
* a line height, a text alignment — is inherited by the application. The
|
|
16
|
+
* theme's custom properties are set again inside, on the provider's element,
|
|
17
|
+
* so a host's variable of the same name never reaches what the application
|
|
18
|
+
* draws. A floating mode takes no room in the page: what it draws is fixed to
|
|
19
|
+
* the viewport.
|
|
20
|
+
*
|
|
21
|
+
* With the theme's own stylesheet, scoped to the provider's element in this
|
|
22
|
+
* root.
|
|
23
|
+
*/
|
|
24
|
+
export declare function embedShadowCss(themeCss?: string): string;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2025-2026 Datalayer, Inc.
|
|
3
|
+
* Distributed under the terms of the Modified BSD License.
|
|
4
|
+
*/
|
|
5
|
+
import { loopAccentStyles, loopFontFamily, loopThemeStyles, scopeThemeCss, THEME_SCOPE_ATTRIBUTE, } from '@datalayer/primer-addons';
|
|
6
|
+
/** One mode's properties, with the theme's face replaced by the host's. */
|
|
7
|
+
function withFace(styles, font) {
|
|
8
|
+
if (!font) {
|
|
9
|
+
return styles;
|
|
10
|
+
}
|
|
11
|
+
return Object.fromEntries(Object.entries(styles).map(([name, value]) => [
|
|
12
|
+
name,
|
|
13
|
+
typeof value === 'string'
|
|
14
|
+
? value.split(loopFontFamily).join(font)
|
|
15
|
+
: value,
|
|
16
|
+
]));
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* The `loop` theme as the embed wears it: the application's accent over it
|
|
20
|
+
* in both modes (T-05), and the host's face when it named one.
|
|
21
|
+
*/
|
|
22
|
+
export function embedThemeStyles({ accent, font = '', }) {
|
|
23
|
+
const mode = (which) => withFace({
|
|
24
|
+
...loopThemeStyles[which],
|
|
25
|
+
...loopAccentStyles(accent, which),
|
|
26
|
+
}, font);
|
|
27
|
+
return {
|
|
28
|
+
...loopThemeStyles,
|
|
29
|
+
light: mode('light'),
|
|
30
|
+
dark: mode('dark'),
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* The element's own stylesheet, written into its shadow root.
|
|
35
|
+
*
|
|
36
|
+
* `all: initial` on the host: nothing the host page sets — a font, a colour,
|
|
37
|
+
* a line height, a text alignment — is inherited by the application. The
|
|
38
|
+
* theme's custom properties are set again inside, on the provider's element,
|
|
39
|
+
* so a host's variable of the same name never reaches what the application
|
|
40
|
+
* draws. A floating mode takes no room in the page: what it draws is fixed to
|
|
41
|
+
* the viewport.
|
|
42
|
+
*
|
|
43
|
+
* With the theme's own stylesheet, scoped to the provider's element in this
|
|
44
|
+
* root.
|
|
45
|
+
*/
|
|
46
|
+
export function embedShadowCss(themeCss) {
|
|
47
|
+
const own = `
|
|
48
|
+
:host {
|
|
49
|
+
all: initial;
|
|
50
|
+
display: block;
|
|
51
|
+
position: relative;
|
|
52
|
+
width: 100%;
|
|
53
|
+
}
|
|
54
|
+
:host([hidden]) {
|
|
55
|
+
display: none;
|
|
56
|
+
}
|
|
57
|
+
:host(:not([data-embed-mode="inline"])) {
|
|
58
|
+
width: 0;
|
|
59
|
+
height: 0;
|
|
60
|
+
}
|
|
61
|
+
.datalayer-app-root,
|
|
62
|
+
.datalayer-app-portal {
|
|
63
|
+
font-family: var(--fontStack-sansSerif, system-ui, sans-serif);
|
|
64
|
+
}
|
|
65
|
+
.datalayer-app-said {
|
|
66
|
+
font: 14px/1.5 system-ui, sans-serif;
|
|
67
|
+
padding: 12px 16px;
|
|
68
|
+
border: 1px solid #d0d7de;
|
|
69
|
+
border-radius: 12px;
|
|
70
|
+
color: #1f2328;
|
|
71
|
+
background: #ffffff;
|
|
72
|
+
}
|
|
73
|
+
iframe.datalayer-app-frame {
|
|
74
|
+
display: block;
|
|
75
|
+
width: 100%;
|
|
76
|
+
border: 0;
|
|
77
|
+
min-height: 240px;
|
|
78
|
+
}
|
|
79
|
+
`;
|
|
80
|
+
return themeCss
|
|
81
|
+
? `${own}\n${scopeThemeCss(themeCss, [`[${THEME_SCOPE_ATTRIBUTE}]`])}`
|
|
82
|
+
: own;
|
|
83
|
+
}
|
package/lib/loop/index.d.ts
CHANGED
|
@@ -16,7 +16,7 @@ export { ChatHeaderPlugin, CHAT_HEADER_PLUGIN_NAME, } from './plugins/chat-heade
|
|
|
16
16
|
export { InputPromptPlugin, INPUT_PROMPT_PLUGIN_NAME, type InputPromptPluginConfig, } from './plugins/input-prompt';
|
|
17
17
|
export { createChatExtrasPlugin, CHAT_EXTRAS_PLUGIN_NAME, type ChatExtrasHandle, } from './plugins/chat-extras';
|
|
18
18
|
export { LoopChatExtras, LoopChatLayout, LoopChatTurn, LoopOpeningDocument, LoopOpeningNotebook, LoopPromptPanel, type ChatLayoutContribution, type ChatLayoutParts, type ChatTurnContribution, type ChatTurnSnapshot, type ChatTurnStatus, type LoopChatExtrasValue, type OpeningDocumentContribution, type OpeningNotebookContribution, type PromptPanelContribution, } from './core';
|
|
19
|
-
export { LoopPageLayoutPlugin, LOOP_PAGE_LAYOUT_PLUGIN_NAME, openConversationPanel, pageLayoutSheet, pageLayoutPanelOpen, setPageLayoutChatMode, type LoopPageLayoutConfig, } from './plugins/page-layout';
|
|
19
|
+
export { LoopPageLayoutPlugin, LOOP_PAGE_LAYOUT_PLUGIN_NAME, openConversationPanel, pageLayoutSheet, pageLayoutPanelOpen, setPageLayoutChatMode, SplitLayout, type LoopPageLayoutConfig, } from './plugins/page-layout';
|
|
20
20
|
export { useOptionalTeamSelection } from './plugins/agents/useTeamSelection';
|
|
21
21
|
export type { TeamMember, TeamSelection } from './plugins/agents/team';
|
|
22
22
|
export { ChatViewPlugin, CHAT_VIEW_PLUGIN_NAME } from './plugins/chat-view';
|
|
@@ -50,6 +50,7 @@ export { SANDBOX_CAPACITIES, SandboxCapacityPlugins, } from './plugins/agent-cod
|
|
|
50
50
|
export { AgentA2uiPlugin, AGENT_A2UI_PLUGIN_NAME } from './plugins/agent-a2ui';
|
|
51
51
|
export { AgentA2uiJupyterOutputPlugin, AGENT_A2UI_JUPYTER_OUTPUT_PLUGIN_NAME, } from './plugins/agent-a2ui-jupyter-output';
|
|
52
52
|
export { defineA2uiScenePlugin, type A2uiSceneOptions, } from './plugins/a2ui-scene';
|
|
53
|
+
export { APP_KIND_PATHS, APP_PAGE_PLUGIN_NAME, APP_PAGE_SURFACE, AppPage, appKindPaths, appPageAction, appPageData, defineAppPagePlugin, hasAppPage, surfaceUnshown, type AppKindPaths, type AppPageAction, type AppPageKind, type AppPagePath, } from './plugins/app-page';
|
|
53
54
|
export { GraphViewPlugin, GRAPH_PLUGIN_NAME, GRAPH_VIEW_TYPE, } from './plugins/graph';
|
|
54
55
|
export { PluginsPanelPlugin, PLUGINS_PANEL_PLUGIN_NAME, PluginsPanel, } from './plugins/plugins-panel';
|
|
55
56
|
export { AGENTS_PLUGIN_NAME, AgentsPlugin, SandboxSelector, browserSource, createBrowserSandboxService, createServerSandboxService, createSwitchableSandboxService, suppliedSource, useOptionalSandboxService, useSandboxService, type AgentsConfig, type AgentsOutput, type SandboxExecution, type SandboxService, type SandboxTarget, type ServiceManagerSource, type SwitchableSandboxService, } from './plugins/agents';
|
|
@@ -63,7 +64,10 @@ export { WindowFrame, WindowFramePlugin, WINDOW_ACTIONS_SLOT, WINDOW_CONTROLS_SL
|
|
|
63
64
|
export { LoopCommandsPlugin, COMMANDS_PLUGIN_NAME } from './plugins/commands';
|
|
64
65
|
export { PromptPlugin, PROMPT_PLUGIN_NAME } from './plugins/prompt';
|
|
65
66
|
export { LoopEmbed, type LoopEmbedProps } from './embed/LoopEmbed';
|
|
67
|
+
export { AppEmbed, type AppEmbedProps } from './embed/AppEmbed';
|
|
68
|
+
export { defineDatalayerAppElement, type DatalayerAppElementOptions, } from './embed/element';
|
|
69
|
+
export { EMBED_ATTRIBUTES, EMBED_HOST_VARIABLES, EMBED_TAG, embedLookOf, embedSnippetOf, floatingViewOf, type EmbedLook, type EmbedSnippetOptions, } from './embed/embedConfig';
|
|
66
70
|
export { SubagentActivityPlugin, SubagentPulse, SUBAGENT_ACTIVITY_PLUGIN_NAME, } from './plugins/subagent-activity';
|
|
67
71
|
export { loopPlugins, type LoopPresetOptions } from './presets';
|
|
68
72
|
export { DocumentExtension, NotebookExtension } from './extensions';
|
|
69
|
-
export { BEHAVIOURS as APP_BEHAVIOUR_ORDER, DEFAULT_BEHAVIOURS as APP_DEFAULT_BEHAVIOURS, behaviourFor, classesOf, isReadOnly, toolBehaviours, toolEscalations, type BehaviourOptions, type ToolArguments, APP_SCHEMA, APPSPEC_KEY_ORDER, DEFAULT_LAYOUTS as APP_DEFAULT_LAYOUTS, dumpAppspec, emptyAppspec, parseAppspec, AppRenderer, checkApp, checkAppspec, type AppCheck, defineAppPlugin, type AppRendererProps, type AppInstance, readAppspecYaml, writeAppspecYaml, type ParsedAppspec, } from './apps';
|
|
73
|
+
export { BEHAVIOURS as APP_BEHAVIOUR_ORDER, DEFAULT_BEHAVIOURS as APP_DEFAULT_BEHAVIOURS, behaviourFor, classesOf, isReadOnly, toolBehaviours, toolEscalations, type BehaviourOptions, type ToolArguments, APP_SCHEMA, APPSPEC_KEY_ORDER, DEFAULT_LAYOUTS as APP_DEFAULT_LAYOUTS, dumpAppspec, emptyAppspec, parseAppspec, AppRenderer, checkApp, checkAppspec, type AppCheck, defineAppPlugin, type AppRendererProps, type AppInstance, appLayoutOptions, readAppspecYaml, writeAppspecYaml, type ParsedAppspec, } from './apps';
|
package/lib/loop/index.js
CHANGED
|
@@ -29,7 +29,7 @@ export { LoopChatExtras, LoopChatLayout, LoopChatTurn, LoopOpeningDocument, Loop
|
|
|
29
29
|
export { LoopPageLayoutPlugin, LOOP_PAGE_LAYOUT_PLUGIN_NAME, openConversationPanel, pageLayoutSheet, pageLayoutPanelOpen,
|
|
30
30
|
// How a host moves the composer: `sidebar` stands it in the conversation
|
|
31
31
|
// panel, under what was said, and opens the panel to show it.
|
|
32
|
-
setPageLayoutChatMode, } from './plugins/page-layout';
|
|
32
|
+
setPageLayoutChatMode, SplitLayout, } from './plugins/page-layout';
|
|
33
33
|
export { useOptionalTeamSelection } from './plugins/agents/useTeamSelection';
|
|
34
34
|
export { ChatViewPlugin, CHAT_VIEW_PLUGIN_NAME } from './plugins/chat-view';
|
|
35
35
|
export { NotebookViewPlugin, NOTEBOOK_VIEW_PLUGIN_NAME, } from './plugins/notebook-view';
|
|
@@ -63,6 +63,7 @@ export { SANDBOX_CAPACITIES, SandboxCapacityPlugins, } from './plugins/agent-cod
|
|
|
63
63
|
export { AgentA2uiPlugin, AGENT_A2UI_PLUGIN_NAME } from './plugins/agent-a2ui';
|
|
64
64
|
export { AgentA2uiJupyterOutputPlugin, AGENT_A2UI_JUPYTER_OUTPUT_PLUGIN_NAME, } from './plugins/agent-a2ui-jupyter-output';
|
|
65
65
|
export { defineA2uiScenePlugin, } from './plugins/a2ui-scene';
|
|
66
|
+
export { APP_KIND_PATHS, APP_PAGE_PLUGIN_NAME, APP_PAGE_SURFACE, AppPage, appKindPaths, appPageAction, appPageData, defineAppPagePlugin, hasAppPage, surfaceUnshown, } from './plugins/app-page';
|
|
66
67
|
export { GraphViewPlugin, GRAPH_PLUGIN_NAME, GRAPH_VIEW_TYPE, } from './plugins/graph';
|
|
67
68
|
export { PluginsPanelPlugin, PLUGINS_PANEL_PLUGIN_NAME, PluginsPanel, } from './plugins/plugins-panel';
|
|
68
69
|
export { AGENTS_PLUGIN_NAME, AgentsPlugin, SandboxSelector, browserSource, createBrowserSandboxService, createServerSandboxService, createSwitchableSandboxService, suppliedSource, useOptionalSandboxService, useSandboxService, } from './plugins/agents';
|
|
@@ -81,6 +82,11 @@ export { LoopCommandsPlugin, COMMANDS_PLUGIN_NAME } from './plugins/commands';
|
|
|
81
82
|
export { PromptPlugin, PROMPT_PLUGIN_NAME } from './plugins/prompt';
|
|
82
83
|
// Loop, ready to drop into somebody else's page.
|
|
83
84
|
export { LoopEmbed } from './embed/LoopEmbed';
|
|
85
|
+
// An application in another product's page: the React component, the
|
|
86
|
+
// `<datalayer-app>` element, and the snippet a host pastes (LOOP D-07 to D-09).
|
|
87
|
+
export { AppEmbed } from './embed/AppEmbed';
|
|
88
|
+
export { defineDatalayerAppElement, } from './embed/element';
|
|
89
|
+
export { EMBED_ATTRIBUTES, EMBED_HOST_VARIABLES, EMBED_TAG, embedLookOf, embedSnippetOf, floatingViewOf, } from './embed/embedConfig';
|
|
84
90
|
export { SubagentActivityPlugin, SubagentPulse, SUBAGENT_ACTIVITY_PLUGIN_NAME, } from './plugins/subagent-activity';
|
|
85
91
|
// The set a workspace normally has, so a host starts from a working Loop
|
|
86
92
|
// rather than assembling one — and never from the example.
|
|
@@ -90,4 +96,4 @@ export { loopPlugins } from './presets';
|
|
|
90
96
|
export { DocumentExtension, NotebookExtension } from './extensions';
|
|
91
97
|
// Applications: what one does when its agent calls a tool — the rules a
|
|
92
98
|
// person wrote, decided on what the tool does.
|
|
93
|
-
export { BEHAVIOURS as APP_BEHAVIOUR_ORDER, DEFAULT_BEHAVIOURS as APP_DEFAULT_BEHAVIOURS, behaviourFor, classesOf, isReadOnly, toolBehaviours, toolEscalations, APP_SCHEMA, APPSPEC_KEY_ORDER, DEFAULT_LAYOUTS as APP_DEFAULT_LAYOUTS, dumpAppspec, emptyAppspec, parseAppspec, AppRenderer, checkApp, checkAppspec, defineAppPlugin, readAppspecYaml, writeAppspecYaml, } from './apps';
|
|
99
|
+
export { BEHAVIOURS as APP_BEHAVIOUR_ORDER, DEFAULT_BEHAVIOURS as APP_DEFAULT_BEHAVIOURS, behaviourFor, classesOf, isReadOnly, toolBehaviours, toolEscalations, APP_SCHEMA, APPSPEC_KEY_ORDER, DEFAULT_LAYOUTS as APP_DEFAULT_LAYOUTS, dumpAppspec, emptyAppspec, parseAppspec, AppRenderer, checkApp, checkAppspec, defineAppPlugin, appLayoutOptions, readAppspecYaml, writeAppspecYaml, } from './apps';
|
|
@@ -8,15 +8,33 @@
|
|
|
8
8
|
* follows, and what keeps a generated form from being the one light card in
|
|
9
9
|
* a dark workspace.
|
|
10
10
|
*
|
|
11
|
+
* The same renderer draws an application's page (`loop/plugins/app-page`):
|
|
12
|
+
* there the surface is fed live `data` by path as the conversation moves, and
|
|
13
|
+
* an action is handed the surface it came from, so that what a block wrote
|
|
14
|
+
* into its data model can be read when a button is pressed.
|
|
15
|
+
*
|
|
11
16
|
* @module loop/plugins/a2ui-surface/InlineSurface
|
|
12
17
|
*/
|
|
13
18
|
import type { JSX } from 'react';
|
|
14
|
-
import { type
|
|
19
|
+
import { type ReactComponentImplementation } from '@a2ui/react/v0_9';
|
|
20
|
+
import { type A2uiClientAction, type A2uiMessage, type SurfaceModel } from '@a2ui/web_core/v0_9';
|
|
21
|
+
/** A surface as the renderer holds it: its data model is `dataModel`. */
|
|
22
|
+
export type InlineSurfaceModel = SurfaceModel<ReactComponentImplementation>;
|
|
23
|
+
type Surface = InlineSurfaceModel;
|
|
15
24
|
/** The catalogue a surface is rewritten to before it is drawn. */
|
|
16
25
|
export declare const SURFACE_CATALOG_ID: string;
|
|
17
|
-
|
|
26
|
+
/** Values to publish into a surface, by path. */
|
|
27
|
+
export type InlineSurfaceData = Record<string, unknown>;
|
|
28
|
+
export declare function InlineSurface({ messages, onAction, validationError, data, }: {
|
|
18
29
|
messages: A2uiMessage[];
|
|
19
|
-
|
|
30
|
+
/** Told of an action, with the surface it came from. */
|
|
31
|
+
onAction: (action: A2uiClientAction, surface?: Surface) => void;
|
|
20
32
|
validationError?: string | null;
|
|
33
|
+
/**
|
|
34
|
+
* Values published into every surface's data model, by path, after the
|
|
35
|
+
* messages are processed and whenever one changes. Only a path whose value
|
|
36
|
+
* changed is written: what a person typed elsewhere in the model stays.
|
|
37
|
+
*/
|
|
38
|
+
data?: InlineSurfaceData;
|
|
21
39
|
}): JSX.Element | null;
|
|
22
40
|
export default InlineSurface;
|
|
@@ -12,12 +12,14 @@ const INHERIT_THEME = {
|
|
|
12
12
|
['--a2ui-color-primary']: 'var(--fgColor-accent)',
|
|
13
13
|
['--a2ui-color-outline']: 'var(--borderColor-default)',
|
|
14
14
|
};
|
|
15
|
-
export function InlineSurface({ messages, onAction, validationError, }) {
|
|
15
|
+
export function InlineSurface({ messages, onAction, validationError, data, }) {
|
|
16
16
|
// Reached through a ref: the processor is built once, and the handler it
|
|
17
17
|
// was built with must not go stale when the host's does not.
|
|
18
18
|
const onActionRef = useRef(onAction);
|
|
19
19
|
onActionRef.current = onAction;
|
|
20
|
-
const processor = useMemo(() => new MessageProcessor([basicCatalog], action => onActionRef.current(action)), []);
|
|
20
|
+
const processor = useMemo(() => new MessageProcessor([basicCatalog], action => onActionRef.current(action, processorRef.current?.model.getSurface(action.surfaceId))), []);
|
|
21
|
+
const processorRef = useRef(undefined);
|
|
22
|
+
processorRef.current = processor;
|
|
21
23
|
const [surfaces, setSurfaces] = useState([]);
|
|
22
24
|
useEffect(() => {
|
|
23
25
|
const created = processor.onSurfaceCreated(surface => setSurfaces(previous => [...previous, surface]));
|
|
@@ -28,15 +30,41 @@ export function InlineSurface({ messages, onAction, validationError, }) {
|
|
|
28
30
|
};
|
|
29
31
|
}, [processor]);
|
|
30
32
|
// Once: the messages are one tool result, processed when it arrives.
|
|
33
|
+
// A tree the catalog refuses is said, where it would have been drawn,
|
|
34
|
+
// rather than thrown out of an effect and taking the page down with it.
|
|
31
35
|
const processedRef = useRef(false);
|
|
36
|
+
const [processError, setProcessError] = useState(null);
|
|
32
37
|
useEffect(() => {
|
|
33
38
|
if (processedRef.current) {
|
|
34
39
|
return;
|
|
35
40
|
}
|
|
36
41
|
processedRef.current = true;
|
|
37
|
-
|
|
42
|
+
try {
|
|
43
|
+
processor.processMessages(messages);
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
setProcessError(`This surface could not be drawn: ${error instanceof Error ? error.message : String(error)}`);
|
|
47
|
+
}
|
|
38
48
|
}, [messages, processor]);
|
|
39
|
-
|
|
49
|
+
// After the messages: the surfaces exist by then, created synchronously.
|
|
50
|
+
const publishedRef = useRef({});
|
|
51
|
+
useEffect(() => {
|
|
52
|
+
if (!data) {
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
const published = publishedRef.current;
|
|
56
|
+
for (const [path, value] of Object.entries(data)) {
|
|
57
|
+
if (Object.is(published[path], value)) {
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
published[path] = value;
|
|
61
|
+
for (const surface of processor.model.surfacesMap.values()) {
|
|
62
|
+
surface.dataModel.set(path, value);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}, [data, processor]);
|
|
66
|
+
const notice = validationError || processError;
|
|
67
|
+
if (surfaces.length === 0 && !notice) {
|
|
40
68
|
return null;
|
|
41
69
|
}
|
|
42
70
|
return (_jsx(A2uiMarkdownProvider, { children: _jsxs(Box, { style: INHERIT_THEME, sx: {
|
|
@@ -44,7 +72,7 @@ export function InlineSurface({ messages, onAction, validationError, }) {
|
|
|
44
72
|
display: 'flex',
|
|
45
73
|
flexDirection: 'column',
|
|
46
74
|
gap: 2,
|
|
47
|
-
}, children: [
|
|
75
|
+
}, children: [notice ? (_jsx(Box, { role: "alert", sx: {
|
|
48
76
|
px: 3,
|
|
49
77
|
py: 2,
|
|
50
78
|
borderRadius: 2,
|
|
@@ -53,7 +81,7 @@ export function InlineSurface({ messages, onAction, validationError, }) {
|
|
|
53
81
|
borderColor: 'danger.muted',
|
|
54
82
|
color: 'danger.fg',
|
|
55
83
|
fontSize: 1,
|
|
56
|
-
}, children:
|
|
84
|
+
}, children: notice })) : null, surfaces.map(surface => (_jsx(Box, { sx: {
|
|
57
85
|
border: '1px solid',
|
|
58
86
|
borderColor: 'border.default',
|
|
59
87
|
borderRadius: 2,
|
|
@@ -34,6 +34,10 @@ export type AgentCapacityOptions = {
|
|
|
34
34
|
createPayload?: Record<string, unknown>;
|
|
35
35
|
/** The openers the empty chat offers for this capacity. */
|
|
36
36
|
suggestions?: ChatSuggestionItem[];
|
|
37
|
+
/** What the agent is told on top of its spec's prompt when the page turns it. */
|
|
38
|
+
instructions?: string;
|
|
39
|
+
/** The model it runs on in the page, in place of its spec's. */
|
|
40
|
+
model?: string;
|
|
37
41
|
};
|
|
38
42
|
export declare function defineAgentCapacityPlugin(options: AgentCapacityOptions): ReactorPlugin<Record<string, never>, unknown, unknown>;
|
|
39
43
|
export default defineAgentCapacityPlugin;
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
import { contribution, definePlugin, } from '@datalayer/reactor';
|
|
24
24
|
import { LoopAgentBlueprint, LoopChatSuggestion, } from '../../core';
|
|
25
25
|
export function defineAgentCapacityPlugin(options) {
|
|
26
|
-
const { key, displayName, description, specId, octicon, emoji, codemode, createPayload, suggestions, } = options;
|
|
26
|
+
const { key, displayName, description, specId, octicon, emoji, codemode, createPayload, suggestions, instructions, model, } = options;
|
|
27
27
|
return definePlugin({
|
|
28
28
|
name: `@datalayer/loop-plugin-agent-${key}`,
|
|
29
29
|
displayName,
|
|
@@ -40,6 +40,8 @@ export function defineAgentCapacityPlugin(options) {
|
|
|
40
40
|
enable_codemode: codemode ?? false,
|
|
41
41
|
...createPayload,
|
|
42
42
|
},
|
|
43
|
+
...(instructions ? { instructions } : {}),
|
|
44
|
+
...(model ? { model } : {}),
|
|
43
45
|
}, { id: key }),
|
|
44
46
|
...(suggestions && suggestions.length > 0
|
|
45
47
|
? [
|
|
@@ -105,3 +105,10 @@ export type SwitchableConfig = {
|
|
|
105
105
|
kernelSource?: ServiceManagerSource;
|
|
106
106
|
};
|
|
107
107
|
export declare function createSwitchableSandboxService({ serverUrl, initialTarget, kernelSource, localAgent, blueprint, }: SwitchableConfig): SwitchableSandboxService;
|
|
108
|
+
/**
|
|
109
|
+
* Create the agent whose per-agent Jupyter sandbox backs Local, on the
|
|
110
|
+
* agent-runtimes server at `serverUrl`, unless it is there already — then
|
|
111
|
+
* only its sandbox is asked for. Exported for a host that addresses the
|
|
112
|
+
* agent without a workspace: the embed's floating modes (`AppEmbed`).
|
|
113
|
+
*/
|
|
114
|
+
export declare function ensureServerAgent(serverUrl: string, agentId: string | undefined, createPayload: Record<string, unknown>): Promise<void>;
|