@draht/web-ui 2026.3.2-2

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 (372) hide show
  1. package/CHANGELOG.md +276 -0
  2. package/README.md +601 -0
  3. package/dist/ChatPanel.d.ts +28 -0
  4. package/dist/ChatPanel.d.ts.map +1 -0
  5. package/dist/ChatPanel.js +193 -0
  6. package/dist/ChatPanel.js.map +1 -0
  7. package/dist/app.css +2 -0
  8. package/dist/components/AgentInterface.d.ts +39 -0
  9. package/dist/components/AgentInterface.d.ts.map +1 -0
  10. package/dist/components/AgentInterface.js +384 -0
  11. package/dist/components/AgentInterface.js.map +1 -0
  12. package/dist/components/AttachmentTile.d.ts +12 -0
  13. package/dist/components/AttachmentTile.d.ts.map +1 -0
  14. package/dist/components/AttachmentTile.js +110 -0
  15. package/dist/components/AttachmentTile.js.map +1 -0
  16. package/dist/components/ConsoleBlock.d.ts +12 -0
  17. package/dist/components/ConsoleBlock.d.ts.map +1 -0
  18. package/dist/components/ConsoleBlock.js +81 -0
  19. package/dist/components/ConsoleBlock.js.map +1 -0
  20. package/dist/components/CustomProviderCard.d.ts +17 -0
  21. package/dist/components/CustomProviderCard.d.ts.map +1 -0
  22. package/dist/components/CustomProviderCard.js +112 -0
  23. package/dist/components/CustomProviderCard.js.map +1 -0
  24. package/dist/components/ExpandableSection.d.ts +15 -0
  25. package/dist/components/ExpandableSection.d.ts.map +1 -0
  26. package/dist/components/ExpandableSection.js +61 -0
  27. package/dist/components/ExpandableSection.js.map +1 -0
  28. package/dist/components/Input.d.ts +26 -0
  29. package/dist/components/Input.d.ts.map +1 -0
  30. package/dist/components/Input.js +57 -0
  31. package/dist/components/Input.js.map +1 -0
  32. package/dist/components/MessageEditor.d.ts +44 -0
  33. package/dist/components/MessageEditor.d.ts.map +1 -0
  34. package/dist/components/MessageEditor.js +418 -0
  35. package/dist/components/MessageEditor.js.map +1 -0
  36. package/dist/components/MessageList.d.ts +14 -0
  37. package/dist/components/MessageList.d.ts.map +1 -0
  38. package/dist/components/MessageList.js +104 -0
  39. package/dist/components/MessageList.js.map +1 -0
  40. package/dist/components/Messages.d.ts +95 -0
  41. package/dist/components/Messages.d.ts.map +1 -0
  42. package/dist/components/Messages.js +363 -0
  43. package/dist/components/Messages.js.map +1 -0
  44. package/dist/components/ProviderKeyInput.d.ts +16 -0
  45. package/dist/components/ProviderKeyInput.d.ts.map +1 -0
  46. package/dist/components/ProviderKeyInput.js +168 -0
  47. package/dist/components/ProviderKeyInput.js.map +1 -0
  48. package/dist/components/SandboxedIframe.d.ts +85 -0
  49. package/dist/components/SandboxedIframe.d.ts.map +1 -0
  50. package/dist/components/SandboxedIframe.js +518 -0
  51. package/dist/components/SandboxedIframe.js.map +1 -0
  52. package/dist/components/StreamingMessageContainer.d.ts +19 -0
  53. package/dist/components/StreamingMessageContainer.d.ts.map +1 -0
  54. package/dist/components/StreamingMessageContainer.js +117 -0
  55. package/dist/components/StreamingMessageContainer.js.map +1 -0
  56. package/dist/components/ThinkingBlock.d.ts +11 -0
  57. package/dist/components/ThinkingBlock.d.ts.map +1 -0
  58. package/dist/components/ThinkingBlock.js +56 -0
  59. package/dist/components/ThinkingBlock.js.map +1 -0
  60. package/dist/components/message-renderer-registry.d.ts +12 -0
  61. package/dist/components/message-renderer-registry.d.ts.map +1 -0
  62. package/dist/components/message-renderer-registry.js +12 -0
  63. package/dist/components/message-renderer-registry.js.map +1 -0
  64. package/dist/components/sandbox/ArtifactsRuntimeProvider.d.ts +35 -0
  65. package/dist/components/sandbox/ArtifactsRuntimeProvider.d.ts.map +1 -0
  66. package/dist/components/sandbox/ArtifactsRuntimeProvider.js +192 -0
  67. package/dist/components/sandbox/ArtifactsRuntimeProvider.js.map +1 -0
  68. package/dist/components/sandbox/AttachmentsRuntimeProvider.d.ts +17 -0
  69. package/dist/components/sandbox/AttachmentsRuntimeProvider.d.ts.map +1 -0
  70. package/dist/components/sandbox/AttachmentsRuntimeProvider.js +65 -0
  71. package/dist/components/sandbox/AttachmentsRuntimeProvider.js.map +1 -0
  72. package/dist/components/sandbox/ConsoleRuntimeProvider.d.ts +42 -0
  73. package/dist/components/sandbox/ConsoleRuntimeProvider.d.ts.map +1 -0
  74. package/dist/components/sandbox/ConsoleRuntimeProvider.js +159 -0
  75. package/dist/components/sandbox/ConsoleRuntimeProvider.js.map +1 -0
  76. package/dist/components/sandbox/FileDownloadRuntimeProvider.d.ts +30 -0
  77. package/dist/components/sandbox/FileDownloadRuntimeProvider.d.ts.map +1 -0
  78. package/dist/components/sandbox/FileDownloadRuntimeProvider.js +95 -0
  79. package/dist/components/sandbox/FileDownloadRuntimeProvider.js.map +1 -0
  80. package/dist/components/sandbox/RuntimeMessageBridge.d.ts +19 -0
  81. package/dist/components/sandbox/RuntimeMessageBridge.d.ts.map +1 -0
  82. package/dist/components/sandbox/RuntimeMessageBridge.js +74 -0
  83. package/dist/components/sandbox/RuntimeMessageBridge.js.map +1 -0
  84. package/dist/components/sandbox/RuntimeMessageRouter.d.ts +65 -0
  85. package/dist/components/sandbox/RuntimeMessageRouter.d.ts.map +1 -0
  86. package/dist/components/sandbox/RuntimeMessageRouter.js +166 -0
  87. package/dist/components/sandbox/RuntimeMessageRouter.js.map +1 -0
  88. package/dist/components/sandbox/SandboxRuntimeProvider.d.ts +48 -0
  89. package/dist/components/sandbox/SandboxRuntimeProvider.d.ts.map +1 -0
  90. package/dist/components/sandbox/SandboxRuntimeProvider.js +2 -0
  91. package/dist/components/sandbox/SandboxRuntimeProvider.js.map +1 -0
  92. package/dist/dialogs/ApiKeyPromptDialog.d.ts +15 -0
  93. package/dist/dialogs/ApiKeyPromptDialog.d.ts.map +1 -0
  94. package/dist/dialogs/ApiKeyPromptDialog.js +77 -0
  95. package/dist/dialogs/ApiKeyPromptDialog.js.map +1 -0
  96. package/dist/dialogs/AttachmentOverlay.d.ts +32 -0
  97. package/dist/dialogs/AttachmentOverlay.d.ts.map +1 -0
  98. package/dist/dialogs/AttachmentOverlay.js +576 -0
  99. package/dist/dialogs/AttachmentOverlay.js.map +1 -0
  100. package/dist/dialogs/CustomProviderDialog.d.ts +25 -0
  101. package/dist/dialogs/CustomProviderDialog.d.ts.map +1 -0
  102. package/dist/dialogs/CustomProviderDialog.js +270 -0
  103. package/dist/dialogs/CustomProviderDialog.js.map +1 -0
  104. package/dist/dialogs/ModelSelector.d.ts +27 -0
  105. package/dist/dialogs/ModelSelector.d.ts.map +1 -0
  106. package/dist/dialogs/ModelSelector.js +320 -0
  107. package/dist/dialogs/ModelSelector.js.map +1 -0
  108. package/dist/dialogs/PersistentStorageDialog.d.ts +17 -0
  109. package/dist/dialogs/PersistentStorageDialog.d.ts.map +1 -0
  110. package/dist/dialogs/PersistentStorageDialog.js +144 -0
  111. package/dist/dialogs/PersistentStorageDialog.js.map +1 -0
  112. package/dist/dialogs/ProvidersModelsTab.d.ts +20 -0
  113. package/dist/dialogs/ProvidersModelsTab.d.ts.map +1 -0
  114. package/dist/dialogs/ProvidersModelsTab.js +188 -0
  115. package/dist/dialogs/ProvidersModelsTab.js.map +1 -0
  116. package/dist/dialogs/SessionListDialog.d.ts +19 -0
  117. package/dist/dialogs/SessionListDialog.d.ts.map +1 -0
  118. package/dist/dialogs/SessionListDialog.js +152 -0
  119. package/dist/dialogs/SessionListDialog.js.map +1 -0
  120. package/dist/dialogs/SettingsDialog.d.ts +30 -0
  121. package/dist/dialogs/SettingsDialog.d.ts.map +1 -0
  122. package/dist/dialogs/SettingsDialog.js +222 -0
  123. package/dist/dialogs/SettingsDialog.js.map +1 -0
  124. package/dist/index.d.ts +67 -0
  125. package/dist/index.d.ts.map +1 -0
  126. package/dist/index.js +70 -0
  127. package/dist/index.js.map +1 -0
  128. package/dist/prompts/prompts.d.ts +11 -0
  129. package/dist/prompts/prompts.d.ts.map +1 -0
  130. package/dist/prompts/prompts.js +272 -0
  131. package/dist/prompts/prompts.js.map +1 -0
  132. package/dist/storage/app-storage.d.ts +33 -0
  133. package/dist/storage/app-storage.d.ts.map +1 -0
  134. package/dist/storage/app-storage.js +43 -0
  135. package/dist/storage/app-storage.js.map +1 -0
  136. package/dist/storage/backends/indexeddb-storage-backend.d.ts +27 -0
  137. package/dist/storage/backends/indexeddb-storage-backend.d.ts.map +1 -0
  138. package/dist/storage/backends/indexeddb-storage-backend.js +167 -0
  139. package/dist/storage/backends/indexeddb-storage-backend.js.map +1 -0
  140. package/dist/storage/store.d.ts +23 -0
  141. package/dist/storage/store.d.ts.map +1 -0
  142. package/dist/storage/store.js +24 -0
  143. package/dist/storage/store.js.map +1 -0
  144. package/dist/storage/stores/custom-providers-store.d.ts +25 -0
  145. package/dist/storage/stores/custom-providers-store.d.ts.map +1 -0
  146. package/dist/storage/stores/custom-providers-store.js +35 -0
  147. package/dist/storage/stores/custom-providers-store.js.map +1 -0
  148. package/dist/storage/stores/provider-keys-store.d.ts +14 -0
  149. package/dist/storage/stores/provider-keys-store.d.ts.map +1 -0
  150. package/dist/storage/stores/provider-keys-store.js +27 -0
  151. package/dist/storage/stores/provider-keys-store.js.map +1 -0
  152. package/dist/storage/stores/sessions-store.d.ts +32 -0
  153. package/dist/storage/stores/sessions-store.d.ts.map +1 -0
  154. package/dist/storage/stores/sessions-store.js +113 -0
  155. package/dist/storage/stores/sessions-store.js.map +1 -0
  156. package/dist/storage/stores/settings-store.d.ts +14 -0
  157. package/dist/storage/stores/settings-store.d.ts.map +1 -0
  158. package/dist/storage/stores/settings-store.js +28 -0
  159. package/dist/storage/stores/settings-store.js.map +1 -0
  160. package/dist/storage/types.d.ts +176 -0
  161. package/dist/storage/types.d.ts.map +1 -0
  162. package/dist/storage/types.js +2 -0
  163. package/dist/storage/types.js.map +1 -0
  164. package/dist/tools/artifacts/ArtifactElement.d.ts +9 -0
  165. package/dist/tools/artifacts/ArtifactElement.d.ts.map +1 -0
  166. package/dist/tools/artifacts/ArtifactElement.js +8 -0
  167. package/dist/tools/artifacts/ArtifactElement.js.map +1 -0
  168. package/dist/tools/artifacts/ArtifactPill.d.ts +4 -0
  169. package/dist/tools/artifacts/ArtifactPill.d.ts.map +1 -0
  170. package/dist/tools/artifacts/ArtifactPill.js +23 -0
  171. package/dist/tools/artifacts/ArtifactPill.js.map +1 -0
  172. package/dist/tools/artifacts/Console.d.ts +18 -0
  173. package/dist/tools/artifacts/Console.d.ts.map +1 -0
  174. package/dist/tools/artifacts/Console.js +92 -0
  175. package/dist/tools/artifacts/Console.js.map +1 -0
  176. package/dist/tools/artifacts/DocxArtifact.d.ts +22 -0
  177. package/dist/tools/artifacts/DocxArtifact.d.ts.map +1 -0
  178. package/dist/tools/artifacts/DocxArtifact.js +205 -0
  179. package/dist/tools/artifacts/DocxArtifact.js.map +1 -0
  180. package/dist/tools/artifacts/ExcelArtifact.d.ts +24 -0
  181. package/dist/tools/artifacts/ExcelArtifact.d.ts.map +1 -0
  182. package/dist/tools/artifacts/ExcelArtifact.js +213 -0
  183. package/dist/tools/artifacts/ExcelArtifact.js.map +1 -0
  184. package/dist/tools/artifacts/GenericArtifact.d.ts +19 -0
  185. package/dist/tools/artifacts/GenericArtifact.d.ts.map +1 -0
  186. package/dist/tools/artifacts/GenericArtifact.js +114 -0
  187. package/dist/tools/artifacts/GenericArtifact.js.map +1 -0
  188. package/dist/tools/artifacts/HtmlArtifact.d.ts +27 -0
  189. package/dist/tools/artifacts/HtmlArtifact.d.ts.map +1 -0
  190. package/dist/tools/artifacts/HtmlArtifact.js +187 -0
  191. package/dist/tools/artifacts/HtmlArtifact.js.map +1 -0
  192. package/dist/tools/artifacts/ImageArtifact.d.ts +20 -0
  193. package/dist/tools/artifacts/ImageArtifact.d.ts.map +1 -0
  194. package/dist/tools/artifacts/ImageArtifact.js +117 -0
  195. package/dist/tools/artifacts/ImageArtifact.js.map +1 -0
  196. package/dist/tools/artifacts/MarkdownArtifact.d.ts +19 -0
  197. package/dist/tools/artifacts/MarkdownArtifact.d.ts.map +1 -0
  198. package/dist/tools/artifacts/MarkdownArtifact.js +79 -0
  199. package/dist/tools/artifacts/MarkdownArtifact.js.map +1 -0
  200. package/dist/tools/artifacts/PdfArtifact.d.ts +25 -0
  201. package/dist/tools/artifacts/PdfArtifact.d.ts.map +1 -0
  202. package/dist/tools/artifacts/PdfArtifact.js +181 -0
  203. package/dist/tools/artifacts/PdfArtifact.js.map +1 -0
  204. package/dist/tools/artifacts/SvgArtifact.d.ts +18 -0
  205. package/dist/tools/artifacts/SvgArtifact.d.ts.map +1 -0
  206. package/dist/tools/artifacts/SvgArtifact.js +75 -0
  207. package/dist/tools/artifacts/SvgArtifact.js.map +1 -0
  208. package/dist/tools/artifacts/TextArtifact.d.ts +19 -0
  209. package/dist/tools/artifacts/TextArtifact.d.ts.map +1 -0
  210. package/dist/tools/artifacts/TextArtifact.js +141 -0
  211. package/dist/tools/artifacts/TextArtifact.js.map +1 -0
  212. package/dist/tools/artifacts/artifacts-tool-renderer.d.ts +11 -0
  213. package/dist/tools/artifacts/artifacts-tool-renderer.d.ts.map +1 -0
  214. package/dist/tools/artifacts/artifacts-tool-renderer.js +273 -0
  215. package/dist/tools/artifacts/artifacts-tool-renderer.js.map +1 -0
  216. package/dist/tools/artifacts/artifacts.d.ts +63 -0
  217. package/dist/tools/artifacts/artifacts.d.ts.map +1 -0
  218. package/dist/tools/artifacts/artifacts.js +664 -0
  219. package/dist/tools/artifacts/artifacts.js.map +1 -0
  220. package/dist/tools/artifacts/index.d.ts +8 -0
  221. package/dist/tools/artifacts/index.d.ts.map +1 -0
  222. package/dist/tools/artifacts/index.js +8 -0
  223. package/dist/tools/artifacts/index.js.map +1 -0
  224. package/dist/tools/extract-document.d.ts +24 -0
  225. package/dist/tools/extract-document.d.ts.map +1 -0
  226. package/dist/tools/extract-document.js +216 -0
  227. package/dist/tools/extract-document.js.map +1 -0
  228. package/dist/tools/index.d.ts +16 -0
  229. package/dist/tools/index.d.ts.map +1 -0
  230. package/dist/tools/index.js +33 -0
  231. package/dist/tools/index.js.map +1 -0
  232. package/dist/tools/javascript-repl.d.ts +44 -0
  233. package/dist/tools/javascript-repl.d.ts.map +1 -0
  234. package/dist/tools/javascript-repl.js +224 -0
  235. package/dist/tools/javascript-repl.js.map +1 -0
  236. package/dist/tools/renderer-registry.d.ts +23 -0
  237. package/dist/tools/renderer-registry.d.ts.map +1 -0
  238. package/dist/tools/renderer-registry.js +107 -0
  239. package/dist/tools/renderer-registry.js.map +1 -0
  240. package/dist/tools/renderers/BashRenderer.d.ts +10 -0
  241. package/dist/tools/renderers/BashRenderer.d.ts.map +1 -0
  242. package/dist/tools/renderers/BashRenderer.js +42 -0
  243. package/dist/tools/renderers/BashRenderer.js.map +1 -0
  244. package/dist/tools/renderers/CalculateRenderer.d.ts +10 -0
  245. package/dist/tools/renderers/CalculateRenderer.d.ts.map +1 -0
  246. package/dist/tools/renderers/CalculateRenderer.js +45 -0
  247. package/dist/tools/renderers/CalculateRenderer.js.map +1 -0
  248. package/dist/tools/renderers/DefaultRenderer.d.ts +6 -0
  249. package/dist/tools/renderers/DefaultRenderer.d.ts.map +1 -0
  250. package/dist/tools/renderers/DefaultRenderer.js +94 -0
  251. package/dist/tools/renderers/DefaultRenderer.js.map +1 -0
  252. package/dist/tools/renderers/GetCurrentTimeRenderer.d.ts +10 -0
  253. package/dist/tools/renderers/GetCurrentTimeRenderer.d.ts.map +1 -0
  254. package/dist/tools/renderers/GetCurrentTimeRenderer.js +72 -0
  255. package/dist/tools/renderers/GetCurrentTimeRenderer.js.map +1 -0
  256. package/dist/tools/types.d.ts +10 -0
  257. package/dist/tools/types.d.ts.map +1 -0
  258. package/dist/tools/types.js +2 -0
  259. package/dist/tools/types.js.map +1 -0
  260. package/dist/utils/attachment-utils.d.ts +19 -0
  261. package/dist/utils/attachment-utils.d.ts.map +1 -0
  262. package/dist/utils/attachment-utils.js +415 -0
  263. package/dist/utils/attachment-utils.js.map +1 -0
  264. package/dist/utils/auth-token.d.ts +3 -0
  265. package/dist/utils/auth-token.d.ts.map +1 -0
  266. package/dist/utils/auth-token.js +19 -0
  267. package/dist/utils/auth-token.js.map +1 -0
  268. package/dist/utils/format.d.ts +6 -0
  269. package/dist/utils/format.d.ts.map +1 -0
  270. package/dist/utils/format.js +47 -0
  271. package/dist/utils/format.js.map +1 -0
  272. package/dist/utils/i18n.d.ts +636 -0
  273. package/dist/utils/i18n.d.ts.map +1 -0
  274. package/dist/utils/i18n.js +418 -0
  275. package/dist/utils/i18n.js.map +1 -0
  276. package/dist/utils/model-discovery.d.ts +38 -0
  277. package/dist/utils/model-discovery.d.ts.map +1 -0
  278. package/dist/utils/model-discovery.js +243 -0
  279. package/dist/utils/model-discovery.js.map +1 -0
  280. package/dist/utils/proxy-utils.d.ts +45 -0
  281. package/dist/utils/proxy-utils.d.ts.map +1 -0
  282. package/dist/utils/proxy-utils.js +116 -0
  283. package/dist/utils/proxy-utils.js.map +1 -0
  284. package/dist/utils/test-sessions.d.ts +359 -0
  285. package/dist/utils/test-sessions.d.ts.map +1 -0
  286. package/dist/utils/test-sessions.js +2325 -0
  287. package/dist/utils/test-sessions.js.map +1 -0
  288. package/example/README.md +61 -0
  289. package/example/index.html +13 -0
  290. package/example/package.json +25 -0
  291. package/example/src/app.css +1 -0
  292. package/example/src/custom-messages.ts +99 -0
  293. package/example/src/env.d.ts +1 -0
  294. package/example/src/main.ts +421 -0
  295. package/example/tsconfig.json +23 -0
  296. package/example/vite.config.ts +6 -0
  297. package/package.json +53 -0
  298. package/scripts/count-prompt-tokens.ts +88 -0
  299. package/src/ChatPanel.ts +207 -0
  300. package/src/app.css +68 -0
  301. package/src/components/AgentInterface.ts +388 -0
  302. package/src/components/AttachmentTile.ts +107 -0
  303. package/src/components/ConsoleBlock.ts +72 -0
  304. package/src/components/CustomProviderCard.ts +100 -0
  305. package/src/components/ExpandableSection.ts +46 -0
  306. package/src/components/Input.ts +113 -0
  307. package/src/components/MessageEditor.ts +400 -0
  308. package/src/components/MessageList.ts +95 -0
  309. package/src/components/Messages.ts +383 -0
  310. package/src/components/ProviderKeyInput.ts +153 -0
  311. package/src/components/SandboxedIframe.ts +626 -0
  312. package/src/components/StreamingMessageContainer.ts +103 -0
  313. package/src/components/ThinkingBlock.ts +43 -0
  314. package/src/components/message-renderer-registry.ts +28 -0
  315. package/src/components/sandbox/ArtifactsRuntimeProvider.ts +219 -0
  316. package/src/components/sandbox/AttachmentsRuntimeProvider.ts +66 -0
  317. package/src/components/sandbox/ConsoleRuntimeProvider.ts +186 -0
  318. package/src/components/sandbox/FileDownloadRuntimeProvider.ts +110 -0
  319. package/src/components/sandbox/RuntimeMessageBridge.ts +82 -0
  320. package/src/components/sandbox/RuntimeMessageRouter.ts +216 -0
  321. package/src/components/sandbox/SandboxRuntimeProvider.ts +52 -0
  322. package/src/dialogs/ApiKeyPromptDialog.ts +75 -0
  323. package/src/dialogs/AttachmentOverlay.ts +636 -0
  324. package/src/dialogs/CustomProviderDialog.ts +274 -0
  325. package/src/dialogs/ModelSelector.ts +313 -0
  326. package/src/dialogs/PersistentStorageDialog.ts +144 -0
  327. package/src/dialogs/ProvidersModelsTab.ts +212 -0
  328. package/src/dialogs/SessionListDialog.ts +150 -0
  329. package/src/dialogs/SettingsDialog.ts +214 -0
  330. package/src/index.ts +119 -0
  331. package/src/prompts/prompts.ts +282 -0
  332. package/src/storage/app-storage.ts +60 -0
  333. package/src/storage/backends/indexeddb-storage-backend.ts +193 -0
  334. package/src/storage/store.ts +33 -0
  335. package/src/storage/stores/custom-providers-store.ts +62 -0
  336. package/src/storage/stores/provider-keys-store.ts +33 -0
  337. package/src/storage/stores/sessions-store.ts +136 -0
  338. package/src/storage/stores/settings-store.ts +34 -0
  339. package/src/storage/types.ts +206 -0
  340. package/src/tools/artifacts/ArtifactElement.ts +14 -0
  341. package/src/tools/artifacts/ArtifactPill.ts +26 -0
  342. package/src/tools/artifacts/Console.ts +93 -0
  343. package/src/tools/artifacts/DocxArtifact.ts +213 -0
  344. package/src/tools/artifacts/ExcelArtifact.ts +231 -0
  345. package/src/tools/artifacts/GenericArtifact.ts +117 -0
  346. package/src/tools/artifacts/HtmlArtifact.ts +195 -0
  347. package/src/tools/artifacts/ImageArtifact.ts +116 -0
  348. package/src/tools/artifacts/MarkdownArtifact.ts +82 -0
  349. package/src/tools/artifacts/PdfArtifact.ts +201 -0
  350. package/src/tools/artifacts/SvgArtifact.ts +78 -0
  351. package/src/tools/artifacts/TextArtifact.ts +148 -0
  352. package/src/tools/artifacts/artifacts-tool-renderer.ts +310 -0
  353. package/src/tools/artifacts/artifacts.ts +713 -0
  354. package/src/tools/artifacts/index.ts +7 -0
  355. package/src/tools/extract-document.ts +275 -0
  356. package/src/tools/index.ts +46 -0
  357. package/src/tools/javascript-repl.ts +293 -0
  358. package/src/tools/renderer-registry.ts +130 -0
  359. package/src/tools/renderers/BashRenderer.ts +52 -0
  360. package/src/tools/renderers/CalculateRenderer.ts +58 -0
  361. package/src/tools/renderers/DefaultRenderer.ts +103 -0
  362. package/src/tools/renderers/GetCurrentTimeRenderer.ts +92 -0
  363. package/src/tools/types.ts +15 -0
  364. package/src/utils/attachment-utils.ts +472 -0
  365. package/src/utils/auth-token.ts +22 -0
  366. package/src/utils/format.ts +42 -0
  367. package/src/utils/i18n.ts +653 -0
  368. package/src/utils/model-discovery.ts +277 -0
  369. package/src/utils/proxy-utils.ts +134 -0
  370. package/src/utils/test-sessions.ts +2357 -0
  371. package/tsconfig.build.json +20 -0
  372. package/tsconfig.json +7 -0
