Ver Fonte

core: prevent duplicate user messages in ACP clients (#22468)

Aiden Cline há 3 dias atrás
pai
commit
b1312a3181

+ 6 - 0
packages/opencode/src/acp/agent.ts

@@ -453,6 +453,12 @@ export namespace ACP {
                 return
             }
           }
+          
+          // ACP clients already know the prompt they just submitted, so replaying
+          // live user parts duplicates the message. We still replay user history in
+          // loadSession() and forkSession() via processMessage().
+          if (part.type !== "text" && part.type !== "file") return
+
           return
         }
 

+ 40 - 0
packages/opencode/test/acp/event-subscription.test.ts

@@ -295,6 +295,46 @@ describe("acp.agent event subscription", () => {
     })
   })
 
+  test("does not emit user_message_chunk for live prompt parts", async () => {
+    await using tmp = await tmpdir()
+    await Instance.provide({
+      directory: tmp.path,
+      fn: async () => {
+        const { agent, controller, sessionUpdates, stop } = createFakeAgent()
+        const cwd = "/tmp/opencode-acp-test"
+        const sessionId = await agent.newSession({ cwd, mcpServers: [] } as any).then((x) => x.sessionId)
+
+        controller.push({
+          directory: cwd,
+          payload: {
+            type: "message.part.updated",
+            properties: {
+              sessionID: sessionId,
+              time: Date.now(),
+              part: {
+                id: "part_1",
+                sessionID: sessionId,
+                messageID: "msg_user",
+                type: "text",
+                text: "hello",
+              },
+            },
+          },
+        } as any)
+
+        await new Promise((r) => setTimeout(r, 20))
+
+        expect(
+          sessionUpdates
+            .filter((u) => u.sessionId === sessionId)
+            .some((u) => u.update.sessionUpdate === "user_message_chunk"),
+        ).toBe(false)
+
+        stop()
+      },
+    })
+  })
+
   test("keeps concurrent sessions isolated when message.part.delta events are interleaved", async () => {
     await using tmp = await tmpdir()
     await Instance.provide({