@datalayer/agent-runtimes 1.3.30 → 1.3.33
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.js +40 -8
- package/lib/chat/assistant/AssistantStage.d.ts +26 -7
- package/lib/chat/assistant/AssistantStage.js +115 -8
- package/lib/chat/assistant/SpeechBalloon.js +7 -3
- package/lib/chat/assistant/characters.d.ts +32 -1
- package/lib/chat/assistant/characters.js +180 -15
- package/lib/chat/assistant/state.d.ts +28 -0
- package/lib/chat/assistant/state.js +31 -0
- package/lib/chat/base/ChatBase.js +34 -19
- package/lib/chat/base/modelChoice.d.ts +27 -1
- package/lib/chat/base/modelChoice.js +29 -15
- package/lib/chat/prompt/InputPrompt.d.ts +7 -1
- package/lib/chat/prompt/InputPrompt.js +2 -2
- package/lib/chat/prompt/InputPromptBase.js +1 -1
- package/lib/chat/prompt/menus/ModelSelector.d.ts +13 -1
- package/lib/chat/prompt/menus/ModelSelector.js +17 -5
- package/lib/chat/useViewportDrag.d.ts +9 -1
- package/lib/chat/useViewportDrag.js +4 -4
- package/lib/components/a2ui/index.d.ts +2 -0
- package/lib/components/a2ui/index.js +2 -0
- package/lib/components/a2ui/visibility.d.ts +15 -0
- package/lib/components/a2ui/visibility.js +24 -0
- package/lib/components/a2ui/visibleWhen.d.ts +17 -0
- package/lib/components/a2ui/visibleWhen.js +54 -0
- package/lib/examples/ChatAssistantExample.d.ts +4 -0
- package/lib/examples/ChatAssistantExample.js +26 -5
- package/lib/examples/utils/owlCharacterPlugin.d.ts +7 -0
- package/lib/examples/utils/owlCharacterPlugin.js +44 -0
- package/lib/loop/apps/AppFeedback.d.ts +27 -0
- package/lib/loop/apps/AppFeedback.js +78 -0
- package/lib/loop/apps/AppRenderer.js +17 -2
- package/lib/loop/apps/appspec.js +6 -3
- package/lib/loop/apps/checks.d.ts +10 -2
- package/lib/loop/apps/checks.js +21 -10
- package/lib/loop/apps/feedback.d.ts +51 -0
- package/lib/loop/apps/feedback.js +61 -0
- package/lib/loop/apps/index.d.ts +2 -0
- package/lib/loop/apps/index.js +2 -0
- package/lib/loop/apps/rules.d.ts +14 -0
- package/lib/loop/apps/rules.js +24 -0
- package/lib/loop/core/canvasBlocks.d.ts +16 -0
- package/lib/loop/core/canvasBlocks.js +13 -0
- package/lib/loop/core/index.d.ts +7 -0
- package/lib/loop/core/index.js +3 -0
- package/lib/loop/index.d.ts +1 -1
- package/lib/loop/plugins/a2ui/A2uiView.js +2 -3
- package/lib/loop/plugins/a2ui-surface/InlineSurface.d.ts +4 -2
- package/lib/loop/plugins/a2ui-surface/InlineSurface.js +3 -4
- package/lib/loop/plugins/app-page/AppPage.js +1 -1
- package/lib/loop/plugins/app-page/{appPage.d.ts → appPageModel.d.ts} +1 -1
- package/lib/loop/plugins/app-page/index.d.ts +1 -1
- package/lib/loop/plugins/app-page/index.js +2 -2
- package/lib/loop/plugins/canvas-blocks/index.d.ts +63 -0
- package/lib/loop/plugins/canvas-blocks/index.js +118 -0
- package/lib/loop/plugins/chat/ChatView.js +7 -3
- package/lib/loop/plugins/chat/turnState.d.ts +5 -2
- package/lib/loop/plugins/chat/turnState.js +2 -1
- package/lib/specs/actions.js +1 -0
- package/lib/specs/agents/agents.js +16 -4
- package/lib/specs/apps.js +21 -10
- package/lib/specs/appspecSchema.js +13 -7
- package/lib/specs/models.d.ts +1 -1
- package/lib/specs/models.js +8 -8
- package/lib/specs/tools.d.ts +1 -0
- package/lib/specs/tools.js +19 -0
- package/lib/stories/loop/LoopReference.stories.d.ts +21 -0
- package/lib/stories/loop/LoopReference.stories.js +31 -0
- package/lib/stories/loop/ReferenceScreens.d.ts +53 -0
- package/lib/stories/loop/ReferenceScreens.js +256 -0
- package/lib/stories/loop/pictures-main.d.ts +2 -0
- package/lib/stories/loop/pictures-main.js +75 -0
- package/lib/types/agentspecs.d.ts +6 -1
- package/lib/types/chat.d.ts +5 -0
- package/lib/types/config.d.ts +8 -0
- package/package.json +9 -6
- package/scripts/check-cloudflare-models.py +2 -2
- package/scripts/codegen/generate_apps.py +2 -1
- package/scripts/codegen/generate_models.py +4 -4
- /package/lib/loop/plugins/app-page/{appPage.js → appPageModel.js} +0 -0
|
@@ -112,7 +112,7 @@ export const APPSPEC_SCHEMA = {
|
|
|
112
112
|
},
|
|
113
113
|
AppCriterion: {
|
|
114
114
|
additionalProperties: false,
|
|
115
|
-
description: 'What an alternative is
|
|
115
|
+
description: 'What an alternative is weighed on.',
|
|
116
116
|
properties: {
|
|
117
117
|
name: {
|
|
118
118
|
description: 'Its name',
|
|
@@ -133,7 +133,7 @@ export const APPSPEC_SCHEMA = {
|
|
|
133
133
|
},
|
|
134
134
|
instructions: {
|
|
135
135
|
default: '',
|
|
136
|
-
description: 'What a
|
|
136
|
+
description: 'What a decision model is asked, or how a metric is computed',
|
|
137
137
|
title: 'Instructions',
|
|
138
138
|
type: 'string',
|
|
139
139
|
},
|
|
@@ -182,7 +182,7 @@ export const APPSPEC_SCHEMA = {
|
|
|
182
182
|
type: 'array',
|
|
183
183
|
},
|
|
184
184
|
criteria: {
|
|
185
|
-
description: 'What each is
|
|
185
|
+
description: 'What each is weighed on',
|
|
186
186
|
items: {
|
|
187
187
|
$ref: '#/$defs/AppCriterion',
|
|
188
188
|
},
|
|
@@ -191,7 +191,7 @@ export const APPSPEC_SCHEMA = {
|
|
|
191
191
|
},
|
|
192
192
|
min_confidence: {
|
|
193
193
|
default: 0,
|
|
194
|
-
description: '
|
|
194
|
+
description: 'An answer less confident than this is put to the reader',
|
|
195
195
|
maximum: 1,
|
|
196
196
|
minimum: 0,
|
|
197
197
|
title: 'Min Confidence',
|
|
@@ -205,10 +205,10 @@ export const APPSPEC_SCHEMA = {
|
|
|
205
205
|
title: 'Scenarios',
|
|
206
206
|
type: 'array',
|
|
207
207
|
},
|
|
208
|
-
|
|
208
|
+
decision_model: {
|
|
209
209
|
default: '',
|
|
210
|
-
description:
|
|
211
|
-
title: '
|
|
210
|
+
description: "The model that answers the decision's typed questions",
|
|
211
|
+
title: 'Decision Model',
|
|
212
212
|
type: 'string',
|
|
213
213
|
},
|
|
214
214
|
},
|
|
@@ -371,6 +371,12 @@ export const APPSPEC_SCHEMA = {
|
|
|
371
371
|
title: 'Include',
|
|
372
372
|
type: 'array',
|
|
373
373
|
},
|
|
374
|
+
suggest_tests: {
|
|
375
|
+
default: false,
|
|
376
|
+
description: 'Whether its conversations may be used to suggest tests: a few, sampled from those kept while it is on, proposed to its builder; off unless said',
|
|
377
|
+
title: 'Suggest Tests',
|
|
378
|
+
type: 'boolean',
|
|
379
|
+
},
|
|
374
380
|
},
|
|
375
381
|
title: 'AppRecord',
|
|
376
382
|
type: 'object',
|
package/lib/specs/models.d.ts
CHANGED
|
@@ -97,7 +97,7 @@ export declare const AI_MODEL_ALIASES: Record<string, string>;
|
|
|
97
97
|
/** A model by its id, or by an id it had before; undefined when the catalogue has neither. */
|
|
98
98
|
export declare function getModel(modelId: string): AIModel | undefined;
|
|
99
99
|
/**
|
|
100
|
-
* A model a chat can run on: not a typed-
|
|
100
|
+
* A model a chat can run on: not a typed-decision model (Jev), which
|
|
101
101
|
* answers typed questions about a state and nothing else. A spec that
|
|
102
102
|
* states no capability is read as a chat model.
|
|
103
103
|
*/
|
package/lib/specs/models.js
CHANGED
|
@@ -333,7 +333,7 @@ export const BEDROCK_US_ANTHROPIC_CLAUDE_SONNET_4_6_0_0_1 = {
|
|
|
333
333
|
'AWS_DEFAULT_REGION',
|
|
334
334
|
],
|
|
335
335
|
tokensLimit: 64000,
|
|
336
|
-
capabilities: ['chat', 'tools', '
|
|
336
|
+
capabilities: ['chat', 'tools', 'decider'],
|
|
337
337
|
contextWindow: 200000,
|
|
338
338
|
};
|
|
339
339
|
export const BEDROCK_US_ANTHROPIC_CLAUDE_SONNET_4_20250514_V1_0_0_0_1 = {
|
|
@@ -356,13 +356,13 @@ export const CLOUDFLARE_GTW_TYPESAFE_JEV_0_0_1 = {
|
|
|
356
356
|
id: 'cloudflare:gtw/typesafe/jev',
|
|
357
357
|
version: '0.0.1',
|
|
358
358
|
name: 'Jev (Cloudflare AI Gateway)',
|
|
359
|
-
description: "Typesafe's typed-
|
|
359
|
+
description: "Typesafe's typed-decision model through the account's AI Gateway - noul, choice and score questions answered as calibrated probabilities; 32k context; zero data retention; the gateway keeps the logs and bills from its credits",
|
|
360
360
|
provider: 'cloudflare',
|
|
361
361
|
providerUrl: 'https://docs.typesafe.ai/models',
|
|
362
362
|
default: false,
|
|
363
363
|
available: true,
|
|
364
364
|
requiredEnvVars: [],
|
|
365
|
-
capabilities: ['
|
|
365
|
+
capabilities: ['decisions'],
|
|
366
366
|
billing: 'credits',
|
|
367
367
|
route: 'ai-gateway',
|
|
368
368
|
contextWindow: 32000,
|
|
@@ -415,7 +415,7 @@ export const CLOUDFLARE_WRK_OPENAI_GPT_OSS_120B_0_0_1 = {
|
|
|
415
415
|
available: false,
|
|
416
416
|
requiredEnvVars: [],
|
|
417
417
|
tokensLimit: 32768,
|
|
418
|
-
capabilities: ['chat', 'tools', 'codemode', '
|
|
418
|
+
capabilities: ['chat', 'tools', 'codemode', 'decider'],
|
|
419
419
|
billing: 'standard',
|
|
420
420
|
route: 'workers-ai',
|
|
421
421
|
contextWindow: 128000,
|
|
@@ -476,13 +476,13 @@ export const CLOUDFLARE_WRK_TYPESAFE_JEV_0_0_1 = {
|
|
|
476
476
|
id: 'cloudflare:wrk/typesafe/jev',
|
|
477
477
|
version: '0.0.1',
|
|
478
478
|
name: 'Jev (Cloudflare Workers AI)',
|
|
479
|
-
description: "Typesafe's typed-
|
|
479
|
+
description: "Typesafe's typed-decision model at Workers AI's own endpoint - noul, choice and score questions answered as calibrated probabilities; 32k context; zero data retention; billed from the account's credits, no gateway in the way",
|
|
480
480
|
provider: 'cloudflare',
|
|
481
481
|
providerUrl: 'https://docs.typesafe.ai/models',
|
|
482
482
|
default: false,
|
|
483
483
|
available: true,
|
|
484
484
|
requiredEnvVars: [],
|
|
485
|
-
capabilities: ['
|
|
485
|
+
capabilities: ['decisions'],
|
|
486
486
|
billing: 'credits',
|
|
487
487
|
route: 'workers-ai',
|
|
488
488
|
contextWindow: 32000,
|
|
@@ -665,12 +665,12 @@ export function getModel(modelId) {
|
|
|
665
665
|
return AI_MODEL_CATALOGUE[AI_MODEL_ALIASES[modelId] ?? modelId];
|
|
666
666
|
}
|
|
667
667
|
/**
|
|
668
|
-
* A model a chat can run on: not a typed-
|
|
668
|
+
* A model a chat can run on: not a typed-decision model (Jev), which
|
|
669
669
|
* answers typed questions about a state and nothing else. A spec that
|
|
670
670
|
* states no capability is read as a chat model.
|
|
671
671
|
*/
|
|
672
672
|
export function isChatModel(model) {
|
|
673
|
-
return !(model.capabilities ?? []).includes('
|
|
673
|
+
return !(model.capabilities ?? []).includes('decisions');
|
|
674
674
|
}
|
|
675
675
|
/** The models a person choosing a chat model is offered from. */
|
|
676
676
|
export function listChatModels() {
|
package/lib/specs/tools.d.ts
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
import type { ToolSpec } from '../types';
|
|
10
10
|
export declare const CREATE_PLAN_TOOL_SPEC_0_0_1: ToolSpec;
|
|
11
11
|
export declare const CURRENT_TIME_TOOL_SPEC_0_0_1: ToolSpec;
|
|
12
|
+
export declare const DECIDE_TOOL_SPEC_0_0_1: ToolSpec;
|
|
12
13
|
export declare const DISPLAY_RECIPE_TOOL_SPEC_0_0_1: ToolSpec;
|
|
13
14
|
export declare const EXAMPLE_CREATE_PLAN_TOOL_SPEC_0_0_1: ToolSpec;
|
|
14
15
|
export declare const EXAMPLE_CURRENT_TIME_TOOL_SPEC_0_0_1: ToolSpec;
|
package/lib/specs/tools.js
CHANGED
|
@@ -41,6 +41,24 @@ export const CURRENT_TIME_TOOL_SPEC_0_0_1 = {
|
|
|
41
41
|
icon: 'clock',
|
|
42
42
|
emoji: '🕒',
|
|
43
43
|
};
|
|
44
|
+
export const DECIDE_TOOL_SPEC_0_0_1 = {
|
|
45
|
+
id: 'decide',
|
|
46
|
+
version: '0.0.1',
|
|
47
|
+
name: 'Decide',
|
|
48
|
+
description: 'Ask Jev typed questions about a text — noul (does a statement hold, with its probability), choice (one of named options) or score (a step on a rubric) — and get the typed answers back, through datalayer-ai-inference.',
|
|
49
|
+
tags: ['runtime', 'decisions', 'jev'],
|
|
50
|
+
enabled: true,
|
|
51
|
+
approval: 'auto',
|
|
52
|
+
timeout: undefined,
|
|
53
|
+
requiresApproval: false,
|
|
54
|
+
runtime: {
|
|
55
|
+
language: 'python',
|
|
56
|
+
package: 'agent_runtimes.tools.decisions',
|
|
57
|
+
method: 'decide',
|
|
58
|
+
},
|
|
59
|
+
icon: 'law',
|
|
60
|
+
emoji: '⚖️',
|
|
61
|
+
};
|
|
44
62
|
export const DISPLAY_RECIPE_TOOL_SPEC_0_0_1 = {
|
|
45
63
|
id: 'display-recipe',
|
|
46
64
|
version: '0.0.1',
|
|
@@ -335,6 +353,7 @@ export const UPDATE_PLAN_STEP_TOOL_SPEC_0_0_1 = {
|
|
|
335
353
|
export const TOOL_CATALOG = {
|
|
336
354
|
'create-plan': CREATE_PLAN_TOOL_SPEC_0_0_1,
|
|
337
355
|
'current-time': CURRENT_TIME_TOOL_SPEC_0_0_1,
|
|
356
|
+
decide: DECIDE_TOOL_SPEC_0_0_1,
|
|
338
357
|
'display-recipe': DISPLAY_RECIPE_TOOL_SPEC_0_0_1,
|
|
339
358
|
'example-create-plan': EXAMPLE_CREATE_PLAN_TOOL_SPEC_0_0_1,
|
|
340
359
|
'example-current-time': EXAMPLE_CURRENT_TIME_TOOL_SPEC_0_0_1,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react-vite';
|
|
2
|
+
import { type AssistantPicture, type ReferenceMode } from './ReferenceScreens';
|
|
3
|
+
import type { ThemeVariant } from '@datalayer/primer-addons';
|
|
4
|
+
interface ReferenceArgs {
|
|
5
|
+
theme: ThemeVariant;
|
|
6
|
+
mode: ReferenceMode;
|
|
7
|
+
picture: AssistantPicture;
|
|
8
|
+
}
|
|
9
|
+
declare const meta: Meta<ReferenceArgs>;
|
|
10
|
+
export default meta;
|
|
11
|
+
type Story = StoryObj<ReferenceArgs>;
|
|
12
|
+
/** A conversation. */
|
|
13
|
+
export declare const Conversation: Story;
|
|
14
|
+
/** A conversation beside its work. */
|
|
15
|
+
export declare const BesideItsWork: Story;
|
|
16
|
+
/** The activity of a worker. */
|
|
17
|
+
export declare const WorkerActivity: Story;
|
|
18
|
+
/** An approval. */
|
|
19
|
+
export declare const Approval: Story;
|
|
20
|
+
/** The floating assistant, in each of its states or stepped aside. */
|
|
21
|
+
export declare const Assistant: Story;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { ASSISTANT_PICTURES, AssistantScreen, ApprovalScreen, BesideWorkScreen, ConversationScreen, REFERENCE_THEMES, ReferenceTheme, WorkerActivityScreen, } from './ReferenceScreens';
|
|
3
|
+
const meta = {
|
|
4
|
+
title: 'Loop/Reference screens',
|
|
5
|
+
parameters: { layout: 'fullscreen' },
|
|
6
|
+
args: { theme: 'loop', mode: 'light', picture: 'idle' },
|
|
7
|
+
argTypes: {
|
|
8
|
+
theme: { control: 'select', options: REFERENCE_THEMES },
|
|
9
|
+
mode: { control: 'inline-radio', options: ['light', 'dark'] },
|
|
10
|
+
picture: { control: 'select', options: [...ASSISTANT_PICTURES] },
|
|
11
|
+
},
|
|
12
|
+
};
|
|
13
|
+
export default meta;
|
|
14
|
+
function story(Screen) {
|
|
15
|
+
return {
|
|
16
|
+
argTypes: { picture: { table: { disable: true } } },
|
|
17
|
+
render: ({ theme, mode }) => (_jsx(ReferenceTheme, { theme: theme, mode: mode, children: _jsx(Screen, {}) })),
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
/** A conversation. */
|
|
21
|
+
export const Conversation = story(ConversationScreen);
|
|
22
|
+
/** A conversation beside its work. */
|
|
23
|
+
export const BesideItsWork = story(BesideWorkScreen);
|
|
24
|
+
/** The activity of a worker. */
|
|
25
|
+
export const WorkerActivity = story(WorkerActivityScreen);
|
|
26
|
+
/** An approval. */
|
|
27
|
+
export const Approval = story(ApprovalScreen);
|
|
28
|
+
/** The floating assistant, in each of its states or stepped aside. */
|
|
29
|
+
export const Assistant = {
|
|
30
|
+
render: ({ theme, mode, picture }) => (_jsx(ReferenceTheme, { theme: theme, mode: mode, children: _jsx(AssistantScreen, { picture: picture }) })),
|
|
31
|
+
};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { JSX, ReactNode } from 'react';
|
|
2
|
+
import { type ThemeVariant } from '@datalayer/primer-addons';
|
|
3
|
+
/** The four screens, by the name a picture and a story take. */
|
|
4
|
+
export declare const REFERENCE_SCREENS: readonly ["conversation", "beside-work", "worker-activity", "approval"];
|
|
5
|
+
export type ReferenceScreen = (typeof REFERENCE_SCREENS)[number];
|
|
6
|
+
/** The floating assistant's pictures (T-27): its states, and stepped aside. */
|
|
7
|
+
export declare const ASSISTANT_PICTURES: readonly ["idle", "thinking", "working", "waiting", "speaking", "aside"];
|
|
8
|
+
export type AssistantPicture = (typeof ASSISTANT_PICTURES)[number];
|
|
9
|
+
/**
|
|
10
|
+
* The characters pictured idle, each in light and dark (T-25, T-24):
|
|
11
|
+
* Datalayer's wizard, cat and L👀P eyes — the paper clip's idle is
|
|
12
|
+
* `assistant-idle` — and the owl an example plugin contributes, drawn
|
|
13
|
+
* through `loop.assistant.character`.
|
|
14
|
+
*/
|
|
15
|
+
export declare const CHARACTER_PICTURES: readonly ["wizard", "cat", "eyes", "owl"];
|
|
16
|
+
export type CharacterPicture = (typeof CHARACTER_PICTURES)[number];
|
|
17
|
+
export type ReferenceMode = 'light' | 'dark';
|
|
18
|
+
/** Every theme of the registry, in its order. */
|
|
19
|
+
export declare const REFERENCE_THEMES: ThemeVariant[];
|
|
20
|
+
/**
|
|
21
|
+
* A screen in a theme and a mode, on its stage: the flat tint of the accent
|
|
22
|
+
* in `loop` (mint, the default), the muted canvas in every other theme.
|
|
23
|
+
*/
|
|
24
|
+
export declare function ReferenceTheme({ theme, mode, children, }: {
|
|
25
|
+
theme: ThemeVariant;
|
|
26
|
+
mode: ReferenceMode;
|
|
27
|
+
children: ReactNode;
|
|
28
|
+
}): JSX.Element;
|
|
29
|
+
/** A conversation. */
|
|
30
|
+
export declare function ConversationScreen(): JSX.Element;
|
|
31
|
+
/** A conversation beside its work: the split, one hairline between them. */
|
|
32
|
+
export declare function BesideWorkScreen(): JSX.Element;
|
|
33
|
+
/** The activity of a worker: what it did on its own, as it did it. */
|
|
34
|
+
export declare function WorkerActivityScreen(): JSX.Element;
|
|
35
|
+
/** An approval: the action, the rule that asks, and the one decision. */
|
|
36
|
+
export declare function ApprovalScreen(): JSX.Element;
|
|
37
|
+
export declare const REFERENCE_SCREEN_COMPONENTS: Record<ReferenceScreen, () => JSX.Element>;
|
|
38
|
+
/**
|
|
39
|
+
* The paper clip in one state, in the page's corner. `aside` puts a dialog
|
|
40
|
+
* over it: the real `useKeepClear` steps it aside, and the picture shows the
|
|
41
|
+
* dialog alone.
|
|
42
|
+
*/
|
|
43
|
+
export declare function AssistantScreen({ picture, }: {
|
|
44
|
+
picture: AssistantPicture;
|
|
45
|
+
}): JSX.Element;
|
|
46
|
+
/**
|
|
47
|
+
* One character idle in the page's corner, read from what the enabled
|
|
48
|
+
* plugins contribute; `ready` is drawn with it.
|
|
49
|
+
*/
|
|
50
|
+
export declare function CharacterScreen({ character, ready, }: {
|
|
51
|
+
character: CharacterPicture;
|
|
52
|
+
ready?: ReactNode;
|
|
53
|
+
}): JSX.Element;
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/*
|
|
3
|
+
* Copyright (c) 2025-2026 Datalayer, Inc.
|
|
4
|
+
* Distributed under the terms of the Modified BSD License.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* The four reference screens of the `loop` theme (LOOP T-01), and the
|
|
8
|
+
* floating assistant's states (T-27), drawn from the real chat components
|
|
9
|
+
* with fixed data: no agent, no network, no clock.
|
|
10
|
+
*
|
|
11
|
+
* - a conversation;
|
|
12
|
+
* - a conversation beside its work;
|
|
13
|
+
* - the activity of a worker;
|
|
14
|
+
* - an approval.
|
|
15
|
+
*
|
|
16
|
+
* Each renders in any theme of the registry and in either mode, so the same
|
|
17
|
+
* screen is the design reference (the stories) and the picture a token change
|
|
18
|
+
* is compared against (`pictures/`, T-16).
|
|
19
|
+
*
|
|
20
|
+
* @module stories/loop/ReferenceScreens
|
|
21
|
+
*/
|
|
22
|
+
import { useEffect, useRef, useState } from 'react';
|
|
23
|
+
import { Box, Button, Heading, Text } from '@primer/react';
|
|
24
|
+
import { DatalayerThemeProvider, loopAccentStyles, setupPrimerPortals, themeConfigs, } from '@datalayer/primer-addons';
|
|
25
|
+
import { ChatBaseHeader } from '../../chat/header/ChatHeaderBase';
|
|
26
|
+
import { ChatMessageList } from '../../chat/messages/ChatMessageList';
|
|
27
|
+
import { InputPrompt } from '../../chat/prompt/InputPrompt';
|
|
28
|
+
import { PresenceFace, PresenceLine } from '../../chat/presence/Presence';
|
|
29
|
+
import { AssistantStage } from '../../chat/assistant/AssistantStage';
|
|
30
|
+
import { buildReactorFromPlugins } from '@datalayer/reactor';
|
|
31
|
+
import { AssistantCharactersPlugin, assistantCharacterNamed, } from '../../loop/plugins/assistant-characters';
|
|
32
|
+
import { OwlCharacterPlugin } from '../../examples/utils/owlCharacterPlugin';
|
|
33
|
+
/** The four screens, by the name a picture and a story take. */
|
|
34
|
+
export const REFERENCE_SCREENS = [
|
|
35
|
+
'conversation',
|
|
36
|
+
'beside-work',
|
|
37
|
+
'worker-activity',
|
|
38
|
+
'approval',
|
|
39
|
+
];
|
|
40
|
+
/** The floating assistant's pictures (T-27): its states, and stepped aside. */
|
|
41
|
+
export const ASSISTANT_PICTURES = [
|
|
42
|
+
'idle',
|
|
43
|
+
'thinking',
|
|
44
|
+
'working',
|
|
45
|
+
'waiting',
|
|
46
|
+
'speaking',
|
|
47
|
+
'aside',
|
|
48
|
+
];
|
|
49
|
+
/**
|
|
50
|
+
* The characters pictured idle, each in light and dark (T-25, T-24):
|
|
51
|
+
* Datalayer's wizard, cat and L👀P eyes — the paper clip's idle is
|
|
52
|
+
* `assistant-idle` — and the owl an example plugin contributes, drawn
|
|
53
|
+
* through `loop.assistant.character`.
|
|
54
|
+
*/
|
|
55
|
+
export const CHARACTER_PICTURES = ['wizard', 'cat', 'eyes', 'owl'];
|
|
56
|
+
/** Every theme of the registry, in its order. */
|
|
57
|
+
export const REFERENCE_THEMES = Object.keys(themeConfigs);
|
|
58
|
+
// ---------------------------------------------------------------------------
|
|
59
|
+
// The theme around a screen
|
|
60
|
+
// ---------------------------------------------------------------------------
|
|
61
|
+
/**
|
|
62
|
+
* A screen in a theme and a mode, on its stage: the flat tint of the accent
|
|
63
|
+
* in `loop` (mint, the default), the muted canvas in every other theme.
|
|
64
|
+
*/
|
|
65
|
+
export function ReferenceTheme({ theme, mode, children, }) {
|
|
66
|
+
const config = themeConfigs[theme] ?? themeConfigs.loop;
|
|
67
|
+
useEffect(() => {
|
|
68
|
+
setupPrimerPortals();
|
|
69
|
+
}, []);
|
|
70
|
+
useEffect(() => {
|
|
71
|
+
document.documentElement.setAttribute('data-reference-theme', theme);
|
|
72
|
+
document.documentElement.setAttribute('data-reference-mode', mode);
|
|
73
|
+
}, [theme, mode]);
|
|
74
|
+
return (_jsx(DatalayerThemeProvider, { colorMode: mode, theme: config.primerTheme, themeStyles: config.themeStyles, baseStyles: theme === 'loop'
|
|
75
|
+
? loopAccentStyles('green', mode)
|
|
76
|
+
: undefined, children: _jsx(Box, { "data-reference-stage": "", sx: {
|
|
77
|
+
position: 'fixed',
|
|
78
|
+
inset: 0,
|
|
79
|
+
p: 4,
|
|
80
|
+
bg: 'var(--loop-stage, var(--bgColor-muted))',
|
|
81
|
+
color: 'fg.default',
|
|
82
|
+
display: 'flex',
|
|
83
|
+
}, children: children }) }));
|
|
84
|
+
}
|
|
85
|
+
/** One rounded surface on the stage: the theme's frame. */
|
|
86
|
+
function Frame({ children }) {
|
|
87
|
+
return (_jsx(Box, { sx: {
|
|
88
|
+
flex: 1,
|
|
89
|
+
minWidth: 0,
|
|
90
|
+
display: 'flex',
|
|
91
|
+
overflow: 'hidden',
|
|
92
|
+
bg: 'canvas.default',
|
|
93
|
+
borderRadius: 'var(--theme-radius-frame, 12px)',
|
|
94
|
+
border: 'var(--theme-hairline, 1px) solid',
|
|
95
|
+
borderColor: 'border.muted',
|
|
96
|
+
boxShadow: 'var(--theme-shadow, none)',
|
|
97
|
+
}, children: children }));
|
|
98
|
+
}
|
|
99
|
+
// ---------------------------------------------------------------------------
|
|
100
|
+
// Fixed data
|
|
101
|
+
// ---------------------------------------------------------------------------
|
|
102
|
+
const AT = new Date('2026-10-04T09:30:00Z');
|
|
103
|
+
function said(id, role, content) {
|
|
104
|
+
return { id, role, content, createdAt: AT };
|
|
105
|
+
}
|
|
106
|
+
function tool(id, toolName, args, status, result) {
|
|
107
|
+
return {
|
|
108
|
+
id,
|
|
109
|
+
type: 'tool-call',
|
|
110
|
+
toolCallId: id,
|
|
111
|
+
toolName,
|
|
112
|
+
args,
|
|
113
|
+
status,
|
|
114
|
+
result,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
const CONVERSATION = [
|
|
118
|
+
said('m1', 'user', 'Which customers wrote about late deliveries this week?'),
|
|
119
|
+
said('m2', 'assistant', 'Three of them: **Ada Lovelace** (order 1042, four days late), ' +
|
|
120
|
+
'**Grace Hopper** (order 1057, asks for a refund) and **Alan Turing** ' +
|
|
121
|
+
'(order 1061, no tracking number). The details are in the ' +
|
|
122
|
+
'[support log](https://example.com/log).'),
|
|
123
|
+
said('m3', 'user', 'Draft a reply to Ada.'),
|
|
124
|
+
said('m4', 'assistant', 'Here is a draft, beside the conversation. It apologises, gives the new ' +
|
|
125
|
+
'date and offers free shipping on her next order.'),
|
|
126
|
+
];
|
|
127
|
+
const BESIDE_WORK = CONVERSATION.slice(2);
|
|
128
|
+
const WORKER_ACTIVITY = [
|
|
129
|
+
said('w1', 'assistant', 'Morning run: 12 new messages in the inbox.'),
|
|
130
|
+
tool('w2', 'read_inbox', { since: '2026-10-04T06:00:00Z' }, 'complete', {
|
|
131
|
+
messages: 12,
|
|
132
|
+
}),
|
|
133
|
+
tool('w3', 'label_message', { id: 'msg-881', label: 'Refund' }, 'complete', {
|
|
134
|
+
ok: true,
|
|
135
|
+
}),
|
|
136
|
+
tool('w4', 'label_message', { id: 'msg-884', label: 'Delivery' }, 'complete', { ok: true }),
|
|
137
|
+
said('w5', 'assistant', 'Nine labelled, two answered from the help centre, one left for you: a ' +
|
|
138
|
+
'refund above the limit.'),
|
|
139
|
+
tool('w6', 'draft_reply', { id: 'msg-887' }, 'executing'),
|
|
140
|
+
];
|
|
141
|
+
const APPROVAL = [
|
|
142
|
+
said('a1', 'user', 'Send the reply to Ada.'),
|
|
143
|
+
said('a2', 'assistant', 'Sending is a rule you keep: I ask first.'),
|
|
144
|
+
tool('a3', 'send_email', { to: 'ada@example.com', subject: 'Your order 1042' }, 'inProgress', { pending_approval: true, approval_id: 'approval-1' }),
|
|
145
|
+
];
|
|
146
|
+
// ---------------------------------------------------------------------------
|
|
147
|
+
// The conversation
|
|
148
|
+
// ---------------------------------------------------------------------------
|
|
149
|
+
const AVATARS = {
|
|
150
|
+
userAvatar: 'me',
|
|
151
|
+
assistantAvatar: 'ai',
|
|
152
|
+
showAvatars: false,
|
|
153
|
+
avatarSize: 24,
|
|
154
|
+
userAvatarBg: 'accent.subtle',
|
|
155
|
+
assistantAvatarBg: 'accent.emphasis',
|
|
156
|
+
};
|
|
157
|
+
/** A chat as an application shows it: its presence, its words, its composer. */
|
|
158
|
+
function Conversation({ name, face, presence, items, composer = true, }) {
|
|
159
|
+
const endRef = useRef(null);
|
|
160
|
+
const [input, setInput] = useState('');
|
|
161
|
+
return (_jsxs(Box, { sx: {
|
|
162
|
+
flex: 1,
|
|
163
|
+
minWidth: 0,
|
|
164
|
+
display: 'flex',
|
|
165
|
+
flexDirection: 'column',
|
|
166
|
+
height: '100%',
|
|
167
|
+
}, children: [_jsx(ChatBaseHeader, { title: name, brandIcon: _jsx(PresenceFace, { face: face, size: 20, state: presence }), headerContent: _jsx(PresenceLine, { state: presence }), padding: 3, messageCount: items.length, onNewChat: () => undefined, onClear: () => undefined }), _jsx(Box, { sx: { flex: 1, minHeight: 0, overflow: 'hidden' }, children: _jsx(ChatMessageList, { displayItems: items, isLoading: false, isStreaming: false, showLoadingIndicator: false, hideMessagesAfterToolUI: false, avatarConfig: AVATARS, padding: 3, emptyContent: null, messagesEndRef: endRef, onRespond: async () => undefined }) }), composer && (_jsx(InputPrompt, { input: input, setInput: setInput, isLoading: false, connectionConfirmed: true, placeholder: "Send a message", autoFocus: false, padding: 3, onSend: () => undefined, onStop: () => undefined, showTokenUsage: false, showModelSelector: false, showToolsMenu: false, showSkillsMenu: false, codemodeEnabled: false, hasConfigData: false, hasSkillsData: false, isA2AProtocol: false }))] }));
|
|
168
|
+
}
|
|
169
|
+
// ---------------------------------------------------------------------------
|
|
170
|
+
// The four screens
|
|
171
|
+
// ---------------------------------------------------------------------------
|
|
172
|
+
/** A conversation. */
|
|
173
|
+
export function ConversationScreen() {
|
|
174
|
+
return (_jsx(Frame, { children: _jsx(Box, { sx: { flex: 1, display: 'flex', justifyContent: 'center' }, children: _jsx(Box, { sx: { width: '100%', maxWidth: 640, display: 'flex' }, children: _jsx(Conversation, { name: "Support desk", face: "\uD83E\uDD8A", presence: "idle", items: CONVERSATION }) }) }) }));
|
|
175
|
+
}
|
|
176
|
+
/** A conversation beside its work: the split, one hairline between them. */
|
|
177
|
+
export function BesideWorkScreen() {
|
|
178
|
+
return (_jsxs(Frame, { children: [_jsx(Box, { sx: { width: 400, flexShrink: 0, display: 'flex' }, children: _jsx(Conversation, { name: "Support desk", face: "\uD83E\uDD8A", presence: "idle", items: BESIDE_WORK }) }), _jsx(Box, { sx: {
|
|
179
|
+
width: 'var(--theme-hairline, 1px)',
|
|
180
|
+
bg: 'border.muted',
|
|
181
|
+
flexShrink: 0,
|
|
182
|
+
} }), _jsxs(Box, { "data-reference-work": "", sx: {
|
|
183
|
+
flex: 1,
|
|
184
|
+
minWidth: 0,
|
|
185
|
+
p: 4,
|
|
186
|
+
display: 'flex',
|
|
187
|
+
flexDirection: 'column',
|
|
188
|
+
gap: 3,
|
|
189
|
+
}, children: [_jsx(Text, { sx: { color: 'fg.muted', fontSize: 1 }, children: "Draft \u00B7 reply" }), _jsx(Heading, { as: "h2", sx: { fontSize: 3, fontWeight: 600 }, children: "Your order 1042" }), _jsx(Text, { sx: { color: 'fg.muted', fontSize: 1 }, children: "To ada@example.com" }), _jsxs(Box, { sx: { display: 'flex', flexDirection: 'column', gap: 2 }, children: [_jsx(Text, { as: "p", sx: { m: 0 }, children: "Dear Ada," }), _jsx(Text, { as: "p", sx: { m: 0 }, children: "We are sorry your order arrived four days late. It left our warehouse on Monday and is with you by Thursday, 8 October." }), _jsx(Text, { as: "p", sx: { m: 0 }, children: "Your next order ships free, with no code to enter." }), _jsx(Text, { as: "p", sx: { m: 0 }, children: "The support desk" })] }), _jsxs(Box, { sx: { display: 'flex', gap: 2, mt: 'auto' }, children: [_jsx(Button, { variant: "primary", children: "Send" }), _jsx(Button, { children: "Edit" })] })] })] }));
|
|
190
|
+
}
|
|
191
|
+
/** The activity of a worker: what it did on its own, as it did it. */
|
|
192
|
+
export function WorkerActivityScreen() {
|
|
193
|
+
return (_jsx(Frame, { children: _jsx(Box, { sx: { flex: 1, display: 'flex', justifyContent: 'center' }, children: _jsx(Box, { sx: { width: '100%', maxWidth: 680, display: 'flex' }, children: _jsx(Conversation, { name: "Inbox triage", face: "\uD83D\uDCEC", presence: "working", items: WORKER_ACTIVITY, composer: false }) }) }) }));
|
|
194
|
+
}
|
|
195
|
+
/** An approval: the action, the rule that asks, and the one decision. */
|
|
196
|
+
export function ApprovalScreen() {
|
|
197
|
+
return (_jsx(Frame, { children: _jsx(Box, { sx: { flex: 1, display: 'flex', justifyContent: 'center' }, children: _jsx(Box, { sx: { width: '100%', maxWidth: 640, display: 'flex' }, children: _jsx(Conversation, { name: "Support desk", face: "\uD83E\uDD8A", presence: "waiting", items: APPROVAL }) }) }) }));
|
|
198
|
+
}
|
|
199
|
+
export const REFERENCE_SCREEN_COMPONENTS = {
|
|
200
|
+
conversation: ConversationScreen,
|
|
201
|
+
'beside-work': BesideWorkScreen,
|
|
202
|
+
'worker-activity': WorkerActivityScreen,
|
|
203
|
+
approval: ApprovalScreen,
|
|
204
|
+
};
|
|
205
|
+
// ---------------------------------------------------------------------------
|
|
206
|
+
// The floating assistant (T-27)
|
|
207
|
+
// ---------------------------------------------------------------------------
|
|
208
|
+
const BALLOONS = {
|
|
209
|
+
speaking: {
|
|
210
|
+
text: 'Three customers wrote about late deliveries this week: Ada, Grace and Alan.',
|
|
211
|
+
more: true,
|
|
212
|
+
},
|
|
213
|
+
waiting: { text: 'Waiting for you: send the reply to Ada?' },
|
|
214
|
+
};
|
|
215
|
+
/**
|
|
216
|
+
* The paper clip in one state, in the page's corner. `aside` puts a dialog
|
|
217
|
+
* over it: the real `useKeepClear` steps it aside, and the picture shows the
|
|
218
|
+
* dialog alone.
|
|
219
|
+
*/
|
|
220
|
+
export function AssistantScreen({ picture, }) {
|
|
221
|
+
const stageRef = useRef(null);
|
|
222
|
+
const state = picture === 'aside' ? 'idle' : picture;
|
|
223
|
+
const balloon = BALLOONS[picture];
|
|
224
|
+
return (_jsxs(Box, { sx: { flex: 1, position: 'relative' }, children: [picture === 'aside' && (_jsxs(Box, { role: "dialog", "aria-label": "A dialog over the assistant", sx: {
|
|
225
|
+
position: 'fixed',
|
|
226
|
+
right: 24,
|
|
227
|
+
bottom: 24,
|
|
228
|
+
width: 280,
|
|
229
|
+
height: 160,
|
|
230
|
+
p: 3,
|
|
231
|
+
zIndex: 2000,
|
|
232
|
+
bg: 'canvas.overlay',
|
|
233
|
+
border: 'var(--theme-hairline, 1px) solid',
|
|
234
|
+
borderColor: 'border.default',
|
|
235
|
+
borderRadius: 'var(--theme-radius-card, 6px)',
|
|
236
|
+
boxShadow: 'var(--theme-shadow, none)',
|
|
237
|
+
}, children: [_jsx(Text, { sx: { fontWeight: 600 }, children: "A dialog" }), _jsx(Text, { as: "p", sx: { color: 'fg.muted', fontSize: 1 }, children: "The assistant steps aside while this is open." })] })), _jsx(AssistantStage, { character: "paperclip", state: state, place: { right: 48, bottom: 48 }, stageRef: stageRef, onDragStart: () => undefined, open: false, onToggle: () => undefined, balloon: balloon, insist: !!balloon, onDismiss: () => undefined })] }));
|
|
238
|
+
}
|
|
239
|
+
// ---------------------------------------------------------------------------
|
|
240
|
+
// The characters (T-25, T-24)
|
|
241
|
+
// ---------------------------------------------------------------------------
|
|
242
|
+
/** Datalayer's characters and the example plugin's owl, as contributed. */
|
|
243
|
+
const characterReactor = buildReactorFromPlugins([
|
|
244
|
+
AssistantCharactersPlugin,
|
|
245
|
+
OwlCharacterPlugin,
|
|
246
|
+
]);
|
|
247
|
+
characterReactor.start();
|
|
248
|
+
/**
|
|
249
|
+
* One character idle in the page's corner, read from what the enabled
|
|
250
|
+
* plugins contribute; `ready` is drawn with it.
|
|
251
|
+
*/
|
|
252
|
+
export function CharacterScreen({ character, ready, }) {
|
|
253
|
+
const stageRef = useRef(null);
|
|
254
|
+
const drawn = assistantCharacterNamed(characterReactor, character);
|
|
255
|
+
return (_jsxs(Box, { sx: { flex: 1, position: 'relative' }, children: [_jsx(AssistantStage, { character: drawn, state: "idle", place: { right: 48, bottom: 48 }, stageRef: stageRef, onDragStart: () => undefined, open: false, onToggle: () => undefined, onDismiss: () => undefined }), ready] }));
|
|
256
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/*
|
|
3
|
+
* Copyright (c) 2025-2026 Datalayer, Inc.
|
|
4
|
+
* Distributed under the terms of the Modified BSD License.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* The page the pictures are taken of (LOOP T-16): one reference screen, or
|
|
8
|
+
* one state of the floating assistant, in one theme and one mode, chosen by
|
|
9
|
+
* the address — `html/pictures.html?screen=approval&theme=loop&mode=dark`,
|
|
10
|
+
* or `?assistant=thinking&mode=light`, or a character idle,
|
|
11
|
+
* `?character=wizard&mode=dark` (Datalayer's, or the owl a plugin contributes).
|
|
12
|
+
*
|
|
13
|
+
* It sets `data-pictures-ready` on the document once the fonts are in — Inter
|
|
14
|
+
* in its two weights, served by this page (T-04) — and two frames have
|
|
15
|
+
* painted, which is what the capture waits for.
|
|
16
|
+
*
|
|
17
|
+
* @module stories/loop/pictures-main
|
|
18
|
+
*/
|
|
19
|
+
const globals = globalThis;
|
|
20
|
+
if (globals['__webpack_public_path__'] === undefined) {
|
|
21
|
+
globals['__webpack_public_path__'] = '';
|
|
22
|
+
}
|
|
23
|
+
import { useEffect } from 'react';
|
|
24
|
+
import { createRoot } from 'react-dom/client';
|
|
25
|
+
import { ASSISTANT_PICTURES, AssistantScreen, CHARACTER_PICTURES, CharacterScreen, REFERENCE_SCREEN_COMPONENTS, REFERENCE_SCREENS, REFERENCE_THEMES, ReferenceTheme, } from './ReferenceScreens';
|
|
26
|
+
import '../../../style/primer-primitives.css';
|
|
27
|
+
// The `loop` theme's face (LOOP T-04): Inter and its metric-matched fallback,
|
|
28
|
+
// served by this page's own Vite, as the landing serves them from its build.
|
|
29
|
+
import '@datalayer/primer-addons/style/loop-face.css';
|
|
30
|
+
const params = new URLSearchParams(window.location.search);
|
|
31
|
+
const theme = (REFERENCE_THEMES.includes(params.get('theme'))
|
|
32
|
+
? params.get('theme')
|
|
33
|
+
: 'loop');
|
|
34
|
+
const mode = params.get('mode') === 'dark' ? 'dark' : 'light';
|
|
35
|
+
const screen = params.get('screen');
|
|
36
|
+
const assistant = params.get('assistant');
|
|
37
|
+
const character = params.get('character');
|
|
38
|
+
function Ready() {
|
|
39
|
+
useEffect(() => {
|
|
40
|
+
let cancelled = false;
|
|
41
|
+
// Inter is fetched only once text asks for it: ask for both weights, so
|
|
42
|
+
// that the picture is never taken in the fallback.
|
|
43
|
+
void Promise.all([
|
|
44
|
+
document.fonts.load('400 14px "Inter Variable"'),
|
|
45
|
+
document.fonts.load('600 14px "Inter Variable"'),
|
|
46
|
+
])
|
|
47
|
+
.then(() => document.fonts.ready)
|
|
48
|
+
.then(() => {
|
|
49
|
+
requestAnimationFrame(() => requestAnimationFrame(() => {
|
|
50
|
+
if (!cancelled) {
|
|
51
|
+
document.documentElement.setAttribute('data-pictures-ready', '');
|
|
52
|
+
}
|
|
53
|
+
}));
|
|
54
|
+
});
|
|
55
|
+
return () => {
|
|
56
|
+
cancelled = true;
|
|
57
|
+
};
|
|
58
|
+
}, []);
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
function Page() {
|
|
62
|
+
if (character && CHARACTER_PICTURES.includes(character)) {
|
|
63
|
+
return (_jsx(ReferenceTheme, { theme: theme, mode: mode, children: _jsx(CharacterScreen, { character: character, ready: _jsx(Ready, {}) }) }));
|
|
64
|
+
}
|
|
65
|
+
if (assistant && ASSISTANT_PICTURES.includes(assistant)) {
|
|
66
|
+
return (_jsxs(ReferenceTheme, { theme: theme, mode: mode, children: [_jsx(AssistantScreen, { picture: assistant }), _jsx(Ready, {})] }));
|
|
67
|
+
}
|
|
68
|
+
const name = screen && REFERENCE_SCREENS.includes(screen) ? screen : 'conversation';
|
|
69
|
+
const Screen = REFERENCE_SCREEN_COMPONENTS[name];
|
|
70
|
+
return (_jsxs(ReferenceTheme, { theme: theme, mode: mode, children: [_jsx(Screen, {}), _jsx(Ready, {})] }));
|
|
71
|
+
}
|
|
72
|
+
const container = document.getElementById('root');
|
|
73
|
+
if (container) {
|
|
74
|
+
createRoot(container).render(_jsx(Page, {}));
|
|
75
|
+
}
|
|
@@ -476,6 +476,11 @@ export interface AppRecordSpec {
|
|
|
476
476
|
keepFor: string;
|
|
477
477
|
retentionDays: number;
|
|
478
478
|
include: string[];
|
|
479
|
+
/**
|
|
480
|
+
* Whether its conversations may be used to suggest tests (LOOP V-16): off
|
|
481
|
+
* unless said, and only those kept while it is on are sampled.
|
|
482
|
+
*/
|
|
483
|
+
suggestTests: boolean;
|
|
479
484
|
}
|
|
480
485
|
/** Optional checks from the catalogue. */
|
|
481
486
|
export interface AppChecksSpec {
|
|
@@ -522,7 +527,7 @@ export interface AppDecisionSpec {
|
|
|
522
527
|
criteria: AppCriterionSpec[];
|
|
523
528
|
minConfidence: number;
|
|
524
529
|
scenarios: AppScenarioSpec[];
|
|
525
|
-
|
|
530
|
+
decisionModel: string;
|
|
526
531
|
}
|
|
527
532
|
/**
|
|
528
533
|
* An application (`agentspecs/apps`): the Appspec. An agent with an interface,
|
package/lib/types/chat.d.ts
CHANGED
|
@@ -653,6 +653,11 @@ export interface ChatBaseProps {
|
|
|
653
653
|
stop: () => void;
|
|
654
654
|
/** Start the conversation over — what the header's + does. */
|
|
655
655
|
newChat: () => void;
|
|
656
|
+
/**
|
|
657
|
+
* The conversation the next message goes to, as the runtime knows it
|
|
658
|
+
* (AG-UI's thread): what an application's record keeps it under.
|
|
659
|
+
*/
|
|
660
|
+
thread: () => string;
|
|
656
661
|
} | null) => void;
|
|
657
662
|
/**
|
|
658
663
|
* Reports whether the chat is streaming a reply, so a host that owns the
|