@datalayer/agent-runtimes 1.5.53 → 1.5.55

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 (100) hide show
  1. package/dist-embed/chunks/ChatView-D4hFmYbm.js +32 -0
  2. package/dist-embed/chunks/{DeckComponent-C7AztSPA.js → DeckComponent-y0KZOMsH.js} +1 -1
  3. package/dist-embed/chunks/{DocumentView-DwpK2feQ.js → DocumentView-BKeO-v4k.js} +1 -1
  4. package/dist-embed/chunks/{EphemeralDocument-rusBlgBp.js → EphemeralDocument-BvbG68Jm.js} +1 -1
  5. package/dist-embed/chunks/{ExcalidrawComponent-Qv9LHutW.js → ExcalidrawComponent-DeNgg0ms.js} +1 -1
  6. package/dist-embed/chunks/{ExcalidrawModal-D6Mb9nmf.js → ExcalidrawModal-X6Yh6FKI.js} +1 -1
  7. package/dist-embed/chunks/{JupyterLexicalExtension-r47Jyrrd.js → JupyterLexicalExtension-Ght2bbbp.js} +5 -5
  8. package/dist-embed/chunks/{YouTubePlugin-4pUBJORX.js → YouTubePlugin-BnaV5Sxl.js} +1 -1
  9. package/dist-embed/chunks/{ar-SA-G6X2FPQ2-CD4X_3wm.js → ar-SA-G6X2FPQ2-DFML-KO4.js} +1 -1
  10. package/dist-embed/chunks/{az-AZ-76LH7QW2-oMbKQcB-.js → az-AZ-76LH7QW2-DTzTpRpk.js} +1 -1
  11. package/dist-embed/chunks/{bg-BG-XCXSNQG7-lSIB5dDU.js → bg-BG-XCXSNQG7-DMTmzgtc.js} +1 -1
  12. package/dist-embed/chunks/{bn-BD-2XOGV67Q-B5PkHAFO.js → bn-BD-2XOGV67Q-D1xy-Djm.js} +1 -1
  13. package/dist-embed/chunks/{ca-ES-6MX7JW3Y-BPeavtUl.js → ca-ES-6MX7JW3Y-hTO_csy7.js} +1 -1
  14. package/dist-embed/chunks/{cs-CZ-2BRQDIVT-DrBOFpi4.js → cs-CZ-2BRQDIVT-DBcXv81g.js} +1 -1
  15. package/dist-embed/chunks/{da-DK-5WZEPLOC-G5bUTE3Z.js → da-DK-5WZEPLOC-Rp51nhJX.js} +1 -1
  16. package/dist-embed/chunks/{de-DE-XR44H4JA-Drpt3qDZ.js → de-DE-XR44H4JA-DIgLamrP.js} +1 -1
  17. package/dist-embed/chunks/{el-GR-BZB4AONW-D4taPxaF.js → el-GR-BZB4AONW-XWt7TL7f.js} +1 -1
  18. package/dist-embed/chunks/{es-ES-U4NZUMDT-BvIGVphk.js → es-ES-U4NZUMDT-Bh1eks-u.js} +1 -1
  19. package/dist-embed/chunks/{eu-ES-A7QVB2H4-B8nvrNDk.js → eu-ES-A7QVB2H4-Bslg2HDc.js} +1 -1
  20. package/dist-embed/chunks/{fa-IR-HGAKTJCU-hwisHoU4.js → fa-IR-HGAKTJCU-9fGOejth.js} +1 -1
  21. package/dist-embed/chunks/{fi-FI-Z5N7JZ37-DKrDvTXs.js → fi-FI-Z5N7JZ37-DctXrD-R.js} +1 -1
  22. package/dist-embed/chunks/{fr-FR-RHASNOE6-DPtlBK_j.js → fr-FR-RHASNOE6-PUSl_g5c.js} +1 -1
  23. package/dist-embed/chunks/{gl-ES-HMX3MZ6V-B1ngwQkd.js → gl-ES-HMX3MZ6V-C5hGec18.js} +1 -1
  24. package/dist-embed/chunks/{he-IL-6SHJWFNN-BaoAQZ3f.js → he-IL-6SHJWFNN-rdU3Uatf.js} +1 -1
  25. package/dist-embed/chunks/{hi-IN-IWLTKZ5I-DzPeRmLM.js → hi-IN-IWLTKZ5I-CbVBP2OS.js} +1 -1
  26. package/dist-embed/chunks/{hu-HU-A5ZG7DT2-BgLcm8oA.js → hu-HU-A5ZG7DT2-BqNM3HXj.js} +1 -1
  27. package/dist-embed/chunks/{id-ID-SAP4L64H-egIA8l8_.js → id-ID-SAP4L64H-Z7074d-A.js} +1 -1
  28. package/dist-embed/chunks/{index-cYM4KfdD.js → index-2ciQBsIP.js} +1 -1
  29. package/dist-embed/chunks/{index-CkQ6IAoY.js → index-BIbnsdGY.js} +1 -1
  30. package/dist-embed/chunks/{index-Z2pxzg3H.js → index-BP84Dsqq.js} +1 -1
  31. package/dist-embed/chunks/{index-BzMt3uYX.js → index-BdQdhGo5.js} +1 -1
  32. package/dist-embed/chunks/{index-BKB97UwL.js → index-BpX_2Evh.js} +1 -1
  33. package/dist-embed/chunks/{index-CEbnhuIo.js → index-BrPjTG8-.js} +1 -1
  34. package/dist-embed/chunks/{index-Di3aBGLV.js → index-CAPuT1O_.js} +1 -1
  35. package/dist-embed/chunks/{index-5N0EOEHV.js → index-CC3OzP1C.js} +1 -1
  36. package/dist-embed/chunks/{index-D9_026K2.js → index-COWwWw7v.js} +1 -1
  37. package/dist-embed/chunks/{index-BTdq_niO.js → index-C_IEokTU.js} +1 -1
  38. package/dist-embed/chunks/{index-_H5U6gal.js → index-CalzGdbU.js} +1 -1
  39. package/dist-embed/chunks/{index-DVaPKQyL.js → index-CynaHotU.js} +1 -1
  40. package/dist-embed/chunks/{index-Cd5CgKFr.js → index-D4zET-qQ.js} +1 -1
  41. package/dist-embed/chunks/{index-BKOQQ5Ku.js → index-DJq5Nwi9.js} +1 -1
  42. package/dist-embed/chunks/{index-CZB8DyUw.js → index-Dx_VgK3b.js} +1 -1
  43. package/dist-embed/chunks/{index-BN8Bbau-.js → index-Dzf9vro3.js} +2 -2
  44. package/dist-embed/chunks/{index-DWfzdTZo.js → index-IGJ-OsCO.js} +1 -1
  45. package/dist-embed/chunks/{index-b6e3y1R-.js → index-mjwdOWLk.js} +1 -1
  46. package/dist-embed/chunks/{index-Gngo0bXi.js → index-wuTQQ7uK.js} +1 -1
  47. package/dist-embed/chunks/{index-CCRwowMu.js → index-zOsAyJ2Z.js} +1 -1
  48. package/dist-embed/chunks/{it-IT-JPQ66NNP-DDwc6pzw.js → it-IT-JPQ66NNP-CMr44eTw.js} +1 -1
  49. package/dist-embed/chunks/{ja-JP-DBVTYXUO-TrA2khDT.js → ja-JP-DBVTYXUO-DT0NU6hE.js} +1 -1
  50. package/dist-embed/chunks/{kaa-6HZHGXH3-GwFnOAIz.js → kaa-6HZHGXH3-C7H2NR4A.js} +1 -1
  51. package/dist-embed/chunks/{kab-KAB-ZGHBKWFO-xYS1Kjfb.js → kab-KAB-ZGHBKWFO-CNMStwQY.js} +1 -1
  52. package/dist-embed/chunks/{kk-KZ-P5N5QNE5-BwDJRk5I.js → kk-KZ-P5N5QNE5-D6IFMubV.js} +1 -1
  53. package/dist-embed/chunks/{km-KH-HSX4SM5Z-Di9J-9zc.js → km-KH-HSX4SM5Z-sh4HcGEj.js} +1 -1
  54. package/dist-embed/chunks/{ko-KR-MTYHY66A-BxF1Locw.js → ko-KR-MTYHY66A-Bgk5LE7Q.js} +1 -1
  55. package/dist-embed/chunks/{ku-TR-6OUDTVRD-mGflwIcv.js → ku-TR-6OUDTVRD-CoM0o1jW.js} +1 -1
  56. package/dist-embed/chunks/{lt-LT-XHIRWOB4-DWluphZ2.js → lt-LT-XHIRWOB4-1uHPL6b-.js} +1 -1
  57. package/dist-embed/chunks/{lv-LV-5QDEKY6T-D9EEzVQ9.js → lv-LV-5QDEKY6T-DYKbCrq6.js} +1 -1
  58. package/dist-embed/chunks/{mr-IN-CRQNXWMA-DoMvP_Jp.js → mr-IN-CRQNXWMA-C7qlI0yH.js} +1 -1
  59. package/dist-embed/chunks/{my-MM-5M5IBNSE-CPPbx93K.js → my-MM-5M5IBNSE-BWSQ_5V3.js} +1 -1
  60. package/dist-embed/chunks/{nb-NO-T6EIAALU-m2hgNNww.js → nb-NO-T6EIAALU-BVQfX-Pe.js} +1 -1
  61. package/dist-embed/chunks/{nl-NL-IS3SIHDZ-B809T0Iy.js → nl-NL-IS3SIHDZ-BXjyEe9g.js} +1 -1
  62. package/dist-embed/chunks/{nn-NO-6E72VCQL-DcMxKEVg.js → nn-NO-6E72VCQL-3eaL8woM.js} +1 -1
  63. package/dist-embed/chunks/{oc-FR-POXYY2M6-BZTBaY64.js → oc-FR-POXYY2M6-CDqoITm8.js} +1 -1
  64. package/dist-embed/chunks/{pa-IN-N4M65BXN-Cs4i3fnS.js → pa-IN-N4M65BXN-CoKaIMNa.js} +1 -1
  65. package/dist-embed/chunks/{percentages-BXMCSKIN-D82iCuEy.js → percentages-BXMCSKIN-X4aF_7zv.js} +3 -3
  66. package/dist-embed/chunks/{pl-PL-T2D74RX3-B3jg7qOY.js → pl-PL-T2D74RX3-DDD5SgtT.js} +1 -1
  67. package/dist-embed/chunks/{pt-BR-5N22H2LF-aCJuloaY.js → pt-BR-5N22H2LF-BIIRVQqv.js} +1 -1
  68. package/dist-embed/chunks/{pt-PT-UZXXM6DQ-8ZZdQp1P.js → pt-PT-UZXXM6DQ-HB1n3nNc.js} +1 -1
  69. package/dist-embed/chunks/{ro-RO-JPDTUUEW-BmyO5zyl.js → ro-RO-JPDTUUEW-CDxFIF2P.js} +1 -1
  70. package/dist-embed/chunks/{ru-RU-B4JR7IUQ-BneR_2Bm.js → ru-RU-B4JR7IUQ-CM2wpzEh.js} +1 -1
  71. package/dist-embed/chunks/{si-LK-N5RQ5JYF-CDB0IyVm.js → si-LK-N5RQ5JYF-u_f-pZ4T.js} +1 -1
  72. package/dist-embed/chunks/{sk-SK-C5VTKIMK-ypZmPMe_.js → sk-SK-C5VTKIMK-1MdhriDY.js} +1 -1
  73. package/dist-embed/chunks/{sl-SI-NN7IZMDC-D9OrZXr7.js → sl-SI-NN7IZMDC-BtkaEwYy.js} +1 -1
  74. package/dist-embed/chunks/{subset-shared.chunk-cQajIUFT.js → subset-shared.chunk-Ca3xPoZL.js} +1 -1
  75. package/dist-embed/chunks/{subset-worker.chunk-DEC9qaDu.js → subset-worker.chunk-CEgJtfh9.js} +1 -1
  76. package/dist-embed/chunks/{sv-SE-XGPEYMSR-CXBRqMMZ.js → sv-SE-XGPEYMSR-CX9l-s8b.js} +1 -1
  77. package/dist-embed/chunks/{ta-IN-2NMHFXQM-BuB9HEjH.js → ta-IN-2NMHFXQM-Bs3QMZdy.js} +1 -1
  78. package/dist-embed/chunks/{th-TH-HPSO5L25-Ci7wR5dZ.js → th-TH-HPSO5L25-yCfu_zLh.js} +1 -1
  79. package/dist-embed/chunks/{tr-TR-DEFEU3FU-CEJUT8zN.js → tr-TR-DEFEU3FU-PnpIJqSm.js} +1 -1
  80. package/dist-embed/chunks/{uk-UA-QMV73CPH-Ceh5JIiD.js → uk-UA-QMV73CPH--aODafpt.js} +1 -1
  81. package/dist-embed/chunks/{url-DuKx0yk0.js → url-CzjbCo42.js} +1 -1
  82. package/dist-embed/chunks/{vi-VN-M7AON7JQ-8-R9Ohxp.js → vi-VN-M7AON7JQ-BruA8Fg-.js} +1 -1
  83. package/dist-embed/chunks/{zh-CN-LNUGB5OW-D4q5wqKm.js → zh-CN-LNUGB5OW-DtbH5pJi.js} +1 -1
  84. package/dist-embed/chunks/{zh-HK-E62DVLB3-_UiIVKpk.js → zh-HK-E62DVLB3-CPacR6Re.js} +1 -1
  85. package/dist-embed/chunks/{zh-TW-RAJ6MFWO-DyXZ-PXI.js → zh-TW-RAJ6MFWO-CImbtPSf.js} +1 -1
  86. package/dist-embed/datalayer-app-main.js +86 -86
  87. package/lib/apps/core/index.d.ts +11 -0
  88. package/lib/apps/plugins/app-rules/AppRulesCard.d.ts +6 -0
  89. package/lib/apps/plugins/app-rules/AppRulesCard.js +9 -1
  90. package/lib/apps/plugins/chat/ChatView.js +18 -3
  91. package/lib/apps/shell/LoopWorkspace.js +8 -0
  92. package/lib/portable/hosts/contracts.json +30 -0
  93. package/lib/specs/agents/agents.d.ts +6 -0
  94. package/lib/specs/agents/agents.js +294 -0
  95. package/lib/voice/HandsFree.js +11 -1
  96. package/lib/voice/VoiceInput.js +10 -2
  97. package/lib/voice/handsFree.d.ts +4 -2
  98. package/lib/voice/handsFree.js +4 -2
  99. package/package.json +1 -1
  100. package/dist-embed/chunks/ChatView-CRp8Mt57.js +0 -32
