@datalayer/agent-runtimes 1.5.26 → 1.5.28

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 (49) hide show
  1. package/dist-embed/chunks/{ChatView-CUWE6I5M.js → ChatView-C0PWJ_wj.js} +4 -4
  2. package/dist-embed/datalayer-app-main.js +111 -101
  3. package/lib/apps/apps/AppKept.js +5 -1
  4. package/lib/apps/embed/element.js +10 -4
  5. package/lib/apps/embed/embedConfig.d.ts +10 -1
  6. package/lib/apps/embed/embedConfig.js +25 -1
  7. package/lib/apps/plugins/chat/ChatView.js +2 -2
  8. package/lib/chat/assistant/AssistantStage.js +17 -0
  9. package/lib/chat/assistant/clearance.d.ts +10 -0
  10. package/lib/chat/assistant/clearance.js +14 -0
  11. package/lib/chat/base/ChatBase.js +375 -437
  12. package/lib/chat/base/conversationItems.d.ts +55 -0
  13. package/lib/chat/base/conversationItems.js +126 -0
  14. package/lib/portable/adapterEvents.d.ts +107 -0
  15. package/lib/portable/adapterEvents.js +239 -0
  16. package/lib/portable/approvalCard.d.ts +56 -0
  17. package/lib/portable/approvalCard.js +56 -0
  18. package/lib/portable/conversation.d.ts +71 -18
  19. package/lib/portable/conversation.js +330 -74
  20. package/lib/portable/fixtures.js +12 -0
  21. package/lib/portable/index.d.ts +4 -1
  22. package/lib/portable/index.js +7 -1
  23. package/lib/portable/presence.js +4 -1
  24. package/lib/portable/runMeasures.d.ts +46 -0
  25. package/lib/portable/runMeasures.js +156 -0
  26. package/lib/protocols/ACPAdapter.js +13 -8
  27. package/lib/specs/voices.js +47 -0
  28. package/lib/utils/utils.d.ts +2 -8
  29. package/lib/utils/utils.js +3 -26
  30. package/lib/voice/ComposerVoice.js +25 -3
  31. package/lib/voice/VoiceInput.d.ts +2 -2
  32. package/lib/voice/VoiceInput.js +6 -4
  33. package/lib/voice/VoiceMenu.js +2 -1
  34. package/lib/voice/chatVoice.d.ts +4 -3
  35. package/lib/voice/chatVoice.js +6 -9
  36. package/lib/voice/consent.d.ts +8 -0
  37. package/lib/voice/consent.js +10 -0
  38. package/lib/voice/hearing.d.ts +23 -1
  39. package/lib/voice/hearing.js +18 -3
  40. package/lib/voice/index.d.ts +11 -6
  41. package/lib/voice/index.js +1 -0
  42. package/lib/voice/serverHearing.d.ts +58 -0
  43. package/lib/voice/serverHearing.js +136 -0
  44. package/lib/voice/settings.d.ts +5 -0
  45. package/lib/voice/settings.js +8 -0
  46. package/lib/voice/speaker.d.ts +4 -3
  47. package/lib/voice/speaker.js +1 -2
  48. package/lib/voice/useVoiceSpeaker.js +0 -3
  49. package/package.json +2 -2
@@ -4,6 +4,7 @@ import { contribution, definePlugin, signal } from '@datalayer/reactor';
4
4
  import { useContributions, useSignalValue } from '@datalayer/reactor/react';
5
5
  import { LoopChatTurn, LoopPromptPanel } from '../core';
6
6
  import { beforeFirstMessage } from './kept';
7
+ import { ASSISTANT_CLEARANCE_VAR } from '../../chat/assistant/clearance';
7
8
  export const APP_KEPT_PLUGIN_NAME = '@datalayer/loop-plugin-app-kept';
8
9
  /* A signal to read when no chat contributed a turn: the hook needs one. */
9
10
  const NO_TURN = signal({ id: 0, status: 'idle' });
