@datalayer/agent-runtimes 1.3.19 → 1.3.20

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.
@@ -20,5 +20,14 @@ export type AppRendererProps = Omit<LoopEmbedProps, 'agentId'> & {
20
20
  /** The application to render. */
21
21
  app: AppSpec;
22
22
  };
23
+ /**
24
+ * An application in a LOOP workspace: its agent, its starters, its layout.
25
+ *
26
+ * Every other prop is `LoopEmbed`'s, and wins over what the application
27
+ * implies — a host that wants the editors beside a chat still says so.
28
+ */
29
+ /** No host plugins: one array, so that it never reads as a change. */
30
+ /** The agentspec a runtime is allocated with before an application's agent is created on it. */
31
+ export declare const DATALAYER_BOOTSTRAP_AGENTSPEC = "example-simple";
23
32
  export declare function AppRenderer({ app, plugins, ...embed }: AppRendererProps): React.JSX.Element;
24
33
  export default AppRenderer;
@@ -73,6 +73,8 @@ export function defineAppPlugin(app) {
73
73
  * implies — a host that wants the editors beside a chat still says so.
74
74
  */
75
75
  /** No host plugins: one array, so that it never reads as a change. */
76
+ /** The agentspec a runtime is allocated with before an application's agent is created on it. */
77
+ export const DATALAYER_BOOTSTRAP_AGENTSPEC = 'example-simple';
76
78
  const NO_PLUGINS = [];
77
79
  export function AppRenderer({ app, plugins = NO_PLUGINS, ...embed }) {
78
80
  const chatOnly = app.interface.layout === 'chat';
@@ -87,6 +89,28 @@ export function AppRenderer({ app, plugins = NO_PLUGINS, ...embed }) {
87
89
  // eslint-disable-next-line react-hooks/exhaustive-deps
88
90
  [source]);
89
91
  const allPlugins = useMemo(() => (appPlugin ? [appPlugin, ...plugins] : plugins), [appPlugin, plugins]);
92
+ /*
93
+ * On Datalayer, the application runs on a runtime: allocated with a plain
94
+ * agentspec, its agent created there with the application's spec — so that
95
+ * the runtime registers it and decides every tool call by its rules (LOOP
96
+ * R-03, R-05), as `loop apps run --cloud` does.
97
+ */
98
+ const datalayerCreatePayload = useMemo(() => app.agent
99
+ ? {
100
+ // Under the application's id, over AG-UI: what the workspace's
101
+ // chat addresses (`agentId` below).
102
+ name: app.id,
103
+ transport: 'ag-ui',
104
+ agent_spec_id: agentIdOf(app),
105
+ app_spec: dumpAppspec(app),
106
+ // Code Mode calls every tool through `execute_code`, which an
107
+ // application without a shell is refused: its tools are called
108
+ // one by one instead, each decided by its rules.
109
+ enable_codemode: Boolean(app.permissions?.computer?.shell),
110
+ }
111
+ : undefined,
112
+ // eslint-disable-next-line react-hooks/exhaustive-deps
113
+ [source]);
90
114
  if (!appPlugin) {
91
115
  return (_jsxs("div", { role: "status", style: { padding: 16 }, children: ["\u201C", app.name, "\u201D is run by a team, which the workspace does not run as an application yet."] }));
92
116
  }
@@ -96,6 +120,9 @@ export function AppRenderer({ app, plugins = NO_PLUGINS, ...embed }) {
96
120
  , {
97
121
  // The application's own agent: created under its id, so that its
98
122
  // spec is applied to an agent of its own, never to the one it extends.
99
- agentId: app.id, editors: !chatOnly, showViewSelector: !chatOnly, teamPicker: false, showAgentVariants: false, graph: false, pluginsPanel: false, ...embed, plugins: allPlugins }));
123
+ agentId: app.id, editors: !chatOnly, showViewSelector: !chatOnly, teamPicker: false, showAgentVariants: false, graph: false, pluginsPanel: false, datalayerAgentSpecId: DATALAYER_BOOTSTRAP_AGENTSPEC,
124
+ // Where an application runs is decided by its host — the Studio's
125
+ // Preview, the hosted page — not offered to its user.
126
+ targetFixed: true, datalayerCreatePayload: datalayerCreatePayload, ...embed, plugins: allPlugins }));
100
127
  }
101
128
  export default AppRenderer;