@@ -144,6 +144,17 @@ export type LoopWorkspaceContext = {
144
144
  setAgentId: (agentId: string) => void;
145
145
  /** Conversation being continued, when there is one. */
146
146
  conversationId?: string;
147
+ /**
148
+ * The thread the chat last sent on, once it has sent: an application's
149
+ * thread is its session on the runtime, so what reads a running session —
150
+ * the Rules card's *This session* (SH-54) — reads it here. Without it a
151
+ * workspace whose host named no conversation never knew its session, and
152
+ * the card said *Start a conversation* after one had started (16 October
153
+ * 2026).
154
+ */
155
+ thread?: string;
156
+ /** For the chat to say which thread it sends on. */
157
+ setThread?: (thread: string) => void;
147
158
  /**
148
159
  * The id the notebook and the document on screen are addressed by.
149
160
  *
@@ -61,6 +61,12 @@ export declare function SessionRules({ agentServerUrl, sessionUid, token, }: {
61
61
  sessionUid: string;
62
62
  token: string;
63
63
  }): JSX.Element;
64
+ /**
65
+ * The running session the card tightens: the conversation the host
66
+ * continued, else the thread the chat sent on — an application's thread is
67
+ * its session on the runtime. None before a message is sent.
68
+ */
69
+ export declare function sessionUidOf(workspace?: Pick<LoopWorkspaceContext, 'conversationId' | 'thread'>): string | undefined;
64
70
  export declare function AppRulesCard({ app, workspace, }: {
65
71
  app: AppSpec;
66
72
  /** The workspace the card sits in, when the slot gives it: names the session running. */
@@ -107,13 +107,21 @@ export function SessionRules({ agentServerUrl, sessionUid, token, }) {
107
107
  };
108
108
  return (_jsxs(Box, { "data-testid": "session-rules", mt: 3, children: [_jsx(Heading, { as: "h4", sx: { fontSize: 1, mb: 1 }, children: SESSION_RULES_WORDS.title }), inForce?.unavailable ? (_jsx(Text, { as: "p", role: "alert", sx: { fontSize: 0, m: 0, mb: 1 }, children: SESSION_RULES_WORDS.unavailable(inForce.unavailable) })) : null, inForce && inForce.session_rules.length === 0 ? (_jsx(Text, { as: "p", sx: { fontSize: 1, color: 'fg.muted', m: 0 }, children: SESSION_RULES_WORDS.none })) : (_jsx(Box, { as: "ul", listStyle: "none", p: 0, m: 0, children: (inForce?.session_rules ?? []).map(rule => (_jsxs(Box, { as: "li", py: 1, fontSize: 1, display: "flex", gap: 2, alignItems: "center", children: [_jsx(Text, { sx: { fontWeight: 'semibold' }, children: rule.name }), _jsx(Text, { sx: { color: 'fg.muted', fontSize: 0 }, children: sessionRuleInWords(rule) }), _jsx(Button, { size: "small", variant: "invisible", disabled: busy, onClick: () => void act(() => removeSessionRule(agentServerUrl, token, sessionUid, rule.name)), children: SESSION_RULES_WORDS.remove })] }, rule.name))) })), _jsxs(Box, { display: "flex", gap: 1, mt: 1, flexWrap: "wrap", alignItems: "center", children: [_jsx(TextInput, { size: "small", value: name, placeholder: SESSION_RULES_WORDS.namePlaceholder, "aria-label": "The rule's name", onChange: event => setName(event.target.value) }), _jsx(Select, { size: "small", value: kind, "aria-label": "What it covers", onChange: event => setKind(event.target.value), children: SESSION_RULE_CLASSES.map(item => (_jsx(Select.Option, { value: item, children: SESSION_RULES_WORDS.classes[item] }, item))) }), _jsx(Select, { size: "small", value: decision, "aria-label": "What it says", onChange: event => setDecision(event.target.value), children: SESSION_RULE_DECISIONS.map(item => (_jsx(Select.Option, { value: item, children: SESSION_RULES_WORDS.decisions[item] }, item))) }), _jsx(Button, { size: "small", disabled: busy, onClick: add, children: SESSION_RULES_WORDS.add })] }), _jsx(Box, { display: "flex", gap: 1, mt: 1, flexWrap: "wrap", "data-testid": "session-rules-file-and-shell", children: FILE_AND_SHELL_RULES.map(rule => (_jsx(Button, { size: "small", variant: "invisible", disabled: busy, title: sessionRuleInWords(rule), onClick: () => void act(() => addSessionRule(agentServerUrl, token, sessionUid, rule)), children: rule.name }, rule.name))) }), problem ? (_jsx(Text, { as: "p", role: "alert", sx: { fontSize: 0, m: 0, mt: 1 }, children: problem })) : null, _jsx(Text, { as: "p", sx: { fontSize: 0, color: 'fg.muted', mt: 1, mb: 0 }, children: SESSION_RULES_WORDS.goneWithSession })] }));
109
109
  }
110
+ /**
111
+ * The running session the card tightens: the conversation the host
112
+ * continued, else the thread the chat sent on — an application's thread is
113
+ * its session on the runtime. None before a message is sent.
114
+ */
115
+ export function sessionUidOf(workspace) {
116
+ return workspace?.conversationId || workspace?.thread || undefined;
117
+ }
110
118
  export function AppRulesCard({ app, workspace, }) {
111
119
  const token = useIAMStore(state => state.token) ?? '';
112
120
  const signedIn = Boolean(token);
113
121
  const agentServerUrl = workspace
114
122
  ? agentServerOf(workspace.sandbox, workspace.serverUrl)
115
123
  : undefined;
116
- const sessionUid = workspace?.conversationId;
124
+ const sessionUid = sessionUidOf(workspace);
117
125
  return (_jsxs(Box, { "data-testid": "app-rules", mb: 4, children: [_jsx(Heading, { as: "h3", sx: { fontSize: 2, mb: 2 }, children: APP_RULES_WORDS.title }), app.rules.length === 0 ? (_jsx(Text, { as: "p", sx: { fontSize: 1, color: 'fg.muted', m: 0 }, children: APP_RULES_WORDS.none })) : (_jsx(Box, { as: "ul", listStyle: "none", p: 0, m: 0, children: app.rules.map(ruleInWords).map((rule, index) => (_jsxs(Box, { as: "li", py: 1, fontSize: 1, children: [_jsx(Text, { children: rule.action }), ' ', _jsx(Label, { title: rule.means, children: rule.says }), _jsx(Text, { as: "p", sx: { m: 0, color: 'fg.muted', fontSize: 0 }, children: rule.covers })] }, index))) })), _jsx(Text, { as: "p", sx: { fontSize: 0, color: 'fg.muted', mt: 1, mb: 0 }, children: APP_RULES_WORDS.byDefault }), signedIn ? (_jsx(Approvals, { app: app })) : (_jsx(Text, { as: "p", sx: { fontSize: 1, color: 'fg.muted', mt: 3, mb: 0 }, children: APP_RULES_WORDS.signedOut })), signedIn && agentServerUrl ? (sessionUid ? (_jsx(SessionRules, { agentServerUrl: agentServerUrl, sessionUid: sessionUid, token: token })) : (_jsx(Text, { as: "p", sx: { fontSize: 0, color: 'fg.muted', mt: 3, mb: 0 }, children: SESSION_RULES_WORDS.noSession }))) : null] }));
118
126
  }
119
127
  export default AppRulesCard;
@@ -80,6 +80,20 @@ export default function ChatView({ workspace }) {
80
80
  const palette = useColorPalette();
81
81
  const controlsRef = useRef(null);
82
82
  const { setViewControls } = workspace;
83
+ /*
84
+ * Say the thread a message goes on to the workspace: an application's
85
+ * thread is its session on the runtime, which the Rules card's *This
86
+ * session* reads (SH-54). Through a ref, as the senders below are built once.
87
+ */
88
+ const setThreadRef = useRef(workspace.setThread);
89
+ setThreadRef.current = workspace.setThread;
90
+ const sayThread = useCallback(() => {
91
+ const thread = controlsRef.current?.thread();
92
+ if (thread) {
93
+ setThreadRef.current?.(thread);
94
+ }
95
+ return thread;
96
+ }, []);
83
97
  const [transient, setTransient] = useState(null);
84
98
  // Read from the reactor rather than taken as a prop: the placeholder and the
85
99
  // default editor are the chat plugin's own configuration, so a host sets them
@@ -440,14 +454,14 @@ export default function ChatView({ workspace }) {
440
454
  return;
441
455
  }
442
456
  // A new turn: whatever the panel showed is gone, this message is it.
443
- turnFeedRef.current?.begin(message, controlsRef.current?.thread());
457
+ turnFeedRef.current?.begin(message, sayThread());
444
458
  const send = controlsRef.current?.send;
445
459
  if (!send) {
446
460
  heldForAdapter.current.push([message, forwardedProps]);
447
461
  return;
448
462
  }
449
463
  send(message, forwardedProps);
450
- }, []);
464
+ }, [sayThread]);
451
465
  // One writer, so neither fact can erase the other.
