Persistent sessions, streaming fixes, stop button#3
Merged
Conversation
Features: - Persistent Copilot sessions that survive app restarts (headless TCP server mode) - ServerManager: spawn/detect/stop detached copilot --headless servers with PID tracking - Settings page: toggle between Embedded and Persistent connection modes - Stop button to abort running chat responses (SDK AbortAsync) - Session reconnection with '🔄 Session reconnected' indicator - Auto-restore previous sessions on app launch Streaming & rendering fixes: - Fix message duplication: deduplicate AssistantMessageEvent by MessageId (SDK fires events N times for sessions resumed N times) - Fix per-turn delta tracking: HasReceivedDeltasThisTurn flag prevents double-append when both delta and full message events fire - Fix streaming content lifecycle: accumulate across turns, clear only when full response completes (no more vanishing messages) - Remove tool call/reasoning cards from chat history (caused hundreds of thin green lines filling the screen). Show single inline tool indicator for currently running tool instead - Add explicit color: white to assistant message text and markdown body (fixes invisible text from Bootstrap color override on dark background) UI improvements: - System message type and styling for reconnection indicators - Enter key fix: JS interop prevents default on Enter without Shift - Connection mode indicator in sidebar (Persistent/Embedded) - Settings tab in sidebar navigation New files: - Models/ConnectionSettings.cs - Connection mode enum and settings persistence - Services/ServerManager.cs - Server lifecycle management with PID files - Components/Pages/Settings.razor - Connection settings UI - README.md - Comprehensive project documentation
PureWeen
added a commit
that referenced
this pull request
Feb 20, 2026
Concurrency fixes: - Swap _sessions before wiring event handler on reconnect (#2) - Block ALL events from orphaned handlers, not just terminal (#3) - Add lock(_imageQueueLock) to all image queue mutations (#4) including dequeue, reinsert, ClearQueue, rename, close, dispose - Clear IsResumed on error and watchdog paths (#5) - Add RunContinuationsAsynchronously to remaining TCS (#6) Architecture/contract fixes: - Add [JsonIgnore] to ShouldWarnOnStall, LastSimilarity (#7) - Fix ConsecutiveErrors increment-before-check ordering (#8) - Set IsCancelled on all non-success termination paths (#10) including stall, error-stall, max-iteration, OperationCanceled, empty-assignment error stall, and single-agent StopReflectionCycle - Add session dir deletion for ghost evaluator pruning (#12) - Add CompletedAt to StopReflectionCycle (#12 related) Already correct (no changes needed): - #9: CurrentIteration == 1 check was already fixed - #11: Comments already reference string-based stall detection Documentation: - Update stall detection from 'hash match' to 'string equality' - Update error handling to show ConsecutiveErrors (not ConsecutiveStalls) - Add IsCancelled invariant to exit conditions table - Add 5 new invariants: orphan gate, reconnect ordering, image queue locking, IsResumed clearing, TCS creation - Document empty-assignment retry behavior 817/817 tests pass. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
PureWeen
added a commit
that referenced
this pull request
Feb 26, 2026
1. Move FlushCurrentResponse inside Invoke() lambda in AssistantTurnEndEvent handler to avoid racing with UI thread on List<ChatMessage> (Finding #1) 2. Preserve isRecentlyActive across catch block in GetEventsFileRestoreHints — malformed JSON in a recently-written events.jsonl no longer loses the file-age signal that bypasses the 30s quiescence timeout (Finding #2) 3. Add Debug log when dedup guard fires in FlushCurrentResponse so legitimate content drops are observable in diagnostics (Finding #3) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This was referenced Mar 9, 2026
This was referenced Mar 15, 2026
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.
Summary
Adds persistent Copilot sessions that survive app restarts, fixes critical streaming/rendering bugs, and adds a stop button + settings page.
Features
copilot --headless --port Nserver that survives app restarts. Sessions auto-reconnect on relaunch.AbortAsync()to interrupt.Bug Fixes
AssistantMessageEventonce per stacked resume handler. Fixed by deduplicating onMessageId.streamingContentwas being cleared between turns in multi-turn agent loops. Now accumulates across turns until the full response completes.color: whiteto assistant message text and markdown body.HasReceivedDeltasThisTurnflag prevents double-append when both delta and full message events fire for the same turn.New Files
Models/ConnectionSettings.cs— Connection mode enum, JSON persistenceServices/ServerManager.cs— Server lifecycle: spawn, detect, stop with PID file trackingComponents/Pages/Settings.razor— Settings UIREADME.md— Project documentationTechnical Notes
copilot --headless --port Nfor JSON-RPC TCP server (compatible with .NET SDK'sCliUrl)~/.copilot/autopilot-server.pidfor cross-restart server detection~/.copilot/autopilot-active-sessions.json