@mariozechner/pi-web-ui 0.5.44

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 (265) hide show
  1. package/README.md +252 -0
  2. package/dist/ChatPanel.d.ts +23 -0
  3. package/dist/ChatPanel.d.ts.map +1 -0
  4. package/dist/ChatPanel.js +224 -0
  5. package/dist/ChatPanel.js.map +1 -0
  6. package/dist/app.css +2 -0
  7. package/dist/components/AgentInterface.d.ts +35 -0
  8. package/dist/components/AgentInterface.d.ts.map +1 -0
  9. package/dist/components/AgentInterface.js +308 -0
  10. package/dist/components/AgentInterface.js.map +1 -0
  11. package/dist/components/AttachmentTile.d.ts +12 -0
  12. package/dist/components/AttachmentTile.d.ts.map +1 -0
  13. package/dist/components/AttachmentTile.js +114 -0
  14. package/dist/components/AttachmentTile.js.map +1 -0
  15. package/dist/components/ConsoleBlock.d.ts +11 -0
  16. package/dist/components/ConsoleBlock.d.ts.map +1 -0
  17. package/dist/components/ConsoleBlock.js +77 -0
  18. package/dist/components/ConsoleBlock.js.map +1 -0
  19. package/dist/components/Input.d.ts +26 -0
  20. package/dist/components/Input.d.ts.map +1 -0
  21. package/dist/components/Input.js +56 -0
  22. package/dist/components/Input.js.map +1 -0
  23. package/dist/components/MessageEditor.d.ts +38 -0
  24. package/dist/components/MessageEditor.d.ts.map +1 -0
  25. package/dist/components/MessageEditor.js +296 -0
  26. package/dist/components/MessageEditor.js.map +1 -0
  27. package/dist/components/MessageList.d.ts +13 -0
  28. package/dist/components/MessageList.d.ts.map +1 -0
  29. package/dist/components/MessageList.js +88 -0
  30. package/dist/components/MessageList.js.map +1 -0
  31. package/dist/components/Messages.d.ts +53 -0
  32. package/dist/components/Messages.d.ts.map +1 -0
  33. package/dist/components/Messages.js +323 -0
  34. package/dist/components/Messages.js.map +1 -0
  35. package/dist/components/ProviderKeyInput.d.ts +16 -0
  36. package/dist/components/ProviderKeyInput.d.ts.map +1 -0
  37. package/dist/components/ProviderKeyInput.js +183 -0
  38. package/dist/components/ProviderKeyInput.js.map +1 -0
  39. package/dist/components/SandboxedIframe.d.ts +63 -0
  40. package/dist/components/SandboxedIframe.d.ts.map +1 -0
  41. package/dist/components/SandboxedIframe.js +435 -0
  42. package/dist/components/SandboxedIframe.js.map +1 -0
  43. package/dist/components/StreamingMessageContainer.d.ts +17 -0
  44. package/dist/components/StreamingMessageContainer.d.ts.map +1 -0
  45. package/dist/components/StreamingMessageContainer.js +114 -0
  46. package/dist/components/StreamingMessageContainer.js.map +1 -0
  47. package/dist/dialogs/ApiKeyPromptDialog.d.ts +15 -0
  48. package/dist/dialogs/ApiKeyPromptDialog.d.ts.map +1 -0
  49. package/dist/dialogs/ApiKeyPromptDialog.js +80 -0
  50. package/dist/dialogs/ApiKeyPromptDialog.js.map +1 -0
  51. package/dist/dialogs/AttachmentOverlay.d.ts +32 -0
  52. package/dist/dialogs/AttachmentOverlay.d.ts.map +1 -0
  53. package/dist/dialogs/AttachmentOverlay.js +575 -0
  54. package/dist/dialogs/AttachmentOverlay.js.map +1 -0
  55. package/dist/dialogs/ModelSelector.d.ts +27 -0
  56. package/dist/dialogs/ModelSelector.d.ts.map +1 -0
  57. package/dist/dialogs/ModelSelector.js +334 -0
  58. package/dist/dialogs/ModelSelector.js.map +1 -0
  59. package/dist/dialogs/SettingsDialog.d.ts +31 -0
  60. package/dist/dialogs/SettingsDialog.d.ts.map +1 -0
  61. package/dist/dialogs/SettingsDialog.js +228 -0
  62. package/dist/dialogs/SettingsDialog.js.map +1 -0
  63. package/dist/index.d.ts +46 -0
  64. package/dist/index.d.ts.map +1 -0
  65. package/dist/index.js +51 -0
  66. package/dist/index.js.map +1 -0
  67. package/dist/state/agent-session.d.ts +58 -0
  68. package/dist/state/agent-session.d.ts.map +1 -0
  69. package/dist/state/agent-session.js +252 -0
  70. package/dist/state/agent-session.js.map +1 -0
  71. package/dist/state/transports/AppTransport.d.ts +13 -0
  72. package/dist/state/transports/AppTransport.d.ts.map +1 -0
  73. package/dist/state/transports/AppTransport.js +316 -0
  74. package/dist/state/transports/AppTransport.js.map +1 -0
  75. package/dist/state/transports/ProviderTransport.d.ts +12 -0
  76. package/dist/state/transports/ProviderTransport.d.ts.map +1 -0
  77. package/dist/state/transports/ProviderTransport.js +44 -0
  78. package/dist/state/transports/ProviderTransport.js.map +1 -0
  79. package/dist/state/transports/index.d.ts +4 -0
  80. package/dist/state/transports/index.d.ts.map +1 -0
  81. package/dist/state/transports/index.js +4 -0
  82. package/dist/state/transports/index.js.map +1 -0
  83. package/dist/state/transports/proxy-types.d.ts +48 -0
  84. package/dist/state/transports/proxy-types.d.ts.map +1 -0
  85. package/dist/state/transports/proxy-types.js +2 -0
  86. package/dist/state/transports/proxy-types.js.map +1 -0
  87. package/dist/state/transports/types.d.ts +11 -0
  88. package/dist/state/transports/types.d.ts.map +1 -0
  89. package/dist/state/transports/types.js +2 -0
  90. package/dist/state/transports/types.js.map +1 -0
  91. package/dist/state/types.d.ts +15 -0
  92. package/dist/state/types.d.ts.map +1 -0
  93. package/dist/state/types.js +2 -0
  94. package/dist/state/types.js.map +1 -0
  95. package/dist/storage/app-storage.d.ts +26 -0
  96. package/dist/storage/app-storage.d.ts.map +1 -0
  97. package/dist/storage/app-storage.js +44 -0
  98. package/dist/storage/app-storage.js.map +1 -0
  99. package/dist/storage/backends/chrome-storage-backend.d.ts +18 -0
  100. package/dist/storage/backends/chrome-storage-backend.d.ts.map +1 -0
  101. package/dist/storage/backends/chrome-storage-backend.js +67 -0
  102. package/dist/storage/backends/chrome-storage-backend.js.map +1 -0
  103. package/dist/storage/backends/indexeddb-backend.d.ts +20 -0
  104. package/dist/storage/backends/indexeddb-backend.d.ts.map +1 -0
  105. package/dist/storage/backends/indexeddb-backend.js +89 -0
  106. package/dist/storage/backends/indexeddb-backend.js.map +1 -0
  107. package/dist/storage/backends/local-storage-backend.d.ts +18 -0
  108. package/dist/storage/backends/local-storage-backend.d.ts.map +1 -0
  109. package/dist/storage/backends/local-storage-backend.js +69 -0
  110. package/dist/storage/backends/local-storage-backend.js.map +1 -0
  111. package/dist/storage/repositories/provider-keys-repository.d.ts +34 -0
  112. package/dist/storage/repositories/provider-keys-repository.d.ts.map +1 -0
  113. package/dist/storage/repositories/provider-keys-repository.js +50 -0
  114. package/dist/storage/repositories/provider-keys-repository.js.map +1 -0
  115. package/dist/storage/repositories/settings-repository.d.ts +34 -0
  116. package/dist/storage/repositories/settings-repository.d.ts.map +1 -0
  117. package/dist/storage/repositories/settings-repository.js +46 -0
  118. package/dist/storage/repositories/settings-repository.js.map +1 -0
  119. package/dist/storage/types.d.ts +43 -0
  120. package/dist/storage/types.d.ts.map +1 -0
  121. package/dist/storage/types.js +2 -0
  122. package/dist/storage/types.js.map +1 -0
  123. package/dist/tools/artifacts/ArtifactElement.d.ts +10 -0
  124. package/dist/tools/artifacts/ArtifactElement.d.ts.map +1 -0
  125. package/dist/tools/artifacts/ArtifactElement.js +12 -0
  126. package/dist/tools/artifacts/ArtifactElement.js.map +1 -0
  127. package/dist/tools/artifacts/HtmlArtifact.d.ts +30 -0
  128. package/dist/tools/artifacts/HtmlArtifact.d.ts.map +1 -0
  129. package/dist/tools/artifacts/HtmlArtifact.js +217 -0
  130. package/dist/tools/artifacts/HtmlArtifact.js.map +1 -0
  131. package/dist/tools/artifacts/MarkdownArtifact.d.ts +20 -0
  132. package/dist/tools/artifacts/MarkdownArtifact.d.ts.map +1 -0
  133. package/dist/tools/artifacts/MarkdownArtifact.js +84 -0
  134. package/dist/tools/artifacts/MarkdownArtifact.js.map +1 -0
  135. package/dist/tools/artifacts/SvgArtifact.d.ts +19 -0
  136. package/dist/tools/artifacts/SvgArtifact.d.ts.map +1 -0
  137. package/dist/tools/artifacts/SvgArtifact.js +80 -0
  138. package/dist/tools/artifacts/SvgArtifact.js.map +1 -0
  139. package/dist/tools/artifacts/TextArtifact.d.ts +20 -0
  140. package/dist/tools/artifacts/TextArtifact.d.ts.map +1 -0
  141. package/dist/tools/artifacts/TextArtifact.js +147 -0
  142. package/dist/tools/artifacts/TextArtifact.js.map +1 -0
  143. package/dist/tools/artifacts/artifacts.d.ts +67 -0
  144. package/dist/tools/artifacts/artifacts.d.ts.map +1 -0
  145. package/dist/tools/artifacts/artifacts.js +836 -0
  146. package/dist/tools/artifacts/artifacts.js.map +1 -0
  147. package/dist/tools/artifacts/index.d.ts +7 -0
  148. package/dist/tools/artifacts/index.d.ts.map +1 -0
  149. package/dist/tools/artifacts/index.js +7 -0
  150. package/dist/tools/artifacts/index.js.map +1 -0
  151. package/dist/tools/index.d.ts +14 -0
  152. package/dist/tools/index.d.ts.map +1 -0
  153. package/dist/tools/index.js +29 -0
  154. package/dist/tools/index.js.map +1 -0
  155. package/dist/tools/javascript-repl.d.ts +43 -0
  156. package/dist/tools/javascript-repl.d.ts.map +1 -0
  157. package/dist/tools/javascript-repl.js +252 -0
  158. package/dist/tools/javascript-repl.js.map +1 -0
  159. package/dist/tools/renderer-registry.d.ts +11 -0
  160. package/dist/tools/renderer-registry.d.ts.map +1 -0
  161. package/dist/tools/renderer-registry.js +15 -0
  162. package/dist/tools/renderer-registry.js.map +1 -0
  163. package/dist/tools/renderers/BashRenderer.d.ts +12 -0
  164. package/dist/tools/renderers/BashRenderer.d.ts.map +1 -0
  165. package/dist/tools/renderers/BashRenderer.js +35 -0
  166. package/dist/tools/renderers/BashRenderer.js.map +1 -0
  167. package/dist/tools/renderers/CalculateRenderer.d.ts +12 -0
  168. package/dist/tools/renderers/CalculateRenderer.d.ts.map +1 -0
  169. package/dist/tools/renderers/CalculateRenderer.js +38 -0
  170. package/dist/tools/renderers/CalculateRenderer.js.map +1 -0
  171. package/dist/tools/renderers/DefaultRenderer.d.ts +8 -0
  172. package/dist/tools/renderers/DefaultRenderer.d.ts.map +1 -0
  173. package/dist/tools/renderers/DefaultRenderer.js +31 -0
  174. package/dist/tools/renderers/DefaultRenderer.js.map +1 -0
  175. package/dist/tools/renderers/GetCurrentTimeRenderer.d.ts +12 -0
  176. package/dist/tools/renderers/GetCurrentTimeRenderer.d.ts.map +1 -0
  177. package/dist/tools/renderers/GetCurrentTimeRenderer.js +30 -0
  178. package/dist/tools/renderers/GetCurrentTimeRenderer.js.map +1 -0
  179. package/dist/tools/types.d.ts +7 -0
  180. package/dist/tools/types.d.ts.map +1 -0
  181. package/dist/tools/types.js +2 -0
  182. package/dist/tools/types.js.map +1 -0
  183. package/dist/utils/attachment-utils.d.ts +19 -0
  184. package/dist/utils/attachment-utils.d.ts.map +1 -0
  185. package/dist/utils/attachment-utils.js +415 -0
  186. package/dist/utils/attachment-utils.js.map +1 -0
  187. package/dist/utils/auth-token.d.ts +3 -0
  188. package/dist/utils/auth-token.d.ts.map +1 -0
  189. package/dist/utils/auth-token.js +19 -0
  190. package/dist/utils/auth-token.js.map +1 -0
  191. package/dist/utils/format.d.ts +6 -0
  192. package/dist/utils/format.d.ts.map +1 -0
  193. package/dist/utils/format.js +47 -0
  194. package/dist/utils/format.js.map +1 -0
  195. package/dist/utils/i18n.d.ts +111 -0
  196. package/dist/utils/i18n.d.ts.map +1 -0
  197. package/dist/utils/i18n.js +224 -0
  198. package/dist/utils/i18n.js.map +1 -0
  199. package/dist/utils/test-sessions.d.ts +347 -0
  200. package/dist/utils/test-sessions.d.ts.map +1 -0
  201. package/dist/utils/test-sessions.js +2215 -0
  202. package/dist/utils/test-sessions.js.map +1 -0
  203. package/example/README.md +61 -0
  204. package/example/index.html +13 -0
  205. package/example/package-lock.json +1965 -0
  206. package/example/package.json +22 -0
  207. package/example/src/app.css +1 -0
  208. package/example/src/main.ts +57 -0
  209. package/example/src/test-sessions.ts +104 -0
  210. package/example/tsconfig.json +15 -0
  211. package/example/vite.config.ts +6 -0
  212. package/package.json +45 -0
  213. package/src/ChatPanel.ts +214 -0
  214. package/src/app.css +44 -0
  215. package/src/components/AgentInterface.ts +316 -0
  216. package/src/components/AttachmentTile.ts +112 -0
  217. package/src/components/ConsoleBlock.ts +67 -0
  218. package/src/components/Input.ts +112 -0
  219. package/src/components/MessageEditor.ts +272 -0
  220. package/src/components/MessageList.ts +82 -0
  221. package/src/components/Messages.ts +310 -0
  222. package/src/components/ProviderKeyInput.ts +170 -0
  223. package/src/components/SandboxedIframe.ts +525 -0
  224. package/src/components/StreamingMessageContainer.ts +101 -0
  225. package/src/dialogs/ApiKeyPromptDialog.ts +76 -0
  226. package/src/dialogs/AttachmentOverlay.ts +635 -0
  227. package/src/dialogs/ModelSelector.ts +324 -0
  228. package/src/dialogs/SettingsDialog.ts +223 -0
  229. package/src/index.ts +63 -0
  230. package/src/state/agent-session.ts +311 -0
  231. package/src/state/transports/AppTransport.ts +363 -0
  232. package/src/state/transports/ProviderTransport.ts +49 -0
  233. package/src/state/transports/index.ts +3 -0
  234. package/src/state/transports/proxy-types.ts +15 -0
  235. package/src/state/transports/types.ts +16 -0
  236. package/src/state/types.ts +11 -0
  237. package/src/storage/app-storage.ts +53 -0
  238. package/src/storage/backends/chrome-storage-backend.ts +82 -0
  239. package/src/storage/backends/indexeddb-backend.ts +107 -0
  240. package/src/storage/backends/local-storage-backend.ts +74 -0
  241. package/src/storage/repositories/provider-keys-repository.ts +55 -0
  242. package/src/storage/repositories/settings-repository.ts +51 -0
  243. package/src/storage/types.ts +48 -0
  244. package/src/tools/artifacts/ArtifactElement.ts +15 -0
  245. package/src/tools/artifacts/HtmlArtifact.ts +221 -0
  246. package/src/tools/artifacts/MarkdownArtifact.ts +81 -0
  247. package/src/tools/artifacts/SvgArtifact.ts +77 -0
  248. package/src/tools/artifacts/TextArtifact.ts +148 -0
  249. package/src/tools/artifacts/artifacts.ts +888 -0
  250. package/src/tools/artifacts/index.ts +6 -0
  251. package/src/tools/index.ts +35 -0
  252. package/src/tools/javascript-repl.ts +309 -0
  253. package/src/tools/renderer-registry.ts +18 -0
  254. package/src/tools/renderers/BashRenderer.ts +45 -0
  255. package/src/tools/renderers/CalculateRenderer.ts +49 -0
  256. package/src/tools/renderers/DefaultRenderer.ts +36 -0
  257. package/src/tools/renderers/GetCurrentTimeRenderer.ts +39 -0
  258. package/src/tools/types.ts +7 -0
  259. package/src/utils/attachment-utils.ts +472 -0
  260. package/src/utils/auth-token.ts +22 -0
  261. package/src/utils/format.ts +42 -0
  262. package/src/utils/i18n.ts +343 -0
  263. package/src/utils/test-sessions.ts +2247 -0
  264. package/tsconfig.build.json +20 -0
  265. package/tsconfig.json +7 -0
