Compare commits

...

1 Commits

Author SHA1 Message Date
Dax 642d6c52c4 fix(opencode): order replay rows by creation time 2026-08-07 03:57:15 +00:00
4 changed files with 44 additions and 13 deletions
+1 -1
View File
@@ -365,7 +365,7 @@ async function runInteractiveRuntime(input: RunRuntimeInput, deps: RunRuntimeDep
}) })
const footer = shell.footer const footer = shell.footer
const rememberLocal = (commit: StreamCommit, after?: LocalReplayAnchor) => { const rememberLocal = (commit: StreamCommit, after?: LocalReplayAnchor) => {
state.localRows = [...state.localRows, { commit, after }].slice(-LOCAL_REPLAY_ROW_LIMIT) state.localRows = [...state.localRows, { commit, after, created: Date.now() }].slice(-LOCAL_REPLAY_ROW_LIMIT)
} }
const loadCatalog = async (): Promise<void> => { const loadCatalog = async (): Promise<void> => {
@@ -266,7 +266,7 @@ export function replayLocalRows(
rows: LocalReplayRow[], rows: LocalReplayRow[],
): StreamCommit[] { ): StreamCommit[] {
const persisted = new Set(messages.map((message) => message.info.id)) const persisted = new Set(messages.map((message) => message.info.id))
return rows.reduce((out, local) => { return rows.reduce((out, local, index) => {
const row = local.commit const row = local.commit
if (row.kind === "user" && row.messageID && persisted.has(row.messageID)) { if (row.kind === "user" && row.messageID && persisted.has(row.messageID)) {
return out return out
@@ -317,12 +317,35 @@ export function replayLocalRows(
return [...out.slice(0, after + 1), row, ...out.slice(after + 1)] return [...out.slice(0, after + 1), row, ...out.slice(after + 1)]
} }
const before = out.findIndex((commit) => commit.messageID && row.messageID! < commit.messageID) const nextAnchor = rows
if (before === -1) { .slice(index + 1)
return [...out, row] .find((next) => next.commit.messageID === row.messageID && next.after)?.after
if (nextAnchor) {
const before = out.findIndex((commit) =>
nextAnchor.partID
? commit.partID === nextAnchor.partID
: commit.kind === nextAnchor.kind && commit.messageID === nextAnchor.messageID,
)
if (before !== -1) return [...out.slice(0, before), row, ...out.slice(before)]
} }
return [...out.slice(0, before), row, ...out.slice(before)] if (local.created !== undefined) {
const created = local.created
const messageID = row.messageID
const later = new Set(
messages
.filter(
(message) =>
message.info.time.created > created ||
(message.info.time.created === created && message.info.id.localeCompare(messageID) > 0),
)
.map((message) => message.info.id),
)
const before = out.findIndex((commit) => commit.messageID && later.has(commit.messageID))
if (before !== -1) return [...out.slice(0, before), row, ...out.slice(before)]
}
return [...out, row]
}, commits) }, commits)
} }
@@ -332,6 +332,7 @@ export type LocalReplayAnchor = {
export type LocalReplayRow = { export type LocalReplayRow = {
commit: StreamCommit commit: StreamCommit
after?: LocalReplayAnchor after?: LocalReplayAnchor
created?: number
} }
// The public contract between the stream transport / prompt queue and // The public contract between the stream transport / prompt queue and
@@ -416,7 +416,14 @@ describe("run session replay", () => {
} as const } as const
expect( expect(
replayLocalRows([userMessage("msg-user-2", "successful")], [persisted], [{ commit: failed }, { commit: error }]), replayLocalRows(
[userMessage("msg-user-2", "successful")],
[persisted],
[
{ commit: failed, created: 0 },
{ commit: error, created: 0 },
],
),
).toEqual([failed, error, persisted]) ).toEqual([failed, error, persisted])
}) })
@@ -657,35 +664,35 @@ describe("run session replay", () => {
).toEqual([prompt, running, error, completed]) ).toEqual([prompt, running, error, completed])
}) })
test("retains an unpersisted local diagnostic before later persisted prompts", () => { test("appends an unanchored local diagnostic without inferring chronology from message IDs", () => {
const first = { const first = {
kind: "user", kind: "user",
text: "before", text: "before",
phase: "start", phase: "start",
source: "system", source: "system",
messageID: "msg-user-1", messageID: "msg-user-z",
} as const } as const
const error = { const error = {
kind: "error", kind: "error",
text: "failed to start new session", text: "failed to start new session",
phase: "start", phase: "start",
source: "system", source: "system",
messageID: "msg-user-2", messageID: "msg-user-m",
} as const } as const
const second = { const second = {
kind: "user", kind: "user",
text: "after", text: "after",
phase: "start", phase: "start",
source: "system", source: "system",
messageID: "msg-user-3", messageID: "msg-user-a",
} as const } as const
expect( expect(
replayLocalRows( replayLocalRows(
[userMessage("msg-user-1", "before"), userMessage("msg-user-3", "after")], [userMessage("msg-user-z", "before"), userMessage("msg-user-a", "after")],
[first, second], [first, second],
[{ commit: error }], [{ commit: error }],
), ),
).toEqual([first, error, second]) ).toEqual([first, second, error])
}) })
}) })