@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.
- package/README.md +252 -0
- package/dist/ChatPanel.d.ts +23 -0
- package/dist/ChatPanel.d.ts.map +1 -0
- package/dist/ChatPanel.js +224 -0
- package/dist/ChatPanel.js.map +1 -0
- package/dist/app.css +2 -0
- package/dist/components/AgentInterface.d.ts +35 -0
- package/dist/components/AgentInterface.d.ts.map +1 -0
- package/dist/components/AgentInterface.js +308 -0
- package/dist/components/AgentInterface.js.map +1 -0
- package/dist/components/AttachmentTile.d.ts +12 -0
- package/dist/components/AttachmentTile.d.ts.map +1 -0
- package/dist/components/AttachmentTile.js +114 -0
- package/dist/components/AttachmentTile.js.map +1 -0
- package/dist/components/ConsoleBlock.d.ts +11 -0
- package/dist/components/ConsoleBlock.d.ts.map +1 -0
- package/dist/components/ConsoleBlock.js +77 -0
- package/dist/components/ConsoleBlock.js.map +1 -0
- package/dist/components/Input.d.ts +26 -0
- package/dist/components/Input.d.ts.map +1 -0
- package/dist/components/Input.js +56 -0
- package/dist/components/Input.js.map +1 -0
- package/dist/components/MessageEditor.d.ts +38 -0
- package/dist/components/MessageEditor.d.ts.map +1 -0
- package/dist/components/MessageEditor.js +296 -0
- package/dist/components/MessageEditor.js.map +1 -0
- package/dist/components/MessageList.d.ts +13 -0
- package/dist/components/MessageList.d.ts.map +1 -0
- package/dist/components/MessageList.js +88 -0
- package/dist/components/MessageList.js.map +1 -0
- package/dist/components/Messages.d.ts +53 -0
- package/dist/components/Messages.d.ts.map +1 -0
- package/dist/components/Messages.js +323 -0
- package/dist/components/Messages.js.map +1 -0
- package/dist/components/ProviderKeyInput.d.ts +16 -0
- package/dist/components/ProviderKeyInput.d.ts.map +1 -0
- package/dist/components/ProviderKeyInput.js +183 -0
- package/dist/components/ProviderKeyInput.js.map +1 -0
- package/dist/components/SandboxedIframe.d.ts +63 -0
- package/dist/components/SandboxedIframe.d.ts.map +1 -0
- package/dist/components/SandboxedIframe.js +435 -0
- package/dist/components/SandboxedIframe.js.map +1 -0
- package/dist/components/StreamingMessageContainer.d.ts +17 -0
- package/dist/components/StreamingMessageContainer.d.ts.map +1 -0
- package/dist/components/StreamingMessageContainer.js +114 -0
- package/dist/components/StreamingMessageContainer.js.map +1 -0
- package/dist/dialogs/ApiKeyPromptDialog.d.ts +15 -0
- package/dist/dialogs/ApiKeyPromptDialog.d.ts.map +1 -0
- package/dist/dialogs/ApiKeyPromptDialog.js +80 -0
- package/dist/dialogs/ApiKeyPromptDialog.js.map +1 -0
- package/dist/dialogs/AttachmentOverlay.d.ts +32 -0
- package/dist/dialogs/AttachmentOverlay.d.ts.map +1 -0
- package/dist/dialogs/AttachmentOverlay.js +575 -0
- package/dist/dialogs/AttachmentOverlay.js.map +1 -0
- package/dist/dialogs/ModelSelector.d.ts +27 -0
- package/dist/dialogs/ModelSelector.d.ts.map +1 -0
- package/dist/dialogs/ModelSelector.js +334 -0
- package/dist/dialogs/ModelSelector.js.map +1 -0
- package/dist/dialogs/SettingsDialog.d.ts +31 -0
- package/dist/dialogs/SettingsDialog.d.ts.map +1 -0
- package/dist/dialogs/SettingsDialog.js +228 -0
- package/dist/dialogs/SettingsDialog.js.map +1 -0
- package/dist/index.d.ts +46 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +51 -0
- package/dist/index.js.map +1 -0
- package/dist/state/agent-session.d.ts +58 -0
- package/dist/state/agent-session.d.ts.map +1 -0
- package/dist/state/agent-session.js +252 -0
- package/dist/state/agent-session.js.map +1 -0
- package/dist/state/transports/AppTransport.d.ts +13 -0
- package/dist/state/transports/AppTransport.d.ts.map +1 -0
- package/dist/state/transports/AppTransport.js +316 -0
- package/dist/state/transports/AppTransport.js.map +1 -0
- package/dist/state/transports/ProviderTransport.d.ts +12 -0
- package/dist/state/transports/ProviderTransport.d.ts.map +1 -0
- package/dist/state/transports/ProviderTransport.js +44 -0
- package/dist/state/transports/ProviderTransport.js.map +1 -0
- package/dist/state/transports/index.d.ts +4 -0
- package/dist/state/transports/index.d.ts.map +1 -0
- package/dist/state/transports/index.js +4 -0
- package/dist/state/transports/index.js.map +1 -0
- package/dist/state/transports/proxy-types.d.ts +48 -0
- package/dist/state/transports/proxy-types.d.ts.map +1 -0
- package/dist/state/transports/proxy-types.js +2 -0
- package/dist/state/transports/proxy-types.js.map +1 -0
- package/dist/state/transports/types.d.ts +11 -0
- package/dist/state/transports/types.d.ts.map +1 -0
- package/dist/state/transports/types.js +2 -0
- package/dist/state/transports/types.js.map +1 -0
- package/dist/state/types.d.ts +15 -0
- package/dist/state/types.d.ts.map +1 -0
- package/dist/state/types.js +2 -0
- package/dist/state/types.js.map +1 -0
- package/dist/storage/app-storage.d.ts +26 -0
- package/dist/storage/app-storage.d.ts.map +1 -0
- package/dist/storage/app-storage.js +44 -0
- package/dist/storage/app-storage.js.map +1 -0
- package/dist/storage/backends/chrome-storage-backend.d.ts +18 -0
- package/dist/storage/backends/chrome-storage-backend.d.ts.map +1 -0
- package/dist/storage/backends/chrome-storage-backend.js +67 -0
- package/dist/storage/backends/chrome-storage-backend.js.map +1 -0
- package/dist/storage/backends/indexeddb-backend.d.ts +20 -0
- package/dist/storage/backends/indexeddb-backend.d.ts.map +1 -0
- package/dist/storage/backends/indexeddb-backend.js +89 -0
- package/dist/storage/backends/indexeddb-backend.js.map +1 -0
- package/dist/storage/backends/local-storage-backend.d.ts +18 -0
- package/dist/storage/backends/local-storage-backend.d.ts.map +1 -0
- package/dist/storage/backends/local-storage-backend.js +69 -0
- package/dist/storage/backends/local-storage-backend.js.map +1 -0
- package/dist/storage/repositories/provider-keys-repository.d.ts +34 -0
- package/dist/storage/repositories/provider-keys-repository.d.ts.map +1 -0
- package/dist/storage/repositories/provider-keys-repository.js +50 -0
- package/dist/storage/repositories/provider-keys-repository.js.map +1 -0
- package/dist/storage/repositories/settings-repository.d.ts +34 -0
- package/dist/storage/repositories/settings-repository.d.ts.map +1 -0
- package/dist/storage/repositories/settings-repository.js +46 -0
- package/dist/storage/repositories/settings-repository.js.map +1 -0
- package/dist/storage/types.d.ts +43 -0
- package/dist/storage/types.d.ts.map +1 -0
- package/dist/storage/types.js +2 -0
- package/dist/storage/types.js.map +1 -0
- package/dist/tools/artifacts/ArtifactElement.d.ts +10 -0
- package/dist/tools/artifacts/ArtifactElement.d.ts.map +1 -0
- package/dist/tools/artifacts/ArtifactElement.js +12 -0
- package/dist/tools/artifacts/ArtifactElement.js.map +1 -0
- package/dist/tools/artifacts/HtmlArtifact.d.ts +30 -0
- package/dist/tools/artifacts/HtmlArtifact.d.ts.map +1 -0
- package/dist/tools/artifacts/HtmlArtifact.js +217 -0
- package/dist/tools/artifacts/HtmlArtifact.js.map +1 -0
- package/dist/tools/artifacts/MarkdownArtifact.d.ts +20 -0
- package/dist/tools/artifacts/MarkdownArtifact.d.ts.map +1 -0
- package/dist/tools/artifacts/MarkdownArtifact.js +84 -0
- package/dist/tools/artifacts/MarkdownArtifact.js.map +1 -0
- package/dist/tools/artifacts/SvgArtifact.d.ts +19 -0
- package/dist/tools/artifacts/SvgArtifact.d.ts.map +1 -0
- package/dist/tools/artifacts/SvgArtifact.js +80 -0
- package/dist/tools/artifacts/SvgArtifact.js.map +1 -0
- package/dist/tools/artifacts/TextArtifact.d.ts +20 -0
- package/dist/tools/artifacts/TextArtifact.d.ts.map +1 -0
- package/dist/tools/artifacts/TextArtifact.js +147 -0
- package/dist/tools/artifacts/TextArtifact.js.map +1 -0
- package/dist/tools/artifacts/artifacts.d.ts +67 -0
- package/dist/tools/artifacts/artifacts.d.ts.map +1 -0
- package/dist/tools/artifacts/artifacts.js +836 -0
- package/dist/tools/artifacts/artifacts.js.map +1 -0
- package/dist/tools/artifacts/index.d.ts +7 -0
- package/dist/tools/artifacts/index.d.ts.map +1 -0
- package/dist/tools/artifacts/index.js +7 -0
- package/dist/tools/artifacts/index.js.map +1 -0
- package/dist/tools/index.d.ts +14 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +29 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/javascript-repl.d.ts +43 -0
- package/dist/tools/javascript-repl.d.ts.map +1 -0
- package/dist/tools/javascript-repl.js +252 -0
- package/dist/tools/javascript-repl.js.map +1 -0
- package/dist/tools/renderer-registry.d.ts +11 -0
- package/dist/tools/renderer-registry.d.ts.map +1 -0
- package/dist/tools/renderer-registry.js +15 -0
- package/dist/tools/renderer-registry.js.map +1 -0
- package/dist/tools/renderers/BashRenderer.d.ts +12 -0
- package/dist/tools/renderers/BashRenderer.d.ts.map +1 -0
- package/dist/tools/renderers/BashRenderer.js +35 -0
- package/dist/tools/renderers/BashRenderer.js.map +1 -0
- package/dist/tools/renderers/CalculateRenderer.d.ts +12 -0
- package/dist/tools/renderers/CalculateRenderer.d.ts.map +1 -0
- package/dist/tools/renderers/CalculateRenderer.js +38 -0
- package/dist/tools/renderers/CalculateRenderer.js.map +1 -0
- package/dist/tools/renderers/DefaultRenderer.d.ts +8 -0
- package/dist/tools/renderers/DefaultRenderer.d.ts.map +1 -0
- package/dist/tools/renderers/DefaultRenderer.js +31 -0
- package/dist/tools/renderers/DefaultRenderer.js.map +1 -0
- package/dist/tools/renderers/GetCurrentTimeRenderer.d.ts +12 -0
- package/dist/tools/renderers/GetCurrentTimeRenderer.d.ts.map +1 -0
- package/dist/tools/renderers/GetCurrentTimeRenderer.js +30 -0
- package/dist/tools/renderers/GetCurrentTimeRenderer.js.map +1 -0
- package/dist/tools/types.d.ts +7 -0
- package/dist/tools/types.d.ts.map +1 -0
- package/dist/tools/types.js +2 -0
- package/dist/tools/types.js.map +1 -0
- package/dist/utils/attachment-utils.d.ts +19 -0
- package/dist/utils/attachment-utils.d.ts.map +1 -0
- package/dist/utils/attachment-utils.js +415 -0
- package/dist/utils/attachment-utils.js.map +1 -0
- package/dist/utils/auth-token.d.ts +3 -0
- package/dist/utils/auth-token.d.ts.map +1 -0
- package/dist/utils/auth-token.js +19 -0
- package/dist/utils/auth-token.js.map +1 -0
- package/dist/utils/format.d.ts +6 -0
- package/dist/utils/format.d.ts.map +1 -0
- package/dist/utils/format.js +47 -0
- package/dist/utils/format.js.map +1 -0
- package/dist/utils/i18n.d.ts +111 -0
- package/dist/utils/i18n.d.ts.map +1 -0
- package/dist/utils/i18n.js +224 -0
- package/dist/utils/i18n.js.map +1 -0
- package/dist/utils/test-sessions.d.ts +347 -0
- package/dist/utils/test-sessions.d.ts.map +1 -0
- package/dist/utils/test-sessions.js +2215 -0
- package/dist/utils/test-sessions.js.map +1 -0
- package/example/README.md +61 -0
- package/example/index.html +13 -0
- package/example/package-lock.json +1965 -0
- package/example/package.json +22 -0
- package/example/src/app.css +1 -0
- package/example/src/main.ts +57 -0
- package/example/src/test-sessions.ts +104 -0
- package/example/tsconfig.json +15 -0
- package/example/vite.config.ts +6 -0
- package/package.json +45 -0
- package/src/ChatPanel.ts +214 -0
- package/src/app.css +44 -0
- package/src/components/AgentInterface.ts +316 -0
- package/src/components/AttachmentTile.ts +112 -0
- package/src/components/ConsoleBlock.ts +67 -0
- package/src/components/Input.ts +112 -0
- package/src/components/MessageEditor.ts +272 -0
- package/src/components/MessageList.ts +82 -0
- package/src/components/Messages.ts +310 -0
- package/src/components/ProviderKeyInput.ts +170 -0
- package/src/components/SandboxedIframe.ts +525 -0
- package/src/components/StreamingMessageContainer.ts +101 -0
- package/src/dialogs/ApiKeyPromptDialog.ts +76 -0
- package/src/dialogs/AttachmentOverlay.ts +635 -0
- package/src/dialogs/ModelSelector.ts +324 -0
- package/src/dialogs/SettingsDialog.ts +223 -0
- package/src/index.ts +63 -0
- package/src/state/agent-session.ts +311 -0
- package/src/state/transports/AppTransport.ts +363 -0
- package/src/state/transports/ProviderTransport.ts +49 -0
- package/src/state/transports/index.ts +3 -0
- package/src/state/transports/proxy-types.ts +15 -0
- package/src/state/transports/types.ts +16 -0
- package/src/state/types.ts +11 -0
- package/src/storage/app-storage.ts +53 -0
- package/src/storage/backends/chrome-storage-backend.ts +82 -0
- package/src/storage/backends/indexeddb-backend.ts +107 -0
- package/src/storage/backends/local-storage-backend.ts +74 -0
- package/src/storage/repositories/provider-keys-repository.ts +55 -0
- package/src/storage/repositories/settings-repository.ts +51 -0
- package/src/storage/types.ts +48 -0
- package/src/tools/artifacts/ArtifactElement.ts +15 -0
- package/src/tools/artifacts/HtmlArtifact.ts +221 -0
- package/src/tools/artifacts/MarkdownArtifact.ts +81 -0
- package/src/tools/artifacts/SvgArtifact.ts +77 -0
- package/src/tools/artifacts/TextArtifact.ts +148 -0
- package/src/tools/artifacts/artifacts.ts +888 -0
- package/src/tools/artifacts/index.ts +6 -0
- package/src/tools/index.ts +35 -0
- package/src/tools/javascript-repl.ts +309 -0
- package/src/tools/renderer-registry.ts +18 -0
- package/src/tools/renderers/BashRenderer.ts +45 -0
- package/src/tools/renderers/CalculateRenderer.ts +49 -0
- package/src/tools/renderers/DefaultRenderer.ts +36 -0
- package/src/tools/renderers/GetCurrentTimeRenderer.ts +39 -0
- package/src/tools/types.ts +7 -0
- package/src/utils/attachment-utils.ts +472 -0
- package/src/utils/auth-token.ts +22 -0
- package/src/utils/format.ts +42 -0
- package/src/utils/i18n.ts +343 -0
- package/src/utils/test-sessions.ts +2247 -0
- package/tsconfig.build.json +20 -0
- 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
|
+
}
|
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
|
+
}
|
package/src/ChatPanel.ts
ADDED
|
@@ -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
|
+
}
|