Add pi web POC

This commit is contained in:
Federico Jaramillo Martinez
2026-05-07 11:12:23 +02:00
parent c9d82667df
commit adf9087e84
17 changed files with 6618 additions and 0 deletions
+116
View File
@@ -0,0 +1,116 @@
import {
AuthStorage,
createAgentSession,
ModelRegistry,
SessionManager,
type AgentSession,
} from "@mariozechner/pi-coding-agent";
import type { ClientSession } from "../types.js";
import type { SessionEventHub } from "../realtime/sessionEventHub.js";
interface ActiveSession {
session: AgentSession;
unsubscribe: () => void;
}
export class PiSessionService {
private readonly active = new Map<string, ActiveSession>();
private readonly authStorage = AuthStorage.create();
private readonly modelRegistry = ModelRegistry.create(this.authStorage);
constructor(private readonly events: SessionEventHub) {}
async list(cwd: string): Promise<ClientSession[]> {
const sessions = await SessionManager.list(cwd);
return sessions.map((s) => ({
id: s.id,
path: s.path,
cwd: s.cwd,
name: s.name,
created: s.created.toISOString(),
modified: s.modified.toISOString(),
messageCount: s.messageCount,
firstMessage: s.firstMessage,
}));
}
async start(cwd: string): Promise<ClientSession> {
const { session } = await this.create(SessionManager.create(cwd), cwd);
return {
id: session.sessionId,
path: session.sessionFile ?? "",
cwd,
created: new Date().toISOString(),
modified: new Date().toISOString(),
messageCount: session.messages.length,
firstMessage: "",
};
}
async messages(sessionId: string): Promise<unknown[]> {
const session = await this.getOrOpen(sessionId);
return session.messages;
}
async prompt(sessionId: string, text: string): Promise<void> {
const session = await this.getOrOpen(sessionId);
void session.prompt(text).catch((error) => {
this.events.publish(sessionId, { type: "session.error", message: error instanceof Error ? error.message : String(error) });
});
}
async abort(sessionId: string): Promise<void> {
const active = this.active.get(sessionId);
if (active) await active.session.abort();
}
close(sessionId: string): void {
const active = this.active.get(sessionId);
if (!active) return;
active.unsubscribe();
active.session.dispose();
this.active.delete(sessionId);
}
private async getOrOpen(sessionId: string): Promise<AgentSession> {
const active = this.active.get(sessionId);
if (active) return active.session;
const match = (await SessionManager.listAll()).find((s) => s.id === sessionId || s.id.startsWith(sessionId));
if (!match) throw new Error("Session not found");
return (await this.create(SessionManager.open(match.path), match.cwd)).session;
}
private async create(sessionManager: SessionManager, cwd: string): Promise<ActiveSession> {
const { session } = await createAgentSession({
cwd,
sessionManager,
authStorage: this.authStorage,
modelRegistry: this.modelRegistry,
});
const unsubscribe = session.subscribe((event) => {
this.events.publish(session.sessionId, toClientEvent(event));
});
const active = { session, unsubscribe };
this.active.set(session.sessionId, active);
return active;
}
}
function toClientEvent(event: any): unknown {
if (event.type === "message_update" && event.assistantMessageEvent?.type === "text_delta") {
return { type: "assistant.delta", text: event.assistantMessageEvent.delta };
}
if (event.type === "tool_execution_start") {
return { type: "tool.start", toolName: event.toolName, toolCallId: event.toolCallId };
}
if (event.type === "tool_execution_end") {
return { type: "tool.end", toolName: event.toolName, toolCallId: event.toolCallId, isError: event.isError };
}
if (event.type === "agent_start") return { type: "agent.start" };
if (event.type === "agent_end") return { type: "agent.end" };
if (event.type === "message_end") return { type: "message.end" };
return { type: "pi.event", eventType: event.type };
}