@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
|
@@ -197,94 +197,9 @@ export function createSwitchableSandboxService({ serverUrl, initialTarget = 'loc
|
|
|
197
197
|
(await detail(restart)));
|
|
198
198
|
}
|
|
199
199
|
}
|
|
200
|
-
/**
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
* The payload is passed rather than read from the closure: the caller has
|
|
204
|
-
* already established that it exists, and TypeScript cannot carry that
|
|
205
|
-
* narrowing across a function boundary.
|
|
206
|
-
*/
|
|
207
|
-
async function ensureLocalAgent(createPayload) {
|
|
208
|
-
const id = agentId?.trim();
|
|
209
|
-
if (!id) {
|
|
210
|
-
throw new Error('Local needs an agent id before its runtime can start.');
|
|
211
|
-
}
|
|
212
|
-
let existing;
|
|
213
|
-
try {
|
|
214
|
-
existing = await fetch(`${serverUrl}/api/v1/agents/${encodeURIComponent(id)}`);
|
|
215
|
-
}
|
|
216
|
-
catch (reason) {
|
|
217
|
-
throw new Error(`Local needs an agent-runtimes server at ${serverUrl}, and nothing answered there. ` +
|
|
218
|
-
`Start one and try again. (${reason instanceof Error ? reason.message : String(reason)})`, { cause: reason });
|
|
219
|
-
}
|
|
220
|
-
if (existing.ok) {
|
|
221
|
-
// The agent is there, which does not mean its sandbox is. Reconfiguring
|
|
222
|
-
// or restarting the manager stops the per-agent sandboxes, because they
|
|
223
|
-
// were built under the previous settings — so coming back to Local after
|
|
224
|
-
// a spell on Jupyter finds the agent alive and nothing behind it. Asking
|
|
225
|
-
// for the sandbox is idempotent, so it costs a round trip and nothing
|
|
226
|
-
// else when one is already running.
|
|
227
|
-
await ensureLocalSandbox(id);
|
|
228
|
-
return;
|
|
229
|
-
}
|
|
230
|
-
if (existing.status !== 404) {
|
|
231
|
-
throw new Error(`The server could not inspect local agent ${id} (${existing.status} ${existing.statusText}). ` +
|
|
232
|
-
(await detail(existing)));
|
|
233
|
-
}
|
|
234
|
-
const created = await fetch(`${serverUrl}/api/v1/agents`, {
|
|
235
|
-
method: 'POST',
|
|
236
|
-
headers: { 'content-type': 'application/json' },
|
|
237
|
-
body: JSON.stringify({
|
|
238
|
-
// Defaults first, so a blueprint that names its own transport or
|
|
239
|
-
// sandbox variant — the sandbox capacity plugins do — wins over
|
|
240
|
-
// them; the name last, because Local's agent id is not negotiable.
|
|
241
|
-
transport: 'ag-ui',
|
|
242
|
-
sandbox_variant: 'jupyter-server',
|
|
243
|
-
...createPayload,
|
|
244
|
-
name: id,
|
|
245
|
-
}),
|
|
246
|
-
});
|
|
247
|
-
if (!created.ok && created.status !== 409) {
|
|
248
|
-
throw new Error(`The server could not launch local agent ${id} (${created.status} ${created.statusText}). ` +
|
|
249
|
-
(await detail(created)));
|
|
250
|
-
}
|
|
251
|
-
// A 409 means somebody else created it between the two calls above, and
|
|
252
|
-
// that agent is as unlikely to have a sandbox as one found by the GET.
|
|
253
|
-
if (created.status === 409) {
|
|
254
|
-
await ensureLocalSandbox(id);
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
/**
|
|
258
|
-
* Make sure the agent has somewhere to run.
|
|
259
|
-
*
|
|
260
|
-
* Creating an agent starts its sandbox, so this is only ever needed for one
|
|
261
|
-
* that already existed. Selecting a target is an operation, not a
|
|
262
|
-
* preference: when the promise resolves the sandbox is meant to be up, and
|
|
263
|
-
* without this the kernel indicator sits empty and the notebook binds to
|
|
264
|
-
* nothing.
|
|
265
|
-
*/
|
|
266
|
-
async function ensureLocalSandbox(id) {
|
|
267
|
-
const response = await fetch(`${serverUrl}/api/v1/agents/${encodeURIComponent(id)}/sandbox/ensure`, { method: 'POST' });
|
|
268
|
-
if (!response.ok) {
|
|
269
|
-
throw new Error(`The server could not start a sandbox for local agent ${id} ` +
|
|
270
|
-
`(${response.status} ${response.statusText}). ` +
|
|
271
|
-
(await detail(response)));
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
/**
|
|
275
|
-
* What the server said went wrong, when it said anything.
|
|
276
|
-
*
|
|
277
|
-
* FastAPI puts the reason in `detail`, and a status code on its own sends a
|
|
278
|
-
* reader to the network tab for something the response already contained.
|
|
279
|
-
*/
|
|
280
|
-
async function detail(response) {
|
|
281
|
-
try {
|
|
282
|
-
const body = (await response.json());
|
|
283
|
-
return typeof body.detail === 'string' ? body.detail : '';
|
|
284
|
-
}
|
|
285
|
-
catch {
|
|
286
|
-
return '';
|
|
287
|
-
}
|
|
200
|
+
/** The agent backing Local, on this workspace's server. */
|
|
201
|
+
function ensureLocalAgent(createPayload) {
|
|
202
|
+
return ensureServerAgent(serverUrl, agentId, createPayload);
|
|
288
203
|
}
|
|
289
204
|
function connectActive() {
|
|
290
205
|
disconnect?.();
|
|
@@ -403,3 +318,91 @@ export function createSwitchableSandboxService({ serverUrl, initialTarget = 'loc
|
|
|
403
318
|
},
|
|
404
319
|
};
|
|
405
320
|
}
|
|
321
|
+
/**
|
|
322
|
+
* Create the agent whose per-agent Jupyter sandbox backs Local, on the
|
|
323
|
+
* agent-runtimes server at `serverUrl`, unless it is there already — then
|
|
324
|
+
* only its sandbox is asked for. Exported for a host that addresses the
|
|
325
|
+
* agent without a workspace: the embed's floating modes (`AppEmbed`).
|
|
326
|
+
*/
|
|
327
|
+
export async function ensureServerAgent(serverUrl, agentId, createPayload) {
|
|
328
|
+
const id = agentId?.trim();
|
|
329
|
+
if (!id) {
|
|
330
|
+
throw new Error('Local needs an agent id before its runtime can start.');
|
|
331
|
+
}
|
|
332
|
+
let existing;
|
|
333
|
+
try {
|
|
334
|
+
existing = await fetch(`${serverUrl}/api/v1/agents/${encodeURIComponent(id)}`);
|
|
335
|
+
}
|
|
336
|
+
catch (reason) {
|
|
337
|
+
throw new Error(`Local needs an agent-runtimes server at ${serverUrl}, and nothing answered there. ` +
|
|
338
|
+
`Start one and try again. (${reason instanceof Error ? reason.message : String(reason)})`, { cause: reason });
|
|
339
|
+
}
|
|
340
|
+
if (existing.ok) {
|
|
341
|
+
// The agent is there, which does not mean its sandbox is. Reconfiguring
|
|
342
|
+
// or restarting the manager stops the per-agent sandboxes, because they
|
|
343
|
+
// were built under the previous settings — so coming back to Local after
|
|
344
|
+
// a spell on Jupyter finds the agent alive and nothing behind it. Asking
|
|
345
|
+
// for the sandbox is idempotent, so it costs a round trip and nothing
|
|
346
|
+
// else when one is already running.
|
|
347
|
+
await ensureServerSandbox(serverUrl, id);
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
350
|
+
if (existing.status !== 404) {
|
|
351
|
+
throw new Error(`The server could not inspect local agent ${id} (${existing.status} ${existing.statusText}). ` +
|
|
352
|
+
(await detail(existing)));
|
|
353
|
+
}
|
|
354
|
+
const created = await fetch(`${serverUrl}/api/v1/agents`, {
|
|
355
|
+
method: 'POST',
|
|
356
|
+
headers: { 'content-type': 'application/json' },
|
|
357
|
+
body: JSON.stringify({
|
|
358
|
+
// Defaults first, so a blueprint that names its own transport or
|
|
359
|
+
// sandbox variant — the sandbox capacity plugins do — wins over
|
|
360
|
+
// them; the name last, because Local's agent id is not negotiable.
|
|
361
|
+
transport: 'ag-ui',
|
|
362
|
+
sandbox_variant: 'jupyter-server',
|
|
363
|
+
...createPayload,
|
|
364
|
+
name: id,
|
|
365
|
+
}),
|
|
366
|
+
});
|
|
367
|
+
if (!created.ok && created.status !== 409) {
|
|
368
|
+
throw new Error(`The server could not launch local agent ${id} (${created.status} ${created.statusText}). ` +
|
|
369
|
+
(await detail(created)));
|
|
370
|
+
}
|
|
371
|
+
// A 409 means somebody else created it between the two calls above, and
|
|
372
|
+
// that agent is as unlikely to have a sandbox as one found by the GET.
|
|
373
|
+
if (created.status === 409) {
|
|
374
|
+
await ensureServerSandbox(serverUrl, id);
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
/**
|
|
378
|
+
* Make sure the agent has somewhere to run.
|
|
379
|
+
*
|
|
380
|
+
* Creating an agent starts its sandbox, so this is only ever needed for one
|
|
381
|
+
* that already existed. Selecting a target is an operation, not a
|
|
382
|
+
* preference: when the promise resolves the sandbox is meant to be up, and
|
|
383
|
+
* without this the kernel indicator sits empty and the notebook binds to
|
|
384
|
+
* nothing.
|
|
385
|
+
*/
|
|
386
|
+
async function ensureServerSandbox(serverUrl, id) {
|
|
387
|
+
const response = await fetch(`${serverUrl}/api/v1/agents/${encodeURIComponent(id)}/sandbox/ensure`, { method: 'POST' });
|
|
388
|
+
if (!response.ok) {
|
|
389
|
+
throw new Error(`The server could not start a sandbox for local agent ${id} ` +
|
|
390
|
+
`(${response.status} ${response.statusText}). ` +
|
|
391
|
+
(await detail(response)));
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
/**
|
|
395
|
+
* What the server said went wrong, when it said anything.
|
|
396
|
+
*
|
|
397
|
+
* FastAPI puts the reason in `detail`, and a status code on its own sends a
|
|
398
|
+
* reader to the network tab for something the response already contained.
|
|
399
|
+
*/
|
|
400
|
+
async function detail(response) {
|
|
401
|
+
try {
|
|
402
|
+
const body = (await response.json());
|
|
403
|
+
return typeof body.detail === 'string' ? body.detail : '';
|
|
404
|
+
}
|
|
405
|
+
catch {
|
|
406
|
+
return '';
|
|
407
|
+
}
|
|
408
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* An application's page, drawn beside its conversation: its A2UI surface on
|
|
3
|
+
* the workspace's own renderer (`InlineSurface`), fed by the chat's current
|
|
4
|
+
* turn, its buttons answered through the chat's controls.
|
|
5
|
+
*
|
|
6
|
+
* @module loop/plugins/app-page/AppPage
|
|
7
|
+
*/
|
|
8
|
+
import type { JSX } from 'react';
|
|
9
|
+
import type { AppSpec } from '../../../types/agentspecs';
|
|
10
|
+
import { type LoopWorkspaceContext } from '../../core';
|
|
11
|
+
export type AppPageProps = {
|
|
12
|
+
app: AppSpec;
|
|
13
|
+
workspace: LoopWorkspaceContext;
|
|
14
|
+
};
|
|
15
|
+
export declare function AppPage({ app, workspace }: AppPageProps): JSX.Element;
|
|
16
|
+
export default AppPage;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useCallback, useMemo, useRef, useState } from 'react';
|
|
3
|
+
import { Box } from '@datalayer/primer-addons';
|
|
4
|
+
import { signal } from '@datalayer/reactor';
|
|
5
|
+
import { useContributions, useSignalValue } from '@datalayer/reactor/react';
|
|
6
|
+
import { LoopChatTurn, } from '../../core';
|
|
7
|
+
import { InlineSurface, SURFACE_CATALOG_ID, } from '../a2ui-surface/InlineSurface';
|
|
8
|
+
import { appPageAction, appPageData, appPageMessages } from './appPage';
|
|
9
|
+
/** No chat in the workspace: the page reads a turn that never starts. */
|
|
10
|
+
const NO_TURN = signal({ id: 0, status: 'idle' });
|
|
11
|
+
export function AppPage({ app, workspace }) {
|
|
12
|
+
const entries = useContributions(LoopChatTurn);
|
|
13
|
+
const turn = useSignalValue(entries[0]?.value.turn ?? NO_TURN);
|
|
14
|
+
const messages = useMemo(() => appPageMessages(app, SURFACE_CATALOG_ID), [app]);
|
|
15
|
+
const data = useMemo(() => appPageData(app, turn), [app, turn]);
|
|
16
|
+
const [refusal, setRefusal] = useState(null);
|
|
17
|
+
// The workspace changes as the chat reports itself; the handler reads the latest.
|
|
18
|
+
const workspaceRef = useRef(workspace);
|
|
19
|
+
workspaceRef.current = workspace;
|
|
20
|
+
// The inputs in words as last sent: a chat's message carries them when they change.
|
|
21
|
+
const lastInputs = useRef('');
|
|
22
|
+
const onAction = useCallback((action, surface) => {
|
|
23
|
+
const outcome = appPageAction(app, { name: action.name, context: action.context ?? {} }, path => surface?.dataModel.get(path), lastInputs.current);
|
|
24
|
+
const controls = workspaceRef.current.viewControls;
|
|
25
|
+
if ('refused' in outcome) {
|
|
26
|
+
setRefusal(outcome.refused);
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
setRefusal(null);
|
|
30
|
+
if ('stop' in outcome) {
|
|
31
|
+
controls.stop?.();
|
|
32
|
+
}
|
|
33
|
+
else if ('newChat' in outcome) {
|
|
34
|
+
controls.newChat?.();
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
// The chat's own send, as a surface in the transcript submits; the
|
|
38
|
+
// prompt channel when the chat has not reported itself yet.
|
|
39
|
+
if (controls.send) {
|
|
40
|
+
controls.send(outcome.send);
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
workspaceRef.current.prompts.submit(outcome.send);
|
|
44
|
+
}
|
|
45
|
+
lastInputs.current = outcome.inputs;
|
|
46
|
+
for (const path of outcome.clear) {
|
|
47
|
+
surface?.dataModel.set(path, '');
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}, [app]);
|
|
51
|
+
return (_jsx(Box, { "data-testid": "app-page", sx: { height: '100%', minHeight: 0, overflow: 'auto', p: 3 }, children: _jsx(InlineSurface, { messages: messages, data: data, onAction: onAction, validationError: refusal }) }));
|
|
52
|
+
}
|
|
53
|
+
export default AppPage;
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* An application's page, as data: what it publishes to its surface by path,
|
|
3
|
+
* what it takes from it, and what a button on it does (LOOP R-01, R-01b,
|
|
4
|
+
* C-04).
|
|
5
|
+
*
|
|
6
|
+
* A chat, a widget or a worker runs as its conversation. Its page is its
|
|
7
|
+
* A2UI surface (`interface.surface`) drawn beside that conversation, fed from
|
|
8
|
+
* it: the question last asked, the answer as it streams, where the turn
|
|
9
|
+
* stands. What a block writes — an input's `value` — stays in the surface's
|
|
10
|
+
* data model at a path the application takes, and what a button does reaches
|
|
11
|
+
* the application through the chat's own channels: a message sent, the
|
|
12
|
+
* answer stopped, the conversation started over. Nothing here is a server
|
|
13
|
+
* API; a setting reaches the application in the words of the message it is
|
|
14
|
+
* sent with, until the session API carries a settings change (R-04).
|
|
15
|
+
*
|
|
16
|
+
* A decision is not here: its page is drawn by the Studio's run page, with
|
|
17
|
+
* its own paths (`INTERFACE_PATHS`), until it moves onto the workspace (R-02).
|
|
18
|
+
*
|
|
19
|
+
* Pure: the plugin (`./index`) and its view (`./AppPage`) do the drawing.
|
|
20
|
+
*
|
|
21
|
+
* @module loop/plugins/app-page/appPage
|
|
22
|
+
*/
|
|
23
|
+
import type { AppSettingSpec, AppSpec } from '../../../types/agentspecs';
|
|
24
|
+
import type { ChatTurnSnapshot } from '../../core';
|
|
25
|
+
/** The id of the editor surface an application's page is drawn in. */
|
|
26
|
+
export declare const APP_PAGE_SURFACE = "app-page";
|
|
27
|
+
/** The id of the A2UI surface itself, inside it. */
|
|
28
|
+
export declare const APP_PAGE_SURFACE_ID = "app";
|
|
29
|
+
/** The kinds that run as their conversation and may have a page drawn by it. */
|
|
30
|
+
export type AppPageKind = 'chat' | 'widget' | 'worker';
|
|
31
|
+
/**
|
|
32
|
+
* One thing an application publishes to its page, or takes from it, by
|
|
33
|
+
* path. The shape of the Studio's `InterfacePath`, so that the Canvas reads
|
|
34
|
+
* this list as it reads a decision's.
|
|
35
|
+
*/
|
|
36
|
+
export type AppPagePath = {
|
|
37
|
+
path: string;
|
|
38
|
+
/** What it is, for a composer. */
|
|
39
|
+
meaning: string;
|
|
40
|
+
/** What it is, for a person choosing it on the Canvas. */
|
|
41
|
+
words: string;
|
|
42
|
+
list?: boolean;
|
|
43
|
+
};
|
|
44
|
+
/** What a Button on the page may do: the Studio's `InterfaceAction`. */
|
|
45
|
+
export type AppPageAction = {
|
|
46
|
+
name: string;
|
|
47
|
+
meaning: string;
|
|
48
|
+
words: string;
|
|
49
|
+
/** The keys its context may carry. */
|
|
50
|
+
context: string[];
|
|
51
|
+
/** Each key, in words. */
|
|
52
|
+
asks: Record<string, string>;
|
|
53
|
+
};
|
|
54
|
+
/** What one kind gives its page and takes from it. */
|
|
55
|
+
export type AppKindPaths = {
|
|
56
|
+
/** What a block may show. */
|
|
57
|
+
publishes: AppPagePath[];
|
|
58
|
+
/** Where what a block writes is read. */
|
|
59
|
+
accepts: AppPagePath[];
|
|
60
|
+
/** What a Button may do. */
|
|
61
|
+
actions: AppPageAction[];
|
|
62
|
+
/**
|
|
63
|
+
* Whether each of the application's settings (`interface.settings`) is
|
|
64
|
+
* also published and taken, at `/inputs/<id>` — see {@link appKindPaths}.
|
|
65
|
+
*/
|
|
66
|
+
inputs: boolean;
|
|
67
|
+
};
|
|
68
|
+
/**
|
|
69
|
+
* What each kind publishes to its page and takes from it, by path — the
|
|
70
|
+
* least that is real today, read from the conversation it runs as.
|
|
71
|
+
*/
|
|
72
|
+
export declare const APP_KIND_PATHS: Record<AppPageKind, AppKindPaths>;
|
|
73
|
+
/** Whether a kind runs as its conversation and has its paths here. */
|
|
74
|
+
export declare const isAppPageKind: (kind: string) => kind is AppPageKind;
|
|
75
|
+
/** The path a setting, an input of the page, is kept at. */
|
|
76
|
+
export declare const inputPath: (id: string) => string;
|
|
77
|
+
/**
|
|
78
|
+
* What an application publishes and takes, with its own settings: the kind's
|
|
79
|
+
* list, and for a kind that has inputs each setting at `/inputs/<id>`, both
|
|
80
|
+
* shown and written. Empty lists for a decision, or a kind not known.
|
|
81
|
+
*/
|
|
82
|
+
export declare function appKindPaths(app: Pick<AppSpec, 'kind' | 'interface'>): AppKindPaths;
|
|
83
|
+
/**
|
|
84
|
+
* Whether the workspace draws the application's page: a chat, a widget or a
|
|
85
|
+
* worker whose layout has one (`page`, `split`). A `chat` layout is the
|
|
86
|
+
* conversation alone: a surface composed for it is not drawn, which
|
|
87
|
+
* `surfaceUnshown` says in a sentence.
|
|
88
|
+
*/
|
|
89
|
+
export declare function hasAppPage(app: Pick<AppSpec, 'kind' | 'interface' | 'agent'>): boolean;
|
|
90
|
+
/**
|
|
91
|
+
* Why a composed surface is not drawn, or `null` when it is (or there is
|
|
92
|
+
* none): the application's layout is `chat`, the conversation alone.
|
|
93
|
+
*/
|
|
94
|
+
export declare function surfaceUnshown(app: Pick<AppSpec, 'kind' | 'interface' | 'agent'>): string | null;
|
|
95
|
+
/** A setting's first value, as its input holds it. */
|
|
96
|
+
export declare function initialInput(setting: AppSettingSpec): unknown;
|
|
97
|
+
/** What the conversation publishes to the page, by path, now. */
|
|
98
|
+
export declare function appPageData(app: Pick<AppSpec, 'kind' | 'name' | 'goal'>, turn: ChatTurnSnapshot): Record<string, unknown>;
|
|
99
|
+
/** The page's data model when it is drawn: what is published, the inputs, the draft. */
|
|
100
|
+
export declare function appPageInitialData(app: Pick<AppSpec, 'kind' | 'name' | 'goal' | 'interface'>): Record<string, unknown>;
|
|
101
|
+
/**
|
|
102
|
+
* The inputs written on the page, in words, one per line: each setting by
|
|
103
|
+
* its label, then any other value a block wrote under `/inputs` by its id.
|
|
104
|
+
*/
|
|
105
|
+
export declare function inputsInWords(app: Pick<AppSpec, 'interface'>, inputs: unknown): string;
|
|
106
|
+
/** What a button asked, as the surface hands it over. */
|
|
107
|
+
export type AppPageEvent = {
|
|
108
|
+
name: string;
|
|
109
|
+
context?: Record<string, unknown>;
|
|
110
|
+
};
|
|
111
|
+
/** What the page does about a button: at most one of these. */
|
|
112
|
+
export type AppPageOutcome = {
|
|
113
|
+
/** A message for the application, sent as the person's next turn. */
|
|
114
|
+
send: string;
|
|
115
|
+
/** The inputs in words as sent, to tell a change next time. */
|
|
116
|
+
inputs: string;
|
|
117
|
+
/** Paths to empty once it is sent. */
|
|
118
|
+
clear: string[];
|
|
119
|
+
} | {
|
|
120
|
+
stop: true;
|
|
121
|
+
} | {
|
|
122
|
+
newChat: true;
|
|
123
|
+
} | {
|
|
124
|
+
refused: string;
|
|
125
|
+
};
|
|
126
|
+
/**
|
|
127
|
+
* What a button pressed on the page does.
|
|
128
|
+
*
|
|
129
|
+
* `read` gives what is in the surface's data model at a path; `lastInputs`
|
|
130
|
+
* is the inputs in words as last sent, so that a chat's message carries its
|
|
131
|
+
* settings only when they changed.
|
|
132
|
+
*/
|
|
133
|
+
export declare function appPageAction(app: Pick<AppSpec, 'kind' | 'name' | 'interface'>, event: AppPageEvent, read: (path: string) => unknown, lastInputs?: string): AppPageOutcome;
|
|
134
|
+
/** A Text, a Button and its label: the parts the default pages are made of. */
|
|
135
|
+
type Component = {
|
|
136
|
+
id: string;
|
|
137
|
+
component: string;
|
|
138
|
+
[key: string]: unknown;
|
|
139
|
+
};
|
|
140
|
+
/**
|
|
141
|
+
* The page drawn when the application has a page layout and no surface
|
|
142
|
+
* composed: what its kind publishes, its settings as inputs, and the
|
|
143
|
+
* buttons its kind handles that the conversation does not already give.
|
|
144
|
+
*/
|
|
145
|
+
export declare function defaultAppSurface(app: Pick<AppSpec, 'kind' | 'interface'>): Component[];
|
|
146
|
+
/**
|
|
147
|
+
* The A2UI messages that draw the application's page: its surface composed,
|
|
148
|
+
* or the default page of its kind, fed its first data.
|
|
149
|
+
*/
|
|
150
|
+
export declare function appPageMessages(app: Pick<AppSpec, 'kind' | 'name' | 'goal' | 'interface'>, catalogId: string): ({
|
|
151
|
+
version: "v0.9";
|
|
152
|
+
createSurface: {
|
|
153
|
+
surfaceId: string;
|
|
154
|
+
catalogId: string;
|
|
155
|
+
};
|
|
156
|
+
updateComponents?: undefined;
|
|
157
|
+
updateDataModel?: undefined;
|
|
158
|
+
} | {
|
|
159
|
+
version: "v0.9";
|
|
160
|
+
updateComponents: {
|
|
161
|
+
surfaceId: string;
|
|
162
|
+
components: {
|
|
163
|
+
[property: string]: unknown;
|
|
164
|
+
id: string;
|
|
165
|
+
component: string;
|
|
166
|
+
}[];
|
|
167
|
+
};
|
|
168
|
+
createSurface?: undefined;
|
|
169
|
+
updateDataModel?: undefined;
|
|
170
|
+
} | {
|
|
171
|
+
version: "v0.9";
|
|
172
|
+
updateDataModel: {
|
|
173
|
+
surfaceId: string;
|
|
174
|
+
path: string;
|
|
175
|
+
value: Record<string, unknown>;
|
|
176
|
+
};
|
|
177
|
+
createSurface?: undefined;
|
|
178
|
+
updateComponents?: undefined;
|
|
179
|
+
})[];
|
|
180
|
+
export {};
|