Skip to content

Mobile UX improvements + processing status indicator#164

Merged
PureWeen merged 5 commits intomainfrom
fix/continued-improvements
Feb 21, 2026
Merged

Mobile UX improvements + processing status indicator#164
PureWeen merged 5 commits intomainfrom
fix/continued-improvements

Conversation

@PureWeen
Copy link
Owner

Summary

Mobile UX improvements, processing status indicator with multi-phase display, and abort fixes.

Mobile UX

  • Report Bug: Opens browser with pre-filled GitHub issue URL on mobile (desktop unchanged)
  • Desktop-only menus hidden: Fix with Copilot, Copilot Console, Terminal, VS Code hidden behind PlatformHelper.IsDesktop guards

Processing Status Indicator

  • Multi-phase display: SendingServer connectedThinkingWorking · Xm Xs · N tool calls
  • ProcessingPhase (int 0-3) tracks current phase, advances on SessionUsageInfoEvent, AssistantTurnStartEvent, ToolExecutionStartEvent
  • ToolCallCount increments on each ToolExecutionCompleteEvent (accurate per-tool counting)
  • Thread-safe: ToolCallCount uses Interlocked.Increment via backing field
  • Synced to mobile via SessionSummary bridge protocol

Abort Fix

  • Stop button clears message queue — prevents queued messages from auto-sending after abort
  • Clears all processing status fields (ProcessingStartedAt, ToolCallCount, ProcessingPhase)
  • Both local and remote-mode paths clear all state
  • Processing fields also reset on all error paths (SessionError, watchdog timeout, SendAsync failures)

Tests (+3 new, 822 total)

  • NewSession_HasDefaultProcessingStatusFields — field defaults
  • ProcessingStatusFields_CanBeSetAndCleared — lifecycle
  • AbortSessionAsync_ClearsQueueAndProcessingStatus — abort clears queue + status
  • Extended Serialize_CamelCaseNaming and SessionsListPayload_RoundTrip for new bridge fields

Scenarios (+2 new)

  • abort-clears-queue-and-status
  • processing-status-indicator

Multi-Model Review (2 Opus 4.6 + 2 Sonnet 4.6)

All 4 reviewers found ToolCallCount atomicity issue → fixed with Interlocked. Additional fixes: missing resets on error paths, sidebar phase update notifications.

PureWeen and others added 5 commits February 20, 2026 17:35
…enu items

- Report Bug on mobile uses Launcher.Default.OpenAsync to open a pre-filled
  GitHub issue URL in the browser (desktop still uses gh CLI)
