Skip to content

feat(web/draft-assist): assist thread, status machine, not-ready banner - #194

Merged
AlexsanderHamir merged 7 commits into
draftai-spaclientfrom
draftai-thread
Aug 14, 2026
Merged

AlexsanderHamir merged 7 commits into
draftai-spaclientfrom
draftai-thread

Conversation

@AlexsanderHamir

@AlexsanderHamir AlexsanderHamir commented Aug 14, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • Assist thread panel, status machine, not-ready banner.
  • Wired into compose v2 (Space-for-AI opens assist beside the handoff rail).
  • Split oversized modules and design-token CSS so WebOnly standards pass.

Test plan

  • vitest draft-assist + compose
  • .\scripts\check.ps1 -WebOnly (14/14)
  • Merge via gh stack merge (stack #198)

AlexsanderHamir and others added 4 commits August 14, 2026 12:22
Wires Plan 3 of the task-draft-ai stack: the compose page opens a live
draft-assist thread in its reserved right column on the first Space or
`/ai` trigger and stays open for the life of the compose session.

- DraftAssistProvider owns lazy session (POST /sessions on first open),
  SSE consumption via useDraftAssistStream, run start/cancel via
  useDraftAssistSession + startRun/cancelRun, and the message list.
- draftAssistStatus reducer implements the SPA status machine documented
  in docs/design/task-draft-ai.md Status machine (idle->starting->
  thinking->streaming|tool->applying->idle plus cancelling, error,
  disconnected) with sentence-case copy strings.
- useDraftAssistWatchdog fires the 8s / 30s / 90s design thresholds
  (Still working / offer Cancel / offer Retry) using a stubbed clock
  for deterministic tests.
- Patches from `patch` frames apply to the TipTap prompt through a
  controlled onApplyPromptPatch callback (set / find_replace / append);
  invalid patches surface as a thread row instead of silently dropping.
- Send becomes Stop while a run is active; Stop is keyboard-reachable.
  Status region is aria-live=polite; errors are aria-live=assertive.
- TaskComposeForm mounts the provider and passes the thread into
  TaskComposeLayout.assist when active; TaskComposePromptField falls
  back to the nearest DraftAssistContext when no onAiTrigger is passed
  from the parent, so the modal wrapper keeps its no-op behavior.
- CSS in app-task-compose-page.css fills the assist column with a
  sticky panel, message list, status region, and composer footer that
  honors prefers-reduced-motion for the streaming caret.

Tests: draftAssistStatus.test.ts (reducer transitions + copy);
useDraftAssistWatchdog.test.ts (phase math and hook lifecycle);
DraftAssistThread.test.tsx (MSW-driven happy path, cancel, patch
apply, a11y region + Stop keyboard focus).

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
@AlexsanderHamir AlexsanderHamir changed the title feat(web/draft-assist): assist thread, status machine, compose wiring feat(web/draft-assist): assist thread, status machine, not-ready banner Aug 14, 2026
AlexsanderHamir and others added 3 commits August 14, 2026 13:03
Keep compose v2 handoff rail and wire draft-assist beside it when Space-for-AI opens.

Co-authored-by: Cursor <cursoragent@cursor.com>
Split context/controller, extract compose shell/rail, move assist CSS,
and use design tokens so WebOnly check passes.

Co-authored-by: Cursor <cursoragent@cursor.com>
@AlexsanderHamir
AlexsanderHamir marked this pull request as ready for review August 14, 2026 20:24
@AlexsanderHamir
AlexsanderHamir merged commit 462741e into main Aug 14, 2026
1 of 10 checks passed
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