From aa346a0e4fd31e4f751c7339b24267c4a2a2215a Mon Sep 17 00:00:00 2001 From: lunaqiu Date: Wed, 2 Sep 2026 13:11:27 +0800 Subject: [PATCH] fix(acp-driver): send the user's task before the host preamble External ACP agents receive Huabu's one-shot system preamble and the user's first prompt concatenated into a single session/prompt message (ACP has no separate system-role channel). The preamble was sent first, so every externally-bound Huabu session started with the exact same static boilerplate text. Several external agents (Copilot CLI observed) title a session from the leading characters of that first message, so every session showed an identical, uninformative title in the agent's own session list (e.g. its VS Code picker) regardless of what the user actually asked. Swap the order so the user's task leads and the preamble trails. The agent still reads the whole message before responding either way, but title heuristics now key off unique, per-session content. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../agenetes/packages/acp-driver/src/handle.ts | 15 +++++++++++++-- .../packages/acp-driver/src/recovery.test.ts | 2 +- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/external/agenetes/packages/acp-driver/src/handle.ts b/external/agenetes/packages/acp-driver/src/handle.ts index 9f1f1903d..aefbcd8b3 100644 --- a/external/agenetes/packages/acp-driver/src/handle.ts +++ b/external/agenetes/packages/acp-driver/src/handle.ts @@ -485,12 +485,23 @@ export class AcpAgentHandle< preamble.length > 0 && !entry.initialPreambleDelivered && !lowered.isCommand; + // The user's actual request leads, the host preamble trails. ACP has + // no separate system-role channel, so this one-shot preamble is just + // more text in the same first `session/prompt` message — but several + // external agents (Copilot CLI observed so far) title a session from + // the leading characters of that first message. The identical static + // preamble always starting the message meant every externally-bound + // Huabu session showed the same uninformative title in the agent's + // own session list (e.g. its VS Code picker), no matter what the user + // actually asked. Putting the per-session task first gives those + // heuristics something meaningful and unique to key off, while the + // agent still reads the full preamble before responding either way. const rendered: LoweredAcpPrompt = { serialized: includedPreamble - ? `${preamble}\n\n${lowered.serialized}` + ? `${lowered.serialized}\n\n${preamble}` : lowered.serialized, blocks: includedPreamble - ? [{ type: 'text', text: preamble }, ...lowered.blocks] + ? [...lowered.blocks, { type: 'text', text: preamble }] : lowered.blocks, includedPreamble, }; diff --git a/external/agenetes/packages/acp-driver/src/recovery.test.ts b/external/agenetes/packages/acp-driver/src/recovery.test.ts index f76c87132..3d522a44e 100644 --- a/external/agenetes/packages/acp-driver/src/recovery.test.ts +++ b/external/agenetes/packages/acp-driver/src/recovery.test.ts @@ -424,8 +424,8 @@ describe('ACP durable history recovery', () => { } expect(prompt.mock.calls[1]?.[1]).toEqual([ - { type: 'text', text: 'SYSTEM' }, { type: 'text', text: 'hello' }, + { type: 'text', text: 'SYSTEM' }, ]); expect(entry.initialPreambleDelivered).toBe(true); expect(sessionMocks.reportEntryState).toHaveBeenCalledTimes(4);