@signalcore/ui 0.1.0 → 1.0.0-beta.0

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 (611) hide show
  1. package/README.md +896 -513
  2. package/dist/AgentAbout.d.ts +186 -0
  3. package/dist/AgentAbout.js +1020 -0
  4. package/dist/AgentAbout.js.map +1 -0
  5. package/dist/AgentCard.d.ts +49 -0
  6. package/dist/AgentCard.js +77 -0
  7. package/dist/AgentCard.js.map +1 -0
  8. package/dist/AgentChat.d.ts +233 -0
  9. package/dist/AgentChat.js +1119 -0
  10. package/dist/AgentChat.js.map +1 -0
  11. package/dist/AgentSpace.d.ts +112 -0
  12. package/dist/AgentSpace.js +339 -0
  13. package/dist/AgentSpace.js.map +1 -0
  14. package/dist/AgentTasks.d.ts +48 -0
  15. package/dist/AgentTasks.js +120 -0
  16. package/dist/AgentTasks.js.map +1 -0
  17. package/dist/BrowserView.d.ts +52 -0
  18. package/dist/BrowserView.js +328 -0
  19. package/dist/BrowserView.js.map +1 -0
  20. package/dist/FileView.d.ts +63 -0
  21. package/dist/FileView.js +449 -0
  22. package/dist/FileView.js.map +1 -0
  23. package/dist/Modes.d.ts +13 -0
  24. package/dist/Modes.js +75 -0
  25. package/dist/Modes.js.map +1 -0
  26. package/dist/VoiceCall.d.ts +91 -0
  27. package/dist/VoiceCall.js +302 -0
  28. package/dist/VoiceCall.js.map +1 -0
  29. package/dist/about.d.ts +212 -0
  30. package/dist/about.js +136 -0
  31. package/dist/about.js.map +1 -0
  32. package/dist/agentIcons.d.ts +33 -0
  33. package/dist/agentIcons.js +36 -0
  34. package/dist/agentIcons.js.map +1 -0
  35. package/dist/automation/Automation.d.ts +35 -0
  36. package/dist/automation/Automation.js +268 -0
  37. package/dist/automation/Automation.js.map +1 -0
  38. package/dist/automation/RunView.d.ts +25 -0
  39. package/dist/automation/RunView.js +187 -0
  40. package/dist/automation/RunView.js.map +1 -0
  41. package/dist/automation/cron.d.ts +41 -0
  42. package/dist/automation/cron.js +169 -0
  43. package/dist/automation/cron.js.map +1 -0
  44. package/dist/automation/marks.js +121 -0
  45. package/dist/automation/marks.js.map +1 -0
  46. package/dist/automation/messages.d.ts +113 -0
  47. package/dist/automation/messages.js +113 -0
  48. package/dist/automation/messages.js.map +1 -0
  49. package/dist/automation/record.d.ts +47 -0
  50. package/dist/automation/record.js +177 -0
  51. package/dist/automation/record.js.map +1 -0
  52. package/dist/automation/types.d.ts +143 -0
  53. package/dist/automation/when.d.ts +36 -0
  54. package/dist/automation/when.js +168 -0
  55. package/dist/automation/when.js.map +1 -0
  56. package/dist/blocks.d.ts +185 -0
  57. package/dist/browser.js +292 -0
  58. package/dist/browser.js.map +1 -0
  59. package/dist/call.d.ts +89 -0
  60. package/dist/call.js +218 -0
  61. package/dist/call.js.map +1 -0
  62. package/dist/channelParts.js +26 -0
  63. package/dist/channelParts.js.map +1 -0
  64. package/dist/classes.js +8 -3
  65. package/dist/classes.js.map +1 -0
  66. package/dist/client.d.ts +146 -54
  67. package/dist/client.js +204 -1
  68. package/dist/client.js.map +1 -0
  69. package/dist/conversationFiles.js +46 -0
  70. package/dist/conversationFiles.js.map +1 -0
  71. package/dist/credentials.d.ts +45 -0
  72. package/dist/credentials.js +98 -0
  73. package/dist/credentials.js.map +1 -0
  74. package/dist/dev.js +17 -0
  75. package/dist/dev.js.map +1 -0
  76. package/dist/es.d.ts +17 -0
  77. package/dist/es.js +382 -0
  78. package/dist/es.js.map +1 -0
  79. package/dist/files.d.ts +21 -0
  80. package/dist/files.js +214 -0
  81. package/dist/files.js.map +1 -0
  82. package/dist/frames.d.ts +115 -0
  83. package/dist/frames.js +219 -0
  84. package/dist/frames.js.map +1 -0
  85. package/dist/icons.js +29 -0
  86. package/dist/icons.js.map +1 -0
  87. package/dist/index.d.ts +63 -60
  88. package/dist/index.js +59 -45
  89. package/dist/kit/AudioPlayer.d.ts +20 -0
  90. package/dist/kit/AudioPlayer.js +116 -0
  91. package/dist/kit/AudioPlayer.js.map +1 -0
  92. package/dist/kit/Button.d.ts +29 -0
  93. package/dist/kit/Button.js +59 -0
  94. package/dist/kit/Button.js.map +1 -0
  95. package/dist/kit/Card.d.ts +16 -0
  96. package/dist/kit/Card.js +36 -0
  97. package/dist/kit/Card.js.map +1 -0
  98. package/dist/kit/Chart.js +152 -0
  99. package/dist/kit/Chart.js.map +1 -0
  100. package/dist/kit/Choices.d.ts +21 -0
  101. package/dist/kit/Choices.js +99 -0
  102. package/dist/kit/Choices.js.map +1 -0
  103. package/dist/kit/Combobox.d.ts +26 -0
  104. package/dist/kit/Combobox.js +190 -0
  105. package/dist/kit/Combobox.js.map +1 -0
  106. package/dist/kit/DateField.d.ts +17 -0
  107. package/dist/kit/DateField.js +133 -0
  108. package/dist/kit/DateField.js.map +1 -0
  109. package/dist/kit/Field.d.ts +40 -0
  110. package/dist/kit/Field.js +98 -0
  111. package/dist/kit/Field.js.map +1 -0
  112. package/dist/kit/FileField.d.ts +113 -0
  113. package/dist/kit/FileField.js +341 -0
  114. package/dist/kit/FileField.js.map +1 -0
  115. package/dist/kit/FileMark.d.ts +15 -0
  116. package/dist/kit/FileMark.js +39 -0
  117. package/dist/kit/FileMark.js.map +1 -0
  118. package/dist/kit/Inputs.d.ts +59 -0
  119. package/dist/kit/Inputs.js +205 -0
  120. package/dist/kit/Inputs.js.map +1 -0
  121. package/dist/kit/List.d.ts +47 -0
  122. package/dist/kit/List.js +85 -0
  123. package/dist/kit/List.js.map +1 -0
  124. package/dist/kit/Mark.d.ts +30 -0
  125. package/dist/kit/Mark.js +27 -0
  126. package/dist/kit/Mark.js.map +1 -0
  127. package/dist/kit/MarkStack.d.ts +15 -0
  128. package/dist/kit/MarkStack.js +26 -0
  129. package/dist/kit/MarkStack.js.map +1 -0
  130. package/dist/kit/Note.d.ts +11 -0
  131. package/dist/kit/Note.js +31 -0
  132. package/dist/kit/Note.js.map +1 -0
  133. package/dist/kit/Popover.js +90 -0
  134. package/dist/kit/Popover.js.map +1 -0
  135. package/dist/kit/RangeField.d.ts +14 -0
  136. package/dist/kit/RangeField.js +47 -0
  137. package/dist/kit/RangeField.js.map +1 -0
  138. package/dist/kit/RatingField.d.ts +14 -0
  139. package/dist/kit/RatingField.js +50 -0
  140. package/dist/kit/RatingField.js.map +1 -0
  141. package/dist/kit/Stat.d.ts +26 -0
  142. package/dist/kit/Stat.js +46 -0
  143. package/dist/kit/Stat.js.map +1 -0
  144. package/dist/kit/Switch.d.ts +14 -0
  145. package/dist/kit/Switch.js +21 -0
  146. package/dist/kit/Switch.js.map +1 -0
  147. package/dist/kit/Tag.d.ts +16 -0
  148. package/dist/kit/Tag.js +20 -0
  149. package/dist/kit/Tag.js.map +1 -0
  150. package/dist/kit/Tile.d.ts +34 -0
  151. package/dist/kit/Tile.js +52 -0
  152. package/dist/kit/Tile.js.map +1 -0
  153. package/dist/kit/TimeField.d.ts +31 -0
  154. package/dist/kit/TimeField.js +109 -0
  155. package/dist/kit/TimeField.js.map +1 -0
  156. package/dist/kit/context.d.ts +22 -0
  157. package/dist/kit/context.js +46 -0
  158. package/dist/kit/context.js.map +1 -0
  159. package/dist/kit/dates.d.ts +14 -0
  160. package/dist/kit/dates.js +129 -0
  161. package/dist/kit/dates.js.map +1 -0
  162. package/dist/kit/messages.d.ts +99 -0
  163. package/dist/kit/messages.js +66 -0
  164. package/dist/kit/messages.js.map +1 -0
  165. package/dist/kit/numbers.d.ts +12 -0
  166. package/dist/kit/numbers.js +40 -0
  167. package/dist/kit/numbers.js.map +1 -0
  168. package/dist/kit/options.d.ts +10 -0
  169. package/dist/kit/options.js +23 -0
  170. package/dist/kit/options.js.map +1 -0
  171. package/dist/kit/uploads.d.ts +42 -0
  172. package/dist/kit/uploads.js +165 -0
  173. package/dist/kit/uploads.js.map +1 -0
  174. package/dist/kit/waveform.js +76 -0
  175. package/dist/kit/waveform.js.map +1 -0
  176. package/dist/locale.d.ts +1 -0
  177. package/dist/locale.js +1 -0
  178. package/dist/markdown.js +84 -0
  179. package/dist/markdown.js.map +1 -0
  180. package/dist/marks.js +217 -0
  181. package/dist/marks.js.map +1 -0
  182. package/dist/reveal.js +48 -0
  183. package/dist/reveal.js.map +1 -0
  184. package/dist/stepGlyphs.js +62 -0
  185. package/dist/stepGlyphs.js.map +1 -0
  186. package/dist/surface/Form.js +264 -0
  187. package/dist/surface/Form.js.map +1 -0
  188. package/dist/surface/Markdown.js +42 -0
  189. package/dist/surface/Markdown.js.map +1 -0
  190. package/dist/surface/Surface.d.ts +31 -17
  191. package/dist/surface/Surface.js +480 -57
  192. package/dist/surface/Surface.js.map +1 -0
  193. package/dist/surface/scope.d.ts +32 -0
  194. package/dist/surface/scope.js +23 -0
  195. package/dist/surface/scope.js.map +1 -0
  196. package/dist/surface/values.d.ts +44 -0
  197. package/dist/surface/values.js +237 -0
  198. package/dist/surface/values.js.map +1 -0
  199. package/dist/tint.d.ts +10 -0
  200. package/dist/tint.js +19 -0
  201. package/dist/tint.js.map +1 -0
  202. package/dist/types.d.ts +534 -0
  203. package/dist/types.js +16 -0
  204. package/dist/types.js.map +1 -0
  205. package/dist/useAgentFace.d.ts +18 -0
  206. package/dist/useAgentFace.js +45 -0
  207. package/dist/useAgentFace.js.map +1 -0
  208. package/dist/useCall.d.ts +39 -0
  209. package/dist/useCall.js +273 -0
  210. package/dist/useCall.js.map +1 -0
  211. package/dist/useConversation.d.ts +77 -0
  212. package/dist/useConversation.js +523 -0
  213. package/dist/useConversation.js.map +1 -0
  214. package/dist/useDictation.d.ts +17 -0
  215. package/dist/useDictation.js +68 -0
  216. package/dist/useDictation.js.map +1 -0
  217. package/dist/useLive.d.ts +26 -0
  218. package/dist/useLive.js +88 -0
  219. package/dist/useLive.js.map +1 -0
  220. package/dist/usePolled.js +68 -0
  221. package/dist/usePolled.js.map +1 -0
  222. package/dist/voice/Orb.d.ts +10 -9
  223. package/dist/voice/Orb.js +43 -39
  224. package/dist/voice/Orb.js.map +1 -0
  225. package/dist/voice/StillOrb.js +33 -0
  226. package/dist/voice/StillOrb.js.map +1 -0
  227. package/dist/voice/WebGLOrb.js +98 -0
  228. package/dist/voice/WebGLOrb.js.map +1 -0
  229. package/dist/voice/fluidDots.js +161 -0
  230. package/dist/voice/fluidDots.js.map +1 -0
  231. package/dist/voice/motion.js +84 -0
  232. package/dist/voice/motion.js.map +1 -0
  233. package/dist/voice/orbs.d.ts +32 -0
  234. package/dist/voice/orbs.js +16 -0
  235. package/dist/voice/orbs.js.map +1 -0
  236. package/dist/voice/useReducedMotion.js +16 -16
  237. package/dist/voice/useReducedMotion.js.map +1 -0
  238. package/dist/voice/wave.js +116 -0
  239. package/dist/voice/wave.js.map +1 -0
  240. package/dist/voice/webgl.js +177 -0
  241. package/dist/voice/webgl.js.map +1 -0
  242. package/dist/widget.js +284 -8
  243. package/package.json +49 -39
  244. package/src/AgentAbout.tsx +1621 -0
  245. package/src/AgentCard.tsx +123 -0
  246. package/src/AgentChat.tsx +1795 -0
  247. package/src/AgentSpace.tsx +540 -0
  248. package/src/AgentTasks.tsx +163 -0
  249. package/src/BrowserView.tsx +442 -0
  250. package/src/FileView.tsx +620 -0
  251. package/src/Modes.tsx +112 -0
  252. package/src/VoiceCall.tsx +411 -0
  253. package/src/about.ts +355 -0
  254. package/src/agentIcons.ts +56 -0
  255. package/src/automation/Automation.tsx +308 -0
  256. package/src/automation/RunView.tsx +213 -0
  257. package/src/automation/cron.ts +196 -0
  258. package/src/automation/marks.tsx +144 -0
  259. package/src/automation/messages.ts +231 -0
  260. package/src/automation/record.ts +206 -0
  261. package/src/automation/types.ts +146 -0
  262. package/src/automation/when.ts +195 -0
  263. package/src/blocks.ts +249 -0
  264. package/src/browser.ts +334 -0
  265. package/src/call.ts +300 -0
  266. package/src/channelParts.ts +17 -0
  267. package/src/classes.ts +10 -0
  268. package/src/client.ts +397 -0
  269. package/src/conversationFiles.ts +54 -0
  270. package/src/credentials.ts +158 -0
  271. package/src/dev.ts +20 -0
  272. package/src/es.ts +423 -0
  273. package/src/files.ts +238 -0
  274. package/src/frames.ts +291 -0
  275. package/src/icons.tsx +49 -0
  276. package/src/index.ts +270 -0
  277. package/src/kit/AudioPlayer.tsx +129 -0
  278. package/src/kit/Button.tsx +97 -0
  279. package/src/kit/Card.tsx +47 -0
  280. package/src/kit/Chart.tsx +129 -0
  281. package/src/kit/Choices.tsx +131 -0
  282. package/src/kit/Combobox.tsx +247 -0
  283. package/src/kit/DateField.tsx +156 -0
  284. package/src/kit/Field.tsx +137 -0
  285. package/src/kit/FileField.tsx +492 -0
  286. package/src/kit/FileMark.tsx +56 -0
  287. package/src/kit/Inputs.tsx +250 -0
  288. package/src/kit/List.tsx +135 -0
  289. package/src/kit/Mark.tsx +64 -0
  290. package/src/kit/MarkStack.tsx +29 -0
  291. package/src/kit/Note.tsx +42 -0
  292. package/src/kit/Popover.tsx +121 -0
  293. package/src/kit/RangeField.tsx +53 -0
  294. package/src/kit/RatingField.tsx +62 -0
  295. package/src/kit/Stat.tsx +60 -0
  296. package/src/kit/Switch.tsx +28 -0
  297. package/src/kit/Tag.tsx +32 -0
  298. package/src/kit/Tile.tsx +74 -0
  299. package/src/kit/TimeField.tsx +157 -0
  300. package/src/kit/context.tsx +246 -0
  301. package/src/kit/dates.ts +150 -0
  302. package/src/kit/messages.ts +160 -0
  303. package/src/kit/numbers.ts +44 -0
  304. package/src/kit/options.ts +30 -0
  305. package/src/kit/uploads.ts +244 -0
  306. package/src/kit/waveform.ts +84 -0
  307. package/src/locale.ts +6 -0
  308. package/src/markdown.ts +69 -0
  309. package/src/marks.tsx +328 -0
  310. package/src/reveal.ts +52 -0
  311. package/src/stepGlyphs.ts +83 -0
  312. package/src/styles.css +6961 -0
  313. package/src/surface/Form.tsx +299 -0
  314. package/src/surface/Markdown.tsx +55 -0
  315. package/src/surface/Surface.tsx +605 -0
  316. package/src/surface/scope.ts +82 -0
  317. package/src/surface/values.ts +361 -0
  318. package/src/tint.ts +14 -0
  319. package/src/types.ts +596 -0
  320. package/src/useAgentFace.ts +47 -0
  321. package/src/useCall.ts +292 -0
  322. package/src/useConversation.ts +627 -0
  323. package/src/useDictation.ts +83 -0
  324. package/src/useLive.ts +115 -0
  325. package/src/usePolled.ts +60 -0
  326. package/src/voice/Orb.tsx +45 -0
  327. package/src/voice/StillOrb.tsx +29 -0
  328. package/src/voice/WebGLOrb.tsx +98 -0
  329. package/src/voice/fluidDots.tsx +171 -0
  330. package/src/voice/motion.ts +112 -0
  331. package/src/voice/orbs.ts +39 -0
  332. package/src/voice/useReducedMotion.ts +24 -0
  333. package/src/voice/wave.tsx +129 -0
  334. package/src/voice/webgl.ts +209 -0
  335. package/src/widget/css.d.ts +5 -0
  336. package/src/widget/element.tsx +535 -0
  337. package/src/widget/index.ts +10 -0
  338. package/src/widget/mount.ts +27 -0
  339. package/src/widget/widget.css +253 -0
  340. package/dist/SignalcoreProvider.d.ts +0 -113
  341. package/dist/SignalcoreProvider.js +0 -84
  342. package/dist/automations/AppMarks.d.ts +0 -11
  343. package/dist/automations/AppMarks.js +0 -18
  344. package/dist/automations/AutomationCard.d.ts +0 -27
  345. package/dist/automations/AutomationCard.js +0 -53
  346. package/dist/automations/AutomationsWindow.d.ts +0 -38
  347. package/dist/automations/AutomationsWindow.js +0 -57
  348. package/dist/automations/Card.d.ts +0 -46
  349. package/dist/automations/Card.js +0 -45
  350. package/dist/automations/ScheduleMarks.d.ts +0 -13
  351. package/dist/automations/ScheduleMarks.js +0 -24
  352. package/dist/automations/presentationIcons.d.ts +0 -7
  353. package/dist/automations/presentationIcons.js +0 -67
  354. package/dist/automations/schedule.d.ts +0 -25
  355. package/dist/automations/schedule.js +0 -59
  356. package/dist/automations/time.d.ts +0 -3
  357. package/dist/automations/time.js +0 -25
  358. package/dist/browser/BrowserView.d.ts +0 -43
  359. package/dist/browser/BrowserView.js +0 -94
  360. package/dist/browser/room.d.ts +0 -21
  361. package/dist/browser/room.js +0 -33
  362. package/dist/browser/useBrowserSession.d.ts +0 -17
  363. package/dist/browser/useBrowserSession.js +0 -67
  364. package/dist/builder/BuilderChat.d.ts +0 -32
  365. package/dist/builder/BuilderChat.js +0 -41
  366. package/dist/builder/BuilderTranscript.d.ts +0 -49
  367. package/dist/builder/BuilderTranscript.js +0 -62
  368. package/dist/builder/StatusLine.d.ts +0 -8
  369. package/dist/builder/StatusLine.js +0 -17
  370. package/dist/builder/answer.d.ts +0 -7
  371. package/dist/builder/answer.js +0 -8
  372. package/dist/builder/blocks.d.ts +0 -31
  373. package/dist/builder/blocks.js +0 -74
  374. package/dist/builder/items.d.ts +0 -15
  375. package/dist/builder/items.js +0 -21
  376. package/dist/builder/steps.d.ts +0 -20
  377. package/dist/builder/steps.js +0 -120
  378. package/dist/builder/time.d.ts +0 -4
  379. package/dist/builder/time.js +0 -24
  380. package/dist/builder/useBuildSession.d.ts +0 -36
  381. package/dist/builder/useBuildSession.js +0 -130
  382. package/dist/builder/workingOn.d.ts +0 -7
  383. package/dist/builder/workingOn.js +0 -15
  384. package/dist/chat/AgentChat.d.ts +0 -37
  385. package/dist/chat/AgentChat.js +0 -21
  386. package/dist/chat/ChatView.d.ts +0 -25
  387. package/dist/chat/ChatView.js +0 -34
  388. package/dist/chat/Composer.d.ts +0 -20
  389. package/dist/chat/Composer.js +0 -22
  390. package/dist/chat/MessageRow.d.ts +0 -22
  391. package/dist/chat/MessageRow.js +0 -32
  392. package/dist/chat/arrival.d.ts +0 -15
  393. package/dist/chat/arrival.js +0 -25
  394. package/dist/chat/history.d.ts +0 -24
  395. package/dist/chat/history.js +0 -45
  396. package/dist/chat/moments.d.ts +0 -25
  397. package/dist/chat/moments.js +0 -72
  398. package/dist/chat/types.d.ts +0 -12
  399. package/dist/chat/types.js +0 -1
  400. package/dist/chat/useComposer.d.ts +0 -46
  401. package/dist/chat/useComposer.js +0 -62
  402. package/dist/chat/useConversation.d.ts +0 -35
  403. package/dist/chat/useConversation.js +0 -71
  404. package/dist/chat/useStickToBottom.d.ts +0 -9
  405. package/dist/chat/useStickToBottom.js +0 -33
  406. package/dist/chat/useTurns.d.ts +0 -49
  407. package/dist/chat/useTurns.js +0 -111
  408. package/dist/classes.d.ts +0 -2
  409. package/dist/development.d.ts +0 -5
  410. package/dist/development.js +0 -8
  411. package/dist/flow/FlowWindow.d.ts +0 -42
  412. package/dist/flow/FlowWindow.js +0 -126
  413. package/dist/flow/index.d.ts +0 -16
  414. package/dist/flow/index.js +0 -16
  415. package/dist/flow/kinds.d.ts +0 -23
  416. package/dist/flow/kinds.js +0 -48
  417. package/dist/flow/map.d.ts +0 -44
  418. package/dist/flow/map.js +0 -225
  419. package/dist/flow/nodePaths.d.ts +0 -7
  420. package/dist/flow/nodePaths.js +0 -17
  421. package/dist/flow/relations.d.ts +0 -42
  422. package/dist/flow/relations.js +0 -174
  423. package/dist/host.d.ts +0 -124
  424. package/dist/host.js +0 -1
  425. package/dist/live/LiveView.d.ts +0 -28
  426. package/dist/live/LiveView.js +0 -55
  427. package/dist/live/capture.d.ts +0 -20
  428. package/dist/live/capture.js +0 -100
  429. package/dist/live/follow.d.ts +0 -26
  430. package/dist/live/follow.js +0 -72
  431. package/dist/live/paint.d.ts +0 -13
  432. package/dist/live/paint.js +0 -77
  433. package/dist/live/useLiveStream.d.ts +0 -16
  434. package/dist/live/useLiveStream.js +0 -57
  435. package/dist/look.d.ts +0 -33
  436. package/dist/look.js +0 -241
  437. package/dist/messages/en.d.ts +0 -3
  438. package/dist/messages/en.js +0 -251
  439. package/dist/messages/es.d.ts +0 -3
  440. package/dist/messages/es.js +0 -251
  441. package/dist/messages/index.d.ts +0 -16
  442. package/dist/messages/index.js +0 -33
  443. package/dist/messages/types.d.ts +0 -246
  444. package/dist/messages/types.js +0 -1
  445. package/dist/parts/Button.d.ts +0 -18
  446. package/dist/parts/Button.js +0 -17
  447. package/dist/parts/Icon.d.ts +0 -39
  448. package/dist/parts/Icon.js +0 -37
  449. package/dist/parts/Input.d.ts +0 -6
  450. package/dist/parts/Input.js +0 -11
  451. package/dist/parts/Spinner.d.ts +0 -2
  452. package/dist/parts/Spinner.js +0 -7
  453. package/dist/patterns.d.ts +0 -15
  454. package/dist/patterns.js +0 -5
  455. package/dist/presets.d.ts +0 -82
  456. package/dist/presets.js +0 -81
  457. package/dist/primitives.d.ts +0 -22
  458. package/dist/primitives.js +0 -58
  459. package/dist/request/RequestCard.d.ts +0 -34
  460. package/dist/request/RequestCard.js +0 -101
  461. package/dist/request/approval/ApprovalPreview.d.ts +0 -5
  462. package/dist/request/approval/ApprovalPreview.js +0 -27
  463. package/dist/request/approval/shapes.d.ts +0 -32
  464. package/dist/request/approval/shapes.js +0 -68
  465. package/dist/request/apps.d.ts +0 -11
  466. package/dist/request/apps.js +0 -27
  467. package/dist/request/cards.d.ts +0 -12
  468. package/dist/request/cards.js +0 -24
  469. package/dist/request/deliver.d.ts +0 -12
  470. package/dist/request/deliver.js +0 -21
  471. package/dist/request/handOver.d.ts +0 -18
  472. package/dist/request/handOver.js +0 -33
  473. package/dist/request/kinds/Approval.d.ts +0 -3
  474. package/dist/request/kinds/Approval.js +0 -9
  475. package/dist/request/kinds/Choice.d.ts +0 -3
  476. package/dist/request/kinds/Choice.js +0 -8
  477. package/dist/request/kinds/Connect.d.ts +0 -9
  478. package/dist/request/kinds/Connect.js +0 -119
  479. package/dist/request/kinds/FreeText.d.ts +0 -3
  480. package/dist/request/kinds/FreeText.js +0 -20
  481. package/dist/request/kinds/HandOver.d.ts +0 -13
  482. package/dist/request/kinds/HandOver.js +0 -20
  483. package/dist/request/kinds/Secret.d.ts +0 -7
  484. package/dist/request/kinds/Secret.js +0 -49
  485. package/dist/request/kinds/Upload.d.ts +0 -6
  486. package/dist/request/kinds/Upload.js +0 -47
  487. package/dist/request/types.d.ts +0 -83
  488. package/dist/request/types.js +0 -1
  489. package/dist/safeUrl.d.ts +0 -6
  490. package/dist/safeUrl.js +0 -8
  491. package/dist/stream/builder.d.ts +0 -176
  492. package/dist/stream/builder.js +0 -202
  493. package/dist/stream/reduce.d.ts +0 -51
  494. package/dist/stream/reduce.js +0 -58
  495. package/dist/stream/untilAborted.d.ts +0 -7
  496. package/dist/stream/untilAborted.js +0 -32
  497. package/dist/stream/useRunStream.d.ts +0 -26
  498. package/dist/stream/useRunStream.js +0 -137
  499. package/dist/styles.css +0 -2318
  500. package/dist/surface/HostNode.d.ts +0 -14
  501. package/dist/surface/HostNode.js +0 -30
  502. package/dist/surface/Node.d.ts +0 -7
  503. package/dist/surface/Node.js +0 -49
  504. package/dist/surface/SurfaceBoundary.d.ts +0 -26
  505. package/dist/surface/SurfaceBoundary.js +0 -20
  506. package/dist/surface/bindings.d.ts +0 -14
  507. package/dist/surface/bindings.js +0 -37
  508. package/dist/surface/check.d.ts +0 -27
  509. package/dist/surface/check.js +0 -102
  510. package/dist/surface/format.d.ts +0 -10
  511. package/dist/surface/format.js +0 -32
  512. package/dist/surface/hosts.d.ts +0 -6
  513. package/dist/surface/hosts.js +0 -11
  514. package/dist/surface/scene.d.ts +0 -21
  515. package/dist/surface/scene.js +0 -8
  516. package/dist/surface/templates/Browser.d.ts +0 -6
  517. package/dist/surface/templates/Browser.js +0 -11
  518. package/dist/surface/templates/Chart.d.ts +0 -6
  519. package/dist/surface/templates/Chart.js +0 -13
  520. package/dist/surface/templates/Choices.d.ts +0 -3
  521. package/dist/surface/templates/Choices.js +0 -12
  522. package/dist/surface/templates/Form.d.ts +0 -3
  523. package/dist/surface/templates/Form.js +0 -44
  524. package/dist/surface/templates/KeyValue.d.ts +0 -3
  525. package/dist/surface/templates/KeyValue.js +0 -7
  526. package/dist/surface/templates/Layout.d.ts +0 -5
  527. package/dist/surface/templates/Layout.js +0 -16
  528. package/dist/surface/templates/Live.d.ts +0 -6
  529. package/dist/surface/templates/Live.js +0 -9
  530. package/dist/surface/templates/Media.d.ts +0 -5
  531. package/dist/surface/templates/Media.js +0 -13
  532. package/dist/surface/templates/Slots.d.ts +0 -3
  533. package/dist/surface/templates/Slots.js +0 -19
  534. package/dist/surface/templates/Table.d.ts +0 -3
  535. package/dist/surface/templates/Table.js +0 -12
  536. package/dist/surface/templates/Text.d.ts +0 -4
  537. package/dist/surface/templates/Text.js +0 -15
  538. package/dist/surface/templates/index.d.ts +0 -7
  539. package/dist/surface/templates/index.js +0 -32
  540. package/dist/surface/types.d.ts +0 -68
  541. package/dist/surface/types.js +0 -6
  542. package/dist/theme.d.ts +0 -62
  543. package/dist/theme.js +0 -9
  544. package/dist/useTokens.d.ts +0 -7
  545. package/dist/useTokens.js +0 -41
  546. package/dist/voice/VoiceWindow.d.ts +0 -18
  547. package/dist/voice/VoiceWindow.js +0 -35
  548. package/dist/voice/index.d.ts +0 -13
  549. package/dist/voice/index.js +0 -12
  550. package/dist/voice/meter.d.ts +0 -16
  551. package/dist/voice/meter.js +0 -52
  552. package/dist/voice/orbColors.d.ts +0 -16
  553. package/dist/voice/orbColors.js +0 -75
  554. package/dist/voice/pushable.d.ts +0 -16
  555. package/dist/voice/pushable.js +0 -56
  556. package/dist/voice/useDictation.d.ts +0 -24
  557. package/dist/voice/useDictation.js +0 -60
  558. package/dist/voice/useReducedMotion.d.ts +0 -5
  559. package/dist/voice/useVoice.d.ts +0 -70
  560. package/dist/voice/useVoice.js +0 -197
  561. package/dist/voice/useVoicePrimitives.d.ts +0 -7
  562. package/dist/voice/useVoicePrimitives.js +0 -11
  563. package/dist/voice/voice.d.ts +0 -55
  564. package/dist/voice/voice.js +0 -9
  565. package/dist/voice/webSpeech.d.ts +0 -33
  566. package/dist/voice/webSpeech.js +0 -258
  567. package/dist/widget.js.map +0 -1
  568. package/dist/windows/AgentSpace.d.ts +0 -78
  569. package/dist/windows/AgentSpace.js +0 -135
  570. package/dist/windows/Captions.d.ts +0 -13
  571. package/dist/windows/Captions.js +0 -22
  572. package/dist/windows/Dock.d.ts +0 -37
  573. package/dist/windows/Dock.js +0 -22
  574. package/dist/windows/Journal.d.ts +0 -15
  575. package/dist/windows/Journal.js +0 -19
  576. package/dist/windows/KindMark.d.ts +0 -7
  577. package/dist/windows/KindMark.js +0 -31
  578. package/dist/windows/Pending.d.ts +0 -8
  579. package/dist/windows/Pending.js +0 -17
  580. package/dist/windows/Stage.d.ts +0 -18
  581. package/dist/windows/Stage.js +0 -21
  582. package/dist/windows/StatusLabel.d.ts +0 -9
  583. package/dist/windows/StatusLabel.js +0 -7
  584. package/dist/windows/Strip.d.ts +0 -17
  585. package/dist/windows/Strip.js +0 -42
  586. package/dist/windows/SurfaceWindow.d.ts +0 -20
  587. package/dist/windows/SurfaceWindow.js +0 -12
  588. package/dist/windows/WindowFrame.d.ts +0 -23
  589. package/dist/windows/WindowFrame.js +0 -22
  590. package/dist/windows/hearing.d.ts +0 -11
  591. package/dist/windows/hearing.js +0 -26
  592. package/dist/windows/kinds.d.ts +0 -47
  593. package/dist/windows/kinds.js +0 -28
  594. package/dist/windows/reduce.d.ts +0 -98
  595. package/dist/windows/reduce.js +0 -151
  596. package/dist/windows/registry.d.ts +0 -18
  597. package/dist/windows/registry.js +0 -61
  598. package/dist/windows/reveal.d.ts +0 -9
  599. package/dist/windows/reveal.js +0 -6
  600. package/dist/windows/space.d.ts +0 -21
  601. package/dist/windows/space.js +0 -6
  602. package/dist/windows/status.d.ts +0 -11
  603. package/dist/windows/status.js +0 -30
  604. package/dist/windows/types.d.ts +0 -15
  605. package/dist/windows/types.js +0 -1
  606. package/dist/windows/useLoaded.d.ts +0 -44
  607. package/dist/windows/useLoaded.js +0 -58
  608. package/dist/windows/useUnread.d.ts +0 -7
  609. package/dist/windows/useUnread.js +0 -21
  610. package/dist/windows/useWindows.d.ts +0 -70
  611. package/dist/windows/useWindows.js +0 -60