@@ -0,0 +1,383 @@
1
+ import type {
2
+ AssistantMessage as AssistantMessageType,
3
+ ImageContent,
4
+ TextContent,
5
+ ToolCall,
6
+ ToolResultMessage as ToolResultMessageType,
7
+ UserMessage as UserMessageType,
8
+ } from "@draht/ai";
9
+ import { html, LitElement, type TemplateResult } from "lit";
10
+ import { customElement, property } from "lit/decorators.js";
11
+ import { renderTool } from "../tools/index.js";
12
+ import type { Attachment } from "../utils/attachment-utils.js";
13
+ import { formatUsage } from "../utils/format.js";
14
+ import { i18n } from "../utils/i18n.js";
15
+ import "./ThinkingBlock.js";
16
+ import type { AgentTool } from "@draht/agent-core";
17
+
18
+ export type UserMessageWithAttachments = {
19
+ role: "user-with-attachments";
20
+ content: string | (TextContent | ImageContent)[];
21
+ timestamp: number;
22
+ attachments?: Attachment[];
23
+ };
24
+
25
+ // Artifact message type for session persistence
26
+ export interface ArtifactMessage {
27
+ role: "artifact";
28
+ action: "create" | "update" | "delete";
29
+ filename: string;
30
+ content?: string;
31
+ title?: string;
32
+ timestamp: string;
33
+ }
34
+
35
+ declare module "@draht/agent-core" {
36
+ interface CustomAgentMessages {
37
+ "user-with-attachments": UserMessageWithAttachments;
38
+ artifact: ArtifactMessage;
39
+ }
40
+ }
41
+
42
+ @customElement("user-message")
43
+ export class UserMessage extends LitElement {
44
+ @property({ type: Object }) message!: UserMessageWithAttachments | UserMessageType;
45
+
46
+ protected override createRenderRoot(): HTMLElement | DocumentFragment {
47
+ return this;
48
+ }
49
+
50
+ override connectedCallback(): void {
51
+ super.connectedCallback();
52
+ this.style.display = "block";
53
+ }
54
+
55
+ override render() {
56
+ const content =
57
+ typeof this.message.content === "string"
58
+ ? this.message.content
59
+ : this.message.content.find((c) => c.type === "text")?.text || "";
60
+
61
+ return html`
62
+ <div class="flex justify-start mx-4">
63
+ <div class="user-message-container py-2 px-4 rounded-xl">
64
+ <markdown-block .content=${content}></markdown-block>
65
+ ${
66
+ this.message.role === "user-with-attachments" &&
67
+ this.message.attachments &&
68
+ this.message.attachments.length > 0
69
+ ? html`
70
+ <div class="mt-3 flex flex-wrap gap-2">
71
+ ${this.message.attachments.map(
72
+ (attachment) => html` <attachment-tile .attachment=${attachment}></attachment-tile> `,
73
+ )}
74
+ </div>
75
+ `
76
+ : ""
77
+ }
78
+ </div>
79
+ </div>
80
+ `;
81
+ }
82
+ }
83
+
84
+ @customElement("assistant-message")
85
+ export class AssistantMessage extends LitElement {
86
+ @property({ type: Object }) message!: AssistantMessageType;
87
+ @property({ type: Array }) tools?: AgentTool<any>[];
88
+ @property({ type: Object }) pendingToolCalls?: Set<string>;
89
+ @property({ type: Boolean }) hideToolCalls = false;
90
+ @property({ type: Object }) toolResultsById?: Map<string, ToolResultMessageType>;
91
+ @property({ type: Boolean }) isStreaming: boolean = false;
92
+ @property({ type: Boolean }) hidePendingToolCalls = false;
93
+ @property({ attribute: false }) onCostClick?: () => void;
94
+
95
+ protected override createRenderRoot(): HTMLElement | DocumentFragment {
96
+ return this;
97
+ }
98
+
99
+ override connectedCallback(): void {
100
+ super.connectedCallback();
101
+ this.style.display = "block";
102
+ }
103
+
104
+ override render() {
105
+ // Render content in the order it appears
106
+ const orderedParts: TemplateResult[] = [];
107
+
108
+ for (const chunk of this.message.content) {
109
+ if (chunk.type === "text" && chunk.text.trim() !== "") {
110
+ orderedParts.push(html`<markdown-block .content=${chunk.text}></markdown-block>`);
111
+ } else if (chunk.type === "thinking" && chunk.thinking.trim() !== "") {
112
+ orderedParts.push(
113
+ html`<thinking-block .content=${chunk.thinking} .isStreaming=${this.isStreaming}></thinking-block>`,
114
+ );
115
+ } else if (chunk.type === "toolCall") {
116
+ if (!this.hideToolCalls) {
117
+ const tool = this.tools?.find((t) => t.name === chunk.name);
118
+ const pending = this.pendingToolCalls?.has(chunk.id) ?? false;
119
+ const result = this.toolResultsById?.get(chunk.id);
120
+ // Skip rendering pending tool calls when hidePendingToolCalls is true
121
+ // (used to prevent duplication when StreamingMessageContainer is showing them)
122
+ if (this.hidePendingToolCalls && pending && !result) {
123
+ continue;
124
+ }
125
+ // A tool call is aborted if the message was aborted and there's no result for this tool call
126
+ const aborted = this.message.stopReason === "aborted" && !result;
127
+ orderedParts.push(
128
+ html`<tool-message
129
+ .tool=${tool}
130
+ .toolCall=${chunk}
131
+ .result=${result}
132
+ .pending=${pending}
133
+ .aborted=${aborted}
134
+ .isStreaming=${this.isStreaming}
135
+ ></tool-message>`,
136
+ );
137
+ }
138
+ }
139
+ }
140
+
141
+ return html`
142
+ <div>
143
+ ${orderedParts.length ? html` <div class="px-4 flex flex-col gap-3">${orderedParts}</div> ` : ""}
144
+ ${
145
+ this.message.usage && !this.isStreaming
146
+ ? this.onCostClick
147
+ ? html` <div class="px-4 mt-2 text-xs text-muted-foreground cursor-pointer hover:text-foreground transition-colors" @click=${this.onCostClick}>${formatUsage(this.message.usage)}</div> `
148
+ : html` <div class="px-4 mt-2 text-xs text-muted-foreground">${formatUsage(this.message.usage)}</div> `
149
+ : ""
150
+ }
151
+ ${
152
+ this.message.stopReason === "error" && this.message.errorMessage
153
+ ? html`
154
+ <div class="mx-4 mt-3 p-3 bg-destructive/10 text-destructive rounded-lg text-sm overflow-hidden">
155
+ <strong>${i18n("Error:")}</strong> ${this.message.errorMessage}
156
+ </div>
157
+ `
158
+ : ""
159
+ }
160
+ ${
161
+ this.message.stopReason === "aborted"
162
+ ? html`<span class="text-sm text-destructive italic">${i18n("Request aborted")}</span>`
163
+ : ""
164
+ }
165
+ </div>
166
+ `;
167
+ }
168
+ }
169
+
170
+ @customElement("tool-message-debug")
171
+ export class ToolMessageDebugView extends LitElement {
172
+ @property({ type: Object }) callArgs: any;
173
+ @property({ type: Object }) result?: ToolResultMessageType;
174
+ @property({ type: Boolean }) hasResult: boolean = false;
175
+
176
+ protected override createRenderRoot(): HTMLElement | DocumentFragment {
177
+ return this; // light DOM for shared styles
178
+ }
179
+
180
+ override connectedCallback(): void {
181
+ super.connectedCallback();
182
+ this.style.display = "block";
183
+ }
184
+
185
+ private pretty(value: unknown): { content: string; isJson: boolean } {
186
+ try {
187
+ if (typeof value === "string") {
188
+ const maybeJson = JSON.parse(value);
189
+ return { content: JSON.stringify(maybeJson, null, 2), isJson: true };
190
+ }
191
+ return { content: JSON.stringify(value, null, 2), isJson: true };
192
+ } catch {
193
+ return { content: typeof value === "string" ? value : String(value), isJson: false };
194
+ }
195
+ }
196
+
197
+ override render() {
198
+ const textOutput =
199
+ this.result?.content
200
+ ?.filter((c) => c.type === "text")
201
+ .map((c: any) => c.text)
202
+ .join("\n") || "";
203
+ const output = this.pretty(textOutput);
204
+ const details = this.pretty(this.result?.details);
205
+
206
+ return html`
207
+ <div class="mt-3 flex flex-col gap-2">
208
+ <div>
209
+ <div class="text-xs font-medium mb-1 text-muted-foreground">${i18n("Call")}</div>
210
+ <code-block .code=${this.pretty(this.callArgs).content} language="json"></code-block>
211
+ </div>
212
+ <div>
213
+ <div class="text-xs font-medium mb-1 text-muted-foreground">${i18n("Result")}</div>
214
+ ${
215
+ this.hasResult
216
+ ? html`<code-block .code=${output.content} language="${output.isJson ? "json" : "text"}"></code-block>
217
+ <code-block .code=${details.content} language="${details.isJson ? "json" : "text"}"></code-block>`
218
+ : html`<div class="text-xs text-muted-foreground">${i18n("(no result)")}</div>`
219
+ }
220
+ </div>
221
+ </div>
222
+ `;
223
+ }
224
+ }
225
+
226
+ @customElement("tool-message")
227
+ export class ToolMessage extends LitElement {
228
+ @property({ type: Object }) toolCall!: ToolCall;
229
+ @property({ type: Object }) tool?: AgentTool<any>;
230
+ @property({ type: Object }) result?: ToolResultMessageType;
231
+ @property({ type: Boolean }) pending: boolean = false;
232
+ @property({ type: Boolean }) aborted: boolean = false;
233
+ @property({ type: Boolean }) isStreaming: boolean = false;
234
+
235
+ protected override createRenderRoot(): HTMLElement | DocumentFragment {
236
+ return this;
237
+ }
238
+
239
+ override connectedCallback(): void {
240
+ super.connectedCallback();
241
+ this.style.display = "block";
242
+ }
243
+
244
+ override render() {
245
+ const toolName = this.tool?.name || this.toolCall.name;
246
+
247
+ // Render tool content (renderer handles errors and styling)
248
+ const result: ToolResultMessageType<any> | undefined = this.aborted
249
+ ? {
250
+ role: "toolResult",
251
+ isError: true,
252
+ content: [],
253
+ toolCallId: this.toolCall.id,
254
+ toolName: this.toolCall.name,
255
+ timestamp: Date.now(),
256
+ }
257
+ : this.result;
258
+ const renderResult = renderTool(
259
+ toolName,
260
+ this.toolCall.arguments,
261
+ result,
262
+ !this.aborted && (this.isStreaming || this.pending),
263
+ );
264
+
265
+ // Handle custom rendering (no card wrapper)
266
+ if (renderResult.isCustom) {
267
+ return renderResult.content;
268
+ }
269
+
270
+ // Default: wrap in card
271
+ return html`
272
+ <div class="p-2.5 border border-border rounded-md bg-card text-card-foreground shadow-xs">
273
+ ${renderResult.content}
274
+ </div>
275
+ `;
276
+ }
277
+ }
278
+
279
+ @customElement("aborted-message")
280
+ export class AbortedMessage extends LitElement {
281
+ protected override createRenderRoot(): HTMLElement | DocumentFragment {
282
+ return this;
283
+ }
284
+
285
+ override connectedCallback(): void {
286
+ super.connectedCallback();
287
+ this.style.display = "block";
288
+ }
289
+
290
+ protected override render(): unknown {
291
+ return html`<span class="text-sm text-destructive italic">${i18n("Request aborted")}</span>`;
292
+ }
293
+ }
294
+
295
+ // ============================================================================
296
+ // Default Message Transformer
297
+ // ============================================================================
298
+
299
+ import type { AgentMessage } from "@draht/agent-core";
300
+ import type { Message } from "@draht/ai";
301
+
302
+ /**
303
+ * Convert attachments to content blocks for LLM.
304
+ * - Images become ImageContent blocks
305
+ * - Documents with extractedText become TextContent blocks with filename header
306
+ */
307
+ export function convertAttachments(attachments: Attachment[]): (TextContent | ImageContent)[] {
308
+ const content: (TextContent | ImageContent)[] = [];
309
+ for (const attachment of attachments) {
310
+ if (attachment.type === "image") {
311
+ content.push({
312
+ type: "image",
313
+ data: attachment.content,
314
+ mimeType: attachment.mimeType,
315
+ } as ImageContent);
316
+ } else if (attachment.type === "document" && attachment.extractedText) {
317
+ content.push({
318
+ type: "text",
319
+ text: `\n\n[Document: ${attachment.fileName}]\n${attachment.extractedText}`,
320
+ } as TextContent);
321
+ }
322
+ }
323
+ return content;
324
+ }
325
+
326
+ /**
327
+ * Check if a message is a UserMessageWithAttachments.
328
+ */
329
+ export function isUserMessageWithAttachments(msg: AgentMessage): msg is UserMessageWithAttachments {
330
+ return (msg as UserMessageWithAttachments).role === "user-with-attachments";
331
+ }
332
+
333
+ /**
334
+ * Check if a message is an ArtifactMessage.
335
+ */
336
+ export function isArtifactMessage(msg: AgentMessage): msg is ArtifactMessage {
337
+ return (msg as ArtifactMessage).role === "artifact";
338
+ }
339
+
340
+ /**
341
+ * Default convertToLlm for web-ui apps.
342
+ *
343
+ * Handles:
344
+ * - UserMessageWithAttachments: converts to user message with content blocks
345
+ * - ArtifactMessage: filtered out (UI-only, for session reconstruction)
346
+ * - Standard LLM messages (user, assistant, toolResult): passed through
347
+ */
348
+ export function defaultConvertToLlm(messages: AgentMessage[]): Message[] {
349
+ return messages
350
+ .filter((m) => {
351
+ // Filter out artifact messages - they're for session reconstruction only
352
+ if (isArtifactMessage(m)) {
353
+ return false;
354
+ }
355
+ return true;
356
+ })
357
+ .map((m): Message | null => {
358
+ // Convert user-with-attachments to user message with content blocks
359
+ if (isUserMessageWithAttachments(m)) {
360
+ const textContent: (TextContent | ImageContent)[] =
361
+ typeof m.content === "string" ? [{ type: "text", text: m.content }] : [...m.content];
362
+
363
+ if (m.attachments) {
364
+ textContent.push(...convertAttachments(m.attachments));
365
+ }
366
+
367
+ return {
368
+ role: "user",
369
+ content: textContent,
370
+ timestamp: m.timestamp,
371
+ } as Message;
372
+ }
373
+
374
+ // Pass through standard LLM roles
375
+ if (m.role === "user" || m.role === "assistant" || m.role === "toolResult") {
376
+ return m as Message;
377
+ }
378
+
379
+ // Filter out unknown message types
380
+ return null;
381
+ })
382
+ .filter((m): m is Message => m !== null);
383
+ }
@@ -0,0 +1,153 @@
1
+ import { type Context, complete, getModel } from "@draht/ai";
2
+ import { i18n } from "@mariozechner/mini-lit";
3
+ import { Badge } from "@mariozechner/mini-lit/dist/Badge.js";
4
+ import { Button } from "@mariozechner/mini-lit/dist/Button.js";
5
+ import { html, LitElement } from "lit";
6
+ import { customElement, property, state } from "lit/decorators.js";
7
+ import { getAppStorage } from "../storage/app-storage.js";
8
+ import { applyProxyIfNeeded } from "../utils/proxy-utils.js";
9
+ import { Input } from "./Input.js";
10
+
11
+ // Test models for each provider
12
+ const TEST_MODELS: Record<string, string> = {
13
+ anthropic: "claude-3-5-haiku-20241022",
14
+ openai: "gpt-4o-mini",
15
+ google: "gemini-2.5-flash",
16
+ groq: "openai/gpt-oss-20b",
17
+ openrouter: "z-ai/glm-4.6",
18
+ "vercel-ai-gateway": "anthropic/claude-opus-4.5",
19
+ cerebras: "gpt-oss-120b",
20
+ xai: "grok-4-fast-non-reasoning",
21
+ zai: "glm-4.5-air",
22
+ };
23
+
24
+ @customElement("provider-key-input")
25
+ export class ProviderKeyInput extends LitElement {
26
+ @property() provider = "";
27
+ @state() private keyInput = "";
28
+ @state() private testing = false;
29
+ @state() private failed = false;
30
+ @state() private hasKey = false;
31
+ @state() private inputChanged = false;
32
+
33
+ protected createRenderRoot() {
34
+ return this;
35
+ }
36
+
37
+ override async connectedCallback() {
38
+ super.connectedCallback();
39
+ await this.checkKeyStatus();
40
+ }
41
+
42
+ private async checkKeyStatus() {
43
+ try {
44
+ const key = await getAppStorage().providerKeys.get(this.provider);
45
+ this.hasKey = !!key;
46
+ } catch (error) {
47
+ console.error("Failed to check key status:", error);
48
+ }
49
+ }
50
+
51
+ private async testApiKey(provider: string, apiKey: string): Promise<boolean> {
52
+ try {
53
+ const modelId = TEST_MODELS[provider];
54
+ // Returning true here for Ollama and friends. Can' know which model to use for testing
55
+ if (!modelId) return true;
56
+
57
+ let model = getModel(provider as any, modelId);
58
+ if (!model) return false;
59
+
60
+ // Get proxy URL from settings (if available)
61
+ const proxyEnabled = await getAppStorage().settings.get<boolean>("proxy.enabled");
62
+ const proxyUrl = await getAppStorage().settings.get<string>("proxy.url");
63
+
64
+ // Apply proxy only if this provider/key combination requires it
65
+ model = applyProxyIfNeeded(model, apiKey, proxyEnabled ? proxyUrl || undefined : undefined);
66
+
67
+ const context: Context = {
68
+ messages: [{ role: "user", content: "Reply with: ok", timestamp: Date.now() }],
69
+ };
70
+
71
+ const result = await complete(model, context, {
72
+ apiKey,
73
+ maxTokens: 200,
74
+ } as any);
75
+
76
+ return result.stopReason === "stop";
77
+ } catch (error) {
78
+ console.error(`API key test failed for ${provider}:`, error);
79
+ return false;
80
+ }
81
+ }
82
+
83
+ private async saveKey() {
84
+ if (!this.keyInput) return;
85
+
86
+ this.testing = true;
87
+ this.failed = false;
88
+
89
+ const success = await this.testApiKey(this.provider, this.keyInput);
90
+
91
+ this.testing = false;
92
+
93
+ if (success) {
94
+ try {
95
+ await getAppStorage().providerKeys.set(this.provider, this.keyInput);
96
+ this.hasKey = true;
97
+ this.inputChanged = false;
98
+ this.requestUpdate();
99
+ } catch (error) {
100
+ console.error("Failed to save API key:", error);
101
+ this.failed = true;
102
+ setTimeout(() => {
103
+ this.failed = false;
104
+ this.requestUpdate();
105
+ }, 5000);
106
+ }
107
+ } else {
108
+ this.failed = true;
109
+ setTimeout(() => {
110
+ this.failed = false;
111
+ this.requestUpdate();
112
+ }, 5000);
113
+ }
114
+ }
115
+
116
+ render() {
117
+ return html`
118
+ <div class="space-y-3">
119
+ <div class="flex items-center gap-2">
120
+ <span class="text-sm font-medium capitalize text-foreground">${this.provider}</span>
121
+ ${
122
+ this.testing
123
+ ? Badge({ children: i18n("Testing..."), variant: "secondary" })
124
+ : this.hasKey
125
+ ? html`<span class="text-green-600 dark:text-green-400">✓</span>`
126
+ : ""
127
+ }
128
+ ${this.failed ? Badge({ children: i18n("✗ Invalid"), variant: "destructive" }) : ""}
129
+ </div>
130
+ <div class="flex items-center gap-2">
131
+ ${Input({
132
+ type: "password",
133
+ placeholder: this.hasKey ? "••••••••••••" : i18n("Enter API key"),
134
+ value: this.keyInput,
135
+ onInput: (e: Event) => {
136
+ this.keyInput = (e.target as HTMLInputElement).value;
137
+ this.inputChanged = true;
138
+ this.requestUpdate();
139
+ },
140
+ className: "flex-1",
141
+ })}
142
+ ${Button({
143
+ onClick: () => this.saveKey(),
144
+ variant: "default",
145
+ size: "sm",
146
+ disabled: !this.keyInput || this.testing || (this.hasKey && !this.inputChanged),
147
+ children: i18n("Save"),
148
+ })}
149
+ </div>
150
+ </div>
151
+ `;
152
+ }
153
+ }