@datalayer/agent-runtimes 1.3.29 → 1.3.32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (107) hide show
  1. package/lib/AgentNode.js +14 -33
  2. package/lib/chat/ChatFloating.js +40 -8
  3. package/lib/chat/assistant/AssistantStage.d.ts +26 -7
  4. package/lib/chat/assistant/AssistantStage.js +115 -8
  5. package/lib/chat/assistant/SpeechBalloon.js +7 -3
  6. package/lib/chat/assistant/characters.d.ts +32 -1
  7. package/lib/chat/assistant/characters.js +180 -15
  8. package/lib/chat/assistant/state.d.ts +28 -0
  9. package/lib/chat/assistant/state.js +31 -0
  10. package/lib/chat/base/ChatBase.js +74 -50
  11. package/lib/chat/base/modelChoice.d.ts +40 -1
  12. package/lib/chat/base/modelChoice.js +42 -15
  13. package/lib/chat/prompt/InputPrompt.d.ts +7 -1
  14. package/lib/chat/prompt/InputPrompt.js +2 -2
  15. package/lib/chat/prompt/InputPromptBase.js +1 -1
  16. package/lib/chat/prompt/menus/ModelSelector.d.ts +13 -1
  17. package/lib/chat/prompt/menus/ModelSelector.js +17 -5
  18. package/lib/chat/useViewportDrag.d.ts +9 -1
  19. package/lib/chat/useViewportDrag.js +4 -4
  20. package/lib/components/a2ui/index.d.ts +2 -0
  21. package/lib/components/a2ui/index.js +2 -0
  22. package/lib/components/a2ui/visibility.d.ts +15 -0
  23. package/lib/components/a2ui/visibility.js +24 -0
  24. package/lib/components/a2ui/visibleWhen.d.ts +17 -0
  25. package/lib/components/a2ui/visibleWhen.js +54 -0
  26. package/lib/examples/ChatAssistantExample.d.ts +4 -0
  27. package/lib/examples/ChatAssistantExample.js +26 -5
  28. package/lib/examples/utils/owlCharacterPlugin.d.ts +7 -0
  29. package/lib/examples/utils/owlCharacterPlugin.js +44 -0
  30. package/lib/loop/apps/AppFeedback.d.ts +27 -0
  31. package/lib/loop/apps/AppFeedback.js +78 -0
  32. package/lib/loop/apps/AppRenderer.d.ts +33 -1
  33. package/lib/loop/apps/AppRenderer.js +111 -29
  34. package/lib/loop/apps/agent.d.ts +15 -0
  35. package/lib/loop/apps/agent.js +42 -0
  36. package/lib/loop/apps/appspec.js +6 -3
  37. package/lib/loop/apps/checks.d.ts +10 -2
  38. package/lib/loop/apps/checks.js +21 -10
  39. package/lib/loop/apps/feedback.d.ts +51 -0
  40. package/lib/loop/apps/feedback.js +61 -0
  41. package/lib/loop/apps/index.d.ts +3 -0
  42. package/lib/loop/apps/index.js +3 -0
  43. package/lib/loop/apps/rules.d.ts +14 -0
  44. package/lib/loop/apps/rules.js +24 -0
  45. package/lib/loop/core/canvasBlocks.d.ts +16 -0
  46. package/lib/loop/core/canvasBlocks.js +13 -0
  47. package/lib/loop/core/index.d.ts +15 -0
  48. package/lib/loop/core/index.js +3 -0
  49. package/lib/loop/embed/AppEmbed.d.ts +42 -0
  50. package/lib/loop/embed/AppEmbed.js +205 -0
  51. package/lib/loop/embed/datalayer-app.d.ts +1 -0
  52. package/lib/loop/embed/datalayer-app.js +16 -0
  53. package/lib/loop/embed/element.d.ts +57 -0
  54. package/lib/loop/embed/element.js +405 -0
  55. package/lib/loop/embed/embedConfig.d.ts +120 -0
  56. package/lib/loop/embed/embedConfig.js +148 -0
  57. package/lib/loop/embed/embedTheme.d.ts +24 -0
  58. package/lib/loop/embed/embedTheme.js +83 -0
  59. package/lib/loop/index.d.ts +6 -2
  60. package/lib/loop/index.js +8 -2
  61. package/lib/loop/plugins/a2ui/A2uiView.js +2 -3
  62. package/lib/loop/plugins/a2ui-surface/InlineSurface.d.ts +23 -3
  63. package/lib/loop/plugins/a2ui-surface/InlineSurface.js +36 -9
  64. package/lib/loop/plugins/agent-capacity/index.d.ts +4 -0
  65. package/lib/loop/plugins/agent-capacity/index.js +3 -1
  66. package/lib/loop/plugins/agents/switchable.d.ts +7 -0
  67. package/lib/loop/plugins/agents/switchable.js +91 -88
  68. package/lib/loop/plugins/app-page/AppPage.d.ts +16 -0
  69. package/lib/loop/plugins/app-page/AppPage.js +53 -0
  70. package/lib/loop/plugins/app-page/appPageModel.d.ts +180 -0
  71. package/lib/loop/plugins/app-page/appPageModel.js +443 -0
  72. package/lib/loop/plugins/app-page/index.d.ts +8 -0
  73. package/lib/loop/plugins/app-page/index.js +34 -0
  74. package/lib/loop/plugins/canvas-blocks/index.d.ts +63 -0
  75. package/lib/loop/plugins/canvas-blocks/index.js +118 -0
  76. package/lib/loop/plugins/chat/ChatView.js +52 -26
  77. package/lib/loop/plugins/chat/turnState.d.ts +5 -2
  78. package/lib/loop/plugins/chat/turnState.js +2 -1
  79. package/lib/loop/plugins/page-layout/SplitLayout.d.ts +31 -0
  80. package/lib/loop/plugins/page-layout/SplitLayout.js +129 -0
  81. package/lib/loop/plugins/page-layout/index.d.ts +13 -0
  82. package/lib/loop/plugins/page-layout/index.js +10 -1
  83. package/lib/loop/presets.d.ts +12 -0
  84. package/lib/loop/presets.js +5 -3
  85. package/lib/specs/actions.js +9 -0
  86. package/lib/specs/agents/agents.js +20 -4
  87. package/lib/specs/apps.d.ts +10 -1
  88. package/lib/specs/apps.js +1779 -154
  89. package/lib/specs/appspecSchema.js +14 -8
  90. package/lib/specs/models.d.ts +1 -1
  91. package/lib/specs/models.js +8 -8
  92. package/lib/specs/tools.d.ts +1 -0
  93. package/lib/specs/tools.js +19 -0
  94. package/lib/stories/loop/LoopReference.stories.d.ts +21 -0
  95. package/lib/stories/loop/LoopReference.stories.js +31 -0
  96. package/lib/stories/loop/ReferenceScreens.d.ts +53 -0
  97. package/lib/stories/loop/ReferenceScreens.js +256 -0
  98. package/lib/stories/loop/pictures-main.d.ts +1 -0
  99. package/lib/stories/loop/pictures-main.js +64 -0
  100. package/lib/types/agentspecs.d.ts +17 -1
  101. package/lib/types/chat.d.ts +5 -0
  102. package/lib/types/config.d.ts +20 -0
  103. package/package.json +10 -6
  104. package/scripts/check-cloudflare-models.py +2 -2
  105. package/scripts/codegen/generate_agents.py +50 -2
  106. package/scripts/codegen/generate_apps.py +38 -7
  107. package/scripts/codegen/generate_models.py +4 -4
