@datalayer/agent-runtimes 1.3.16 → 1.3.18

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 (41) hide show
  1. package/lib/loop/apps/AppRenderer.d.ts +24 -0
  2. package/lib/loop/apps/AppRenderer.js +101 -0
  3. package/lib/loop/apps/appspec.d.ts +69 -0
  4. package/lib/loop/apps/appspec.js +574 -0
  5. package/lib/loop/apps/checks.d.ts +21 -0
  6. package/lib/loop/apps/checks.js +565 -0
  7. package/lib/loop/apps/index.d.ts +10 -0
  8. package/lib/loop/apps/index.js +14 -0
  9. package/lib/loop/apps/rules.d.ts +64 -0
  10. package/lib/loop/apps/rules.js +289 -0
  11. package/lib/loop/apps/yaml.d.ts +17 -0
  12. package/lib/loop/apps/yaml.js +185 -0
  13. package/lib/loop/index.d.ts +1 -0
  14. package/lib/loop/index.js +3 -0
  15. package/lib/specs/actions.d.ts +30 -0
  16. package/lib/specs/actions.js +616 -0
  17. package/lib/specs/apps.d.ts +25 -0
  18. package/lib/specs/apps.js +1072 -0
  19. package/lib/specs/cogs.d.ts +19 -0
  20. package/lib/specs/cogs.js +736 -0
  21. package/lib/specs/frames.d.ts +19 -0
  22. package/lib/specs/frames.js +444 -0
  23. package/lib/specs/gates.d.ts +22 -0
  24. package/lib/specs/gates.js +177 -0
  25. package/lib/specs/guards.d.ts +26 -0
  26. package/lib/specs/guards.js +930 -0
  27. package/lib/specs/index.d.ts +8 -0
  28. package/lib/specs/index.js +8 -0
  29. package/lib/specs/ops.d.ts +15 -0
  30. package/lib/specs/ops.js +1272 -0
  31. package/lib/specs/tracks.d.ts +15 -0
  32. package/lib/specs/tracks.js +87 -0
  33. package/lib/types/agentspecs.d.ts +442 -0
  34. package/package.json +2 -1
  35. package/scripts/codegen/agentspecs_clone.py +53 -0
  36. package/scripts/codegen/compose.py +65 -0
  37. package/scripts/codegen/generate_agents.py +8 -0
  38. package/scripts/codegen/generate_apps.py +454 -0
  39. package/scripts/codegen/generate_cogs.py +308 -0
  40. package/scripts/codegen/generate_frames.py +278 -0
  41. package/scripts/codegen/generate_ops.py +388 -0
@@ -0,0 +1,24 @@
1
+ import type { ReactorPlugin } from '@datalayer/reactor';
2
+ import type { AppSpec } from '../../types/agentspecs';
3
+ import { type LoopEmbedProps } from '../embed/LoopEmbed';
4
+ /** The id of an agent or a Cog, without its version. */
5
+ export declare const agentIdOf: (app: Pick<AppSpec, "agent" | "team">) => string;
6
+ /**
7
+ * The plugin that makes a LOOP workspace run an application.
8
+ *
9
+ * The agent is created with the application's own document (`app_spec`) in
10
+ * its payload; a runtime that knows applications configures the agent from
11
+ * it, and one that does not creates the agent alone — the application is
12
+ * then shown and not enforced, which is why a hosted application only runs
13
+ * on a runtime that does.
14
+ *
15
+ * An application run by a team is not supported in the workspace yet: a team
16
+ * is not an agent spec, and is refused here rather than launched as one.
17
+ */
18
+ export declare function defineAppPlugin(app: AppSpec): ReactorPlugin<Record<string, never>, unknown, unknown>;
19
+ export type AppRendererProps = Omit<LoopEmbedProps, 'agentId'> & {
20
+ /** The application to render. */
21
+ app: AppSpec;
22
+ };
23
+ export declare function AppRenderer({ app, plugins, ...embed }: AppRendererProps): React.JSX.Element;
24
+ export default AppRenderer;
@@ -0,0 +1,101 @@
1
+ import { jsxs as _jsxs, jsx as _jsx } 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, rendered: the LOOP workspace configured from an Appspec
8
+ * (LOOP R-01).
9
+ *
10
+ * One renderer for every place an application appears — the Studio's
11
+ * Preview, its hosted page, an embed, the home page — so that what a builder
12
+ * sees while building is what its users get. It is not a second shell: it is
13
+ * `LoopEmbed`, given
14
+ *
15
+ * - an **application plugin** (`defineAppPlugin`): the agent that answers,
16
+ * created with the application in its payload — so the runtime reaches only
17
+ * what the application connects to and enforces its rules before every tool
18
+ * call — and the application's starters as the openers of the empty chat;
19
+ * - the **layout of its kind**: a chat is the conversation alone, with the
20
+ * A2UI surfaces its answers draw; the other layouts keep the editors.
21
+ *
22
+ * @module loop/apps/AppRenderer
23
+ */
24
+ import { useMemo } from 'react';
25
+ import { defineAgentCapacityPlugin } from '../plugins/agent-capacity';
26
+ import { LoopEmbed } from '../embed/LoopEmbed';
27
+ import { dumpAppspec } from './appspec';
28
+ /** The id of an agent or a Cog, without its version. */
29
+ export const agentIdOf = (app) => {
30
+ const reference = app.agent || app.team;
31
+ const at = reference.lastIndexOf(':');
32
+ return at > 0 && reference.slice(at + 1).includes('.')
33
+ ? reference.slice(0, at)
34
+ : reference;
35
+ };
36
+ /**
37
+ * The plugin that makes a LOOP workspace run an application.
38
+ *
39
+ * The agent is created with the application's own document (`app_spec`) in
40
+ * its payload; a runtime that knows applications configures the agent from
41
+ * it, and one that does not creates the agent alone — the application is
42
+ * then shown and not enforced, which is why a hosted application only runs
43
+ * on a runtime that does.
44
+ *
45
+ * An application run by a team is not supported in the workspace yet: a team
46
+ * is not an agent spec, and is refused here rather than launched as one.
47
+ */
48
+ export function defineAppPlugin(app) {
49
+ if (!app.agent) {
50
+ throw new Error(`“${app.name}” is run by a team, which the workspace does not run as an application yet.`);
51
+ }
52
+ return defineAgentCapacityPlugin({
53
+ key: `app-${app.id}`,
54
+ displayName: app.name,
55
+ description: app.description || `The ${app.name} application`,
56
+ specId: agentIdOf(app),
57
+ emoji: app.emoji,
58
+ createPayload: {
59
+ name: app.id,
60
+ app_spec: dumpAppspec(app),
61
+ ...(app.model ? { model: app.model } : {}),
62
+ },
63
+ suggestions: app.interface.starters.map(starter => ({
64
+ text: starter.label,
65
+ message: starter.message,
66
+ })),
67
+ });
68
+ }
69
+ /**
70
+ * An application in a LOOP workspace: its agent, its starters, its layout.
71
+ *
72
+ * Every other prop is `LoopEmbed`'s, and wins over what the application
73
+ * implies — a host that wants the editors beside a chat still says so.
74
+ */
75
+ /** No host plugins: one array, so that it never reads as a change. */
76
+ const NO_PLUGINS = [];
77
+ export function AppRenderer({ app, plugins = NO_PLUGINS, ...embed }) {
78
+ const chatOnly = app.interface.layout === 'chat';
79
+ /*
80
+ * The application plugin, made once per application. `LoopEmbed` rebuilds
81
+ * its whole reactor when its plugins change, so a new plugin on every
82
+ * render of the host would restart the running workspace. The key is the
83
+ * application as its file holds it: a change to it is a new application.
84
+ */
85
+ const source = JSON.stringify(dumpAppspec(app));
86
+ const appPlugin = useMemo(() => (app.agent ? defineAppPlugin(app) : null),
87
+ // eslint-disable-next-line react-hooks/exhaustive-deps
88
+ [source]);
89
+ const allPlugins = useMemo(() => (appPlugin ? [appPlugin, ...plugins] : plugins), [appPlugin, plugins]);
90
+ if (!appPlugin) {
91
+ 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
+ }
93
+ return (_jsx(LoopEmbed
94
+ // The application's own agent: created under its id, so that its
95
+ // spec is applied to an agent of its own, never to the one it extends.
96
+ , {
97
+ // The application's own agent: created under its id, so that its
98
+ // 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 }));
100
+ }
101
+ export default AppRenderer;
@@ -0,0 +1,69 @@
1
+ /**
2
+ * The Appspec as a file, and as the application an editor holds.
3
+ *
4
+ * An application is kept as a YAML or JSON document in the spec's own words —
5
+ * `applies_to`, `ready_at`, `keep_for` — with nothing written that is at its
6
+ * default. An editor works on the whole of it: an {@link AppSpec} with every
7
+ * field present, in TypeScript's spelling.
8
+ *
9
+ * {@link parseAppspec} reads the first into the second, and
10
+ * {@link dumpAppspec} writes it back: the same application always writes the
11
+ * same document, keys in one fixed order — the spec's own where it declares
12
+ * them, alphabetical where it does not (a scenario's weights, a component of
13
+ * a surface) — so that a difference between two versions shows what changed
14
+ * and nothing else. Reading what was written
15
+ * gives the application back, and writing what was read gives the document
16
+ * back — which is what lets three editors work on one file.
17
+ *
18
+ * Reading is tolerant, because a draft is not yet an application: what is
19
+ * missing takes its default, and what is wrong is reported beside the result
20
+ * rather than thrown. Whether the application can be used is decided by the
21
+ * spec's own validation, not here.
22
+ *
23
+ * Pure: nothing here calls a service or renders.
24
+ *
25
+ * @module loop/apps/appspec
26
+ */
27
+ import type { AppAccent, AppKind, AppLayout, AppSpec } from '../../types/agentspecs';
28
+ /** The version of the spec itself. */
29
+ export declare const APP_SCHEMA = "loop.app/v1";
30
+ /** The face of an application that has not chosen one. */
31
+ export declare const DEFAULT_EMOJI = "\uD83D\uDC40";
32
+ export declare const APP_KINDS: AppKind[];
33
+ export declare const APP_ACCENTS: AppAccent[];
34
+ /** The layout a kind starts with. */
35
+ export declare const DEFAULT_LAYOUTS: Record<AppKind, AppLayout>;
36
+ /** What an application keeps of what it did, when it does not say. */
37
+ export declare const DEFAULT_RECORD_INCLUDE: string[];
38
+ type Data = Record<string, unknown>;
39
+ /** A retention as days: `90_days`, `18_months`, `1_years`; 0 when it cannot be read. */
40
+ export declare function retentionDays(keepFor: string): number;
41
+ /** An application with nothing said: what *Start blank* opens. */
42
+ export declare function emptyAppspec(kind?: AppKind): AppSpec;
43
+ /** What reading a document gives: the application, and what the document got wrong. */
44
+ export interface ParsedAppspec {
45
+ app: AppSpec;
46
+ /** In sentences; empty when the document reads as it was written. */
47
+ problems: string[];
48
+ }
49
+ /**
50
+ * An application from a document in the spec's own words.
51
+ *
52
+ * Tolerant: what is missing takes its default, and what cannot be read is
53
+ * reported in `problems` — a key the spec does not know, a version of the
54
+ * spec this does not read, a kind that is not one. The application returned
55
+ * is always whole, so an editor can open it and show what is wrong.
56
+ */
57
+ export declare function parseAppspec(document: unknown): ParsedAppspec;
58
+ /**
59
+ * An application as the document its file holds.
60
+ *
61
+ * The spec's own words, keys in one fixed order, nothing written that is at
62
+ * its default: the same application always writes the same document. What an
63
+ * application carries that is not the spec's — what it needs set up — is left
64
+ * out.
65
+ */
66
+ export declare function dumpAppspec(app: AppSpec): Data;
67
+ /** The keys of a document in the order they are written. */
68
+ export declare const APPSPEC_KEY_ORDER: readonly string[];
69
+ export {};