From 22e486a69c0de71a82373f99b811241f88593280 Mon Sep 17 00:00:00 2001 From: Alejandro Maisonnat Date: Wed, 6 May 2026 02:02:53 -0300 Subject: [PATCH] feat(acp): extract system prompt from synthetic parts in session/prompt When Hermes Agent sends messages via ACP, it formats system messages as text parts with annotations.audience: ['assistant']. OpenCode already marks these as 'synthetic' but concatenated them with user messages into a single prompt. This change: 1. Extracts 'synthetic' text parts from the parts array 2. Concatenates them into a 'system' string 3. Passes the 'system' parameter to session.prompt() SDK call 4. Filters synthetic parts from regularParts so the agent sees proper separation between system context and user messages This makes OpenCode ACP compatible with Claude Code's ACP message format used by tools like Hermes Agent. --- packages/opencode/src/acp/agent.ts | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/packages/opencode/src/acp/agent.ts b/packages/opencode/src/acp/agent.ts index d66c1b258325..32ed783ce884 100644 --- a/packages/opencode/src/acp/agent.ts +++ b/packages/opencode/src/acp/agent.ts @@ -1441,8 +1441,18 @@ export class Agent implements ACPAgent { log.info("parts", { parts }) + // Extract system prompt from synthetic parts (marked with audience: ["assistant"]) + let system: string | undefined + const regularParts = parts.filter((p) => { + if (p.type === "text" && p.synthetic) { + system = (system || "") + p.text + "\n" + return false + } + return true + }) + const cmd = (() => { - const text = parts + const text = regularParts .filter((p): p is { type: "text"; text: string } => p.type === "text") .map((p) => p.text) .join("") @@ -1476,7 +1486,8 @@ export class Agent implements ACPAgent { modelID: model.modelID, }, variant: this.sessionManager.getVariant(sessionID), - parts, + parts: regularParts, + system, agent, directory, })