@datalayer/agent-runtimes 1.3.83 → 1.3.85
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/chat/ChatFloating.d.ts +5 -4
- package/lib/chat/ChatFloating.js +8 -6
- package/lib/chat/ChatLanguage.d.ts +17 -0
- package/lib/chat/ChatLanguage.js +29 -0
- package/lib/chat/assistant/AssistantStage.d.ts +4 -4
- package/lib/chat/assistant/AssistantStage.js +4 -2
- package/lib/chat/assistant/BalloonParts.d.ts +2 -1
- package/lib/chat/assistant/BalloonParts.js +12 -5
- package/lib/chat/assistant/BalloonVisual.js +3 -1
- package/lib/chat/assistant/ConversationBalloon.d.ts +1 -1
- package/lib/chat/assistant/ConversationBalloon.js +3 -2
- package/lib/chat/assistant/SpeechBalloon.d.ts +1 -1
- package/lib/chat/assistant/SpeechBalloon.js +10 -7
- package/lib/chat/assistant/toolLine.d.ts +8 -4
- package/lib/chat/assistant/toolLine.js +13 -9
- package/lib/chat/base/ChatBase.js +30 -11
- package/lib/chat/base/loopElement.d.ts +53 -0
- package/lib/chat/base/loopElement.js +78 -0
- package/lib/chat/base/loopWindow.d.ts +31 -0
- package/lib/chat/base/loopWindow.js +74 -0
- package/lib/chat/display/EmptyState.js +3 -1
- package/lib/chat/index.d.ts +2 -0
- package/lib/chat/index.js +3 -0
- package/lib/chat/messages/ChatMessages.js +3 -1
- package/lib/chat/messages/TurnFooter.js +3 -1
- package/lib/chat/prompt/InputPrompt.js +3 -1
- package/lib/chat/prompt/InputPromptLexical.js +3 -1
- package/lib/chat/prompt/footer/InPromptFooter.js +3 -1
- package/lib/chat/tools/ToolApprovalBanner.js +5 -3
- package/lib/chat/tools/ToolApprovalDialog.js +5 -3
- package/lib/chat/tools/ToolCallDisplay.js +29 -25
- package/lib/chat/words.d.ts +102 -0
- package/lib/chat/words.js +460 -0
- package/lib/components/a2ui/custom/index.d.ts +39 -0
- package/lib/components/a2ui/custom/index.js +95 -0
- package/lib/components/a2ui/custom/sandbox.d.ts +73 -0
- package/lib/components/a2ui/custom/sandbox.js +188 -0
- package/lib/components/a2ui/datalayer/FileUpload.d.ts +10 -2
- package/lib/components/a2ui/datalayer/FileUpload.js +10 -7
- package/lib/components/a2ui/datalayer/Form.d.ts +2 -0
- package/lib/components/a2ui/datalayer/Form.js +9 -2
- package/lib/components/a2ui/datalayer/formWidgets.d.ts +19 -0
- package/lib/components/a2ui/datalayer/formWidgets.js +51 -0
- package/lib/components/a2ui/datalayer/index.d.ts +1 -1
- package/lib/components/a2ui/datalayer/index.js +1 -1
- package/lib/components/a2ui/datalayer/schema.d.ts +10 -0
- package/lib/components/a2ui/datalayer/schema.js +12 -1
- package/lib/components/a2ui/index.d.ts +1 -0
- package/lib/components/a2ui/index.js +1 -0
- package/lib/components/a2ui/visibleWhen.d.ts +12 -1
- package/lib/components/a2ui/visibleWhen.js +24 -3
- package/lib/components/inspector/AgentInspector.d.ts +25 -44
- package/lib/components/inspector/AgentInspector.js +27 -215
- package/lib/components/inspector/AgentInspectorDialog.d.ts +6 -6
- package/lib/components/inspector/AgentInspectorDialog.js +2 -2
- package/lib/components/inspector/a2aSpans.d.ts +51 -0
- package/lib/components/inspector/a2aSpans.js +373 -0
- package/lib/components/inspector/agentSpans.d.ts +120 -0
- package/lib/components/inspector/agentSpans.js +253 -0
- package/lib/components/inspector/chatSpans.d.ts +36 -0
- package/lib/components/inspector/chatSpans.js +50 -0
- package/lib/components/inspector/classify.d.ts +11 -8
- package/lib/components/inspector/classify.js +23 -24
- package/lib/components/inspector/index.d.ts +7 -7
- package/lib/components/inspector/index.js +7 -7
- package/lib/components/teams/A2ATeamGraph.d.ts +4 -4
- package/lib/components/teams/SceneTranscript.d.ts +29 -0
- package/lib/components/teams/SceneTranscript.js +54 -0
- package/lib/components/teams/SceneView.d.ts +41 -0
- package/lib/components/teams/SceneView.js +28 -0
- package/lib/components/teams/index.d.ts +3 -0
- package/lib/components/teams/index.js +3 -0
- package/lib/components/teams/sceneTranscript.d.ts +74 -0
- package/lib/components/teams/sceneTranscript.js +294 -0
- package/lib/components/teams/teamConnections.d.ts +2 -2
- package/lib/components/teams/teamConnections.js +3 -3
- package/lib/components/teams/useA2ATeam.d.ts +4 -4
- package/lib/components/teams/useA2ATeam.js +50 -46
- package/lib/examples/AgentA2ATeamExample.d.ts +10 -9
- package/lib/examples/AgentA2ATeamExample.js +70 -60
- package/lib/examples/AssistantExample.js +2 -2
- package/lib/loop/apps/AppComposer.d.ts +40 -4
- package/lib/loop/apps/AppComposer.js +194 -19
- package/lib/loop/apps/AppRenderer.d.ts +21 -3
- package/lib/loop/apps/AppRenderer.js +88 -48
- package/lib/loop/apps/appspec.d.ts +13 -1
- package/lib/loop/apps/appspec.js +305 -12
- package/lib/loop/apps/checks.d.ts +14 -0
- package/lib/loop/apps/checks.js +276 -5
- package/lib/loop/apps/composer.d.ts +21 -10
- package/lib/loop/apps/composer.js +41 -8
- package/lib/loop/apps/customComponents.d.ts +41 -0
- package/lib/loop/apps/customComponents.js +260 -0
- package/lib/loop/apps/hostTools.d.ts +8 -1
- package/lib/loop/apps/hostTools.js +9 -0
- package/lib/loop/apps/index.d.ts +1 -0
- package/lib/loop/apps/index.js +1 -0
- package/lib/loop/apps/language.d.ts +68 -0
- package/lib/loop/apps/language.js +275 -0
- package/lib/loop/apps/settingsInputs.d.ts +29 -0
- package/lib/loop/apps/settingsInputs.js +147 -0
- package/lib/loop/apps/uploads.d.ts +43 -0
- package/lib/loop/apps/uploads.js +66 -0
- package/lib/loop/core/a2uiComponents.d.ts +10 -0
- package/lib/loop/core/a2uiComponents.js +15 -0
- package/lib/loop/core/index.d.ts +15 -1
- package/lib/loop/core/index.js +3 -0
- package/lib/loop/embed/AppEmbed.d.ts +25 -3
- package/lib/loop/embed/AppEmbed.js +106 -18
- package/lib/loop/embed/element.d.ts +5 -0
- package/lib/loop/embed/element.js +84 -5
- package/lib/loop/embed/embedConfig.d.ts +8 -0
- package/lib/loop/embed/embedConfig.js +18 -0
- package/lib/loop/embed/embedSession.d.ts +14 -0
- package/lib/loop/embed/embedSession.js +34 -0
- package/lib/loop/embed/hostBridge.d.ts +50 -3
- package/lib/loop/embed/hostBridge.js +22 -2
- package/lib/loop/index.d.ts +4 -3
- package/lib/loop/index.js +4 -3
- package/lib/loop/plugins/a2ui-surface/InlineSurface.d.ts +7 -1
- package/lib/loop/plugins/a2ui-surface/InlineSurface.js +7 -2
- package/lib/loop/plugins/a2ui-surface/SurfaceToolResult.js +4 -1
- package/lib/loop/plugins/a2ui-surface/ownComponents.d.ts +6 -0
- package/lib/loop/plugins/a2ui-surface/ownComponents.js +30 -0
- package/lib/loop/plugins/app-components/index.d.ts +26 -0
- package/lib/loop/plugins/app-components/index.js +56 -0
- package/lib/loop/plugins/app-elements/AppElements.d.ts +27 -0
- package/lib/loop/plugins/app-elements/AppElements.js +79 -0
- package/lib/loop/plugins/app-elements/index.d.ts +20 -0
- package/lib/loop/plugins/app-elements/index.js +43 -0
- package/lib/loop/plugins/app-page/AppPage.d.ts +9 -0
- package/lib/loop/plugins/app-page/AppPage.js +106 -8
- package/lib/loop/plugins/app-page/appPageModel.d.ts +17 -1
- package/lib/loop/plugins/app-page/appPageModel.js +122 -4
- package/lib/loop/plugins/app-page/index.d.ts +1 -0
- package/lib/loop/plugins/app-page/index.js +1 -0
- package/lib/loop/plugins/app-page/pageRun.d.ts +46 -0
- package/lib/loop/plugins/app-page/pageRun.js +111 -0
- package/lib/loop/plugins/assistant/index.js +8 -6
- package/lib/loop/plugins/chat/ChatView.js +16 -6
- package/lib/loop/plugins/chat/index.d.ts +1 -1
- package/lib/loop/plugins/chat/index.js +2 -1
- package/lib/models/PageTag.d.ts +1 -1
- package/lib/protocols/BrowserAgentAdapter.d.ts +8 -6
- package/lib/protocols/BrowserAgentAdapter.js +13 -10
- package/lib/runtimes/browser/a2aPeer.d.ts +2 -1
- package/lib/runtimes/browser/protocol.d.ts +1 -1
- package/lib/specs/actions.js +78 -1
- package/lib/specs/apps.d.ts +5 -0
- package/lib/specs/apps.js +1518 -216
- package/lib/specs/appspecSchema.js +630 -3
- package/lib/specs/teams/teams.d.ts +3 -0
- package/lib/specs/teams/teams.js +249 -0
- package/lib/specs/uiPlugins.js +6 -1
- package/lib/types/agentspecs.d.ts +200 -1
- package/lib/types/chat.d.ts +6 -5
- package/lib/types/teams.d.ts +13 -2
- package/package.json +2 -2
- package/scripts/codegen/generate_apps.py +20 -2
- package/scripts/codegen/generate_teams.py +15 -2
- package/lib/components/inspector/JsonTree.d.ts +0 -24
- package/lib/components/inspector/JsonTree.js +0 -89
- package/lib/components/inspector/a2aInspect.d.ts +0 -56
- package/lib/components/inspector/a2aInspect.js +0 -478
- package/lib/components/inspector/agentInspector.d.ts +0 -179
- package/lib/components/inspector/agentInspector.js +0 -267
- package/lib/components/inspector/chatInspect.d.ts +0 -38
- package/lib/components/inspector/chatInspect.js +0 -65
package/lib/loop/apps/appspec.js
CHANGED
|
@@ -3,8 +3,11 @@
|
|
|
3
3
|
* Distributed under the terms of the Modified BSD License.
|
|
4
4
|
*/
|
|
5
5
|
import { BEHAVIOURS } from './rules';
|
|
6
|
+
import { DEFAULT_MAX_FILES, DEFAULT_UPLOAD_MB } from './uploads';
|
|
6
7
|
/** The version of the spec itself. */
|
|
7
8
|
export const APP_SCHEMA = 'loop.app/v1';
|
|
9
|
+
/** The language an application's own words are in, unless it says (LOOP P-26). */
|
|
10
|
+
export const DEFAULT_LANGUAGE = 'en';
|
|
8
11
|
/** The face of an application that has not chosen one. */
|
|
9
12
|
export const DEFAULT_EMOJI = '\u{1F440}';
|
|
10
13
|
export const APP_KINDS = ['chat', 'widget', 'decision', 'worker'];
|
|
@@ -124,6 +127,9 @@ export function emptyAppspec(kind = 'chat') {
|
|
|
124
127
|
starters: [],
|
|
125
128
|
commands: [],
|
|
126
129
|
modes: [],
|
|
130
|
+
profiles: [],
|
|
131
|
+
language: DEFAULT_LANGUAGE,
|
|
132
|
+
translations: {},
|
|
127
133
|
components: [],
|
|
128
134
|
outputs: [],
|
|
129
135
|
},
|
|
@@ -170,6 +176,7 @@ const KNOWN_KEYS = [
|
|
|
170
176
|
'model',
|
|
171
177
|
'skills',
|
|
172
178
|
'backend_tools',
|
|
179
|
+
'tools',
|
|
173
180
|
'context',
|
|
174
181
|
'contents',
|
|
175
182
|
'connections',
|
|
@@ -193,6 +200,19 @@ const KNOWN_KEYS = [
|
|
|
193
200
|
'avatar',
|
|
194
201
|
'banner',
|
|
195
202
|
];
|
|
203
|
+
/** Where a check of its code runs (LOOP P-06). */
|
|
204
|
+
const CHECK_STAGES = ['answer', 'tool_call'];
|
|
205
|
+
/** A tool of its own, written in its code (LOOP P-06); a wrong one is said by the checks. */
|
|
206
|
+
function parseTool(data) {
|
|
207
|
+
return {
|
|
208
|
+
name: text(data.name),
|
|
209
|
+
description: text(data.description),
|
|
210
|
+
parameters: isData(data.parameters)
|
|
211
|
+
? data.parameters
|
|
212
|
+
: { ...NO_HOST_PARAMETERS },
|
|
213
|
+
does: texts(data.does),
|
|
214
|
+
};
|
|
215
|
+
}
|
|
196
216
|
function parseConnection(data) {
|
|
197
217
|
return {
|
|
198
218
|
server: text(data.server),
|
|
@@ -243,6 +263,67 @@ function parseMode(data) {
|
|
|
243
263
|
}
|
|
244
264
|
return mode;
|
|
245
265
|
}
|
|
266
|
+
/** A starter, its category said only when it has one (LOOP P-20). */
|
|
267
|
+
function parseStarter(data) {
|
|
268
|
+
const starter = {
|
|
269
|
+
label: text(data.label),
|
|
270
|
+
message: text(data.message),
|
|
271
|
+
};
|
|
272
|
+
if (typeof data.category === 'string' && data.category) {
|
|
273
|
+
starter.category = data.category;
|
|
274
|
+
}
|
|
275
|
+
return starter;
|
|
276
|
+
}
|
|
277
|
+
/** One of several assistants in one application (LOOP P-20). */
|
|
278
|
+
function parseProfile(data) {
|
|
279
|
+
return {
|
|
280
|
+
id: text(data.id),
|
|
281
|
+
label: text(data.label),
|
|
282
|
+
description: text(data.description),
|
|
283
|
+
instructions: text(data.instructions),
|
|
284
|
+
model: typeof data.model === 'string' && data.model ? data.model : null,
|
|
285
|
+
starters: records(data.starters).map(parseStarter),
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
/** Words by key, what is not a word left out. */
|
|
289
|
+
function wordsBy(value) {
|
|
290
|
+
return Object.fromEntries(Object.entries(isData(value) ? value : {}).filter((entry) => typeof entry[1] === 'string'));
|
|
291
|
+
}
|
|
292
|
+
/** Records by key, what is not one left out. */
|
|
293
|
+
function recordsBy(value) {
|
|
294
|
+
return Object.fromEntries(Object.entries(isData(value) ? value : {}).filter((entry) => isData(entry[1])));
|
|
295
|
+
}
|
|
296
|
+
const mapValues = (value, map) => Object.fromEntries(Object.entries(value).map(([key, item]) => [key, map(item)]));
|
|
297
|
+
/** An application's words in one other language (LOOP P-26), every key present. */
|
|
298
|
+
function parseTranslation(data) {
|
|
299
|
+
return {
|
|
300
|
+
name: text(data.name),
|
|
301
|
+
description: text(data.description),
|
|
302
|
+
welcome: text(data.welcome),
|
|
303
|
+
starters: mapValues(recordsBy(data.starters), starter => ({
|
|
304
|
+
label: text(starter.label),
|
|
305
|
+
message: text(starter.message),
|
|
306
|
+
})),
|
|
307
|
+
categories: wordsBy(data.categories),
|
|
308
|
+
settings: mapValues(recordsBy(data.settings), field => ({
|
|
309
|
+
title: text(field.title),
|
|
310
|
+
description: text(field.description),
|
|
311
|
+
options: wordsBy(field.options),
|
|
312
|
+
})),
|
|
313
|
+
commands: wordsBy(data.commands),
|
|
314
|
+
modes: mapValues(recordsBy(data.modes), mode => ({
|
|
315
|
+
label: text(mode.label),
|
|
316
|
+
options: mapValues(recordsBy(mode.options), option => ({
|
|
317
|
+
label: text(option.label),
|
|
318
|
+
description: text(option.description),
|
|
319
|
+
})),
|
|
320
|
+
})),
|
|
321
|
+
profiles: mapValues(recordsBy(data.profiles), profile => ({
|
|
322
|
+
label: text(profile.label),
|
|
323
|
+
description: text(profile.description),
|
|
324
|
+
})),
|
|
325
|
+
};
|
|
326
|
+
}
|
|
246
327
|
function parseSurface(data) {
|
|
247
328
|
return {
|
|
248
329
|
protocol: text(data.protocol, DEFAULT_PROTOCOL),
|
|
@@ -272,17 +353,124 @@ function parseVoice(data) {
|
|
|
272
353
|
where: oneOf(voice.where, ['auto', 'device', 'server'], DEFAULT_VOICE.where),
|
|
273
354
|
};
|
|
274
355
|
}
|
|
356
|
+
/** What a person may send without being asked (P-21), as the spec says it. */
|
|
357
|
+
function parseUploads(data) {
|
|
358
|
+
return {
|
|
359
|
+
kinds: records(data.kinds).map(kind => ({
|
|
360
|
+
type: text(kind.type),
|
|
361
|
+
maxMb: numberOf(kind.max_mb, DEFAULT_UPLOAD_MB),
|
|
362
|
+
})),
|
|
363
|
+
maxFiles: numberOf(data.max_files, DEFAULT_MAX_FILES),
|
|
364
|
+
};
|
|
365
|
+
}
|
|
366
|
+
/** What a page's output may be drawn with (LOOP P-05), and the property of each that shows its value. */
|
|
367
|
+
export const PAGE_OUTPUT_SHOWS = {
|
|
368
|
+
Text: 'text',
|
|
369
|
+
Image: 'url',
|
|
370
|
+
Table: 'rows',
|
|
371
|
+
Chart: 'points',
|
|
372
|
+
};
|
|
373
|
+
/** The height of a component its developer wrote (P-17), unless it says. */
|
|
374
|
+
export const DEFAULT_CUSTOM_HEIGHT = 240;
|
|
375
|
+
/**
|
|
376
|
+
* A component its developer wrote (LOOP P-17), as written: its schema and
|
|
377
|
+
* example kept whole, so that the checks say what is wrong with them.
|
|
378
|
+
*/
|
|
379
|
+
function parseCustomComponent(data) {
|
|
380
|
+
const component = {
|
|
381
|
+
name: text(data.name),
|
|
382
|
+
description: text(data.description),
|
|
383
|
+
props: isData(data.props)
|
|
384
|
+
? JSON.parse(JSON.stringify(data.props))
|
|
385
|
+
: { type: 'object', properties: {} },
|
|
386
|
+
shows: texts(data.shows),
|
|
387
|
+
sends: texts(data.sends),
|
|
388
|
+
source: text(data.source),
|
|
389
|
+
integrity: text(data.integrity),
|
|
390
|
+
height: numberOf(data.height, DEFAULT_CUSTOM_HEIGHT),
|
|
391
|
+
};
|
|
392
|
+
if (isData(data.example)) {
|
|
393
|
+
component.example = JSON.parse(JSON.stringify(data.example));
|
|
394
|
+
}
|
|
395
|
+
return component;
|
|
396
|
+
}
|
|
397
|
+
function dumpCustomComponent(component) {
|
|
398
|
+
const written = new Writer()
|
|
399
|
+
.text('name', component.name, '\u0000')
|
|
400
|
+
.text('description', component.description, '\u0000');
|
|
401
|
+
written.data.props = JSON.parse(JSON.stringify(component.props));
|
|
402
|
+
written
|
|
403
|
+
.list('shows', component.shows)
|
|
404
|
+
.list('sends', component.sends)
|
|
405
|
+
.text('source', component.source, '\u0000')
|
|
406
|
+
.text('integrity', component.integrity)
|
|
407
|
+
.value('height', component.height, DEFAULT_CUSTOM_HEIGHT);
|
|
408
|
+
if (component.example) {
|
|
409
|
+
written.data.example = JSON.parse(JSON.stringify(component.example));
|
|
410
|
+
}
|
|
411
|
+
return written.data;
|
|
412
|
+
}
|
|
413
|
+
/**
|
|
414
|
+
* The property a page's output fills with its value (P-05): a catalog
|
|
415
|
+
* component's (`PAGE_OUTPUT_SHOWS`), or what a component of the
|
|
416
|
+
* application's own shows first (P-17). Undefined for any other.
|
|
417
|
+
*/
|
|
418
|
+
export function pageOutputShows(component, own = []) {
|
|
419
|
+
if (component in PAGE_OUTPUT_SHOWS) {
|
|
420
|
+
return PAGE_OUTPUT_SHOWS[component];
|
|
421
|
+
}
|
|
422
|
+
return own.find(each => each.name === component)?.shows[0];
|
|
423
|
+
}
|
|
424
|
+
/**
|
|
425
|
+
* A widget's page written in its code (P-05), as written: its inputs a form
|
|
426
|
+
* kept whole, an output drawn with another component kept as written so that
|
|
427
|
+
* the checks say it.
|
|
428
|
+
*/
|
|
429
|
+
function parsePage(data) {
|
|
430
|
+
const page = {
|
|
431
|
+
function: text(data.function),
|
|
432
|
+
inputs: (isData(data.inputs)
|
|
433
|
+
? JSON.parse(JSON.stringify(data.inputs))
|
|
434
|
+
: {}),
|
|
435
|
+
outputs: records(data.outputs).map(output => ({
|
|
436
|
+
name: text(output.name),
|
|
437
|
+
title: text(output.title),
|
|
438
|
+
component: text(output.component, 'Text'),
|
|
439
|
+
props: isData(output.props)
|
|
440
|
+
? JSON.parse(JSON.stringify(output.props))
|
|
441
|
+
: {},
|
|
442
|
+
})),
|
|
443
|
+
live: data.live !== false,
|
|
444
|
+
};
|
|
445
|
+
if (isData(data.inputs_ui)) {
|
|
446
|
+
page.inputsUi = JSON.parse(JSON.stringify(data.inputs_ui));
|
|
447
|
+
}
|
|
448
|
+
return page;
|
|
449
|
+
}
|
|
450
|
+
function dumpPage(page) {
|
|
451
|
+
const written = new Writer().text('function', page.function, '\u0000');
|
|
452
|
+
written.data.inputs = JSON.parse(JSON.stringify(page.inputs));
|
|
453
|
+
if (page.inputsUi) {
|
|
454
|
+
written.data.inputs_ui = { ...page.inputsUi };
|
|
455
|
+
}
|
|
456
|
+
written.list('outputs', page.outputs.map(output => new Writer()
|
|
457
|
+
.text('name', output.name, '\u0000')
|
|
458
|
+
.text('title', output.title)
|
|
459
|
+
.text('component', output.component, 'Text')
|
|
460
|
+
.part('props', { ...output.props }).data));
|
|
461
|
+
return written.value('live', page.live, true).data;
|
|
462
|
+
}
|
|
275
463
|
function parseInterface(data, kind) {
|
|
276
464
|
const parsed = {
|
|
277
465
|
layout: oneOf(data.layout, ['chat', 'page', 'split'], DEFAULT_LAYOUTS[kind]),
|
|
278
466
|
accent: oneOf(data.accent, APP_ACCENTS, 'green'),
|
|
279
467
|
welcome: text(data.welcome),
|
|
280
|
-
starters: records(data.starters).map(
|
|
281
|
-
label: text(starter.label),
|
|
282
|
-
message: text(starter.message),
|
|
283
|
-
})),
|
|
468
|
+
starters: records(data.starters).map(parseStarter),
|
|
284
469
|
commands: records(data.commands).map(parseCommand),
|
|
285
470
|
modes: records(data.modes).map(parseMode),
|
|
471
|
+
profiles: records(data.profiles).map(parseProfile),
|
|
472
|
+
language: text(data.language, DEFAULT_LANGUAGE),
|
|
473
|
+
translations: mapValues(recordsBy(data.translations), parseTranslation),
|
|
286
474
|
components: texts(data.components),
|
|
287
475
|
voice: parseVoice(data.voice),
|
|
288
476
|
outputs: texts(data.outputs),
|
|
@@ -293,9 +481,24 @@ function parseInterface(data, kind) {
|
|
|
293
481
|
if (isData(data.settings)) {
|
|
294
482
|
parsed.settings = JSON.parse(JSON.stringify(data.settings));
|
|
295
483
|
}
|
|
484
|
+
// How its settings' fields are drawn (P-20), kept as written: a wrong
|
|
485
|
+
// widget is said by the checks.
|
|
486
|
+
if (isData(data.settings_ui)) {
|
|
487
|
+
parsed.settingsUi = JSON.parse(JSON.stringify(data.settings_ui));
|
|
488
|
+
}
|
|
489
|
+
if (isData(data.uploads)) {
|
|
490
|
+
parsed.uploads = parseUploads(data.uploads);
|
|
491
|
+
}
|
|
492
|
+
// Components its developer wrote (P-17): absent when it has none.
|
|
493
|
+
if (Array.isArray(data.custom_components)) {
|
|
494
|
+
parsed.customComponents = records(data.custom_components).map(parseCustomComponent);
|
|
495
|
+
}
|
|
296
496
|
if (isData(data.surface)) {
|
|
297
497
|
parsed.surface = parseSurface(data.surface);
|
|
298
498
|
}
|
|
499
|
+
if (isData(data.page)) {
|
|
500
|
+
parsed.page = parsePage(data.page);
|
|
501
|
+
}
|
|
299
502
|
if (isAssistantCharacterId(data.assistant)) {
|
|
300
503
|
parsed.assistant = data.assistant;
|
|
301
504
|
}
|
|
@@ -353,6 +556,11 @@ function parseDeployment(data) {
|
|
|
353
556
|
? {
|
|
354
557
|
host: {
|
|
355
558
|
context: texts(data.embedded.host.context),
|
|
559
|
+
// Kept as written when said: a value that is none is refused
|
|
560
|
+
// by the checks, never read as `claimed` (D-21).
|
|
561
|
+
...(data.embedded.host.user !== undefined
|
|
562
|
+
? { user: text(data.embedded.host.user) }
|
|
563
|
+
: {}),
|
|
356
564
|
functions: records(data.embedded.host.functions).map(fn => ({
|
|
357
565
|
name: text(fn.name),
|
|
358
566
|
description: text(fn.description),
|
|
@@ -416,6 +624,12 @@ export function parseAppspec(document) {
|
|
|
416
624
|
const verified = isData(tests.verified) ? tests.verified : {};
|
|
417
625
|
const record = isData(data.record) ? data.record : {};
|
|
418
626
|
const checks = isData(data.checks) ? data.checks : {};
|
|
627
|
+
// A check of its code runs on an answer or a tool call (LOOP P-06).
|
|
628
|
+
for (const check of records(checks.code)) {
|
|
629
|
+
if (!CHECK_STAGES.includes(check.on)) {
|
|
630
|
+
problems.push(`The check \`${text(check.name)}\` of its code runs on answer or tool_call, not \`${String(check.on)}\`.`);
|
|
631
|
+
}
|
|
632
|
+
}
|
|
419
633
|
const keepFor = text(record.keep_for, DEFAULT_KEEP_FOR);
|
|
420
634
|
if (retentionDays(keepFor) === 0) {
|
|
421
635
|
problems.push(`Cannot read the retention \`${keepFor}\`: write 90_days, 18_months or 1_years.`);
|
|
@@ -435,6 +649,7 @@ export function parseAppspec(document) {
|
|
|
435
649
|
model: text(data.model),
|
|
436
650
|
skills: texts(data.skills),
|
|
437
651
|
backendTools: texts(data.backend_tools),
|
|
652
|
+
tools: records(data.tools).map(parseTool),
|
|
438
653
|
context: texts(data.context),
|
|
439
654
|
contents: texts(data.contents),
|
|
440
655
|
connections: records(data.connections).map(parseConnection),
|
|
@@ -457,6 +672,8 @@ export function parseAppspec(document) {
|
|
|
457
672
|
cases: records(tests.cases).map(testCase => ({
|
|
458
673
|
ask: text(testCase.ask),
|
|
459
674
|
expect: text(testCase.expect),
|
|
675
|
+
// Decided by its code (LOOP P-06), when it names the function.
|
|
676
|
+
...(text(testCase.code) ? { code: text(testCase.code) } : {}),
|
|
460
677
|
})),
|
|
461
678
|
verified: {
|
|
462
679
|
live: texts(verified.live),
|
|
@@ -476,6 +693,11 @@ export function parseAppspec(document) {
|
|
|
476
693
|
guards: texts(checks.guards),
|
|
477
694
|
gates: texts(checks.gates),
|
|
478
695
|
track: text(checks.track),
|
|
696
|
+
code: records(checks.code).map(check => ({
|
|
697
|
+
name: text(check.name),
|
|
698
|
+
on: oneOf(check.on, CHECK_STAGES, 'answer'),
|
|
699
|
+
description: text(check.description),
|
|
700
|
+
})),
|
|
479
701
|
},
|
|
480
702
|
deployment: parseDeployment(isData(data.deployment) ? data.deployment : {}),
|
|
481
703
|
goal: text(data.goal),
|
|
@@ -557,16 +779,44 @@ function dumpSurface(surface) {
|
|
|
557
779
|
.text('composed_by', surface.composedBy)
|
|
558
780
|
.text('composed_at', surface.composedAt).data;
|
|
559
781
|
}
|
|
782
|
+
function dumpStarter(starter) {
|
|
783
|
+
return new Writer()
|
|
784
|
+
.text('label', starter.label, '\u0000')
|
|
785
|
+
.text('message', starter.message, '\u0000')
|
|
786
|
+
.text('category', starter.category ?? '').data;
|
|
787
|
+
}
|
|
788
|
+
/** Words by key, what is empty left out. */
|
|
789
|
+
const saidWords = (words) => Object.fromEntries(Object.entries(words).filter(([, said]) => said !== ''));
|
|
790
|
+
/** One translation as it is written (P-26): only what it says. */
|
|
791
|
+
function dumpTranslation(words) {
|
|
792
|
+
const parts = (value, dump) => Object.fromEntries(Object.entries(value).map(([key, item]) => [key, dump(item)]));
|
|
793
|
+
return new Writer()
|
|
794
|
+
.text('name', words.name)
|
|
795
|
+
.text('description', words.description)
|
|
796
|
+
.text('welcome', words.welcome)
|
|
797
|
+
.part('starters', parts(words.starters, starter => new Writer()
|
|
798
|
+
.text('label', starter.label)
|
|
799
|
+
.text('message', starter.message).data))
|
|
800
|
+
.part('categories', saidWords(words.categories))
|
|
801
|
+
.part('settings', parts(words.settings, field => new Writer()
|
|
802
|
+
.text('title', field.title)
|
|
803
|
+
.text('description', field.description)
|
|
804
|
+
.part('options', saidWords(field.options)).data))
|
|
805
|
+
.part('commands', saidWords(words.commands))
|
|
806
|
+
.part('modes', parts(words.modes, mode => new Writer().text('label', mode.label).part('options', parts(mode.options, option => new Writer()
|
|
807
|
+
.text('label', option.label)
|
|
808
|
+
.text('description', option.description).data)).data))
|
|
809
|
+
.part('profiles', parts(words.profiles, profile => new Writer()
|
|
810
|
+
.text('label', profile.label)
|
|
811
|
+
.text('description', profile.description).data)).data;
|
|
812
|
+
}
|
|
560
813
|
function dumpInterface(spec, kind) {
|
|
561
814
|
const writer = new Writer()
|
|
562
815
|
// A layout is written when it is not the one its kind starts with.
|
|
563
816
|
.value('layout', spec.layout, DEFAULT_LAYOUTS[kind])
|
|
564
817
|
.value('accent', spec.accent, 'green')
|
|
565
818
|
.text('welcome', spec.welcome)
|
|
566
|
-
.list('starters', spec.starters.map(
|
|
567
|
-
label: starter.label,
|
|
568
|
-
message: starter.message,
|
|
569
|
-
})))
|
|
819
|
+
.list('starters', spec.starters.map(dumpStarter))
|
|
570
820
|
.list('commands', spec.commands.map(command => ({
|
|
571
821
|
name: command.name,
|
|
572
822
|
description: command.description,
|
|
@@ -587,11 +837,37 @@ function dumpInterface(spec, kind) {
|
|
|
587
837
|
}
|
|
588
838
|
return written.data;
|
|
589
839
|
}))
|
|
590
|
-
.
|
|
591
|
-
.
|
|
840
|
+
.list('profiles', (spec.profiles ?? []).map(profile => new Writer()
|
|
841
|
+
.text('id', profile.id, '\u0000')
|
|
842
|
+
.text('label', profile.label, '\u0000')
|
|
843
|
+
.text('description', profile.description)
|
|
844
|
+
.text('instructions', profile.instructions)
|
|
845
|
+
.text('model', profile.model ?? '')
|
|
846
|
+
.list('starters', profile.starters.map(dumpStarter)).data))
|
|
847
|
+
.part('settings', spec.settings ? { ...spec.settings } : {});
|
|
848
|
+
// How its settings' fields are drawn (P-20): written when said.
|
|
849
|
+
if (spec.settingsUi) {
|
|
850
|
+
writer.data.settings_ui = { ...spec.settingsUi };
|
|
851
|
+
}
|
|
852
|
+
writer
|
|
853
|
+
.text('language', spec.language ?? DEFAULT_LANGUAGE, DEFAULT_LANGUAGE)
|
|
854
|
+
.part('translations', mapValues(spec.translations ?? {}, dumpTranslation));
|
|
855
|
+
// What a person may send without being asked (P-21): written when said.
|
|
856
|
+
if (spec.uploads) {
|
|
857
|
+
writer.data.uploads = new Writer()
|
|
858
|
+
.list('kinds', spec.uploads.kinds.map(kind => new Writer()
|
|
859
|
+
.text('type', kind.type, '\u0000')
|
|
860
|
+
.value('max_mb', kind.maxMb, DEFAULT_UPLOAD_MB).data))
|
|
861
|
+
.value('max_files', spec.uploads.maxFiles, DEFAULT_MAX_FILES).data;
|
|
862
|
+
}
|
|
863
|
+
writer.list('components', spec.components);
|
|
864
|
+
writer.list('custom_components', (spec.customComponents ?? []).map(dumpCustomComponent));
|
|
592
865
|
if (spec.surface) {
|
|
593
866
|
writer.data.surface = dumpSurface(spec.surface);
|
|
594
867
|
}
|
|
868
|
+
if (spec.page) {
|
|
869
|
+
writer.data.page = dumpPage(spec.page);
|
|
870
|
+
}
|
|
595
871
|
if (spec.assistant) {
|
|
596
872
|
writer.data.assistant = spec.assistant;
|
|
597
873
|
}
|
|
@@ -664,6 +940,16 @@ export function dumpAppspec(app) {
|
|
|
664
940
|
.text('model', app.model)
|
|
665
941
|
.list('skills', app.skills)
|
|
666
942
|
.list('backend_tools', app.backendTools)
|
|
943
|
+
.list('tools', (app.tools ?? []).map(tool => ({
|
|
944
|
+
name: tool.name,
|
|
945
|
+
description: tool.description,
|
|
946
|
+
// No arguments is what it is unless said.
|
|
947
|
+
...(JSON.stringify(tool.parameters) ===
|
|
948
|
+
JSON.stringify(NO_HOST_PARAMETERS)
|
|
949
|
+
? {}
|
|
950
|
+
: { parameters: tool.parameters }),
|
|
951
|
+
does: tool.does,
|
|
952
|
+
})))
|
|
667
953
|
.list('context', app.context)
|
|
668
954
|
.list('contents', app.contents)
|
|
669
955
|
.list('connections', app.connections.map(connection => new Writer()
|
|
@@ -692,6 +978,7 @@ export function dumpAppspec(app) {
|
|
|
692
978
|
.list('cases', app.tests.cases.map(testCase => ({
|
|
693
979
|
ask: testCase.ask,
|
|
694
980
|
expect: testCase.expect,
|
|
981
|
+
...(testCase.code ? { code: testCase.code } : {}),
|
|
695
982
|
})))
|
|
696
983
|
.part('verified', new Writer()
|
|
697
984
|
.list('live', app.tests.verified.live)
|
|
@@ -704,7 +991,12 @@ export function dumpAppspec(app) {
|
|
|
704
991
|
.part('checks', new Writer()
|
|
705
992
|
.list('guards', app.checks.guards)
|
|
706
993
|
.list('gates', app.checks.gates)
|
|
707
|
-
.text('track', app.checks.track)
|
|
994
|
+
.text('track', app.checks.track)
|
|
995
|
+
.list('code', (app.checks.code ?? []).map(check => ({
|
|
996
|
+
name: check.name,
|
|
997
|
+
on: check.on,
|
|
998
|
+
description: check.description,
|
|
999
|
+
}))).data)
|
|
708
1000
|
.part('deployment', new Writer()
|
|
709
1001
|
.present('hosted', app.deployment.hosted &&
|
|
710
1002
|
new Writer()
|
|
@@ -726,7 +1018,8 @@ export function dumpAppspec(app) {
|
|
|
726
1018
|
JSON.stringify(NO_HOST_PARAMETERS)
|
|
727
1019
|
? {}
|
|
728
1020
|
: { parameters: fn.parameters }),
|
|
729
|
-
})))
|
|
1021
|
+
})))
|
|
1022
|
+
.value('user', app.deployment.embedded.host.user ?? 'claimed', 'claimed').data).data).data)
|
|
730
1023
|
.text('goal', app.goal)
|
|
731
1024
|
.list('triggers', app.triggers.map(trigger => new Writer()
|
|
732
1025
|
.text('type', trigger.type, '\u0000')
|
|
@@ -14,6 +14,20 @@ export interface AppCheck {
|
|
|
14
14
|
* UI plugins, by the name a surface gives it.
|
|
15
15
|
*/
|
|
16
16
|
export declare const componentNamed: (name: string) => ComponentSpec | undefined;
|
|
17
|
+
/**
|
|
18
|
+
* What its code declares that agentspecs refuses (LOOP P-06): its tools,
|
|
19
|
+
* its checks and the tests it decides, each by a Python name, each name
|
|
20
|
+
* once; a tool says what it does, by class, each class once.
|
|
21
|
+
*/
|
|
22
|
+
export declare function ownCodeProblems(app: AppSpec): string[];
|
|
23
|
+
/**
|
|
24
|
+
* What agentspecs refuses of a widget's page written in its code (LOOP
|
|
25
|
+
* P-05): a page that is not a widget's, inputs that are not a form, outputs
|
|
26
|
+
* of one name twice, drawn with another component, saying in their `props`
|
|
27
|
+
* what their value fills or lacking what their component needs, and an input
|
|
28
|
+
* named as a setting — both are on the page at `/inputs/<name>`.
|
|
29
|
+
*/
|
|
30
|
+
export declare function pageProblems(app: AppSpec): string[];
|
|
17
31
|
/** How an organization's own context is named: never a catalogue id (agentspecs' `ORGANIZATION_FRAME_PREFIX`). */
|
|
18
32
|
/**
|
|
19
33
|
* What stops a Form block from asking (LOOP C-16), in agentspecs'
|