@@ -0,0 +1,1621 @@
1
+ import {
2
+ useCallback,
3
+ useEffect,
4
+ useId,
5
+ useLayoutEffect,
6
+ useMemo,
7
+ useRef,
8
+ useState,
9
+ type ReactNode,
10
+ } from "react";
11
+
12
+ import {
13
+ BooksIcon,
14
+ BroadcastIcon,
15
+ KeyIcon,
16
+ LightbulbIcon,
17
+ PuzzlePieceIcon,
18
+ WrenchIcon,
19
+ type Icon as Glyph,
20
+ } from "@phosphor-icons/react";
21
+ import {
22
+ aboutState,
23
+ appTitle,
24
+ automationsOf,
25
+ countOf,
26
+ formatSize,
27
+ toneOf,
28
+ toolName,
29
+ toolTitle,
30
+ type AboutOut,
31
+ type ActionFact,
32
+ type AutomationFact,
33
+ type AutomationKind,
34
+ type ChannelFact,
35
+ type ChannelKind,
36
+ type ConnectionFact,
37
+ type DataFact,
38
+ type Facts,
39
+ type FileFact,
40
+ type Icon,
41
+ type MemoryFact,
42
+ type Provider,
43
+ type StatusTone,
44
+ type Told,
45
+ type Topic,
46
+ type VaultFact,
47
+ } from "./about";
48
+ import { Automation } from "./automation/Automation";
49
+ import { RunView } from "./automation/RunView";
50
+ import type { Automation as Standing, Run } from "./automation/types";
51
+ import { agentGlyph } from "./agentIcons";
52
+ import { classes } from "./classes";
53
+ import { ApiError, type Client } from "./client";
54
+ import { baseName } from "./files";
55
+ import { GLYPHS } from "./icons";
56
+ import { KitProvider, useKit, type KitClassNames, type KitPart } from "./kit/context";
57
+ import { FileMark } from "./kit/FileMark";
58
+ import { List, Row } from "./kit/List";
59
+ import { Mark } from "./kit/Mark";
60
+ import { MarkStack } from "./kit/MarkStack";
61
+ import { Tag } from "./kit/Tag";
62
+ import { KIT_MESSAGES, type KitLocale, type KitMessages } from "./kit/messages";
63
+ import { actionMark, channelMark, deviceMark, providerMark } from "./marks";
64
+
65
+ /** What each part of what it works with is, at a glance: bare, beside its name. */
66
+ const TOPIC_GLYPHS: Readonly<Record<Topic, Glyph>> = {
67
+ apps: PuzzlePieceIcon,
68
+ tools: WrenchIcon,
69
+ knowledge: BooksIcon,
70
+ learning: LightbulbIcon,
71
+ channels: BroadcastIcon,
72
+ keys: KeyIcon,
73
+ };
74
+ import type { Channel, ChannelStatus } from "./types";
75
+ import { agentTint } from "./tint";
76
+ import { usePolled } from "./usePolled";
77
+
78
+ /** The words Qué puede says; a host gives its own, in its language. */
79
+ export interface AboutMessages {
80
+ /** While the words are read, before anything is known. */
81
+ loading: string;
82
+ /** While the agent writes what it does the first time: a model call, a few seconds. */
83
+ writing: (name: string) => string;
84
+ /** Under the words while the agent writes them again, because it changed since. */
85
+ updating: string;
86
+ /** The button that tries again when the words could not be read or written. */
87
+ refresh: string;
88
+ /** Over what it asks the person's leave for. */
89
+ asks: string;
90
+ /** Over the tools that come with every agent, when it has its own too. */
91
+ builtIn: string;
92
+ /** The words could not be read or written; the server's own sentence follows when it gave one. */
93
+ failed: string;
94
+ /** Over what it does on its own. */
95
+ does: string;
96
+ /** In their place when it does nothing on its own yet. */
97
+ noAutomations: string;
98
+ /** On an automation that is off. */
99
+ paused: string;
100
+ /** What an automation waits for, when the agent hasn't said when yet. */
101
+ kinds: Readonly<Record<AutomationKind, string>>;
102
+ /** Each topic's name, on its tile and over it when open. */
103
+ topics: Readonly<Record<Topic, string>>;
104
+ /** A topic with nothing: on its row, and as its one line when open. */
105
+ empty: Readonly<Record<Topic, string>>;
106
+ /** Under an open topic's name: what it is, in a line. */
107
+ hints: Readonly<Record<Topic, string>>;
108
+ /** Over what is the agent's own, inside what it knows and its keys. */
109
+ theirs: (name: string) => string;
110
+ /** Over what is the organization's, shared with every agent: said once, by this heading. */
111
+ organization: string;
112
+ /** Over the tables, inside what it knows. */
113
+ tables: string;
114
+ /** Under a file `search_files` does not read: it is only kept. */
115
+ kept: string;
116
+ /** Beside a tool that is off. */
117
+ off: string;
118
+ /** What it may do in a table, beside it. */
119
+ can: Readonly<Record<string, string>>;
120
+ /** Over the words, and on the way back from a topic: who this is about. */
121
+ title: (name: string) => string;
122
+ /** Over the topics. */
123
+ facts: string;
124
+ /** In place of a run that is no longer there. */
125
+ runGone: string;
126
+ /** What the kit's pieces say in it (an automation, a run): their words, in the host's language. */
127
+ kit: Partial<KitMessages>;
128
+ /** A shipped action's name in the owner's words, by its code name; the rest keep the code name. */
129
+ actions: Readonly<Record<string, string>>;
130
+ /** A file's size, as the host's people read it. */
131
+ size: (bytes: number) => string;
132
+ /** When a memory was kept, beside it. */
133
+ ago: (when: Date) => string;
134
+ /** A channel's name, by its kind: its row's title. */
135
+ channelNames: Readonly<Record<ChannelKind, string>>;
136
+ /** How a channel stands, beside its dot. */
137
+ channelStates: Readonly<Record<ChannelStatus, string>>;
138
+ /** The provider's word on a channel's status (English, as the API keeps it), in the host's. */
139
+ channelDetail: (detail: string) => string;
140
+ }
141
+
142
+ export const ABOUT_MESSAGES: AboutMessages = {
143
+ loading: "Loading…",
144
+ writing: (name) => `${name} is writing down what it does…`,
145
+ updating: "Updating…",
146
+ refresh: "Try again",
147
+ asks: "It asks you before",
148
+ builtIn: "Built in",
149
+ failed: "What it can do could not be read.",
150
+ does: "What it does on its own",
151
+ noAutomations: "Nothing on its own yet: it answers when someone writes to it.",
152
+ paused: "Paused",
153
+ kinds: { schedule: "At a time", webhook: "When called", event: "On an event" },
154
+ topics: {
155
+ apps: "Apps",
156
+ tools: "Tools",
157
+ knowledge: "Knowledge",
158
+ learning: "Learning",
159
+ channels: "Channels",
160
+ keys: "Keys",
161
+ },
162
+ empty: {
163
+ apps: "None yet",
164
+ tools: "None on",
165
+ knowledge: "Nothing yet",
166
+ learning: "Nothing yet",
167
+ channels: "None yet",
168
+ keys: "None",
169
+ },
170
+ hints: {
171
+ apps: "The business's apps it uses, and what it may do in each.",
172
+ tools: "What it can do while it talks with someone.",
173
+ knowledge: "The documents and tables it reads to answer.",
174
+ learning: "What it has learned from its conversations.",
175
+ channels: "Where it works: where people write to it, and the devices it uses.",
176
+ keys: "Passwords and keys it uses, kept sealed.",
177
+ },
178
+ theirs: (name) => `${name}'s own`,
179
+ organization: "The organization's",
180
+ tables: "Tables",
181
+ kept: "Only kept",
182
+ off: "off",
183
+ can: { find: "looks up", add: "adds", update: "changes" },
184
+ title: (name) => `About ${name}`,
185
+ facts: "What it works with",
186
+ runGone: "This run is no longer there.",
187
+ kit: KIT_MESSAGES,
188
+ actions: {},
189
+ size: (bytes) => formatSize(bytes),
190
+ ago: (when) => when.toLocaleDateString(),
191
+ channelNames: {
192
+ whatsapp: "WhatsApp",
193
+ instagram: "Instagram",
194
+ sms: "SMS",
195
+ email: "Email",
196
+ web: "Web chat",
197
+ phone: "Phone",
198
+ },
199
+ channelStates: {
200
+ active: "Active",
201
+ pending: "Pending",
202
+ error: "Error",
203
+ disconnected: "Disconnected",
204
+ },
205
+ channelDetail: (detail) => detail,
206
+ };
207
+
208
+ /** The parts, by the class each carries; `classNames` adds a host's own under the same keys. */
209
+ export type AboutPart =
210
+ | "sc-about"
211
+ | "sc-about__pane"
212
+ | "sc-about__intro"
213
+ | "sc-about__heading"
214
+ | "sc-about__name"
215
+ | "sc-about__topics"
216
+ | "sc-about__topic"
217
+ | "sc-about__topic-name"
218
+ | "sc-about__topic-none"
219
+ | "sc-about__topic-count"
220
+ | "sc-about__topic-go"
221
+ | "sc-about__lead"
222
+ | "sc-about__updated"
223
+ | "sc-about__updating"
224
+ | "sc-about__section"
225
+ | "sc-about__label"
226
+ | "sc-about__asks"
227
+ | "sc-about__menu"
228
+ | "sc-about__memory"
229
+ | "sc-about__back"
230
+ | "sc-about__bar"
231
+ | "sc-about__bar-end"
232
+ | "sc-about__automation"
233
+ | "sc-about__run"
234
+ | "sc-about__group"
235
+ | "sc-about__title"
236
+ | "sc-about__subtitle"
237
+ | "sc-about__file"
238
+ | "sc-about__detail"
239
+ | "sc-about__hint"
240
+ | "sc-about__count"
241
+ | "sc-about__tools"
242
+ | "sc-about__dot"
243
+ | "sc-about__state"
244
+ | "sc-about__empty"
245
+ | "sc-about__writing";
246
+
247
+ /** The panel's own parts and the kit's it is drawn with: a host styles both under one prop. */
248
+ type ClassNames = Partial<Record<AboutPart | KitPart, string>> | undefined;
249
+
250
+ /** What a host's control is given, besides the thing it stands beside. */
251
+ export interface AboutTools {
252
+ /**
253
+ * Reads the facts again, and has the agent write its words anew when the change made them
254
+ * stale; the open topic stays. Call it after a change.
255
+ */
256
+ refresh: () => Promise<void>;
257
+ }
258
+
259
+ type Control<T> = ((thing: T, tools: AboutTools) => ReactNode) | undefined;
260
+
261
+ /**
262
+ * The host's own controls: the package only reads, a host that lets its people change things
263
+ * draws them here. Each one is drawn at the right end of what it stands beside.
264
+ */
265
+ export interface AboutControls {
266
+ /** Over what it does on its own (a new automation). */
267
+ newAutomation?: ((tools: AboutTools) => ReactNode) | undefined;
268
+ /** On each automation (switch it off, delete it). */
269
+ automation?: Control<AutomationFact>;
270
+ /** Under its automations: what else it does on its own (the tasks it runs for contacts). */
271
+ automationsNote?: ((tools: AboutTools) => ReactNode) | undefined;
272
+ /** Over an open topic (add an app, upload a file, add a key). */
273
+ topic?: Partial<Record<Topic, (tools: AboutTools) => ReactNode>> | undefined;
274
+ app?: Control<ConnectionFact>;
275
+ tool?: Control<ActionFact>;
276
+ file?: Control<FileFact>;
277
+ table?: Control<DataFact>;
278
+ memory?: Control<MemoryFact>;
279
+ key?: Control<VaultFact>;
280
+ /** On each channel the agent answers (its settings, a check, disconnecting it). */
281
+ channel?: Control<Channel>;
282
+ }
283
+
284
+ /**
285
+ * How a host draws an app's mark, with its own brands (the package carries none): v2's
286
+ * `AppDirectory`. `provider` says the catalog and the app (`arcade:gmail`); `icon` is the one the
287
+ * provider declares, when it does.
288
+ */
289
+ export interface AppDirectory {
290
+ logo: (app: {
291
+ provider: string;
292
+ name: string;
293
+ icon?: string | null | undefined;
294
+ size: number;
295
+ }) => ReactNode;
296
+ }
297
+
298
+ export interface AgentAboutProps {
299
+ client: Client;
300
+ agentId: string;
301
+ /** Its mark (`AGENT_ICONS`), drawn beside its name in its tint; a sparkle until it has one. */
302
+ icon?: string | null | undefined;
303
+ /** The agent's name, for the words that address it. */
304
+ name: string;
305
+ messages?: Partial<AboutMessages> | undefined;
306
+ classNames?: ClassNames;
307
+ controls?: AboutControls | undefined;
308
+ /** The host's logos for apps; without them an app shows the mark its provider gives. */
309
+ apps?: AppDirectory | undefined;
310
+ /**
311
+ * Opens a file the owner presses in what it knows (in the host's viewer: `FileView` in a
312
+ * dialog); without it the files are only listed.
313
+ */
314
+ onOpenFile?: ((file: FileFact) => void) | undefined;
315
+ /**
316
+ * What is open in it: its home, a topic, an automation, a run of one. Given, the host keeps it
317
+ * (in its address, say) and hears each move through `onViewChange`; without it the panel keeps
318
+ * its own.
319
+ */
320
+ view?: AboutView | undefined;
321
+ onViewChange?: ((view: AboutView) => void) | undefined;
322
+ /** Opens a conversation a run opened or was asked in; without it, none opens. */
323
+ onOpenConversation?: ((id: string) => void) | undefined;
324
+ /** The language its dates and times are said in. */
325
+ locale?: KitLocale | undefined;
326
+ }
327
+
328
+ /**
329
+ * What is open in the panel, one level under another: its home; a topic or an automation from
330
+ * it; a run from its automation.
331
+ */
332
+ export type AboutView =
333
+ | { kind: "home" }
334
+ | { kind: "topic"; topic: Topic }
335
+ | { kind: "automation"; name: string }
336
+ | { kind: "run"; name: string; run: string };
337
+
338
+ export const ABOUT_HOME: AboutView = { kind: "home" };
339
+
340
+ /** How far a view is from the home: what says whether a move goes in or back out. */
341
+ const depthOf = (view: AboutView): number =>
342
+ view.kind === "home" ? 0 : view.kind === "run" ? 2 : 1;
343
+
344
+ /** A view as one string: what tells two apart. */
345
+ const keyOf = (view: AboutView): string =>
346
+ view.kind === "home"
347
+ ? "home"
348
+ : view.kind === "topic"
349
+ ? `topic:${view.topic}`
350
+ : view.kind === "automation"
351
+ ? `automation:${view.name}`
352
+ : `run:${view.name}:${view.run}`;
353
+
354
+ /** The view a step back from `view` goes to. */
355
+ export function aboutBack(view: AboutView): AboutView {
356
+ return view.kind === "run" ? { kind: "automation", name: view.name } : ABOUT_HOME;
357
+ }
358
+
359
+ /**
360
+ * Qué puede, made to sit beside the conversation: who it is about, in its own words (a line or
361
+ * two); what it does on its own, one row per automation (its kind's mark, or its app's logo),
362
+ * what it does and when, as the agent tells it; what it asks leave for; then what it works with,
363
+ * as a grid of tiles, one per topic (its apps, tools, what it knows and has learned, where it
364
+ * works, its keys), each with its count and a glimpse of what it holds, opening it in the same
365
+ * place. Every list is the kit's `List` and `Row`, and every tile its `Tile`, the ones an agent's
366
+ * screens use, so a host styles them once. The words are written by the agent the first time and
367
+ * again whenever it changed since, by themselves. The component only reads; a host draws its own
368
+ * controls through `controls` and calls `tools.refresh()` after a change, and opens a file
369
+ * through `onOpenFile`. An automation opens in the panel itself, one level in (what it does, its
370
+ * steps, its runs), and a run one more, each with its way back; `view` lets the host keep where
371
+ * it is. Another agent starts afresh.
372
+ */
373
+ export function AgentAbout(props: AgentAboutProps) {
374
+ return (
375
+ <KitProvider
376
+ classNames={props.classNames as KitClassNames}
377
+ messages={props.messages?.kit}
378
+ locale={props.locale}
379
+ >
380
+ <View key={props.agentId} {...props} />
381
+ </KitProvider>
382
+ );
383
+ }
384
+
385
+ function View({
386
+ client,
387
+ agentId,
388
+ icon,
389
+ name,
390
+ messages,
391
+ classNames,
392
+ controls,
393
+ apps,
394
+ onOpenFile,
395
+ view: given,
396
+ onViewChange,
397
+ onOpenConversation,
398
+ }: AgentAboutProps) {
399
+ const words = { ...ABOUT_MESSAGES, ...messages };
400
+ const [data, setData] = useState<AboutOut | null>(null);
401
+ const [live, setLive] = useState<readonly Standing[] | null>(null);
402
+ const [writing, setWriting] = useState(false);
403
+ const [problem, setProblem] = useState<unknown>(null);
404
+ // Every change the host makes reads the open automation or run again, too.
405
+ const [version, setVersion] = useState(0);
406
+ const [own, setOwn] = useState<AboutView>(ABOUT_HOME);
407
+ const view = given ?? own;
408
+ const motion = useMotion(view);
409
+ const root = useRef<HTMLDivElement>(null);
410
+ const scrolled = useRef(new Map<string, number>());
411
+ const intro = useId();
412
+
413
+ /** Opens `next`, keeping where the panel was scrolled to on the way in, for the way back. */
414
+ const go = (next: AboutView) => {
415
+ const scroller = scrollerOf(root.current);
416
+ if (scroller !== null && depthOf(next) > depthOf(view)) {
417
+ scrolled.current.set(keyOf(view), scroller.scrollTop);
418
+ }
419
+ (onViewChange ?? setOwn)(next);
420
+ };
421
+
422
+ // A view opens at its top, or back where it was left.
423
+ const shown = keyOf(view);
424
+ useLayoutEffect(() => {
425
+ const scroller = scrollerOf(root.current);
426
+ if (scroller !== null) scroller.scrollTop = scrolled.current.get(shown) ?? 0;
427
+ }, [shown]);
428
+
429
+ // Each call takes `still`, whether its answer is still wanted: a mount undone before the answer
430
+ // (StrictMode runs effects twice) keeps nothing, so one writing runs, not two.
431
+
432
+ /** Has the agent write about itself anew; what it answers is the words and the facts both. */
433
+ const write = useCallback(
434
+ async (still: () => boolean) => {
435
+ setProblem(null);
436
+ setWriting(true);
437
+ try {
438
+ const written = await client.agents.describe(agentId);
439
+ if (still()) setData(written);
440
+ } catch (error) {
441
+ if (still()) setProblem(error);
442
+ } finally {
443
+ if (still()) setWriting(false);
444
+ }
445
+ },
446
+ [client, agentId],
447
+ );
448
+
449
+ /**
450
+ * Reads the words and the facts, and how each automation stands (a server without them leaves
451
+ * the rows as they were told); when the words are missing or stale, has the agent write them.
452
+ */
453
+ const read = useCallback(
454
+ async (still: () => boolean) => {
455
+ setProblem(null);
456
+ try {
457
+ const [first, standing] = await Promise.all([
458
+ client.agents.about(agentId),
459
+ client.automations.list(agentId).catch(() => null),
460
+ ]);
461
+ if (!still()) return;
462
+ setData(first);
463
+ setLive(standing);
464
+ // Words never written, or written before the agent last changed: it writes them again
465
+ // by itself, so what it says stays true without anyone asking.
466
+ if (first.about === null || first.about_at === null) await write(still);
467
+ } catch (error) {
468
+ if (still()) setProblem(error);
469
+ }
470
+ },
471
+ [client, agentId, write],
472
+ );
473
+
474
+ useEffect(() => {
475
+ let gone = false;
476
+ void read(() => !gone);
477
+ return () => {
478
+ gone = true;
479
+ };
480
+ }, [read]);
481
+
482
+ const tools = useMemo<AboutTools>(
483
+ () => ({
484
+ refresh: async () => {
485
+ setVersion((count) => count + 1);
486
+ await read(() => true);
487
+ },
488
+ }),
489
+ [read],
490
+ );
491
+ // What to try again after a failure: the reading when nothing was read, the writing otherwise.
492
+ const retry = () => (data === null ? read(() => true) : write(() => true));
493
+ // A tool by the owner's words for it; one of its own code, by its name made words.
494
+ const label = (action: ActionFact) =>
495
+ action.source === "own" ? toolName(action.name) : (words.actions[action.name] ?? action.name);
496
+ const pane = (bar: ReactNode, children: ReactNode) => (
497
+ <div ref={root} className={`sc ${classes(classNames, "sc-about")}`}>
498
+ <div key={shown} data-motion={motion} className={classes(classNames, "sc-about__pane")}>
499
+ {bar}
500
+ {children}
501
+ </div>
502
+ </div>
503
+ );
504
+ const home = words.title(name);
505
+
506
+ if (view.kind === "topic" && data !== null) {
507
+ return pane(
508
+ <Bar back={home} onBack={() => go(ABOUT_HOME)} classNames={classNames} />,
509
+ <TopicView
510
+ client={client}
511
+ agentId={agentId}
512
+ name={name}
513
+ version={version}
514
+ topic={view.topic}
515
+ facts={data.facts}
516
+ apps={apps}
517
+ label={label}
518
+ words={words}
519
+ classNames={classNames}
520
+ tools={tools}
521
+ controls={controls}
522
+ onOpenFile={onOpenFile}
523
+ />,
524
+ );
525
+ }
526
+
527
+ if (view.kind === "automation") {
528
+ const fact = data?.facts.automations.find((each) => each.name === view.name);
529
+ return pane(
530
+ <Bar
531
+ back={home}
532
+ onBack={() => go(ABOUT_HOME)}
533
+ end={fact !== undefined ? controls?.automation?.(fact, tools) : undefined}
534
+ classNames={classNames}
535
+ />,
536
+ <AutomationPane
537
+ key={version}
538
+ client={client}
539
+ agentId={agentId}
540
+ name={view.name}
541
+ apps={apps}
542
+ words={words}
543
+ classNames={classNames}
544
+ onOpenRun={(run) => go({ kind: "run", name: view.name, run: run.id })}
545
+ />,
546
+ );
547
+ }
548
+
549
+ if (view.kind === "run") {
550
+ return pane(
551
+ <Bar
552
+ back={live?.find((each) => each.name === view.name)?.title ?? home}
553
+ onBack={() => go({ kind: "automation", name: view.name })}
554
+ classNames={classNames}
555
+ />,
556
+ <RunPane
557
+ key={version}
558
+ client={client}
559
+ agentId={agentId}
560
+ name={view.name}
561
+ run={view.run}
562
+ apps={apps}
563
+ words={words}
564
+ classNames={classNames}
565
+ onOpenConversation={onOpenConversation}
566
+ />,
567
+ );
568
+ }
569
+
570
+ const state = data === null ? null : aboutState(data.about, data.about_at, writing);
571
+ return pane(
572
+ null,
573
+ <>
574
+ <section aria-labelledby={intro} className={classes(classNames, "sc-about__intro")}>
575
+ <AgentName
576
+ id={intro}
577
+ agentId={agentId}
578
+ icon={icon}
579
+ name={name}
580
+ label={home}
581
+ classNames={classNames}
582
+ />
583
+ {problem !== null ? (
584
+ <Problem words={words} classNames={classNames} onRetry={retry}>
585
+ {words.failed}
586
+ {problem instanceof ApiError && ` ${problem.detail}`}
587
+ </Problem>
588
+ ) : data === null || data.about === null ? (
589
+ <Writing
590
+ text={data === null ? words.loading : words.writing(name)}
591
+ classNames={classNames}
592
+ />
593
+ ) : (
594
+ <p className={classes(classNames, "sc-about__lead")}>{data.about.summary}</p>
595
+ )}
596
+ {state === "writing" && data?.about != null && (
597
+ <p role="status" className={classes(classNames, "sc-about__updating")}>
598
+ {words.updating}
599
+ </p>
600
+ )}
601
+ </section>
602
+ {data !== null && (
603
+ <>
604
+ <Automations
605
+ apps={apps}
606
+ told={automationsOf(data.about, data.facts)}
607
+ live={live}
608
+ words={words}
609
+ classNames={classNames}
610
+ tools={tools}
611
+ controls={controls}
612
+ onOpen={(automation) => go({ kind: "automation", name: automation.name })}
613
+ />
614
+ {data.about !== null && data.about.asks.length > 0 && (
615
+ <Asks asks={data.about.asks} words={words} classNames={classNames} />
616
+ )}
617
+ <nav aria-label={words.facts} className={classes(classNames, "sc-about__menu")}>
618
+ <p className={classes(classNames, "sc-about__label")}>{words.facts}</p>
619
+ <div className={classes(classNames, "sc-about__topics")}>
620
+ {HOME_TOPICS.map((topic) => (
621
+ <TopicRow
622
+ key={topic}
623
+ topic={topic}
624
+ facts={data.facts}
625
+ apps={apps}
626
+ words={words}
627
+ classNames={classNames}
628
+ onOpen={() => go({ kind: "topic", topic })}
629
+ />
630
+ ))}
631
+ </div>
632
+ </nav>
633
+ </>
634
+ )}
635
+ </>,
636
+ );
637
+ }
638
+
639
+ /**
640
+ * What the panel's home shows the agent works with, in the order the owner looks for it: where
641
+ * people reach it, the apps it uses, what it knows, what it learned, its keys. Its tools are
642
+ * the platform's business: they show in the technical view, not here.
643
+ */
644
+ const HOME_TOPICS: readonly Topic[] = ["channels", "apps", "knowledge", "learning", "keys"];
645
+
646
+ /** How many icons a topic's row draws before "+N". */
647
+ const MOST_MARKS = 5;
648
+
649
+ /**
650
+ * A topic on the panel's home, as icons: its name, then what it holds as their logos or marks
651
+ * (the channels', the apps', the files') and how many; a topic with nothing says so, quietly.
652
+ * Pressing it opens the topic.
653
+ */
654
+ function TopicRow({
655
+ topic,
656
+ facts,
657
+ apps,
658
+ words,
659
+ classNames,
660
+ onOpen,
661
+ }: {
662
+ topic: Topic;
663
+ facts: Facts;
664
+ apps: AppDirectory | undefined;
665
+ words: AboutMessages;
666
+ classNames: ClassNames;
667
+ onOpen: () => void;
668
+ }) {
669
+ const count = countOf(topic, facts);
670
+ return (
671
+ <button
672
+ type="button"
673
+ onClick={onOpen}
674
+ data-empty={count === 0 || undefined}
675
+ className={classes(classNames, "sc-about__topic")}
676
+ >
677
+ <span className={classes(classNames, "sc-about__topic-name")}>{words.topics[topic]}</span>
678
+ {count === 0 ? (
679
+ <span className={classes(classNames, "sc-about__topic-none")}>{words.empty[topic]}</span>
680
+ ) : (
681
+ <>
682
+ <TopicMarks topic={topic} facts={facts} apps={apps} words={words} count={count} />
683
+ <span className={classes(classNames, "sc-about__topic-count")}>{count}</span>
684
+ </>
685
+ )}
686
+ <svg
687
+ viewBox="0 0 16 16"
688
+ fill="none"
689
+ aria-hidden
690
+ className={classes(classNames, "sc-about__topic-go")}
691
+ >
692
+ <path
693
+ d="M6 3.5 10.5 8 6 12.5"
694
+ stroke="currentColor"
695
+ strokeWidth="1.5"
696
+ strokeLinecap="round"
697
+ strokeLinejoin="round"
698
+ />
699
+ </svg>
700
+ </button>
701
+ );
702
+ }
703
+
704
+ /** What a topic holds, as icons: each channel's and app's logo, each file's mark; else its glyph. */
705
+ function TopicMarks({
706
+ topic,
707
+ facts,
708
+ apps,
709
+ words,
710
+ count,
711
+ }: {
712
+ topic: Topic;
713
+ facts: Facts;
714
+ apps: AppDirectory | undefined;
715
+ words: AboutMessages;
716
+ count: number;
717
+ }) {
718
+ const marks: ReactNode[] =
719
+ topic === "channels"
720
+ ? facts.channels.map((channel) => (
721
+ <span key={`${channel.kind}:${channel.name}`}>
722
+ {channelLogo(channel.kind, apps, words, 20)}
723
+ </span>
724
+ ))
725
+ : topic === "apps"
726
+ ? facts.connections.map((connection) => (
727
+ <span key={connection.name}>{appMark(connectionApp(connection), apps, 20)}</span>
728
+ ))
729
+ : topic === "knowledge"
730
+ ? facts.files.map((file) => <FileMark key={file.path} name={file.path} size={20} />)
731
+ : [<Mark key={topic} icon={TOPIC_GLYPHS[topic]} size={20} />];
732
+ const shown = marks.slice(0, MOST_MARKS);
733
+ const drawn = topic === "learning" || topic === "keys" ? 0 : count;
734
+ return <MarkStack more={Math.max(0, drawn - shown.length)}>{shown}</MarkStack>;
735
+ }
736
+
737
+ /**
738
+ * Who the panel is about, at its top: the agent's mark in its tint, bare, beside its name; the
739
+ * panel's title ("About Ana") stays for screen readers.
740
+ */
741
+ function AgentName({
742
+ id,
743
+ agentId,
744
+ icon,
745
+ name,
746
+ label,
747
+ classNames,
748
+ }: {
749
+ id: string;
750
+ agentId: string;
751
+ icon: string | null | undefined;
752
+ name: string;
753
+ label: string;
754
+ classNames: ClassNames;
755
+ }) {
756
+ const Glyph = agentGlyph(icon);
757
+ return (
758
+ <h2
759
+ id={id}
760
+ aria-label={label}
761
+ data-tint={agentTint(agentId)}
762
+ className={classes(classNames, "sc-about__name")}
763
+ >
764
+ <Glyph aria-hidden weight="duotone" />
765
+ <span>{name}</span>
766
+ </h2>
767
+ );
768
+ }
769
+
770
+ /**
771
+ * Which way the panel moved to show `view`: in (one level deeper), back out, or nowhere (the first
772
+ * view). Kept per view, so a view's own updates never replay it.
773
+ */
774
+ function useMotion(view: AboutView): "in" | "out" | undefined {
775
+ const key = keyOf(view);
776
+ const depth = depthOf(view);
777
+ const [moved, setMoved] = useState<{
778
+ key: string;
779
+ depth: number;
780
+ motion: "in" | "out" | undefined;
781
+ }>({ key, depth, motion: undefined });
782
+ if (moved.key !== key) {
783
+ setMoved({ key, depth, motion: depth >= moved.depth ? "in" : "out" });
784
+ }
785
+ return moved.motion;
786
+ }
787
+
788
+ /** The nearest box around `element` that scrolls: where the panel's place is kept. */
789
+ function scrollerOf(element: HTMLElement | null): HTMLElement | null {
790
+ for (let at = element?.parentElement ?? null; at !== null; at = at.parentElement) {
791
+ const overflow = getComputedStyle(at).overflowY;
792
+ if (overflow === "auto" || overflow === "scroll") return at;
793
+ }
794
+ return null;
795
+ }
796
+
797
+ /**
798
+ * The bar over a view opened from another: the way back to it, named, at its start; the host's
799
+ * controls at its end. It stays at the top as the view scrolls.
800
+ */
801
+ function Bar({
802
+ back,
803
+ onBack,
804
+ end,
805
+ classNames,
806
+ }: {
807
+ back: string;
808
+ onBack: () => void;
809
+ end?: ReactNode;
810
+ classNames: ClassNames;
811
+ }) {
812
+ return (
813
+ <div className={classes(classNames, "sc-about__bar")}>
814
+ <button type="button" onClick={onBack} className={classes(classNames, "sc-about__back")}>
815
+ <svg viewBox="0 0 16 16" fill="none" aria-hidden>
816
+ <path
817
+ d="M10 3.5 5.5 8l4.5 4.5"
818
+ stroke="currentColor"
819
+ strokeWidth="1.5"
820
+ strokeLinecap="round"
821
+ strokeLinejoin="round"
822
+ />
823
+ </svg>
824
+ <span>{back}</span>
825
+ </button>
826
+ {end != null && <span className={classes(classNames, "sc-about__bar-end")}>{end}</span>}
827
+ </div>
828
+ );
829
+ }
830
+
831
+ /**
832
+ * An automation, open in the panel: what starts it and when it runs next, the owner's sentence,
833
+ * its steps, the table it moves, its runs (each opening its record). Read again every few
834
+ * seconds while a run of it is under way.
835
+ */
836
+ function AutomationPane({
837
+ client,
838
+ agentId,
839
+ name,
840
+ apps,
841
+ words,
842
+ classNames,
843
+ onOpenRun,
844
+ }: Drawn & {
845
+ client: Client;
846
+ agentId: string;
847
+ name: string;
848
+ apps: AppDirectory | undefined;
849
+ onOpenRun: (run: Run) => void;
850
+ }) {
851
+ const { messages } = useKit();
852
+ const read = usePolled(
853
+ () => client.automations.get(agentId, name),
854
+ `${agentId}:${name}`,
855
+ (automation) => automation.runs.some((run) => run.status === "running"),
856
+ );
857
+ if (read.gone) return <Gone classNames={classNames}>{messages.automation.gone}</Gone>;
858
+ if (read.value === null) {
859
+ return read.problem === null ? (
860
+ <Loading words={words} classNames={classNames} />
861
+ ) : (
862
+ <Gone classNames={classNames}>{words.failed}</Gone>
863
+ );
864
+ }
865
+ return (
866
+ <Automation
867
+ className={classes(classNames, "sc-about__automation")}
868
+ automation={read.value}
869
+ runs={read.value.runs}
870
+ apps={apps}
871
+ onOpenRun={onOpenRun}
872
+ />
873
+ );
874
+ }
875
+
876
+ /**
877
+ * A run, open in the panel: how it went, step by step in words, what it opened. Read with its
878
+ * automation (its steps' order and its apps' names), again while it is under way.
879
+ */
880
+ function RunPane({
881
+ client,
882
+ agentId,
883
+ name,
884
+ run,
885
+ apps,
886
+ words,
887
+ classNames,
888
+ onOpenConversation,
889
+ }: Drawn & {
890
+ client: Client;
891
+ agentId: string;
892
+ name: string;
893
+ run: string;
894
+ apps: AppDirectory | undefined;
895
+ onOpenConversation: ((id: string) => void) | undefined;
896
+ }) {
897
+ const read = usePolled(
898
+ async () => {
899
+ const [record, automation] = await Promise.all([
900
+ client.runs.get(run),
901
+ client.automations.get(agentId, name).catch(() => null),
902
+ ]);
903
+ return { record, automation };
904
+ },
905
+ run,
906
+ ({ record }) => record.status === "running",
907
+ );
908
+ if (read.gone) return <Gone classNames={classNames}>{words.runGone}</Gone>;
909
+ if (read.value === null) {
910
+ return read.problem === null ? (
911
+ <Loading words={words} classNames={classNames} />
912
+ ) : (
913
+ <Gone classNames={classNames}>{words.failed}</Gone>
914
+ );
915
+ }
916
+ return (
917
+ <RunView
918
+ className={classes(classNames, "sc-about__run")}
919
+ run={read.value.record}
920
+ automation={read.value.automation}
921
+ apps={apps}
922
+ onOpenConversation={onOpenConversation}
923
+ />
924
+ );
925
+ }
926
+
927
+ /** A view whose thing is being read: lines with a light sweeping them. */
928
+ function Loading({ words, classNames }: Drawn) {
929
+ return <Writing text={words.loading} classNames={classNames} />;
930
+ }
931
+
932
+ /** In place of what is no longer there, or could not be read. */
933
+ function Gone({ classNames, children }: { classNames: ClassNames; children: ReactNode }) {
934
+ return <p className={classes(classNames, "sc-about__empty")}>{children}</p>;
935
+ }
936
+
937
+ /** An automation's mark says its kind: a time, a call from another system, an event. */
938
+ const KIND_ICONS: Readonly<Record<AutomationKind, Icon>> = {
939
+ schedule: "clock",
940
+ webhook: "code",
941
+ event: "bell",
942
+ };
943
+
944
+ /** An app's mark: the host's logo when it draws one, else the provider's, bare. */
945
+ function appMark(
946
+ app: { provider: string; name: string; icon?: string | null | undefined },
947
+ apps: AppDirectory | undefined,
948
+ size: number,
949
+ ) {
950
+ if (apps !== undefined) return apps.logo({ ...app, size });
951
+ return (
952
+ <Mark logo size={size}>
953
+ {providerMark(app.provider.split(":")[0] as Provider, app.icon ?? undefined)}
954
+ </Mark>
955
+ );
956
+ }
957
+
958
+ const connectionApp = (connection: ConnectionFact) => ({
959
+ provider: `${connection.provider}:${connection.toolkit ?? connection.name}`,
960
+ name: appTitle(connection),
961
+ icon: connection.icon,
962
+ });
963
+
964
+ /**
965
+ * A channel's mark: the host's logo for its brand when it draws apps (WhatsApp, Instagram, the
966
+ * plain mark of a text message), else the package's glyph, bare.
967
+ */
968
+ function channelLogo(
969
+ kind: ChannelKind,
970
+ apps: AppDirectory | undefined,
971
+ words: AboutMessages,
972
+ size: number,
973
+ ) {
974
+ if (apps !== undefined)
975
+ return apps.logo({ provider: kind, name: words.channelNames[kind], size });
976
+ return <Mark size={size}>{channelMark(kind)}</Mark>;
977
+ }
978
+
979
+ interface Drawn {
980
+ words: AboutMessages;
981
+ classNames: ClassNames;
982
+ }
983
+
984
+ /** What could not be read or written, in the warning tone, and the button to try again. */
985
+ function Problem({
986
+ words,
987
+ classNames,
988
+ onRetry,
989
+ children,
990
+ }: Drawn & { onRetry: () => Promise<void>; children: ReactNode }) {
991
+ return (
992
+ <p role="alert" className={classes(classNames, "sc-about__updated")}>
993
+ <span>{children}</span>
994
+ <button type="button" onClick={() => void onRetry()}>
995
+ {words.refresh}
996
+ </button>
997
+ </p>
998
+ );
999
+ }
1000
+
1001
+ /** The agent writing: the lead's lines with a light sweeping them, and the sentence saying so. */
1002
+ function Writing({ text, classNames }: { text: string; classNames: ClassNames }) {
1003
+ return (
1004
+ <div role="status" className={classes(classNames, "sc-about__writing")}>
1005
+ <div aria-hidden>
1006
+ <i />
1007
+ <i />
1008
+ </div>
1009
+ <p>{text}</p>
1010
+ </div>
1011
+ );
1012
+ }
1013
+
1014
+ /** What it asks leave for: its label, then the things, a short list. */
1015
+ function Asks({ asks, words, classNames }: Drawn & { asks: string[] }) {
1016
+ const id = useId();
1017
+ return (
1018
+ <section
1019
+ aria-labelledby={id}
1020
+ className={classes(classNames, "sc-about__section", "sc-about__asks")}
1021
+ >
1022
+ <div className={classes(classNames, "sc-about__label")}>
1023
+ <h3 id={id}>{words.asks}</h3>
1024
+ </div>
1025
+ <ul>
1026
+ {asks.map((ask, index) => (
1027
+ <li key={index}>{ask}</li>
1028
+ ))}
1029
+ </ul>
1030
+ </section>
1031
+ );
1032
+ }
1033
+
1034
+ /**
1035
+ * What it does on its own: one row per automation, its kind's mark (or, on an app's event, the
1036
+ * app's logo), what it does then over when, as the agent tells it (its title and its kind until
1037
+ * it has), a paused one quieter; how it stands now when that needs a look (a run under way, the
1038
+ * last one failed); the host's control at each row's end, and over them the way to a new one. A
1039
+ * row opens its automation.
1040
+ */
1041
+ function Automations({
1042
+ told,
1043
+ live,
1044
+ words,
1045
+ classNames,
1046
+ tools,
1047
+ controls,
1048
+ apps,
1049
+ onOpen,
1050
+ }: Drawn & {
1051
+ told: Told[];
1052
+ live: readonly Standing[] | null;
1053
+ tools: AboutTools;
1054
+ controls: AboutControls | undefined;
1055
+ apps: AppDirectory | undefined;
1056
+ onOpen: (automation: AutomationFact) => void;
1057
+ }) {
1058
+ const id = useId();
1059
+ const { messages } = useKit();
1060
+ const standing = new Map(live?.map((automation) => [automation.name, automation]));
1061
+ return (
1062
+ <section aria-labelledby={id} className={classes(classNames, "sc-about__section")}>
1063
+ <div className={classes(classNames, "sc-about__label")}>
1064
+ <h3 id={id}>{words.does}</h3>
1065
+ {controls?.newAutomation !== undefined && (
1066
+ <span className={classes(classNames, "sc-about__tools")}>
1067
+ {controls.newAutomation(tools)}
1068
+ </span>
1069
+ )}
1070
+ </div>
1071
+ {told.length === 0 ? (
1072
+ <p className={classes(classNames, "sc-about__empty")}>{words.noAutomations}</p>
1073
+ ) : (
1074
+ <List>
1075
+ {told.map(({ automation, line }) => {
1076
+ const when = line?.when ?? words.kinds[automation.kind];
1077
+ const now = standing.get(automation.name);
1078
+ const going = now?.last_run?.status === "running";
1079
+ return (
1080
+ <Row
1081
+ key={automation.id}
1082
+ mark={
1083
+ automation.provider === undefined ? (
1084
+ <Mark icon={GLYPHS[KIND_ICONS[automation.kind]]} />
1085
+ ) : (
1086
+ appMark(
1087
+ {
1088
+ provider: automation.provider,
1089
+ name:
1090
+ automation.app_title ?? toolName(automation.app ?? automation.provider),
1091
+ icon: automation.icon,
1092
+ },
1093
+ apps,
1094
+ 28,
1095
+ )
1096
+ )
1097
+ }
1098
+ title={line?.text ?? automation.title}
1099
+ subtitle={when}
1100
+ error={now?.state === "failing" ? messages.automation.states.failing : undefined}
1101
+ meta={
1102
+ going ? (
1103
+ <Tag tone="info">
1104
+ <i aria-hidden className={classes(classNames, "sc-run__live")} />
1105
+ {messages.automation.statuses.running}
1106
+ </Tag>
1107
+ ) : automation.on ? undefined : (
1108
+ <Tag>{words.paused}</Tag>
1109
+ )
1110
+ }
1111
+ quiet={!automation.on}
1112
+ onPress={() => onOpen(automation)}
1113
+ trailing={controls?.automation?.(automation, tools)}
1114
+ />
1115
+ );
1116
+ })}
1117
+ </List>
1118
+ )}
1119
+ {controls?.automationsNote?.(tools)}
1120
+ </section>
1121
+ );
1122
+ }
1123
+
1124
+ /**
1125
+ * One topic, open: its name with its count and the host's control, a line saying what it is, then
1126
+ * its rows (what it knows as its files and its tables; what it learned; the rest with a mark and
1127
+ * a note), or its one line when it holds nothing.
1128
+ */
1129
+ function TopicView({
1130
+ client,
1131
+ agentId,
1132
+ name,
1133
+ version,
1134
+ topic,
1135
+ facts,
1136
+ apps,
1137
+ label,
1138
+ words,
1139
+ classNames,
1140
+ tools,
1141
+ controls,
1142
+ onOpenFile,
1143
+ }: Drawn & {
1144
+ client: Client;
1145
+ agentId: string;
1146
+ /** The agent's name, over what is its own. */
1147
+ name: string;
1148
+ /** Moves with every change the host makes: what the topic reads itself, it reads again. */
1149
+ version: number;
1150
+ topic: Topic;
1151
+ facts: Facts;
1152
+ apps: AppDirectory | undefined;
1153
+ label: (action: ActionFact) => string;
1154
+ tools: AboutTools;
1155
+ controls: AboutControls | undefined;
1156
+ onOpenFile: ((file: FileFact) => void) | undefined;
1157
+ }) {
1158
+ const id = useId();
1159
+ const tool = controls?.topic?.[topic];
1160
+ const count = countOf(topic, facts);
1161
+ // The tools are all listed, the ones that are off too: they are what the owner turns on.
1162
+ const shown = topic === "tools" ? facts.actions.length : count;
1163
+ return (
1164
+ <section aria-labelledby={id} className={classes(classNames, "sc-about__group")}>
1165
+ <h3 id={id} className={classes(classNames, "sc-about__title")}>
1166
+ <span>{words.topics[topic]}</span>
1167
+ {count > 0 && <b className={classes(classNames, "sc-about__count")}>{count}</b>}
1168
+ {tool !== undefined && (
1169
+ <span className={classes(classNames, "sc-about__tools")}>{tool(tools)}</span>
1170
+ )}
1171
+ </h3>
1172
+ <p className={classes(classNames, "sc-about__hint")}>{words.hints[topic]}</p>
1173
+ {topic === "channels" ? (
1174
+ <Channels
1175
+ client={client}
1176
+ agentId={agentId}
1177
+ version={version}
1178
+ facts={facts}
1179
+ apps={apps}
1180
+ words={words}
1181
+ classNames={classNames}
1182
+ tools={tools}
1183
+ controls={controls}
1184
+ />
1185
+ ) : shown === 0 ? (
1186
+ <p className={classes(classNames, "sc-about__empty")}>{words.empty[topic]}</p>
1187
+ ) : topic === "knowledge" ? (
1188
+ <Knowledge
1189
+ name={name}
1190
+ facts={facts}
1191
+ words={words}
1192
+ classNames={classNames}
1193
+ tools={tools}
1194
+ controls={controls}
1195
+ onOpenFile={onOpenFile}
1196
+ />
1197
+ ) : topic === "tools" ? (
1198
+ <Tools
1199
+ name={name}
1200
+ facts={facts}
1201
+ label={label}
1202
+ words={words}
1203
+ classNames={classNames}
1204
+ tools={tools}
1205
+ controls={controls}
1206
+ />
1207
+ ) : topic === "keys" ? (
1208
+ <Keys
1209
+ name={name}
1210
+ facts={facts}
1211
+ words={words}
1212
+ classNames={classNames}
1213
+ tools={tools}
1214
+ controls={controls}
1215
+ />
1216
+ ) : topic === "learning" ? (
1217
+ <List>
1218
+ {facts.memories.map((memory) => (
1219
+ <Row
1220
+ key={memory.id}
1221
+ className={classes(classNames, "sc-about__memory")}
1222
+ title={memory.text}
1223
+ subtitle={words.ago(new Date(memory.created_at))}
1224
+ trailing={controls?.memory?.(memory, tools)}
1225
+ />
1226
+ ))}
1227
+ </List>
1228
+ ) : (
1229
+ <Rows items={appItems(facts, tools, controls, apps)} classNames={classNames} />
1230
+ )}
1231
+ </section>
1232
+ );
1233
+ }
1234
+
1235
+ /** How each state of a channel reads beside its dot: working, waiting, broken, or off. */
1236
+ const CHANNEL_TONES: Readonly<Record<ChannelStatus, StatusTone | "wait">> = {
1237
+ active: "on",
1238
+ pending: "wait",
1239
+ error: "off",
1240
+ disconnected: "quiet",
1241
+ };
1242
+
1243
+ const isStatus = (status: string): status is ChannelStatus => status in CHANNEL_TONES;
1244
+
1245
+ /** The order channels are listed in: by kind, as people reach a business most; disconnected last. */
1246
+ const KIND_ORDER: readonly ChannelKind[] = [
1247
+ "whatsapp",
1248
+ "instagram",
1249
+ "sms",
1250
+ "email",
1251
+ "web",
1252
+ "phone",
1253
+ ];
1254
+
1255
+ const inOrder = (channels: readonly Channel[]): Channel[] =>
1256
+ [...channels].sort(
1257
+ (a, b) =>
1258
+ Number(a.status === "disconnected") - Number(b.status === "disconnected") ||
1259
+ KIND_ORDER.indexOf(a.kind) - KIND_ORDER.indexOf(b.kind),
1260
+ );
1261
+
1262
+ /**
1263
+ * Where it works: each channel it answers, as the API lists them (WhatsApp, Instagram, SMS; the
1264
+ * disconnected ones last, quieter), by its brand's mark and name, its number or handle, how it stands with the
1265
+ * provider's word on it, and the host's control at its end; then the devices it uses. Read
1266
+ * when the topic opens and after each change the host makes; until then, or on a server without
1267
+ * the list, the facts' rows.
1268
+ */
1269
+ function Channels({
1270
+ client,
1271
+ agentId,
1272
+ version,
1273
+ facts,
1274
+ apps,
1275
+ words,
1276
+ classNames,
1277
+ tools,
1278
+ controls,
1279
+ }: Drawn & {
1280
+ client: Client;
1281
+ agentId: string;
1282
+ version: number;
1283
+ facts: Facts;
1284
+ apps: AppDirectory | undefined;
1285
+ tools: AboutTools;
1286
+ controls: AboutControls | undefined;
1287
+ }) {
1288
+ const [listed, setListed] = useState<readonly Channel[] | null>(null);
1289
+ useEffect(() => {
1290
+ let gone = false;
1291
+ client.channels.list(agentId).then(
1292
+ (channels) => {
1293
+ if (!gone) setListed(channels);
1294
+ },
1295
+ () => undefined,
1296
+ );
1297
+ return () => {
1298
+ gone = true;
1299
+ };
1300
+ }, [client, agentId, version]);
1301
+
1302
+ const state = (status: string) => {
1303
+ const known = isStatus(status);
1304
+ return (
1305
+ <span
1306
+ data-tone={known ? CHANNEL_TONES[status] : toneOf(status)}
1307
+ className={classes(classNames, "sc-about__state")}
1308
+ >
1309
+ <i aria-hidden className={classes(classNames, "sc-about__dot")} />
1310
+ {known ? words.channelStates[status] : status}
1311
+ </span>
1312
+ );
1313
+ };
1314
+ // Its number or handle, and under it the provider's word on it; on an error, that word is why.
1315
+ const told = (channel: Channel) => {
1316
+ const detail = channel.detail === null ? null : words.channelDetail(channel.detail);
1317
+ const error = channel.status === "error";
1318
+ return {
1319
+ subtitle: (
1320
+ <>
1321
+ {channel.name}
1322
+ {!error && detail !== null && detail !== "" && (
1323
+ <span className={classes(classNames, "sc-about__detail")}>{detail}</span>
1324
+ )}
1325
+ </>
1326
+ ),
1327
+ error: error ? (detail ?? undefined) : undefined,
1328
+ };
1329
+ };
1330
+ const rows =
1331
+ listed === null
1332
+ ? facts.channels.map((channel: ChannelFact) => (
1333
+ <Row
1334
+ key={`${channel.kind}:${channel.name}`}
1335
+ mark={channelLogo(channel.kind, apps, words, 28)}
1336
+ title={words.channelNames[channel.kind]}
1337
+ subtitle={channel.name}
1338
+ meta={state(channel.status)}
1339
+ />
1340
+ ))
1341
+ : inOrder(listed).map((channel) => (
1342
+ <Row
1343
+ key={channel.id}
1344
+ mark={channelLogo(channel.kind, apps, words, 28)}
1345
+ title={words.channelNames[channel.kind]}
1346
+ {...told(channel)}
1347
+ meta={state(channel.status)}
1348
+ quiet={channel.status === "disconnected"}
1349
+ trailing={controls?.channel?.(channel, tools) ?? undefined}
1350
+ />
1351
+ ));
1352
+ const devices = facts.devices.map((device) => (
1353
+ <Row
1354
+ key={`device:${device.kind}:${device.name}`}
1355
+ mark={<Mark>{deviceMark(device.kind)}</Mark>}
1356
+ title={device.name}
1357
+ meta={
1358
+ <i
1359
+ aria-hidden
1360
+ data-tone={toneOf(device.status)}
1361
+ className={classes(classNames, "sc-about__dot")}
1362
+ />
1363
+ }
1364
+ />
1365
+ ));
1366
+ if (rows.length + devices.length === 0) {
1367
+ return <p className={classes(classNames, "sc-about__empty")}>{words.empty.channels}</p>;
1368
+ }
1369
+ return (
1370
+ <List>
1371
+ {rows}
1372
+ {devices}
1373
+ </List>
1374
+ );
1375
+ }
1376
+
1377
+ /**
1378
+ * One row of a topic: a mark, a name, a quieter line (what an app may do there, a note), a dot
1379
+ * for a status, and the host's control at its end.
1380
+ */
1381
+ interface Item {
1382
+ key: string;
1383
+ mark: ReactNode;
1384
+ label: string;
1385
+ note?: string | undefined;
1386
+ status?: StatusTone | undefined;
1387
+ off?: boolean | undefined;
1388
+ control?: ReactNode;
1389
+ }
1390
+
1391
+ /** Its apps: each by its logo and name, what it may do there under it, how it stands at its end. */
1392
+ function appItems(
1393
+ facts: Facts,
1394
+ tools: AboutTools,
1395
+ controls: AboutControls | undefined,
1396
+ apps: AppDirectory | undefined,
1397
+ ): Item[] {
1398
+ return facts.connections.map((connection) => ({
1399
+ key: `${connection.provider}:${connection.name}`,
1400
+ mark: appMark(connectionApp(connection), apps, 28),
1401
+ label: appTitle(connection),
1402
+ note: connection.actions.map((action) => toolTitle(connection, action)).join(", "),
1403
+ status: connection.status === undefined ? undefined : toneOf(connection.status),
1404
+ control: controls?.app?.(connection, tools),
1405
+ }));
1406
+ }
1407
+
1408
+ /**
1409
+ * What it can do while it talks: its own code's actions, then the ones every agent comes with
1410
+ * (each under its heading when it has both); in each, the ones it has first, then the ones the
1411
+ * owner can turn on, quieter, saying so.
1412
+ */
1413
+ function Tools({
1414
+ name,
1415
+ facts,
1416
+ label,
1417
+ words,
1418
+ classNames,
1419
+ tools,
1420
+ controls,
1421
+ }: Drawn & {
1422
+ name: string;
1423
+ facts: Facts;
1424
+ label: (action: ActionFact) => string;
1425
+ tools: AboutTools;
1426
+ controls: AboutControls | undefined;
1427
+ }) {
1428
+ const groups = [
1429
+ { key: "own", title: words.theirs(name), actions: facts.actions.filter(isOwn) },
1430
+ { key: "built", title: words.builtIn, actions: facts.actions.filter((a) => !isOwn(a)) },
1431
+ ].filter((group) => group.actions.length > 0);
1432
+ const rows = (actions: readonly ActionFact[]) => (
1433
+ <Rows
1434
+ items={[...actions.filter((a) => a.on), ...actions.filter((a) => !a.on)].map((action) => ({
1435
+ key: `${action.source}:${action.name}`,
1436
+ mark: <Mark>{actionMark(action.name, action.source)}</Mark>,
1437
+ label: label(action),
1438
+ note: action.on ? undefined : words.off,
1439
+ off: !action.on,
1440
+ control: controls?.tool?.(action, tools),
1441
+ }))}
1442
+ classNames={classNames}
1443
+ />
1444
+ );
1445
+ if (groups.length === 1) return rows(groups[0]?.actions ?? []);
1446
+ return (
1447
+ <>
1448
+ {groups.map((group) => (
1449
+ <Group key={group.key} title={group.title} classNames={classNames}>
1450
+ {rows(group.actions)}
1451
+ </Group>
1452
+ ))}
1453
+ </>
1454
+ );
1455
+ }
1456
+
1457
+ const isOwn = (action: ActionFact): boolean => action.source === "own";
1458
+
1459
+ /** A part of a topic under its small heading: whose things they are, or what kind. */
1460
+ function Group({
1461
+ title,
1462
+ classNames,
1463
+ children,
1464
+ }: {
1465
+ title: string;
1466
+ classNames: ClassNames;
1467
+ children: ReactNode;
1468
+ }) {
1469
+ return (
1470
+ <>
1471
+ <h4 className={classes(classNames, "sc-about__subtitle")}>{title}</h4>
1472
+ {children}
1473
+ </>
1474
+ );
1475
+ }
1476
+
1477
+ /** What is the agent's own, then the organization's: the heading says whose, once. */
1478
+ function byOwner<T extends { shared?: boolean | undefined }>(
1479
+ things: readonly T[],
1480
+ name: string,
1481
+ words: AboutMessages,
1482
+ ): { key: string; title: string; things: T[] }[] {
1483
+ return [
1484
+ { key: "own", title: words.theirs(name), things: things.filter((thing) => !thing.shared) },
1485
+ {
1486
+ key: "shared",
1487
+ title: words.organization,
1488
+ things: things.filter((thing) => thing.shared === true),
1489
+ },
1490
+ ].filter((group) => group.things.length > 0);
1491
+ }
1492
+
1493
+ /**
1494
+ * What it knows, by whose it is: its own files, then the organization's (shared with every
1495
+ * agent: the heading says so, once), then the tables it reads or writes. A file is its kind's
1496
+ * mark, its name on one line, its folder under it (and that it is only kept, when `search_files`
1497
+ * does not read it), its size at the right; pressed, the host opens it; the host's controls at
1498
+ * its end.
1499
+ */
1500
+ function Knowledge({
1501
+ name,
1502
+ facts,
1503
+ words,
1504
+ classNames,
1505
+ tools,
1506
+ controls,
1507
+ onOpenFile,
1508
+ }: Drawn & {
1509
+ name: string;
1510
+ facts: Facts;
1511
+ tools: AboutTools;
1512
+ controls: AboutControls | undefined;
1513
+ onOpenFile: ((file: FileFact) => void) | undefined;
1514
+ }) {
1515
+ return (
1516
+ <>
1517
+ {byOwner(facts.files, name, words).map((group) => (
1518
+ <Group key={group.key} title={group.title} classNames={classNames}>
1519
+ <List>
1520
+ {group.things.map((file) => (
1521
+ <Row
1522
+ key={file.path}
1523
+ className={classes(classNames, "sc-about__file")}
1524
+ mark={<FileMark name={file.path} />}
1525
+ title={<span title={file.path}>{baseName(file.path)}</span>}
1526
+ subtitle={fileLine(file, words)}
1527
+ meta={words.size(file.size)}
1528
+ onPress={onOpenFile && (() => onOpenFile(file))}
1529
+ trailing={controls?.file?.(file, tools) ?? undefined}
1530
+ />
1531
+ ))}
1532
+ </List>
1533
+ </Group>
1534
+ ))}
1535
+ {facts.data.length > 0 && (
1536
+ <Group title={words.tables} classNames={classNames}>
1537
+ <Rows
1538
+ items={facts.data.map((table) => ({
1539
+ key: table.table,
1540
+ mark: <Mark icon={GLYPHS.table} />,
1541
+ label: table.title ?? table.table,
1542
+ note: table.can.map((can) => words.can[can] ?? can).join(", "),
1543
+ control: controls?.table?.(table, tools),
1544
+ }))}
1545
+ classNames={classNames}
1546
+ />
1547
+ </Group>
1548
+ )}
1549
+ </>
1550
+ );
1551
+ }
1552
+
1553
+ /** Under a file's name: its folder, and that it is only kept when nothing reads it at a search. */
1554
+ function fileLine(file: FileFact, words: AboutMessages): string | undefined {
1555
+ const folder = folderOf(file.path);
1556
+ if (file.searchable) return folder === "" ? undefined : folder;
1557
+ return folder === "" ? words.kept : `${folder} · ${words.kept}`;
1558
+ }
1559
+
1560
+ /** Its keys, its own then the organization's, each with where it may be sent. */
1561
+ function Keys({
1562
+ name,
1563
+ facts,
1564
+ words,
1565
+ classNames,
1566
+ tools,
1567
+ controls,
1568
+ }: Drawn & {
1569
+ name: string;
1570
+ facts: Facts;
1571
+ tools: AboutTools;
1572
+ controls: AboutControls | undefined;
1573
+ }) {
1574
+ return (
1575
+ <>
1576
+ {byOwner(facts.vault, name, words).map((group) => (
1577
+ <Group key={group.key} title={group.title} classNames={classNames}>
1578
+ <Rows
1579
+ items={group.things.map((secret) => ({
1580
+ key: `${group.key}:${secret.name}`,
1581
+ mark: <Mark icon={GLYPHS.lock} />,
1582
+ label: secret.name,
1583
+ note: secret.hosts?.join(", "),
1584
+ control: controls?.key?.(secret, tools),
1585
+ }))}
1586
+ classNames={classNames}
1587
+ />
1588
+ </Group>
1589
+ ))}
1590
+ </>
1591
+ );
1592
+ }
1593
+
1594
+ /** The folders a file sits in: "" for one at the top. */
1595
+ const folderOf = (path: string): string => path.slice(0, Math.max(0, path.lastIndexOf("/")));
1596
+
1597
+ function Rows({ items, classNames }: { items: Item[]; classNames: ClassNames }) {
1598
+ return (
1599
+ <List>
1600
+ {items.map((item) => (
1601
+ <Row
1602
+ key={item.key}
1603
+ mark={item.mark}
1604
+ title={item.label}
1605
+ subtitle={item.note === undefined || item.note === "" ? undefined : item.note}
1606
+ meta={
1607
+ item.status === undefined ? undefined : (
1608
+ <i
1609
+ aria-hidden
1610
+ data-tone={item.status}
1611
+ className={classes(classNames, "sc-about__dot")}
1612
+ />
1613
+ )
1614
+ }
1615
+ quiet={item.off}
1616
+ trailing={item.control ?? undefined}
1617
+ />
1618
+ ))}
1619
+ </List>
1620
+ );
1621
+ }