@@ -13,7 +14,10 @@ export function AppKept({ says }) {
13
14
  if (!beforeFirstMessage(turn)) {
14
15
  return null;
15
16
  }
16
- return (_jsx("div", { role: "note", style: { padding: '4px 8px' }, children: _jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: says }) }));
17
+ return (
18
+ // Clear of the floating assistant in its corner, at a phone's width too
19
+ // (REVIEWS Q-08).
20
+ _jsx("div", { role: "note", style: { padding: `4px var(${ASSISTANT_CLEARANCE_VAR}, 8px) 4px 8px` }, children: _jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: says }) }));
17
21
  }
18
22
  /**
19
23
  * The plugin, for one application: what it keeps, under its prompt. Made
@@ -70,7 +70,7 @@ import { parseAppspec } from '../apps/appspec';
70
70
  import { readAppspecYaml } from '../apps/yaml';
71
71
  import { AppEmbed, embedAssistantCharacter } from './AppEmbed';
72
72
  import { WINDOW_NOT_YET } from './embedSession';
73
- import { EMBED_HOST_VARIABLES, EMBED_OBSERVED_ATTRIBUTES, EMBED_TAG, EmbedAttributeError, adoptPropertiesSetEarly, embedLookOf, inlineHeightOf, languageOf, resumeOf, runnable, } from './embedConfig';
73
+ import { EMBED_HOST_VARIABLES, EMBED_OBSERVED_ATTRIBUTES, EMBED_TAG, EMBED_TOKEN_NAMES_NO_DEPLOYMENT, EmbedAttributeError, adoptPropertiesSetEarly, embedLookOf, embedTokenDeployment, inlineHeightOf, languageOf, resumeOf, runnable, } from './embedConfig';
74
74
  import { embedShadowCss } from './embedTheme';
75
75
  import { DEFAULT_API, readVisitorApp } from './visitorApp';
76
76
  export { runnable };
@@ -164,9 +164,15 @@ export async function readEmbeddedApp({ api, origin, app, token, fetcher = fetch
164
164
  return { kind: 'frame', src: frameSrcOf(origin, app, token) };
165
165
  }
166
166
  const spec = runnable(parseAppspec(definition.spec));
167
- return spec.kind === 'decision'
168
- ? { kind: 'frame', src: frameSrcOf(origin, app, token) }
169
- : { kind: 'spec', app: spec };
167
+ if (spec.kind === 'decision') {
168
+ return { kind: 'frame', src: frameSrcOf(origin, app, token) };
169
+ }
170
+ // The visit runs the deployment its token names, and no other (VOICE.md
171
+ // decision 16): a token naming none is refused before anything is drawn.
172
+ if (!embedTokenDeployment(token)) {
173
+ return { kind: 'said', text: EMBED_TOKEN_NAMES_NO_DEPLOYMENT };
174
+ }
175
+ return { kind: 'spec', app: spec };
170
176
  }
171
177
  /** The script that is running, when it is a script tag. */
