@datalayer/agent-runtimes 1.3.27 → 1.3.29

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/lib/chat/ChatFloating.d.ts +12 -2
  2. package/lib/chat/ChatFloating.js +196 -25
  3. package/lib/chat/assistant/AssistantStage.d.ts +70 -0
  4. package/lib/chat/assistant/AssistantStage.js +192 -0
  5. package/lib/chat/assistant/SpeechBalloon.d.ts +26 -0
  6. package/lib/chat/assistant/SpeechBalloon.js +46 -0
  7. package/lib/chat/assistant/SpriteCharacter.d.ts +26 -0
  8. package/lib/chat/assistant/SpriteCharacter.js +73 -0
  9. package/lib/chat/assistant/characters.d.ts +30 -0
  10. package/lib/chat/assistant/characters.js +41 -0
  11. package/lib/chat/assistant/formats/acs.d.ts +88 -0
  12. package/lib/chat/assistant/formats/acs.js +493 -0
  13. package/lib/chat/assistant/formats/agentCompression.d.ts +5 -0
  14. package/lib/chat/assistant/formats/agentCompression.js +92 -0
  15. package/lib/chat/assistant/formats/blobs.d.ts +6 -0
  16. package/lib/chat/assistant/formats/blobs.js +52 -0
  17. package/lib/chat/assistant/formats/clippy.d.ts +21 -0
  18. package/lib/chat/assistant/formats/clippy.js +167 -0
  19. package/lib/chat/assistant/formats/index.d.ts +13 -0
  20. package/lib/chat/assistant/formats/index.js +15 -0
  21. package/lib/chat/assistant/formats/objectLiteral.d.ts +23 -0
  22. package/lib/chat/assistant/formats/objectLiteral.js +233 -0
  23. package/lib/chat/assistant/formats/stateAnimations.d.ts +16 -0
  24. package/lib/chat/assistant/formats/stateAnimations.js +115 -0
  25. package/lib/chat/assistant/formats/types.d.ts +56 -0
  26. package/lib/chat/assistant/formats/types.js +11 -0
  27. package/lib/chat/assistant/state.d.ts +62 -0
  28. package/lib/chat/assistant/state.js +116 -0
  29. package/lib/chat/header/ChatViewModeToggle.js +6 -3
  30. package/lib/chat/presence/Presence.d.ts +9 -0
  31. package/lib/chat/presence/Presence.js +57 -0
  32. package/lib/chat/presence/presenceStatus.d.ts +32 -0
  33. package/lib/chat/presence/presenceStatus.js +46 -0
  34. package/lib/chat/viewModes.d.ts +6 -0
  35. package/lib/chat/viewModes.js +10 -1
  36. package/lib/examples/ChatAssistantExample.d.ts +8 -0
  37. package/lib/examples/ChatAssistantExample.js +59 -0
  38. package/lib/examples/example-selector.js +1 -0
  39. package/lib/examples/main.js +3 -0
  40. package/lib/loop/apps/AppRenderer.d.ts +8 -1
  41. package/lib/loop/apps/AppRenderer.js +2 -1
  42. package/lib/loop/apps/appspec.d.ts +5 -1
  43. package/lib/loop/apps/appspec.js +21 -1
  44. package/lib/loop/apps/checks.js +3 -1
  45. package/lib/loop/core/index.d.ts +15 -0
  46. package/lib/loop/core/index.js +1 -0
  47. package/lib/loop/plugins/assistant-characters/index.d.ts +30 -0
  48. package/lib/loop/plugins/assistant-characters/index.js +41 -0
  49. package/lib/loop/plugins/chat/ChatView.js +21 -1
  50. package/lib/loop/plugins/chat/index.d.ts +8 -0
  51. package/lib/loop/plugins/page-layout/index.js +5 -1
  52. package/lib/specs/actions.js +6 -0
  53. package/lib/specs/apps.d.ts +3 -0
  54. package/lib/specs/apps.js +793 -65
  55. package/lib/specs/appspecSchema.js +20 -2
  56. package/lib/types/agentspecs.d.ts +10 -1
  57. package/lib/types/chat.d.ts +1 -1
  58. package/package.json +1 -1
@@ -141,6 +141,7 @@ export const LoopChatComposer = defineContributionPoint('loop.chat.composer');
141
141
  export const LoopChatHeader = defineContributionPoint('loop.chat.header');
