diff --git a/src/index.ts b/src/index.ts index e1c4ff3..a4552ba 100644 --- a/src/index.ts +++ b/src/index.ts @@ -5,6 +5,7 @@ import { createTelegramBot } from "./telegram-bot.js"; import { startA2AServer } from "./a2a-server.js"; import { getDb, getIncompleteTasks, updateTaskStatus } from "./task-journal.js"; import { writeMemoryEvent } from "./memory.js"; +import { emitSessionArtifact } from "./session-emit.js"; import { log } from "./logger.js"; async function main() { @@ -54,6 +55,7 @@ async function main() { const shutdown = async (signal: string) => { log("info", `Received ${signal}, shutting down...`); await writeMemoryEvent(`Max agent shutting down (${signal})`); + emitSessionArtifact({ topic: `Max agent shutdown (${signal})`, type: "maintenance" }); bot.stop(); process.exit(0); }; diff --git a/src/session-emit.ts b/src/session-emit.ts new file mode 100644 index 0000000..1346319 --- /dev/null +++ b/src/session-emit.ts @@ -0,0 +1,40 @@ +import { execSync } from "child_process"; +import { log } from "./logger.js"; + +interface EmitOptions { + topic: string; + projects?: string[]; + type?: "coding" | "conversation" | "research" | "maintenance"; + decisions?: string; + next?: string; + issues?: string[]; +} + +export function emitSessionArtifact(opts: EmitOptions): void { + const script = `${process.env.HOME}/max/agent-shared/scripts/max-session-emit.sh`; + const env = { + ...process.env, + SESSION_TOPIC: opts.topic, + SESSION_PROJECTS: (opts.projects ?? []).join(","), + SESSION_TYPE: opts.type ?? "maintenance", + SESSION_DECISIONS: opts.decisions ?? "None.", + SESSION_NEXT: opts.next ?? "None.", + SESSION_ISSUES: (opts.issues ?? []).join(","), + }; + try { + execSync(`bash ${script}`, { env, timeout: 30_000, stdio: "pipe" }); + log("info", `Session artifact emitted: ${opts.topic}`); + } catch (e: any) { + log("warn", `Session emit failed: ${e.message}`); + } +} + +export function inferProjectsFromText(text: string): string[] { + const known = [ + "launchpad", "nixclaw", "recall", "vault", "cortex", "mux", + "agent-shared", "agent-max", "agentweave", "portfolio", "foundry", + "linkedin-autopilot", "doordash", "nix-vision", "flight-tracker", + ]; + const lower = text.toLowerCase(); + return known.filter((p) => lower.includes(p)); +} diff --git a/src/worker.ts b/src/worker.ts index 87bf4a9..a5d8675 100644 --- a/src/worker.ts +++ b/src/worker.ts @@ -5,6 +5,7 @@ import { createAgent } from "./agent.js"; import { setAgentWeaveSession, resetAgentWeaveSession } from "./agentweave-context.js"; import { log } from "./logger.js"; import { saveSession } from "./session.js"; +import { emitSessionArtifact, inferProjectsFromText } from "./session-emit.js"; const AGENTWEAVE_MAX_PROXY = process.env.AGENTWEAVE_PROXY_URL || "http://arnabsnas.local:30400"; @@ -98,14 +99,29 @@ async function main() { const lastMsg: any = agent.state.messages[agent.state.messages.length - 1]; if (lastMsg?.role === "assistant" && lastMsg.stopReason === "error" && lastMsg.errorMessage) { saveSession(agent); + emitSessionArtifact({ + topic: taskLabel || text.slice(0, 80), + projects: inferProjectsFromText(text), + type: "maintenance", + }); await postProgress({ type: "error", taskId, error: `LLM error: ${lastMsg.errorMessage}` }); return; } } saveSession(agent); + emitSessionArtifact({ + topic: taskLabel || text.slice(0, 80), + projects: inferProjectsFromText(text), + type: "coding", + }); await postProgress({ type: "complete", taskId, message: "Worker completed", result: responseText }); } catch (e: any) { + emitSessionArtifact({ + topic: taskLabel || text.slice(0, 80), + projects: inferProjectsFromText(text), + type: "maintenance", + }); await postProgress({ type: "error", taskId, error: e?.message || String(e) }); } finally { if (parentSessionId) {