Skip to content

Commit 69cfc44

Browse files
fix(acp): replay loaded session transcript (anomalyco#30645)
Co-authored-by: opencode-agent[bot] <opencode-agent[bot]@users.noreply.github.com> Co-authored-by: Shoubhit Dash <shoubhit2005@gmail.com>
1 parent 30ec231 commit 69cfc44

2 files changed

Lines changed: 65 additions & 0 deletions

File tree

packages/opencode/src/acp/event.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import type {
1212
import { Effect } from "effect"
1313
import { ACPSession } from "./session"
1414
import { ACPPermission } from "./permission"
15+
import { partsToContentChunks, type ReplayPart } from "./content"
1516
import {
1617
duplicateRunningToolUpdate,
1718
errorToolUpdate,
@@ -87,7 +88,31 @@ export class Subscription {
8788
await this.recordFetchedPart(message.info.sessionID, message, part)
8889
if (part.type === "tool") {
8990
await this.handleToolPart(message.info.sessionID, part)
91+
continue
9092
}
93+
await this.replayContentPart(message, part)
94+
}
95+
}
96+
97+
private async replayContentPart(message: SessionMessageResponse, part: Part) {
98+
if (part.type !== "text" && part.type !== "file" && part.type !== "reasoning") return
99+
100+
const sessionUpdate =
101+
part.type === "reasoning"
102+
? "agent_thought_chunk"
103+
: message.info.role === "user"
104+
? "user_message_chunk"
105+
: "agent_message_chunk"
106+
107+
for (const chunk of partsToContentChunks([part as ReplayPart])) {
108+
await this.input.connection.sessionUpdate({
109+
sessionId: message.info.sessionID,
110+
update: {
111+
sessionUpdate,
112+
messageId: message.info.id,
113+
...chunk,
114+
},
115+
})
91116
}
92117
}
93118

packages/opencode/test/acp/service-session.test.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,46 @@ describe("ACP service sessions", () => {
316316
expect(result.configOptions?.find((option) => option.id === "mode")?.currentValue).toBe("plan")
317317
})
318318

319+
it("replays loaded session transcript chunks", async () => {
320+
const { service, updates } = makeService([
321+
{
322+
info: { id: "msg_user", sessionID: "ses_loaded", role: "user" },
323+
parts: [{ id: "part_user", sessionID: "ses_loaded", messageID: "msg_user", type: "text", text: "hello" }],
324+
},
325+
{
326+
info: { id: "msg_assistant", sessionID: "ses_loaded", role: "assistant" },
327+
parts: [
328+
{
329+
id: "part_assistant",
330+
sessionID: "ses_loaded",
331+
messageID: "msg_assistant",
332+
type: "text",
333+
text: "hi there",
334+
},
335+
],
336+
},
337+
])
338+
339+
await Effect.runPromise(service.loadSession({ cwd: "/workspace", sessionId: "ses_loaded", mcpServers: [] }))
340+
341+
expect(
342+
updates
343+
.map((item) => item.update)
344+
.filter((item) => item.sessionUpdate === "user_message_chunk" || item.sessionUpdate === "agent_message_chunk"),
345+
).toEqual([
346+
{
347+
sessionUpdate: "user_message_chunk",
348+
messageId: "msg_user",
349+
content: { type: "text", text: "hello" },
350+
},
351+
{
352+
sessionUpdate: "agent_message_chunk",
353+
messageId: "msg_assistant",
354+
content: { type: "text", text: "hi there" },
355+
},
356+
])
357+
})
358+
319359
it("lists sessions sorted by updated time with cursor support", async () => {
320360
const { service } = makeService()
321361
const first = await Effect.runPromise(service.listSessions({ cwd: "/workspace" }))

0 commit comments

Comments
 (0)