feat(prototypes): add pi-web-ui-lan prototype
LAN-accessible web UI for pi agent interaction.
This commit is contained in:
parent
1e1965dc17
commit
131fb86852
26
prototypes/pi-web-ui-lan/README.md
Normal file
26
prototypes/pi-web-ui-lan/README.md
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
# Pi Web UI (LAN prototype)
|
||||||
|
|
||||||
|
Minimal LAN-only web UI using `@mariozechner/pi-web-ui`.
|
||||||
|
|
||||||
|
## Run (LAN)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /home/dan/proj/skills/prototypes/pi-web-ui-lan
|
||||||
|
npm install
|
||||||
|
npm run dev:lan
|
||||||
|
```
|
||||||
|
|
||||||
|
Vite will print a LAN URL (e.g., `http://192.168.1.20:5173`). Open it on your phone connected to the same Wi‑Fi.
|
||||||
|
|
||||||
|
## Workflow
|
||||||
|
|
||||||
|
1. Start the dev server (`npm run dev:lan`).
|
||||||
|
2. Open the LAN URL on the phone.
|
||||||
|
3. Open Settings → Manage API Keys and add your provider key.
|
||||||
|
4. Chat in the UI.
|
||||||
|
|
||||||
|
## Notes / Limitations
|
||||||
|
|
||||||
|
- This prototype runs in **direct mode** (browser calls provider APIs directly).
|
||||||
|
- It does **not** access the local filesystem or repo yet.
|
||||||
|
- Next step for repo access: add a local RPC/agent backend and bridge it to the UI.
|
||||||
12
prototypes/pi-web-ui-lan/index.html
Normal file
12
prototypes/pi-web-ui-lan/index.html
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
<!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 (LAN)</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="app"></div>
|
||||||
|
<script type="module" src="/src/main.ts"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
22
prototypes/pi-web-ui-lan/package.json
Normal file
22
prototypes/pi-web-ui-lan/package.json
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
{
|
||||||
|
"name": "pi-web-ui-lan",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"private": true,
|
||||||
|
"type": "module",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "vite",
|
||||||
|
"dev:lan": "vite --host 0.0.0.0 --port 5173",
|
||||||
|
"build": "vite build",
|
||||||
|
"preview": "vite preview --host 0.0.0.0 --port 5173"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@mariozechner/pi-agent-core": "^0.49.3",
|
||||||
|
"@mariozechner/pi-ai": "^0.49.3",
|
||||||
|
"@mariozechner/pi-web-ui": "^0.49.3",
|
||||||
|
"lit": "^3.3.1"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"typescript": "^5.7.3",
|
||||||
|
"vite": "^7.1.6"
|
||||||
|
}
|
||||||
|
}
|
||||||
2938
prototypes/pi-web-ui-lan/pnpm-lock.yaml
Normal file
2938
prototypes/pi-web-ui-lan/pnpm-lock.yaml
Normal file
File diff suppressed because it is too large
Load diff
49
prototypes/pi-web-ui-lan/src/main.ts
Normal file
49
prototypes/pi-web-ui-lan/src/main.ts
Normal file
|
|
@ -0,0 +1,49 @@
|
||||||
|
import { Agent } from "@mariozechner/pi-agent-core";
|
||||||
|
import { getModel } from "@mariozechner/pi-ai";
|
||||||
|
import {
|
||||||
|
ApiKeyPromptDialog,
|
||||||
|
AppStorage,
|
||||||
|
ChatPanel,
|
||||||
|
IndexedDBStorageBackend,
|
||||||
|
ProviderKeysStore,
|
||||||
|
SessionsStore,
|
||||||
|
SettingsStore,
|
||||||
|
defaultConvertToLlm,
|
||||||
|
setAppStorage,
|
||||||
|
} from "@mariozechner/pi-web-ui";
|
||||||
|
import "@mariozechner/pi-web-ui/app.css";
|
||||||
|
|
||||||
|
const settings = new SettingsStore();
|
||||||
|
const providerKeys = new ProviderKeysStore();
|
||||||
|
const sessions = new SessionsStore();
|
||||||
|
|
||||||
|
const backend = new IndexedDBStorageBackend({
|
||||||
|
dbName: "pi-web-ui-lan",
|
||||||
|
version: 1,
|
||||||
|
stores: [settings.getConfig(), providerKeys.getConfig(), sessions.getConfig(), SessionsStore.getMetadataConfig()],
|
||||||
|
});
|
||||||
|
|
||||||
|
settings.setBackend(backend);
|
||||||
|
providerKeys.setBackend(backend);
|
||||||
|
sessions.setBackend(backend);
|
||||||
|
|
||||||
|
const storage = new AppStorage(settings, providerKeys, sessions, undefined, backend);
|
||||||
|
setAppStorage(storage);
|
||||||
|
|
||||||
|
const agent = new Agent({
|
||||||
|
initialState: {
|
||||||
|
systemPrompt: "You are a helpful assistant.",
|
||||||
|
model: getModel("google", "gemini-3-flash-preview"),
|
||||||
|
thinkingLevel: "off",
|
||||||
|
messages: [],
|
||||||
|
tools: [],
|
||||||
|
},
|
||||||
|
convertToLlm: defaultConvertToLlm,
|
||||||
|
});
|
||||||
|
|
||||||
|
const chatPanel = new ChatPanel();
|
||||||
|
await chatPanel.setAgent(agent, {
|
||||||
|
onApiKeyRequired: async (provider) => ApiKeyPromptDialog.prompt(provider),
|
||||||
|
});
|
||||||
|
|
||||||
|
document.getElementById("app")?.appendChild(chatPanel);
|
||||||
15
prototypes/pi-web-ui-lan/tsconfig.json
Normal file
15
prototypes/pi-web-ui-lan/tsconfig.json
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "ES2022",
|
||||||
|
"module": "ES2022",
|
||||||
|
"lib": ["ES2022", "DOM", "DOM.Iterable"],
|
||||||
|
"moduleResolution": "bundler",
|
||||||
|
"strict": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"allowSyntheticDefaultImports": true,
|
||||||
|
"experimentalDecorators": true,
|
||||||
|
"useDefineForClassFields": false
|
||||||
|
},
|
||||||
|
"include": ["src/**/*"]
|
||||||
|
}
|
||||||
10
prototypes/pi-web-ui-lan/vite.config.ts
Normal file
10
prototypes/pi-web-ui-lan/vite.config.ts
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
import { defineConfig } from "vite";
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
resolve: {
|
||||||
|
conditions: ["production", "browser", "module", "default"],
|
||||||
|
},
|
||||||
|
server: {
|
||||||
|
port: 5173,
|
||||||
|
},
|
||||||
|
});
|
||||||
Loading…
Reference in a new issue