fix: replace broken agent.on() with subscribe() API, add favicon, fix page title
Some checks are pending
CI / build-check-test (push) Waiting to run

- agent.on() does not exist - replaced all 3 calls with single agent.subscribe() handler
- Maps AgentEvent types: agent_start/end, turn_start/end, tool_execution_start, message_start/end
- Cost tracking now reads usage from message_end event message.usage field
- Added favicon.ico and apple-touch-icon.png from mascot
- Fixed page title from Pi Web UI to Agent JAE
This commit is contained in:
JAE 2026-03-27 07:31:07 +00:00
parent 33f439296f
commit 3bb3caa650
4 changed files with 68 additions and 50 deletions

View file

@ -1,10 +1,12 @@
<!doctype html> <!doctype html>
<html lang="en"> <html lang="en">
<head> <head>
<link rel="icon" type="image/x-icon" href="/favicon.ico">
<link rel="apple-touch-icon" href="/apple-touch-icon.png">
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Pi Web UI - Example</title> <title>Agent JAE</title>
<meta name="description" content="Example usage of @mariozechner/pi-web-ui - Reusable AI chat interface" /> <meta name="description" content="Agent JAE - AI Coding Agent by JaeSwift" />
</head> </head>
<body class="bg-background"> <body class="bg-background">
<div id="app"></div> <div id="app"></div>

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

View file

@ -258,22 +258,38 @@ async function createAgent(initialState?: AgentState) {
currentModel = model.modelId || "llama-3.3-70b"; currentModel = model.modelId || "llama-3.3-70b";
currentProvider = model.provider || "venice"; currentProvider = model.provider || "venice";
// Listen for agent messages to track state // Subscribe to agent events for UI state tracking
agent.on("message", (msg: AgentMessage) => { agent.subscribe((event) => {
if (!hasMessages && msg.role === "assistant") { const typing = document.querySelector("jae-typing-indicator") as JaeTypingIndicator;
hasMessages = true; const mood = document.querySelector("jae-mood-indicator") as JaeMoodIndicator;
renderApp();
} switch (event.type) {
// Track tool usage for mood and auto-open panels case "agent_start":
if (msg.role === "assistant" && msg.toolCalls) { if (typing) typing.show("high");
for (const tc of msg.toolCalls) { break;
if (tc.name === "browser" || tc.name === "web_fetch" || tc.name === "navigate") {
case "agent_end":
if (typing) typing.hide();
break;
case "turn_start":
if (typing) typing.show("high");
break;
case "turn_end":
if (typing) typing.hide();
break;
case "tool_execution_start":
if (typing) typing.show("medium");
// Auto-open panels based on tool usage
if (event.toolName === "browser" || event.toolName === "web_fetch" || event.toolName === "navigate") {
if (rightPanel !== "browser") { if (rightPanel !== "browser") {
rightPanel = "browser"; rightPanel = "browser";
renderApp(); renderApp();
} }
} }
if (tc.name === "bash") { if (event.toolName === "bash") {
if (rightPanel !== "terminal") { if (rightPanel !== "terminal") {
rightPanel = "terminal"; rightPanel = "terminal";
renderApp(); renderApp();
@ -283,14 +299,24 @@ async function createAgent(initialState?: AgentState) {
}); });
} }
} }
} break;
case "message_start": {
const msg = event.message;
if (!hasMessages && msg.role === "assistant") {
hasMessages = true;
renderApp();
} }
// Auto-learn from user messages // Auto-learn from user messages
if (msg.role === "user" && typeof msg.content === "string") { if (msg.role === "user" && typeof msg.content === "string") {
processMessageForMemory("user", msg.content); processMessageForMemory("user", msg.content);
} }
// Update mood based on content break;
const mood = document.querySelector("jae-mood-indicator") as JaeMoodIndicator; }
case "message_end": {
const msg = event.message;
// Update mood based on assistant content
if (mood && msg.role === "assistant" && typeof msg.content === "string") { if (mood && msg.role === "assistant" && typeof msg.content === "string") {
const text = msg.content.toLowerCase(); const text = msg.content.toLowerCase();
if (text.includes("error") || text.includes("failed") || text.includes("cannot")) { if (text.includes("error") || text.includes("failed") || text.includes("cannot")) {
@ -303,26 +329,16 @@ async function createAgent(initialState?: AgentState) {
mood.setMood("focused"); mood.setMood("focused");
} }
} }
}); // Track cost from usage data on the message
const usage = (msg as any).usage;
agent.on("stateChange", (state: string) => { if (usage) {
const typing = document.querySelector("jae-typing-indicator") as JaeTypingIndicator;
if (typing) {
if (state === "thinking" || state === "running") {
typing.show("high");
} else if (state === "tool_calling") {
typing.show("medium");
} else {
typing.hide();
}
}
});
// Track cost
agent.on("usage", (usage: { inputTokens: number; outputTokens: number; totalTokens: number }) => {
const costEl = document.querySelector("jae-cost-tracker") as CostTracker; const costEl = document.querySelector("jae-cost-tracker") as CostTracker;
if (costEl && usage) { if (costEl) {
costEl.addUsage(usage.inputTokens || 0, usage.outputTokens || 0); costEl.addUsage(usage.input || 0, usage.output || 0);
}
}
break;
}
} }
}); });