fix: settle busy sessions after managed OpenCode restart (#3002)
* fix: reconcile busy sessions after managed OpenCode restart Forced health-check restarts previously rebound the event stream without settling in-flight turns, so sessions stayed busy with no terminal state. Interrupt those sessions, classify health failures, and retain bounded process diagnostics for post-restart diagnosis. Fixes #2943 Co-authored-by: serkraser <serkraser@gmail.com> * fix: surface interrupted chats after OpenCode restart Complete unfinished assistant turns as aborted once the session is authoritatively idle, and show a persistent toast so users can continue instead of remaining silently stranded. Fixes #2943 Co-authored-by: serkraser <serkraser@gmail.com> * fix: redact Basic auth credentials in restart diagnostics The key/value sanitizer stopped at whitespace, so Authorization: Basic credentials survived in stderr tails and health snapshots. Redact the scheme token before that rule runs. Co-authored-by: serkraser <serkraser@gmail.com>
This commit is contained in:
@@ -119,6 +119,31 @@ describe("materializeSessionSnapshots", () => {
|
||||
expect(result.part.msg_1[0]).toBe(livePart)
|
||||
})
|
||||
|
||||
test("preserves a locally aborted assistant message when a stale unfinished snapshot arrives", () => {
|
||||
const unfinishedMessage = message("msg_1")
|
||||
if (unfinishedMessage.role !== "assistant") throw new Error("Expected assistant fixture")
|
||||
const abortedMessage: Message = {
|
||||
...unfinishedMessage,
|
||||
time: { created: 1, completed: 5000 },
|
||||
error: { name: "MessageAbortedError", data: { message: "aborted" } },
|
||||
}
|
||||
const staleMessage = message("msg_1")
|
||||
const state = {
|
||||
message: { ses_1: [abortedMessage] },
|
||||
part: { msg_1: [] },
|
||||
}
|
||||
|
||||
const result = materializeSessionSnapshots(
|
||||
state,
|
||||
"ses_1",
|
||||
[{ info: staleMessage, parts: [] }],
|
||||
)
|
||||
|
||||
expect(result.message).toBe(state.message)
|
||||
expect(result.message.ses_1[0]).toBe(abortedMessage)
|
||||
expect(result.message.ses_1[0]).not.toBe(staleMessage)
|
||||
})
|
||||
|
||||
test("does not preserve omitted optimistic user text parts beside server snapshot parts", () => {
|
||||
const optimisticPart = { id: "prt_optimistic", messageID: "msg_1", type: "text", text: "Hello" } as Part
|
||||
const serverPart = part("prt_server", "msg_1", "text", "Hello")
|
||||
|
||||
Reference in New Issue
Block a user