@datalayer/agent-runtimes 1.3.18 → 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.
- package/lib/loop/apps/AppRenderer.d.ts +9 -0
- package/lib/loop/apps/AppRenderer.js +28 -1
- package/lib/loop/embed/LoopEmbed.js +4 -0
- package/lib/loop/plugins/agents/DatalayerAgentBridge.js +14 -4
- package/lib/loop/plugins/agents/plugin.d.ts +12 -0
- package/lib/loop/plugins/agents/plugin.js +4 -2
- package/lib/loop/presets.d.ts +6 -0
- package/lib/loop/presets.js +4 -1
- package/lib/specs/appspecSchema.d.ts +18 -0
- package/lib/specs/appspecSchema.js +982 -0
- package/lib/specs/index.d.ts +1 -0
- package/lib/specs/index.js +1 -0
- package/package.json +1 -1
- package/scripts/codegen/generate_apps.py +47 -0
|
@@ -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,
|
|
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
|
|
23
|
-
|
|
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:
|
|
56
|
+
name: agentName,
|
|
57
|
+
...(protocol ? { protocol } : {}),
|
|
50
58
|
agentSpecId,
|
|
51
59
|
model: AGENTSPECS[agentSpecId]?.model,
|
|
52
60
|
description: AGENTSPECS[agentSpecId]?.description,
|
|
53
|
-
|
|
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
|
-
|
|
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
|
package/lib/loop/presets.d.ts
CHANGED
|
@@ -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
|
*
|
package/lib/loop/presets.js
CHANGED
|
@@ -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,
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Appspec's JSON Schema, generated from agentspecs by
|
|
3
|
+
* `scripts/codegen/generate_apps.py`. Do not edit.
|
|
4
|
+
*
|
|
5
|
+
* @module specs/appspecSchema
|
|
6
|
+
*/
|
|
7
|
+
export type JsonSchema = {
|
|
8
|
+
[key: string]: unknown;
|
|
9
|
+
type?: string;
|
|
10
|
+
description?: string;
|
|
11
|
+
properties?: Record<string, JsonSchema>;
|
|
12
|
+
items?: JsonSchema;
|
|
13
|
+
enum?: readonly unknown[];
|
|
14
|
+
anyOf?: readonly JsonSchema[];
|
|
15
|
+
$ref?: string;
|
|
16
|
+
$defs?: Record<string, JsonSchema>;
|
|
17
|
+
};
|
|
18
|
+
export declare const APPSPEC_SCHEMA: JsonSchema;
|
|
@@ -0,0 +1,982 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2025-2026 Datalayer, Inc.
|
|
3
|
+
* Distributed under the terms of the Modified BSD License.
|
|
4
|
+
*/
|
|
5
|
+
export const APPSPEC_SCHEMA = {
|
|
6
|
+
$defs: {
|
|
7
|
+
Accent: {
|
|
8
|
+
description: 'The one colour of an application; everything else is neutral.',
|
|
9
|
+
enum: ['green', 'rose', 'sky', 'lime', 'sun', 'violet'],
|
|
10
|
+
title: 'Accent',
|
|
11
|
+
type: 'string',
|
|
12
|
+
},
|
|
13
|
+
Access: {
|
|
14
|
+
description: 'How far a connection goes.',
|
|
15
|
+
enum: ['read', 'write'],
|
|
16
|
+
title: 'Access',
|
|
17
|
+
type: 'string',
|
|
18
|
+
},
|
|
19
|
+
ActsAs: {
|
|
20
|
+
description: 'In whose name a connection acts.',
|
|
21
|
+
enum: ['owner', 'user'],
|
|
22
|
+
title: 'ActsAs',
|
|
23
|
+
type: 'string',
|
|
24
|
+
},
|
|
25
|
+
AppChecks: {
|
|
26
|
+
additionalProperties: false,
|
|
27
|
+
description: 'Optional: checks from the catalogue, for a builder who wants them.',
|
|
28
|
+
properties: {
|
|
29
|
+
guards: {
|
|
30
|
+
description: 'Guards, `id` or `id:version`',
|
|
31
|
+
items: {
|
|
32
|
+
type: 'string',
|
|
33
|
+
},
|
|
34
|
+
title: 'Guards',
|
|
35
|
+
type: 'array',
|
|
36
|
+
},
|
|
37
|
+
gates: {
|
|
38
|
+
description: 'Gates, `id` or `id:version`',
|
|
39
|
+
items: {
|
|
40
|
+
type: 'string',
|
|
41
|
+
},
|
|
42
|
+
title: 'Gates',
|
|
43
|
+
type: 'array',
|
|
44
|
+
},
|
|
45
|
+
track: {
|
|
46
|
+
default: '',
|
|
47
|
+
description: 'A Track, `id` or `id:version`',
|
|
48
|
+
title: 'Track',
|
|
49
|
+
type: 'string',
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
title: 'AppChecks',
|
|
53
|
+
type: 'object',
|
|
54
|
+
},
|
|
55
|
+
AppComputer: {
|
|
56
|
+
additionalProperties: false,
|
|
57
|
+
description: 'What the application may do on its own computer. Each is off until it is turned on.',
|
|
58
|
+
properties: {
|
|
59
|
+
browse: {
|
|
60
|
+
default: false,
|
|
61
|
+
description: 'Open pages in a browser',
|
|
62
|
+
title: 'Browse',
|
|
63
|
+
type: 'boolean',
|
|
64
|
+
},
|
|
65
|
+
files: {
|
|
66
|
+
default: false,
|
|
67
|
+
description: 'Read and write files',
|
|
68
|
+
title: 'Files',
|
|
69
|
+
type: 'boolean',
|
|
70
|
+
},
|
|
71
|
+
shell: {
|
|
72
|
+
default: false,
|
|
73
|
+
description: 'Run commands',
|
|
74
|
+
title: 'Shell',
|
|
75
|
+
type: 'boolean',
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
title: 'AppComputer',
|
|
79
|
+
type: 'object',
|
|
80
|
+
},
|
|
81
|
+
AppConnection: {
|
|
82
|
+
additionalProperties: false,
|
|
83
|
+
description: 'Something the application reaches.',
|
|
84
|
+
properties: {
|
|
85
|
+
server: {
|
|
86
|
+
description: 'An MCP server of the catalogue, `id` or `id:version`',
|
|
87
|
+
title: 'Server',
|
|
88
|
+
type: 'string',
|
|
89
|
+
},
|
|
90
|
+
access: {
|
|
91
|
+
$ref: '#/$defs/Access',
|
|
92
|
+
default: 'read',
|
|
93
|
+
description: 'How far: `read`, or `write`',
|
|
94
|
+
},
|
|
95
|
+
as: {
|
|
96
|
+
$ref: '#/$defs/ActsAs',
|
|
97
|
+
default: 'owner',
|
|
98
|
+
description: "In whose name: `owner` (the builder's account) or `user` (each user's own)",
|
|
99
|
+
},
|
|
100
|
+
only: {
|
|
101
|
+
description: 'The tools of the server the application may use, by name or pattern (`*gmail*`: `*` is any run of characters, `?` any one); all of them when empty. A tool left out is not reached at all',
|
|
102
|
+
items: {
|
|
103
|
+
type: 'string',
|
|
104
|
+
},
|
|
105
|
+
title: 'Only',
|
|
106
|
+
type: 'array',
|
|
107
|
+
},
|
|
108
|
+
},
|
|
109
|
+
required: ['server'],
|
|
110
|
+
title: 'AppConnection',
|
|
111
|
+
type: 'object',
|
|
112
|
+
},
|
|
113
|
+
AppCriterion: {
|
|
114
|
+
additionalProperties: false,
|
|
115
|
+
description: 'What an alternative is judged on.',
|
|
116
|
+
properties: {
|
|
117
|
+
name: {
|
|
118
|
+
description: 'Its name',
|
|
119
|
+
title: 'Name',
|
|
120
|
+
type: 'string',
|
|
121
|
+
},
|
|
122
|
+
kind: {
|
|
123
|
+
$ref: '#/$defs/CriterionKind',
|
|
124
|
+
default: 'metric',
|
|
125
|
+
description: '`metric`, `noul`, `choice`, `score`',
|
|
126
|
+
},
|
|
127
|
+
weight: {
|
|
128
|
+
default: 1,
|
|
129
|
+
description: 'How much it counts',
|
|
130
|
+
minimum: 0,
|
|
131
|
+
title: 'Weight',
|
|
132
|
+
type: 'number',
|
|
133
|
+
},
|
|
134
|
+
instructions: {
|
|
135
|
+
default: '',
|
|
136
|
+
description: 'What a judgment model is asked, or how a metric is computed',
|
|
137
|
+
title: 'Instructions',
|
|
138
|
+
type: 'string',
|
|
139
|
+
},
|
|
140
|
+
options: {
|
|
141
|
+
description: 'For a choice or a score: from the worst to the best',
|
|
142
|
+
items: {
|
|
143
|
+
type: 'string',
|
|
144
|
+
},
|
|
145
|
+
title: 'Options',
|
|
146
|
+
type: 'array',
|
|
147
|
+
},
|
|
148
|
+
direction: {
|
|
149
|
+
default: 'higher',
|
|
150
|
+
description: 'Whether more counts for, or against',
|
|
151
|
+
pattern: '^(higher|lower)$',
|
|
152
|
+
title: 'Direction',
|
|
153
|
+
type: 'string',
|
|
154
|
+
},
|
|
155
|
+
measure: {
|
|
156
|
+
default: '',
|
|
157
|
+
description: 'For a metric: what a benchmark run fills it from',
|
|
158
|
+
pattern: '^(|pass_rate|cost_per_task|seconds_per_task)$',
|
|
159
|
+
title: 'Measure',
|
|
160
|
+
type: 'string',
|
|
161
|
+
},
|
|
162
|
+
},
|
|
163
|
+
required: ['name'],
|
|
164
|
+
title: 'AppCriterion',
|
|
165
|
+
type: 'object',
|
|
166
|
+
},
|
|
167
|
+
AppDecision: {
|
|
168
|
+
additionalProperties: false,
|
|
169
|
+
description: 'What a decision application decides.',
|
|
170
|
+
properties: {
|
|
171
|
+
question: {
|
|
172
|
+
description: 'The question it answers',
|
|
173
|
+
title: 'Question',
|
|
174
|
+
type: 'string',
|
|
175
|
+
},
|
|
176
|
+
alternatives: {
|
|
177
|
+
description: 'What is chosen between',
|
|
178
|
+
items: {
|
|
179
|
+
type: 'string',
|
|
180
|
+
},
|
|
181
|
+
title: 'Alternatives',
|
|
182
|
+
type: 'array',
|
|
183
|
+
},
|
|
184
|
+
criteria: {
|
|
185
|
+
description: 'What each is judged on',
|
|
186
|
+
items: {
|
|
187
|
+
$ref: '#/$defs/AppCriterion',
|
|
188
|
+
},
|
|
189
|
+
title: 'Criteria',
|
|
190
|
+
type: 'array',
|
|
191
|
+
},
|
|
192
|
+
min_confidence: {
|
|
193
|
+
default: 0,
|
|
194
|
+
description: 'A judgment less confident than this is put to the reader',
|
|
195
|
+
maximum: 1,
|
|
196
|
+
minimum: 0,
|
|
197
|
+
title: 'Min Confidence',
|
|
198
|
+
type: 'number',
|
|
199
|
+
},
|
|
200
|
+
scenarios: {
|
|
201
|
+
description: 'Named sets of weights',
|
|
202
|
+
items: {
|
|
203
|
+
$ref: '#/$defs/AppScenario',
|
|
204
|
+
},
|
|
205
|
+
title: 'Scenarios',
|
|
206
|
+
type: 'array',
|
|
207
|
+
},
|
|
208
|
+
judgment_model: {
|
|
209
|
+
default: '',
|
|
210
|
+
description: 'The model that answers the judgments',
|
|
211
|
+
title: 'Judgment Model',
|
|
212
|
+
type: 'string',
|
|
213
|
+
},
|
|
214
|
+
},
|
|
215
|
+
required: ['question'],
|
|
216
|
+
title: 'AppDecision',
|
|
217
|
+
type: 'object',
|
|
218
|
+
},
|
|
219
|
+
AppDeployment: {
|
|
220
|
+
additionalProperties: false,
|
|
221
|
+
description: 'Where the application goes.',
|
|
222
|
+
properties: {
|
|
223
|
+
hosted: {
|
|
224
|
+
anyOf: [
|
|
225
|
+
{
|
|
226
|
+
$ref: '#/$defs/HostedDeployment',
|
|
227
|
+
},
|
|
228
|
+
{
|
|
229
|
+
type: 'null',
|
|
230
|
+
},
|
|
231
|
+
],
|
|
232
|
+
default: null,
|
|
233
|
+
description: 'At an address of its own',
|
|
234
|
+
},
|
|
235
|
+
embedded: {
|
|
236
|
+
anyOf: [
|
|
237
|
+
{
|
|
238
|
+
$ref: '#/$defs/EmbeddedDeployment',
|
|
239
|
+
},
|
|
240
|
+
{
|
|
241
|
+
type: 'null',
|
|
242
|
+
},
|
|
243
|
+
],
|
|
244
|
+
default: null,
|
|
245
|
+
description: 'Inside another product',
|
|
246
|
+
},
|
|
247
|
+
},
|
|
248
|
+
title: 'AppDeployment',
|
|
249
|
+
type: 'object',
|
|
250
|
+
},
|
|
251
|
+
AppInterface: {
|
|
252
|
+
additionalProperties: false,
|
|
253
|
+
description: 'What the user sees.',
|
|
254
|
+
properties: {
|
|
255
|
+
layout: {
|
|
256
|
+
anyOf: [
|
|
257
|
+
{
|
|
258
|
+
$ref: '#/$defs/Layout',
|
|
259
|
+
},
|
|
260
|
+
{
|
|
261
|
+
type: 'null',
|
|
262
|
+
},
|
|
263
|
+
],
|
|
264
|
+
default: null,
|
|
265
|
+
description: "`chat`, `page` or `split`; the kind's own when unsaid",
|
|
266
|
+
},
|
|
267
|
+
accent: {
|
|
268
|
+
$ref: '#/$defs/Accent',
|
|
269
|
+
default: 'green',
|
|
270
|
+
description: "The application's one colour",
|
|
271
|
+
},
|
|
272
|
+
welcome: {
|
|
273
|
+
default: '',
|
|
274
|
+
description: 'What the application says first',
|
|
275
|
+
title: 'Welcome',
|
|
276
|
+
type: 'string',
|
|
277
|
+
},
|
|
278
|
+
starters: {
|
|
279
|
+
description: 'First messages offered to the user',
|
|
280
|
+
items: {
|
|
281
|
+
$ref: '#/$defs/AppStarter',
|
|
282
|
+
},
|
|
283
|
+
title: 'Starters',
|
|
284
|
+
type: 'array',
|
|
285
|
+
},
|
|
286
|
+
settings: {
|
|
287
|
+
description: 'What the user may set',
|
|
288
|
+
items: {
|
|
289
|
+
$ref: '#/$defs/AppSetting',
|
|
290
|
+
},
|
|
291
|
+
title: 'Settings',
|
|
292
|
+
type: 'array',
|
|
293
|
+
},
|
|
294
|
+
components: {
|
|
295
|
+
description: "The components of the catalog the surface may use; the kind's own when empty",
|
|
296
|
+
items: {
|
|
297
|
+
type: 'string',
|
|
298
|
+
},
|
|
299
|
+
title: 'Components',
|
|
300
|
+
type: 'array',
|
|
301
|
+
},
|
|
302
|
+
surface: {
|
|
303
|
+
anyOf: [
|
|
304
|
+
{
|
|
305
|
+
$ref: '#/$defs/AppSurface',
|
|
306
|
+
},
|
|
307
|
+
{
|
|
308
|
+
type: 'null',
|
|
309
|
+
},
|
|
310
|
+
],
|
|
311
|
+
default: null,
|
|
312
|
+
description: 'The component tree, when there is one',
|
|
313
|
+
},
|
|
314
|
+
},
|
|
315
|
+
title: 'AppInterface',
|
|
316
|
+
type: 'object',
|
|
317
|
+
},
|
|
318
|
+
AppKind: {
|
|
319
|
+
description: 'What kind of application it is: what its user meets.',
|
|
320
|
+
enum: ['chat', 'widget', 'decision', 'worker'],
|
|
321
|
+
title: 'AppKind',
|
|
322
|
+
type: 'string',
|
|
323
|
+
},
|
|
324
|
+
AppPermissions: {
|
|
325
|
+
additionalProperties: false,
|
|
326
|
+
description: 'What the application may reach beside its connections. Nothing, unless said.',
|
|
327
|
+
properties: {
|
|
328
|
+
spaces: {
|
|
329
|
+
description: 'The Spaces it reads or writes',
|
|
330
|
+
items: {
|
|
331
|
+
$ref: '#/$defs/AppSpaceGrant',
|
|
332
|
+
},
|
|
333
|
+
title: 'Spaces',
|
|
334
|
+
type: 'array',
|
|
335
|
+
},
|
|
336
|
+
computer: {
|
|
337
|
+
$ref: '#/$defs/AppComputer',
|
|
338
|
+
description: 'Its computer: browse, files, shell',
|
|
339
|
+
},
|
|
340
|
+
},
|
|
341
|
+
title: 'AppPermissions',
|
|
342
|
+
type: 'object',
|
|
343
|
+
},
|
|
344
|
+
AppRecord: {
|
|
345
|
+
additionalProperties: false,
|
|
346
|
+
description: 'What is kept of what the application did, and for how long.',
|
|
347
|
+
properties: {
|
|
348
|
+
keep_for: {
|
|
349
|
+
default: '1_years',
|
|
350
|
+
description: 'How long: `90_days`, `18_months`, `1_years`',
|
|
351
|
+
title: 'Keep For',
|
|
352
|
+
type: 'string',
|
|
353
|
+
},
|
|
354
|
+
include: {
|
|
355
|
+
description: 'What is kept',
|
|
356
|
+
items: {
|
|
357
|
+
$ref: '#/$defs/RecordItem',
|
|
358
|
+
},
|
|
359
|
+
title: 'Include',
|
|
360
|
+
type: 'array',
|
|
361
|
+
},
|
|
362
|
+
},
|
|
363
|
+
title: 'AppRecord',
|
|
364
|
+
type: 'object',
|
|
365
|
+
},
|
|
366
|
+
AppRule: {
|
|
367
|
+
additionalProperties: false,
|
|
368
|
+
description: 'When the application acts alone, and when it asks.',
|
|
369
|
+
properties: {
|
|
370
|
+
action: {
|
|
371
|
+
description: 'The action, in the words a person reads: `Send an email`',
|
|
372
|
+
title: 'Action',
|
|
373
|
+
type: 'string',
|
|
374
|
+
},
|
|
375
|
+
applies_to: {
|
|
376
|
+
anyOf: [
|
|
377
|
+
{
|
|
378
|
+
type: 'string',
|
|
379
|
+
},
|
|
380
|
+
{
|
|
381
|
+
items: {
|
|
382
|
+
type: 'string',
|
|
383
|
+
},
|
|
384
|
+
type: 'array',
|
|
385
|
+
},
|
|
386
|
+
],
|
|
387
|
+
description: 'What the rule applies to: a class of action (`read`, `write`, `send`, `buy`, `delete`, `publish`), or named tools (`server.tool`, or a tool id)',
|
|
388
|
+
title: 'Applies To',
|
|
389
|
+
},
|
|
390
|
+
behaviour: {
|
|
391
|
+
$ref: '#/$defs/Behaviour',
|
|
392
|
+
description: '`do_it`, `if_asked`, `ask_first` or `leave_to_me`',
|
|
393
|
+
},
|
|
394
|
+
},
|
|
395
|
+
required: ['action', 'applies_to', 'behaviour'],
|
|
396
|
+
title: 'AppRule',
|
|
397
|
+
type: 'object',
|
|
398
|
+
},
|
|
399
|
+
AppScenario: {
|
|
400
|
+
additionalProperties: false,
|
|
401
|
+
description: 'A named set of weights: one way of looking at the same findings.',
|
|
402
|
+
properties: {
|
|
403
|
+
name: {
|
|
404
|
+
description: 'Its name',
|
|
405
|
+
title: 'Name',
|
|
406
|
+
type: 'string',
|
|
407
|
+
},
|
|
408
|
+
weights: {
|
|
409
|
+
additionalProperties: {
|
|
410
|
+
type: 'number',
|
|
411
|
+
},
|
|
412
|
+
description: 'By criterion name',
|
|
413
|
+
title: 'Weights',
|
|
414
|
+
type: 'object',
|
|
415
|
+
},
|
|
416
|
+
},
|
|
417
|
+
required: ['name'],
|
|
418
|
+
title: 'AppScenario',
|
|
419
|
+
type: 'object',
|
|
420
|
+
},
|
|
421
|
+
AppSetting: {
|
|
422
|
+
additionalProperties: false,
|
|
423
|
+
description: 'Something the user may set for their session.',
|
|
424
|
+
properties: {
|
|
425
|
+
id: {
|
|
426
|
+
description: 'The name the application reads it by',
|
|
427
|
+
title: 'Id',
|
|
428
|
+
type: 'string',
|
|
429
|
+
},
|
|
430
|
+
type: {
|
|
431
|
+
$ref: '#/$defs/SettingType',
|
|
432
|
+
description: '`select`, `text`, `toggle`, `slider` or `number`',
|
|
433
|
+
},
|
|
434
|
+
label: {
|
|
435
|
+
description: 'What the user reads',
|
|
436
|
+
title: 'Label',
|
|
437
|
+
type: 'string',
|
|
438
|
+
},
|
|
439
|
+
options: {
|
|
440
|
+
description: 'For a select: its options',
|
|
441
|
+
items: {
|
|
442
|
+
type: 'string',
|
|
443
|
+
},
|
|
444
|
+
title: 'Options',
|
|
445
|
+
type: 'array',
|
|
446
|
+
},
|
|
447
|
+
default: {
|
|
448
|
+
anyOf: [
|
|
449
|
+
{
|
|
450
|
+
type: 'string',
|
|
451
|
+
},
|
|
452
|
+
{
|
|
453
|
+
type: 'boolean',
|
|
454
|
+
},
|
|
455
|
+
{
|
|
456
|
+
type: 'number',
|
|
457
|
+
},
|
|
458
|
+
{
|
|
459
|
+
type: 'null',
|
|
460
|
+
},
|
|
461
|
+
],
|
|
462
|
+
default: null,
|
|
463
|
+
description: 'Its value at the start',
|
|
464
|
+
title: 'Default',
|
|
465
|
+
},
|
|
466
|
+
min: {
|
|
467
|
+
anyOf: [
|
|
468
|
+
{
|
|
469
|
+
type: 'number',
|
|
470
|
+
},
|
|
471
|
+
{
|
|
472
|
+
type: 'null',
|
|
473
|
+
},
|
|
474
|
+
],
|
|
475
|
+
default: null,
|
|
476
|
+
description: 'For a slider or a number: the least',
|
|
477
|
+
title: 'Min',
|
|
478
|
+
},
|
|
479
|
+
max: {
|
|
480
|
+
anyOf: [
|
|
481
|
+
{
|
|
482
|
+
type: 'number',
|
|
483
|
+
},
|
|
484
|
+
{
|
|
485
|
+
type: 'null',
|
|
486
|
+
},
|
|
487
|
+
],
|
|
488
|
+
default: null,
|
|
489
|
+
description: 'For a slider or a number: the most',
|
|
490
|
+
title: 'Max',
|
|
491
|
+
},
|
|
492
|
+
},
|
|
493
|
+
required: ['id', 'type', 'label'],
|
|
494
|
+
title: 'AppSetting',
|
|
495
|
+
type: 'object',
|
|
496
|
+
},
|
|
497
|
+
AppSpaceGrant: {
|
|
498
|
+
additionalProperties: false,
|
|
499
|
+
description: 'A Space the application may reach.',
|
|
500
|
+
properties: {
|
|
501
|
+
space: {
|
|
502
|
+
description: 'The Space, by its handle or its id',
|
|
503
|
+
title: 'Space',
|
|
504
|
+
type: 'string',
|
|
505
|
+
},
|
|
506
|
+
access: {
|
|
507
|
+
$ref: '#/$defs/Access',
|
|
508
|
+
default: 'read',
|
|
509
|
+
description: '`read`, or `write`',
|
|
510
|
+
},
|
|
511
|
+
},
|
|
512
|
+
required: ['space'],
|
|
513
|
+
title: 'AppSpaceGrant',
|
|
514
|
+
type: 'object',
|
|
515
|
+
},
|
|
516
|
+
AppStarter: {
|
|
517
|
+
additionalProperties: false,
|
|
518
|
+
description: 'A first message offered to the user.',
|
|
519
|
+
properties: {
|
|
520
|
+
label: {
|
|
521
|
+
description: 'What the button says',
|
|
522
|
+
title: 'Label',
|
|
523
|
+
type: 'string',
|
|
524
|
+
},
|
|
525
|
+
message: {
|
|
526
|
+
description: 'What is sent when it is chosen',
|
|
527
|
+
title: 'Message',
|
|
528
|
+
type: 'string',
|
|
529
|
+
},
|
|
530
|
+
},
|
|
531
|
+
required: ['label', 'message'],
|
|
532
|
+
title: 'AppStarter',
|
|
533
|
+
type: 'object',
|
|
534
|
+
},
|
|
535
|
+
AppSurface: {
|
|
536
|
+
additionalProperties: false,
|
|
537
|
+
description: 'The component tree the user meets, over the approved catalog (A2UI).',
|
|
538
|
+
properties: {
|
|
539
|
+
protocol: {
|
|
540
|
+
default: 'a2ui/v0.9',
|
|
541
|
+
description: 'The protocol the tree is written in',
|
|
542
|
+
title: 'Protocol',
|
|
543
|
+
type: 'string',
|
|
544
|
+
},
|
|
545
|
+
components: {
|
|
546
|
+
description: "The components, as the protocol's `updateComponents` carries them",
|
|
547
|
+
items: {
|
|
548
|
+
additionalProperties: true,
|
|
549
|
+
type: 'object',
|
|
550
|
+
},
|
|
551
|
+
title: 'Components',
|
|
552
|
+
type: 'array',
|
|
553
|
+
},
|
|
554
|
+
composed_by: {
|
|
555
|
+
default: '',
|
|
556
|
+
description: "Who composed it: a model's id, `developer`, `template`",
|
|
557
|
+
title: 'Composed By',
|
|
558
|
+
type: 'string',
|
|
559
|
+
},
|
|
560
|
+
composed_at: {
|
|
561
|
+
default: '',
|
|
562
|
+
description: 'When, as an ISO date',
|
|
563
|
+
title: 'Composed At',
|
|
564
|
+
type: 'string',
|
|
565
|
+
},
|
|
566
|
+
},
|
|
567
|
+
title: 'AppSurface',
|
|
568
|
+
type: 'object',
|
|
569
|
+
},
|
|
570
|
+
AppTestCase: {
|
|
571
|
+
additionalProperties: false,
|
|
572
|
+
description: 'An example of what the application should do, in plain words.',
|
|
573
|
+
properties: {
|
|
574
|
+
ask: {
|
|
575
|
+
description: 'What it is asked',
|
|
576
|
+
title: 'Ask',
|
|
577
|
+
type: 'string',
|
|
578
|
+
},
|
|
579
|
+
expect: {
|
|
580
|
+
description: 'What it should do',
|
|
581
|
+
title: 'Expect',
|
|
582
|
+
type: 'string',
|
|
583
|
+
},
|
|
584
|
+
},
|
|
585
|
+
required: ['ask', 'expect'],
|
|
586
|
+
title: 'AppTestCase',
|
|
587
|
+
type: 'object',
|
|
588
|
+
},
|
|
589
|
+
AppTests: {
|
|
590
|
+
additionalProperties: false,
|
|
591
|
+
description: 'How the application is verified.',
|
|
592
|
+
properties: {
|
|
593
|
+
ready_at: {
|
|
594
|
+
default: 0.8,
|
|
595
|
+
description: 'The share of tests that has to pass for the application to be ready',
|
|
596
|
+
maximum: 1,
|
|
597
|
+
minimum: 0,
|
|
598
|
+
title: 'Ready At',
|
|
599
|
+
type: 'number',
|
|
600
|
+
},
|
|
601
|
+
evalset: {
|
|
602
|
+
default: '',
|
|
603
|
+
description: 'An evalset its runs validate against, when one is chosen',
|
|
604
|
+
title: 'Evalset',
|
|
605
|
+
type: 'string',
|
|
606
|
+
},
|
|
607
|
+
cases: {
|
|
608
|
+
description: 'Its test conversations',
|
|
609
|
+
items: {
|
|
610
|
+
$ref: '#/$defs/AppTestCase',
|
|
611
|
+
},
|
|
612
|
+
title: 'Cases',
|
|
613
|
+
type: 'array',
|
|
614
|
+
},
|
|
615
|
+
},
|
|
616
|
+
title: 'AppTests',
|
|
617
|
+
type: 'object',
|
|
618
|
+
},
|
|
619
|
+
AppTrigger: {
|
|
620
|
+
additionalProperties: false,
|
|
621
|
+
description: "What starts a worker's work.",
|
|
622
|
+
properties: {
|
|
623
|
+
type: {
|
|
624
|
+
$ref: '#/$defs/TriggerType',
|
|
625
|
+
description: '`schedule`, `event` or `once`',
|
|
626
|
+
},
|
|
627
|
+
cron: {
|
|
628
|
+
default: '',
|
|
629
|
+
description: 'For a schedule: a cron expression, `0 8 * * *`',
|
|
630
|
+
title: 'Cron',
|
|
631
|
+
type: 'string',
|
|
632
|
+
},
|
|
633
|
+
event: {
|
|
634
|
+
default: '',
|
|
635
|
+
description: 'For an event: its name, `email_received`',
|
|
636
|
+
title: 'Event',
|
|
637
|
+
type: 'string',
|
|
638
|
+
},
|
|
639
|
+
at: {
|
|
640
|
+
default: '',
|
|
641
|
+
description: 'For once: when, as an ISO date',
|
|
642
|
+
title: 'At',
|
|
643
|
+
type: 'string',
|
|
644
|
+
},
|
|
645
|
+
description: {
|
|
646
|
+
default: '',
|
|
647
|
+
description: 'What it is, in words: `Every morning at 8`',
|
|
648
|
+
title: 'Description',
|
|
649
|
+
type: 'string',
|
|
650
|
+
},
|
|
651
|
+
prompt: {
|
|
652
|
+
default: '',
|
|
653
|
+
description: 'What the worker is told when it fires',
|
|
654
|
+
title: 'Prompt',
|
|
655
|
+
type: 'string',
|
|
656
|
+
},
|
|
657
|
+
},
|
|
658
|
+
required: ['type'],
|
|
659
|
+
title: 'AppTrigger',
|
|
660
|
+
type: 'object',
|
|
661
|
+
},
|
|
662
|
+
Behaviour: {
|
|
663
|
+
description: 'What an application does when it meets an action: the four a person chooses from.',
|
|
664
|
+
enum: ['do_it', 'if_asked', 'ask_first', 'leave_to_me'],
|
|
665
|
+
title: 'Behaviour',
|
|
666
|
+
type: 'string',
|
|
667
|
+
},
|
|
668
|
+
CriterionKind: {
|
|
669
|
+
description: 'How a criterion is assessed.',
|
|
670
|
+
enum: ['metric', 'noul', 'choice', 'score'],
|
|
671
|
+
title: 'CriterionKind',
|
|
672
|
+
type: 'string',
|
|
673
|
+
},
|
|
674
|
+
EmbedMode: {
|
|
675
|
+
description: "How an application sits in another product's page.",
|
|
676
|
+
enum: ['inline', 'bubble', 'panel'],
|
|
677
|
+
title: 'EmbedMode',
|
|
678
|
+
type: 'string',
|
|
679
|
+
},
|
|
680
|
+
EmbeddedDeployment: {
|
|
681
|
+
additionalProperties: false,
|
|
682
|
+
description: "The application inside another product's page.",
|
|
683
|
+
properties: {
|
|
684
|
+
mode: {
|
|
685
|
+
$ref: '#/$defs/EmbedMode',
|
|
686
|
+
default: 'inline',
|
|
687
|
+
description: '`inline`, `bubble` or `panel`',
|
|
688
|
+
},
|
|
689
|
+
origins: {
|
|
690
|
+
description: 'The origins allowed to embed it',
|
|
691
|
+
items: {
|
|
692
|
+
type: 'string',
|
|
693
|
+
},
|
|
694
|
+
title: 'Origins',
|
|
695
|
+
type: 'array',
|
|
696
|
+
},
|
|
697
|
+
},
|
|
698
|
+
title: 'EmbeddedDeployment',
|
|
699
|
+
type: 'object',
|
|
700
|
+
},
|
|
701
|
+
HostedDeployment: {
|
|
702
|
+
additionalProperties: false,
|
|
703
|
+
description: 'The application at an address of its own.',
|
|
704
|
+
properties: {
|
|
705
|
+
visibility: {
|
|
706
|
+
$ref: '#/$defs/Visibility',
|
|
707
|
+
default: 'private',
|
|
708
|
+
description: 'Who can open it',
|
|
709
|
+
},
|
|
710
|
+
slug: {
|
|
711
|
+
default: '',
|
|
712
|
+
description: 'The readable part of its address',
|
|
713
|
+
title: 'Slug',
|
|
714
|
+
type: 'string',
|
|
715
|
+
},
|
|
716
|
+
},
|
|
717
|
+
title: 'HostedDeployment',
|
|
718
|
+
type: 'object',
|
|
719
|
+
},
|
|
720
|
+
Layout: {
|
|
721
|
+
description: 'How the application is laid out.',
|
|
722
|
+
enum: ['chat', 'page', 'split'],
|
|
723
|
+
title: 'Layout',
|
|
724
|
+
type: 'string',
|
|
725
|
+
},
|
|
726
|
+
RecordItem: {
|
|
727
|
+
description: 'What an application may keep of what it did.',
|
|
728
|
+
enum: [
|
|
729
|
+
'conversations',
|
|
730
|
+
'actions',
|
|
731
|
+
'decisions',
|
|
732
|
+
'approvals',
|
|
733
|
+
'checks',
|
|
734
|
+
'sources',
|
|
735
|
+
'outputs',
|
|
736
|
+
'feedback',
|
|
737
|
+
],
|
|
738
|
+
title: 'RecordItem',
|
|
739
|
+
type: 'string',
|
|
740
|
+
},
|
|
741
|
+
SettingType: {
|
|
742
|
+
description: 'What a setting is set with.',
|
|
743
|
+
enum: ['select', 'text', 'toggle', 'slider', 'number'],
|
|
744
|
+
title: 'SettingType',
|
|
745
|
+
type: 'string',
|
|
746
|
+
},
|
|
747
|
+
TriggerType: {
|
|
748
|
+
description: 'What starts a worker: the trigger kinds of the catalogue.',
|
|
749
|
+
enum: ['schedule', 'event', 'once'],
|
|
750
|
+
title: 'TriggerType',
|
|
751
|
+
type: 'string',
|
|
752
|
+
},
|
|
753
|
+
Visibility: {
|
|
754
|
+
description: 'Who can open a hosted application.',
|
|
755
|
+
enum: ['private', 'invited', 'organization', 'link', 'public'],
|
|
756
|
+
title: 'Visibility',
|
|
757
|
+
type: 'string',
|
|
758
|
+
},
|
|
759
|
+
},
|
|
760
|
+
additionalProperties: false,
|
|
761
|
+
description: 'Specification for an application.',
|
|
762
|
+
properties: {
|
|
763
|
+
schema: {
|
|
764
|
+
description: 'The version of the spec itself',
|
|
765
|
+
title: 'Schema',
|
|
766
|
+
const: 'loop.app/v1',
|
|
767
|
+
default: 'loop.app/v1',
|
|
768
|
+
},
|
|
769
|
+
id: {
|
|
770
|
+
description: 'Unique application identifier',
|
|
771
|
+
title: 'Id',
|
|
772
|
+
type: 'string',
|
|
773
|
+
},
|
|
774
|
+
version: {
|
|
775
|
+
default: '0.0.1',
|
|
776
|
+
description: 'Application version',
|
|
777
|
+
title: 'Version',
|
|
778
|
+
type: 'string',
|
|
779
|
+
},
|
|
780
|
+
name: {
|
|
781
|
+
description: 'Display name',
|
|
782
|
+
title: 'Name',
|
|
783
|
+
type: 'string',
|
|
784
|
+
},
|
|
785
|
+
kind: {
|
|
786
|
+
$ref: '#/$defs/AppKind',
|
|
787
|
+
description: '`chat`, `widget`, `decision` or `worker`',
|
|
788
|
+
},
|
|
789
|
+
description: {
|
|
790
|
+
default: '',
|
|
791
|
+
description: 'What it does, in a sentence',
|
|
792
|
+
title: 'Description',
|
|
793
|
+
type: 'string',
|
|
794
|
+
},
|
|
795
|
+
owner: {
|
|
796
|
+
default: '',
|
|
797
|
+
description: 'Who answers for it',
|
|
798
|
+
title: 'Owner',
|
|
799
|
+
type: 'string',
|
|
800
|
+
},
|
|
801
|
+
agent: {
|
|
802
|
+
default: '',
|
|
803
|
+
description: 'The agent or the Cog that does the work, `id` or `id:version`',
|
|
804
|
+
title: 'Agent',
|
|
805
|
+
type: 'string',
|
|
806
|
+
},
|
|
807
|
+
team: {
|
|
808
|
+
default: '',
|
|
809
|
+
description: 'Or a team of them, `id` or `id:version`',
|
|
810
|
+
title: 'Team',
|
|
811
|
+
type: 'string',
|
|
812
|
+
},
|
|
813
|
+
instructions: {
|
|
814
|
+
default: '',
|
|
815
|
+
description: 'What this application tells its agent, on top of its own',
|
|
816
|
+
title: 'Instructions',
|
|
817
|
+
type: 'string',
|
|
818
|
+
},
|
|
819
|
+
model: {
|
|
820
|
+
default: '',
|
|
821
|
+
description: "The model, when it is not the organization's default",
|
|
822
|
+
title: 'Model',
|
|
823
|
+
type: 'string',
|
|
824
|
+
},
|
|
825
|
+
skills: {
|
|
826
|
+
description: "Skills it adds to its agent's",
|
|
827
|
+
items: {
|
|
828
|
+
type: 'string',
|
|
829
|
+
},
|
|
830
|
+
title: 'Skills',
|
|
831
|
+
type: 'array',
|
|
832
|
+
},
|
|
833
|
+
tools: {
|
|
834
|
+
description: "Tools of the catalogue it adds to its agent's",
|
|
835
|
+
items: {
|
|
836
|
+
type: 'string',
|
|
837
|
+
},
|
|
838
|
+
title: 'Tools',
|
|
839
|
+
type: 'array',
|
|
840
|
+
},
|
|
841
|
+
context: {
|
|
842
|
+
description: 'The Frames it works under',
|
|
843
|
+
items: {
|
|
844
|
+
type: 'string',
|
|
845
|
+
},
|
|
846
|
+
title: 'Context',
|
|
847
|
+
type: 'array',
|
|
848
|
+
},
|
|
849
|
+
contents: {
|
|
850
|
+
description: 'The documents and datasets it answers from',
|
|
851
|
+
items: {
|
|
852
|
+
type: 'string',
|
|
853
|
+
},
|
|
854
|
+
title: 'Contents',
|
|
855
|
+
type: 'array',
|
|
856
|
+
},
|
|
857
|
+
connections: {
|
|
858
|
+
description: 'What it reaches',
|
|
859
|
+
items: {
|
|
860
|
+
$ref: '#/$defs/AppConnection',
|
|
861
|
+
},
|
|
862
|
+
title: 'Connections',
|
|
863
|
+
type: 'array',
|
|
864
|
+
},
|
|
865
|
+
rules: {
|
|
866
|
+
description: 'When it acts alone, and when it asks',
|
|
867
|
+
items: {
|
|
868
|
+
$ref: '#/$defs/AppRule',
|
|
869
|
+
},
|
|
870
|
+
title: 'Rules',
|
|
871
|
+
type: 'array',
|
|
872
|
+
},
|
|
873
|
+
permissions: {
|
|
874
|
+
$ref: '#/$defs/AppPermissions',
|
|
875
|
+
description: 'What else it may reach: Spaces, its computer. Nothing, unless said',
|
|
876
|
+
},
|
|
877
|
+
interface: {
|
|
878
|
+
$ref: '#/$defs/AppInterface',
|
|
879
|
+
description: 'What the user sees',
|
|
880
|
+
},
|
|
881
|
+
tests: {
|
|
882
|
+
$ref: '#/$defs/AppTests',
|
|
883
|
+
description: 'How it is verified',
|
|
884
|
+
},
|
|
885
|
+
record: {
|
|
886
|
+
$ref: '#/$defs/AppRecord',
|
|
887
|
+
description: 'What is kept of what it did',
|
|
888
|
+
},
|
|
889
|
+
checks: {
|
|
890
|
+
$ref: '#/$defs/AppChecks',
|
|
891
|
+
description: 'Optional checks from the catalogue',
|
|
892
|
+
},
|
|
893
|
+
deployment: {
|
|
894
|
+
$ref: '#/$defs/AppDeployment',
|
|
895
|
+
description: 'Where it goes',
|
|
896
|
+
},
|
|
897
|
+
goal: {
|
|
898
|
+
default: '',
|
|
899
|
+
description: 'For a worker: what it works toward',
|
|
900
|
+
title: 'Goal',
|
|
901
|
+
type: 'string',
|
|
902
|
+
},
|
|
903
|
+
triggers: {
|
|
904
|
+
description: 'For a worker: what starts its work',
|
|
905
|
+
items: {
|
|
906
|
+
$ref: '#/$defs/AppTrigger',
|
|
907
|
+
},
|
|
908
|
+
title: 'Triggers',
|
|
909
|
+
type: 'array',
|
|
910
|
+
},
|
|
911
|
+
memory: {
|
|
912
|
+
default: '',
|
|
913
|
+
description: 'A memory of the catalogue, when it remembers',
|
|
914
|
+
title: 'Memory',
|
|
915
|
+
type: 'string',
|
|
916
|
+
},
|
|
917
|
+
notifications: {
|
|
918
|
+
description: 'Where an approval reaches a person',
|
|
919
|
+
items: {
|
|
920
|
+
type: 'string',
|
|
921
|
+
},
|
|
922
|
+
title: 'Notifications',
|
|
923
|
+
type: 'array',
|
|
924
|
+
},
|
|
925
|
+
decision: {
|
|
926
|
+
anyOf: [
|
|
927
|
+
{
|
|
928
|
+
$ref: '#/$defs/AppDecision',
|
|
929
|
+
},
|
|
930
|
+
{
|
|
931
|
+
type: 'null',
|
|
932
|
+
},
|
|
933
|
+
],
|
|
934
|
+
default: null,
|
|
935
|
+
description: 'For a decision: what it decides',
|
|
936
|
+
},
|
|
937
|
+
enabled: {
|
|
938
|
+
default: true,
|
|
939
|
+
description: 'Whether it is offered today',
|
|
940
|
+
title: 'Enabled',
|
|
941
|
+
type: 'boolean',
|
|
942
|
+
},
|
|
943
|
+
tags: {
|
|
944
|
+
items: {
|
|
945
|
+
type: 'string',
|
|
946
|
+
},
|
|
947
|
+
title: 'Tags',
|
|
948
|
+
type: 'array',
|
|
949
|
+
},
|
|
950
|
+
icon: {
|
|
951
|
+
default: 'apps',
|
|
952
|
+
description: 'Icon identifier',
|
|
953
|
+
title: 'Icon',
|
|
954
|
+
type: 'string',
|
|
955
|
+
},
|
|
956
|
+
emoji: {
|
|
957
|
+
default: '👀',
|
|
958
|
+
description: 'Its face: one emoji, shown wherever the application appears',
|
|
959
|
+
title: 'Emoji',
|
|
960
|
+
type: 'string',
|
|
961
|
+
},
|
|
962
|
+
avatar: {
|
|
963
|
+
default: '',
|
|
964
|
+
description: 'Its avatar, by name: a drawing of the set people choose theirs from on their profile. Its emoji stands for it when unsaid, and where only text goes',
|
|
965
|
+
pattern: '^\\s*([A-Z][A-Za-z0-9]{0,63})?\\s*$',
|
|
966
|
+
title: 'Avatar',
|
|
967
|
+
type: 'string',
|
|
968
|
+
},
|
|
969
|
+
banner: {
|
|
970
|
+
default: '',
|
|
971
|
+
description: 'Its banner, by name, from the set people choose theirs from on their profile. The one its id seeds when unsaid',
|
|
972
|
+
pattern: '^\\s*([A-Z][A-Za-z0-9]{0,63})?\\s*$',
|
|
973
|
+
title: 'Banner',
|
|
974
|
+
type: 'string',
|
|
975
|
+
},
|
|
976
|
+
},
|
|
977
|
+
required: ['id', 'name', 'kind'],
|
|
978
|
+
title: 'Appspec',
|
|
979
|
+
type: 'object',
|
|
980
|
+
$schema: 'https://json-schema.org/draft/2020-12/schema',
|
|
981
|
+
$id: 'https://agentspecs.datalayer.tech/schemas/loop.app/v1.json',
|
|
982
|
+
};
|
package/lib/specs/index.d.ts
CHANGED
package/lib/specs/index.js
CHANGED
package/package.json
CHANGED
|
@@ -415,6 +415,49 @@ def _drop_nulls(value: Any) -> Any:
|
|
|
415
415
|
return value
|
|
416
416
|
|
|
417
417
|
|
|
418
|
+
def generate_schema_typescript_code() -> str:
|
|
419
|
+
"""The Appspec's JSON Schema, for the editors of the page (LOOP S-01, S-02).
|
|
420
|
+
|
|
421
|
+
Taken from the agentspecs the catalogue is generated from, so that what
|
|
422
|
+
an editor completes and explains is what the spec accepts.
|
|
423
|
+
"""
|
|
424
|
+
from agentspecs.apps import json_schema
|
|
425
|
+
|
|
426
|
+
schema = json.dumps(json_schema(), indent=2, ensure_ascii=False, sort_keys=False)
|
|
427
|
+
return "\n".join(
|
|
428
|
+
[
|
|
429
|
+
"/*",
|
|
430
|
+
" * Copyright (c) 2025-2026 Datalayer, Inc.",
|
|
431
|
+
" * Distributed under the terms of the Modified BSD License.",
|
|
432
|
+
" */",
|
|
433
|
+
"",
|
|
434
|
+
"/**",
|
|
435
|
+
" * The Appspec's JSON Schema, generated from agentspecs by",
|
|
436
|
+
" * `scripts/codegen/generate_apps.py`. Do not edit.",
|
|
437
|
+
" *",
|
|
438
|
+
" * @module specs/appspecSchema",
|
|
439
|
+
" */",
|
|
440
|
+
"",
|
|
441
|
+
"/* eslint-disable */",
|
|
442
|
+
"",
|
|
443
|
+
"export type JsonSchema = {",
|
|
444
|
+
" [key: string]: unknown;",
|
|
445
|
+
" type?: string;",
|
|
446
|
+
" description?: string;",
|
|
447
|
+
" properties?: Record<string, JsonSchema>;",
|
|
448
|
+
" items?: JsonSchema;",
|
|
449
|
+
" enum?: readonly unknown[];",
|
|
450
|
+
" anyOf?: readonly JsonSchema[];",
|
|
451
|
+
" $ref?: string;",
|
|
452
|
+
" $defs?: Record<string, JsonSchema>;",
|
|
453
|
+
"};",
|
|
454
|
+
"",
|
|
455
|
+
f"export const APPSPEC_SCHEMA: JsonSchema = {schema};",
|
|
456
|
+
"",
|
|
457
|
+
]
|
|
458
|
+
)
|
|
459
|
+
|
|
460
|
+
|
|
418
461
|
def main() -> None:
|
|
419
462
|
"""Generate the application catalogue and the action classes."""
|
|
420
463
|
parser = argparse.ArgumentParser(
|
|
@@ -439,6 +482,10 @@ def main() -> None:
|
|
|
439
482
|
),
|
|
440
483
|
(args.actions_python_output, generate_actions_python_code(actions)),
|
|
441
484
|
(args.actions_typescript_output, generate_actions_typescript_code(actions)),
|
|
485
|
+
(
|
|
486
|
+
args.typescript_output.with_name("appspecSchema.ts"),
|
|
487
|
+
generate_schema_typescript_code(),
|
|
488
|
+
),
|
|
442
489
|
]
|
|
443
490
|
for path, text in outputs:
|
|
444
491
|
path.parent.mkdir(parents=True, exist_ok=True)
|