From 68af555313e5a5d230e799165a30e6c39b1ad342 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E6=A9=98?= Date: Fri, 22 May 2026 13:06:14 +0000 Subject: [PATCH] fix: share ACP client across run/continue for session continuity MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The client is now created once in createHermesAgent() and shared by runHermes and continueHermes closures. This preserves conversation context during frontmatter retry loops — continue() sends a follow-up prompt on the same ACP session instead of starting a new one. Client is cleaned up via process.on('exit'). Ref #398 --- packages/workflow-agent-hermes/src/hermes.ts | 43 +++++++++++--------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/packages/workflow-agent-hermes/src/hermes.ts b/packages/workflow-agent-hermes/src/hermes.ts index 178d49f..3ce000d 100644 --- a/packages/workflow-agent-hermes/src/hermes.ts +++ b/packages/workflow-agent-hermes/src/hermes.ts @@ -45,38 +45,41 @@ export function buildHermesPrompt(ctx: AgentContext): string { return parts.join("\n"); } -async function runHermes(ctx: AgentContext): Promise { - const fullPrompt = buildHermesPrompt(ctx); +/** + * Agent CLI factory: parses argv, runs Hermes, extracts output, writes StepNode. + * + * A single ACP client is shared across run() and continue() calls so that + * frontmatter retry loops keep the same Hermes session context. The client + * is closed once the agent process exits (via process.on("exit")). + */ +export function createHermesAgent(): () => Promise { const client = new HermesAcpClient(); - try { + + // Ensure cleanup regardless of how the process exits. + process.on("exit", () => { + void client.close(); + }); + + async function runHermes(ctx: AgentContext): Promise { + const fullPrompt = buildHermesPrompt(ctx); await client.connect(process.cwd()); const { text, sessionId } = await client.prompt(fullPrompt); const detailHash = await storeHermesRawOutput(ctx.store, text); return { output: text, detailHash, sessionId }; - } finally { - await client.close(); } -} -async function continueHermes( - _sessionId: string, - message: string, - store: Store, -): Promise { - // ACP does not support resuming an external session; start a new session with the message as prompt - const client = new HermesAcpClient(); - try { - await client.connect(process.cwd()); + async function continueHermes( + _sessionId: string, + message: string, + store: Store, + ): Promise { + // Client is already connected from runHermes — same ACP session, + // so the agent sees the full conversation history (crucial for retries). const { text, sessionId } = await client.prompt(message); const detailHash = await storeHermesRawOutput(store, text); return { output: text, detailHash, sessionId }; - } finally { - await client.close(); } -} -/** Agent CLI factory: parses argv, runs Hermes, extracts output, writes StepNode. */ -export function createHermesAgent(): () => Promise { return createAgent({ name: "hermes", run: runHermes,