142
142
  export const LoopAgentBlueprint = defineContributionPoint('loop.agent.blueprint');
143
143
  export const LoopChatSuggestion = defineContributionPoint('loop.chat.suggestion');
144
+ export const LoopAssistantCharacter = defineContributionPoint('loop.assistant.character');
144
145
  export const LoopChatExtras = defineContributionPoint('loop.chat.extras');
145
146
  export const LoopOpeningNotebook = defineContributionPoint('loop.notebook.opening');
146
147
  export const LoopOpeningDocument = defineContributionPoint('loop.document.opening');
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Datalayer's own characters for the floating assistant, contributed
3
+ * (LOOP T-24, T-25): the paper clip, the wizard, the cat and the LšŸ‘€P eyes.
4
+ * Disabled, they leave the catalogue; another plugin may contribute others.
5
+ *
6
+ * @module loop/plugins/assistant-characters
7
+ */
8
+ import { type ReactorPlugin } from '@datalayer/reactor';
9
+ import { type AssistantCharacter } from '../../../chat/assistant/characters';
10
+ import type { AssistantCharacterData } from '../../../chat/assistant/formats/types';
11
+ import { LoopAssistantCharacter, type AssistantCharacterContribution } from '../../core';
12
+ /** What is read of a reactor here: its contributions to the point. */
13
+ type ContributionsReader = {
14
+ getContributions: (point: typeof LoopAssistantCharacter) => ReadonlyArray<{
15
+ value: AssistantCharacterContribution;
16
+ }>;
17
+ };
18
+ export declare const ASSISTANT_CHARACTERS_PLUGIN_NAME = "@datalayer/loop-plugin-assistant-characters";
19
+ export declare const AssistantCharactersPlugin: ReactorPlugin<Record<string, never>, unknown, unknown>;
20
+ /** The characters the enabled plugins contribute, in contribution order. */
21
+ export declare function assistantCharactersOf(reactor: ContributionsReader): {
22
+ id: string;
23
+ character: AssistantCharacter | AssistantCharacterData;
24
+ }[];
25
+ /**
26
+ * The character an application names, from what is contributed; an id no
27
+ * enabled plugin contributes is an error that says which ids there are.
28
+ */
29
+ export declare function assistantCharacterNamed(reactor: ContributionsReader, id: string): AssistantCharacter | AssistantCharacterData;
30
+ export default AssistantCharactersPlugin;
@@ -0,0 +1,41 @@
1
+ /*
2
+ * Copyright (c) 2025-2026 Datalayer, Inc.
3
+ * Distributed under the terms of the Modified BSD License.
4
+ */
5
+ /**
6
+ * Datalayer's own characters for the floating assistant, contributed
7
+ * (LOOP T-24, T-25): the paper clip, the wizard, the cat and the LšŸ‘€P eyes.
8
+ * Disabled, they leave the catalogue; another plugin may contribute others.
9
+ *
10
+ * @module loop/plugins/assistant-characters
11
+ */
12
+ import { contribution, definePlugin, } from '@datalayer/reactor';
13
+ import { ASSISTANT_CHARACTERS, } from '../../../chat/assistant/characters';
14
+ import { LoopAssistantCharacter, } from '../../core';
15
+ export const ASSISTANT_CHARACTERS_PLUGIN_NAME = '@datalayer/loop-plugin-assistant-characters';
16
+ export const AssistantCharactersPlugin = definePlugin({
17
+ name: ASSISTANT_CHARACTERS_PLUGIN_NAME,
18
+ displayName: 'Assistant characters',
19
+ description: "Datalayer's own characters for the floating assistant: a paper clip, a wizard, a cat and the LšŸ‘€P eyes.",
20
+ octicon: 'paperclip',
21
+ contributes: ASSISTANT_CHARACTERS.map(character => contribution(LoopAssistantCharacter, { id: character.id, character }, { id: character.id })),
22
+ });
23
+ /** The characters the enabled plugins contribute, in contribution order. */
24
+ export function assistantCharactersOf(reactor) {
25
+ return reactor
26
+ .getContributions(LoopAssistantCharacter)
27
+ .map(entry => entry.value);
28
+ }
29
+ /**
30
+ * The character an application names, from what is contributed; an id no
31
+ * enabled plugin contributes is an error that says which ids there are.
32
+ */
33
+ export function assistantCharacterNamed(reactor, id) {
34
+ const all = assistantCharactersOf(reactor);
35
+ const found = all.find(entry => entry.id === id);
36
+ if (!found) {
37
+ throw new Error(`No enabled plugin contributes the assistant character "${id}"; the characters are ${all.map(entry => entry.id).join(', ') || 'none'}.`);
38
+ }
39
+ return found.character;
40
+ }
41
+ export default AssistantCharactersPlugin;
@@ -43,6 +43,8 @@ import { turnWritersOf } from './turnState';
43
43
  import { isInactiveSurfaceContribution, orderToolContributions, toolsForChatView, } from './chatViewTools';