@@ -63,6 +63,10 @@ export function LoopEmbed({ agentId = '', showHeader = false, chatHeaderActions,
63
63
  [
64
64
  preset.serverUrl,
65
65
  preset.target,
66
+ preset.datalayerAgentSpecId,
67
+ preset.targetFixed,
68
+ // By its content: an application's spec written inline is a new object each render.
69
+ JSON.stringify(preset.datalayerCreatePayload ?? null),
66
70
  preset.defaultEditor,
67
71
  preset.showViewSelector,
68
72
  preset.hideChatHeader,
@@ -19,8 +19,9 @@ import { useOptionalSandboxService } from './useSandboxService';
19
19
  const DEFAULT_DATALAYER_AGENTSPEC = 'jupyter-tutor';
20
20
  export function DatalayerAgentBridge() {
21
21
  const reactor = useReactorPlatform();
22
- const agentSpecId = reactor.getConfig(AGENTS_PLUGIN_NAME)?.datalayerAgentSpecId ??
23
- DEFAULT_DATALAYER_AGENTSPEC;
22
+ const agentsConfig = reactor.getConfig(AGENTS_PLUGIN_NAME);
23
+ const agentSpecId = agentsConfig?.datalayerAgentSpecId ?? DEFAULT_DATALAYER_AGENTSPEC;
24
+ const createPayload = agentsConfig?.datalayerCreatePayload;
24
25
  const service = useOptionalSandboxService();
25
26
  const target = useSignalValue(service?.target ?? IDLE_SANDBOX_TARGET_SIGNAL);
26
27
  const onDatalayer = target === 'datalayer';
@@ -45,12 +46,21 @@ export function DatalayerAgentBridge() {
45
46
  * spec id in it and hands that over. Same thing, said in the place the
46
47
  * creation actually looks.
47
48
  */
49
+ // An application names its own agent and transport; a bare spec, the spec's.
50
+ const agentName = typeof createPayload?.name === 'string' ? createPayload.name : agentSpecId;
51
+ const protocol = createPayload?.transport === 'ag-ui' ||
52
+ createPayload?.transport === 'vercel-ai'
53
+ ? createPayload.transport
54
+ : undefined;
48
55
  const agentConfig = useMemo(() => ({
49
- name: agentSpecId,
56
+ name: agentName,
57
+ ...(protocol ? { protocol } : {}),
50
58
  agentSpecId,
51
59
  model: AGENTSPECS[agentSpecId]?.model,
52
60
  description: AGENTSPECS[agentSpecId]?.description,
53
- }), [agentSpecId]);
61
+ // An application's spec, when the workspace runs one.
62
+ ...(createPayload ? { createPayload } : {}),
63
+ }), [agentSpecId, agentName, protocol, createPayload]);
54
64
  const { runtime, status, error } = useAgentRuntimes({
55
65
  agentSpecId,
56
66
  agentConfig,
@@ -73,6 +73,18 @@ export type AgentsConfig = {
73
73
  * The other targets take their agent from wherever they already run one.
74
74
  */
75
75
  datalayerAgentSpecId?: string;
76
+ /**
77
+ * What the agent created on that runtime is created with besides its spec:
78
+ * an application's `app_spec`, so that the runtime runs the application and
79
+ * decides its tool calls by its rules (LOOP R-05, R-03).
80
+ */
81
+ datalayerCreatePayload?: Record<string, unknown>;
82
+ /**
83
+ * The target is the host's decision, not the reader's: started there even
84
+ * with the control hidden. For an application that runs where it is
85
+ * deployed; a workspace leaves it unset.
86
+ */
87
+ targetFixed?: boolean;
76
88
  };
77
89
  export type AgentsOutput = {
78
90
  sandbox: SwitchableSandboxService;
@@ -57,8 +57,10 @@ export const AgentsPlugin = definePlugin({
57
57
  sandbox: createSwitchableSandboxService({
58
58
  serverUrl: config.serverUrl,
59
59
  // Pinned when there is no choice to make: a host that hid the control
60
- // must not be started on a target the reader cannot move off.
61
- initialTarget: showVariants ? config.target : 'browser',
60
+ // must not be started on a target the reader cannot move off — unless
61
+ // the host fixed the target itself, as an application deployed on
62
+ // Datalayer is (AppRenderer): there is nothing for the reader to move.
63
+ initialTarget: showVariants || config.targetFixed ? config.target : 'browser',
62
64
  kernelSource: config.kernelSource,
63
65
  localAgent: config.localAgent,
64
66
  // The capacity plugins' say, read at switch time — lazily, because a
@@ -120,6 +120,12 @@ export type LoopPresetOptions = {
120
120
  teamId?: string;
121
121
  /** What a local agent is created from, when one is. */
122
122
  localAgent?: AgentsConfig['localAgent'];
123
+ /** The agentspec a Datalayer runtime is allocated with (the `datalayer` target). */
124
+ datalayerAgentSpecId?: string;
125
+ /** What the agent on that runtime is created with besides its spec — an `app_spec`. */
126
+ datalayerCreatePayload?: Record<string, unknown>;
127
+ /** The target is the host's to fix, even with the agent control hidden. */
128
+ targetFixed?: boolean;
123
129
  /**
124
130
  * The agentspec the local agent is created from, by id.
125
131
  *
@@ -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, 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, 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.
@@ -88,6 +88,9 @@ export function loopPlugins(options = {}) {
88
88
  configurePlugin(AgentsPlugin, {
89
89
  serverUrl,
90
90
  target,
91
+ datalayerAgentSpecId,
92
+ datalayerCreatePayload,
93
+ targetFixed,
91
94
  showAgentVariants,
92
95
  showAgentSummary: agentSummary,
93
96
  teamId,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@datalayer/agent-runtimes",
3
- "version": "1.3.19",
3
+ "version": "1.3.20",
4
4
  "type": "module",
5
5
  "workspaces": [
6
6
  ".",