@@ -0,0 +1,42 @@
1
+ import type { CSSProperties, JSX, ReactNode } from 'react';
2
+ import type { AppAccent, AppEmbedMode, AppSpec } from '../../types/agentspecs';
3
+ import { type AppInstance } from '../apps/AppRenderer';
4
+ import { type EmbedColorMode } from './embedConfig';
5
+ export type AppEmbedProps = {
6
+ /** The application. */
7
+ app: AppSpec;
8
+ /** How it sits in the page; the Appspec's `deployment.embedded.mode` by default. */
9
+ mode?: AppEmbedMode;
10
+ /** The host's accent; the application's own by default. */
11
+ accent?: AppAccent;
12
+ /** Light, dark, or the visitor's system. */
13
+ colorMode?: EmbedColorMode;
14
+ /** The host's face, a CSS font family; the theme's by default. */
15
+ font?: string;
16
+ /**
17
+ * An agent-runtimes server the application's agent runs on. Without one,
18
+ * it runs on a Datalayer runtime, launched with the visitor's Datalayer
19
+ * credentials.
20
+ */
21
+ serverUrl?: string;
22
+ /** What its record is kept under, on Datalayer. */
23
+ instance?: AppInstance;
24
+ /** Height of an inline application. */
25
+ height?: number | string;
26
+ /**
27
+ * Draw overlays — menus, dialogs — inside the embed's own root rather than
28
+ * in Primer's, in the host's `<body>`: what the element asks for, since a
29
+ * shadow root's styles stop at its edge. A React host leaves it off.
30
+ */
31
+ ownPortal?: boolean;
32
+ };
33
+ /** The `loop` theme, with the application's (or the host's) accent and face. */
34
+ export declare function EmbedThemed({ accent, colorMode, font, children, style, }: {
35
+ accent: AppAccent;
36
+ colorMode: 'light' | 'dark';
37
+ font?: string;
38
+ children: ReactNode;
39
+ style?: CSSProperties;
40
+ }): JSX.Element;
41
+ export declare function AppEmbed({ app, mode, accent, colorMode, font, serverUrl, instance, height, ownPortal, }: AppEmbedProps): JSX.Element;
42
+ export default AppEmbed;
@@ -0,0 +1,205 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /*
3
+ * Copyright (c) 2025-2026 Datalayer, Inc.
4
+ * Distributed under the terms of the Modified BSD License.
5
+ */
6
+ /**
7
+ * An application in another product's page, as a React component (LOOP
8
+ * D-07, D-09, D-11): what the `<datalayer-app>` element draws, and what a
9
+ * host that uses React mounts itself.
10
+ *
11
+ * Four modes, as the Appspec says (`deployment.embedded.mode`) or the host:
12
+ *
13
+ * - **inline** — the application where the component is: `AppRenderer`, its
14
+ * page beside its conversation when it has one;
15
+ * - **bubble** — a round button in the corner that opens the conversation in
16
+ * a popup, the copilot pattern;
17
+ * - **panel** — the conversation at the right edge of the page, at full
18
+ * height;
19
+ * - **assistant** — the application's character on the page, speaking in a
20
+ * balloon (§6.9), the one its Appspec names (`interface.assistant`).
21
+ *
22
+ * The three floating modes are `ChatFloating`'s, given the application's
23
+ * name, welcome, starters and accent, and its agent's endpoint — created
24
+ * with the application's spec in its payload, so the runtime enforces its
25
+ * rules there as it does inline.
26
+ *
27
+ * In the `loop` theme with the application's accent (T-12, T-05), which the
28
+ * host may override with the face and the mode (D-11).
29
+ *
30
+ * @module loop/embed/AppEmbed
31
+ */
32
+ import { useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';
33
+ import { registerPortalRoot } from '@primer/react';
34
+ import { DatalayerThemeProvider, loopTheme } from '@datalayer/primer-addons';
35
+ import { useIAMStore } from '@datalayer/core/lib/state/substates/IAMState';
36
+ import { ChatFloating } from '../../chat/ChatFloating';
37
+ import { useAgentRuntimes } from '../../hooks/useAgentRuntimes';
38
+ import { AppRenderer, DATALAYER_BOOTSTRAP_AGENTSPEC, appDatalayerCreatePayload, defineAppPlugin, } from '../apps/AppRenderer';
39
+ import { LoopAgentBlueprint } from '../core';
40
+ import { ensureServerAgent } from '../plugins/agents/switchable';
41
+ import { floatingViewOf } from './embedConfig';
42
+ import { embedThemeStyles } from './embedTheme';
43
+ /** What the application's agent is created with on an agent-runtimes server. */
44
+ function serverCreatePayload(app) {
45
+ const blueprint = (defineAppPlugin(app).contributes ?? []).find((item) => item.point === LoopAgentBlueprint);
46
+ return blueprint?.value.createPayload ?? { name: app.id };
47
+ }
48
+ /**
49
+ * The application's agent on the host's agent-runtimes server: created
50
+ * there with the application's spec unless it is there already, as the
51
+ * workspace's Local target does.
52
+ */
53
+ function useServerAgent(app, serverUrl) {
54
+ const [state, setState] = useState({
55
+ waiting: 'Starting…',
56
+ });
57
+ const source = JSON.stringify(app);
58
+ useEffect(() => {
59
+ let cancelled = false;
60
+ const base = serverUrl.replace(/\/+$/, '');
61
+ setState({ waiting: 'Starting…' });
62
+ ensureServerAgent(base, app.id, serverCreatePayload(app)).then(() => {
63
+ if (!cancelled) {
64
+ setState({
65
+ protocol: {
66
+ type: 'ag-ui',
67
+ endpoint: `${base}/api/v1/ag-ui/${app.id}/`,
68
+ agentId: app.id,
69
+ },
70
+ });
71
+ }
72
+ }, (error) => {
73
+ if (!cancelled) {
74
+ setState({
75
+ error: error instanceof Error ? error.message : String(error),
76
+ });
77
+ }
78
+ });
79
+ return () => {
80
+ cancelled = true;
81
+ };
82
+ // eslint-disable-next-line react-hooks/exhaustive-deps
83
+ }, [serverUrl, source]);
84
+ return state;
85
+ }
86
+ /**
87
+ * The application's agent on a Datalayer runtime: allocated with a plain
88
+ * agentspec, the agent created there with the application's spec — the
89
+ * runtime `AppRenderer` launches inline (R-03, R-05).
90
+ */
91
+ function useDatalayerAgent(app, instance) {
92
+ const token = useIAMStore(state => state.token);
93
+ const source = JSON.stringify(app);
94
+ const agentConfig = useMemo(() => ({
95
+ name: app.id,
96
+ protocol: 'ag-ui',
97
+ agentSpecId: DATALAYER_BOOTSTRAP_AGENTSPEC,
98
+ createPayload: appDatalayerCreatePayload(app, instance),
99
+ }),
100
+ // eslint-disable-next-line react-hooks/exhaustive-deps
101
+ [source, instance?.appUid, instance?.deploymentUid, instance?.version]);
102
+ const { runtime, error } = useAgentRuntimes({
103
+ agentSpecId: DATALAYER_BOOTSTRAP_AGENTSPEC,
104
+ agentConfig,
105
+ variant: 'cloud-pydanticai',
106
+ // Only for a visitor Datalayer knows: a runtime is somebody's to pay for.
107
+ autoStart: Boolean(token),
108
+ autoCreateAgent: Boolean(token),
109
+ });
110
+ if (!token) {
111
+ return {
112
+ error: `${app.name} runs on Datalayer, which needs you signed in. An application embedded for visitors who are not needs its embed token (LOOP D-14), or an agent-runtimes server of the host's own (the "server" attribute).`,
113
+ };
114
+ }
115
+ if (error) {
116
+ return { error };
117
+ }
118
+ if (!runtime?.agentBaseUrl) {
119
+ return { waiting: 'Starting…' };
120
+ }
121
+ return {
122
+ protocol: {
123
+ type: 'ag-ui',
124
+ endpoint: `${runtime.agentBaseUrl}/api/v1/ag-ui/${app.id}/`,
125
+ agentId: app.id,
126
+ authToken: token,
127
+ },
128
+ };
129
+ }
130
+ /** The application's face, as the floating chat's button and header draw it. */
131
+ function Face({ emoji }) {
132
+ return (_jsx("span", { "aria-hidden": true, style: { fontSize: 18, lineHeight: 1 }, children: emoji }));
133
+ }
134
+ /** The bubble, the panel and the assistant: `ChatFloating` in that mode. */
135
+ function FloatingChat({ app, view, colorMode, agent, }) {
136
+ const welcome = app.interface.welcome || app.description;
137
+ return (_jsx(ChatFloating
138
+ // A new agent is a new conversation.
139
+ , { defaultViewMode: view, assistantCharacter: app.interface.assistant ?? 'paperclip', protocol: agent.protocol, authToken: agent.protocol?.authToken, title: app.name, description: welcome, brandIcon: _jsx(Face, { emoji: app.emoji }), buttonIcon: _jsx(Face, { emoji: app.emoji }), buttonTooltip: `Talk to ${app.name}`, suggestions: app.interface.starters.map(starter => ({
140
+ title: starter.label,
141
+ message: starter.message,
142
+ })), themeVariant: "loop", colorMode: colorMode, showTokenUsage: false, showSettingsButton: false, showPoweredBy: false, useStore: false, launching: !agent.protocol && !agent.error, launchingMessage: agent.waiting, disabled: Boolean(agent.error), disableReason: agent.error }, agent.protocol?.endpoint ?? 'waiting'));
143
+ }
144
+ /** Floating, its agent on the host's agent-runtimes server. */
145
+ function ServerFloating({ serverUrl, ...props }) {
146
+ return (_jsx(FloatingChat, { ...props, agent: useServerAgent(props.app, serverUrl) }));
147
+ }
148
+ /** Floating, its agent on a Datalayer runtime. */
149
+ function DatalayerFloating({ instance, ...props }) {
150
+ return (_jsx(FloatingChat, { ...props, agent: useDatalayerAgent(props.app, instance) }));
151
+ }
152
+ /**
153
+ * Overlays — menus, dialogs — drawn inside the embed's own root, under the
154
+ * theme's element, so that they wear its theme: what the element asks for,
155
+ * since Primer's own portal root is in the host's `<body>`, outside the
156
+ * shadow root and its styles.
157
+ */
158
+ function OwnPortalRoot() {
159
+ const ref = useRef(null);
160
+ useLayoutEffect(() => {
161
+ if (ref.current) {
162
+ registerPortalRoot(ref.current);
163
+ }
164
+ }, []);
165
+ return _jsx("div", { ref: ref, className: "datalayer-app-portal" });
166
+ }
167
+ /** The visitor's system mode, followed while it changes. */
168
+ function useSystemMode() {
169
+ const query = typeof window !== 'undefined' && typeof window.matchMedia === 'function'
170
+ ? window.matchMedia('(prefers-color-scheme: dark)')
171
+ : null;
172
+ const [dark, setDark] = useState(Boolean(query?.matches));
173
+ useEffect(() => {
174
+ if (!query) {
175
+ return undefined;
176
+ }
177
+ const follow = () => setDark(query.matches);
178
+ query.addEventListener?.('change', follow);
179
+ return () => query.removeEventListener?.('change', follow);
180
+ }, [query]);
181
+ return dark ? 'dark' : 'light';
182
+ }
183
+ /** The `loop` theme, with the application's (or the host's) accent and face. */
184
+ export function EmbedThemed({ accent, colorMode, font, children, style, }) {
185
+ const themeStyles = useMemo(() => embedThemeStyles({ accent, font }), [accent, font]);
186
+ return (
187
+ /*
188
+ * Marked as themed above the provider, so that the provider counts
189
+ * itself nested and leaves the host's <body> and Primer's portal root
190
+ * alone: it would otherwise write the theme's tokens, colour and face on
191
+ * the host's page (T-13). A wrapper of no box.
192
+ */
193
+ _jsx("div", { "data-color-mode": colorMode, style: { display: 'contents' }, children: _jsx(DatalayerThemeProvider, { colorMode: colorMode, theme: loopTheme, themeStyles: themeStyles, baseStyles: style, children: children }) }));
194
+ }
195
+ export function AppEmbed({ app, mode, accent, colorMode = 'auto', font, serverUrl, instance, height = 640, ownPortal = false, }) {
196
+ const system = useSystemMode();
197
+ const resolvedMode = colorMode === 'auto' ? system : colorMode;
198
+ const shownAs = mode ?? app.deployment.embedded?.mode ?? 'inline';
199
+ const view = floatingViewOf(shownAs);
200
+ return (_jsxs(EmbedThemed, { accent: accent ?? app.interface.accent, colorMode: resolvedMode, font: font, style: view
201
+ ? // Floating: nothing in the page's flow, nothing painted behind.
202
+ { backgroundColor: 'transparent' }
203
+ : { height, display: 'flex', flexDirection: 'column' }, children: [ownPortal ? _jsx(OwnPortalRoot, {}) : null, view && serverUrl ? (_jsx(ServerFloating, { app: app, view: view, serverUrl: serverUrl, colorMode: resolvedMode })) : view ? (_jsx(DatalayerFloating, { app: app, view: view, instance: instance, colorMode: resolvedMode })) : (_jsx(AppRenderer, { app: app, target: serverUrl ? 'local' : 'datalayer', ...(serverUrl ? { serverUrl } : {}), instance: instance }))] }));
204
+ }
205
+ export default AppEmbed;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,16 @@
1
+ /*
2
+ * Copyright (c) 2025-2026 Datalayer, Inc.
3
+ * Distributed under the terms of the Modified BSD License.
4
+ */
5
+ /**
6
+ * The one script a host loads (LOOP D-08): it defines `<datalayer-app>` and
7
+ * nothing else. Built on its own by `npm run build:embed`
8
+ * (`vite.embed.config.ts`) into `dist-embed/datalayer-app.js`, with the
9
+ * stylesheet the element links into its shadow root beside it
10
+ * (`dist-embed/datalayer-app.css`); served from a Datalayer origin at
11
+ * `/embed/`.
12
+ *
13
+ * @module loop/embed/datalayer-app
14
+ */
15
+ import { defineDatalayerAppElement } from './element';
16
+ defineDatalayerAppElement();
@@ -0,0 +1,57 @@
1
+ import type { AppSpec } from '../../types/agentspecs';
2
+ import { type ParsedAppspec } from '../apps/appspec';
3
+ /** What the framed run page and the element say to each other. */
4
+ export declare const EMBED_MESSAGES: {
5
+ readonly size: "datalayer-app:size";
6
+ readonly decision: "datalayer-app:decision";
7
+ /** To the frame: an embed token, the first or a new one. */
8
+ readonly token: "datalayer-app:token";
9
+ /** From the frame: the token lapsed; a new one is needed. */
10
+ readonly tokenExpired: "datalayer-app:token-expired";
11
+ };
12
+ /** Where an application comes from, once read. */
13
+ export type EmbedSource = {
14
+ kind: 'spec';
15
+ app: AppSpec;
16
+ } | {
17
+ kind: 'frame';
18
+ src: string;
19
+ } | {
20
+ kind: 'said';
21
+ text: string;
22
+ expired?: boolean;
23
+ };
24
+ /** An Appspec from its text, YAML or JSON; refused in a sentence when it is neither. */
25
+ export declare function appspecOfText(text: string): AppSpec;
26
+ /**
27
+ * An application the embed can run, or a sentence saying why not: one with
28
+ * an id, and an agent to answer — what the spec tolerates in a draft, an
29
+ * embed cannot run.
30
+ */
31
+ export declare function runnable({ app, problems }: ParsedAppspec): AppSpec;
32
+ /** The run page an application on Datalayer is framed from. */
33
+ export declare function frameSrcOf(origin: string, app: string, token?: string): string;
34
+ /**
35
+ * An application on Datalayer, read with its embed token: what the space
36
+ * keeps of it (`model_s`, the stored definition), whose `spec` is the
37
+ * Appspec. A decision is framed; so is an application that has no spec.
38
+ */
39
+ export declare function readEmbeddedApp({ api, origin, app, token, fetcher, }: {
40
+ api: string;
41
+ origin: string;
42
+ app: string;
43
+ token: string;
44
+ fetcher?: typeof fetch;
45
+ }): Promise<EmbedSource>;
46
+ export type DatalayerAppElementOptions = {
47
+ /** The element's name; `datalayer-app` by default. */
48
+ tag?: string;
49
+ /** Where the script was loaded from: the default origin, and where its stylesheet is. */
50
+ scriptUrl?: string;
51
+ };
52
+ /**
53
+ * Define the element, once. Returns its class, or `undefined` where there is
54
+ * no `customElements` (a server render) — a second call returns the class
55
+ * already defined.
56
+ */
57
+ export declare function defineDatalayerAppElement(options?: DatalayerAppElementOptions): CustomElementConstructor | undefined;