@mariozechner/pi-web-ui 0.5.44 → 0.5.45

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 (346) hide show
  1. package/README.md +178 -99
  2. package/dist/ChatPanel.d.ts +15 -10
  3. package/dist/ChatPanel.d.ts.map +1 -1
  4. package/dist/ChatPanel.js +68 -100
  5. package/dist/ChatPanel.js.map +1 -1
  6. package/dist/{state/agent-session.d.ts → agent/agent.d.ts} +23 -19
  7. package/dist/agent/agent.d.ts.map +1 -0
  8. package/dist/{state/agent-session.js → agent/agent.js} +50 -32
  9. package/dist/agent/agent.js.map +1 -0
  10. package/dist/{state → agent}/transports/AppTransport.d.ts +1 -3
  11. package/dist/agent/transports/AppTransport.d.ts.map +1 -0
  12. package/dist/{state → agent}/transports/AppTransport.js +5 -4
  13. package/dist/{state → agent}/transports/AppTransport.js.map +1 -1
  14. package/dist/{state → agent}/transports/ProviderTransport.d.ts +1 -3
  15. package/dist/agent/transports/ProviderTransport.d.ts.map +1 -0
  16. package/dist/{state → agent}/transports/ProviderTransport.js +6 -7
  17. package/dist/agent/transports/ProviderTransport.js.map +1 -0
  18. package/dist/{state → agent}/transports/index.d.ts.map +1 -1
  19. package/dist/agent/transports/index.js.map +1 -0
  20. package/dist/{state → agent}/transports/proxy-types.d.ts.map +1 -1
  21. package/dist/agent/transports/proxy-types.js.map +1 -0
  22. package/dist/agent/transports/types.d.ts +12 -0
  23. package/dist/agent/transports/types.d.ts.map +1 -0
  24. package/dist/{state → agent}/transports/types.js.map +1 -1
  25. package/dist/{state → agent}/types.d.ts.map +1 -1
  26. package/dist/{state → agent}/types.js.map +1 -1
  27. package/dist/app.css +1 -1
  28. package/dist/components/AgentInterface.d.ts +7 -4
  29. package/dist/components/AgentInterface.d.ts.map +1 -1
  30. package/dist/components/AgentInterface.js +29 -17
  31. package/dist/components/AgentInterface.js.map +1 -1
  32. package/dist/components/ConsoleBlock.d.ts +1 -0
  33. package/dist/components/ConsoleBlock.d.ts.map +1 -1
  34. package/dist/components/ConsoleBlock.js +7 -1
  35. package/dist/components/ConsoleBlock.js.map +1 -1
  36. package/dist/components/ExpandableSection.d.ts +15 -0
  37. package/dist/components/ExpandableSection.d.ts.map +1 -0
  38. package/dist/components/ExpandableSection.js +63 -0
  39. package/dist/components/ExpandableSection.js.map +1 -0
  40. package/dist/components/MessageEditor.d.ts +8 -1
  41. package/dist/components/MessageEditor.d.ts.map +1 -1
  42. package/dist/components/MessageEditor.js +149 -6
  43. package/dist/components/MessageEditor.js.map +1 -1
  44. package/dist/components/MessageList.d.ts +3 -2
  45. package/dist/components/MessageList.d.ts.map +1 -1
  46. package/dist/components/MessageList.js +14 -1
  47. package/dist/components/MessageList.js.map +1 -1
  48. package/dist/components/Messages.d.ts +15 -6
  49. package/dist/components/Messages.d.ts.map +1 -1
  50. package/dist/components/Messages.js +17 -83
  51. package/dist/components/Messages.js.map +1 -1
  52. package/dist/components/ProviderKeyInput.d.ts.map +1 -1
  53. package/dist/components/ProviderKeyInput.js +6 -5
  54. package/dist/components/ProviderKeyInput.js.map +1 -1
  55. package/dist/components/SandboxedIframe.d.ts +29 -7
  56. package/dist/components/SandboxedIframe.d.ts.map +1 -1
  57. package/dist/components/SandboxedIframe.js +350 -282
  58. package/dist/components/SandboxedIframe.js.map +1 -1
  59. package/dist/components/message-renderer-registry.d.ts +12 -0
  60. package/dist/components/message-renderer-registry.d.ts.map +1 -0
  61. package/dist/components/message-renderer-registry.js +12 -0
  62. package/dist/components/message-renderer-registry.js.map +1 -0
  63. package/dist/components/sandbox/ArtifactsRuntimeProvider.d.ts +35 -0
  64. package/dist/components/sandbox/ArtifactsRuntimeProvider.d.ts.map +1 -0
  65. package/dist/components/sandbox/ArtifactsRuntimeProvider.js +189 -0
  66. package/dist/components/sandbox/ArtifactsRuntimeProvider.js.map +1 -0
  67. package/dist/components/sandbox/AttachmentsRuntimeProvider.d.ts +17 -0
  68. package/dist/components/sandbox/AttachmentsRuntimeProvider.d.ts.map +1 -0
  69. package/dist/components/sandbox/AttachmentsRuntimeProvider.js +64 -0
  70. package/dist/components/sandbox/AttachmentsRuntimeProvider.js.map +1 -0
  71. package/dist/components/sandbox/ConsoleRuntimeProvider.d.ts +42 -0
  72. package/dist/components/sandbox/ConsoleRuntimeProvider.d.ts.map +1 -0
  73. package/dist/components/sandbox/ConsoleRuntimeProvider.js +161 -0
  74. package/dist/components/sandbox/ConsoleRuntimeProvider.js.map +1 -0
  75. package/dist/components/sandbox/FileDownloadRuntimeProvider.d.ts +30 -0
  76. package/dist/components/sandbox/FileDownloadRuntimeProvider.d.ts.map +1 -0
  77. package/dist/components/sandbox/FileDownloadRuntimeProvider.js +97 -0
  78. package/dist/components/sandbox/FileDownloadRuntimeProvider.js.map +1 -0
  79. package/dist/components/sandbox/RuntimeMessageBridge.d.ts +19 -0
  80. package/dist/components/sandbox/RuntimeMessageBridge.d.ts.map +1 -0
  81. package/dist/components/sandbox/RuntimeMessageBridge.js +74 -0
  82. package/dist/components/sandbox/RuntimeMessageBridge.js.map +1 -0
  83. package/dist/components/sandbox/RuntimeMessageRouter.d.ts +65 -0
  84. package/dist/components/sandbox/RuntimeMessageRouter.d.ts.map +1 -0
  85. package/dist/components/sandbox/RuntimeMessageRouter.js +168 -0
  86. package/dist/components/sandbox/RuntimeMessageRouter.js.map +1 -0
  87. package/dist/components/sandbox/SandboxRuntimeProvider.d.ts +33 -0
  88. package/dist/components/sandbox/SandboxRuntimeProvider.d.ts.map +1 -0
  89. package/dist/components/sandbox/SandboxRuntimeProvider.js +2 -0
  90. package/dist/components/sandbox/SandboxRuntimeProvider.js.map +1 -0
  91. package/dist/dialogs/ApiKeyPromptDialog.d.ts.map +1 -1
  92. package/dist/dialogs/ApiKeyPromptDialog.js +2 -5
  93. package/dist/dialogs/ApiKeyPromptDialog.js.map +1 -1
  94. package/dist/dialogs/ModelSelector.js.map +1 -1
  95. package/dist/dialogs/PersistentStorageDialog.d.ts +17 -0
  96. package/dist/dialogs/PersistentStorageDialog.d.ts.map +1 -0
  97. package/dist/dialogs/PersistentStorageDialog.js +144 -0
  98. package/dist/dialogs/PersistentStorageDialog.js.map +1 -0
  99. package/dist/dialogs/SessionListDialog.d.ts +19 -0
  100. package/dist/dialogs/SessionListDialog.d.ts.map +1 -0
  101. package/dist/dialogs/SessionListDialog.js +152 -0
  102. package/dist/dialogs/SessionListDialog.js.map +1 -0
  103. package/dist/dialogs/SettingsDialog.d.ts.map +1 -1
  104. package/dist/dialogs/SettingsDialog.js +1 -0
  105. package/dist/dialogs/SettingsDialog.js.map +1 -1
  106. package/dist/index.d.ts +34 -16
  107. package/dist/index.d.ts.map +1 -1
  108. package/dist/index.js +32 -14
  109. package/dist/index.js.map +1 -1
  110. package/dist/prompts/prompts.d.ts +11 -0
  111. package/dist/prompts/prompts.d.ts.map +1 -0
  112. package/dist/prompts/prompts.js +272 -0
  113. package/dist/prompts/prompts.js.map +1 -0
  114. package/dist/storage/app-storage.d.ts +17 -12
  115. package/dist/storage/app-storage.d.ts.map +1 -1
  116. package/dist/storage/app-storage.js +13 -20
  117. package/dist/storage/app-storage.js.map +1 -1
  118. package/dist/storage/backends/indexeddb-storage-backend.d.ts +27 -0
  119. package/dist/storage/backends/indexeddb-storage-backend.d.ts.map +1 -0
  120. package/dist/storage/backends/indexeddb-storage-backend.js +166 -0
  121. package/dist/storage/backends/indexeddb-storage-backend.js.map +1 -0
  122. package/dist/storage/store.d.ts +23 -0
  123. package/dist/storage/store.d.ts.map +1 -0
  124. package/dist/storage/store.js +26 -0
  125. package/dist/storage/store.js.map +1 -0
  126. package/dist/storage/stores/provider-keys-store.d.ts +14 -0
  127. package/dist/storage/stores/provider-keys-store.d.ts.map +1 -0
  128. package/dist/storage/stores/provider-keys-store.js +27 -0
  129. package/dist/storage/stores/provider-keys-store.js.map +1 -0
  130. package/dist/storage/stores/sessions-store.d.ts +31 -0
  131. package/dist/storage/stores/sessions-store.d.ts.map +1 -0
  132. package/dist/storage/stores/sessions-store.js +113 -0
  133. package/dist/storage/stores/sessions-store.js.map +1 -0
  134. package/dist/storage/stores/settings-store.d.ts +14 -0
  135. package/dist/storage/stores/settings-store.d.ts.map +1 -0
  136. package/dist/storage/stores/settings-store.js +28 -0
  137. package/dist/storage/stores/settings-store.js.map +1 -0
  138. package/dist/storage/types.d.ts +156 -22
  139. package/dist/storage/types.d.ts.map +1 -1
  140. package/dist/tools/artifacts/ArtifactElement.d.ts +0 -1
  141. package/dist/tools/artifacts/ArtifactElement.d.ts.map +1 -1
  142. package/dist/tools/artifacts/ArtifactElement.js +0 -1
  143. package/dist/tools/artifacts/ArtifactElement.js.map +1 -1
  144. package/dist/tools/artifacts/ArtifactPill.d.ts +4 -0
  145. package/dist/tools/artifacts/ArtifactPill.d.ts.map +1 -0
  146. package/dist/tools/artifacts/ArtifactPill.js +22 -0
  147. package/dist/tools/artifacts/ArtifactPill.js.map +1 -0
  148. package/dist/tools/artifacts/Console.d.ts +18 -0
  149. package/dist/tools/artifacts/Console.d.ts.map +1 -0
  150. package/dist/tools/artifacts/Console.js +95 -0
  151. package/dist/tools/artifacts/Console.js.map +1 -0
  152. package/dist/tools/artifacts/DocxArtifact.d.ts +22 -0
  153. package/dist/tools/artifacts/DocxArtifact.d.ts.map +1 -0
  154. package/dist/tools/artifacts/DocxArtifact.js +208 -0
  155. package/dist/tools/artifacts/DocxArtifact.js.map +1 -0
  156. package/dist/tools/artifacts/ExcelArtifact.d.ts +24 -0
  157. package/dist/tools/artifacts/ExcelArtifact.d.ts.map +1 -0
  158. package/dist/tools/artifacts/ExcelArtifact.js +216 -0
  159. package/dist/tools/artifacts/ExcelArtifact.js.map +1 -0
  160. package/dist/tools/artifacts/GenericArtifact.d.ts +19 -0
  161. package/dist/tools/artifacts/GenericArtifact.d.ts.map +1 -0
  162. package/dist/tools/artifacts/GenericArtifact.js +117 -0
  163. package/dist/tools/artifacts/GenericArtifact.js.map +1 -0
  164. package/dist/tools/artifacts/HtmlArtifact.d.ts +8 -11
  165. package/dist/tools/artifacts/HtmlArtifact.d.ts.map +1 -1
  166. package/dist/tools/artifacts/HtmlArtifact.js +56 -88
  167. package/dist/tools/artifacts/HtmlArtifact.js.map +1 -1
  168. package/dist/tools/artifacts/ImageArtifact.d.ts +20 -0
  169. package/dist/tools/artifacts/ImageArtifact.d.ts.map +1 -0
  170. package/dist/tools/artifacts/ImageArtifact.js +120 -0
  171. package/dist/tools/artifacts/ImageArtifact.js.map +1 -0
  172. package/dist/tools/artifacts/MarkdownArtifact.d.ts +0 -1
  173. package/dist/tools/artifacts/MarkdownArtifact.d.ts.map +1 -1
  174. package/dist/tools/artifacts/MarkdownArtifact.js +0 -4
  175. package/dist/tools/artifacts/MarkdownArtifact.js.map +1 -1
  176. package/dist/tools/artifacts/PdfArtifact.d.ts +25 -0
  177. package/dist/tools/artifacts/PdfArtifact.d.ts.map +1 -0
  178. package/dist/tools/artifacts/PdfArtifact.js +184 -0
  179. package/dist/tools/artifacts/PdfArtifact.js.map +1 -0
  180. package/dist/tools/artifacts/SvgArtifact.d.ts +0 -1
  181. package/dist/tools/artifacts/SvgArtifact.d.ts.map +1 -1
  182. package/dist/tools/artifacts/SvgArtifact.js +0 -4
  183. package/dist/tools/artifacts/SvgArtifact.js.map +1 -1
  184. package/dist/tools/artifacts/TextArtifact.d.ts +0 -1
  185. package/dist/tools/artifacts/TextArtifact.d.ts.map +1 -1
  186. package/dist/tools/artifacts/TextArtifact.js +0 -4
  187. package/dist/tools/artifacts/TextArtifact.js.map +1 -1
  188. package/dist/tools/artifacts/artifacts-tool-renderer.d.ts +11 -0
  189. package/dist/tools/artifacts/artifacts-tool-renderer.d.ts.map +1 -0
  190. package/dist/tools/artifacts/artifacts-tool-renderer.js +262 -0
  191. package/dist/tools/artifacts/artifacts-tool-renderer.js.map +1 -0
  192. package/dist/tools/artifacts/artifacts.d.ts +10 -13
  193. package/dist/tools/artifacts/artifacts.d.ts.map +1 -1
  194. package/dist/tools/artifacts/artifacts.js +166 -344
  195. package/dist/tools/artifacts/artifacts.js.map +1 -1
  196. package/dist/tools/artifacts/index.d.ts +1 -0
  197. package/dist/tools/artifacts/index.d.ts.map +1 -1
  198. package/dist/tools/artifacts/index.js +1 -0
  199. package/dist/tools/artifacts/index.js.map +1 -1
  200. package/dist/tools/extract-document.d.ts +24 -0
  201. package/dist/tools/extract-document.d.ts.map +1 -0
  202. package/dist/tools/extract-document.js +193 -0
  203. package/dist/tools/extract-document.js.map +1 -0
  204. package/dist/tools/index.d.ts +9 -7
  205. package/dist/tools/index.d.ts.map +1 -1
  206. package/dist/tools/index.js +17 -13
  207. package/dist/tools/index.js.map +1 -1
  208. package/dist/tools/javascript-repl.d.ts +16 -15
  209. package/dist/tools/javascript-repl.d.ts.map +1 -1
  210. package/dist/tools/javascript-repl.js +101 -133
  211. package/dist/tools/javascript-repl.js.map +1 -1
  212. package/dist/tools/renderer-registry.d.ts +12 -0
  213. package/dist/tools/renderer-registry.d.ts.map +1 -1
  214. package/dist/tools/renderer-registry.js +78 -0
  215. package/dist/tools/renderer-registry.js.map +1 -1
  216. package/dist/tools/renderers/BashRenderer.d.ts +2 -4
  217. package/dist/tools/renderers/BashRenderer.d.ts.map +1 -1
  218. package/dist/tools/renderers/BashRenderer.js +30 -26
  219. package/dist/tools/renderers/BashRenderer.js.map +1 -1
  220. package/dist/tools/renderers/CalculateRenderer.d.ts +2 -4
  221. package/dist/tools/renderers/CalculateRenderer.d.ts.map +1 -1
  222. package/dist/tools/renderers/CalculateRenderer.js +32 -28
  223. package/dist/tools/renderers/CalculateRenderer.js.map +1 -1
  224. package/dist/tools/renderers/DefaultRenderer.d.ts +2 -4
  225. package/dist/tools/renderers/DefaultRenderer.d.ts.map +1 -1
  226. package/dist/tools/renderers/DefaultRenderer.js +78 -18
  227. package/dist/tools/renderers/DefaultRenderer.js.map +1 -1
  228. package/dist/tools/renderers/GetCurrentTimeRenderer.d.ts +2 -4
  229. package/dist/tools/renderers/GetCurrentTimeRenderer.d.ts.map +1 -1
  230. package/dist/tools/renderers/GetCurrentTimeRenderer.js +57 -21
  231. package/dist/tools/renderers/GetCurrentTimeRenderer.js.map +1 -1
  232. package/dist/tools/types.d.ts +5 -2
  233. package/dist/tools/types.d.ts.map +1 -1
  234. package/dist/utils/i18n.d.ts +424 -1
  235. package/dist/utils/i18n.d.ts.map +1 -1
  236. package/dist/utils/i18n.js +131 -7
  237. package/dist/utils/i18n.js.map +1 -1
  238. package/example/package.json +2 -1
  239. package/example/src/custom-messages.ts +112 -0
  240. package/example/src/main.ts +391 -38
  241. package/package.json +48 -43
  242. package/scripts/count-prompt-tokens.ts +88 -0
  243. package/src/ChatPanel.ts +93 -101
  244. package/src/{state/agent-session.ts → agent/agent.ts} +80 -55
  245. package/src/{state → agent}/transports/AppTransport.ts +6 -6
  246. package/src/{state → agent}/transports/ProviderTransport.ts +13 -7
  247. package/src/{state → agent}/transports/types.ts +8 -2
  248. package/src/components/AgentInterface.ts +32 -16
  249. package/src/components/ConsoleBlock.ts +5 -1
  250. package/src/components/ExpandableSection.ts +46 -0
  251. package/src/components/MessageEditor.ts +159 -5
  252. package/src/components/MessageList.ts +18 -3
  253. package/src/components/Messages.ts +48 -89
  254. package/src/components/ProviderKeyInput.ts +6 -5
  255. package/src/components/SandboxedIframe.ts +412 -321
  256. package/src/components/message-renderer-registry.ts +28 -0
  257. package/src/components/sandbox/ArtifactsRuntimeProvider.ts +219 -0
  258. package/src/components/sandbox/AttachmentsRuntimeProvider.ts +66 -0
  259. package/src/components/sandbox/ConsoleRuntimeProvider.ts +187 -0
  260. package/src/components/sandbox/FileDownloadRuntimeProvider.ts +110 -0
  261. package/src/components/sandbox/RuntimeMessageBridge.ts +82 -0
  262. package/src/components/sandbox/RuntimeMessageRouter.ts +216 -0
  263. package/src/components/sandbox/SandboxRuntimeProvider.ts +35 -0
  264. package/src/dialogs/ApiKeyPromptDialog.ts +2 -5
  265. package/src/dialogs/ModelSelector.ts +2 -2
  266. package/src/dialogs/PersistentStorageDialog.ts +141 -0
  267. package/src/dialogs/SessionListDialog.ts +148 -0
  268. package/src/dialogs/SettingsDialog.ts +1 -0
  269. package/src/index.ts +61 -20
  270. package/src/prompts/prompts.ts +282 -0
  271. package/src/storage/app-storage.ts +27 -24
  272. package/src/storage/backends/indexeddb-storage-backend.ts +193 -0
  273. package/src/storage/store.ts +33 -0
  274. package/src/storage/stores/provider-keys-store.ts +33 -0
  275. package/src/storage/stores/sessions-store.ts +130 -0
  276. package/src/storage/stores/settings-store.ts +34 -0
  277. package/src/storage/types.ts +182 -22
  278. package/src/tools/artifacts/ArtifactElement.ts +0 -1
  279. package/src/tools/artifacts/ArtifactPill.ts +25 -0
  280. package/src/tools/artifacts/Console.ts +93 -0
  281. package/src/tools/artifacts/DocxArtifact.ts +213 -0
  282. package/src/tools/artifacts/ExcelArtifact.ts +231 -0
  283. package/src/tools/artifacts/GenericArtifact.ts +117 -0
  284. package/src/tools/artifacts/HtmlArtifact.ts +64 -94
  285. package/src/tools/artifacts/ImageArtifact.ts +116 -0
  286. package/src/tools/artifacts/MarkdownArtifact.ts +0 -1
  287. package/src/tools/artifacts/PdfArtifact.ts +201 -0
  288. package/src/tools/artifacts/SvgArtifact.ts +0 -1
  289. package/src/tools/artifacts/TextArtifact.ts +0 -1
  290. package/src/tools/artifacts/artifacts-tool-renderer.ts +298 -0
  291. package/src/tools/artifacts/artifacts.ts +190 -366
  292. package/src/tools/artifacts/index.ts +1 -0
  293. package/src/tools/extract-document.ts +250 -0
  294. package/src/tools/index.ts +25 -14
  295. package/src/tools/javascript-repl.ts +138 -160
  296. package/src/tools/renderer-registry.ts +98 -0
  297. package/src/tools/renderers/BashRenderer.ts +33 -30
  298. package/src/tools/renderers/CalculateRenderer.ts +36 -31
  299. package/src/tools/renderers/DefaultRenderer.ts +84 -21
  300. package/src/tools/renderers/GetCurrentTimeRenderer.ts +68 -23
  301. package/src/tools/types.ts +10 -2
  302. package/src/utils/i18n.ts +203 -8
  303. package/dist/state/agent-session.d.ts.map +0 -1
  304. package/dist/state/agent-session.js.map +0 -1
  305. package/dist/state/transports/AppTransport.d.ts.map +0 -1
  306. package/dist/state/transports/ProviderTransport.d.ts.map +0 -1
  307. package/dist/state/transports/ProviderTransport.js.map +0 -1
  308. package/dist/state/transports/index.js.map +0 -1
  309. package/dist/state/transports/proxy-types.js.map +0 -1
  310. package/dist/state/transports/types.d.ts +0 -11
  311. package/dist/state/transports/types.d.ts.map +0 -1
  312. package/dist/storage/backends/chrome-storage-backend.d.ts +0 -18
  313. package/dist/storage/backends/chrome-storage-backend.d.ts.map +0 -1
  314. package/dist/storage/backends/chrome-storage-backend.js +0 -67
  315. package/dist/storage/backends/chrome-storage-backend.js.map +0 -1
  316. package/dist/storage/backends/indexeddb-backend.d.ts +0 -20
  317. package/dist/storage/backends/indexeddb-backend.d.ts.map +0 -1
  318. package/dist/storage/backends/indexeddb-backend.js +0 -89
  319. package/dist/storage/backends/indexeddb-backend.js.map +0 -1
  320. package/dist/storage/backends/local-storage-backend.d.ts +0 -18
  321. package/dist/storage/backends/local-storage-backend.d.ts.map +0 -1
  322. package/dist/storage/backends/local-storage-backend.js +0 -69
  323. package/dist/storage/backends/local-storage-backend.js.map +0 -1
  324. package/dist/storage/repositories/provider-keys-repository.d.ts +0 -34
  325. package/dist/storage/repositories/provider-keys-repository.d.ts.map +0 -1
  326. package/dist/storage/repositories/provider-keys-repository.js +0 -50
  327. package/dist/storage/repositories/provider-keys-repository.js.map +0 -1
  328. package/dist/storage/repositories/settings-repository.d.ts +0 -34
  329. package/dist/storage/repositories/settings-repository.d.ts.map +0 -1
  330. package/dist/storage/repositories/settings-repository.js +0 -46
  331. package/dist/storage/repositories/settings-repository.js.map +0 -1
  332. package/src/storage/backends/chrome-storage-backend.ts +0 -82
  333. package/src/storage/backends/indexeddb-backend.ts +0 -107
  334. package/src/storage/backends/local-storage-backend.ts +0 -74
  335. package/src/storage/repositories/provider-keys-repository.ts +0 -55
  336. package/src/storage/repositories/settings-repository.ts +0 -51
  337. /package/dist/{state → agent}/transports/index.d.ts +0 -0
  338. /package/dist/{state → agent}/transports/index.js +0 -0
  339. /package/dist/{state → agent}/transports/proxy-types.d.ts +0 -0
  340. /package/dist/{state → agent}/transports/proxy-types.js +0 -0
  341. /package/dist/{state → agent}/transports/types.js +0 -0
  342. /package/dist/{state → agent}/types.d.ts +0 -0
  343. /package/dist/{state → agent}/types.js +0 -0
  344. /package/src/{state → agent}/transports/index.ts +0 -0
  345. /package/src/{state → agent}/transports/proxy-types.ts +0 -0
  346. /package/src/{state → agent}/types.ts +0 -0
