Skip to content

WIP: Compose interaction mode#121

Draft
FuJacob wants to merge 4 commits into
mainfrom
compose-interaction-mode
Draft

WIP: Compose interaction mode#121
FuJacob wants to merge 4 commits into
mainfrom
compose-interaction-mode

Conversation

@FuJacob
Copy link
Copy Markdown
Owner

@FuJacob FuJacob commented May 21, 2026

Summary

Lands the foundation for Compose Mode: a new SuggestionInteractionMode that gathers broader AX-tree context and prepares a full draft for deliberate review, alongside the existing inline-autocomplete path. This PR is the Phase 1 + Phase 2 slice from rfc.md — mode plumbing, settings/UI surface, and the bounded AX tree walker — without the live Compose generation/typing flow.

Status: WIP draft. The plumbing is in place end-to-end (mode setting → snapshot → router → prompt → context collector → overlay preview hook), but Compose generation is not yet triggered by Tab and the manual draft-typing controller has not been wired into the coordinator. Autocomplete behavior is unchanged.

What landed in this branch:

  • SuggestionInteractionMode enum, persisted in SuggestionSettingsModel and carried in SuggestionSettingsSnapshot.
  • Menu bar Mode picker + Settings "Interaction Mode" picker with explanatory text.
  • ComposeContextCollector — bounded ancestor walk + DFS over the focused AX subtree with role allow/block lists, node and depth budgets, and Task.yield() cancellation points.
  • ComposeContextNormalizer, ComposePromptRenderer, ComposeTextNormalizer, ComposeRequestFactory — pure helpers in Cotabby/Support/.
  • ComposeRequest / ComposeResult / ActiveComposeSession value types; ActiveGenerationSession sum type collapsing autocomplete + compose into one active slot.
  • SuggestionGenerating.generateCompose(for:) added to the protocol; router forwards Compose to llama only and surfaces an unavailable state for Apple Intelligence + MLX.
  • SuggestionOverlayControlling.showComposePreview + ComposePreviewView for a multiline preview surface distinct from inline ghost text.
  • SuggestionInserter.typeDraft(_:shouldContinue:) for chunked synthetic Unicode typing with periodic cancellation checks.
  • SuggestionAvailabilityEvaluator is mode-aware: Compose does not require Screen Recording for AX-only context.
  • LlamaRuntimeManager.generateUncached so Compose's larger drafts cannot pollute the autocomplete KV cache.
  • RuntimeModelCatalog.composeRequiredFilename + supportsCompose(filename:) for the planned tabby-depth-1 requirement.

What is not yet in this branch (deliberate next-PR scope):

  • First Tab does not yet kick off Compose generation; second Tab does not yet trigger typeDraft. The coordinator currently disables predictions with "Compose Mode is selected. Draft generation will be enabled after the Compose request pipeline is installed." when the mode is set.
  • Mode-aware "model required" UI (lock model picker to tabby-depth-1, surface download CTA when missing).
  • Manual QA across GitHub PR comments, Gmail, Slack, Notes.

Validation

xcodebuild -project Cotabby.xcodeproj -scheme Cotabby -destination 'platform=macOS' build
# ** BUILD SUCCEEDED **

xcodebuild -project Cotabby.xcodeproj -scheme Cotabby -destination 'platform=macOS' build-for-testing
# ** TEST BUILD SUCCEEDED **

xcodebuild test-without-building -project Cotabby.xcodeproj -scheme Cotabby -destination 'platform=macOS'
# Executed 274 tests, with 0 failures

swiftlint lint --quiet
# 2 pre-existing cyclomatic_complexity warnings (SuggestionCoordinator+Prediction, ComposeContextCollector); no errors

New tests: ComposeContextNormalizerTests (4 cases) — whitespace, dedupe, navigation noise, and line/context bounds.

UI changes have not been exercised in a running build yet because Compose generation is not wired up; the Mode picker round-trips through UserDefaults but selecting Compose currently surfaces the "pipeline not installed" disabled reason.

Linked issues

Refs #66, #67, #68, #69, #70 — Compose Mode RFC issues.

Risk / rollout notes

  • This PR was significantly stale (forked before the tabby/Cotabby/ rename, the MLX engine addition, the full-suggestion acceptance keybind, structured logging, multi-line completion, and several other features). The merge took two passes — 040e3ba resolved the initial conflict set; 071f9ea re-merged five additional main commits that landed mid-merge (most notably the multi-line completion toggle, which added isMultiLineEnabled to the snapshot). Reviewers should focus on:
    • SuggestionSettingsModel.snapshotPublisher — Combine chain restructured to fan in the new mode + timing + multi-line fields cleanly.
    • SuggestionEngineRouter.generateCompose — only routes to llama; Apple Intelligence and MLX throw unavailable rather than silently forwarding.
    • SuggestionAvailabilityEvaluator.disabledReason — Screen Recording is now gated behind interactionMode == .autocomplete.
    • SuggestionInteractionState.validateSessionForAcceptance — restricted to the autocomplete session because Compose has its own accept flow.
  • userTags is a snapshot field reserved for Compose's prompt; it currently always emits [] until a tag editor lands. No persistence migration needed.
  • pbxproj: one new manual test entry (ComposeContextNormalizerTests.swift). Source files auto-discover.
  • Do not merge until the Phase 3+4 follow-up wires generation into the coordinator; merging this branch alone would land latent code with no visible effect.

FuJacob and others added 4 commits May 14, 2026 21:33
Builds on the Compose interaction mode foundation with additional
service-layer plumbing, context normalization, prompt rendering,
and overlay/insertion support for compose-style suggestions.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Resolves all conflicts after the Tabby -> Cotabby rename, the MLX engine
addition, full-suggestion acceptance keybind, and structured logging
landed on main. Key resolutions:

- `SuggestionSettingsSnapshot` keeps `selectedInteractionMode` and
  `userTags` from the branch, plus the new `debounceMilliseconds`,
  `focusPollIntervalMilliseconds`, and `mlxSwift` engine kind from main.
- `SuggestionGenerating` now includes `generateCompose`; `Foundation`,
  `Llama`, `MLX`, and `Unavailable` engines all implement it. The router
  forwards Compose to llama only.
- `SuggestionAvailabilityEvaluator` only requires Screen Recording in
  autocomplete mode so AX-only Compose context is not gated by it.
- `InputSuppressionController.registerSyntheticInsertion` accumulates
  pending key counts and accepts a longer duration so chunked Compose
  typing reuses one suppression window.
- `SuggestionInteractionState.validateSessionForAcceptance` checks the
  autocomplete session only (Compose uses its own accept flow).
- `MenuBarView` adopts the new Mode picker; the broken word-count header
  binding from the branch is dropped in favor of main's Report button.
- ComposeContextCollector moves to `Cotabby/Services/Context/` and
  `ComposeContextNormalizerTests` is registered in `Cotabby.xcodeproj`.
- Existing test stubs (`FakeOverlayController`, `StubSuggestionEngine`)
  pick up the new protocol methods.

Build, build-for-testing, and the full 260-test suite all pass.
Five new main commits landed during the first merge, including the
multi-line completion toggle. Extends `SuggestionSettingsSnapshot` and
its publisher with `isMultiLineEnabled` while preserving the Compose
interaction-mode fields. Build, test build, and the full 274-test suite
all pass.
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