- Hide Fix with Copilot, Copilot Console, Terminal, and VS Code menu items
  on mobile (they spawn local processes that don't exist on mobile)
- Report Bug and Rename/Pin/Move/Close remain available on all platforms

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Track ProcessingStartedAt, TurnRoundCount, HasReceivedFirstEvent in AgentSessionInfo
- Show 'Waiting for first response...' before any events arrive
- Show 'Working · Xm Xs · N tool rounds...' during active processing
- Display compact status in sidebar session list items
- Sync processing fields via bridge for remote/mobile clients
- Reset fields on SendPromptAsync, clear on CompleteResponse

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- AbortSessionAsync now clears MessageQueue so queued messages don't
  auto-send after stop (fixes mobile stop button not working)
- Clear ProcessingStartedAt/TurnRoundCount/HasReceivedFirstEvent on abort
- Both local and remote-mode paths clear all processing fields
- Add 3 new tests: default processing fields, set/clear, abort clears queue
- Extend bridge serialization tests for processing status fields
- Update copilot-instructions.md with processing status, abort behavior,
  mobile platform differences
- Add 2 new scenarios: abort-clears-queue, processing-status-indicator

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Replace TurnRoundCount with ToolCallCount (increments on each
  ToolExecutionCompleteEvent instead of AssistantTurnEndEvent)
- Replace HasReceivedFirstEvent bool with ProcessingPhase int:
  0=Sending, 1=ServerConnected, 2=Thinking, 3=Working
- Phase transitions: SendPromptAsync→0, SessionUsageInfoEvent→1,
  AssistantTurnStartEvent→2, ToolExecutionStartEvent→3
- UI shows: Sending → Server connected → Thinking → Working · Xm Xs · N tool calls
- Update all tests, bridge sync, and documentation

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- ToolCallCount: use Interlocked.Increment via backing field for
  thread-safe increment on background SDK event threads (4/4 reviewers)
- Reset ProcessingStartedAt/ToolCallCount/ProcessingPhase on all error
  paths: SessionErrorEvent, watchdog timeout, SendAsync failures (Opus)
- Fire OnStateChanged when ProcessingPhase transitions to Thinking/Working
  so sidebar updates beyond ServerConnected phase (Sonnet)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@PureWeen PureWeen merged commit f7c4fb2 into main Feb 21, 2026
6 checks passed
PureWeen added a commit that referenced this pull request Feb 21, 2026
Invariant audit found 4 pre-existing gaps where IsProcessing was cleared
without resetting all companion fields:

1. CompleteResponse: missing ActiveToolCallCount reset
2. SendAsync reconnect+retry failure: missing IsResumed, HasUsedToolsThisTurn,
   ActiveToolCallCount, FlushCurrentResponse
3. SendAsync initial failure: same missing fields
4. Remote mode abort: missing IsResumed

These are the exact same class of bug that caused regressions in PRs #148,
#158, and #164. Every path that sets IsProcessing=false must also clear:
IsResumed, HasUsedToolsThisTurn, ActiveToolCallCount, ProcessingStartedAt,
ToolCallCount, ProcessingPhase, and FlushCurrentResponse.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
PureWeen added a commit that referenced this pull request Feb 21, 2026
…edge

Add comprehensive documentation of the recurring stuck-session bug pattern
(7 PRs, 16 fix/regression cycles) to copilot-instructions.md:

- Full cleanup checklist for all IsProcessing=false paths
- Table of all 7 paths with locations
- 7 common mistakes with PR references where each occurred
- Staleness check and IsResumed clearing documentation
- Cross-thread volatile field requirements
- ProcessingGeneration guard explanation
- Watchdog diagnostic log tag additions

This knowledge was hard-won across PRs #141, #147, #148, #153, #158,
#163, #164 and should prevent future regressions by making the invariants
explicit and discoverable.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@PureWeen PureWeen deleted the fix/continued-improvements branch February 22, 2026 00:15
PureWeen added a commit that referenced this pull request Feb 25, 2026
## Problem
After app restart, resumed sessions that were mid-turn show
**Thinking...** with a Stop button. The user must manually click Stop
every time. The existing watchdog waited 600s (10 min!) before clearing
stuck IsProcessing.

## Solution
Add a **30s resume quiescence timeout** for sessions that receive zero
SDK events after restart. If no events flow within 30s of app start, the
session is cleared as stuck.

### Key design decisions (informed by 4-model consultation: Opus 4.6,
Sonnet 4.6, Codex 5.3, GPT-5.1):

1. **30s quiescence** — short enough users don't wait, long enough for
SDK reconnect (~5s typical, 6x safety margin)
2. **Event-gated** — only fires when \HasReceivedEventsSinceResume ==
false\. Once events start flowing, transitions to normal 120s/600s
timeout tiers
3. **Seed from DateTime.UtcNow, NOT file time** — all 3 models
independently flagged that seeding from events.jsonl would cause
immediate kills for sessions >15s old (exact PR #148 regression pattern)
4. **Reuses existing watchdog fire path** — no new IsProcessing cleanup
code, all 8 invariants preserved

### Timeout tiers (3-tier, was 2-tier):
| Condition | Timeout |
|-----------|---------|
| Resumed, zero events since restart | **30s** (NEW) |
| Normal processing, no tools | 120s |
| Active tools / resumed with events / multi-agent | 600s |

## Tests
- **16 new regression guard tests** covering quiescence edge cases, seed
time safety, exhaustive timeout matrix
- Updated existing tests to use \ComputeEffectiveTimeout\ helper
mirroring production 3-tier formula
- **108 total watchdog+recovery tests pass** ✅

## Regression history context
This code has been through 7 PRs of fix/regression cycles (PRs
#141#147#148#153#158#163#164). The most relevant precedent: PR
#148 added a 10s resume timeout that killed active sessions. Our 30s
timeout avoids this by being event-gated and seeded from UtcNow.

Fixes the 'click Stop on every restart' UX issue.

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant