Integrating the Web UI
Relevant source files
The following files were used as context for generating this wiki page:The @mariozechner/pi-web-ui package provides a set of reusable web components for building modern, feature-rich AI chat interfaces. Built with mini-lit and styled with Tailwind CSS, it offers a complete chat UI that handles message history, streaming responses, tool execution, and file attachments. The components are platform-agnostic, designed to work in standard web applications, browser extensions, and Electron apps.
This guide covers the core components, architecture, and configuration steps for integrating the Web UI into a project. The primary component is the ChatPanel, which works in conjunction with an Agent instance to manage state and communicate with large language models.
Sources: packages/web-ui/README.md:1-10, packages/web-ui/package.json:3,42
Quick Start Example
Integrating the Web UI involves setting up the HTML entry point, initializing the core components in TypeScript, and connecting them. The example application demonstrates a minimal setup.
Sources: packages/web-ui/example/README.md:3-9
1. HTML Setup
The main HTML file needs a container element for the application and a script tag to load the main TypeScript entry point.
packages/web-ui/example/index.html
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Pi Web UI - Example</title>
</head>
<body class="bg-background">
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>
Sources: packages/web-ui/example/index.html:1-12
2. TypeScript Initialization
The main script initializes the storage, agent, and UI components. The ChatPanel is the main UI component that gets appended to the DOM.
packages/web-ui/example/src/main.ts
import {
Agent,
ChatPanel,
ProviderTransport,
AppStorage,
SessionIndexedDBBackend,
setAppStorage,
ApiKeyPromptDialog,
} from '@mariozechner/pi-web-ui';
import { getModel } from '@mariozechner/pi-ai';
import '@mariozechner/pi-web-ui/app.css';
import { JAVASCRIPT_REPL_TOOL_DESCRIPTION, ARTIFACTS_TOOL_DESCRIPTION } from '@mariozechner/pi-web-ui';
// 1. Set up storage
const storage = new AppStorage({
sessions: new SessionIndexedDBBackend('pi-web-ui-example-sessions'),
});
setAppStorage(storage);
// 2. Create transport
const transport = new ProviderTransport();
// 3. Create agent
const agent = new Agent({
initialState: {
systemPrompt: `...`, // System prompt definition
model: getModel('anthropic', 'claude-3-haiku-20240307'),
tools: [
// Tool definitions
],
},
transport,
});
// 4. Create ChatPanel and attach agent
const chatPanel = new ChatPanel();
await chatPanel.setAgent(agent);
// 5. Append to DOM
const app = document.querySelector('#app');
if (app) {
app.appendChild(chatPanel);
}
Sources: packages/web-ui/example/src/main.ts:1-68, packages/web-ui/README.md:14-36
Initialization Flow
The following diagram illustrates the setup process described in the quick start example.
Core Components
The Web UI is built around a few key components that manage state, communication, and rendering.
| Component | Description |
|---|---|
ChatPanel | The main, high-level web component that renders the entire chat interface, including messages, input bar, and settings. |
Agent | The core state manager. It holds the conversation history, tool definitions, and current model, and orchestrates the interaction between the UI and the transport layer. |
ProviderTransport | The default transport layer that communicates directly with AI provider APIs (e.g., Anthropic, OpenAI) from the browser. It handles API key management. |
AppTransport | An alternative transport for proxying requests through a custom backend server instead of making direct API calls from the client. |
Sources: packages/web-ui/README.md:39-84, packages/web-ui/src/index.ts:1-30
The relationship between these core components is shown in the diagram below.
Architecture and Data Flow
When a user sends a message, the ChatPanel captures the input and passes it to the Agent. The Agent then uses its configured transport (e.g., ProviderTransport) to send the request to the AI model. Responses, including streaming text and tool calls, are received by the Agent, which updates its state. The ChatPanel, subscribed to the Agent's events, re-renders to display the new information.
This sequence is illustrated in the diagram below.
Configuration
System Prompt and Tools
The Agent is configured with an initialState object that defines its behavior. This includes the systemPrompt and a list of tools the model can use. The descriptions for these tools are crucial for the model to understand their capabilities.
The example below shows how the JavaScript REPL and Artifacts tools are described. These descriptions inform the model about the available helper functions within the execution environment.
packages/web-ui/src/prompts/prompts.ts
export const JAVASCRIPT_REPL_TOOL_DESCRIPTION = (runtimeProviderDescriptions: string[]) => `# JavaScript REPL
## Purpose
Execute JavaScript code in a sandboxed browser environment...
## Helper Functions (Automatically Available)
These functions are injected into the execution environment and available globally:
${runtimeProviderDescriptions.join("\n\n")}
`;
export const ARTIFACTS_TOOL_DESCRIPTION = (runtimeProviderDescriptions: string[]) => `# Artifacts
Create and manage persistent files that live alongside the conversation.
...
### Helper Functions (Automatically Available)
These functions are injected into HTML artifact sandbox:
${runtimeProviderDescriptions.join("\n\n")}
`;
Sources: packages/web-ui/src/prompts/prompts.ts:8-100, packages/web-ui/example/src/main.ts:28-44
API Key Management
The example application uses a "Direct Mode," where the ProviderTransport calls AI provider APIs directly from the browser. API keys are managed through a settings dialog and stored in the browser's localStorage. They are only sent to the respective AI provider's API.
The ChatPanel has an onApiKeyRequired callback that can be implemented to prompt the user for a key when one is missing.
Sources: packages/web-ui/example/README.md:17-33, packages/web-ui/README.md:50-53
Styling
The package provides a pre-built CSS file that includes the Claude theme and Tailwind utilities. This can be imported directly.
import '@mariozechner/pi-web-ui/app.css';
Alternatively, for custom builds, developers can import the theme and use their own Tailwind configuration.
Sources: packages/web-ui/README.md:143-152, packages/web-ui/example/src/main.ts:11
Storage and Session Management
The @mariozechner/pi-web-ui package includes a flexible storage system for persisting sessions, API keys, and settings. The AppStorage class is the central point for configuring different storage backends.
Storage Backends
| Backend | Purpose | Storage Mechanism |
|---|---|---|
LocalStorageBackend | General key-value storage. | Browser localStorage |
IndexedDBBackend | For larger data. | Browser IndexedDB |
SessionIndexedDBBackend | Specialized for storing and listing chat sessions. | Browser IndexedDB |
WebExtensionStorageBackend | For use in browser extensions. | chrome.storage API |
Sources: packages/web-ui/README.md:118-125
Configuration
Storage is configured by creating an AppStorage instance and passing it to setAppStorage. This makes the storage instance globally available to all UI components.
packages/web-ui/example/src/main.ts
// 1. Set up storage
const storage = new AppStorage({
sessions: new SessionIndexedDBBackend('pi-web-ui-example-sessions'),
});
setAppStorage(storage);
Sources: packages/web-ui/example/src/main.ts:14-18, packages/web-ui/README.md:108-115
Conclusion
Integrating the @mariozechner/pi-web-ui package provides a robust and customizable foundation for building AI-powered chat applications. By composing the ChatPanel, Agent, and a Transport, developers can quickly stand up a complete chat interface. The system's flexibility is enhanced through configurable storage backends, customizable tool renderers, and a clear separation between UI, state management, and API communication. The provided example application serves as a practical starting point for new integrations.
Sources: packages/web-ui/README.md, packages/web-ui/example/README.md