feat(electrobun): agent execution layer — sidecar manager + message adapters + store
- SidecarManager: spawns claude/codex/ollama runners via Bun.spawn(), NDJSON stdio protocol, Claude CLI auto-detection, env stripping, AbortController stop, Deno/Node runtime detection - MessageAdapter: parses Claude stream-json, Codex ThreadEvent, Ollama chunks into common AgentMessage format - agent-store.svelte.ts: per-project reactive session state, RPC event listeners for agent.message/status/cost - AgentPane: wired to real sessions (start/stop/prompt), stop button, thinking/system message rendering - ProjectCard: status dot from real agent status, cost/tokens from store - 5 new RPC types (agent.start/stop/prompt/list + events)
This commit is contained in:
parent
95f1f8208f
commit
ef0183de7f
8 changed files with 1566 additions and 61 deletions
|
|
@ -2,6 +2,7 @@ import path from "path";
|
|||
import { BrowserWindow, BrowserView, Updater } from "electrobun/bun";
|
||||
import { PtyClient } from "./pty-client.ts";
|
||||
import { settingsDb } from "./settings-db.ts";
|
||||
import { SidecarManager } from "./sidecar-manager.ts";
|
||||
import type { PtyRPCSchema } from "../shared/pty-rpc-schema.ts";
|
||||
import { randomUUID } from "crypto";
|
||||
|
||||
|
|
@ -11,6 +12,7 @@ const DEV_SERVER_URL = `http://localhost:${DEV_SERVER_PORT}`;
|
|||
// ── PTY daemon client ────────────────────────────────────────────────────────
|
||||
|
||||
const ptyClient = new PtyClient();
|
||||
const sidecarManager = new SidecarManager();
|
||||
|
||||
async function connectToDaemon(retries = 5, delayMs = 500): Promise<boolean> {
|
||||
for (let attempt = 1; attempt <= retries; attempt++) {
|
||||
|
|
@ -347,6 +349,90 @@ const rpc = BrowserView.defineRPC<PtyRPCSchema>({
|
|||
return { ok: false };
|
||||
}
|
||||
},
|
||||
|
||||
// ── Agent handlers ──────────────────────────────────────────────────
|
||||
|
||||
"agent.start": ({ sessionId, provider, prompt, cwd, model, systemPrompt, maxTurns, permissionMode, claudeConfigDir, extraEnv }) => {
|
||||
try {
|
||||
const result = sidecarManager.startSession(sessionId, provider, prompt, {
|
||||
cwd,
|
||||
model,
|
||||
systemPrompt,
|
||||
maxTurns,
|
||||
permissionMode,
|
||||
claudeConfigDir,
|
||||
extraEnv,
|
||||
});
|
||||
|
||||
if (result.ok) {
|
||||
// Forward sidecar messages to webview
|
||||
sidecarManager.onMessage(sessionId, (sid, messages) => {
|
||||
try {
|
||||
rpc.send["agent.message"]({ sessionId: sid, messages });
|
||||
} catch (err) {
|
||||
console.error("[agent.message] forward error:", err);
|
||||
}
|
||||
});
|
||||
|
||||
sidecarManager.onStatus(sessionId, (sid, status, error) => {
|
||||
try {
|
||||
rpc.send["agent.status"]({ sessionId: sid, status, error });
|
||||
} catch (err) {
|
||||
console.error("[agent.status] forward error:", err);
|
||||
}
|
||||
|
||||
// Send cost update on status change
|
||||
const sessions = sidecarManager.listSessions();
|
||||
const session = sessions.find((s) => s.sessionId === sid);
|
||||
if (session) {
|
||||
try {
|
||||
rpc.send["agent.cost"]({
|
||||
sessionId: sid,
|
||||
costUsd: session.costUsd,
|
||||
inputTokens: session.inputTokens,
|
||||
outputTokens: session.outputTokens,
|
||||
});
|
||||
} catch { /* ignore */ }
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return result;
|
||||
} catch (err) {
|
||||
const error = err instanceof Error ? err.message : String(err);
|
||||
console.error("[agent.start]", err);
|
||||
return { ok: false, error };
|
||||
}
|
||||
},
|
||||
|
||||
"agent.stop": ({ sessionId }) => {
|
||||
try {
|
||||
return sidecarManager.stopSession(sessionId);
|
||||
} catch (err) {
|
||||
const error = err instanceof Error ? err.message : String(err);
|
||||
console.error("[agent.stop]", err);
|
||||
return { ok: false, error };
|
||||
}
|
||||
},
|
||||
|
||||
"agent.prompt": ({ sessionId, prompt }) => {
|
||||
try {
|
||||
return sidecarManager.writePrompt(sessionId, prompt);
|
||||
} catch (err) {
|
||||
const error = err instanceof Error ? err.message : String(err);
|
||||
console.error("[agent.prompt]", err);
|
||||
return { ok: false, error };
|
||||
}
|
||||
},
|
||||
|
||||
"agent.list": () => {
|
||||
try {
|
||||
return { sessions: sidecarManager.listSessions() };
|
||||
} catch (err) {
|
||||
console.error("[agent.list]", err);
|
||||
return { sessions: [] };
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
messages: {},
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue