Repository navigation
feat(threads): show where a thread continued after a server restart - #515
Merged
Merged
Conversation
incognitojam
force-pushed
the
styal/verify-thread-resumed-after-restart
branch
from
September 28, 2026 17:05
4ea0a31 to
d5fcb84
Compare
incognitojam
marked this pull request as ready for review
September 28, 2026 17:06
Web previewThe preview was removed because this PR closed or the preview label was removed. |
incognitojam
force-pushed
the
styal/verify-thread-resumed-after-restart
branch
from
September 28, 2026 20:09
eb00484 to
52f438a
Compare
When the server continues a thread's work after a restart, it now records a server-restart.continued activity once the continuation is sent. Web and mobile show it as a note in the turn's work, kept out of grouped work rows so a folded turn does not hide it.
The note used the interrupted turn, or no turn for background work, but a prompted continuation starts a new turn. Use the turn ID sendTurn returns so the note sits on the turn that carries the continued output. Relabel the background note to say the agent was asked to restart its background work, and move the grouping rule for standalone rows from contracts to client-runtime.
A prompted continuation after a server restart runs in a new provider turn, so one request showed as two "Worked for" groups, and the first ended on a progress update that read like a final answer. Both clients now treat a turn opened by a restart note, with no user message since the previous turn, as part of that turn: one fold, one duration, one final answer. Background-work continuations get their own activity kind and stay separate, since the earlier turn had already finished.
…ration A response folded across a server restart measured from the user's message to the final answer, so the time the server was down counted as work. It now subtracts the gap between the interrupted turn's last entry and the turn that continued it. Each standalone activity kind also names how clients draw it, so a new kind no longer falls through to the restart note's icon.
incognitojam
force-pushed
the
styal/verify-thread-resumed-after-restart
branch
from
September 29, 2026 10:40
d8bdc8a to
1b98667
Compare
incognitojam
temporarily deployed
to
web-preview
September 29, 2026 11:06 — with
GitHub Actions
Inactive
incognitojam
pushed a commit
that referenced
this pull request
Oct 3, 2026
…otgg#12147) (cherry picked from commit 22539f2) Fork adaptation: Thought and tool activity groups on web and mobile exclude every standalone row the fork defines (context compaction and server-restart notes), not only compaction, so a restart note keeps its own row; mobile uses the fork's standalone-row check in place of the compaction check that fork #515 replaced. The fork's fold summary types stay beside upstream's activity group types. Upstream-PR: 12147 Fork-Feature: server-restart-continuation-note, inspectable-tool-activity
This branch was previously deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Note
Threads that the server continues after a restart now show Continued after server restart at the point the agent picked up again, and the work before and after the restart folds into one response. It's a new activity kind, so no migration is needed.
When the server restarts with a thread mid-turn, it resumes the provider session and sends a continuation prompt ("Continue where you left off.", or the background-work prompt). That prompt isn't a thread message, so the conversation showed no sign of the restart. The transcript jumped from the last output before the restart to the agent's next message, and anything the restart stopped (background shells, monitors, subagents) had no visible cause. A prompted continuation also runs in a new provider turn, so one request showed as two "Worked for" groups, and the first ended on a progress update that read like a final answer.
What changed
reconcileProviderSessionsrecords aserver-restart.continuedactivity once the continuation has been sent. The row is attached to the turn thatsendTurnreturns, which is the turn that carries the continued work. Its timestamp is taken just before sending, so it sorts ahead of the agent's first output. If sending fails, no row is recorded and the thread shows the existing error instead.server-restart.background-continuedkind.isStandaloneTimelineActivityKind, the grouping rule web and mobile share, which covers context compaction and the restart rows,deriveContinuedTurnRoots, which both clients use to find the turn a continuation belongs to, andrestartDowntimeMs, which both use to leave the restart gap out of the response's duration. Each standalone kind names how clients draw it, so a new kind has to choose between the divider and the restart note.server-restart.continuednote, with no user message since the previous turn, folds together with that turn: one "Worked for" row covering both, and only the final answer left visible. That duration runs from the user's message to the final answer, less the time between the interrupted turn's last entry and the restart note, so a long outage doesn't count as work. The interrupted turn's last message stays inside the fold. Background-work continuations stay a separate response, because the earlier turn had already finished and its answer should stay visible.thread.activity-appendedevent.Expanded, the note sits between the last command before the restart and the agent's first message after it:
Validation
Server:
serverRuntimeStartup.reconcile.test.tsasserts that each continued thread records exactly one row, attached to the turnsendTurnreturned. It covers the marked-update and opt-in-restart paths, the promptless (Codex) and prompted (Claude) continuations, and the background-work continuation with its label.Web:
MessagesTimeline.logic.test.tscovers a lone restart row and a lone compaction row staying visible outside folded work, a continued turn folding into the turn it continued (one fold, duration without the restart gap, note in order when expanded), and a background-work continuation staying separate. The merge tests fail with the merge disabled.Mobile:
threadActivity.test.tscovers the same merge and background cases. Running mobile's feed derivation on the copied thread's real messages and activities gives one fold for the request, matching web.Browser: checked in the web app on a copy of a real Claude thread that the server continued after a restart. The event was inserted at the continuation time, and every copied resume cursor was removed first so no live provider session could be resumed. The request collapses into one "Worked for 3m 10s" row followed by the final answer (3m 28s from message to answer, less 18s before the restart note), and expanding it shows the note between the last pre-restart command and the resumed message. Removing the event gives the before shot.
Real restarts: on an isolated dev server with "Continue threads after restarts" on, I restarted the server mid-turn three times on a Claude thread and once on a Codex thread (which continues without a prompt). Each restart recorded exactly one note, on the turn
sendTurnreturned, and every later event of that turn used the same turn ID. The note sorted first in its turn, and web and Android each showed one fold per request. For background work, I wrote the marker a self-update writes and restarted the server: the background note landed on the new turn and showed as a separate response on web and Android.Not verified
Written by an agent (Claude Code, claude-opus-5-5).