452
466
  useEffect(() => {
453
467
  setViewControls(sendReady
@@ -481,9 +495,10 @@ export default function ChatView({ workspace }) {
481
495
  }
482
496
  const held = heldForAdapter.current.splice(0, heldForAdapter.current.length);
483
497
  for (const [message, forwardedProps] of held) {
498
+ sayThread();
484
499
  controlsRef.current?.send(message, forwardedProps);
485
500
  }
486
- }, [sendReady]);
501
+ }, [sendReady, sayThread]);
487
502
  /*
488
503
  * Fired once, on the first real send, for the life of this mounted chat —
489
504
  * a ref rather than a signal, because nothing here needs to re-render when
@@ -45,6 +45,11 @@ function WorkspaceBody({ serverUrl, agentId: initialAgentId, conversationId, mod
45
45
  useEffect(() => {
46
46
  setAgentId(initialAgentId);
47
47
  }, [initialAgentId]);
48
+ // The thread the chat sends on, said by the chat (its session, SH-54).
49
+ const [thread, setThreadState] = useState(undefined);
50
+ const setThread = useCallback((next) => {
51
+ setThreadState(current => (current === next ? current : next));
52
+ }, []);
48
53
  const [activeViewType, setActiveViewType] = useState(initialViewType ?? '');
49
54
  // Seeded by the host (a handoff carries what the terminal knew), then kept
50
55
  // current by whichever plugin owns the sandbox.
@@ -109,6 +114,8 @@ function WorkspaceBody({ serverUrl, agentId: initialAgentId, conversationId, mod
109
114
  surfaceId: surfaceIdRef.current,
110
115
  setAgentId,
111
116
  conversationId,
117
+ thread,
118
+ setThread,
112
119
  model,
113
120
  sandbox,
114
121
  setSandbox,
@@ -124,6 +131,7 @@ function WorkspaceBody({ serverUrl, agentId: initialAgentId, conversationId, mod
124
131
  serverUrl,
125
132
  agentId,
126
133
  conversationId,
134
+ thread,
127
135
  model,
128
136
  sandbox,
129
137
  activeViewType,
@@ -125,6 +125,35 @@
125
125
  "expires_in"
126
126
  ]
127
127
  },
128
+ "bind_session": {
129
+ "about": "The host maps a session it opened to a place of its own, with the host token it opened it with and its host key: binding it again replaces the target. The target is opaque to ai-agents (a JSON object of at most target_limit characters) and is handed back with every delivery of that session.",
130
+ "request": {
131
+ "target": {
132
+ "appId": "A0",
133
+ "channelId": "C0",
134
+ "teamId": "T0",
135
+ "threadTs": "1700000000.000001",
136
+ "userId": "U0ALICE"
137
+ }
138
+ },
139
+ "session_uid_pattern": "^[A-Za-z0-9_-]{8,128}$",
140
+ "target_limit": 2048,
141
+ "response_keys": [
142
+ "success",
143
+ "binding"
144
+ ],
145
+ "binding_keys": [
146
+ "uid",
147
+ "host_uid",
148
+ "session_uid",
149
+ "deployment_uid",
150
+ "agent_id",
151
+ "link_uid",
152
+ "principal_uid",
153
+ "target",
154
+ "state"
155
+ ]
156
+ },
128
157
  "external_turn": {
129
158
  "start_request": {
130
159
  "agent": "agent-desk",
@@ -142,6 +171,7 @@
142
171
  "type": "CUSTOM",
143
172
  "name": "loop.turn",
144
173
  "value_keys": [
174
+ "session",
145
175
  "turn",
146
176
  "external_event_id",
147
177
  "replayed",
@@ -42,6 +42,12 @@ export declare const EXAMPLE_GPT_AND_CLAUDE_COLLABORATE_AGENTSPEC_0_0_1: Agentsp
42
42
  export declare const EXAMPLE_GUARDRAILS_AGENTSPEC_0_0_1: Agentspec;
43
43
  export declare const EXAMPLE_HAIKU_GENERATIVE_UI_AGENTSPEC_0_0_1: Agentspec;
44
44
  export declare const EXAMPLE_HARNESS_CLAUDE_CODE_AGENTSPEC_0_0_1: Agentspec;
45
+ export declare const EXAMPLE_HARNESS_CODEX_AGENTSPEC_0_0_1: Agentspec;
46
+ export declare const EXAMPLE_HARNESS_FAST_AGENT_SPEC_0_0_1: Agentspec;
47
+ export declare const EXAMPLE_HARNESS_GEMINI_CLI_AGENTSPEC_0_0_1: Agentspec;
48
+ export declare const EXAMPLE_HARNESS_GOOSE_AGENTSPEC_0_0_1: Agentspec;
49
+ export declare const EXAMPLE_HARNESS_OPENCODE_AGENTSPEC_0_0_1: Agentspec;
50
+ export declare const EXAMPLE_HARNESS_OPENHANDS_AGENTSPEC_0_0_1: Agentspec;
45
51
  export declare const EXAMPLE_HOOKS_AGENTSPEC_0_0_1: Agentspec;
46
52
  export declare const EXAMPLE_HUMAN_APPROVED_AUTOMATION_AGENTSPEC_0_0_1: Agentspec;
47
53
  export declare const EXAMPLE_HUMAN_IN_THE_LOOP_AGENTSPEC_0_0_1: Agentspec;
@@ -2630,6 +2630,294 @@ export const EXAMPLE_HARNESS_CLAUDE_CODE_AGENTSPEC_0_0_1 = {
2630
2630
  parameters: undefined,
2631
2631
  subagents: undefined,
2632
2632
  };
2633
+ export const EXAMPLE_HARNESS_CODEX_AGENTSPEC_0_0_1 = {
2634
+ id: 'example-harness-codex',
2635
+ version: '0.0.1',
2636
+ name: 'A Codex Agent',
2637
+ description: `OpenAI's Codex as a Datalayer agent: launched in the runtime over the Agent Client Protocol, its files, terminals and permissions decided by the Shield under the application's Rules, every action in the record. Needs the account's OPENAI_API_KEY.`,
2638
+ tags: ['coding', 'harness', 'acp'],
2639
+ domain: undefined,
2640
+ enabled: false,
2641
+ model: undefined,
2642
+ mcpServers: [],
2643
+ skills: [].filter(Boolean),
2644
+ backendTools: [],
2645
+ frontendTools: [],
2646
+ environmentName: 'ai-agents-env',
2647
+ icon: undefined,
2648
+ emoji: undefined,
2649
+ color: undefined,
2650
+ suggestions: [],
2651
+ welcomeMessage: undefined,
2652
+ welcomeNotebook: undefined,
2653
+ welcomeDocument: undefined,
2654
+ sandboxVariant: 'jupyter-server',
2655
+ harness: 'codex',
2656
+ systemPrompt: undefined,
2657
+ systemPromptCodemodeAddons: undefined,
2658
+ goal: undefined,
2659
+ delegable: [],
2660
+ protocol: undefined,
2661
+ ui: [],
2662
+ protocols: [],
2663
+ trigger: undefined,
2664
+ modelConfig: undefined,
2665
+ mcpServerTools: undefined,
2666
+ guardrails: undefined,
2667
+ evals: undefined,
2668
+ codemode: undefined,
2669
+ output: undefined,
2670
+ advanced: undefined,
2671
+ checkpoints: undefined,
2672
+ authorizationPolicy: undefined,
2673
+ notifications: undefined,
2674
+ memory: 'ephemeral',
2675
+ preHooks: undefined,
2676
+ postHooks: undefined,
2677
+ toolHooks: undefined,
2678
+ parameters: undefined,
2679
+ subagents: undefined,
2680
+ };
2681
+ export const EXAMPLE_HARNESS_FAST_AGENT_SPEC_0_0_1 = {
2682
+ id: 'example-harness-fast-agent',
2683
+ version: '0.0.1',
2684
+ name: 'A fast-agent Agent',
2685
+ description: `fast-agent as a Datalayer agent: launched in the runtime over the Agent Client Protocol, its files, terminals and permissions decided by the Shield under the application's Rules, every action in the record. Needs the account's ANTHROPIC_API_KEY.`,
2686
+ tags: ['coding', 'harness', 'acp'],
2687
+ domain: undefined,
2688
+ enabled: false,
2689
+ model: undefined,
2690
+ mcpServers: [],
2691
+ skills: [].filter(Boolean),
2692
+ backendTools: [],
2693
+ frontendTools: [],
2694
+ environmentName: 'ai-agents-env',
2695
+ icon: undefined,
2696
+ emoji: undefined,
2697
+ color: undefined,
2698
+ suggestions: [],
2699
+ welcomeMessage: undefined,
2700
+ welcomeNotebook: undefined,
2701
+ welcomeDocument: undefined,
2702
+ sandboxVariant: 'jupyter-server',
2703
+ harness: 'fast-agent',
2704
+ systemPrompt: undefined,
2705
+ systemPromptCodemodeAddons: undefined,
2706
+ goal: undefined,
2707
+ delegable: [],
2708
+ protocol: undefined,
2709
+ ui: [],
2710
+ protocols: [],
2711
+ trigger: undefined,
2712
+ modelConfig: undefined,
2713
+ mcpServerTools: undefined,
2714
+ guardrails: undefined,
2715
+ evals: undefined,
2716
+ codemode: undefined,
2717
+ output: undefined,
2718
+ advanced: undefined,
2719
+ checkpoints: undefined,
2720
+ authorizationPolicy: undefined,
2721
+ notifications: undefined,
2722
+ memory: 'ephemeral',
2723
+ preHooks: undefined,
2724
+ postHooks: undefined,
2725
+ toolHooks: undefined,
2726
+ parameters: undefined,
2727
+ subagents: undefined,
2728
+ };
2729
+ export const EXAMPLE_HARNESS_GEMINI_CLI_AGENTSPEC_0_0_1 = {
2730
+ id: 'example-harness-gemini-cli',
2731
+ version: '0.0.1',
2732
+ name: 'A Gemini CLI Agent',
2733
+ description: `Google's Gemini CLI as a Datalayer agent: launched in the runtime over the Agent Client Protocol, its files, terminals and permissions decided by the Shield under the application's Rules, every action in the record. Needs the account's GEMINI_API_KEY.`,
2734
+ tags: ['coding', 'harness', 'acp'],
2735
+ domain: undefined,
2736
+ enabled: false,
2737
+ model: undefined,
2738
+ mcpServers: [],
2739
+ skills: [].filter(Boolean),
2740
+ backendTools: [],
2741
+ frontendTools: [],
2742
+ environmentName: 'ai-agents-env',
2743
+ icon: undefined,
2744
+ emoji: undefined,
2745
+ color: undefined,
2746
+ suggestions: [],
2747
+ welcomeMessage: undefined,
2748
+ welcomeNotebook: undefined,
2749
+ welcomeDocument: undefined,
2750
+ sandboxVariant: 'jupyter-server',
2751
+ harness: 'gemini-cli',
2752
+ systemPrompt: undefined,
2753
+ systemPromptCodemodeAddons: undefined,
2754
+ goal: undefined,
2755
+ delegable: [],
2756
+ protocol: undefined,
2757
+ ui: [],
2758
+ protocols: [],
2759
+ trigger: undefined,
2760
+ modelConfig: undefined,
2761
+ mcpServerTools: undefined,
2762
+ guardrails: undefined,
2763
+ evals: undefined,
2764
+ codemode: undefined,
2765
+ output: undefined,
2766
+ advanced: undefined,
2767
+ checkpoints: undefined,
2768
+ authorizationPolicy: undefined,
2769
+ notifications: undefined,
2770
+ memory: 'ephemeral',
2771
+ preHooks: undefined,
2772
+ postHooks: undefined,
2773
+ toolHooks: undefined,
2774
+ parameters: undefined,
2775
+ subagents: undefined,
2776
+ };
2777
+ export const EXAMPLE_HARNESS_GOOSE_AGENTSPEC_0_0_1 = {
2778
+ id: 'example-harness-goose',
2779
+ version: '0.0.1',
2780
+ name: 'A goose Agent',
2781
+ description: `goose as a Datalayer agent: launched in the runtime over the Agent Client Protocol, its files, terminals and permissions decided by the Shield under the application's Rules, every action in the record. Needs the account's ANTHROPIC_API_KEY.`,
2782
+ tags: ['coding', 'harness', 'acp'],
2783
+ domain: undefined,
2784
+ enabled: false,
2785
+ model: undefined,
2786
+ mcpServers: [],
2787
+ skills: [].filter(Boolean),
2788
+ backendTools: [],
2789
+ frontendTools: [],
2790
+ environmentName: 'ai-agents-env',
2791
+ icon: undefined,
2792
+ emoji: undefined,
2793
+ color: undefined,
2794
+ suggestions: [],
2795
+ welcomeMessage: undefined,
2796
+ welcomeNotebook: undefined,
2797
+ welcomeDocument: undefined,
2798
+ sandboxVariant: 'jupyter-server',
2799
+ harness: 'goose',
2800
+ systemPrompt: undefined,
2801
+ systemPromptCodemodeAddons: undefined,
2802
+ goal: undefined,
2803
+ delegable: [],
2804
+ protocol: undefined,
2805
+ ui: [],
2806
+ protocols: [],
2807
+ trigger: undefined,
2808
+ modelConfig: undefined,
2809
+ mcpServerTools: undefined,
2810
+ guardrails: undefined,
2811
+ evals: undefined,
2812
+ codemode: undefined,
2813
+ output: undefined,
2814
+ advanced: undefined,
2815
+ checkpoints: undefined,
2816
+ authorizationPolicy: undefined,
2817
+ notifications: undefined,
2818
+ memory: 'ephemeral',
2819
+ preHooks: undefined,
2820
+ postHooks: undefined,
2821
+ toolHooks: undefined,
2822
+ parameters: undefined,
2823
+ subagents: undefined,
2824
+ };
2825
+ export const EXAMPLE_HARNESS_OPENCODE_AGENTSPEC_0_0_1 = {
2826
+ id: 'example-harness-opencode',
2827
+ version: '0.0.1',
2828
+ name: 'An OpenCode Agent',
2829
+ description: `OpenCode as a Datalayer agent: launched in the runtime over the Agent Client Protocol, its files, terminals and permissions decided by the Shield under the application's Rules, every action in the record. Needs the account's ANTHROPIC_API_KEY.`,
2830
+ tags: ['coding', 'harness', 'acp'],
2831
+ domain: undefined,
2832
+ enabled: false,
2833
+ model: undefined,
2834
+ mcpServers: [],
2835
+ skills: [].filter(Boolean),
2836
+ backendTools: [],
2837
+ frontendTools: [],
2838
+ environmentName: 'ai-agents-env',
2839
+ icon: undefined,
2840
+ emoji: undefined,
2841
+ color: undefined,
2842
+ suggestions: [],
2843
+ welcomeMessage: undefined,
2844
+ welcomeNotebook: undefined,
2845
+ welcomeDocument: undefined,
2846
+ sandboxVariant: 'jupyter-server',
2847
+ harness: 'opencode',
2848
+ systemPrompt: undefined,
2849
+ systemPromptCodemodeAddons: undefined,
2850
+ goal: undefined,
2851
+ delegable: [],
2852
+ protocol: undefined,
2853
+ ui: [],
2854
+ protocols: [],
2855
+ trigger: undefined,
2856
+ modelConfig: undefined,
2857
+ mcpServerTools: undefined,
2858
+ guardrails: undefined,
2859
+ evals: undefined,
2860
+ codemode: undefined,
2861
+ output: undefined,
2862
+ advanced: undefined,
2863
+ checkpoints: undefined,
2864
+ authorizationPolicy: undefined,
2865
+ notifications: undefined,
2866
+ memory: 'ephemeral',
2867
+ preHooks: undefined,
2868
+ postHooks: undefined,
2869
+ toolHooks: undefined,
2870
+ parameters: undefined,
2871
+ subagents: undefined,
2872
+ };
2873
+ export const EXAMPLE_HARNESS_OPENHANDS_AGENTSPEC_0_0_1 = {
2874
+ id: 'example-harness-openhands',
2875
+ version: '0.0.1',
2876
+ name: 'An OpenHands Agent',
2877
+ description: `The OpenHands CLI as a Datalayer agent: launched in the runtime over the Agent Client Protocol, its files, terminals and permissions decided by the Shield under the application's Rules, every action in the record. Needs the account's LLM_API_KEY.`,
2878
+ tags: ['coding', 'harness', 'acp'],
2879
+ domain: undefined,
2880
+ enabled: false,
2881
+ model: undefined,
2882
+ mcpServers: [],
2883
+ skills: [].filter(Boolean),
2884
+ backendTools: [],
2885
+ frontendTools: [],
2886
+ environmentName: 'ai-agents-env',
2887
+ icon: undefined,
2888
+ emoji: undefined,
2889
+ color: undefined,
2890
+ suggestions: [],
2891
+ welcomeMessage: undefined,
2892
+ welcomeNotebook: undefined,
2893
+ welcomeDocument: undefined,
2894
+ sandboxVariant: 'jupyter-server',
2895
+ harness: 'openhands',
2896
+ systemPrompt: undefined,
2897
+ systemPromptCodemodeAddons: undefined,
2898
+ goal: undefined,
2899
+ delegable: [],
2900
+ protocol: undefined,
2901
+ ui: [],
2902
+ protocols: [],
2903
+ trigger: undefined,
2904
+ modelConfig: undefined,
2905
+ mcpServerTools: undefined,
2906
+ guardrails: undefined,
2907
+ evals: undefined,
2908
+ codemode: undefined,
2909
+ output: undefined,
2910
+ advanced: undefined,
2911
+ checkpoints: undefined,
2912
+ authorizationPolicy: undefined,
2913
+ notifications: undefined,
2914
+ memory: 'ephemeral',
2915
+ preHooks: undefined,
2916
+ postHooks: undefined,
2917
+ toolHooks: undefined,
2918
+ parameters: undefined,
2919
+ subagents: undefined,
2920
+ };
2633
2921
  export const EXAMPLE_HOOKS_AGENTSPEC_0_0_1 = {
2634
2922
  id: 'example-hooks',
2635
2923
  version: '0.0.1',
@@ -13563,6 +13851,12 @@ export const AGENTSPECS = {
13563
13851
  'example-guardrails': EXAMPLE_GUARDRAILS_AGENTSPEC_0_0_1,
13564
13852
  'example-haiku-generative-ui': EXAMPLE_HAIKU_GENERATIVE_UI_AGENTSPEC_0_0_1,
13565
13853
  'example-harness-claude-code': EXAMPLE_HARNESS_CLAUDE_CODE_AGENTSPEC_0_0_1,
13854
+ 'example-harness-codex': EXAMPLE_HARNESS_CODEX_AGENTSPEC_0_0_1,
13855
+ 'example-harness-fast-agent': EXAMPLE_HARNESS_FAST_AGENT_SPEC_0_0_1,
13856
+ 'example-harness-gemini-cli': EXAMPLE_HARNESS_GEMINI_CLI_AGENTSPEC_0_0_1,
13857
+ 'example-harness-goose': EXAMPLE_HARNESS_GOOSE_AGENTSPEC_0_0_1,
13858
+ 'example-harness-opencode': EXAMPLE_HARNESS_OPENCODE_AGENTSPEC_0_0_1,
13859
+ 'example-harness-openhands': EXAMPLE_HARNESS_OPENHANDS_AGENTSPEC_0_0_1,
13566
13860
  'example-hooks': EXAMPLE_HOOKS_AGENTSPEC_0_0_1,
13567
13861
  'example-human-approved-automation': EXAMPLE_HUMAN_APPROVED_AUTOMATION_AGENTSPEC_0_0_1,
13568
13862
  'example-human-in-the-loop': EXAMPLE_HUMAN_IN_THE_LOOP_AGENTSPEC_0_0_1,
@@ -198,7 +198,17 @@ export function HandsFree({ hearing, language, consentKey, microphoneId, turnSil
198
198
  }, [on, paused]);
199
199
  return (_jsxs(Box, { display: "inline-flex", alignItems: "center", sx: { gap: 1, position: 'relative' }, "data-hands-free": state, children: [_jsx(Tooltip, { text: on
200
200
  ? 'Stop talking with it'
201
- : 'Talk with it: speak, it answers, and listens on (hands-free)', direction: "n", children: _jsx(Button, { size: "small", variant: on ? 'primary' : 'invisible', "aria-pressed": on, "aria-label": on ? 'Stop talking with it' : 'Talk with it', disabled: disabled, "data-hands-free-toggle": "", onClick: () => (on ? turnOff() : turnOn()), children: HANDS_FREE_WORDS.off }) }), on ? (_jsxs(_Fragment, { children: [_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, role: "status", "aria-live": "polite", "data-hands-free-state": state, children: HANDS_FREE_WORDS[state] }), paused ? (_jsx(IconButton, { icon: () => _jsx("span", { "aria-hidden": "true", children: "\u25B6" }), size: "small", variant: "invisible", "aria-label": "Resume listening", "data-hands-free-resume": "", onClick: () => setPaused(false) })) : (_jsx(IconButton, { icon: () => _jsx("span", { "aria-hidden": "true", children: "\u275A\u275A" }), size: "small", variant: "invisible", "aria-label": "Pause listening (Esc)", "data-hands-free-pause": "", onClick: () => {
201
+ : 'Talk with it: speak, it answers, and listens on (hands-free)', direction: "n", children: _jsx(Button, { size: "small", variant: on ? 'primary' : 'invisible', "aria-pressed": on, "aria-label": on ? 'Stop talking with it' : 'Talk with it', "aria-disabled": disabled || undefined, "data-hands-free-toggle": "", onClick: () => {
202
+ if (disabled) {
203
+ return;
204
+ }
205
+ if (on) {
206
+ turnOff();
207
+ }
208
+ else {
209
+ turnOn();
210
+ }
211
+ }, children: HANDS_FREE_WORDS.off }) }), on ? (_jsxs(_Fragment, { children: [_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, role: "status", "aria-live": "polite", "data-hands-free-state": state, children: HANDS_FREE_WORDS[state] }), paused ? (_jsx(IconButton, { icon: () => _jsx("span", { "aria-hidden": "true", children: "\u25B6" }), size: "small", variant: "invisible", "aria-label": "Resume listening", "data-hands-free-resume": "", onClick: () => setPaused(false) })) : (_jsx(IconButton, { icon: () => _jsx("span", { "aria-hidden": "true", children: "\u275A\u275A" }), size: "small", variant: "invisible", "aria-label": "Pause listening (Esc)", "data-hands-free-pause": "", onClick: () => {
202
212
  setPaused(true);
203
213
  capture.current?.cancel();
204
214
  capture.current = undefined;
@@ -239,13 +239,15 @@ export function VoiceInput({ hearing, language, onTranscript, onInterim, silence
239
239
  // Never left open behind the page.
240
240
  useEffect(() => () => capture.current?.cancel(), []);
241
241
  const listening = state === 'listening';
242
+ // Not to be pressed: turned off, or the words still being heard.
243
+ const inert = disabled || state === 'hearing';
242
244
  const label = listening
243
245
  ? clicked
244
246
  ? 'Listening — click to stop'
245
247
  : 'Listening — let go to stop'
246
248
  : 'Click to talk, or hold (Ctrl+Space)';
247
- return (_jsxs(Box, { "data-voice-input": state, display: "inline-flex", alignItems: "center", gap: 1, position: "relative", children: [speaking && onStopSpeaking && (_jsx(Tooltip, { text: "Stop speaking (Esc)", direction: "n", children: _jsx(IconButton, { icon: MuteIcon, "aria-label": "Stop speaking", size: "small", variant: "invisible", "data-voice-stop": "", onClick: onStopSpeaking }) })), listening && (_jsx(Box, { "aria-hidden": "true", width: 40, height: 4, borderRadius: 2, bg: "neutral.muted", overflow: "hidden", children: _jsx(Box, { ref: meter, width: "100%", height: "100%", bg: "danger.emphasis", transformOrigin: "left", transform: prefersStill() ? 'scaleX(1)' : 'scaleX(0.04)' }) })), (state === 'loading' || state === 'hearing') && (_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, "data-voice-progress": "", children: state === 'loading' && progress !== undefined ? `${progress}%` : '…' })), _jsx(Tooltip, { text: label, direction: "n", children: _jsx(IconButton, { icon: () => _jsx(MicrophoneIcon, { size: 16 }), "aria-label": label, "aria-pressed": listening, size: "small", variant: listening ? 'danger' : 'invisible', disabled: disabled || state === 'hearing', "data-voice-mic": "", onPointerDown: event => {
248
- if (event.button !== 0) {
249
+ return (_jsxs(Box, { "data-voice-input": state, display: "inline-flex", alignItems: "center", gap: 1, position: "relative", children: [speaking && onStopSpeaking && (_jsx(Tooltip, { text: "Stop speaking (Esc)", direction: "n", children: _jsx(IconButton, { icon: MuteIcon, "aria-label": "Stop speaking", size: "small", variant: "invisible", "data-voice-stop": "", onClick: onStopSpeaking }) })), listening && (_jsx(Box, { "aria-hidden": "true", width: 40, height: 4, borderRadius: 2, bg: "neutral.muted", overflow: "hidden", children: _jsx(Box, { ref: meter, width: "100%", height: "100%", bg: "danger.emphasis", transformOrigin: "left", transform: prefersStill() ? 'scaleX(1)' : 'scaleX(0.04)' }) })), (state === 'loading' || state === 'hearing') && (_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, "data-voice-progress": "", children: state === 'loading' && progress !== undefined ? `${progress}%` : '…' })), _jsx(Tooltip, { text: label, direction: "n", children: _jsx(IconButton, { icon: () => _jsx(MicrophoneIcon, { size: 16 }), "aria-label": label, "aria-pressed": listening, size: "small", variant: listening ? 'danger' : 'invisible', "aria-disabled": inert || undefined, "data-voice-mic": "", onPointerDown: event => {
250
+ if (inert || event.button !== 0) {
249
251
  return;
250
252
  }
251
253
  pressedAt.current = Date.now();
@@ -255,6 +257,9 @@ export function VoiceInput({ hearing, language, onTranscript, onInterim, silence
255
257
  void start();
256
258
  }
257
259
  }, onPointerUp: () => {
260
+ if (inert) {
261
+ return;
262
+ }
258
263
  // Held: letting go stops. A click: it goes on until the next
259
264
  // one, or until the person stops speaking.
260
265
  if (stopOnRelease.current ||
@@ -269,6 +274,9 @@ export function VoiceInput({ hearing, language, onTranscript, onInterim, silence
269
274
  // Enter or Space on the focused button toggles, for the keyboard (VO-66).
270
275
  if (event.key === 'Enter' || event.key === ' ') {
271
276
  event.preventDefault();
277
+ if (inert) {
278
+ return;
279
+ }
272
280
  if (stateRef.current === 'listening') {
273
281
  void stop();
274
282
  }
@@ -53,8 +53,10 @@ export declare function turnEnded(heard: HeardSoFarLike, turnSilenceMs?: number)
53
53
  * At most this share of what plays is taken to come back into the
54
54
  * microphone once the browser's echo cancellation has done its part (VO-13),
55
55
  * on the meters' own scales (the microphone's `Capture.level`, the speaker's
56
- * `level`). A setting, not a measure yet: VO-52 measures it on a laptop's
57
- * own speakers.
56
+ * `level`). Measured on a laptop's own speakers in Chrome (VO-13): the echo
57
+ * left after cancellation was about 1% of the playback (0.055 at p95), and a
58
+ * voice over the answer passed this gate several times a second. 0.6 keeps
59
+ * a margin for worse speakers and rooms.
58
60
  */
59
61
  export declare const ECHO_SHARE = 0.6;
60
62
  /** How far above that echo the person's voice must be, on the meter's scale. */
@@ -41,8 +41,10 @@ export function turnEnded(heard, turnSilenceMs = TURN_SILENCE_MS) {
41
41
  * At most this share of what plays is taken to come back into the
42
42
  * microphone once the browser's echo cancellation has done its part (VO-13),
43
43
  * on the meters' own scales (the microphone's `Capture.level`, the speaker's
44
- * `level`). A setting, not a measure yet: VO-52 measures it on a laptop's
45
- * own speakers.
44
+ * `level`). Measured on a laptop's own speakers in Chrome (VO-13): the echo
45
+ * left after cancellation was about 1% of the playback (0.055 at p95), and a
46
+ * voice over the answer passed this gate several times a second. 0.6 keeps
47
+ * a margin for worse speakers and rooms.
46
48
  */
47
49
  export const ECHO_SHARE = 0.6;
48
50
  /** How far above that echo the person's voice must be, on the meter's scale. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@datalayer/agent-runtimes",
3
- "version": "1.5.53",
3
+ "version": "1.5.55",
4
4
  "type": "module",
5
5
  "workspaces": [
6
6
  ".",