44
44
  import { useAgentCommandTools } from '../../../tools/adapters/commands';
45
45
  import { NONE_EDITOR, seedEditorChoice, setEditorOptions, } from '../shell/editorChoice';
46
+ import { PresenceFace, PresenceLine } from '../../../chat/presence/Presence';
47
+ import { presenceState, presenceToolOf, } from '../../../chat/presence/presenceStatus';
46
48
  /** No editor: the conversation on its own. */
47
49
  const NO_SURFACE = '';
48
50
  /**
@@ -186,6 +188,16 @@ export default function ChatView({ workspace }) {
186
188
  */
187
189
  const [busy, setBusy] = useState(false);
188
190
  const [sendReady, setSendReady] = useState(false);
191
+ const [presenceTool, setPresenceTool] = useState({
192
+ open: false,
193
+ pendingApproval: false,
194
+ });
195
+ const presenceNow = presenceState(busy, presenceTool);
196
+ const onPresence = config?.presence?.onPresence;
197
+ // A host drawing the face in a frame of its own is told as it changes.
198
+ useEffect(() => {
199
+ onPresence?.(presenceNow);
200
+ }, [onPresence, presenceNow]);
189
201
  const handleSendReady = useCallback((controls) => {
190
202
  controlsRef.current = controls;
191
203
  setSendReady(!!controls);
@@ -199,6 +211,11 @@ export default function ChatView({ workspace }) {
199
211
  * Cleared when nothing is running.
200
212
  */
201
213
  const handleDisplayItemsChange = useCallback((items) => {
214
+ // The newest tool call, for an application's line of status (T-08).
215
+ const { open, pendingApproval } = presenceToolOf(items);
216
+ setPresenceTool(previous => previous.open === open && previous.pendingApproval === pendingApproval
217
+ ? previous
218
+ : { open, pendingApproval });
202
219
  const feed = turnFeedRef.current;
203
220
  if (!feed) {
204
221
  return;
@@ -1436,7 +1453,10 @@ export default function ChatView({ workspace }) {
1436
1453
  // Big enough to read as the agent's mark rather than as
1437
1454
  // punctuation before its name, and still short enough not to
1438
1455
  // set the header's height.
1439
- brandIcon: presence?.face ? (_jsx("span", { "aria-hidden": true, style: { fontSize: 20, lineHeight: 1 }, children: presence.face })) : (_jsx(BrandIcon, { size: 20 })), emptyState: {
1456
+ brandIcon: presence?.face ? (_jsx(PresenceFace, { face: presence.face, size: 20, state: presenceNow })) : (_jsx(BrandIcon, { size: 20 })),
1457
+ // An application says what it is doing, in plain words, beside
1458
+ // its name (T-08); an agent's chat keeps its header as it is.
1459
+ headerContent: presence ? _jsx(PresenceLine, { state: presenceNow }) : undefined, emptyState: {
1440
1460
  // An application's own face, large: the thing a person's eye
1441
1461
  // lands on first (LOOP T-08).
1442
1462
  icon: presence?.face ? (_jsx("span", { "aria-hidden": true, style: { fontSize: 48, lineHeight: 1 }, children: presence.face })) : (_jsx(BrandIcon, { size: 48 })),
@@ -1,3 +1,4 @@
1
+ import type { PresenceState } from '../../../chat/presence/presenceStatus';
1
2
  /** What a host may set on the chat. */
2
3
  /** Who is answering, as the person meets them. */
3
4
  export interface ChatPresence {
@@ -6,6 +7,13 @@ export interface ChatPresence {
6
7
  face?: string;
7
8
  /** What it says before anyone writes. */
8
9
  welcome?: string;
10
+ /**
11
+ * Told what it is doing as it changes — idle, thinking, working, waiting
12
+ * for you — for a host that draws the face itself, in a frame of its own.
13
+ * Read once, when the workspace is built: pass a stable function, such as
14
+ * a state setter.
15
+ */
16
+ onPresence?: (state: PresenceState) => void;
9
17
  }
10
18
  export type ChatPluginConfig = {
11
19
  /**
@@ -35,6 +35,8 @@ const promptStance = signal('floating-top');
35
35
  * page layout to a page, the assumption that signal already makes.
36
36
  */
37
37
  let floatingStance = 'floating-top';
38
+ /** The modes the page layout does not place. */
39
+ const PAGE_LAYOUT_DISABLED_MODES = ['assistant'];
38
40
  export function pageLayoutForChatMode(mode) {
39
41
  switch (mode) {
40
42
  case 'sidebar':
@@ -60,7 +62,9 @@ export function setPageLayoutChatMode(mode) {
60
62
  /** The toggle in the floating composer's footer. */
61
63
  function ChatModeAction() {
62
64
  const mode = useSignalValue(pageLayoutChatMode);
63
- return _jsx(ChatViewModeToggle, { value: mode, onChange: setPageLayoutChatMode });
65
+ // The page layout places the chat itself: the floating assistant, which
66
+ // ChatFloating draws, is offered greyed out with its reason (T-21).
67
+ return (_jsx(ChatViewModeToggle, { value: mode, onChange: setPageLayoutChatMode, disabledModes: PAGE_LAYOUT_DISABLED_MODES }));
64
68
  }
65
69
  /**
66
70
  * The chat view's parts on the page layout.
@@ -439,6 +439,7 @@ export const SERVER_ACTIONS = {
439
439
  * to reproduce.
440
440
  */
441
441
  export const APP_BEHAVIOURS = {
442
+ 'data-quality': {},
442
443
  'inbox-triage': {
443
444
  'google-workspace.append_table_rows': 'leave_to_me',
444
445
  'google-workspace.batch_modify_gmail_message_labels': 'do_it',
@@ -561,8 +562,10 @@ export const APP_BEHAVIOURS = {
561
562
  'google-workspace.update_drive_file': 'leave_to_me',
562
563
  'google-workspace.update_paragraph_style': 'leave_to_me',
563
564
  },
565
+ 'model-choice': {},
564
566
  'quote-calculator': {},
565
567
  'ship-or-fix': {},
568
+ 'supplier-comparison': {},
566
569
  'web-research': {
567
570
  'tavily.tavily_crawl': 'do_it',
568
571
  'tavily.tavily_extract': 'do_it',
@@ -576,6 +579,7 @@ export const APP_BEHAVIOURS = {
576
579
  * application and tool, each condition and the behaviour when it holds.
577
580
  */
578
581
  export const APP_ESCALATIONS = {
582
+ 'data-quality': {},
579
583
  'inbox-triage': {
580
584
  'google-workspace.batch_modify_gmail_message_labels': [
581
585
  {
@@ -610,7 +614,9 @@ export const APP_ESCALATIONS = {
610
614
  },
611
615
  ],
612
616
  },
617
+ 'model-choice': {},
613
618
  'quote-calculator': {},
614
619
  'ship-or-fix': {},
620
+ 'supplier-comparison': {},
615
621
  'web-research': {},
616
622
  };
@@ -8,9 +8,12 @@
8
8
  * DO NOT EDIT MANUALLY - run 'make specs' to regenerate.
9
9
  */
10
10
  import type { AppKind, AppSpec } from '../types/agentspecs';
11
+ export declare const DATA_QUALITY_APP_0_0_1: AppSpec;
11
12
  export declare const INBOX_TRIAGE_APP_0_0_1: AppSpec;
13
+ export declare const MODEL_CHOICE_APP_0_0_1: AppSpec;
12
14
  export declare const QUOTE_CALCULATOR_APP_0_0_1: AppSpec;
13
15
  export declare const SHIP_OR_FIX_APP_0_0_1: AppSpec;
16
+ export declare const SUPPLIER_COMPARISON_APP_0_0_1: AppSpec;
14
17
  export declare const WEB_RESEARCH_APP_0_0_1: AppSpec;
15
18
  export declare const APP_CATALOGUE: Record<string, AppSpec>;
16
19
  /** An application, by `id` or `id:version`, or undefined. */