172
178
  function currentScriptUrl() {
@@ -25,7 +25,7 @@ export declare const EMBED_STYLESHEET_PATH = "/embed/datalayer-app.css";
25
25
  export declare const EMBED_ATTRIBUTES: {
26
26
  readonly app: "The application’s id on Datalayer.";
27
27
  readonly origin: "Where Datalayer is; the origin the script was loaded from by default.";
28
- readonly token: "An embed token for an application that is not public, issued to your server for each visit.";
28
+ readonly token: "An embed token for an application that is not public, issued to your server for each visit; it names the embedded deployment the visit runs, which nothing else on the page names.";
29
29
  readonly spec: "The address of an Appspec (YAML or JSON) to run, in place of `app`.";
30
30
  readonly mode: "inline, bubble, panel or assistant; the Appspec’s `deployment.embedded.mode` by default, then inline.";
31
31
  readonly accent: "green, rose, sky, lime, sun or violet; the Appspec’s `interface.accent` by default, else the theme’s own colours.";
@@ -39,6 +39,15 @@ export declare const EMBED_ATTRIBUTES: {
39
39
  readonly 'user-token': "A token your server signed with the deployment’s secret, naming your user (HS256: sub, name, exp at most an hour away): what an application that says user: signed opens its session with.";
40
40
  };
41
41
  export type EmbedAttribute = keyof typeof EMBED_ATTRIBUTES;
42
+ /**
43
+ * The deployment an embed token names (VOICE.md decision 16): the embedded
44
+ * deployment its owner's server asked it for. Read without vouching for it —
45
+ * the services that take the token verify it — and the only place the
46
+ * element learns its deployment: it takes no attribute for one.
47
+ */
48
+ export declare function embedTokenDeployment(token: string): string | undefined;
49
+ /** What an embed token naming no deployment is told (VOICE.md decision 16). */
50
+ export declare const EMBED_TOKEN_NAMES_NO_DEPLOYMENT = "datalayer-app: the embed token names no deployment. Your server asks for one naming the application\u2019s embedded deployment: POST \u2026/api/spacer/v1/apps/<id>/embed-token with {\"deployment\": \"<its uid>\"}.";
42
51
  /** Every attribute the element watches. */
43
52
  export declare const EMBED_OBSERVED_ATTRIBUTES: EmbedAttribute[];
44
53
  /**
@@ -16,7 +16,7 @@ export const EMBED_STYLESHEET_PATH = '/embed/datalayer-app.css';
16
16
  export const EMBED_ATTRIBUTES = {
17
17
  app: 'The application’s id on Datalayer.',
18
18
  origin: 'Where Datalayer is; the origin the script was loaded from by default.',
19
- token: 'An embed token for an application that is not public, issued to your server for each visit.',
19
+ token: 'An embed token for an application that is not public, issued to your server for each visit; it names the embedded deployment the visit runs, which nothing else on the page names.',
20
20
  spec: 'The address of an Appspec (YAML or JSON) to run, in place of `app`.',
21
21
  mode: 'inline, bubble, panel or assistant; the Appspec’s `deployment.embedded.mode` by default, then inline.',
22
22
  accent: 'green, rose, sky, lime, sun or violet; the Appspec’s `interface.accent` by default, else the theme’s own colours.',
@@ -29,6 +29,30 @@ export const EMBED_ATTRIBUTES = {
29
29
  language: 'The language the visitor reads the application in, as BCP 47 tags it (fr, pt-BR): its translation into it, and the chat’s own words; the visitor’s browser’s by default.',
30
30
  'user-token': 'A token your server signed with the deployment’s secret, naming your user (HS256: sub, name, exp at most an hour away): what an application that says user: signed opens its session with.',
31
31
  };
32
+ /**
33
+ * The deployment an embed token names (VOICE.md decision 16): the embedded
34
+ * deployment its owner's server asked it for. Read without vouching for it —
35
+ * the services that take the token verify it — and the only place the
36
+ * element learns its deployment: it takes no attribute for one.
37
+ */
38
+ export function embedTokenDeployment(token) {
39
+ const payload = token.split('.')[1];
40
+ if (!payload) {
41
+ return undefined;
42
+ }
43
+ try {
44
+ const base64 = payload.replace(/-/g, '+').replace(/_/g, '/');
45
+ const claims = JSON.parse(atob(base64.padEnd(base64.length + ((4 - (base64.length % 4)) % 4), '=')));
46
+ return typeof claims.deployment_uid === 'string' && claims.deployment_uid
47
+ ? claims.deployment_uid
48
+ : undefined;
49
+ }
50
+ catch {
51
+ return undefined;
52
+ }
53
+ }
54
+ /** What an embed token naming no deployment is told (VOICE.md decision 16). */
55
+ export const EMBED_TOKEN_NAMES_NO_DEPLOYMENT = 'datalayer-app: the embed token names no deployment. Your server asks for one naming the application’s embedded deployment: POST …/api/spacer/v1/apps/<id>/embed-token with {"deployment": "<its uid>"}.';
32
56
  /** Every attribute the element watches. */
33
57
  export const EMBED_OBSERVED_ATTRIBUTES = Object.keys(EMBED_ATTRIBUTES);
34
58
  /**
@@ -1321,9 +1321,9 @@ export default function ChatView({ workspace }) {
1321
1321
  /*
1322
1322
  * Its voice asked of the speech service as this chat speaks to its runtime
1323
1323
  * (VOICE.md VO-37, VO-19): the host's token, else this one — a visitor's,
1324
- * an embed's or the person's — and the deployment it runs.
1324
+ * an embed's or the person's; an embed's names its deployment (decision 16).
1325
1325
  */
1326
- const askedVoice = useMemo(() => voiceAskedAs(config?.voice, iamToken || undefined, deploymentUid), [config?.voice, iamToken, deploymentUid]);
1326
+ const askedVoice = useMemo(() => voiceAskedAs(config?.voice, iamToken || undefined), [config?.voice, iamToken]);
1327
1327
  /*
1328
1328
  * A deployment's runtime, and the visitors', answer only the application's
1329
1329
  * own routes (OwnRoutesOnly, PAP_DATALAYER's release gates): its chat calls
@@ -7,6 +7,7 @@ import { Dialog, Text } from '@primer/react';
7
7
  import { assistantCharacter } from './characters';
8
8
  import { BalloonHistoryLarge, SpeechBalloon, } from './SpeechBalloon';
9
9
  import { conversationHeaderText } from './BalloonParts';
10
+ import { ASSISTANT_CLEARANCE_VAR } from './clearance';
10
11
  import { AssistantContextMenu, LONG_PRESS_MS, opensContextMenu, } from './AssistantContextMenu';
11
12
  import { BalloonExpandContext, ExpandedVisual, focusExpanded, } from './BalloonVisual';
12
13
  import { SpriteCharacter } from './SpriteCharacter';
@@ -405,6 +406,22 @@ export function AssistantStage({ character, state, size = 88, place, stageRef, o
405
406
  telling ||
406
407
  detailing !== null ||
407
408
  stayPut);
409
+ // What it covers in its corner, for a line written under a prompt there
410
+ // (REVIEWS Q-08).
411
+ const cornerRight = place.left === undefined && place.top === undefined
412
+ ? pixels(place.right)
413
+ : undefined;
414
+ const cornerBottom = pixels(place.bottom);
415
+ useEffect(() => {
416
+ if (aside || cornerRight === undefined || cornerBottom === undefined) {
417
+ return;
418
+ }
419
+ const root = document.documentElement;
420
+ root.style.setProperty(ASSISTANT_CLEARANCE_VAR, `${cornerRight + size}px`);
421
+ return () => {
422
+ root.style.removeProperty(ASSISTANT_CLEARANCE_VAR);
423
+ };
424
+ }, [aside, cornerRight, cornerBottom, size]);
408
425
  useMouth(stageRef, mouthLevel, state === 'speaking');
409
426
  // A decision being asked, or its answer, keeps the balloon up.
410
427
  const [deciding, setDeciding] = useState(false);
@@ -0,0 +1,10 @@
1
+ /**
2
+ * What the floating assistant covers from the right edge of the window while
3
+ * it stands in a bottom corner, as a CSS length on the document: a line
4
+ * written under a prompt there (what an application keeps, R-31) leaves it
5
+ * free, so that the character never stands over its words at a phone's width
6
+ * (REVIEWS Q-08). Unset when it stands anywhere else, steps aside or is gone.
7
+ *
8
+ * @module chat/assistant/clearance
9
+ */
10
+ export declare const ASSISTANT_CLEARANCE_VAR = "--assistant-clearance";
@@ -0,0 +1,14 @@
1
+ /*
2
+ * Copyright (c) 2025-2026 Datalayer, Inc.
3
+ * Distributed under the terms of the Modified BSD License.
4
+ */
5
+ /**
6
+ * What the floating assistant covers from the right edge of the window while
7
+ * it stands in a bottom corner, as a CSS length on the document: a line
8
+ * written under a prompt there (what an application keeps, R-31) leaves it
9
+ * free, so that the character never stands over its words at a phone's width
10
+ * (REVIEWS Q-08). Unset when it stands anywhere else, steps aside or is gone.
11
+ *
12
+ * @module chat/assistant/clearance
13
+ */
14
+ export const ASSISTANT_CLEARANCE_VAR = '--assistant-clearance';