@@ -7,7 +7,7 @@ import type { MessageEditor } from "./MessageEditor.js";
7
7
  import "./MessageEditor.js";
8
8
  import "./MessageList.js";
9
9
  import "./Messages.js"; // Import for side effects to register the custom elements
10
- import type { AgentSession, AgentSessionEvent } from "../state/agent-session.js";
10
+ import type { Agent, AgentEvent } from "../agent/agent.js";
11
11
  import { getAppStorage } from "../storage/app-storage.js";
12
12
  import "./StreamingMessageContainer.js";
13
13
  import type { Attachment } from "../utils/attachment-utils.js";
@@ -18,14 +18,17 @@ import type { StreamingMessageContainer } from "./StreamingMessageContainer.js";
18
18
  @customElement("agent-interface")
19
19
  export class AgentInterface extends LitElement {
20
20
  // Optional external session: when provided, this component becomes a view over the session
21
- @property({ attribute: false }) session?: AgentSession;
22
- @property() enableAttachments = true;
23
- @property() enableModelSelector = true;
24
- @property() enableThinking = true;
25
- @property() showThemeToggle = false;
26
- @property() showDebugToggle = false;
21
+ @property({ attribute: false }) session?: Agent;
22
+ @property({ type: Boolean }) enableAttachments = true;
23
+ @property({ type: Boolean }) enableModelSelector = true;
24
+ @property({ type: Boolean }) enableThinkingSelector = true;
25
+ @property({ type: Boolean }) showThemeToggle = false;
27
26
  // Optional custom API key prompt handler - if not provided, uses default dialog
28
27
  @property({ attribute: false }) onApiKeyRequired?: (provider: string) => Promise<boolean>;
28
+ // Optional callback called before sending a message
29
+ @property({ attribute: false }) onBeforeSend?: () => void | Promise<void>;
30
+ // Optional callback called before executing a tool call - return false to prevent execution
31
+ @property({ attribute: false }) onBeforeToolCall?: (toolName: string, args: any) => boolean | Promise<boolean>;
29
32
 
30
33
  // References
31
34
  @query("message-editor") private _messageEditor!: MessageEditor;
@@ -49,10 +52,23 @@ export class AgentInterface extends LitElement {
49
52
  update();
50
53
  }
51
54
 
55
+ public setAutoScroll(enabled: boolean) {
56
+ this._autoScroll = enabled;
57
+ }
58
+
52
59
  protected override createRenderRoot(): HTMLElement | DocumentFragment {
53
60
  return this;
54
61
  }
55
62
 
63
+ override willUpdate(changedProperties: Map<string, any>) {
64
+ super.willUpdate(changedProperties);
65
+
66
+ // Re-subscribe when session property changes
67
+ if (changedProperties.has("session")) {
68
+ this.setupSessionSubscription();
69
+ }
70
+ }
71
+
56
72
  override async connectedCallback() {
57
73
  super.connectedCallback();
58
74
 
@@ -85,11 +101,6 @@ export class AgentInterface extends LitElement {
85
101
 
86
102
  // Subscribe to external session if provided
87
103
  this.setupSessionSubscription();
88
-
89
- // Attach debug listener if session provided
90
- if (this.session) {
91
- this.session = this.session; // explicitly set to trigger subscription
92
- }
93
104
  }
94
105
 
95
106
  override disconnectedCallback() {
@@ -117,7 +128,7 @@ export class AgentInterface extends LitElement {
117
128
  this._unsubscribeSession = undefined;
118
129
  }
119
130
  if (!this.session) return;
120
- this._unsubscribeSession = this.session.subscribe(async (ev: AgentSessionEvent) => {
131
+ this._unsubscribeSession = this.session.subscribe(async (ev: AgentEvent) => {
121
132
  if (ev.type === "state-update") {
122
133
  if (this._streamingContainer) {
123
134
  this._streamingContainer.isStreaming = ev.state.isStreaming;
@@ -166,7 +177,7 @@ export class AgentInterface extends LitElement {
166
177
 
167
178
  // Check if API key exists for the provider (only needed in direct mode)
168
179
  const provider = session.state.model.provider;
169
- const apiKey = await getAppStorage().providerKeys.getKey(provider);
180
+ const apiKey = await getAppStorage().providerKeys.get(provider);
170
181
 
171
182
  // If no API key, prompt for it
172
183
  if (!apiKey) {
@@ -183,6 +194,11 @@ export class AgentInterface extends LitElement {
183
194
  }
184
195
  }
185
196
 
197
+ // Call onBeforeSend hook before sending
198
+ if (this.onBeforeSend) {
199
+ await this.onBeforeSend();
200
+ }
201
+
186
202
  // Only clear editor after we know we can send
187
203
  this._messageEditor.value = "";
188
204
  this._messageEditor.attachments = [];
@@ -286,7 +302,7 @@ export class AgentInterface extends LitElement {
286
302
  .thinkingLevel=${state.thinkingLevel}
287
303
  .showAttachmentButton=${this.enableAttachments}
288
304
  .showModelSelector=${this.enableModelSelector}
289
- .showThinking=${this.enableThinking}
305
+ .showThinkingSelector=${this.enableThinkingSelector}
290
306
  .onSend=${(input: string, attachments: Attachment[]) => {
291
307
  this.sendMessage(input, attachments);
292
308
  }}
@@ -295,7 +311,7 @@ export class AgentInterface extends LitElement {
295
311
  ModelSelector.open(state.model, (model) => session.setModel(model));
296
312
  }}
297
313
  .onThinkingChange=${
298
- this.enableThinking
314
+ this.enableThinkingSelector
299
315
  ? (level: "off" | "minimal" | "low" | "medium" | "high") => {
300
316
  session.setThinkingLevel(level);
301
317
  }
@@ -6,6 +6,7 @@ import { i18n } from "../utils/i18n.js";
6
6
 
7
7
  export class ConsoleBlock extends LitElement {
8
8
  @property() content: string = "";
9
+ @property() variant: "default" | "error" = "default";
9
10
  @state() private copied = false;
10
11
 
11
12
  protected override createRenderRoot(): HTMLElement | DocumentFragment {
@@ -38,6 +39,9 @@ export class ConsoleBlock extends LitElement {
38
39
  }
39
40
 
40
41
  override render() {
42
+ const isError = this.variant === "error";
43
+ const textClass = isError ? "text-destructive" : "text-foreground";
44
+
41
45
  return html`
42
46
  <div class="border border-border rounded-lg overflow-hidden">
43
47
  <div class="flex items-center justify-between px-3 py-1.5 bg-muted border-b border-border">
@@ -52,7 +56,7 @@ export class ConsoleBlock extends LitElement {
52
56
  </button>
53
57
  </div>
54
58
  <div class="console-scroll overflow-auto max-h-64">
55
- <pre class="!bg-background !border-0 !rounded-none m-0 p-3 text-xs text-foreground font-mono whitespace-pre-wrap">
59
+ <pre class="!bg-background !border-0 !rounded-none m-0 p-3 text-xs ${textClass} font-mono whitespace-pre-wrap">
56
60
  ${this.content || ""}</pre
57
61
  >
58
62
  </div>
@@ -0,0 +1,46 @@
1
+ import { icon } from "@mariozechner/mini-lit";
2
+ import { html, LitElement, type TemplateResult } from "lit";
3
+ import { customElement, property, state } from "lit/decorators.js";
4
+ import { ChevronDown, ChevronRight } from "lucide";
5
+
6
+ /**
7
+ * Reusable expandable section component for tool renderers.
8
+ * Captures children in connectedCallback and re-renders them in the details area.
9
+ */
10
+ @customElement("expandable-section")
11
+ export class ExpandableSection extends LitElement {
12
+ @property() summary!: string;
13
+ @property({ type: Boolean }) defaultExpanded = false;
14
+ @state() private expanded = false;
15
+ private capturedChildren: Node[] = [];
16
+
17
+ protected createRenderRoot() {
18
+ return this; // light DOM
19
+ }
20
+
21
+ override connectedCallback() {
22
+ super.connectedCallback();
23
+ // Capture children before first render
24
+ this.capturedChildren = Array.from(this.childNodes);
25
+ // Clear children (we'll re-insert them in render)
26
+ this.innerHTML = "";
27
+ this.expanded = this.defaultExpanded;
28
+ }
29
+
30
+ override render(): TemplateResult {
31
+ return html`
32
+ <div>
33
+ <button
34
+ @click=${() => {
35
+ this.expanded = !this.expanded;
36
+ }}
37
+ class="flex items-center gap-2 text-sm text-muted-foreground hover:text-foreground transition-colors w-full text-left"
38
+ >
39
+ ${icon(this.expanded ? ChevronDown : ChevronRight, "sm")}
40
+ <span>${this.summary}</span>
41
+ </button>
42
+ ${this.expanded ? html`<div class="mt-2">${this.capturedChildren}</div>` : ""}
43
+ </div>
44
+ `;
45
+ }
46
+ }
@@ -1,9 +1,9 @@
1
- import { Button, html, icon } from "@mariozechner/mini-lit";
1
+ import { Button, html, icon, Select, type SelectOption } from "@mariozechner/mini-lit";
2
2
  import type { Model } from "@mariozechner/pi-ai";
3
3
  import { LitElement } from "lit";
4
4
  import { customElement, property, state } from "lit/decorators.js";
5
5
  import { createRef, ref } from "lit/directives/ref.js";
6
- import { Loader2, Paperclip, Send, Sparkles, Square } from "lucide";
6
+ import { Brain, Loader2, Paperclip, Send, Sparkles, Square } from "lucide";
7
7
  import "./AttachmentTile.js";
8
8
  import { type Attachment, loadAttachment } from "../utils/attachment-utils.js";
9
9
  import { i18n } from "../utils/i18n.js";
@@ -33,13 +33,15 @@ export class MessageEditor extends LitElement {
33
33
 
34
34
  @property() isStreaming = false;
35
35
  @property() currentModel?: Model<any>;
36
+ @property() thinkingLevel: "off" | "minimal" | "low" | "medium" | "high" = "off";
36
37
  @property() showAttachmentButton = true;
37
38
  @property() showModelSelector = true;
38
- @property() showThinking = false; // Disabled for now
39
+ @property() showThinkingSelector = true;
39
40
  @property() onInput?: (value: string) => void;
40
41
  @property() onSend?: (input: string, attachments: Attachment[]) => void;
41
42
  @property() onAbort?: () => void;
42
43
  @property() onModelSelect?: () => void;
44
+ @property() onThinkingChange?: (level: "off" | "minimal" | "low" | "medium" | "high") => void;
43
45
  @property() onFilesChange?: (files: Attachment[]) => void;
44
46
  @property() attachments: Attachment[] = [];
45
47
  @property() maxFiles = 10;
@@ -48,6 +50,7 @@ export class MessageEditor extends LitElement {
48
50
  "image/*,application/pdf,.docx,.pptx,.xlsx,.xls,.txt,.md,.json,.xml,.html,.css,.js,.ts,.jsx,.tsx,.yml,.yaml";
49
51
 
50
52
  @state() processingFiles = false;
53
+ @state() isDragging = false;
51
54
  private fileInputRef = createRef<HTMLInputElement>();
52
55
 
53
56
  protected override createRenderRoot(): HTMLElement | DocumentFragment {
@@ -74,6 +77,56 @@ export class MessageEditor extends LitElement {
74
77
  }
75
78
  };
76
79
 
80
+ private handlePaste = async (e: ClipboardEvent) => {
81
+ const items = e.clipboardData?.items;
82
+ if (!items) return;
83
+
84
+ const imageFiles: File[] = [];
85
+
86
+ // Check for image items in clipboard
87
+ for (let i = 0; i < items.length; i++) {
88
+ const item = items[i];
89
+ if (item.type.startsWith("image/")) {
90
+ const file = item.getAsFile();
91
+ if (file) {
92
+ imageFiles.push(file);
93
+ }
94
+ }
95
+ }
96
+
97
+ // If we found images, process them
98
+ if (imageFiles.length > 0) {
99
+ e.preventDefault(); // Prevent default paste behavior
100
+
101
+ if (imageFiles.length + this.attachments.length > this.maxFiles) {
102
+ alert(`Maximum ${this.maxFiles} files allowed`);
103
+ return;
104
+ }
105
+
106
+ this.processingFiles = true;
107
+ const newAttachments: Attachment[] = [];
108
+
109
+ for (const file of imageFiles) {
110
+ try {
111
+ if (file.size > this.maxFileSize) {
112
+ alert(`Image exceeds maximum size of ${Math.round(this.maxFileSize / 1024 / 1024)}MB`);
113
+ continue;
114
+ }
115
+
116
+ const attachment = await loadAttachment(file);
117
+ newAttachments.push(attachment);
118
+ } catch (error) {
119
+ console.error("Error processing pasted image:", error);
120
+ alert(`Failed to process pasted image: ${String(error)}`);
121
+ }
122
+ }
123
+
124
+ this.attachments = [...this.attachments, ...newAttachments];
125
+ this.onFilesChange?.(this.attachments);
126
+ this.processingFiles = false;
127
+ }
128
+ };
129
+
77
130
  private handleSend = () => {
78
131
  this.onSend?.(this.value, this.attachments);
79
132
  };
@@ -122,6 +175,62 @@ export class MessageEditor extends LitElement {
122
175
  this.onFilesChange?.(this.attachments);
123
176
  }
124
177
 
178
+ private handleDragOver = (e: DragEvent) => {
179
+ e.preventDefault();
180
+ e.stopPropagation();
181
+ if (!this.isDragging) {
182
+ this.isDragging = true;
183
+ }
184
+ };
185
+
186
+ private handleDragLeave = (e: DragEvent) => {
187
+ e.preventDefault();
188
+ e.stopPropagation();
189
+ // Only set isDragging to false if we're leaving the entire component
190
+ const rect = (e.currentTarget as HTMLElement).getBoundingClientRect();
191
+ const x = e.clientX;
192
+ const y = e.clientY;
193
+ if (x <= rect.left || x >= rect.right || y <= rect.top || y >= rect.bottom) {
194
+ this.isDragging = false;
195
+ }
196
+ };
197
+
198
+ private handleDrop = async (e: DragEvent) => {
199
+ e.preventDefault();
200
+ e.stopPropagation();
201
+ this.isDragging = false;
202
+
203
+ const files = Array.from(e.dataTransfer?.files || []);
204
+ if (files.length === 0) return;
205
+
206
+ if (files.length + this.attachments.length > this.maxFiles) {
207
+ alert(`Maximum ${this.maxFiles} files allowed`);
208
+ return;
209
+ }
210
+
211
+ this.processingFiles = true;
212
+ const newAttachments: Attachment[] = [];
213
+
214
+ for (const file of files) {
215
+ try {
216
+ if (file.size > this.maxFileSize) {
217
+ alert(`${file.name} exceeds maximum size of ${Math.round(this.maxFileSize / 1024 / 1024)}MB`);
218
+ continue;
219
+ }
220
+
221
+ const attachment = await loadAttachment(file);
222
+ newAttachments.push(attachment);
223
+ } catch (error) {
224
+ console.error(`Error processing ${file.name}:`, error);
225
+ alert(`Failed to process ${file.name}: ${String(error)}`);
226
+ }
227
+ }
228
+
229
+ this.attachments = [...this.attachments, ...newAttachments];
230
+ this.onFilesChange?.(this.attachments);
231
+ this.processingFiles = false;
232
+ };
233
+
125
234
  private adjustTextareaHeight() {
126
235
  const textarea = this.textareaRef.value;
127
236
  if (textarea) {
@@ -150,8 +259,28 @@ export class MessageEditor extends LitElement {
150
259
  }
151
260
 
152
261
  override render() {
262
+ // Check if current model supports thinking/reasoning
263
+ const model = this.currentModel;
264
+ const supportsThinking = model?.reasoning === true; // Models with reasoning:true support thinking
265
+
153
266
  return html`
154
- <div class="bg-card rounded-xl border border-border shadow-sm">
267
+ <div
268
+ class="bg-card rounded-xl border shadow-sm relative ${this.isDragging ? "border-primary border-2 bg-primary/5" : "border-border"}"
269
+ @dragover=${this.handleDragOver}
270
+ @dragleave=${this.handleDragLeave}
271
+ @drop=${this.handleDrop}
272
+ >
273
+ <!-- Drag overlay -->
274
+ ${
275
+ this.isDragging
276
+ ? html`
277
+ <div class="absolute inset-0 bg-primary/10 rounded-xl pointer-events-none z-10 flex items-center justify-center">
278
+ <div class="text-primary font-medium">${i18n("Drop files here")}</div>
279
+ </div>
280
+ `
281
+ : ""
282
+ }
283
+
155
284
  <!-- Attachments -->
156
285
  ${
157
286
  this.attachments.length > 0
@@ -179,6 +308,7 @@ export class MessageEditor extends LitElement {
179
308
  .value=${this.value}
180
309
  @input=${this.handleTextareaInput}
181
310
  @keydown=${this.handleKeyDown}
311
+ @paste=${this.handlePaste}
182
312
  ${ref(this.textareaRef)}
183
313
  ></textarea>
184
314
 
@@ -194,7 +324,7 @@ export class MessageEditor extends LitElement {
194
324
 
195
325
  <!-- Button Row -->
196
326
  <div class="px-2 pb-2 flex items-center justify-between">
197
- <!-- Left side - attachment and quick action buttons -->
327
+ <!-- Left side - attachment and thinking selector -->
198
328
  <div class="flex gap-2 items-center">
199
329
  ${
200
330
  this.showAttachmentButton
@@ -215,6 +345,30 @@ export class MessageEditor extends LitElement {
215
345
  `
216
346
  : ""
217
347
  }
348
+ ${
349
+ supportsThinking && this.showThinkingSelector
350
+ ? html`
351
+ ${Select({
352
+ value: this.thinkingLevel,
353
+ placeholder: i18n("Off"),
354
+ options: [
355
+ { value: "off", label: i18n("Off"), icon: icon(Brain, "sm") },
356
+ { value: "minimal", label: i18n("Minimal"), icon: icon(Brain, "sm") },
357
+ { value: "low", label: i18n("Low"), icon: icon(Brain, "sm") },
358
+ { value: "medium", label: i18n("Medium"), icon: icon(Brain, "sm") },
359
+ { value: "high", label: i18n("High"), icon: icon(Brain, "sm") },
360
+ ] as SelectOption[],
361
+ onChange: (value: string) => {
362
+ this.onThinkingChange?.(value as "off" | "minimal" | "low" | "medium" | "high");
363
+ },
364
+ width: "80px",
365
+ size: "sm",
366
+ variant: "ghost",
367
+ fitContent: true,
368
+ })}
369
+ `
370
+ : ""
371
+ }
218
372
  </div>
219
373
 
220
374
  <!-- Model selector and send on the right -->
@@ -2,15 +2,16 @@ import { html } from "@mariozechner/mini-lit";
2
2
  import type {
3
3
  AgentTool,
4
4
  AssistantMessage as AssistantMessageType,
5
- Message,
6
5
  ToolResultMessage as ToolResultMessageType,
7
6
  } from "@mariozechner/pi-ai";
8
7
  import { LitElement, type TemplateResult } from "lit";
9
8
  import { property } from "lit/decorators.js";
10
9
  import { repeat } from "lit/directives/repeat.js";
10
+ import type { AppMessage } from "./Messages.js";
11
+ import { renderMessage } from "./message-renderer-registry.js";
11
12
 
12
13
  export class MessageList extends LitElement {
13
- @property({ type: Array }) messages: Message[] = [];
14
+ @property({ type: Array }) messages: AppMessage[] = [];
14
15
  @property({ type: Array }) tools: AgentTool[] = [];
15
16
  @property({ type: Object }) pendingToolCalls?: Set<string>;
16
17
  @property({ type: Boolean }) isStreaming: boolean = false;
@@ -36,6 +37,20 @@ export class MessageList extends LitElement {
36
37
  const items: Array<{ key: string; template: TemplateResult }> = [];
37
38
  let index = 0;
38
39
  for (const msg of this.messages) {
40
+ // Skip artifact messages - they're for session persistence only, not UI display
41
+ if (msg.role === "artifact") {
42
+ continue;
43
+ }
44
+
45
+ // Try custom renderer first
46
+ const customTemplate = renderMessage(msg);
47
+ if (customTemplate) {
48
+ items.push({ key: `msg:${index}`, template: customTemplate });
49
+ index++;
50
+ continue;
51
+ }
52
+
53
+ // Fall back to built-in renderers
39
54
  if (msg.role === "user") {
40
55
  items.push({
41
56
  key: `msg:${index}`,
@@ -58,7 +73,7 @@ export class MessageList extends LitElement {
58
73
  index++;
59
74
  } else {
60
75
  // Skip standalone toolResult messages; they are rendered via paired tool-message above
61
- // For completeness, other roles are not expected
76
+ // Skip unknown roles
62
77
  }
63
78
  }
64
79
  return items;
@@ -1,4 +1,4 @@
1
- import { Button, html, icon } from "@mariozechner/mini-lit";
1
+ import { html } from "@mariozechner/mini-lit";
2
2
  import type {
3
3
  AgentTool,
4
4
  AssistantMessage as AssistantMessageType,
@@ -6,17 +6,41 @@ import type {
6
6
  ToolResultMessage as ToolResultMessageType,
7
7
  UserMessage as UserMessageType,
8
8
  } from "@mariozechner/pi-ai";
9
- import type { AgentToolResult } from "@mariozechner/pi-ai/dist/agent/types.js";
10
9
  import { LitElement, type TemplateResult } from "lit";
11
- import { customElement, property, state } from "lit/decorators.js";
12
- import { Bug, Loader, Wrench } from "lucide";
13
- import { renderToolParams, renderToolResult } from "../tools/index.js";
10
+ import { customElement, property } from "lit/decorators.js";
11
+ import { renderTool } from "../tools/index.js";
14
12
  import type { Attachment } from "../utils/attachment-utils.js";
15
13
  import { formatUsage } from "../utils/format.js";
16
14
  import { i18n } from "../utils/i18n.js";
17
15
 
18
16
  export type UserMessageWithAttachments = UserMessageType & { attachments?: Attachment[] };
19
- export type AppMessage = AssistantMessageType | UserMessageWithAttachments | ToolResultMessageType;
17
+
18
+ // Artifact message type for session persistence
19
+ export interface ArtifactMessage {
20
+ role: "artifact";
21
+ action: "create" | "update" | "delete";
22
+ filename: string;
23
+ content?: string;
24
+ title?: string;
25
+ timestamp: string;
26
+ }
27
+
28
+ // Base message union
29
+ type BaseMessage = AssistantMessageType | UserMessageWithAttachments | ToolResultMessageType | ArtifactMessage;
30
+
31
+ // Extensible interface - apps can extend via declaration merging
32
+ // Example:
33
+ // declare module "@mariozechner/pi-web-ui" {
34
+ // interface CustomMessages {
35
+ // "system-notification": SystemNotificationMessage;
36
+ // }
37
+ // }
38
+ export interface CustomMessages {
39
+ // Empty by default - apps extend via declaration merging
40
+ }
41
+
42
+ // AppMessage is union of base messages + custom messages
43
+ export type AppMessage = BaseMessage | CustomMessages[keyof CustomMessages];
20
44
 
21
45
  @customElement("user-message")
22
46
  export class UserMessage extends LitElement {
@@ -88,7 +112,8 @@ export class AssistantMessage extends LitElement {
88
112
  const tool = this.tools?.find((t) => t.name === chunk.name);
89
113
  const pending = this.pendingToolCalls?.has(chunk.id) ?? false;
90
114
  const result = this.toolResultsById?.get(chunk.id);
91
- const aborted = !pending && !result && !this.isStreaming;
115
+ // A tool call is aborted if the message was aborted and there's no result for this tool call
116
+ const aborted = this.message.stopReason === "aborted" && !result;
92
117
  orderedParts.push(
93
118
  html`<tool-message
94
119
  .tool=${tool}
@@ -133,7 +158,7 @@ export class AssistantMessage extends LitElement {
133
158
  @customElement("tool-message-debug")
134
159
  export class ToolMessageDebugView extends LitElement {
135
160
  @property({ type: Object }) callArgs: any;
136
- @property({ type: String }) result?: AgentToolResult<any>;
161
+ @property({ type: Object }) result?: ToolResultMessageType;
137
162
  @property({ type: Boolean }) hasResult: boolean = false;
138
163
 
139
164
  protected override createRenderRoot(): HTMLElement | DocumentFragment {
@@ -189,7 +214,6 @@ export class ToolMessage extends LitElement {
189
214
  @property({ type: Boolean }) pending: boolean = false;
190
215
  @property({ type: Boolean }) aborted: boolean = false;
191
216
  @property({ type: Boolean }) isStreaming: boolean = false;
192
- @state() private _showDebug = false;
193
217
 
194
218
  protected override createRenderRoot(): HTMLElement | DocumentFragment {
195
219
  return this;
@@ -200,94 +224,29 @@ export class ToolMessage extends LitElement {
200
224
  this.style.display = "block";
201
225
  }
202
226
 
203
- private toggleDebug = () => {
204
- this._showDebug = !this._showDebug;
205
- };
206
-
207
227
  override render() {
208
- const toolLabel = this.tool?.label || this.toolCall.name;
209
228
  const toolName = this.tool?.name || this.toolCall.name;
210
- const isError = this.result?.isError === true;
211
- const hasResult = !!this.result;
212
-
213
- let statusIcon: TemplateResult;
214
- if (this.pending || (this.isStreaming && !hasResult)) {
215
- statusIcon = html`<span class="inline-block text-muted-foreground animate-spin">${icon(Loader, "sm")}</span>`;
216
- } else if (this.aborted && !hasResult) {
217
- statusIcon = html`<span class="inline-block text-destructive">${icon(Wrench, "sm")}</span>`;
218
- } else if (hasResult && isError) {
219
- statusIcon = html`<span class="inline-block text-destructive">${icon(Wrench, "sm")}</span>`;
220
- } else if (hasResult) {
221
- statusIcon = html`<span class="inline-block text-muted-foreground">${icon(Wrench, "sm")}</span>`;
222
- } else {
223
- statusIcon = html`<span class="inline-block text-muted-foreground">${icon(Wrench, "sm")}</span>`;
224
- }
225
229
 
226
- // Normalize error text
227
- let errorMessage = this.result?.output || "";
228
- if (isError) {
229
- try {
230
- const parsed = JSON.parse(errorMessage);
231
- if ((parsed as any).error) errorMessage = (parsed as any).error;
232
- else if ((parsed as any).message) errorMessage = (parsed as any).message;
233
- } catch {}
234
- errorMessage = errorMessage.replace(/^(Tool )?Error:\s*/i, "");
235
- errorMessage = errorMessage.replace(/^Error:\s*/i, "");
236
- }
237
-
238
- const paramsTpl = renderToolParams(
230
+ // Render tool content (renderer handles errors and styling)
231
+ const result: ToolResultMessageType<any> | undefined = this.aborted
232
+ ? { role: "toolResult", isError: true, output: "", toolCallId: this.toolCall.id, toolName: this.toolCall.name }
233
+ : this.result;
234
+ const renderResult = renderTool(
239
235
  toolName,
240
236
  this.toolCall.arguments,
241
- this.isStreaming || (this.pending && !hasResult),
237
+ result,
238
+ !this.aborted && (this.isStreaming || this.pending),
242
239
  );
243
- const resultTpl =
244
- hasResult && !isError ? renderToolResult(toolName, this.toolCall.arguments, this.result!) : undefined;
245
240
 
246
- return html`
247
- <div class="p-2.5 border border-border rounded-md bg-card text-card-foreground">
248
- <div class="flex items-center justify-between text-xs text-muted-foreground">
249
- <div class="flex items-center gap-2">
250
- ${statusIcon}
251
- <span class="font-medium">${toolLabel}</span>
252
- </div>
253
- ${Button({
254
- variant: this._showDebug ? "default" : "ghost",
255
- size: "sm",
256
- onClick: this.toggleDebug,
257
- children: icon(Bug, "sm"),
258
- className: "text-muted-foreground",
259
- })}
260
- </div>
241
+ // Handle custom rendering (no card wrapper)
242
+ if (renderResult.isCustom) {
243
+ return renderResult.content;
244
+ }
261
245
 
262
- ${
263
- this._showDebug
264
- ? html`<tool-message-debug
265
- .callArgs=${this.toolCall.arguments}
266
- .result=${this.result}
267
- .hasResult=${!!this.result}
268
- ></tool-message-debug>`
269
- : html`
270
- <div class="mt-2 text-sm text-muted-foreground">${paramsTpl}</div>
271
- ${
272
- this.pending && !hasResult
273
- ? html`<div class="mt-2 text-sm text-muted-foreground">${i18n("Waiting for tool result…")}</div>`
274
- : ""
275
- }
276
- ${
277
- this.aborted && !hasResult
278
- ? html`<div class="mt-2 text-sm text-muted-foreground">${i18n("Call was aborted; no result.")}</div>`
279
- : ""
280
- }
281
- ${
282
- hasResult && isError
283
- ? html`<div class="mt-2 p-2 border border-destructive rounded bg-destructive/10 text-sm text-destructive">
284
- ${errorMessage}
285
- </div>`
286
- : ""
287
- }
288
- ${resultTpl ? html`<div class="mt-2">${resultTpl}</div>` : ""}
289
- `
290
- }
246
+ // Default: wrap in card
247
+ return html`
248
+ <div class="p-2.5 border border-border rounded-md bg-card text-card-foreground shadow-xs">
249
+ ${renderResult.content}
291
250
  </div>
292
251
  `;
293
252
  }