@mariozechner/pi-web-ui 0.30.2 → 0.31.1
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/CHANGELOG.md +90 -0
- package/README.md +420 -150
- package/dist/ChatPanel.d.ts +1 -2
- package/dist/ChatPanel.d.ts.map +1 -1
- package/dist/ChatPanel.js +22 -45
- package/dist/ChatPanel.js.map +1 -1
- package/dist/components/AgentInterface.d.ts +1 -1
- package/dist/components/AgentInterface.d.ts.map +1 -1
- package/dist/components/AgentInterface.js +113 -91
- package/dist/components/AgentInterface.js.map +1 -1
- package/dist/components/AttachmentTile.d.ts.map +1 -1
- package/dist/components/AttachmentTile.js +12 -28
- package/dist/components/AttachmentTile.js.map +1 -1
- package/dist/components/ConsoleBlock.d.ts.map +1 -1
- package/dist/components/ConsoleBlock.js +6 -21
- package/dist/components/ConsoleBlock.js.map +1 -1
- package/dist/components/CustomProviderCard.d.ts.map +1 -1
- package/dist/components/CustomProviderCard.js +15 -34
- package/dist/components/CustomProviderCard.js.map +1 -1
- package/dist/components/ExpandableSection.d.ts.map +1 -1
- package/dist/components/ExpandableSection.js +10 -27
- package/dist/components/ExpandableSection.js.map +1 -1
- package/dist/components/Input.js.map +1 -1
- package/dist/components/MessageEditor.d.ts +2 -1
- package/dist/components/MessageEditor.d.ts.map +1 -1
- package/dist/components/MessageEditor.js +147 -190
- package/dist/components/MessageEditor.js.map +1 -1
- package/dist/components/MessageList.d.ts +2 -3
- package/dist/components/MessageList.d.ts.map +1 -1
- package/dist/components/MessageList.js +11 -28
- package/dist/components/MessageList.js.map +1 -1
- package/dist/components/Messages.d.ts +37 -7
- package/dist/components/Messages.d.ts.map +1 -1
- package/dist/components/Messages.js +127 -103
- package/dist/components/Messages.js.map +1 -1
- package/dist/components/ProviderKeyInput.d.ts.map +1 -1
- package/dist/components/ProviderKeyInput.js +15 -39
- package/dist/components/ProviderKeyInput.js.map +1 -1
- package/dist/components/SandboxedIframe.d.ts.map +1 -1
- package/dist/components/SandboxedIframe.js +11 -15
- package/dist/components/SandboxedIframe.js.map +1 -1
- package/dist/components/StreamingMessageContainer.d.ts +3 -2
- package/dist/components/StreamingMessageContainer.d.ts.map +1 -1
- package/dist/components/StreamingMessageContainer.js +16 -34
- package/dist/components/StreamingMessageContainer.js.map +1 -1
- package/dist/components/ThinkingBlock.d.ts.map +1 -1
- package/dist/components/ThinkingBlock.js +9 -26
- package/dist/components/ThinkingBlock.js.map +1 -1
- package/dist/components/message-renderer-registry.d.ts +5 -5
- package/dist/components/message-renderer-registry.d.ts.map +1 -1
- package/dist/components/message-renderer-registry.js.map +1 -1
- package/dist/components/sandbox/ArtifactsRuntimeProvider.d.ts.map +1 -1
- package/dist/components/sandbox/ArtifactsRuntimeProvider.js +3 -0
- package/dist/components/sandbox/ArtifactsRuntimeProvider.js.map +1 -1
- package/dist/components/sandbox/AttachmentsRuntimeProvider.d.ts.map +1 -1
- package/dist/components/sandbox/AttachmentsRuntimeProvider.js +1 -0
- package/dist/components/sandbox/AttachmentsRuntimeProvider.js.map +1 -1
- package/dist/components/sandbox/ConsoleRuntimeProvider.d.ts.map +1 -1
- package/dist/components/sandbox/ConsoleRuntimeProvider.js +3 -5
- package/dist/components/sandbox/ConsoleRuntimeProvider.js.map +1 -1
- package/dist/components/sandbox/FileDownloadRuntimeProvider.d.ts.map +1 -1
- package/dist/components/sandbox/FileDownloadRuntimeProvider.js +1 -3
- package/dist/components/sandbox/FileDownloadRuntimeProvider.js.map +1 -1
- package/dist/components/sandbox/RuntimeMessageBridge.d.ts.map +1 -1
- package/dist/components/sandbox/RuntimeMessageBridge.js.map +1 -1
- package/dist/components/sandbox/RuntimeMessageRouter.d.ts.map +1 -1
- package/dist/components/sandbox/RuntimeMessageRouter.js +3 -5
- package/dist/components/sandbox/RuntimeMessageRouter.js.map +1 -1
- package/dist/dialogs/ApiKeyPromptDialog.d.ts.map +1 -1
- package/dist/dialogs/ApiKeyPromptDialog.js +10 -23
- package/dist/dialogs/ApiKeyPromptDialog.js.map +1 -1
- package/dist/dialogs/AttachmentOverlay.d.ts.map +1 -1
- package/dist/dialogs/AttachmentOverlay.js +34 -46
- package/dist/dialogs/AttachmentOverlay.js.map +1 -1
- package/dist/dialogs/CustomProviderDialog.d.ts.map +1 -1
- package/dist/dialogs/CustomProviderDialog.js +19 -39
- package/dist/dialogs/CustomProviderDialog.js.map +1 -1
- package/dist/dialogs/ModelSelector.d.ts.map +1 -1
- package/dist/dialogs/ModelSelector.js +25 -53
- package/dist/dialogs/ModelSelector.js.map +1 -1
- package/dist/dialogs/PersistentStorageDialog.d.ts.map +1 -1
- package/dist/dialogs/PersistentStorageDialog.js +9 -23
- package/dist/dialogs/PersistentStorageDialog.js.map +1 -1
- package/dist/dialogs/ProvidersModelsTab.d.ts.map +1 -1
- package/dist/dialogs/ProvidersModelsTab.js +7 -23
- package/dist/dialogs/ProvidersModelsTab.js.map +1 -1
- package/dist/dialogs/SessionListDialog.d.ts.map +1 -1
- package/dist/dialogs/SessionListDialog.js +14 -29
- package/dist/dialogs/SessionListDialog.js.map +1 -1
- package/dist/dialogs/SettingsDialog.d.ts.map +1 -1
- package/dist/dialogs/SettingsDialog.js +20 -52
- package/dist/dialogs/SettingsDialog.js.map +1 -1
- package/dist/index.d.ts +5 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -6
- package/dist/index.js.map +1 -1
- package/dist/prompts/prompts.d.ts.map +1 -1
- package/dist/storage/app-storage.d.ts.map +1 -1
- package/dist/storage/app-storage.js +5 -0
- package/dist/storage/app-storage.js.map +1 -1
- package/dist/storage/backends/indexeddb-storage-backend.d.ts.map +1 -1
- package/dist/storage/backends/indexeddb-storage-backend.js +2 -1
- package/dist/storage/backends/indexeddb-storage-backend.js.map +1 -1
- package/dist/storage/store.d.ts.map +1 -1
- package/dist/storage/store.js +1 -3
- package/dist/storage/store.js.map +1 -1
- package/dist/storage/stores/custom-providers-store.d.ts.map +1 -1
- package/dist/storage/stores/custom-providers-store.js.map +1 -1
- package/dist/storage/stores/provider-keys-store.d.ts.map +1 -1
- package/dist/storage/stores/provider-keys-store.js.map +1 -1
- package/dist/storage/stores/sessions-store.d.ts +1 -1
- package/dist/storage/stores/sessions-store.d.ts.map +1 -1
- package/dist/storage/stores/sessions-store.js.map +1 -1
- package/dist/storage/stores/settings-store.d.ts.map +1 -1
- package/dist/storage/stores/settings-store.js.map +1 -1
- package/dist/storage/types.d.ts +2 -3
- package/dist/storage/types.d.ts.map +1 -1
- package/dist/tools/artifacts/ArtifactElement.d.ts.map +1 -1
- package/dist/tools/artifacts/ArtifactElement.js +1 -4
- package/dist/tools/artifacts/ArtifactElement.js.map +1 -1
- package/dist/tools/artifacts/ArtifactPill.js.map +1 -1
- package/dist/tools/artifacts/Console.d.ts.map +1 -1
- package/dist/tools/artifacts/Console.js +10 -28
- package/dist/tools/artifacts/Console.js.map +1 -1
- package/dist/tools/artifacts/DocxArtifact.d.ts.map +1 -1
- package/dist/tools/artifacts/DocxArtifact.js +7 -23
- package/dist/tools/artifacts/DocxArtifact.js.map +1 -1
- package/dist/tools/artifacts/ExcelArtifact.d.ts.map +1 -1
- package/dist/tools/artifacts/ExcelArtifact.js +7 -23
- package/dist/tools/artifacts/ExcelArtifact.js.map +1 -1
- package/dist/tools/artifacts/GenericArtifact.d.ts.map +1 -1
- package/dist/tools/artifacts/GenericArtifact.js +5 -19
- package/dist/tools/artifacts/GenericArtifact.js.map +1 -1
- package/dist/tools/artifacts/HtmlArtifact.d.ts.map +1 -1
- package/dist/tools/artifacts/HtmlArtifact.js +16 -35
- package/dist/tools/artifacts/HtmlArtifact.js.map +1 -1
- package/dist/tools/artifacts/ImageArtifact.d.ts.map +1 -1
- package/dist/tools/artifacts/ImageArtifact.js +5 -19
- package/dist/tools/artifacts/ImageArtifact.js.map +1 -1
- package/dist/tools/artifacts/MarkdownArtifact.d.ts.map +1 -1
- package/dist/tools/artifacts/MarkdownArtifact.js +8 -24
- package/dist/tools/artifacts/MarkdownArtifact.js.map +1 -1
- package/dist/tools/artifacts/PdfArtifact.d.ts.map +1 -1
- package/dist/tools/artifacts/PdfArtifact.js +8 -24
- package/dist/tools/artifacts/PdfArtifact.js.map +1 -1
- package/dist/tools/artifacts/SvgArtifact.d.ts.map +1 -1
- package/dist/tools/artifacts/SvgArtifact.js +8 -24
- package/dist/tools/artifacts/SvgArtifact.js.map +1 -1
- package/dist/tools/artifacts/TextArtifact.d.ts.map +1 -1
- package/dist/tools/artifacts/TextArtifact.js +6 -20
- package/dist/tools/artifacts/TextArtifact.js.map +1 -1
- package/dist/tools/artifacts/artifacts-tool-renderer.d.ts.map +1 -1
- package/dist/tools/artifacts/artifacts-tool-renderer.js +1 -0
- package/dist/tools/artifacts/artifacts-tool-renderer.js.map +1 -1
- package/dist/tools/artifacts/artifacts.d.ts +2 -3
- package/dist/tools/artifacts/artifacts.d.ts.map +1 -1
- package/dist/tools/artifacts/artifacts.js +30 -52
- package/dist/tools/artifacts/artifacts.js.map +1 -1
- package/dist/tools/extract-document.d.ts +2 -2
- package/dist/tools/extract-document.d.ts.map +1 -1
- package/dist/tools/extract-document.js.map +1 -1
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/javascript-repl.d.ts +3 -3
- package/dist/tools/javascript-repl.d.ts.map +1 -1
- package/dist/tools/javascript-repl.js.map +1 -1
- package/dist/tools/renderer-registry.js.map +1 -1
- package/dist/tools/renderers/BashRenderer.d.ts.map +1 -1
- package/dist/tools/renderers/BashRenderer.js.map +1 -1
- package/dist/tools/renderers/CalculateRenderer.d.ts.map +1 -1
- package/dist/tools/renderers/CalculateRenderer.js.map +1 -1
- package/dist/tools/renderers/DefaultRenderer.d.ts.map +1 -1
- package/dist/tools/renderers/DefaultRenderer.js.map +1 -1
- package/dist/tools/renderers/GetCurrentTimeRenderer.d.ts.map +1 -1
- package/dist/tools/renderers/GetCurrentTimeRenderer.js.map +1 -1
- package/dist/utils/attachment-utils.js.map +1 -1
- package/dist/utils/auth-token.js.map +1 -1
- package/dist/utils/format.js.map +1 -1
- package/dist/utils/i18n.d.ts +14 -14
- package/dist/utils/i18n.d.ts.map +1 -1
- package/dist/utils/i18n.js.map +1 -1
- package/dist/utils/model-discovery.js.map +1 -1
- package/dist/utils/proxy-utils.d.ts +9 -1
- package/dist/utils/proxy-utils.d.ts.map +1 -1
- package/dist/utils/proxy-utils.js +19 -0
- package/dist/utils/proxy-utils.js.map +1 -1
- package/dist/utils/test-sessions.d.ts +47 -47
- package/dist/utils/test-sessions.js.map +1 -1
- package/example/package.json +1 -1
- package/example/src/custom-messages.ts +26 -36
- package/example/src/main.ts +11 -20
- package/example/tsconfig.json +1 -0
- package/package.json +4 -4
- package/src/ChatPanel.ts +2 -3
- package/src/components/AgentInterface.ts +57 -13
- package/src/components/MessageEditor.ts +2 -1
- package/src/components/MessageList.ts +3 -4
- package/src/components/Messages.ts +108 -19
- package/src/components/StreamingMessageContainer.ts +6 -5
- package/src/components/message-renderer-registry.ts +5 -5
- package/src/index.ts +13 -10
- package/src/storage/stores/sessions-store.ts +1 -1
- package/src/storage/types.ts +2 -3
- package/src/tools/artifacts/artifacts.ts +4 -4
- package/src/tools/extract-document.ts +2 -1
- package/src/tools/javascript-repl.ts +2 -1
- package/src/utils/proxy-utils.ts +23 -1
- package/dist/agent/agent.d.ts +0 -62
- package/dist/agent/agent.d.ts.map +0 -1
- package/dist/agent/agent.js +0 -274
- package/dist/agent/agent.js.map +0 -1
- package/dist/agent/transports/AppTransport.d.ts +0 -15
- package/dist/agent/transports/AppTransport.d.ts.map +0 -1
- package/dist/agent/transports/AppTransport.js +0 -327
- package/dist/agent/transports/AppTransport.js.map +0 -1
- package/dist/agent/transports/ProviderTransport.d.ts +0 -14
- package/dist/agent/transports/ProviderTransport.d.ts.map +0 -1
- package/dist/agent/transports/ProviderTransport.js +0 -55
- package/dist/agent/transports/ProviderTransport.js.map +0 -1
- package/dist/agent/transports/index.d.ts +0 -4
- package/dist/agent/transports/index.d.ts.map +0 -1
- package/dist/agent/transports/index.js +0 -4
- package/dist/agent/transports/index.js.map +0 -1
- package/dist/agent/transports/proxy-types.d.ts +0 -48
- package/dist/agent/transports/proxy-types.d.ts.map +0 -1
- package/dist/agent/transports/proxy-types.js +0 -2
- package/dist/agent/transports/proxy-types.js.map +0 -1
- package/dist/agent/transports/types.d.ts +0 -15
- package/dist/agent/transports/types.d.ts.map +0 -1
- package/dist/agent/transports/types.js +0 -2
- package/dist/agent/transports/types.js.map +0 -1
- package/dist/agent/types.d.ts +0 -15
- package/dist/agent/types.d.ts.map +0 -1
- package/dist/agent/types.js +0 -2
- package/dist/agent/types.js.map +0 -1
- package/example/src/test-sessions.ts +0 -104
- package/src/agent/agent.ts +0 -341
- package/src/agent/transports/AppTransport.ts +0 -371
- package/src/agent/transports/ProviderTransport.ts +0 -71
- package/src/agent/transports/index.ts +0 -3
- package/src/agent/transports/proxy-types.ts +0 -15
- package/src/agent/transports/types.ts +0 -26
- package/src/agent/types.ts +0 -11
package/README.md
CHANGED
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
# @mariozechner/pi-web-ui
|
|
2
2
|
|
|
3
|
-
Reusable web UI components for building AI chat interfaces powered by [@mariozechner/pi-ai](../ai).
|
|
3
|
+
Reusable web UI components for building AI chat interfaces powered by [@mariozechner/pi-ai](../ai) and [@mariozechner/pi-agent-core](../agent).
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Built with [mini-lit](https://github.com/badlogic/mini-lit) web components and Tailwind CSS v4.
|
|
6
6
|
|
|
7
7
|
## Features
|
|
8
8
|
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
- Attachments
|
|
12
|
-
- Artifacts
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
-
|
|
9
|
+
- **Chat UI**: Complete interface with message history, streaming, and tool execution
|
|
10
|
+
- **Tools**: JavaScript REPL, document extraction, and artifacts (HTML, SVG, Markdown, etc.)
|
|
11
|
+
- **Attachments**: PDF, DOCX, XLSX, PPTX, images with preview and text extraction
|
|
12
|
+
- **Artifacts**: Interactive HTML, SVG, Markdown with sandboxed execution
|
|
13
|
+
- **Storage**: IndexedDB-backed storage for sessions, API keys, and settings
|
|
14
|
+
- **CORS Proxy**: Automatic proxy handling for browser environments
|
|
15
|
+
- **Custom Providers**: Support for Ollama, LM Studio, vLLM, and OpenAI-compatible APIs
|
|
16
16
|
|
|
17
17
|
## Installation
|
|
18
18
|
|
|
19
19
|
```bash
|
|
20
|
-
npm install @mariozechner/pi-web-ui
|
|
20
|
+
npm install @mariozechner/pi-web-ui @mariozechner/pi-agent-core @mariozechner/pi-ai
|
|
21
21
|
```
|
|
22
22
|
|
|
23
23
|
## Quick Start
|
|
@@ -25,19 +25,43 @@ npm install @mariozechner/pi-web-ui
|
|
|
25
25
|
See the [example](./example) directory for a complete working application.
|
|
26
26
|
|
|
27
27
|
```typescript
|
|
28
|
-
import { Agent
|
|
29
|
-
SessionIndexedDBBackend, setAppStorage } from '@mariozechner/pi-web-ui';
|
|
28
|
+
import { Agent } from '@mariozechner/pi-agent-core';
|
|
30
29
|
import { getModel } from '@mariozechner/pi-ai';
|
|
30
|
+
import {
|
|
31
|
+
ChatPanel,
|
|
32
|
+
AppStorage,
|
|
33
|
+
IndexedDBStorageBackend,
|
|
34
|
+
ProviderKeysStore,
|
|
35
|
+
SessionsStore,
|
|
36
|
+
SettingsStore,
|
|
37
|
+
setAppStorage,
|
|
38
|
+
defaultConvertToLlm,
|
|
39
|
+
ApiKeyPromptDialog,
|
|
40
|
+
} from '@mariozechner/pi-web-ui';
|
|
31
41
|
import '@mariozechner/pi-web-ui/app.css';
|
|
32
42
|
|
|
33
43
|
// Set up storage
|
|
34
|
-
const
|
|
35
|
-
|
|
44
|
+
const settings = new SettingsStore();
|
|
45
|
+
const providerKeys = new ProviderKeysStore();
|
|
46
|
+
const sessions = new SessionsStore();
|
|
47
|
+
|
|
48
|
+
const backend = new IndexedDBStorageBackend({
|
|
49
|
+
dbName: 'my-app',
|
|
50
|
+
version: 1,
|
|
51
|
+
stores: [
|
|
52
|
+
settings.getConfig(),
|
|
53
|
+
providerKeys.getConfig(),
|
|
54
|
+
sessions.getConfig(),
|
|
55
|
+
SessionsStore.getMetadataConfig(),
|
|
56
|
+
],
|
|
36
57
|
});
|
|
37
|
-
setAppStorage(storage);
|
|
38
58
|
|
|
39
|
-
|
|
40
|
-
|
|
59
|
+
settings.setBackend(backend);
|
|
60
|
+
providerKeys.setBackend(backend);
|
|
61
|
+
sessions.setBackend(backend);
|
|
62
|
+
|
|
63
|
+
const storage = new AppStorage(settings, providerKeys, sessions, undefined, backend);
|
|
64
|
+
setAppStorage(storage);
|
|
41
65
|
|
|
42
66
|
// Create agent
|
|
43
67
|
const agent = new Agent({
|
|
@@ -48,135 +72,286 @@ const agent = new Agent({
|
|
|
48
72
|
messages: [],
|
|
49
73
|
tools: [],
|
|
50
74
|
},
|
|
51
|
-
|
|
75
|
+
convertToLlm: defaultConvertToLlm,
|
|
52
76
|
});
|
|
53
77
|
|
|
54
|
-
// Create chat panel
|
|
78
|
+
// Create chat panel
|
|
55
79
|
const chatPanel = new ChatPanel();
|
|
56
|
-
await chatPanel.setAgent(agent
|
|
80
|
+
await chatPanel.setAgent(agent, {
|
|
81
|
+
onApiKeyRequired: (provider) => ApiKeyPromptDialog.prompt(provider),
|
|
82
|
+
});
|
|
57
83
|
|
|
58
84
|
document.body.appendChild(chatPanel);
|
|
59
85
|
```
|
|
60
86
|
|
|
61
|
-
|
|
87
|
+
## Architecture
|
|
62
88
|
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
89
|
+
```
|
|
90
|
+
┌─────────────────────────────────────────────────────┐
|
|
91
|
+
│ ChatPanel │
|
|
92
|
+
│ ┌─────────────────────┐ ┌─────────────────────┐ │
|
|
93
|
+
│ │ AgentInterface │ │ ArtifactsPanel │ │
|
|
94
|
+
│ │ (messages, input) │ │ (HTML, SVG, MD) │ │
|
|
95
|
+
│ └─────────────────────┘ └─────────────────────┘ │
|
|
96
|
+
└─────────────────────────────────────────────────────┘
|
|
97
|
+
│
|
|
98
|
+
▼
|
|
99
|
+
┌─────────────────────────────────────────────────────┐
|
|
100
|
+
│ Agent (from pi-agent-core) │
|
|
101
|
+
│ - State management (messages, model, tools) │
|
|
102
|
+
│ - Event emission (agent_start, message_update, ...) │
|
|
103
|
+
│ - Tool execution │
|
|
104
|
+
└─────────────────────────────────────────────────────┘
|
|
105
|
+
│
|
|
106
|
+
▼
|
|
107
|
+
┌─────────────────────────────────────────────────────┐
|
|
108
|
+
│ AppStorage │
|
|
109
|
+
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
|
|
110
|
+
│ │ Settings │ │ Provider │ │ Sessions │ │
|
|
111
|
+
│ │ Store │ │Keys Store│ │ Store │ │
|
|
112
|
+
│ └──────────┘ └──────────┘ └──────────┘ │
|
|
113
|
+
│ │ │
|
|
114
|
+
│ IndexedDBStorageBackend │
|
|
115
|
+
└─────────────────────────────────────────────────────┘
|
|
67
116
|
```
|
|
68
117
|
|
|
69
|
-
##
|
|
118
|
+
## Components
|
|
70
119
|
|
|
71
120
|
### ChatPanel
|
|
72
121
|
|
|
73
|
-
|
|
122
|
+
High-level chat interface with built-in artifacts panel.
|
|
74
123
|
|
|
75
124
|
```typescript
|
|
76
|
-
import { ChatPanel, ApiKeyPromptDialog } from '@mariozechner/pi-web-ui';
|
|
77
|
-
|
|
78
125
|
const chatPanel = new ChatPanel();
|
|
126
|
+
await chatPanel.setAgent(agent, {
|
|
127
|
+
// Prompt for API key when needed
|
|
128
|
+
onApiKeyRequired: async (provider) => ApiKeyPromptDialog.prompt(provider),
|
|
79
129
|
|
|
80
|
-
//
|
|
81
|
-
|
|
82
|
-
return await ApiKeyPromptDialog.prompt(provider);
|
|
83
|
-
};
|
|
130
|
+
// Hook before sending messages
|
|
131
|
+
onBeforeSend: async () => { /* save draft, etc. */ },
|
|
84
132
|
|
|
85
|
-
//
|
|
86
|
-
|
|
133
|
+
// Handle cost display click
|
|
134
|
+
onCostClick: () => { /* show cost breakdown */ },
|
|
135
|
+
|
|
136
|
+
// Custom sandbox URL for browser extensions
|
|
137
|
+
sandboxUrlProvider: () => chrome.runtime.getURL('sandbox.html'),
|
|
138
|
+
|
|
139
|
+
// Add custom tools
|
|
140
|
+
toolsFactory: (agent, agentInterface, artifactsPanel, runtimeProvidersFactory) => {
|
|
141
|
+
const replTool = createJavaScriptReplTool();
|
|
142
|
+
replTool.runtimeProvidersFactory = runtimeProvidersFactory;
|
|
143
|
+
return [replTool];
|
|
144
|
+
},
|
|
145
|
+
});
|
|
87
146
|
```
|
|
88
147
|
|
|
89
|
-
###
|
|
148
|
+
### AgentInterface
|
|
90
149
|
|
|
91
|
-
|
|
150
|
+
Lower-level chat interface for custom layouts.
|
|
92
151
|
|
|
93
152
|
```typescript
|
|
94
|
-
|
|
95
|
-
|
|
153
|
+
const chat = document.createElement('agent-interface') as AgentInterface;
|
|
154
|
+
chat.session = agent;
|
|
155
|
+
chat.enableAttachments = true;
|
|
156
|
+
chat.enableModelSelector = true;
|
|
157
|
+
chat.enableThinkingSelector = true;
|
|
158
|
+
chat.onApiKeyRequired = async (provider) => { /* ... */ };
|
|
159
|
+
chat.onBeforeSend = async () => { /* ... */ };
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
Properties:
|
|
163
|
+
- `session`: Agent instance
|
|
164
|
+
- `enableAttachments`: Show attachment button (default: true)
|
|
165
|
+
- `enableModelSelector`: Show model selector (default: true)
|
|
166
|
+
- `enableThinkingSelector`: Show thinking level selector (default: true)
|
|
167
|
+
- `showThemeToggle`: Show theme toggle (default: false)
|
|
168
|
+
|
|
169
|
+
### Agent (from pi-agent-core)
|
|
170
|
+
|
|
171
|
+
```typescript
|
|
172
|
+
import { Agent } from '@mariozechner/pi-agent-core';
|
|
96
173
|
|
|
97
174
|
const agent = new Agent({
|
|
98
175
|
initialState: {
|
|
99
176
|
model: getModel('anthropic', 'claude-sonnet-4-5-20250929'),
|
|
100
|
-
systemPrompt: 'You are
|
|
177
|
+
systemPrompt: 'You are helpful.',
|
|
101
178
|
thinkingLevel: 'off',
|
|
102
179
|
messages: [],
|
|
103
180
|
tools: [],
|
|
104
181
|
},
|
|
105
|
-
|
|
182
|
+
convertToLlm: defaultConvertToLlm,
|
|
106
183
|
});
|
|
107
184
|
|
|
108
|
-
//
|
|
185
|
+
// Events
|
|
109
186
|
agent.subscribe((event) => {
|
|
110
|
-
|
|
111
|
-
|
|
187
|
+
switch (event.type) {
|
|
188
|
+
case 'agent_start': // Agent loop started
|
|
189
|
+
case 'agent_end': // Agent loop finished
|
|
190
|
+
case 'turn_start': // LLM call started
|
|
191
|
+
case 'turn_end': // LLM call finished
|
|
192
|
+
case 'message_start':
|
|
193
|
+
case 'message_update': // Streaming update
|
|
194
|
+
case 'message_end':
|
|
195
|
+
break;
|
|
112
196
|
}
|
|
113
197
|
});
|
|
114
198
|
|
|
115
|
-
// Send
|
|
116
|
-
await agent.
|
|
199
|
+
// Send message
|
|
200
|
+
await agent.prompt('Hello!');
|
|
201
|
+
await agent.prompt({ role: 'user-with-attachments', content: 'Check this', attachments, timestamp: Date.now() });
|
|
202
|
+
|
|
203
|
+
// Control
|
|
204
|
+
agent.abort();
|
|
205
|
+
agent.setModel(newModel);
|
|
206
|
+
agent.setThinkingLevel('medium');
|
|
207
|
+
agent.setTools([...]);
|
|
208
|
+
agent.queueMessage(customMessage);
|
|
117
209
|
```
|
|
118
210
|
|
|
119
|
-
|
|
211
|
+
## Message Types
|
|
120
212
|
|
|
121
|
-
|
|
213
|
+
### UserMessageWithAttachments
|
|
214
|
+
|
|
215
|
+
User message with file attachments:
|
|
122
216
|
|
|
123
217
|
```typescript
|
|
124
|
-
|
|
218
|
+
const message: UserMessageWithAttachments = {
|
|
219
|
+
role: 'user-with-attachments',
|
|
220
|
+
content: 'Analyze this document',
|
|
221
|
+
attachments: [pdfAttachment],
|
|
222
|
+
timestamp: Date.now(),
|
|
223
|
+
};
|
|
125
224
|
|
|
126
|
-
|
|
127
|
-
|
|
225
|
+
// Type guard
|
|
226
|
+
if (isUserMessageWithAttachments(msg)) {
|
|
227
|
+
console.log(msg.attachments);
|
|
228
|
+
}
|
|
128
229
|
```
|
|
129
230
|
|
|
130
|
-
|
|
231
|
+
### ArtifactMessage
|
|
131
232
|
|
|
132
|
-
|
|
233
|
+
For session persistence of artifacts:
|
|
133
234
|
|
|
134
|
-
|
|
235
|
+
```typescript
|
|
236
|
+
const artifact: ArtifactMessage = {
|
|
237
|
+
role: 'artifact',
|
|
238
|
+
action: 'create', // or 'update', 'delete'
|
|
239
|
+
filename: 'chart.html',
|
|
240
|
+
content: '<div>...</div>',
|
|
241
|
+
timestamp: new Date().toISOString(),
|
|
242
|
+
};
|
|
135
243
|
|
|
136
|
-
|
|
244
|
+
// Type guard
|
|
245
|
+
if (isArtifactMessage(msg)) {
|
|
246
|
+
console.log(msg.filename);
|
|
247
|
+
}
|
|
248
|
+
```
|
|
137
249
|
|
|
138
|
-
|
|
139
|
-
import { ProviderTransport } from '@mariozechner/pi-web-ui';
|
|
250
|
+
### Custom Message Types
|
|
140
251
|
|
|
141
|
-
|
|
252
|
+
Extend via declaration merging:
|
|
142
253
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
254
|
+
```typescript
|
|
255
|
+
interface SystemNotification {
|
|
256
|
+
role: 'system-notification';
|
|
257
|
+
message: string;
|
|
258
|
+
level: 'info' | 'warning' | 'error';
|
|
259
|
+
timestamp: string;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
declare module '@mariozechner/pi-agent-core' {
|
|
263
|
+
interface CustomAgentMessages {
|
|
264
|
+
'system-notification': SystemNotification;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
// Register renderer
|
|
269
|
+
registerMessageRenderer('system-notification', {
|
|
270
|
+
render: (msg) => html`<div class="alert">${msg.message}</div>`,
|
|
146
271
|
});
|
|
272
|
+
|
|
273
|
+
// Extend convertToLlm
|
|
274
|
+
function myConvertToLlm(messages: AgentMessage[]): Message[] {
|
|
275
|
+
const processed = messages.map((m) => {
|
|
276
|
+
if (m.role === 'system-notification') {
|
|
277
|
+
return { role: 'user', content: `<system>${m.message}</system>`, timestamp: Date.now() };
|
|
278
|
+
}
|
|
279
|
+
return m;
|
|
280
|
+
});
|
|
281
|
+
return defaultConvertToLlm(processed);
|
|
282
|
+
}
|
|
147
283
|
```
|
|
148
284
|
|
|
149
|
-
|
|
285
|
+
## Message Transformer
|
|
150
286
|
|
|
151
|
-
|
|
287
|
+
`convertToLlm` transforms app messages to LLM-compatible format:
|
|
152
288
|
|
|
153
289
|
```typescript
|
|
154
|
-
import {
|
|
290
|
+
import { defaultConvertToLlm, convertAttachments } from '@mariozechner/pi-web-ui';
|
|
155
291
|
|
|
156
|
-
|
|
292
|
+
// defaultConvertToLlm handles:
|
|
293
|
+
// - UserMessageWithAttachments → user message with image/text content blocks
|
|
294
|
+
// - ArtifactMessage → filtered out (UI-only)
|
|
295
|
+
// - Standard messages (user, assistant, toolResult) → passed through
|
|
296
|
+
```
|
|
157
297
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
298
|
+
## Tools
|
|
299
|
+
|
|
300
|
+
### JavaScript REPL
|
|
301
|
+
|
|
302
|
+
Execute JavaScript in a sandboxed browser environment:
|
|
303
|
+
|
|
304
|
+
```typescript
|
|
305
|
+
import { createJavaScriptReplTool } from '@mariozechner/pi-web-ui';
|
|
306
|
+
|
|
307
|
+
const replTool = createJavaScriptReplTool();
|
|
308
|
+
|
|
309
|
+
// Configure runtime providers for artifact/attachment access
|
|
310
|
+
replTool.runtimeProvidersFactory = () => [
|
|
311
|
+
new AttachmentsRuntimeProvider(attachments),
|
|
312
|
+
new ArtifactsRuntimeProvider(artifactsPanel, agent, true), // read-write
|
|
313
|
+
];
|
|
314
|
+
|
|
315
|
+
agent.setTools([replTool]);
|
|
162
316
|
```
|
|
163
317
|
|
|
164
|
-
|
|
318
|
+
### Extract Document
|
|
165
319
|
|
|
166
|
-
|
|
320
|
+
Extract text from documents at URLs:
|
|
321
|
+
|
|
322
|
+
```typescript
|
|
323
|
+
import { createExtractDocumentTool } from '@mariozechner/pi-web-ui';
|
|
324
|
+
|
|
325
|
+
const extractTool = createExtractDocumentTool();
|
|
326
|
+
extractTool.corsProxyUrl = 'https://corsproxy.io/?';
|
|
327
|
+
|
|
328
|
+
agent.setTools([extractTool]);
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
### Artifacts Tool
|
|
332
|
+
|
|
333
|
+
Built into ArtifactsPanel, supports: HTML, SVG, Markdown, text, JSON, images, PDF, DOCX, XLSX.
|
|
334
|
+
|
|
335
|
+
```typescript
|
|
336
|
+
const artifactsPanel = new ArtifactsPanel();
|
|
337
|
+
artifactsPanel.agent = agent;
|
|
338
|
+
|
|
339
|
+
// The tool is available as artifactsPanel.tool
|
|
340
|
+
agent.setTools([artifactsPanel.tool]);
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
### Custom Tool Renderers
|
|
167
344
|
|
|
168
345
|
```typescript
|
|
169
346
|
import { registerToolRenderer, type ToolRenderer } from '@mariozechner/pi-web-ui';
|
|
170
|
-
import { html } from '@mariozechner/mini-lit';
|
|
171
347
|
|
|
172
348
|
const myRenderer: ToolRenderer = {
|
|
173
|
-
|
|
174
|
-
return
|
|
349
|
+
render(params, result, isStreaming) {
|
|
350
|
+
return {
|
|
351
|
+
content: html`<div>...</div>`,
|
|
352
|
+
isCustom: false, // true = no card wrapper
|
|
353
|
+
};
|
|
175
354
|
},
|
|
176
|
-
|
|
177
|
-
renderResult(params, result) {
|
|
178
|
-
return html`<div>Result: ${result.output}</div>`;
|
|
179
|
-
}
|
|
180
355
|
};
|
|
181
356
|
|
|
182
357
|
registerToolRenderer('my_tool', myRenderer);
|
|
@@ -184,147 +359,242 @@ registerToolRenderer('my_tool', myRenderer);
|
|
|
184
359
|
|
|
185
360
|
## Storage
|
|
186
361
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
### AppStorage
|
|
190
|
-
|
|
191
|
-
Central storage configuration for the application.
|
|
362
|
+
### Setup
|
|
192
363
|
|
|
193
364
|
```typescript
|
|
194
|
-
import {
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
365
|
+
import {
|
|
366
|
+
AppStorage,
|
|
367
|
+
IndexedDBStorageBackend,
|
|
368
|
+
SettingsStore,
|
|
369
|
+
ProviderKeysStore,
|
|
370
|
+
SessionsStore,
|
|
371
|
+
CustomProvidersStore,
|
|
372
|
+
setAppStorage,
|
|
373
|
+
getAppStorage,
|
|
374
|
+
} from '@mariozechner/pi-web-ui';
|
|
375
|
+
|
|
376
|
+
// Create stores
|
|
377
|
+
const settings = new SettingsStore();
|
|
378
|
+
const providerKeys = new ProviderKeysStore();
|
|
379
|
+
const sessions = new SessionsStore();
|
|
380
|
+
const customProviders = new CustomProvidersStore();
|
|
381
|
+
|
|
382
|
+
// Create backend with all store configs
|
|
383
|
+
const backend = new IndexedDBStorageBackend({
|
|
384
|
+
dbName: 'my-app',
|
|
385
|
+
version: 1,
|
|
386
|
+
stores: [
|
|
387
|
+
settings.getConfig(),
|
|
388
|
+
providerKeys.getConfig(),
|
|
389
|
+
sessions.getConfig(),
|
|
390
|
+
SessionsStore.getMetadataConfig(),
|
|
391
|
+
customProviders.getConfig(),
|
|
392
|
+
],
|
|
198
393
|
});
|
|
199
394
|
|
|
395
|
+
// Wire stores to backend
|
|
396
|
+
settings.setBackend(backend);
|
|
397
|
+
providerKeys.setBackend(backend);
|
|
398
|
+
sessions.setBackend(backend);
|
|
399
|
+
customProviders.setBackend(backend);
|
|
400
|
+
|
|
401
|
+
// Create and set global storage
|
|
402
|
+
const storage = new AppStorage(settings, providerKeys, sessions, customProviders, backend);
|
|
200
403
|
setAppStorage(storage);
|
|
201
404
|
```
|
|
202
405
|
|
|
203
|
-
###
|
|
406
|
+
### SettingsStore
|
|
407
|
+
|
|
408
|
+
Key-value settings:
|
|
409
|
+
|
|
410
|
+
```typescript
|
|
411
|
+
await storage.settings.set('proxy.enabled', true);
|
|
412
|
+
await storage.settings.set('proxy.url', 'https://proxy.example.com');
|
|
413
|
+
const enabled = await storage.settings.get<boolean>('proxy.enabled');
|
|
414
|
+
```
|
|
204
415
|
|
|
205
|
-
|
|
206
|
-
- `IndexedDBBackend` - Uses IndexedDB for larger data
|
|
207
|
-
- `SessionIndexedDBBackend` - Specialized for session storage
|
|
208
|
-
- `WebExtensionStorageBackend` - For browser extensions using chrome.storage API
|
|
416
|
+
### ProviderKeysStore
|
|
209
417
|
|
|
210
|
-
|
|
418
|
+
API keys by provider:
|
|
211
419
|
|
|
212
420
|
```typescript
|
|
213
|
-
|
|
421
|
+
await storage.providerKeys.set('anthropic', 'sk-ant-...');
|
|
422
|
+
const key = await storage.providerKeys.get('anthropic');
|
|
423
|
+
const providers = await storage.providerKeys.list();
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
### SessionsStore
|
|
214
427
|
|
|
215
|
-
|
|
428
|
+
Chat sessions with metadata:
|
|
216
429
|
|
|
430
|
+
```typescript
|
|
217
431
|
// Save session
|
|
218
|
-
await storage.sessions
|
|
432
|
+
await storage.sessions.save(sessionData, metadata);
|
|
219
433
|
|
|
220
434
|
// Load session
|
|
221
|
-
const
|
|
435
|
+
const data = await storage.sessions.get(sessionId);
|
|
436
|
+
const metadata = await storage.sessions.getMetadata(sessionId);
|
|
437
|
+
|
|
438
|
+
// List sessions (sorted by lastModified)
|
|
439
|
+
const allMetadata = await storage.sessions.getAllMetadata();
|
|
222
440
|
|
|
223
|
-
//
|
|
224
|
-
|
|
441
|
+
// Update title
|
|
442
|
+
await storage.sessions.updateTitle(sessionId, 'New Title');
|
|
443
|
+
|
|
444
|
+
// Delete
|
|
445
|
+
await storage.sessions.delete(sessionId);
|
|
225
446
|
```
|
|
226
447
|
|
|
227
|
-
|
|
448
|
+
### CustomProvidersStore
|
|
228
449
|
|
|
229
|
-
|
|
450
|
+
Custom LLM providers:
|
|
230
451
|
|
|
231
452
|
```typescript
|
|
232
|
-
|
|
453
|
+
const provider: CustomProvider = {
|
|
454
|
+
id: crypto.randomUUID(),
|
|
455
|
+
name: 'My Ollama',
|
|
456
|
+
type: 'ollama',
|
|
457
|
+
baseUrl: 'http://localhost:11434',
|
|
458
|
+
};
|
|
459
|
+
|
|
460
|
+
await storage.customProviders.set(provider);
|
|
461
|
+
const all = await storage.customProviders.getAll();
|
|
233
462
|
```
|
|
234
463
|
|
|
235
|
-
|
|
464
|
+
## Attachments
|
|
236
465
|
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
@
|
|
241
|
-
|
|
466
|
+
Load and process files:
|
|
467
|
+
|
|
468
|
+
```typescript
|
|
469
|
+
import { loadAttachment, type Attachment } from '@mariozechner/pi-web-ui';
|
|
470
|
+
|
|
471
|
+
// From File input
|
|
472
|
+
const file = inputElement.files[0];
|
|
473
|
+
const attachment = await loadAttachment(file);
|
|
474
|
+
|
|
475
|
+
// From URL
|
|
476
|
+
const attachment = await loadAttachment('https://example.com/doc.pdf');
|
|
477
|
+
|
|
478
|
+
// From ArrayBuffer
|
|
479
|
+
const attachment = await loadAttachment(arrayBuffer, 'document.pdf');
|
|
480
|
+
|
|
481
|
+
// Attachment structure
|
|
482
|
+
interface Attachment {
|
|
483
|
+
id: string;
|
|
484
|
+
type: 'image' | 'document';
|
|
485
|
+
fileName: string;
|
|
486
|
+
mimeType: string;
|
|
487
|
+
size: number;
|
|
488
|
+
content: string; // base64 encoded
|
|
489
|
+
extractedText?: string; // For documents
|
|
490
|
+
preview?: string; // base64 preview image
|
|
491
|
+
}
|
|
242
492
|
```
|
|
243
493
|
|
|
244
|
-
|
|
494
|
+
Supported formats: PDF, DOCX, XLSX, PPTX, images, text files.
|
|
245
495
|
|
|
246
|
-
|
|
496
|
+
## CORS Proxy
|
|
247
497
|
|
|
248
|
-
|
|
498
|
+
For browser environments with CORS restrictions:
|
|
249
499
|
|
|
250
|
-
|
|
500
|
+
```typescript
|
|
501
|
+
import { createStreamFn, shouldUseProxyForProvider, isCorsError } from '@mariozechner/pi-web-ui';
|
|
502
|
+
|
|
503
|
+
// AgentInterface auto-configures proxy from settings
|
|
504
|
+
// For manual setup:
|
|
505
|
+
agent.streamFn = createStreamFn(async () => {
|
|
506
|
+
const enabled = await storage.settings.get<boolean>('proxy.enabled');
|
|
507
|
+
return enabled ? await storage.settings.get<string>('proxy.url') : undefined;
|
|
508
|
+
});
|
|
509
|
+
|
|
510
|
+
// Providers requiring proxy:
|
|
511
|
+
// - zai: always
|
|
512
|
+
// - anthropic: only OAuth tokens (sk-ant-oat-*)
|
|
513
|
+
```
|
|
514
|
+
|
|
515
|
+
## Dialogs
|
|
516
|
+
|
|
517
|
+
### SettingsDialog
|
|
251
518
|
|
|
252
519
|
```typescript
|
|
253
|
-
import { SettingsDialog,
|
|
520
|
+
import { SettingsDialog, ProvidersModelsTab, ProxyTab, ApiKeysTab } from '@mariozechner/pi-web-ui';
|
|
254
521
|
|
|
255
|
-
|
|
256
|
-
|
|
522
|
+
SettingsDialog.open([
|
|
523
|
+
new ProvidersModelsTab(), // Custom providers + model list
|
|
524
|
+
new ProxyTab(), // CORS proxy settings
|
|
525
|
+
new ApiKeysTab(), // API keys per provider
|
|
526
|
+
]);
|
|
257
527
|
```
|
|
258
528
|
|
|
259
529
|
### SessionListDialog
|
|
260
530
|
|
|
261
|
-
Display and load saved sessions.
|
|
262
|
-
|
|
263
531
|
```typescript
|
|
264
532
|
import { SessionListDialog } from '@mariozechner/pi-web-ui';
|
|
265
533
|
|
|
266
|
-
SessionListDialog.open(
|
|
267
|
-
|
|
268
|
-
}
|
|
534
|
+
SessionListDialog.open(
|
|
535
|
+
async (sessionId) => { /* load session */ },
|
|
536
|
+
(deletedId) => { /* handle deletion */ },
|
|
537
|
+
);
|
|
269
538
|
```
|
|
270
539
|
|
|
271
540
|
### ApiKeyPromptDialog
|
|
272
541
|
|
|
273
|
-
Prompt user for API key when needed.
|
|
274
|
-
|
|
275
542
|
```typescript
|
|
276
543
|
import { ApiKeyPromptDialog } from '@mariozechner/pi-web-ui';
|
|
277
544
|
|
|
278
|
-
const
|
|
545
|
+
const success = await ApiKeyPromptDialog.prompt('anthropic');
|
|
279
546
|
```
|
|
280
547
|
|
|
281
|
-
###
|
|
282
|
-
|
|
283
|
-
Request persistent storage permission.
|
|
548
|
+
### ModelSelector
|
|
284
549
|
|
|
285
550
|
```typescript
|
|
286
|
-
import {
|
|
551
|
+
import { ModelSelector } from '@mariozechner/pi-web-ui';
|
|
287
552
|
|
|
288
|
-
|
|
553
|
+
ModelSelector.open(currentModel, (selectedModel) => {
|
|
554
|
+
agent.setModel(selectedModel);
|
|
555
|
+
});
|
|
289
556
|
```
|
|
290
557
|
|
|
291
|
-
##
|
|
558
|
+
## Styling
|
|
292
559
|
|
|
293
|
-
|
|
560
|
+
Import the pre-built CSS:
|
|
294
561
|
|
|
295
562
|
```typescript
|
|
296
|
-
import
|
|
563
|
+
import '@mariozechner/pi-web-ui/app.css';
|
|
564
|
+
```
|
|
297
565
|
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
566
|
+
Or use Tailwind with custom config:
|
|
567
|
+
|
|
568
|
+
```css
|
|
569
|
+
@import '@mariozechner/mini-lit/themes/claude.css';
|
|
570
|
+
@tailwind base;
|
|
571
|
+
@tailwind components;
|
|
572
|
+
@tailwind utilities;
|
|
303
573
|
```
|
|
304
574
|
|
|
305
|
-
|
|
575
|
+
## Internationalization
|
|
306
576
|
|
|
307
577
|
```typescript
|
|
308
|
-
import {
|
|
578
|
+
import { i18n, setLanguage, translations } from '@mariozechner/pi-web-ui';
|
|
309
579
|
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
580
|
+
// Add translations
|
|
581
|
+
translations.de = {
|
|
582
|
+
'Loading...': 'Laden...',
|
|
583
|
+
'No sessions yet': 'Noch keine Sitzungen',
|
|
584
|
+
};
|
|
585
|
+
|
|
586
|
+
setLanguage('de');
|
|
587
|
+
console.log(i18n('Loading...')); // "Laden..."
|
|
314
588
|
```
|
|
315
589
|
|
|
316
590
|
## Examples
|
|
317
591
|
|
|
318
|
-
- [example/](./example) - Complete web
|
|
319
|
-
- [sitegeist](https://
|
|
320
|
-
|
|
321
|
-
## API Reference
|
|
322
|
-
|
|
323
|
-
See [src/index.ts](src/index.ts) for the full public API.
|
|
592
|
+
- [example/](./example) - Complete web app with sessions, artifacts, custom messages
|
|
593
|
+
- [sitegeist](https://sitegeist.ai) - Browser extension using pi-web-ui
|
|
324
594
|
|
|
325
|
-
## Known
|
|
595
|
+
## Known Issues
|
|
326
596
|
|
|
327
|
-
- **PersistentStorageDialog**: Currently broken
|
|
597
|
+
- **PersistentStorageDialog**: Currently broken
|
|
328
598
|
|
|
329
599
|
## License
|
|
330
600
|
|