- Implement CustomMessages interface for type-safe message extension via declaration merging - Add MessageRenderer<T> with generic typing for custom message rendering - Add messageTransformer to Agent for filtering/transforming messages before LLM - Move message filtering from transports to Agent (separation of concerns) - Add message renderer registry with typed role support - Update web-ui example with SystemNotificationMessage demo - Add custom transformer that converts notifications to <system> tags - Add SessionListDialog onDelete callback for active session cleanup - Handle non-existent session IDs in URL (redirect to new session) - Update both web-ui example and browser extension with session fixes |
||
|---|---|---|
| .. | ||
| example | ||
| src | ||
| package.json | ||
| README.md | ||
| tsconfig.build.json | ||
| tsconfig.json | ||
@mariozechner/pi-web-ui
Reusable web UI components for building AI chat interfaces powered by @mariozechner/pi-ai.
Built with mini-lit web components and Tailwind CSS v4.
Features
- Modern Chat Interface - Complete chat UI with message history, streaming responses, and tool execution
- Tool Support - Built-in renderers for calculator, bash, time, and custom tools
- Attachments - PDF, Office documents, images with preview and text extraction
- Artifacts - HTML, SVG, Markdown, and text artifact rendering with sandboxed execution
- Pluggable Transports - Direct API calls or proxy server support
- Platform Agnostic - Works in browser extensions, web apps, VS Code extensions, Electron apps
- TypeScript - Full type safety with TypeScript
Installation
npm install @mariozechner/pi-web-ui
Quick Start
See the example directory for a complete working application.
import { Agent, ChatPanel, ProviderTransport, AppStorage,
SessionIndexedDBBackend, setAppStorage } from '@mariozechner/pi-web-ui';
import { getModel } from '@mariozechner/pi-ai';
import '@mariozechner/pi-web-ui/app.css';
// Set up storage
const storage = new AppStorage({
sessions: new SessionIndexedDBBackend('my-app-sessions'),
});
setAppStorage(storage);
// Create transport
const transport = new ProviderTransport();
// Create agent
const agent = new Agent({
initialState: {
systemPrompt: 'You are a helpful assistant.',
model: getModel('anthropic', 'claude-sonnet-4-5-20250929'),
thinkingLevel: 'off',
messages: [],
tools: [],
},
transport,
});
// Create chat panel and attach agent
const chatPanel = new ChatPanel();
await chatPanel.setAgent(agent);
document.body.appendChild(chatPanel);
Run the example:
cd example
npm install
npm run dev
Core Components
ChatPanel
The main chat interface component. Displays messages, handles input, and coordinates with the Agent.
import { ChatPanel, ApiKeyPromptDialog } from '@mariozechner/pi-web-ui';
const chatPanel = new ChatPanel();
// Optional: Handle API key prompts
chatPanel.onApiKeyRequired = async (provider: string) => {
return await ApiKeyPromptDialog.prompt(provider);
};
// Attach an agent
await chatPanel.setAgent(agent);
Agent
Core state manager that handles conversation state, tool execution, and streaming.
import { Agent, ProviderTransport } from '@mariozechner/pi-web-ui';
import { getModel } from '@mariozechner/pi-ai';
const agent = new Agent({
initialState: {
model: getModel('anthropic', 'claude-sonnet-4-5-20250929'),
systemPrompt: 'You are a helpful assistant.',
thinkingLevel: 'off',
messages: [],
tools: [],
},
transport: new ProviderTransport(),
});
// Subscribe to events
agent.subscribe((event) => {
if (event.type === 'state-update') {
console.log('Messages:', event.state.messages);
}
});
// Send a message
await agent.send('Hello!');
AgentInterface
Lower-level chat interface for custom implementations. Used internally by ChatPanel.
import { AgentInterface } from '@mariozechner/pi-web-ui';
const chat = new AgentInterface();
await chat.setAgent(agent);
Transports
Transport layers handle communication with AI providers.
ProviderTransport
The main transport that calls AI provider APIs using stored API keys.
import { ProviderTransport } from '@mariozechner/pi-web-ui';
const transport = new ProviderTransport();
const agent = new Agent({
initialState: { /* ... */ },
transport,
});
AppTransport
Alternative transport for proxying requests through a custom server.
import { AppTransport } from '@mariozechner/pi-web-ui';
const transport = new AppTransport();
const agent = new Agent({
initialState: { /* ... */ },
transport,
});
Tool Renderers
Customize how tool calls and results are displayed.
import { registerToolRenderer, type ToolRenderer } from '@mariozechner/pi-web-ui';
import { html } from '@mariozechner/mini-lit';
const myRenderer: ToolRenderer = {
renderParams(params, isStreaming) {
return html`<div>Calling tool with: ${JSON.stringify(params)}</div>`;
},
renderResult(params, result) {
return html`<div>Result: ${result.output}</div>`;
}
};
registerToolRenderer('my_tool', myRenderer);
Storage
The package provides flexible storage backends for API keys, settings, and session persistence.
AppStorage
Central storage configuration for the application.
import { AppStorage, setAppStorage, SessionIndexedDBBackend } from '@mariozechner/pi-web-ui';
const storage = new AppStorage({
sessions: new SessionIndexedDBBackend('my-app-sessions'),
});
setAppStorage(storage);
Available Backends
LocalStorageBackend- Uses browser localStorageIndexedDBBackend- Uses IndexedDB for larger dataSessionIndexedDBBackend- Specialized for session storageChromeStorageBackend- For browser extensions using chrome.storage API
Session Management
import { getAppStorage } from '@mariozechner/pi-web-ui';
const storage = getAppStorage();
// Save session
await storage.sessions?.saveSession(sessionId, agentState, undefined, title);
// Load session
const sessionData = await storage.sessions?.loadSession(sessionId);
// List sessions
const sessions = await storage.sessions?.listSessions();
Styling
The package includes pre-built Tailwind CSS with the Claude theme:
import '@mariozechner/pi-web-ui/app.css';
Or customize with your own Tailwind config:
@import '@mariozechner/mini-lit/themes/claude.css';
@tailwind base;
@tailwind components;
@tailwind utilities;
Dialogs
The package includes several dialog components for common interactions.
SettingsDialog
Settings dialog with tabbed interface for API keys, proxy configuration, etc.
import { SettingsDialog, ApiKeysTab, ProxyTab } from '@mariozechner/pi-web-ui';
// Open settings with tabs
SettingsDialog.open([new ApiKeysTab(), new ProxyTab()]);
SessionListDialog
Display and load saved sessions.
import { SessionListDialog } from '@mariozechner/pi-web-ui';
SessionListDialog.open(async (sessionId) => {
await loadSession(sessionId);
});
ApiKeyPromptDialog
Prompt user for API key when needed.
import { ApiKeyPromptDialog } from '@mariozechner/pi-web-ui';
const apiKey = await ApiKeyPromptDialog.prompt('anthropic');
PersistentStorageDialog
Request persistent storage permission.
import { PersistentStorageDialog } from '@mariozechner/pi-web-ui';
await PersistentStorageDialog.request();
Platform Integration
Browser Extension
import { AppStorage, ChromeStorageBackend, Agent, ProviderTransport } from '@mariozechner/pi-web-ui';
const storage = new AppStorage({
providerKeys: new ChromeStorageBackend(),
settings: new ChromeStorageBackend(),
});
setAppStorage(storage);
Web Application
import { AppStorage, SessionIndexedDBBackend, setAppStorage } from '@mariozechner/pi-web-ui';
const storage = new AppStorage({
sessions: new SessionIndexedDBBackend('my-app-sessions'),
});
setAppStorage(storage);
Examples
- example/ - Complete web application with session management
- browser-extension - Browser extension implementation
API Reference
See src/index.ts for the full public API.
License
MIT