mirror of
https://github.com/anomalyco/opencode.git
synced 2026-08-15 17:08:21 -04:00
fix: make revert boundaries chronological
This commit is contained in:
@@ -480,23 +480,23 @@ describe("server session", () => {
|
||||
|
||||
test("projects committed revert before server reconciliation", () => {
|
||||
const ctx = setup({ child: session("child") })
|
||||
ctx.store.remember({ ...session("child"), revert: { messageID: "msg_2", partID: "prt_1" } })
|
||||
ctx.store.set("input", "child", ["msg_1", "msg_2"])
|
||||
ctx.store.remember({ ...session("child"), revert: { messageID: "msg_000", partID: "prt_1" } })
|
||||
ctx.store.set("input", "child", ["msg_fff", "msg_000"])
|
||||
ctx.store.set("session_message", "child", [
|
||||
{ id: "msg_1", type: "user", text: "keep", time: { created: 1 } },
|
||||
{ id: "msg_2", type: "user", text: "remove", time: { created: 2 } },
|
||||
{ id: "msg_fff", type: "user", text: "keep", time: { created: 1 } },
|
||||
{ id: "msg_000", type: "user", text: "remove", time: { created: 2 } },
|
||||
])
|
||||
|
||||
ctx.store.applyV2({
|
||||
id: "evt_revert",
|
||||
created: 3,
|
||||
type: "session.revert.committed",
|
||||
data: { sessionID: "child", to: "msg_2" },
|
||||
data: { sessionID: "child", to: "msg_000" },
|
||||
} as OpenCodeEvent)
|
||||
|
||||
expect(ctx.store.data.info.child?.revert).toBeUndefined()
|
||||
expect(ctx.store.data.input.child).toEqual(["msg_1"])
|
||||
expect(ctx.store.data.session_message.child?.map((message) => message.id)).toEqual(["msg_1"])
|
||||
expect(ctx.store.data.input.child).toEqual(["msg_fff"])
|
||||
expect(ctx.store.data.session_message.child?.map((message) => message.id)).toEqual(["msg_fff"])
|
||||
})
|
||||
|
||||
test("does not restore a message hydrated before a committed revert", async () => {
|
||||
|
||||
@@ -1041,13 +1041,17 @@ export function createServerSession(
|
||||
if (event.type === "session.revert.committed") {
|
||||
messageHydrationRevision.set(sessionID, (messageHydrationRevision.get(sessionID) ?? 0) + 1)
|
||||
if (info) remember({ ...info, revert: undefined })
|
||||
setData("input", sessionID, (items) => items?.filter((id) => id < event.data.to))
|
||||
setData("input", sessionID, (items) => {
|
||||
const boundary = items?.findIndex((id) => id === event.data.to) ?? -1
|
||||
return boundary < 0 ? items : items?.slice(0, boundary)
|
||||
})
|
||||
const source = data.session_message[sessionID] ?? []
|
||||
const removed = source.filter((message) => message.id >= event.data.to).map((message) => message.id)
|
||||
const boundary = source.findIndex((message) => message.id === event.data.to)
|
||||
const removed = boundary < 0 ? [] : source.slice(boundary).map((message) => message.id)
|
||||
removedMessages.set(sessionID, new Set([...(removedMessages.get(sessionID) ?? []), ...removed]))
|
||||
projectV2({
|
||||
sessionID,
|
||||
messages: source.filter((message) => message.id < event.data.to),
|
||||
messages: boundary < 0 ? source : source.slice(0, boundary),
|
||||
touched: [],
|
||||
removed,
|
||||
})
|
||||
|
||||
@@ -833,10 +833,13 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({
|
||||
"session",
|
||||
"input",
|
||||
event.data.sessionID,
|
||||
(store.session.input[event.data.sessionID] ?? []).filter((id) => id < event.data.to),
|
||||
(items) => {
|
||||
const boundary = items?.findIndex((id) => id === event.data.to) ?? -1
|
||||
return boundary < 0 ? items : items?.slice(0, boundary)
|
||||
},
|
||||
)
|
||||
message.update(event.data.sessionID, (draft, index) => {
|
||||
const position = draft.findIndex((item) => item.id >= event.data.to)
|
||||
const position = draft.findIndex((item) => item.id === event.data.to)
|
||||
if (position === -1) return
|
||||
for (const item of draft.splice(position)) index.delete(item.id)
|
||||
})
|
||||
|
||||
@@ -52,8 +52,9 @@ export function createSessionRows(sessionID: Accessor<string>) {
|
||||
)
|
||||
const visible = queued.size === 0 ? messages : messages.filter((message) => !queued.has(message.id))
|
||||
const boundary = revertBoundary()
|
||||
const boundaryIndex = boundary ? visible.findIndex((message) => message.id === boundary) : -1
|
||||
const rows = reduceSessionRows(
|
||||
boundary ? visible.filter((message) => message.id < boundary) : visible,
|
||||
boundaryIndex < 0 ? visible : visible.slice(0, boundaryIndex),
|
||||
inputs,
|
||||
turnTokens(),
|
||||
)
|
||||
|
||||
@@ -1105,7 +1105,7 @@ test("removes committed revert messages from local state", async () => {
|
||||
))
|
||||
|
||||
try {
|
||||
for (const [seq, inboxID] of ["msg_001", "msg_002", "msg_003"].entries()) {
|
||||
for (const [seq, inboxID] of ["msg_fff", "msg_000", "msg_001"].entries()) {
|
||||
emitEvent(events, {
|
||||
id: Event.ID.create(),
|
||||
created: seq,
|
||||
@@ -1121,13 +1121,13 @@ test("removes committed revert messages from local state", async () => {
|
||||
created: 3,
|
||||
type: "session.revert.committed",
|
||||
durable: durable(sessionID, 3),
|
||||
data: { sessionID, to: "msg_002" },
|
||||
data: { sessionID, to: "msg_000" },
|
||||
})
|
||||
|
||||
await wait(() => data.session.message.list(sessionID).length === 1)
|
||||
expect(data.session.message.list(sessionID).map((message) => message.id)).toEqual(["msg_001"])
|
||||
expect(data.session.message.get(sessionID, "msg_002")).toBeUndefined()
|
||||
expect(data.session.message.get(sessionID, "msg_003")).toBeUndefined()
|
||||
expect(data.session.message.list(sessionID).map((message) => message.id)).toEqual(["msg_fff"])
|
||||
expect(data.session.message.get(sessionID, "msg_000")).toBeUndefined()
|
||||
expect(data.session.message.get(sessionID, "msg_001")).toBeUndefined()
|
||||
} finally {
|
||||
app.renderer.destroy()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user