@@ -0,0 +1,22 @@
1
+ {
2
+ "name": "pi-web-ui-example",
3
+ "version": "1.0.0",
4
+ "type": "module",
5
+ "scripts": {
6
+ "dev": "vite",
7
+ "build": "vite build",
8
+ "preview": "vite preview"
9
+ },
10
+ "dependencies": {
11
+ "@mariozechner/mini-lit": "^0.1.7",
12
+ "@mariozechner/pi-ai": "file:../../ai",
13
+ "@mariozechner/pi-web-ui": "file:../",
14
+ "@tailwindcss/vite": "^4.1.13",
15
+ "lit": "^3.3.1",
16
+ "lucide": "^0.544.0"
17
+ },
18
+ "devDependencies": {
19
+ "typescript": "^5.7.3",
20
+ "vite": "^7.1.6"
21
+ }
22
+ }
@@ -0,0 +1 @@
1
+ @import "../../dist/app.css";
@@ -0,0 +1,57 @@
1
+ import { Button, icon } from "@mariozechner/mini-lit";
2
+ import "@mariozechner/mini-lit/dist/ThemeToggle.js";
3
+ import { ApiKeyPromptDialog, ApiKeysTab, ChatPanel, initAppStorage, ProxyTab, SettingsDialog } from "@mariozechner/pi-web-ui";
4
+ import { html, render } from "lit";
5
+ import { Settings } from "lucide";
6
+ import "./app.css";
7
+
8
+ // Initialize storage with default configuration (localStorage)
9
+ initAppStorage();
10
+
11
+ const systemPrompt = `You are a helpful AI assistant with access to various tools.
12
+
13
+ Available tools:
14
+ - JavaScript REPL: Execute JavaScript code in a sandboxed browser environment (can do calculations, get time, process data, create visualizations, etc.)
15
+ - Artifacts: Create interactive HTML, SVG, Markdown, and text artifacts
16
+
17
+ Feel free to use these tools when needed to provide accurate and helpful responses.`;
18
+
19
+ // Create and configure the chat panel
20
+ const chatPanel = new ChatPanel();
21
+ chatPanel.systemPrompt = systemPrompt;
22
+ chatPanel.additionalTools = [];
23
+ chatPanel.onApiKeyRequired = async (provider: string) => {
24
+ return await ApiKeyPromptDialog.prompt(provider);
25
+ };
26
+
27
+ // Render the app structure
28
+ const appHtml = html`
29
+ <div class="w-full h-screen flex flex-col bg-background text-foreground overflow-hidden">
30
+ <!-- Header -->
31
+ <div class="flex items-center justify-between border-b border-border shrink-0">
32
+ <div class="px-4 py-3">
33
+ <span class="text-base font-semibold text-foreground">Pi Web UI Example</span>
34
+ </div>
35
+ <div class="flex items-center gap-1 px-2">
36
+ <theme-toggle></theme-toggle>
37
+ ${Button({
38
+ variant: "ghost",
39
+ size: "sm",
40
+ children: icon(Settings, "sm"),
41
+ onClick: () => SettingsDialog.open([new ApiKeysTab(), new ProxyTab()]),
42
+ title: "Settings",
43
+ })}
44
+ </div>
45
+ </div>
46
+
47
+ <!-- Chat Panel -->
48
+ ${chatPanel}
49
+ </div>
50
+ `;
51
+
52
+ const app = document.getElementById("app");
53
+ if (!app) {
54
+ throw new Error("App container not found");
55
+ }
56
+
57
+ render(appHtml, app);
@@ -0,0 +1,104 @@
1
+ const simpleHtml = {
2
+ "systemPrompt": "You are a helpful AI assistant with access to various tools.\n\nAvailable tools:\n- Calculator: Perform mathematical calculations\n- Current Time: Get the current date and time in any timezone\n- Artifacts: Create interactive HTML, SVG, Markdown, and text artifacts\n\nFeel free to use these tools when needed to provide accurate and helpful responses.",
3
+ "model": {
4
+ "id": "claude-sonnet-4-5-20250929",
5
+ "name": "Claude Sonnet 4.5",
6
+ "api": "anthropic-messages",
7
+ "provider": "anthropic",
8
+ "baseUrl": "https://api.anthropic.com",
9
+ "reasoning": true,
10
+ "input": [
11
+ "text",
12
+ "image"
13
+ ],
14
+ "cost": {
15
+ "input": 3,
16
+ "output": 15,
17
+ "cacheRead": 0.3,
18
+ "cacheWrite": 3.75
19
+ },
20
+ "contextWindow": 200000,
21
+ "maxTokens": 64000
22
+ },
23
+ "messages": [
24
+ {
25
+ "role": "user",
26
+ "content": [
27
+ {
28
+ "type": "text",
29
+ "text": "simple html"
30
+ }
31
+ ]
32
+ },
33
+ {
34
+ "role": "assistant",
35
+ "content": [
36
+ {
37
+ "type": "text",
38
+ "text": "I'll create a simple HTML page for you!"
39
+ },
40
+ {
41
+ "type": "toolCall",
42
+ "id": "toolu_01JXaq9rMAUt1goJ5tMQXgLh",
43
+ "name": "artifacts",
44
+ "arguments": {
45
+ "command": "create",
46
+ "filename": "index.html",
47
+ "title": "Simple HTML Page",
48
+ "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>Simple HTML Page</title>\n <style>\n body {\n font-family: Arial, sans-serif;\n max-width: 800px;\n margin: 0 auto;\n padding: 20px;\n background-color: #f5f5f5;\n }\n \n header {\n background-color: #4CAF50;\n color: white;\n padding: 20px;\n text-align: center;\n border-radius: 8px;\n }\n \n main {\n background-color: white;\n padding: 20px;\n margin-top: 20px;\n border-radius: 8px;\n box-shadow: 0 2px 4px rgba(0,0,0,0.1);\n }\n \n button {\n background-color: #4CAF50;\n color: white;\n padding: 10px 20px;\n border: none;\n border-radius: 4px;\n cursor: pointer;\n font-size: 16px;\n }\n \n button:hover {\n background-color: #45a049;\n }\n </style>\n</head>\n<body>\n <header>\n <h1>Welcome to My Simple Page</h1>\n </header>\n \n <main>\n <h2>Hello!</h2>\n <p>This is a simple HTML page with some basic styling.</p>\n \n <h3>Features:</h3>\n <ul>\n <li>Clean design</li>\n <li>Responsive layout</li>\n <li>Interactive button</li>\n </ul>\n \n <button onclick=\"showMessage()\">Click Me!</button>\n <p id=\"message\"></p>\n </main>\n \n <script>\n function showMessage() {\n document.getElementById('message').textContent = '✨ Thanks for clicking!';\n }\n </script>\n</body>\n</html>"
49
+ }
50
+ }
51
+ ],
52
+ "api": "anthropic-messages",
53
+ "provider": "anthropic",
54
+ "model": "claude-sonnet-4-5-20250929",
55
+ "usage": {
56
+ "input": 2108,
57
+ "output": 666,
58
+ "cacheRead": 0,
59
+ "cacheWrite": 0,
60
+ "cost": {
61
+ "input": 0.006324,
62
+ "output": 0.00999,
63
+ "cacheRead": 0,
64
+ "cacheWrite": 0,
65
+ "total": 0.016314000000000002
66
+ }
67
+ },
68
+ "stopReason": "toolUse"
69
+ },
70
+ {
71
+ "role": "toolResult",
72
+ "toolCallId": "toolu_01JXaq9rMAUt1goJ5tMQXgLh",
73
+ "toolName": "artifacts",
74
+ "output": "Created file index.html\n\nExecution timed out. Partial logs:\nKeine Logs für index.html",
75
+ "isError": false
76
+ },
77
+ {
78
+ "role": "assistant",
79
+ "content": [
80
+ {
81
+ "type": "text",
82
+ "text": "I've created a simple HTML page for you! It includes:\n\n- **Clean header** with a green background\n- **Main content area** with a white card-style design\n- **A list** showing some features\n- **An interactive button** that displays a message when clicked\n- **Responsive styling** that looks good on different screen sizes\n\nThe page has a light gray background and uses simple, clean styling. Try clicking the button to see it in action! \n\nWould you like me to modify anything or add more features?"
83
+ }
84
+ ],
85
+ "api": "anthropic-messages",
86
+ "provider": "anthropic",
87
+ "model": "claude-sonnet-4-5-20250929",
88
+ "usage": {
89
+ "input": 2811,
90
+ "output": 115,
91
+ "cacheRead": 0,
92
+ "cacheWrite": 0,
93
+ "cost": {
94
+ "input": 0.008433,
95
+ "output": 0.001725,
96
+ "cacheRead": 0,
97
+ "cacheWrite": 0,
98
+ "total": 0.010158
99
+ }
100
+ },
101
+ "stopReason": "stop"
102
+ }
103
+ ]
104
+ };
@@ -0,0 +1,15 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "ES2022",
5
+ "lib": ["ES2022", "DOM", "DOM.Iterable"],
6
+ "moduleResolution": "bundler",
7
+ "strict": true,
8
+ "skipLibCheck": true,
9
+ "esModuleInterop": true,
10
+ "allowSyntheticDefaultImports": true,
11
+ "experimentalDecorators": true,
12
+ "useDefineForClassFields": false
13
+ },
14
+ "include": ["src/**/*"]
15
+ }
@@ -0,0 +1,6 @@
1
+ import tailwindcss from "@tailwindcss/vite";
2
+ import { defineConfig } from "vite";
3
+
4
+ export default defineConfig({
5
+ plugins: [tailwindcss()],
6
+ });
package/package.json ADDED
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "@mariozechner/pi-web-ui",
3
+ "version": "0.5.44",
4
+ "description": "Reusable web UI components for AI chat interfaces powered by @mariozechner/pi-ai",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "exports": {
9
+ ".": "./dist/index.js",
10
+ "./app.css": "./dist/app.css"
11
+ },
12
+ "scripts": {
13
+ "clean": "rm -rf dist",
14
+ "build": "tsc -p tsconfig.build.json && tailwindcss -i ./src/app.css -o ./dist/app.css --minify",
15
+ "dev": "concurrently --names \"build,example\" --prefix-colors \"cyan,green\" \"tsc -p tsconfig.build.json --watch\" \"tailwindcss -i ./src/app.css -o ./dist/app.css --watch\" \"npm run dev --prefix example\"",
16
+ "typecheck": "tsc --noEmit",
17
+ "check": "npm run typecheck"
18
+ },
19
+ "dependencies": {
20
+ "@mariozechner/mini-lit": "^0.1.8",
21
+ "@mariozechner/pi-ai": "^0.5.43",
22
+ "docx-preview": "^0.3.7",
23
+ "jszip": "^3.10.1",
24
+ "lit": "^3.3.1",
25
+ "lucide": "^0.544.0",
26
+ "pdfjs-dist": "^5.4.149",
27
+ "xlsx": "^0.18.5"
28
+ },
29
+ "devDependencies": {
30
+ "@tailwindcss/cli": "^4.0.0-beta.14",
31
+ "concurrently": "^9.2.1",
32
+ "typescript": "^5.7.3"
33
+ },
34
+ "keywords": [
35
+ "ai",
36
+ "chat",
37
+ "ui",
38
+ "components",
39
+ "llm",
40
+ "web-components",
41
+ "mini-lit"
42
+ ],
43
+ "author": "Mario Zechner",
44
+ "license": "MIT"
45
+ }
@@ -0,0 +1,214 @@
1
+ import { Badge, html } from "@mariozechner/mini-lit";
2
+ import { type AgentTool, getModel } from "@mariozechner/pi-ai";
3
+ import { LitElement } from "lit";
4
+ import { customElement, property, state } from "lit/decorators.js";
5
+ import "./components/AgentInterface.js";
6
+ import { AgentSession, type AgentSessionState, type ThinkingLevel } from "./state/agent-session.js";
7
+ import { ArtifactsPanel } from "./tools/artifacts/index.js";
8
+ import { createJavaScriptReplTool } from "./tools/javascript-repl.js";
9
+ import { registerToolRenderer } from "./tools/renderer-registry.js";
10
+ import { getAuthToken } from "./utils/auth-token.js";
11
+ import { i18n } from "./utils/i18n.js";
12
+
13
+ const BREAKPOINT = 800; // px - switch between overlay and side-by-side
14
+
15
+ @customElement("pi-chat-panel")
16
+ export class ChatPanel extends LitElement {
17
+ @state() private session!: AgentSession;
18
+ @state() private artifactsPanel!: ArtifactsPanel;
19
+ @state() private hasArtifacts = false;
20
+ @state() private artifactCount = 0;
21
+ @state() private showArtifactsPanel = false;
22
+ @state() private windowWidth = window.innerWidth;
23
+ @property({ type: String }) systemPrompt = "You are a helpful AI assistant.";
24
+ @property({ type: Array }) additionalTools: AgentTool<any, any>[] = [];
25
+ @property({ attribute: false }) sandboxUrlProvider?: () => string;
26
+ @property({ attribute: false }) onApiKeyRequired?: (provider: string) => Promise<boolean>;
27
+
28
+ private resizeHandler = () => {
29
+ this.windowWidth = window.innerWidth;
30
+ this.requestUpdate();
31
+ };
32
+
33
+ createRenderRoot() {
34
+ return this;
35
+ }
36
+
37
+ override async connectedCallback() {
38
+ super.connectedCallback();
39
+
40
+ // Listen to window resize
41
+ window.addEventListener("resize", this.resizeHandler);
42
+
43
+ // Ensure panel fills height and allows flex layout
44
+ this.style.display = "flex";
45
+ this.style.flexDirection = "column";
46
+ this.style.height = "100%";
47
+ this.style.minHeight = "0";
48
+
49
+ // Create JavaScript REPL tool with attachments provider
50
+ const javascriptReplTool = createJavaScriptReplTool();
51
+ if (this.sandboxUrlProvider) {
52
+ javascriptReplTool.sandboxUrlProvider = this.sandboxUrlProvider;
53
+ }
54
+
55
+ // Set up artifacts panel
56
+ this.artifactsPanel = new ArtifactsPanel();
57
+ if (this.sandboxUrlProvider) {
58
+ this.artifactsPanel.sandboxUrlProvider = this.sandboxUrlProvider;
59
+ }
60
+ registerToolRenderer("artifacts", this.artifactsPanel);
61
+
62
+ // Attachments provider for both REPL and artifacts
63
+ const getAttachments = () => {
64
+ // Get all attachments from conversation messages
65
+ const attachments: any[] = [];
66
+ for (const message of this.session.state.messages) {
67
+ if (message.role === "user") {
68
+ const content = Array.isArray(message.content) ? message.content : [message.content];
69
+ for (const block of content) {
70
+ if (typeof block !== "string" && block.type === "image") {
71
+ attachments.push({
72
+ id: `image-${attachments.length}`,
73
+ fileName: "image.png",
74
+ mimeType: block.mimeType || "image/png",
75
+ size: 0,
76
+ content: block.data,
77
+ });
78
+ }
79
+ }
80
+ }
81
+ }
82
+ return attachments;
83
+ };
84
+
85
+ javascriptReplTool.attachmentsProvider = getAttachments;
86
+ this.artifactsPanel.attachmentsProvider = getAttachments;
87
+
88
+ this.artifactsPanel.onArtifactsChange = () => {
89
+ const count = this.artifactsPanel.artifacts?.size ?? 0;
90
+ const created = count > this.artifactCount;
91
+ this.hasArtifacts = count > 0;
92
+ this.artifactCount = count;
93
+
94
+ // Auto-open when new artifacts are created
95
+ if (this.hasArtifacts && created) {
96
+ this.showArtifactsPanel = true;
97
+ }
98
+ this.requestUpdate();
99
+ };
100
+
101
+ this.artifactsPanel.onClose = () => {
102
+ this.showArtifactsPanel = false;
103
+ this.requestUpdate();
104
+ };
105
+
106
+ this.artifactsPanel.onOpen = () => {
107
+ this.showArtifactsPanel = true;
108
+ this.requestUpdate();
109
+ };
110
+
111
+ const initialState = {
112
+ systemPrompt: this.systemPrompt,
113
+ model: getModel("anthropic", "claude-sonnet-4-5-20250929"),
114
+ tools: [...this.additionalTools, javascriptReplTool, this.artifactsPanel.tool],
115
+ thinkingLevel: "off" as ThinkingLevel,
116
+ messages: [],
117
+ } satisfies Partial<AgentSessionState>;
118
+ // initialState = { ...initialState, ...(simpleHtml as any) };
119
+ // initialState = { ...initialState, ...(longSession as any) };
120
+
121
+ // Create agent session first so attachments provider works
122
+ this.session = new AgentSession({
123
+ initialState,
124
+ authTokenProvider: async () => getAuthToken(),
125
+ transportMode: "provider", // Use provider mode by default (API keys from storage, optional CORS proxy)
126
+ });
127
+
128
+ // Reconstruct artifacts panel from initial messages (session must exist first)
129
+ await this.artifactsPanel.reconstructFromMessages(initialState.messages);
130
+ this.hasArtifacts = this.artifactsPanel.artifacts.size > 0;
131
+ }
132
+
133
+ override disconnectedCallback() {
134
+ super.disconnectedCallback();
135
+ window.removeEventListener("resize", this.resizeHandler);
136
+ }
137
+
138
+ // Expose method to toggle artifacts panel
139
+ public toggleArtifactsPanel() {
140
+ this.showArtifactsPanel = !this.showArtifactsPanel;
141
+ this.requestUpdate();
142
+ }
143
+
144
+ // Check if artifacts panel is currently visible
145
+ public get artifactsPanelVisible(): boolean {
146
+ return this.showArtifactsPanel;
147
+ }
148
+
149
+ render() {
150
+ if (!this.session) {
151
+ return html`<div class="flex items-center justify-center h-full">
152
+ <div class="text-muted-foreground">Loading...</div>
153
+ </div>`;
154
+ }
155
+
156
+ const isMobile = this.windowWidth < BREAKPOINT;
157
+
158
+ // Set panel props
159
+ if (this.artifactsPanel) {
160
+ this.artifactsPanel.collapsed = !this.showArtifactsPanel;
161
+ this.artifactsPanel.overlay = isMobile;
162
+ }
163
+
164
+ return html`
165
+ <div class="relative w-full h-full overflow-hidden flex">
166
+ <div class="h-full" style="${!isMobile && this.showArtifactsPanel && this.hasArtifacts ? "width: 50%;" : "width: 100%;"}">
167
+ <agent-interface
168
+ .session=${this.session}
169
+ .enableAttachments=${true}
170
+ .enableModelSelector=${true}
171
+ .enableThinking=${true}
172
+ .showThemeToggle=${false}
173
+ .showDebugToggle=${false}
174
+ .onApiKeyRequired=${this.onApiKeyRequired}
175
+ ></agent-interface>
176
+ </div>
177
+
178
+ <!-- Floating pill when artifacts exist and panel is collapsed -->
179
+ ${
180
+ this.hasArtifacts && !this.showArtifactsPanel
181
+ ? html`
182
+ <button
183
+ class="absolute z-30 top-4 left-1/2 -translate-x-1/2 pointer-events-auto"
184
+ @click=${() => {
185
+ this.showArtifactsPanel = true;
186
+ this.requestUpdate();
187
+ }}
188
+ title=${i18n("Show artifacts")}
189
+ >
190
+ ${Badge(html`
191
+ <span class="inline-flex items-center gap-1">
192
+ <span>${i18n("Artifacts")}</span>
193
+ ${
194
+ this.artifactCount > 1
195
+ ? html`<span
196
+ class="text-[10px] leading-none bg-primary-foreground/20 text-primary-foreground rounded px-1 font-mono tabular-nums"
197
+ >${this.artifactCount}</span
198
+ >`
199
+ : ""
200
+ }
201
+ </span>
202
+ `)}
203
+ </button>
204
+ `
205
+ : ""
206
+ }
207
+
208
+ <div class="h-full ${isMobile ? "absolute inset-0 pointer-events-none" : ""}" style="${!isMobile ? (!this.hasArtifacts || !this.showArtifactsPanel ? "display: none;" : "width: 50%;") : ""}">
209
+ ${this.artifactsPanel}
210
+ </div>
211
+ </div>
212
+ `;
213
+ }
214
+ }
package/src/app.css ADDED
@@ -0,0 +1,44 @@
1
+ /* Import Claude theme from mini-lit */
2
+ @import "@mariozechner/mini-lit/styles/themes/default.css";
3
+
4
+ /* Tell Tailwind to scan mini-lit components */
5
+ /* biome-ignore lint/suspicious/noUnknownAtRules: Tailwind 4 source directive */
6
+ @source "../../../node_modules/@mariozechner/mini-lit/dist";
7
+
8
+ /* Import Tailwind */
9
+ /* biome-ignore lint/correctness/noInvalidPositionAtImportRule: fuck you */
10
+ @import "tailwindcss";
11
+
12
+ body {
13
+ font-size: 16px;
14
+ -webkit-font-smoothing: antialiased;
15
+ }
16
+
17
+ * {
18
+ scrollbar-width: thin;
19
+ scrollbar-color: var(--color-border) rgba(0, 0, 0, 0);
20
+ }
21
+
22
+ *::-webkit-scrollbar {
23
+ width: 8px;
24
+ height: 8px;
25
+ }
26
+
27
+ *::-webkit-scrollbar-track {
28
+ background: transparent;
29
+ }
30
+
31
+ *::-webkit-scrollbar-thumb {
32
+ background-color: var(--color-border);
33
+ border-radius: 4px;
34
+ }
35
+
36
+ *::-webkit-scrollbar-thumb:hover {
37
+ background-color: rgba(0, 0, 0, 0);
38
+ }
39
+
40
+ /* Fix cursor for dialog close buttons */
41
+ .fixed.inset-0 button[aria-label*="Close"],
42
+ .fixed.inset-0 button[type="button"] {
43
+ cursor: pointer;
44
+ }