fix(ios): support image paste from composer edit menu - #5610

Closed
saphid wants to merge 10 commits into
pingdotgg:t3code/rebuild-mobile-app-swiftfrom
saphid:agent/swiftui-image-paste
Closed

fix(ios): support image paste from composer edit menu#5610
saphid wants to merge 10 commits into
pingdotgg:t3code/rebuild-mobile-app-swiftfrom
saphid:agent/swiftui-image-paste

Conversation

@saphid

@saphidsaphid commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

What changed

  • Replace the SwiftUI composer field with a small UIKit-backed UITextView so copied images appear in the native long-press Paste menu.
  • Keep ordinary text paste unchanged, preserve text from mixed image/text pasteboard items, and keep command, model, skill, and path replacement caret placement correct.
  • Send pasted image providers through the existing image processor and attachment strip, preserving successful providers when another provider fails.
  • Reserve the shared eight-image capacity across in-flight picker, camera, Files, and paste work, and reject callbacks captured for a stale composer context.

The patch is limited to the SwiftUI iOS composer and attachment ingestion, plus focused tests and user documentation. It is stacked on the experimental SwiftUI client in #5178. The branch is rebased on 0d0c77431, which includes f79886039 and its native-CI repair.

Why

The SwiftUI field accepted pasted text but did not offer Paste for a copied screenshot or photo. A UIKit text responder can advertise image and text paste types through the standard iOS edit menu, then hand image providers to the same preparation path as the existing attachment picker.

UI evidence

Before: copied image, no PasteAfter: native Paste action
Before: long-press edit menu without PasteAfter: long-press edit menu with Paste

Resulting attachment

Copied image appears in the attachment strip

Eight-image limit

A further paste remains at eight attachments and shows the limit alert

Image-conforming provider regression

A HEIC-conforming pasteboard item still exposes Paste at the eight-image limit

Interaction video: native Paste action to attachment (10.97 seconds)

The four primary images and video were re-downloaded from the immutable evidence commit and matched their local SHA-256 hashes. The video was identified as H.264 at 1206×2622 and played in T3's collaborative preview. The HEIC regression image was captured from the final signed build after the Macroscope fix.

Validation

  • AttachmentPreparationTests + FeatureComposerPowerTests: 22 passed, 0 failed on the frozen diff after the review fixes.
  • T3_SWIFT_SIMULATOR_ID=… apps/swift-ios/Scripts/ci-test.sh: 228 tests in 27 suites, 0 failures. Existing unrelated simulator warnings remained visible; no test was weakened.
  • node scripts/generate-swift-wire-fixtures.ts --check: passed on the final diff, verifying the earlier native-CI fixture failure is repaired by the current stacking base.
  • Final signed Xcode 26.6 build, install, and launch on an iPhone 17 Pro simulator running iOS 26.5: passed.
  • Integrated UI: native menu and text-only paste; image-only paste to one attachment; mixed paste to text plus one attachment; text inserted at a nonterminal caret; nine-image paste capped at eight; and a further paste at capacity remained at eight with the limit alert.
  • Focused simulator tests cover shared pending capacity, partial-provider success, stale lifecycle tokens used by picker/camera/paste callbacks, provider loading, draft restoration, and UTF-16 caret restoration.
  • git diff --check: passed. Final range is four commits and 999 changed lines (915 additions, 84 deletions), reduced from 1,299 by removing the generic task store and duplicate test seams.
  • Fresh GPT-5.6 Sol high minimum-scope review inspected the frozen range and found one actionable issue: image interception was being disabled once eight attachments were present. Macroscope then found that hasImages misses some image-conforming providers, reproduced with public.heic. The final patch keeps interception active at capacity and detects UTType.image conformance. A late exact-head Cursor finding then reproduced an empty-to-restored-text caret jump; the fix now places that caret at the UTF-16 end while preserving ordinary selections. Affected tests and the signed integrated pass were repeated.

Checklist

  • Single-purpose SwiftUI image-paste change, minimized to the reliable behavior and its proof
  • Exact behavior and rationale described
  • Before/after and resulting-state screenshots included
  • Short interaction video included and playback verified
  • Focused tests, full native script, fixture check, and integrated simulator pass completed

Related

Implementation, integration, and fresh review: GPT-5.6 Sol in T3 Code.


Note

Medium Risk
Touches core composer input and async attachment ingestion with lifecycle cancellation; behavior is well-tested but regressions in paste, limits, or draft/project context switches would affect every send path on iOS.

Overview
Enables Paste for copied screenshots/photos in the iOS chat composer by swapping the SwiftUI TextField for a UIKit-backed FeatureComposerUITextView that advertises image paste types and routes image providers through the same ingestion path as Photos, Camera, and Files.

Paste and attachments: Mixed pasteboards still insert plain text (via FeatureComposerPasteTextPolicy) while images load in a serialized FeatureComposerPasteQueue, respect the shared eight-image cap (FeatureImageAttachmentPolicy.reserve / attachmentsToAppend), and surface alerts on limit or partial failure. Image detection uses UTType.image conformance so HEIC-style items still show Paste at capacity.

Lifecycle:FeatureAttachmentLifecycle tokens tied to attachmentContextID (thread or project) cancel stale picker, camera, file, and paste work on context change or send; NewThreadView shares one lifecycle across project switches.

Composer UX: Trigger replacements and empty-to-restored draft updates set caret position with UTF-16-aware selection policy; the text field grows within a bounded viewport. Focused unit tests and brief user docs cover the new behavior.

Reviewed by Cursor Bugbot for commit 9fc22e1. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Add image paste support to the iOS chat composer

  • Subclasses UITextView as FeatureComposerUITextView to intercept paste events, exposing the system paste menu for images and inserting any coexisting plain text before queuing image attachments.
  • Introduces FeatureComposerPasteQueue to serialize and cancel pending paste operations when the attachment context changes or a message is sent.
  • Enforces an 8-image limit across concurrent picker and paste flows via FeatureImageAttachmentPolicy and FeatureAttachmentPreparationState.reserve; excess images are dropped and the user sees an alert.
  • Replaces the SwiftUI TextField with a new FeatureComposerTextInput (UIViewRepresentable) that grows to a viewport-dependent max height and preserves caret position after autocomplete insertions.
  • Attachment context is now bound to thread/project ID so in-flight async operations are invalidated on context changes.

Macroscope summarized 9fc22e1.

Delivery: direct
Validated against Theo commit: f98cab5
Depends on: none
Merge order: this PR only
Validation status: Mergeable; native/repository checks and current review are green. The unrelated Vercel authorization failure is a maintainer-side gate.

@coderabbitai

coderabbitaiBot commented Aug 7, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 3b9d22c2-4390-4d41-9896-e3e89f4adb83

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:L 100-499 changed lines (additions + deletions). size:XL 500-999 changed lines (additions + deletions). and removed size:L 100-499 changed lines (additions + deletions). labels Aug 7, 2026
Comment threadapps/swift-ios/Features/Chat/FeatureComposerView.swift
@saphid
saphidforce-pushed the agent/swiftui-image-paste branch from 0f6efd1 to 7ea541dCompareAugust 8, 2026 01:16
@github-actionsgithub-actionsBot added size:XXL 1,000+ changed lines (additions + deletions). and removed size:XL 500-999 changed lines (additions + deletions). labels Aug 8, 2026
@saphid
saphidforce-pushed the agent/swiftui-image-paste branch 2 times, most recently from 8f34edd to 388ce56CompareAugust 8, 2026 22:47
@t3dotgg

Copy link
Copy Markdown
Member

Note

🤖 GPT-5.6 responding on behalf of Theo

/recheck-vouch

@github-actionsgithub-actionsBot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. and removed vouch:unvouched PR author is not yet trusted in the VOUCHED list. labels Aug 9, 2026
@t3dotgg
t3dotggforce-pushed the t3code/rebuild-mobile-app-swift branch from 65e66ee to 4df1e9bCompareAugust 9, 2026 02:26
@saphid
saphidforce-pushed the agent/swiftui-image-paste branch from 388ce56 to 08cc37cCompareAugust 9, 2026 03:26
@saphid

Copy link
Copy Markdown
ContributorAuthor

Rebased this draft onto the signed SwiftUI base rewrite at 4df1e9b. All nine PR commits replayed cleanly and range-diff is patch-identical. GitHub now reports the intended 7-file diff (1,118 additions, 74 deletions). Verification: 24 focused Xcode tests passed, 0 failed; git diff --check passed. New tip: 08cc37c15.

Comment threadapps/swift-ios/Features/Chat/FeatureComposerView.swift
@saphid
saphidforce-pushed the agent/swiftui-image-paste branch from 08cc37c to f5da001CompareAugust 9, 2026 12:32
@github-actionsgithub-actionsBot added size:XL 500-999 changed lines (additions + deletions). and removed size:XXL 1,000+ changed lines (additions + deletions). labels Aug 9, 2026
@saphid
saphidforce-pushed the agent/swiftui-image-paste branch from f5da001 to 46b4c62CompareAugust 9, 2026 12:39
@saphid
saphid marked this pull request as ready for review August 9, 2026 12:43
@saphid

saphid commented Aug 9, 2026

Copy link
Copy Markdown
ContributorAuthor

Ready for maintainer review at 7dd058199 on base 0d0c77431.

  • The late exact-head Cursor caret finding was reproduced, fixed, regression-tested, replied to, and resolved.
  • Focused attachment/composer suites: 22 passed. Full apps/swift-ios/Scripts/ci-test.sh: 228 tests in 27 suites passed. Signed simulator build/install/launch passed.
  • Exact-head SwiftUI native tests, CI Check/Test, Mobile Native Static Analysis, Release Smoke, Macroscope Correctness, and Cursor Bugbot passed.
  • Macroscope Approvability completed neutral with the expected verdict that this user-facing feature needs human review; it reported no new correctness issue. CodeRabbit still explicitly says its review was skipped and is not counted as a review.
  • The remaining Vercel marketing status is the same authorization failure, unrelated to this seven-file SwiftUI-only range. GitHub reports the PR non-draft, mergeable, vouch:trusted, and size:XL at 999 changed lines.
  • The PR body retains immutable publicly rendered screenshots and a verified playable interaction video. The current live audit has no unresolved review threads.

Only human maintainer review/merge remains.

Comment threadapps/swift-ios/Features/Chat/FeatureComposerView.swift
@macroscopeapp

macroscopeappBot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

This PR adds a substantial new feature (image paste support from iOS edit menu) with ~900 lines of new code including custom UITextView paste handling, lifecycle management, and batch image processing. New user-facing capabilities of this scope warrant human review.

You can customize Macroscope's approvability policy. Learn more.

@saphid

Copy link
Copy Markdown
ContributorAuthor

@t3dotgg This SwiftUI PR is ready for your review. Its exact head is mergeable; repository/native CI, MacroScope, Cursor, and review-thread audits are clean with zero unresolved threads. The only red status is the unrelated Vercel marketing authorization check.

@t3dotgg
t3dotggforce-pushed the t3code/rebuild-mobile-app-swift branch from 4cb3307 to 497f54fCompareAugust 10, 2026 03:58
@github-actionsgithub-actionsBot added size:XXL 1,000+ changed lines (additions + deletions). and removed size:XL 500-999 changed lines (additions + deletions). labels Aug 10, 2026
@saphid

Copy link
Copy Markdown
ContributorAuthor

Added the tall-draft follow-up in a6d78788e. The UIKit composer now remains internally scrollable, keeps programmatic caret moves visible, and grows only up to half the proposed viewport (with a 12-line fallback when the proposal is unavailable), so long drafts stay reachable without displacing the transcript. apps/swift-ios/Scripts/ci-test.sh passes 230 tests. A fresh Claude Opus 5 high review found no remaining defect in the paste/tall-composer interaction.

@saphid

Copy link
Copy Markdown
ContributorAuthor

Follow-up simulator evidence for the tall-composer continuation:

Very tall draft remains reachable above the software keyboard

Verified on iOS 26.5 with the software keyboard enabled: the restored multi-line draft scrolls/grows without making its bottom controls unreachable.

@saphid
saphidforce-pushed the agent/swiftui-image-paste branch from a6d7878 to f7987c6CompareAugust 10, 2026 10:23
Comment threadapps/swift-ios/Features/Chat/FeatureComposerView.swift Outdated
Comment threadapps/swift-ios/Features/Chat/FeatureComposerView.swift

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit d3c6ddc. Configure here.

Comment threadapps/swift-ios/Features/Chat/FeatureComposerView.swift Outdated
@saphid

Copy link
Copy Markdown
ContributorAuthor

Added two focused acceptance tests for the final editor outcome, on top of the current live PR head (including its latest UTF-16/NUL paste fix). No production code changed in this update.

The tests prove that visible composer height grows beyond three lines before its viewport bound, while content remains unlimited after visible height caps.

Integrated iOS 26.5 proof used a 516-character New Task draft: it grew, capped at 50% of the viewport, scrolled internally with the caret at the end, and kept attachment/model/send semantic targets reachable. Private video: https://alexs-macbook-pro-1.tail4e5636.ts.net:8766/swiftui-final-editor-growth-keyboard-proof-20260810.mp4

Post-update verification: focused Composer+Attachment 26/26; full native 237 tests/28 suites; git diff --check clean. Direct Opus review was attempted twice but unavailable: one aborted stream and one real exit 1 / HTTP 429 session limit. No completed independent verdict is claimed; the change is test-only and parent self-audit found no actionable issue.

This is the acceptance evidence for closing #5801 as superseded. #5829's one-line keyboard cap remains intentionally excluded because it conflicts with this final invariant.

t3-code[bot]
t3-codeBot approved these changes Aug 12, 2026

@t3-codet3-codeBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reviewed the full composer paste and attachment lifecycle diff, including context rotation, capacity handling, text decoding, caret restoration, and focused tests. no blocking issues found.

@t3dotgg

Copy link
Copy Markdown
Member

Resolve conflicts and re-run ci

@saphid

Copy link
Copy Markdown
ContributorAuthor

Closing this version while I rebuild the upstream contribution set from the latest base. Clean versions are coming soon.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL1,000+ changed lines (additions + deletions).vouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@saphid@t3dotgg
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

fix(ios): support image paste from composer edit menu - #5610

Closed
saphid wants to merge 10 commits into
pingdotgg:t3code/rebuild-mobile-app-swiftfrom
saphid:agent/swiftui-image-paste
Closed

fix(ios): support image paste from composer edit menu#5610
saphid wants to merge 10 commits into
pingdotgg:t3code/rebuild-mobile-app-swiftfrom
saphid:agent/swiftui-image-paste

Conversation

@saphid

@saphidsaphid commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

What changed

  • Replace the SwiftUI composer field with a small UIKit-backed UITextView so copied images appear in the native long-press Paste menu.
  • Keep ordinary text paste unchanged, preserve text from mixed image/text pasteboard items, and keep command, model, skill, and path replacement caret placement correct.
  • Send pasted image providers through the existing image processor and attachment strip, preserving successful providers when another provider fails.
  • Reserve the shared eight-image capacity across in-flight picker, camera, Files, and paste work, and reject callbacks captured for a stale composer context.

The patch is limited to the SwiftUI iOS composer and attachment ingestion, plus focused tests and user documentation. It is stacked on the experimental SwiftUI client in #5178. The branch is rebased on 0d0c77431, which includes f79886039 and its native-CI repair.

Why

The SwiftUI field accepted pasted text but did not offer Paste for a copied screenshot or photo. A UIKit text responder can advertise image and text paste types through the standard iOS edit menu, then hand image providers to the same preparation path as the existing attachment picker.

UI evidence

Before: copied image, no PasteAfter: native Paste action
Before: long-press edit menu without PasteAfter: long-press edit menu with Paste

Resulting attachment

Copied image appears in the attachment strip

Eight-image limit

A further paste remains at eight attachments and shows the limit alert

Image-conforming provider regression

A HEIC-conforming pasteboard item still exposes Paste at the eight-image limit

Interaction video: native Paste action to attachment (10.97 seconds)

The four primary images and video were re-downloaded from the immutable evidence commit and matched their local SHA-256 hashes. The video was identified as H.264 at 1206×2622 and played in T3's collaborative preview. The HEIC regression image was captured from the final signed build after the Macroscope fix.

Validation

  • AttachmentPreparationTests + FeatureComposerPowerTests: 22 passed, 0 failed on the frozen diff after the review fixes.
  • T3_SWIFT_SIMULATOR_ID=… apps/swift-ios/Scripts/ci-test.sh: 228 tests in 27 suites, 0 failures. Existing unrelated simulator warnings remained visible; no test was weakened.
  • node scripts/generate-swift-wire-fixtures.ts --check: passed on the final diff, verifying the earlier native-CI fixture failure is repaired by the current stacking base.
  • Final signed Xcode 26.6 build, install, and launch on an iPhone 17 Pro simulator running iOS 26.5: passed.
  • Integrated UI: native menu and text-only paste; image-only paste to one attachment; mixed paste to text plus one attachment; text inserted at a nonterminal caret; nine-image paste capped at eight; and a further paste at capacity remained at eight with the limit alert.
  • Focused simulator tests cover shared pending capacity, partial-provider success, stale lifecycle tokens used by picker/camera/paste callbacks, provider loading, draft restoration, and UTF-16 caret restoration.
  • git diff --check: passed. Final range is four commits and 999 changed lines (915 additions, 84 deletions), reduced from 1,299 by removing the generic task store and duplicate test seams.
  • Fresh GPT-5.6 Sol high minimum-scope review inspected the frozen range and found one actionable issue: image interception was being disabled once eight attachments were present. Macroscope then found that hasImages misses some image-conforming providers, reproduced with public.heic. The final patch keeps interception active at capacity and detects UTType.image conformance. A late exact-head Cursor finding then reproduced an empty-to-restored-text caret jump; the fix now places that caret at the UTF-16 end while preserving ordinary selections. Affected tests and the signed integrated pass were repeated.

Checklist

  • Single-purpose SwiftUI image-paste change, minimized to the reliable behavior and its proof
  • Exact behavior and rationale described
  • Before/after and resulting-state screenshots included
  • Short interaction video included and playback verified
  • Focused tests, full native script, fixture check, and integrated simulator pass completed

Related

Implementation, integration, and fresh review: GPT-5.6 Sol in T3 Code.


Note

Medium Risk
Touches core composer input and async attachment ingestion with lifecycle cancellation; behavior is well-tested but regressions in paste, limits, or draft/project context switches would affect every send path on iOS.

Overview
Enables Paste for copied screenshots/photos in the iOS chat composer by swapping the SwiftUI TextField for a UIKit-backed FeatureComposerUITextView that advertises image paste types and routes image providers through the same ingestion path as Photos, Camera, and Files.

Paste and attachments: Mixed pasteboards still insert plain text (via FeatureComposerPasteTextPolicy) while images load in a serialized FeatureComposerPasteQueue, respect the shared eight-image cap (FeatureImageAttachmentPolicy.reserve / attachmentsToAppend), and surface alerts on limit or partial failure. Image detection uses UTType.image conformance so HEIC-style items still show Paste at capacity.

Lifecycle:FeatureAttachmentLifecycle tokens tied to attachmentContextID (thread or project) cancel stale picker, camera, file, and paste work on context change or send; NewThreadView shares one lifecycle across project switches.

Composer UX: Trigger replacements and empty-to-restored draft updates set caret position with UTF-16-aware selection policy; the text field grows within a bounded viewport. Focused unit tests and brief user docs cover the new behavior.

Reviewed by Cursor Bugbot for commit 9fc22e1. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Add image paste support to the iOS chat composer

  • Subclasses UITextView as FeatureComposerUITextView to intercept paste events, exposing the system paste menu for images and inserting any coexisting plain text before queuing image attachments.
  • Introduces FeatureComposerPasteQueue to serialize and cancel pending paste operations when the attachment context changes or a message is sent.
  • Enforces an 8-image limit across concurrent picker and paste flows via FeatureImageAttachmentPolicy and FeatureAttachmentPreparationState.reserve; excess images are dropped and the user sees an alert.
  • Replaces the SwiftUI TextField with a new FeatureComposerTextInput (UIViewRepresentable) that grows to a viewport-dependent max height and preserves caret position after autocomplete insertions.
  • Attachment context is now bound to thread/project ID so in-flight async operations are invalidated on context changes.

Macroscope summarized 9fc22e1.

Delivery: direct
Validated against Theo commit: f98cab5
Depends on: none
Merge order: this PR only
Validation status: Mergeable; native/repository checks and current review are green. The unrelated Vercel authorization failure is a maintainer-side gate.

@coderabbitai

coderabbitaiBot commented Aug 7, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 3b9d22c2-4390-4d41-9896-e3e89f4adb83

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:L 100-499 changed lines (additions + deletions). size:XL 500-999 changed lines (additions + deletions). and removed size:L 100-499 changed lines (additions + deletions). labels Aug 7, 2026
Comment threadapps/swift-ios/Features/Chat/FeatureComposerView.swift
@saphid
saphidforce-pushed the agent/swiftui-image-paste branch from 0f6efd1 to 7ea541dCompareAugust 8, 2026 01:16
@github-actionsgithub-actionsBot added size:XXL 1,000+ changed lines (additions + deletions). and removed size:XL 500-999 changed lines (additions + deletions). labels Aug 8, 2026
@saphid
saphidforce-pushed the agent/swiftui-image-paste branch 2 times, most recently from 8f34edd to 388ce56CompareAugust 8, 2026 22:47
@t3dotgg

Copy link
Copy Markdown
Member

Note

🤖 GPT-5.6 responding on behalf of Theo

/recheck-vouch

@github-actionsgithub-actionsBot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. and removed vouch:unvouched PR author is not yet trusted in the VOUCHED list. labels Aug 9, 2026
@t3dotgg
t3dotggforce-pushed the t3code/rebuild-mobile-app-swift branch from 65e66ee to 4df1e9bCompareAugust 9, 2026 02:26
@saphid
saphidforce-pushed the agent/swiftui-image-paste branch from 388ce56 to 08cc37cCompareAugust 9, 2026 03:26
@saphid

Copy link
Copy Markdown
ContributorAuthor

Rebased this draft onto the signed SwiftUI base rewrite at 4df1e9b. All nine PR commits replayed cleanly and range-diff is patch-identical. GitHub now reports the intended 7-file diff (1,118 additions, 74 deletions). Verification: 24 focused Xcode tests passed, 0 failed; git diff --check passed. New tip: 08cc37c15.

Comment threadapps/swift-ios/Features/Chat/FeatureComposerView.swift
@saphid
saphidforce-pushed the agent/swiftui-image-paste branch from 08cc37c to f5da001CompareAugust 9, 2026 12:32
@github-actionsgithub-actionsBot added size:XL 500-999 changed lines (additions + deletions). and removed size:XXL 1,000+ changed lines (additions + deletions). labels Aug 9, 2026
@saphid
saphidforce-pushed the agent/swiftui-image-paste branch from f5da001 to 46b4c62CompareAugust 9, 2026 12:39
@saphid
saphid marked this pull request as ready for review August 9, 2026 12:43
@saphid

saphid commented Aug 9, 2026

Copy link
Copy Markdown
ContributorAuthor

Ready for maintainer review at 7dd058199 on base 0d0c77431.

  • The late exact-head Cursor caret finding was reproduced, fixed, regression-tested, replied to, and resolved.
  • Focused attachment/composer suites: 22 passed. Full apps/swift-ios/Scripts/ci-test.sh: 228 tests in 27 suites passed. Signed simulator build/install/launch passed.
  • Exact-head SwiftUI native tests, CI Check/Test, Mobile Native Static Analysis, Release Smoke, Macroscope Correctness, and Cursor Bugbot passed.
  • Macroscope Approvability completed neutral with the expected verdict that this user-facing feature needs human review; it reported no new correctness issue. CodeRabbit still explicitly says its review was skipped and is not counted as a review.
  • The remaining Vercel marketing status is the same authorization failure, unrelated to this seven-file SwiftUI-only range. GitHub reports the PR non-draft, mergeable, vouch:trusted, and size:XL at 999 changed lines.
  • The PR body retains immutable publicly rendered screenshots and a verified playable interaction video. The current live audit has no unresolved review threads.

Only human maintainer review/merge remains.

Comment threadapps/swift-ios/Features/Chat/FeatureComposerView.swift
@macroscopeapp

macroscopeappBot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

This PR adds a substantial new feature (image paste support from iOS edit menu) with ~900 lines of new code including custom UITextView paste handling, lifecycle management, and batch image processing. New user-facing capabilities of this scope warrant human review.

You can customize Macroscope's approvability policy. Learn more.

@saphid

Copy link
Copy Markdown
ContributorAuthor

@t3dotgg This SwiftUI PR is ready for your review. Its exact head is mergeable; repository/native CI, MacroScope, Cursor, and review-thread audits are clean with zero unresolved threads. The only red status is the unrelated Vercel marketing authorization check.

@t3dotgg
t3dotggforce-pushed the t3code/rebuild-mobile-app-swift branch from 4cb3307 to 497f54fCompareAugust 10, 2026 03:58
@github-actionsgithub-actionsBot added size:XXL 1,000+ changed lines (additions + deletions). and removed size:XL 500-999 changed lines (additions + deletions). labels Aug 10, 2026
@saphid

Copy link
Copy Markdown
ContributorAuthor

Added the tall-draft follow-up in a6d78788e. The UIKit composer now remains internally scrollable, keeps programmatic caret moves visible, and grows only up to half the proposed viewport (with a 12-line fallback when the proposal is unavailable), so long drafts stay reachable without displacing the transcript. apps/swift-ios/Scripts/ci-test.sh passes 230 tests. A fresh Claude Opus 5 high review found no remaining defect in the paste/tall-composer interaction.

@saphid

Copy link
Copy Markdown
ContributorAuthor

Follow-up simulator evidence for the tall-composer continuation:

Very tall draft remains reachable above the software keyboard

Verified on iOS 26.5 with the software keyboard enabled: the restored multi-line draft scrolls/grows without making its bottom controls unreachable.

@saphid
saphidforce-pushed the agent/swiftui-image-paste branch from a6d7878 to f7987c6CompareAugust 10, 2026 10:23
Comment threadapps/swift-ios/Features/Chat/FeatureComposerView.swift Outdated
Comment threadapps/swift-ios/Features/Chat/FeatureComposerView.swift

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit d3c6ddc. Configure here.

Comment threadapps/swift-ios/Features/Chat/FeatureComposerView.swift Outdated
@saphid

Copy link
Copy Markdown
ContributorAuthor

Added two focused acceptance tests for the final editor outcome, on top of the current live PR head (including its latest UTF-16/NUL paste fix). No production code changed in this update.

The tests prove that visible composer height grows beyond three lines before its viewport bound, while content remains unlimited after visible height caps.

Integrated iOS 26.5 proof used a 516-character New Task draft: it grew, capped at 50% of the viewport, scrolled internally with the caret at the end, and kept attachment/model/send semantic targets reachable. Private video: https://alexs-macbook-pro-1.tail4e5636.ts.net:8766/swiftui-final-editor-growth-keyboard-proof-20260810.mp4

Post-update verification: focused Composer+Attachment 26/26; full native 237 tests/28 suites; git diff --check clean. Direct Opus review was attempted twice but unavailable: one aborted stream and one real exit 1 / HTTP 429 session limit. No completed independent verdict is claimed; the change is test-only and parent self-audit found no actionable issue.

This is the acceptance evidence for closing #5801 as superseded. #5829's one-line keyboard cap remains intentionally excluded because it conflicts with this final invariant.

t3-code[bot]
t3-codeBot approved these changes Aug 12, 2026

@t3-codet3-codeBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reviewed the full composer paste and attachment lifecycle diff, including context rotation, capacity handling, text decoding, caret restoration, and focused tests. no blocking issues found.

@t3dotgg

Copy link
Copy Markdown
Member

Resolve conflicts and re-run ci

@saphid

Copy link
Copy Markdown
ContributorAuthor

Closing this version while I rebuild the upstream contribution set from the latest base. Clean versions are coming soon.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL1,000+ changed lines (additions + deletions).vouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@saphid@t3dotgg
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(ios): support image paste from composer edit menu - #5610

Closed
saphid wants to merge 10 commits into
pingdotgg:t3code/rebuild-mobile-app-swiftfrom
saphid:agent/swiftui-image-paste
Closed

fix(ios): support image paste from composer edit menu#5610
saphid wants to merge 10 commits into
pingdotgg:t3code/rebuild-mobile-app-swiftfrom
saphid:agent/swiftui-image-paste

Conversation

@saphid

@saphidsaphid commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

What changed

  • Replace the SwiftUI composer field with a small UIKit-backed UITextView so copied images appear in the native long-press Paste menu.
  • Keep ordinary text paste unchanged, preserve text from mixed image/text pasteboard items, and keep command, model, skill, and path replacement caret placement correct.
  • Send pasted image providers through the existing image processor and attachment strip, preserving successful providers when another provider fails.
  • Reserve the shared eight-image capacity across in-flight picker, camera, Files, and paste work, and reject callbacks captured for a stale composer context.

The patch is limited to the SwiftUI iOS composer and attachment ingestion, plus focused tests and user documentation. It is stacked on the experimental SwiftUI client in #5178. The branch is rebased on 0d0c77431, which includes f79886039 and its native-CI repair.

Why

The SwiftUI field accepted pasted text but did not offer Paste for a copied screenshot or photo. A UIKit text responder can advertise image and text paste types through the standard iOS edit menu, then hand image providers to the same preparation path as the existing attachment picker.

UI evidence

Before: copied image, no PasteAfter: native Paste action
Before: long-press edit menu without PasteAfter: long-press edit menu with Paste

Resulting attachment

Copied image appears in the attachment strip

Eight-image limit

A further paste remains at eight attachments and shows the limit alert

Image-conforming provider regression

A HEIC-conforming pasteboard item still exposes Paste at the eight-image limit

Interaction video: native Paste action to attachment (10.97 seconds)

The four primary images and video were re-downloaded from the immutable evidence commit and matched their local SHA-256 hashes. The video was identified as H.264 at 1206×2622 and played in T3's collaborative preview. The HEIC regression image was captured from the final signed build after the Macroscope fix.

Validation

  • AttachmentPreparationTests + FeatureComposerPowerTests: 22 passed, 0 failed on the frozen diff after the review fixes.
  • T3_SWIFT_SIMULATOR_ID=… apps/swift-ios/Scripts/ci-test.sh: 228 tests in 27 suites, 0 failures. Existing unrelated simulator warnings remained visible; no test was weakened.
  • node scripts/generate-swift-wire-fixtures.ts --check: passed on the final diff, verifying the earlier native-CI fixture failure is repaired by the current stacking base.
  • Final signed Xcode 26.6 build, install, and launch on an iPhone 17 Pro simulator running iOS 26.5: passed.
  • Integrated UI: native menu and text-only paste; image-only paste to one attachment; mixed paste to text plus one attachment; text inserted at a nonterminal caret; nine-image paste capped at eight; and a further paste at capacity remained at eight with the limit alert.
  • Focused simulator tests cover shared pending capacity, partial-provider success, stale lifecycle tokens used by picker/camera/paste callbacks, provider loading, draft restoration, and UTF-16 caret restoration.
  • git diff --check: passed. Final range is four commits and 999 changed lines (915 additions, 84 deletions), reduced from 1,299 by removing the generic task store and duplicate test seams.
  • Fresh GPT-5.6 Sol high minimum-scope review inspected the frozen range and found one actionable issue: image interception was being disabled once eight attachments were present. Macroscope then found that hasImages misses some image-conforming providers, reproduced with public.heic. The final patch keeps interception active at capacity and detects UTType.image conformance. A late exact-head Cursor finding then reproduced an empty-to-restored-text caret jump; the fix now places that caret at the UTF-16 end while preserving ordinary selections. Affected tests and the signed integrated pass were repeated.

Checklist

  • Single-purpose SwiftUI image-paste change, minimized to the reliable behavior and its proof
  • Exact behavior and rationale described
  • Before/after and resulting-state screenshots included
  • Short interaction video included and playback verified
  • Focused tests, full native script, fixture check, and integrated simulator pass completed

Related

Implementation, integration, and fresh review: GPT-5.6 Sol in T3 Code.


Note

Medium Risk
Touches core composer input and async attachment ingestion with lifecycle cancellation; behavior is well-tested but regressions in paste, limits, or draft/project context switches would affect every send path on iOS.

Overview
Enables Paste for copied screenshots/photos in the iOS chat composer by swapping the SwiftUI TextField for a UIKit-backed FeatureComposerUITextView that advertises image paste types and routes image providers through the same ingestion path as Photos, Camera, and Files.

Paste and attachments: Mixed pasteboards still insert plain text (via FeatureComposerPasteTextPolicy) while images load in a serialized FeatureComposerPasteQueue, respect the shared eight-image cap (FeatureImageAttachmentPolicy.reserve / attachmentsToAppend), and surface alerts on limit or partial failure. Image detection uses UTType.image conformance so HEIC-style items still show Paste at capacity.

Lifecycle:FeatureAttachmentLifecycle tokens tied to attachmentContextID (thread or project) cancel stale picker, camera, file, and paste work on context change or send; NewThreadView shares one lifecycle across project switches.

Composer UX: Trigger replacements and empty-to-restored draft updates set caret position with UTF-16-aware selection policy; the text field grows within a bounded viewport. Focused unit tests and brief user docs cover the new behavior.

Reviewed by Cursor Bugbot for commit 9fc22e1. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Add image paste support to the iOS chat composer

  • Subclasses UITextView as FeatureComposerUITextView to intercept paste events, exposing the system paste menu for images and inserting any coexisting plain text before queuing image attachments.
  • Introduces FeatureComposerPasteQueue to serialize and cancel pending paste operations when the attachment context changes or a message is sent.
  • Enforces an 8-image limit across concurrent picker and paste flows via FeatureImageAttachmentPolicy and FeatureAttachmentPreparationState.reserve; excess images are dropped and the user sees an alert.
  • Replaces the SwiftUI TextField with a new FeatureComposerTextInput (UIViewRepresentable) that grows to a viewport-dependent max height and preserves caret position after autocomplete insertions.
  • Attachment context is now bound to thread/project ID so in-flight async operations are invalidated on context changes.

Macroscope summarized 9fc22e1.

Delivery: direct
Validated against Theo commit: f98cab5
Depends on: none
Merge order: this PR only
Validation status: Mergeable; native/repository checks and current review are green. The unrelated Vercel authorization failure is a maintainer-side gate.

@coderabbitai

coderabbitaiBot commented Aug 7, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 3b9d22c2-4390-4d41-9896-e3e89f4adb83

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:L 100-499 changed lines (additions + deletions). size:XL 500-999 changed lines (additions + deletions). and removed size:L 100-499 changed lines (additions + deletions). labels Aug 7, 2026
Comment threadapps/swift-ios/Features/Chat/FeatureComposerView.swift
@saphid
saphidforce-pushed the agent/swiftui-image-paste branch from 0f6efd1 to 7ea541dCompareAugust 8, 2026 01:16
@github-actionsgithub-actionsBot added size:XXL 1,000+ changed lines (additions + deletions). and removed size:XL 500-999 changed lines (additions + deletions). labels Aug 8, 2026
@saphid
saphidforce-pushed the agent/swiftui-image-paste branch 2 times, most recently from 8f34edd to 388ce56CompareAugust 8, 2026 22:47
@t3dotgg

Copy link
Copy Markdown
Member

Note

🤖 GPT-5.6 responding on behalf of Theo

/recheck-vouch

@github-actionsgithub-actionsBot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. and removed vouch:unvouched PR author is not yet trusted in the VOUCHED list. labels Aug 9, 2026
@t3dotgg
t3dotggforce-pushed the t3code/rebuild-mobile-app-swift branch from 65e66ee to 4df1e9bCompareAugust 9, 2026 02:26
@saphid
saphidforce-pushed the agent/swiftui-image-paste branch from 388ce56 to 08cc37cCompareAugust 9, 2026 03:26
@saphid

Copy link
Copy Markdown
ContributorAuthor

Rebased this draft onto the signed SwiftUI base rewrite at 4df1e9b. All nine PR commits replayed cleanly and range-diff is patch-identical. GitHub now reports the intended 7-file diff (1,118 additions, 74 deletions). Verification: 24 focused Xcode tests passed, 0 failed; git diff --check passed. New tip: 08cc37c15.

Comment threadapps/swift-ios/Features/Chat/FeatureComposerView.swift
@saphid
saphidforce-pushed the agent/swiftui-image-paste branch from 08cc37c to f5da001CompareAugust 9, 2026 12:32
@github-actionsgithub-actionsBot added size:XL 500-999 changed lines (additions + deletions). and removed size:XXL 1,000+ changed lines (additions + deletions). labels Aug 9, 2026
@saphid
saphidforce-pushed the agent/swiftui-image-paste branch from f5da001 to 46b4c62CompareAugust 9, 2026 12:39
@saphid
saphid marked this pull request as ready for review August 9, 2026 12:43
@saphid

saphid commented Aug 9, 2026

Copy link
Copy Markdown
ContributorAuthor

Ready for maintainer review at 7dd058199 on base 0d0c77431.

  • The late exact-head Cursor caret finding was reproduced, fixed, regression-tested, replied to, and resolved.
  • Focused attachment/composer suites: 22 passed. Full apps/swift-ios/Scripts/ci-test.sh: 228 tests in 27 suites passed. Signed simulator build/install/launch passed.
  • Exact-head SwiftUI native tests, CI Check/Test, Mobile Native Static Analysis, Release Smoke, Macroscope Correctness, and Cursor Bugbot passed.
  • Macroscope Approvability completed neutral with the expected verdict that this user-facing feature needs human review; it reported no new correctness issue. CodeRabbit still explicitly says its review was skipped and is not counted as a review.
  • The remaining Vercel marketing status is the same authorization failure, unrelated to this seven-file SwiftUI-only range. GitHub reports the PR non-draft, mergeable, vouch:trusted, and size:XL at 999 changed lines.
  • The PR body retains immutable publicly rendered screenshots and a verified playable interaction video. The current live audit has no unresolved review threads.

Only human maintainer review/merge remains.

Comment threadapps/swift-ios/Features/Chat/FeatureComposerView.swift
@macroscopeapp

macroscopeappBot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

This PR adds a substantial new feature (image paste support from iOS edit menu) with ~900 lines of new code including custom UITextView paste handling, lifecycle management, and batch image processing. New user-facing capabilities of this scope warrant human review.

You can customize Macroscope's approvability policy. Learn more.

@saphid

Copy link
Copy Markdown
ContributorAuthor

@t3dotgg This SwiftUI PR is ready for your review. Its exact head is mergeable; repository/native CI, MacroScope, Cursor, and review-thread audits are clean with zero unresolved threads. The only red status is the unrelated Vercel marketing authorization check.

@t3dotgg
t3dotggforce-pushed the t3code/rebuild-mobile-app-swift branch from 4cb3307 to 497f54fCompareAugust 10, 2026 03:58
@github-actionsgithub-actionsBot added size:XXL 1,000+ changed lines (additions + deletions). and removed size:XL 500-999 changed lines (additions + deletions). labels Aug 10, 2026
@saphid

Copy link
Copy Markdown
ContributorAuthor

Added the tall-draft follow-up in a6d78788e. The UIKit composer now remains internally scrollable, keeps programmatic caret moves visible, and grows only up to half the proposed viewport (with a 12-line fallback when the proposal is unavailable), so long drafts stay reachable without displacing the transcript. apps/swift-ios/Scripts/ci-test.sh passes 230 tests. A fresh Claude Opus 5 high review found no remaining defect in the paste/tall-composer interaction.

@saphid

Copy link
Copy Markdown
ContributorAuthor

Follow-up simulator evidence for the tall-composer continuation:

Very tall draft remains reachable above the software keyboard

Verified on iOS 26.5 with the software keyboard enabled: the restored multi-line draft scrolls/grows without making its bottom controls unreachable.

@saphid
saphidforce-pushed the agent/swiftui-image-paste branch from a6d7878 to f7987c6CompareAugust 10, 2026 10:23
Comment threadapps/swift-ios/Features/Chat/FeatureComposerView.swift Outdated
Comment threadapps/swift-ios/Features/Chat/FeatureComposerView.swift

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit d3c6ddc. Configure here.

Comment threadapps/swift-ios/Features/Chat/FeatureComposerView.swift Outdated
@saphid

Copy link
Copy Markdown
ContributorAuthor

Added two focused acceptance tests for the final editor outcome, on top of the current live PR head (including its latest UTF-16/NUL paste fix). No production code changed in this update.

The tests prove that visible composer height grows beyond three lines before its viewport bound, while content remains unlimited after visible height caps.

Integrated iOS 26.5 proof used a 516-character New Task draft: it grew, capped at 50% of the viewport, scrolled internally with the caret at the end, and kept attachment/model/send semantic targets reachable. Private video: https://alexs-macbook-pro-1.tail4e5636.ts.net:8766/swiftui-final-editor-growth-keyboard-proof-20260810.mp4

Post-update verification: focused Composer+Attachment 26/26; full native 237 tests/28 suites; git diff --check clean. Direct Opus review was attempted twice but unavailable: one aborted stream and one real exit 1 / HTTP 429 session limit. No completed independent verdict is claimed; the change is test-only and parent self-audit found no actionable issue.

This is the acceptance evidence for closing #5801 as superseded. #5829's one-line keyboard cap remains intentionally excluded because it conflicts with this final invariant.

t3-code[bot]
t3-codeBot approved these changes Aug 12, 2026

@t3-codet3-codeBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reviewed the full composer paste and attachment lifecycle diff, including context rotation, capacity handling, text decoding, caret restoration, and focused tests. no blocking issues found.

@t3dotgg

Copy link
Copy Markdown
Member

Resolve conflicts and re-run ci

@saphid

Copy link
Copy Markdown
ContributorAuthor

Closing this version while I rebuild the upstream contribution set from the latest base. Clean versions are coming soon.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL1,000+ changed lines (additions + deletions).vouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@saphid@t3dotgg
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(ios): support image paste from composer edit menu - #5610

Closed
saphid wants to merge 10 commits into
pingdotgg:t3code/rebuild-mobile-app-swiftfrom
saphid:agent/swiftui-image-paste
Closed

fix(ios): support image paste from composer edit menu#5610
saphid wants to merge 10 commits into
pingdotgg:t3code/rebuild-mobile-app-swiftfrom
saphid:agent/swiftui-image-paste

Conversation

@saphid

@saphidsaphid commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

What changed

  • Replace the SwiftUI composer field with a small UIKit-backed UITextView so copied images appear in the native long-press Paste menu.
  • Keep ordinary text paste unchanged, preserve text from mixed image/text pasteboard items, and keep command, model, skill, and path replacement caret placement correct.
  • Send pasted image providers through the existing image processor and attachment strip, preserving successful providers when another provider fails.
  • Reserve the shared eight-image capacity across in-flight picker, camera, Files, and paste work, and reject callbacks captured for a stale composer context.

The patch is limited to the SwiftUI iOS composer and attachment ingestion, plus focused tests and user documentation. It is stacked on the experimental SwiftUI client in #5178. The branch is rebased on 0d0c77431, which includes f79886039 and its native-CI repair.

Why

The SwiftUI field accepted pasted text but did not offer Paste for a copied screenshot or photo. A UIKit text responder can advertise image and text paste types through the standard iOS edit menu, then hand image providers to the same preparation path as the existing attachment picker.

UI evidence

Before: copied image, no PasteAfter: native Paste action
Before: long-press edit menu without PasteAfter: long-press edit menu with Paste

Resulting attachment

Copied image appears in the attachment strip

Eight-image limit

A further paste remains at eight attachments and shows the limit alert

Image-conforming provider regression

A HEIC-conforming pasteboard item still exposes Paste at the eight-image limit

Interaction video: native Paste action to attachment (10.97 seconds)

The four primary images and video were re-downloaded from the immutable evidence commit and matched their local SHA-256 hashes. The video was identified as H.264 at 1206×2622 and played in T3's collaborative preview. The HEIC regression image was captured from the final signed build after the Macroscope fix.

Validation

  • AttachmentPreparationTests + FeatureComposerPowerTests: 22 passed, 0 failed on the frozen diff after the review fixes.
  • T3_SWIFT_SIMULATOR_ID=… apps/swift-ios/Scripts/ci-test.sh: 228 tests in 27 suites, 0 failures. Existing unrelated simulator warnings remained visible; no test was weakened.
  • node scripts/generate-swift-wire-fixtures.ts --check: passed on the final diff, verifying the earlier native-CI fixture failure is repaired by the current stacking base.
  • Final signed Xcode 26.6 build, install, and launch on an iPhone 17 Pro simulator running iOS 26.5: passed.
  • Integrated UI: native menu and text-only paste; image-only paste to one attachment; mixed paste to text plus one attachment; text inserted at a nonterminal caret; nine-image paste capped at eight; and a further paste at capacity remained at eight with the limit alert.
  • Focused simulator tests cover shared pending capacity, partial-provider success, stale lifecycle tokens used by picker/camera/paste callbacks, provider loading, draft restoration, and UTF-16 caret restoration.
  • git diff --check: passed. Final range is four commits and 999 changed lines (915 additions, 84 deletions), reduced from 1,299 by removing the generic task store and duplicate test seams.
  • Fresh GPT-5.6 Sol high minimum-scope review inspected the frozen range and found one actionable issue: image interception was being disabled once eight attachments were present. Macroscope then found that hasImages misses some image-conforming providers, reproduced with public.heic. The final patch keeps interception active at capacity and detects UTType.image conformance. A late exact-head Cursor finding then reproduced an empty-to-restored-text caret jump; the fix now places that caret at the UTF-16 end while preserving ordinary selections. Affected tests and the signed integrated pass were repeated.

Checklist

  • Single-purpose SwiftUI image-paste change, minimized to the reliable behavior and its proof
  • Exact behavior and rationale described
  • Before/after and resulting-state screenshots included
  • Short interaction video included and playback verified
  • Focused tests, full native script, fixture check, and integrated simulator pass completed

Related

Implementation, integration, and fresh review: GPT-5.6 Sol in T3 Code.


Note

Medium Risk
Touches core composer input and async attachment ingestion with lifecycle cancellation; behavior is well-tested but regressions in paste, limits, or draft/project context switches would affect every send path on iOS.

Overview
Enables Paste for copied screenshots/photos in the iOS chat composer by swapping the SwiftUI TextField for a UIKit-backed FeatureComposerUITextView that advertises image paste types and routes image providers through the same ingestion path as Photos, Camera, and Files.

Paste and attachments: Mixed pasteboards still insert plain text (via FeatureComposerPasteTextPolicy) while images load in a serialized FeatureComposerPasteQueue, respect the shared eight-image cap (FeatureImageAttachmentPolicy.reserve / attachmentsToAppend), and surface alerts on limit or partial failure. Image detection uses UTType.image conformance so HEIC-style items still show Paste at capacity.

Lifecycle:FeatureAttachmentLifecycle tokens tied to attachmentContextID (thread or project) cancel stale picker, camera, file, and paste work on context change or send; NewThreadView shares one lifecycle across project switches.

Composer UX: Trigger replacements and empty-to-restored draft updates set caret position with UTF-16-aware selection policy; the text field grows within a bounded viewport. Focused unit tests and brief user docs cover the new behavior.

Reviewed by Cursor Bugbot for commit 9fc22e1. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Add image paste support to the iOS chat composer

  • Subclasses UITextView as FeatureComposerUITextView to intercept paste events, exposing the system paste menu for images and inserting any coexisting plain text before queuing image attachments.
  • Introduces FeatureComposerPasteQueue to serialize and cancel pending paste operations when the attachment context changes or a message is sent.
  • Enforces an 8-image limit across concurrent picker and paste flows via FeatureImageAttachmentPolicy and FeatureAttachmentPreparationState.reserve; excess images are dropped and the user sees an alert.
  • Replaces the SwiftUI TextField with a new FeatureComposerTextInput (UIViewRepresentable) that grows to a viewport-dependent max height and preserves caret position after autocomplete insertions.
  • Attachment context is now bound to thread/project ID so in-flight async operations are invalidated on context changes.

Macroscope summarized 9fc22e1.

Delivery: direct
Validated against Theo commit: f98cab5
Depends on: none
Merge order: this PR only
Validation status: Mergeable; native/repository checks and current review are green. The unrelated Vercel authorization failure is a maintainer-side gate.

@coderabbitai

coderabbitaiBot commented Aug 7, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 3b9d22c2-4390-4d41-9896-e3e89f4adb83

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:L 100-499 changed lines (additions + deletions). size:XL 500-999 changed lines (additions + deletions). and removed size:L 100-499 changed lines (additions + deletions). labels Aug 7, 2026
Comment threadapps/swift-ios/Features/Chat/FeatureComposerView.swift
@saphid
saphidforce-pushed the agent/swiftui-image-paste branch from 0f6efd1 to 7ea541dCompareAugust 8, 2026 01:16
@github-actionsgithub-actionsBot added size:XXL 1,000+ changed lines (additions + deletions). and removed size:XL 500-999 changed lines (additions + deletions). labels Aug 8, 2026
@saphid
saphidforce-pushed the agent/swiftui-image-paste branch 2 times, most recently from 8f34edd to 388ce56CompareAugust 8, 2026 22:47
@t3dotgg

Copy link
Copy Markdown
Member

Note

🤖 GPT-5.6 responding on behalf of Theo

/recheck-vouch

@github-actionsgithub-actionsBot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. and removed vouch:unvouched PR author is not yet trusted in the VOUCHED list. labels Aug 9, 2026
@t3dotgg
t3dotggforce-pushed the t3code/rebuild-mobile-app-swift branch from 65e66ee to 4df1e9bCompareAugust 9, 2026 02:26
@saphid
saphidforce-pushed the agent/swiftui-image-paste branch from 388ce56 to 08cc37cCompareAugust 9, 2026 03:26
@saphid

Copy link
Copy Markdown
ContributorAuthor

Rebased this draft onto the signed SwiftUI base rewrite at 4df1e9b. All nine PR commits replayed cleanly and range-diff is patch-identical. GitHub now reports the intended 7-file diff (1,118 additions, 74 deletions). Verification: 24 focused Xcode tests passed, 0 failed; git diff --check passed. New tip: 08cc37c15.

Comment threadapps/swift-ios/Features/Chat/FeatureComposerView.swift
@saphid
saphidforce-pushed the agent/swiftui-image-paste branch from 08cc37c to f5da001CompareAugust 9, 2026 12:32
@github-actionsgithub-actionsBot added size:XL 500-999 changed lines (additions + deletions). and removed size:XXL 1,000+ changed lines (additions + deletions). labels Aug 9, 2026
@saphid
saphidforce-pushed the agent/swiftui-image-paste branch from f5da001 to 46b4c62CompareAugust 9, 2026 12:39
@saphid
saphid marked this pull request as ready for review August 9, 2026 12:43
@saphid

saphid commented Aug 9, 2026

Copy link
Copy Markdown
ContributorAuthor

Ready for maintainer review at 7dd058199 on base 0d0c77431.

  • The late exact-head Cursor caret finding was reproduced, fixed, regression-tested, replied to, and resolved.
  • Focused attachment/composer suites: 22 passed. Full apps/swift-ios/Scripts/ci-test.sh: 228 tests in 27 suites passed. Signed simulator build/install/launch passed.
  • Exact-head SwiftUI native tests, CI Check/Test, Mobile Native Static Analysis, Release Smoke, Macroscope Correctness, and Cursor Bugbot passed.
  • Macroscope Approvability completed neutral with the expected verdict that this user-facing feature needs human review; it reported no new correctness issue. CodeRabbit still explicitly says its review was skipped and is not counted as a review.
  • The remaining Vercel marketing status is the same authorization failure, unrelated to this seven-file SwiftUI-only range. GitHub reports the PR non-draft, mergeable, vouch:trusted, and size:XL at 999 changed lines.
  • The PR body retains immutable publicly rendered screenshots and a verified playable interaction video. The current live audit has no unresolved review threads.

Only human maintainer review/merge remains.

Comment threadapps/swift-ios/Features/Chat/FeatureComposerView.swift
@macroscopeapp

macroscopeappBot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

This PR adds a substantial new feature (image paste support from iOS edit menu) with ~900 lines of new code including custom UITextView paste handling, lifecycle management, and batch image processing. New user-facing capabilities of this scope warrant human review.

You can customize Macroscope's approvability policy. Learn more.

@saphid

Copy link
Copy Markdown
ContributorAuthor

@t3dotgg This SwiftUI PR is ready for your review. Its exact head is mergeable; repository/native CI, MacroScope, Cursor, and review-thread audits are clean with zero unresolved threads. The only red status is the unrelated Vercel marketing authorization check.

@t3dotgg
t3dotggforce-pushed the t3code/rebuild-mobile-app-swift branch from 4cb3307 to 497f54fCompareAugust 10, 2026 03:58
@github-actionsgithub-actionsBot added size:XXL 1,000+ changed lines (additions + deletions). and removed size:XL 500-999 changed lines (additions + deletions). labels Aug 10, 2026
@saphid

Copy link
Copy Markdown
ContributorAuthor

Added the tall-draft follow-up in a6d78788e. The UIKit composer now remains internally scrollable, keeps programmatic caret moves visible, and grows only up to half the proposed viewport (with a 12-line fallback when the proposal is unavailable), so long drafts stay reachable without displacing the transcript. apps/swift-ios/Scripts/ci-test.sh passes 230 tests. A fresh Claude Opus 5 high review found no remaining defect in the paste/tall-composer interaction.

@saphid

Copy link
Copy Markdown
ContributorAuthor

Follow-up simulator evidence for the tall-composer continuation:

Very tall draft remains reachable above the software keyboard

Verified on iOS 26.5 with the software keyboard enabled: the restored multi-line draft scrolls/grows without making its bottom controls unreachable.

@saphid
saphidforce-pushed the agent/swiftui-image-paste branch from a6d7878 to f7987c6CompareAugust 10, 2026 10:23
Comment threadapps/swift-ios/Features/Chat/FeatureComposerView.swift Outdated
Comment threadapps/swift-ios/Features/Chat/FeatureComposerView.swift

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit d3c6ddc. Configure here.

Comment threadapps/swift-ios/Features/Chat/FeatureComposerView.swift Outdated
@saphid

Copy link
Copy Markdown
ContributorAuthor

Added two focused acceptance tests for the final editor outcome, on top of the current live PR head (including its latest UTF-16/NUL paste fix). No production code changed in this update.

The tests prove that visible composer height grows beyond three lines before its viewport bound, while content remains unlimited after visible height caps.

Integrated iOS 26.5 proof used a 516-character New Task draft: it grew, capped at 50% of the viewport, scrolled internally with the caret at the end, and kept attachment/model/send semantic targets reachable. Private video: https://alexs-macbook-pro-1.tail4e5636.ts.net:8766/swiftui-final-editor-growth-keyboard-proof-20260810.mp4

Post-update verification: focused Composer+Attachment 26/26; full native 237 tests/28 suites; git diff --check clean. Direct Opus review was attempted twice but unavailable: one aborted stream and one real exit 1 / HTTP 429 session limit. No completed independent verdict is claimed; the change is test-only and parent self-audit found no actionable issue.

This is the acceptance evidence for closing #5801 as superseded. #5829's one-line keyboard cap remains intentionally excluded because it conflicts with this final invariant.

t3-code[bot]
t3-codeBot approved these changes Aug 12, 2026

@t3-codet3-codeBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reviewed the full composer paste and attachment lifecycle diff, including context rotation, capacity handling, text decoding, caret restoration, and focused tests. no blocking issues found.

@t3dotgg

Copy link
Copy Markdown
Member

Resolve conflicts and re-run ci

@saphid

Copy link
Copy Markdown
ContributorAuthor

Closing this version while I rebuild the upstream contribution set from the latest base. Clean versions are coming soon.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL1,000+ changed lines (additions + deletions).vouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@saphid@t3dotgg
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

fix(ios): support image paste from composer edit menu - #5610

Closed
saphid wants to merge 10 commits into
pingdotgg:t3code/rebuild-mobile-app-swiftfrom
saphid:agent/swiftui-image-paste
Closed

fix(ios): support image paste from composer edit menu#5610
saphid wants to merge 10 commits into
pingdotgg:t3code/rebuild-mobile-app-swiftfrom
saphid:agent/swiftui-image-paste

Conversation

@saphid

@saphidsaphid commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

What changed

  • Replace the SwiftUI composer field with a small UIKit-backed UITextView so copied images appear in the native long-press Paste menu.
  • Keep ordinary text paste unchanged, preserve text from mixed image/text pasteboard items, and keep command, model, skill, and path replacement caret placement correct.
  • Send pasted image providers through the existing image processor and attachment strip, preserving successful providers when another provider fails.
  • Reserve the shared eight-image capacity across in-flight picker, camera, Files, and paste work, and reject callbacks captured for a stale composer context.

The patch is limited to the SwiftUI iOS composer and attachment ingestion, plus focused tests and user documentation. It is stacked on the experimental SwiftUI client in #5178. The branch is rebased on 0d0c77431, which includes f79886039 and its native-CI repair.

Why

The SwiftUI field accepted pasted text but did not offer Paste for a copied screenshot or photo. A UIKit text responder can advertise image and text paste types through the standard iOS edit menu, then hand image providers to the same preparation path as the existing attachment picker.

UI evidence

Before: copied image, no PasteAfter: native Paste action
Before: long-press edit menu without PasteAfter: long-press edit menu with Paste

Resulting attachment

Copied image appears in the attachment strip

Eight-image limit

A further paste remains at eight attachments and shows the limit alert

Image-conforming provider regression

A HEIC-conforming pasteboard item still exposes Paste at the eight-image limit

Interaction video: native Paste action to attachment (10.97 seconds)

The four primary images and video were re-downloaded from the immutable evidence commit and matched their local SHA-256 hashes. The video was identified as H.264 at 1206×2622 and played in T3's collaborative preview. The HEIC regression image was captured from the final signed build after the Macroscope fix.

Validation

  • AttachmentPreparationTests + FeatureComposerPowerTests: 22 passed, 0 failed on the frozen diff after the review fixes.
  • T3_SWIFT_SIMULATOR_ID=… apps/swift-ios/Scripts/ci-test.sh: 228 tests in 27 suites, 0 failures. Existing unrelated simulator warnings remained visible; no test was weakened.
  • node scripts/generate-swift-wire-fixtures.ts --check: passed on the final diff, verifying the earlier native-CI fixture failure is repaired by the current stacking base.
  • Final signed Xcode 26.6 build, install, and launch on an iPhone 17 Pro simulator running iOS 26.5: passed.
  • Integrated UI: native menu and text-only paste; image-only paste to one attachment; mixed paste to text plus one attachment; text inserted at a nonterminal caret; nine-image paste capped at eight; and a further paste at capacity remained at eight with the limit alert.
  • Focused simulator tests cover shared pending capacity, partial-provider success, stale lifecycle tokens used by picker/camera/paste callbacks, provider loading, draft restoration, and UTF-16 caret restoration.
  • git diff --check: passed. Final range is four commits and 999 changed lines (915 additions, 84 deletions), reduced from 1,299 by removing the generic task store and duplicate test seams.
  • Fresh GPT-5.6 Sol high minimum-scope review inspected the frozen range and found one actionable issue: image interception was being disabled once eight attachments were present. Macroscope then found that hasImages misses some image-conforming providers, reproduced with public.heic. The final patch keeps interception active at capacity and detects UTType.image conformance. A late exact-head Cursor finding then reproduced an empty-to-restored-text caret jump; the fix now places that caret at the UTF-16 end while preserving ordinary selections. Affected tests and the signed integrated pass were repeated.

Checklist

  • Single-purpose SwiftUI image-paste change, minimized to the reliable behavior and its proof
  • Exact behavior and rationale described
  • Before/after and resulting-state screenshots included
  • Short interaction video included and playback verified
  • Focused tests, full native script, fixture check, and integrated simulator pass completed

Related

Implementation, integration, and fresh review: GPT-5.6 Sol in T3 Code.


Note

Medium Risk
Touches core composer input and async attachment ingestion with lifecycle cancellation; behavior is well-tested but regressions in paste, limits, or draft/project context switches would affect every send path on iOS.

Overview
Enables Paste for copied screenshots/photos in the iOS chat composer by swapping the SwiftUI TextField for a UIKit-backed FeatureComposerUITextView that advertises image paste types and routes image providers through the same ingestion path as Photos, Camera, and Files.

Paste and attachments: Mixed pasteboards still insert plain text (via FeatureComposerPasteTextPolicy) while images load in a serialized FeatureComposerPasteQueue, respect the shared eight-image cap (FeatureImageAttachmentPolicy.reserve / attachmentsToAppend), and surface alerts on limit or partial failure. Image detection uses UTType.image conformance so HEIC-style items still show Paste at capacity.

Lifecycle:FeatureAttachmentLifecycle tokens tied to attachmentContextID (thread or project) cancel stale picker, camera, file, and paste work on context change or send; NewThreadView shares one lifecycle across project switches.

Composer UX: Trigger replacements and empty-to-restored draft updates set caret position with UTF-16-aware selection policy; the text field grows within a bounded viewport. Focused unit tests and brief user docs cover the new behavior.

Reviewed by Cursor Bugbot for commit 9fc22e1. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Add image paste support to the iOS chat composer

  • Subclasses UITextView as FeatureComposerUITextView to intercept paste events, exposing the system paste menu for images and inserting any coexisting plain text before queuing image attachments.
  • Introduces FeatureComposerPasteQueue to serialize and cancel pending paste operations when the attachment context changes or a message is sent.
  • Enforces an 8-image limit across concurrent picker and paste flows via FeatureImageAttachmentPolicy and FeatureAttachmentPreparationState.reserve; excess images are dropped and the user sees an alert.
  • Replaces the SwiftUI TextField with a new FeatureComposerTextInput (UIViewRepresentable) that grows to a viewport-dependent max height and preserves caret position after autocomplete insertions.
  • Attachment context is now bound to thread/project ID so in-flight async operations are invalidated on context changes.

Macroscope summarized 9fc22e1.

Delivery: direct
Validated against Theo commit: f98cab5
Depends on: none
Merge order: this PR only
Validation status: Mergeable; native/repository checks and current review are green. The unrelated Vercel authorization failure is a maintainer-side gate.

@coderabbitai

coderabbitaiBot commented Aug 7, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 3b9d22c2-4390-4d41-9896-e3e89f4adb83

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:L 100-499 changed lines (additions + deletions). size:XL 500-999 changed lines (additions + deletions). and removed size:L 100-499 changed lines (additions + deletions). labels Aug 7, 2026
Comment threadapps/swift-ios/Features/Chat/FeatureComposerView.swift
@saphid
saphidforce-pushed the agent/swiftui-image-paste branch from 0f6efd1 to 7ea541dCompareAugust 8, 2026 01:16
@github-actionsgithub-actionsBot added size:XXL 1,000+ changed lines (additions + deletions). and removed size:XL 500-999 changed lines (additions + deletions). labels Aug 8, 2026
@saphid
saphidforce-pushed the agent/swiftui-image-paste branch 2 times, most recently from 8f34edd to 388ce56CompareAugust 8, 2026 22:47
@t3dotgg

Copy link
Copy Markdown
Member

Note

🤖 GPT-5.6 responding on behalf of Theo

/recheck-vouch

@github-actionsgithub-actionsBot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. and removed vouch:unvouched PR author is not yet trusted in the VOUCHED list. labels Aug 9, 2026
@t3dotgg
t3dotggforce-pushed the t3code/rebuild-mobile-app-swift branch from 65e66ee to 4df1e9bCompareAugust 9, 2026 02:26
@saphid
saphidforce-pushed the agent/swiftui-image-paste branch from 388ce56 to 08cc37cCompareAugust 9, 2026 03:26
@saphid

Copy link
Copy Markdown
ContributorAuthor

Rebased this draft onto the signed SwiftUI base rewrite at 4df1e9b. All nine PR commits replayed cleanly and range-diff is patch-identical. GitHub now reports the intended 7-file diff (1,118 additions, 74 deletions). Verification: 24 focused Xcode tests passed, 0 failed; git diff --check passed. New tip: 08cc37c15.

Comment threadapps/swift-ios/Features/Chat/FeatureComposerView.swift
@saphid
saphidforce-pushed the agent/swiftui-image-paste branch from 08cc37c to f5da001CompareAugust 9, 2026 12:32
@github-actionsgithub-actionsBot added size:XL 500-999 changed lines (additions + deletions). and removed size:XXL 1,000+ changed lines (additions + deletions). labels Aug 9, 2026
@saphid
saphidforce-pushed the agent/swiftui-image-paste branch from f5da001 to 46b4c62CompareAugust 9, 2026 12:39
@saphid
saphid marked this pull request as ready for review August 9, 2026 12:43
@saphid

saphid commented Aug 9, 2026

Copy link
Copy Markdown
ContributorAuthor

Ready for maintainer review at 7dd058199 on base 0d0c77431.

  • The late exact-head Cursor caret finding was reproduced, fixed, regression-tested, replied to, and resolved.
  • Focused attachment/composer suites: 22 passed. Full apps/swift-ios/Scripts/ci-test.sh: 228 tests in 27 suites passed. Signed simulator build/install/launch passed.
  • Exact-head SwiftUI native tests, CI Check/Test, Mobile Native Static Analysis, Release Smoke, Macroscope Correctness, and Cursor Bugbot passed.
  • Macroscope Approvability completed neutral with the expected verdict that this user-facing feature needs human review; it reported no new correctness issue. CodeRabbit still explicitly says its review was skipped and is not counted as a review.
  • The remaining Vercel marketing status is the same authorization failure, unrelated to this seven-file SwiftUI-only range. GitHub reports the PR non-draft, mergeable, vouch:trusted, and size:XL at 999 changed lines.
  • The PR body retains immutable publicly rendered screenshots and a verified playable interaction video. The current live audit has no unresolved review threads.

Only human maintainer review/merge remains.

Comment threadapps/swift-ios/Features/Chat/FeatureComposerView.swift
@macroscopeapp

macroscopeappBot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

This PR adds a substantial new feature (image paste support from iOS edit menu) with ~900 lines of new code including custom UITextView paste handling, lifecycle management, and batch image processing. New user-facing capabilities of this scope warrant human review.

You can customize Macroscope's approvability policy. Learn more.

@saphid

Copy link
Copy Markdown
ContributorAuthor

@t3dotgg This SwiftUI PR is ready for your review. Its exact head is mergeable; repository/native CI, MacroScope, Cursor, and review-thread audits are clean with zero unresolved threads. The only red status is the unrelated Vercel marketing authorization check.

@t3dotgg
t3dotggforce-pushed the t3code/rebuild-mobile-app-swift branch from 4cb3307 to 497f54fCompareAugust 10, 2026 03:58
@github-actionsgithub-actionsBot added size:XXL 1,000+ changed lines (additions + deletions). and removed size:XL 500-999 changed lines (additions + deletions). labels Aug 10, 2026
@saphid

Copy link
Copy Markdown
ContributorAuthor

Added the tall-draft follow-up in a6d78788e. The UIKit composer now remains internally scrollable, keeps programmatic caret moves visible, and grows only up to half the proposed viewport (with a 12-line fallback when the proposal is unavailable), so long drafts stay reachable without displacing the transcript. apps/swift-ios/Scripts/ci-test.sh passes 230 tests. A fresh Claude Opus 5 high review found no remaining defect in the paste/tall-composer interaction.

@saphid

Copy link
Copy Markdown
ContributorAuthor

Follow-up simulator evidence for the tall-composer continuation:

Very tall draft remains reachable above the software keyboard

Verified on iOS 26.5 with the software keyboard enabled: the restored multi-line draft scrolls/grows without making its bottom controls unreachable.

@saphid
saphidforce-pushed the agent/swiftui-image-paste branch from a6d7878 to f7987c6CompareAugust 10, 2026 10:23
Comment threadapps/swift-ios/Features/Chat/FeatureComposerView.swift Outdated
Comment threadapps/swift-ios/Features/Chat/FeatureComposerView.swift

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit d3c6ddc. Configure here.

Comment threadapps/swift-ios/Features/Chat/FeatureComposerView.swift Outdated
@saphid

Copy link
Copy Markdown
ContributorAuthor

Added two focused acceptance tests for the final editor outcome, on top of the current live PR head (including its latest UTF-16/NUL paste fix). No production code changed in this update.

The tests prove that visible composer height grows beyond three lines before its viewport bound, while content remains unlimited after visible height caps.

Integrated iOS 26.5 proof used a 516-character New Task draft: it grew, capped at 50% of the viewport, scrolled internally with the caret at the end, and kept attachment/model/send semantic targets reachable. Private video: https://alexs-macbook-pro-1.tail4e5636.ts.net:8766/swiftui-final-editor-growth-keyboard-proof-20260810.mp4

Post-update verification: focused Composer+Attachment 26/26; full native 237 tests/28 suites; git diff --check clean. Direct Opus review was attempted twice but unavailable: one aborted stream and one real exit 1 / HTTP 429 session limit. No completed independent verdict is claimed; the change is test-only and parent self-audit found no actionable issue.

This is the acceptance evidence for closing #5801 as superseded. #5829's one-line keyboard cap remains intentionally excluded because it conflicts with this final invariant.

t3-code[bot]
t3-codeBot approved these changes Aug 12, 2026

@t3-codet3-codeBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reviewed the full composer paste and attachment lifecycle diff, including context rotation, capacity handling, text decoding, caret restoration, and focused tests. no blocking issues found.

@t3dotgg

Copy link
Copy Markdown
Member

Resolve conflicts and re-run ci

@saphid

Copy link
Copy Markdown
ContributorAuthor

Closing this version while I rebuild the upstream contribution set from the latest base. Clean versions are coming soon.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL1,000+ changed lines (additions + deletions).vouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@saphid@t3dotgg
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(ios): support image paste from composer edit menu - #5610

Closed
saphid wants to merge 10 commits into
pingdotgg:t3code/rebuild-mobile-app-swiftfrom
saphid:agent/swiftui-image-paste
Closed

fix(ios): support image paste from composer edit menu#5610
saphid wants to merge 10 commits into
pingdotgg:t3code/rebuild-mobile-app-swiftfrom
saphid:agent/swiftui-image-paste

Conversation

@saphid

@saphidsaphid commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

What changed

  • Replace the SwiftUI composer field with a small UIKit-backed UITextView so copied images appear in the native long-press Paste menu.
  • Keep ordinary text paste unchanged, preserve text from mixed image/text pasteboard items, and keep command, model, skill, and path replacement caret placement correct.
  • Send pasted image providers through the existing image processor and attachment strip, preserving successful providers when another provider fails.
  • Reserve the shared eight-image capacity across in-flight picker, camera, Files, and paste work, and reject callbacks captured for a stale composer context.

The patch is limited to the SwiftUI iOS composer and attachment ingestion, plus focused tests and user documentation. It is stacked on the experimental SwiftUI client in #5178. The branch is rebased on 0d0c77431, which includes f79886039 and its native-CI repair.

Why

The SwiftUI field accepted pasted text but did not offer Paste for a copied screenshot or photo. A UIKit text responder can advertise image and text paste types through the standard iOS edit menu, then hand image providers to the same preparation path as the existing attachment picker.

UI evidence

Before: copied image, no PasteAfter: native Paste action
Before: long-press edit menu without PasteAfter: long-press edit menu with Paste

Resulting attachment

Copied image appears in the attachment strip

Eight-image limit

A further paste remains at eight attachments and shows the limit alert

Image-conforming provider regression

A HEIC-conforming pasteboard item still exposes Paste at the eight-image limit

Interaction video: native Paste action to attachment (10.97 seconds)

The four primary images and video were re-downloaded from the immutable evidence commit and matched their local SHA-256 hashes. The video was identified as H.264 at 1206×2622 and played in T3's collaborative preview. The HEIC regression image was captured from the final signed build after the Macroscope fix.

Validation

  • AttachmentPreparationTests + FeatureComposerPowerTests: 22 passed, 0 failed on the frozen diff after the review fixes.
  • T3_SWIFT_SIMULATOR_ID=… apps/swift-ios/Scripts/ci-test.sh: 228 tests in 27 suites, 0 failures. Existing unrelated simulator warnings remained visible; no test was weakened.
  • node scripts/generate-swift-wire-fixtures.ts --check: passed on the final diff, verifying the earlier native-CI fixture failure is repaired by the current stacking base.
  • Final signed Xcode 26.6 build, install, and launch on an iPhone 17 Pro simulator running iOS 26.5: passed.
  • Integrated UI: native menu and text-only paste; image-only paste to one attachment; mixed paste to text plus one attachment; text inserted at a nonterminal caret; nine-image paste capped at eight; and a further paste at capacity remained at eight with the limit alert.
  • Focused simulator tests cover shared pending capacity, partial-provider success, stale lifecycle tokens used by picker/camera/paste callbacks, provider loading, draft restoration, and UTF-16 caret restoration.
  • git diff --check: passed. Final range is four commits and 999 changed lines (915 additions, 84 deletions), reduced from 1,299 by removing the generic task store and duplicate test seams.
  • Fresh GPT-5.6 Sol high minimum-scope review inspected the frozen range and found one actionable issue: image interception was being disabled once eight attachments were present. Macroscope then found that hasImages misses some image-conforming providers, reproduced with public.heic. The final patch keeps interception active at capacity and detects UTType.image conformance. A late exact-head Cursor finding then reproduced an empty-to-restored-text caret jump; the fix now places that caret at the UTF-16 end while preserving ordinary selections. Affected tests and the signed integrated pass were repeated.

Checklist

  • Single-purpose SwiftUI image-paste change, minimized to the reliable behavior and its proof
  • Exact behavior and rationale described
  • Before/after and resulting-state screenshots included
  • Short interaction video included and playback verified
  • Focused tests, full native script, fixture check, and integrated simulator pass completed

Related

Implementation, integration, and fresh review: GPT-5.6 Sol in T3 Code.


Note

Medium Risk
Touches core composer input and async attachment ingestion with lifecycle cancellation; behavior is well-tested but regressions in paste, limits, or draft/project context switches would affect every send path on iOS.

Overview
Enables Paste for copied screenshots/photos in the iOS chat composer by swapping the SwiftUI TextField for a UIKit-backed FeatureComposerUITextView that advertises image paste types and routes image providers through the same ingestion path as Photos, Camera, and Files.

Paste and attachments: Mixed pasteboards still insert plain text (via FeatureComposerPasteTextPolicy) while images load in a serialized FeatureComposerPasteQueue, respect the shared eight-image cap (FeatureImageAttachmentPolicy.reserve / attachmentsToAppend), and surface alerts on limit or partial failure. Image detection uses UTType.image conformance so HEIC-style items still show Paste at capacity.

Lifecycle:FeatureAttachmentLifecycle tokens tied to attachmentContextID (thread or project) cancel stale picker, camera, file, and paste work on context change or send; NewThreadView shares one lifecycle across project switches.

Composer UX: Trigger replacements and empty-to-restored draft updates set caret position with UTF-16-aware selection policy; the text field grows within a bounded viewport. Focused unit tests and brief user docs cover the new behavior.

Reviewed by Cursor Bugbot for commit 9fc22e1. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Add image paste support to the iOS chat composer

  • Subclasses UITextView as FeatureComposerUITextView to intercept paste events, exposing the system paste menu for images and inserting any coexisting plain text before queuing image attachments.
  • Introduces FeatureComposerPasteQueue to serialize and cancel pending paste operations when the attachment context changes or a message is sent.
  • Enforces an 8-image limit across concurrent picker and paste flows via FeatureImageAttachmentPolicy and FeatureAttachmentPreparationState.reserve; excess images are dropped and the user sees an alert.
  • Replaces the SwiftUI TextField with a new FeatureComposerTextInput (UIViewRepresentable) that grows to a viewport-dependent max height and preserves caret position after autocomplete insertions.
  • Attachment context is now bound to thread/project ID so in-flight async operations are invalidated on context changes.

Macroscope summarized 9fc22e1.

Delivery: direct
Validated against Theo commit: f98cab5
Depends on: none
Merge order: this PR only
Validation status: Mergeable; native/repository checks and current review are green. The unrelated Vercel authorization failure is a maintainer-side gate.

@coderabbitai

coderabbitaiBot commented Aug 7, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 3b9d22c2-4390-4d41-9896-e3e89f4adb83

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:L 100-499 changed lines (additions + deletions). size:XL 500-999 changed lines (additions + deletions). and removed size:L 100-499 changed lines (additions + deletions). labels Aug 7, 2026
Comment threadapps/swift-ios/Features/Chat/FeatureComposerView.swift
@saphid
saphidforce-pushed the agent/swiftui-image-paste branch from 0f6efd1 to 7ea541dCompareAugust 8, 2026 01:16
@github-actionsgithub-actionsBot added size:XXL 1,000+ changed lines (additions + deletions). and removed size:XL 500-999 changed lines (additions + deletions). labels Aug 8, 2026
@saphid
saphidforce-pushed the agent/swiftui-image-paste branch 2 times, most recently from 8f34edd to 388ce56CompareAugust 8, 2026 22:47
@t3dotgg

Copy link
Copy Markdown
Member

Note

🤖 GPT-5.6 responding on behalf of Theo

/recheck-vouch

@github-actionsgithub-actionsBot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. and removed vouch:unvouched PR author is not yet trusted in the VOUCHED list. labels Aug 9, 2026
@t3dotgg
t3dotggforce-pushed the t3code/rebuild-mobile-app-swift branch from 65e66ee to 4df1e9bCompareAugust 9, 2026 02:26
@saphid
saphidforce-pushed the agent/swiftui-image-paste branch from 388ce56 to 08cc37cCompareAugust 9, 2026 03:26
@saphid

Copy link
Copy Markdown
ContributorAuthor

Rebased this draft onto the signed SwiftUI base rewrite at 4df1e9b. All nine PR commits replayed cleanly and range-diff is patch-identical. GitHub now reports the intended 7-file diff (1,118 additions, 74 deletions). Verification: 24 focused Xcode tests passed, 0 failed; git diff --check passed. New tip: 08cc37c15.

Comment threadapps/swift-ios/Features/Chat/FeatureComposerView.swift
@saphid
saphidforce-pushed the agent/swiftui-image-paste branch from 08cc37c to f5da001CompareAugust 9, 2026 12:32
@github-actionsgithub-actionsBot added size:XL 500-999 changed lines (additions + deletions). and removed size:XXL 1,000+ changed lines (additions + deletions). labels Aug 9, 2026
@saphid
saphidforce-pushed the agent/swiftui-image-paste branch from f5da001 to 46b4c62CompareAugust 9, 2026 12:39
@saphid
saphid marked this pull request as ready for review August 9, 2026 12:43
@saphid

saphid commented Aug 9, 2026

Copy link
Copy Markdown
ContributorAuthor

Ready for maintainer review at 7dd058199 on base 0d0c77431.

  • The late exact-head Cursor caret finding was reproduced, fixed, regression-tested, replied to, and resolved.
  • Focused attachment/composer suites: 22 passed. Full apps/swift-ios/Scripts/ci-test.sh: 228 tests in 27 suites passed. Signed simulator build/install/launch passed.
  • Exact-head SwiftUI native tests, CI Check/Test, Mobile Native Static Analysis, Release Smoke, Macroscope Correctness, and Cursor Bugbot passed.
  • Macroscope Approvability completed neutral with the expected verdict that this user-facing feature needs human review; it reported no new correctness issue. CodeRabbit still explicitly says its review was skipped and is not counted as a review.
  • The remaining Vercel marketing status is the same authorization failure, unrelated to this seven-file SwiftUI-only range. GitHub reports the PR non-draft, mergeable, vouch:trusted, and size:XL at 999 changed lines.
  • The PR body retains immutable publicly rendered screenshots and a verified playable interaction video. The current live audit has no unresolved review threads.

Only human maintainer review/merge remains.

Comment threadapps/swift-ios/Features/Chat/FeatureComposerView.swift
@macroscopeapp

macroscopeappBot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

This PR adds a substantial new feature (image paste support from iOS edit menu) with ~900 lines of new code including custom UITextView paste handling, lifecycle management, and batch image processing. New user-facing capabilities of this scope warrant human review.

You can customize Macroscope's approvability policy. Learn more.

@saphid

Copy link
Copy Markdown
ContributorAuthor

@t3dotgg This SwiftUI PR is ready for your review. Its exact head is mergeable; repository/native CI, MacroScope, Cursor, and review-thread audits are clean with zero unresolved threads. The only red status is the unrelated Vercel marketing authorization check.

@t3dotgg
t3dotggforce-pushed the t3code/rebuild-mobile-app-swift branch from 4cb3307 to 497f54fCompareAugust 10, 2026 03:58
@github-actionsgithub-actionsBot added size:XXL 1,000+ changed lines (additions + deletions). and removed size:XL 500-999 changed lines (additions + deletions). labels Aug 10, 2026
@saphid

Copy link
Copy Markdown
ContributorAuthor

Added the tall-draft follow-up in a6d78788e. The UIKit composer now remains internally scrollable, keeps programmatic caret moves visible, and grows only up to half the proposed viewport (with a 12-line fallback when the proposal is unavailable), so long drafts stay reachable without displacing the transcript. apps/swift-ios/Scripts/ci-test.sh passes 230 tests. A fresh Claude Opus 5 high review found no remaining defect in the paste/tall-composer interaction.

@saphid

Copy link
Copy Markdown
ContributorAuthor

Follow-up simulator evidence for the tall-composer continuation:

Very tall draft remains reachable above the software keyboard

Verified on iOS 26.5 with the software keyboard enabled: the restored multi-line draft scrolls/grows without making its bottom controls unreachable.

@saphid
saphidforce-pushed the agent/swiftui-image-paste branch from a6d7878 to f7987c6CompareAugust 10, 2026 10:23
Comment threadapps/swift-ios/Features/Chat/FeatureComposerView.swift Outdated
Comment threadapps/swift-ios/Features/Chat/FeatureComposerView.swift

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit d3c6ddc. Configure here.

Comment threadapps/swift-ios/Features/Chat/FeatureComposerView.swift Outdated
@saphid

Copy link
Copy Markdown
ContributorAuthor

Added two focused acceptance tests for the final editor outcome, on top of the current live PR head (including its latest UTF-16/NUL paste fix). No production code changed in this update.

The tests prove that visible composer height grows beyond three lines before its viewport bound, while content remains unlimited after visible height caps.

Integrated iOS 26.5 proof used a 516-character New Task draft: it grew, capped at 50% of the viewport, scrolled internally with the caret at the end, and kept attachment/model/send semantic targets reachable. Private video: https://alexs-macbook-pro-1.tail4e5636.ts.net:8766/swiftui-final-editor-growth-keyboard-proof-20260810.mp4

Post-update verification: focused Composer+Attachment 26/26; full native 237 tests/28 suites; git diff --check clean. Direct Opus review was attempted twice but unavailable: one aborted stream and one real exit 1 / HTTP 429 session limit. No completed independent verdict is claimed; the change is test-only and parent self-audit found no actionable issue.

This is the acceptance evidence for closing #5801 as superseded. #5829's one-line keyboard cap remains intentionally excluded because it conflicts with this final invariant.

t3-code[bot]
t3-codeBot approved these changes Aug 12, 2026

@t3-codet3-codeBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reviewed the full composer paste and attachment lifecycle diff, including context rotation, capacity handling, text decoding, caret restoration, and focused tests. no blocking issues found.

@t3dotgg

Copy link
Copy Markdown
Member

Resolve conflicts and re-run ci

@saphid

Copy link
Copy Markdown
ContributorAuthor

Closing this version while I rebuild the upstream contribution set from the latest base. Clean versions are coming soon.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL1,000+ changed lines (additions + deletions).vouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@saphid@t3dotgg
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(ios): support image paste from composer edit menu - #5610

Closed
saphid wants to merge 10 commits into
pingdotgg:t3code/rebuild-mobile-app-swiftfrom
saphid:agent/swiftui-image-paste
Closed

fix(ios): support image paste from composer edit menu#5610
saphid wants to merge 10 commits into
pingdotgg:t3code/rebuild-mobile-app-swiftfrom
saphid:agent/swiftui-image-paste

Conversation

@saphid

@saphidsaphid commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

What changed

  • Replace the SwiftUI composer field with a small UIKit-backed UITextView so copied images appear in the native long-press Paste menu.
  • Keep ordinary text paste unchanged, preserve text from mixed image/text pasteboard items, and keep command, model, skill, and path replacement caret placement correct.
  • Send pasted image providers through the existing image processor and attachment strip, preserving successful providers when another provider fails.
  • Reserve the shared eight-image capacity across in-flight picker, camera, Files, and paste work, and reject callbacks captured for a stale composer context.

The patch is limited to the SwiftUI iOS composer and attachment ingestion, plus focused tests and user documentation. It is stacked on the experimental SwiftUI client in #5178. The branch is rebased on 0d0c77431, which includes f79886039 and its native-CI repair.

Why

The SwiftUI field accepted pasted text but did not offer Paste for a copied screenshot or photo. A UIKit text responder can advertise image and text paste types through the standard iOS edit menu, then hand image providers to the same preparation path as the existing attachment picker.

UI evidence

Before: copied image, no PasteAfter: native Paste action
Before: long-press edit menu without PasteAfter: long-press edit menu with Paste

Resulting attachment

Copied image appears in the attachment strip

Eight-image limit

A further paste remains at eight attachments and shows the limit alert

Image-conforming provider regression

A HEIC-conforming pasteboard item still exposes Paste at the eight-image limit

Interaction video: native Paste action to attachment (10.97 seconds)

The four primary images and video were re-downloaded from the immutable evidence commit and matched their local SHA-256 hashes. The video was identified as H.264 at 1206×2622 and played in T3's collaborative preview. The HEIC regression image was captured from the final signed build after the Macroscope fix.

Validation

  • AttachmentPreparationTests + FeatureComposerPowerTests: 22 passed, 0 failed on the frozen diff after the review fixes.
  • T3_SWIFT_SIMULATOR_ID=… apps/swift-ios/Scripts/ci-test.sh: 228 tests in 27 suites, 0 failures. Existing unrelated simulator warnings remained visible; no test was weakened.
  • node scripts/generate-swift-wire-fixtures.ts --check: passed on the final diff, verifying the earlier native-CI fixture failure is repaired by the current stacking base.
  • Final signed Xcode 26.6 build, install, and launch on an iPhone 17 Pro simulator running iOS 26.5: passed.
  • Integrated UI: native menu and text-only paste; image-only paste to one attachment; mixed paste to text plus one attachment; text inserted at a nonterminal caret; nine-image paste capped at eight; and a further paste at capacity remained at eight with the limit alert.
  • Focused simulator tests cover shared pending capacity, partial-provider success, stale lifecycle tokens used by picker/camera/paste callbacks, provider loading, draft restoration, and UTF-16 caret restoration.
  • git diff --check: passed. Final range is four commits and 999 changed lines (915 additions, 84 deletions), reduced from 1,299 by removing the generic task store and duplicate test seams.
  • Fresh GPT-5.6 Sol high minimum-scope review inspected the frozen range and found one actionable issue: image interception was being disabled once eight attachments were present. Macroscope then found that hasImages misses some image-conforming providers, reproduced with public.heic. The final patch keeps interception active at capacity and detects UTType.image conformance. A late exact-head Cursor finding then reproduced an empty-to-restored-text caret jump; the fix now places that caret at the UTF-16 end while preserving ordinary selections. Affected tests and the signed integrated pass were repeated.

Checklist

  • Single-purpose SwiftUI image-paste change, minimized to the reliable behavior and its proof
  • Exact behavior and rationale described
  • Before/after and resulting-state screenshots included
  • Short interaction video included and playback verified
  • Focused tests, full native script, fixture check, and integrated simulator pass completed

Related

Implementation, integration, and fresh review: GPT-5.6 Sol in T3 Code.


Note

Medium Risk
Touches core composer input and async attachment ingestion with lifecycle cancellation; behavior is well-tested but regressions in paste, limits, or draft/project context switches would affect every send path on iOS.

Overview
Enables Paste for copied screenshots/photos in the iOS chat composer by swapping the SwiftUI TextField for a UIKit-backed FeatureComposerUITextView that advertises image paste types and routes image providers through the same ingestion path as Photos, Camera, and Files.

Paste and attachments: Mixed pasteboards still insert plain text (via FeatureComposerPasteTextPolicy) while images load in a serialized FeatureComposerPasteQueue, respect the shared eight-image cap (FeatureImageAttachmentPolicy.reserve / attachmentsToAppend), and surface alerts on limit or partial failure. Image detection uses UTType.image conformance so HEIC-style items still show Paste at capacity.

Lifecycle:FeatureAttachmentLifecycle tokens tied to attachmentContextID (thread or project) cancel stale picker, camera, file, and paste work on context change or send; NewThreadView shares one lifecycle across project switches.

Composer UX: Trigger replacements and empty-to-restored draft updates set caret position with UTF-16-aware selection policy; the text field grows within a bounded viewport. Focused unit tests and brief user docs cover the new behavior.

Reviewed by Cursor Bugbot for commit 9fc22e1. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Add image paste support to the iOS chat composer

  • Subclasses UITextView as FeatureComposerUITextView to intercept paste events, exposing the system paste menu for images and inserting any coexisting plain text before queuing image attachments.
  • Introduces FeatureComposerPasteQueue to serialize and cancel pending paste operations when the attachment context changes or a message is sent.
  • Enforces an 8-image limit across concurrent picker and paste flows via FeatureImageAttachmentPolicy and FeatureAttachmentPreparationState.reserve; excess images are dropped and the user sees an alert.
  • Replaces the SwiftUI TextField with a new FeatureComposerTextInput (UIViewRepresentable) that grows to a viewport-dependent max height and preserves caret position after autocomplete insertions.
  • Attachment context is now bound to thread/project ID so in-flight async operations are invalidated on context changes.

Macroscope summarized 9fc22e1.

Delivery: direct
Validated against Theo commit: f98cab5
Depends on: none
Merge order: this PR only
Validation status: Mergeable; native/repository checks and current review are green. The unrelated Vercel authorization failure is a maintainer-side gate.

@coderabbitai

coderabbitaiBot commented Aug 7, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 3b9d22c2-4390-4d41-9896-e3e89f4adb83

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:L 100-499 changed lines (additions + deletions). size:XL 500-999 changed lines (additions + deletions). and removed size:L 100-499 changed lines (additions + deletions). labels Aug 7, 2026
Comment threadapps/swift-ios/Features/Chat/FeatureComposerView.swift
@saphid
saphidforce-pushed the agent/swiftui-image-paste branch from 0f6efd1 to 7ea541dCompareAugust 8, 2026 01:16
@github-actionsgithub-actionsBot added size:XXL 1,000+ changed lines (additions + deletions). and removed size:XL 500-999 changed lines (additions + deletions). labels Aug 8, 2026
@saphid
saphidforce-pushed the agent/swiftui-image-paste branch 2 times, most recently from 8f34edd to 388ce56CompareAugust 8, 2026 22:47
@t3dotgg

Copy link
Copy Markdown
Member

Note

🤖 GPT-5.6 responding on behalf of Theo

/recheck-vouch

@github-actionsgithub-actionsBot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. and removed vouch:unvouched PR author is not yet trusted in the VOUCHED list. labels Aug 9, 2026
@t3dotgg
t3dotggforce-pushed the t3code/rebuild-mobile-app-swift branch from 65e66ee to 4df1e9bCompareAugust 9, 2026 02:26
@saphid
saphidforce-pushed the agent/swiftui-image-paste branch from 388ce56 to 08cc37cCompareAugust 9, 2026 03:26
@saphid

Copy link
Copy Markdown
ContributorAuthor

Rebased this draft onto the signed SwiftUI base rewrite at 4df1e9b. All nine PR commits replayed cleanly and range-diff is patch-identical. GitHub now reports the intended 7-file diff (1,118 additions, 74 deletions). Verification: 24 focused Xcode tests passed, 0 failed; git diff --check passed. New tip: 08cc37c15.

Comment threadapps/swift-ios/Features/Chat/FeatureComposerView.swift
@saphid
saphidforce-pushed the agent/swiftui-image-paste branch from 08cc37c to f5da001CompareAugust 9, 2026 12:32
@github-actionsgithub-actionsBot added size:XL 500-999 changed lines (additions + deletions). and removed size:XXL 1,000+ changed lines (additions + deletions). labels Aug 9, 2026
@saphid
saphidforce-pushed the agent/swiftui-image-paste branch from f5da001 to 46b4c62CompareAugust 9, 2026 12:39
@saphid
saphid marked this pull request as ready for review August 9, 2026 12:43
@saphid

saphid commented Aug 9, 2026

Copy link
Copy Markdown
ContributorAuthor

Ready for maintainer review at 7dd058199 on base 0d0c77431.

  • The late exact-head Cursor caret finding was reproduced, fixed, regression-tested, replied to, and resolved.
  • Focused attachment/composer suites: 22 passed. Full apps/swift-ios/Scripts/ci-test.sh: 228 tests in 27 suites passed. Signed simulator build/install/launch passed.
  • Exact-head SwiftUI native tests, CI Check/Test, Mobile Native Static Analysis, Release Smoke, Macroscope Correctness, and Cursor Bugbot passed.
  • Macroscope Approvability completed neutral with the expected verdict that this user-facing feature needs human review; it reported no new correctness issue. CodeRabbit still explicitly says its review was skipped and is not counted as a review.
  • The remaining Vercel marketing status is the same authorization failure, unrelated to this seven-file SwiftUI-only range. GitHub reports the PR non-draft, mergeable, vouch:trusted, and size:XL at 999 changed lines.
  • The PR body retains immutable publicly rendered screenshots and a verified playable interaction video. The current live audit has no unresolved review threads.

Only human maintainer review/merge remains.

Comment threadapps/swift-ios/Features/Chat/FeatureComposerView.swift
@macroscopeapp

macroscopeappBot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

This PR adds a substantial new feature (image paste support from iOS edit menu) with ~900 lines of new code including custom UITextView paste handling, lifecycle management, and batch image processing. New user-facing capabilities of this scope warrant human review.

You can customize Macroscope's approvability policy. Learn more.

@saphid

Copy link
Copy Markdown
ContributorAuthor

@t3dotgg This SwiftUI PR is ready for your review. Its exact head is mergeable; repository/native CI, MacroScope, Cursor, and review-thread audits are clean with zero unresolved threads. The only red status is the unrelated Vercel marketing authorization check.

@t3dotgg
t3dotggforce-pushed the t3code/rebuild-mobile-app-swift branch from 4cb3307 to 497f54fCompareAugust 10, 2026 03:58
@github-actionsgithub-actionsBot added size:XXL 1,000+ changed lines (additions + deletions). and removed size:XL 500-999 changed lines (additions + deletions). labels Aug 10, 2026
@saphid

Copy link
Copy Markdown
ContributorAuthor

Added the tall-draft follow-up in a6d78788e. The UIKit composer now remains internally scrollable, keeps programmatic caret moves visible, and grows only up to half the proposed viewport (with a 12-line fallback when the proposal is unavailable), so long drafts stay reachable without displacing the transcript. apps/swift-ios/Scripts/ci-test.sh passes 230 tests. A fresh Claude Opus 5 high review found no remaining defect in the paste/tall-composer interaction.

@saphid

Copy link
Copy Markdown
ContributorAuthor

Follow-up simulator evidence for the tall-composer continuation:

Very tall draft remains reachable above the software keyboard

Verified on iOS 26.5 with the software keyboard enabled: the restored multi-line draft scrolls/grows without making its bottom controls unreachable.

@saphid
saphidforce-pushed the agent/swiftui-image-paste branch from a6d7878 to f7987c6CompareAugust 10, 2026 10:23
Comment threadapps/swift-ios/Features/Chat/FeatureComposerView.swift Outdated
Comment threadapps/swift-ios/Features/Chat/FeatureComposerView.swift

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit d3c6ddc. Configure here.

Comment threadapps/swift-ios/Features/Chat/FeatureComposerView.swift Outdated
@saphid

Copy link
Copy Markdown
ContributorAuthor

Added two focused acceptance tests for the final editor outcome, on top of the current live PR head (including its latest UTF-16/NUL paste fix). No production code changed in this update.

The tests prove that visible composer height grows beyond three lines before its viewport bound, while content remains unlimited after visible height caps.

Integrated iOS 26.5 proof used a 516-character New Task draft: it grew, capped at 50% of the viewport, scrolled internally with the caret at the end, and kept attachment/model/send semantic targets reachable. Private video: https://alexs-macbook-pro-1.tail4e5636.ts.net:8766/swiftui-final-editor-growth-keyboard-proof-20260810.mp4

Post-update verification: focused Composer+Attachment 26/26; full native 237 tests/28 suites; git diff --check clean. Direct Opus review was attempted twice but unavailable: one aborted stream and one real exit 1 / HTTP 429 session limit. No completed independent verdict is claimed; the change is test-only and parent self-audit found no actionable issue.

This is the acceptance evidence for closing #5801 as superseded. #5829's one-line keyboard cap remains intentionally excluded because it conflicts with this final invariant.

t3-code[bot]
t3-codeBot approved these changes Aug 12, 2026

@t3-codet3-codeBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reviewed the full composer paste and attachment lifecycle diff, including context rotation, capacity handling, text decoding, caret restoration, and focused tests. no blocking issues found.

@t3dotgg

Copy link
Copy Markdown
Member

Resolve conflicts and re-run ci

@saphid

Copy link
Copy Markdown
ContributorAuthor

Closing this version while I rebuild the upstream contribution set from the latest base. Clean versions are coming soon.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL1,000+ changed lines (additions + deletions).vouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@saphid@t3dotgg
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

fix(ios): support image paste from composer edit menu - #5610

Closed
saphid wants to merge 10 commits into
pingdotgg:t3code/rebuild-mobile-app-swiftfrom
saphid:agent/swiftui-image-paste
Closed

fix(ios): support image paste from composer edit menu#5610
saphid wants to merge 10 commits into
pingdotgg:t3code/rebuild-mobile-app-swiftfrom
saphid:agent/swiftui-image-paste

Conversation

@saphid

@saphidsaphid commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

What changed

  • Replace the SwiftUI composer field with a small UIKit-backed UITextView so copied images appear in the native long-press Paste menu.
  • Keep ordinary text paste unchanged, preserve text from mixed image/text pasteboard items, and keep command, model, skill, and path replacement caret placement correct.
  • Send pasted image providers through the existing image processor and attachment strip, preserving successful providers when another provider fails.
  • Reserve the shared eight-image capacity across in-flight picker, camera, Files, and paste work, and reject callbacks captured for a stale composer context.

The patch is limited to the SwiftUI iOS composer and attachment ingestion, plus focused tests and user documentation. It is stacked on the experimental SwiftUI client in #5178. The branch is rebased on 0d0c77431, which includes f79886039 and its native-CI repair.

Why

The SwiftUI field accepted pasted text but did not offer Paste for a copied screenshot or photo. A UIKit text responder can advertise image and text paste types through the standard iOS edit menu, then hand image providers to the same preparation path as the existing attachment picker.

UI evidence

Before: copied image, no PasteAfter: native Paste action
Before: long-press edit menu without PasteAfter: long-press edit menu with Paste

Resulting attachment

Copied image appears in the attachment strip

Eight-image limit

A further paste remains at eight attachments and shows the limit alert

Image-conforming provider regression

A HEIC-conforming pasteboard item still exposes Paste at the eight-image limit

Interaction video: native Paste action to attachment (10.97 seconds)

The four primary images and video were re-downloaded from the immutable evidence commit and matched their local SHA-256 hashes. The video was identified as H.264 at 1206×2622 and played in T3's collaborative preview. The HEIC regression image was captured from the final signed build after the Macroscope fix.

Validation

  • AttachmentPreparationTests + FeatureComposerPowerTests: 22 passed, 0 failed on the frozen diff after the review fixes.
  • T3_SWIFT_SIMULATOR_ID=… apps/swift-ios/Scripts/ci-test.sh: 228 tests in 27 suites, 0 failures. Existing unrelated simulator warnings remained visible; no test was weakened.
  • node scripts/generate-swift-wire-fixtures.ts --check: passed on the final diff, verifying the earlier native-CI fixture failure is repaired by the current stacking base.
  • Final signed Xcode 26.6 build, install, and launch on an iPhone 17 Pro simulator running iOS 26.5: passed.
  • Integrated UI: native menu and text-only paste; image-only paste to one attachment; mixed paste to text plus one attachment; text inserted at a nonterminal caret; nine-image paste capped at eight; and a further paste at capacity remained at eight with the limit alert.
  • Focused simulator tests cover shared pending capacity, partial-provider success, stale lifecycle tokens used by picker/camera/paste callbacks, provider loading, draft restoration, and UTF-16 caret restoration.
  • git diff --check: passed. Final range is four commits and 999 changed lines (915 additions, 84 deletions), reduced from 1,299 by removing the generic task store and duplicate test seams.
  • Fresh GPT-5.6 Sol high minimum-scope review inspected the frozen range and found one actionable issue: image interception was being disabled once eight attachments were present. Macroscope then found that hasImages misses some image-conforming providers, reproduced with public.heic. The final patch keeps interception active at capacity and detects UTType.image conformance. A late exact-head Cursor finding then reproduced an empty-to-restored-text caret jump; the fix now places that caret at the UTF-16 end while preserving ordinary selections. Affected tests and the signed integrated pass were repeated.

Checklist

  • Single-purpose SwiftUI image-paste change, minimized to the reliable behavior and its proof
  • Exact behavior and rationale described
  • Before/after and resulting-state screenshots included
  • Short interaction video included and playback verified
  • Focused tests, full native script, fixture check, and integrated simulator pass completed

Related

Implementation, integration, and fresh review: GPT-5.6 Sol in T3 Code.


Note

Medium Risk
Touches core composer input and async attachment ingestion with lifecycle cancellation; behavior is well-tested but regressions in paste, limits, or draft/project context switches would affect every send path on iOS.

Overview
Enables Paste for copied screenshots/photos in the iOS chat composer by swapping the SwiftUI TextField for a UIKit-backed FeatureComposerUITextView that advertises image paste types and routes image providers through the same ingestion path as Photos, Camera, and Files.

Paste and attachments: Mixed pasteboards still insert plain text (via FeatureComposerPasteTextPolicy) while images load in a serialized FeatureComposerPasteQueue, respect the shared eight-image cap (FeatureImageAttachmentPolicy.reserve / attachmentsToAppend), and surface alerts on limit or partial failure. Image detection uses UTType.image conformance so HEIC-style items still show Paste at capacity.

Lifecycle:FeatureAttachmentLifecycle tokens tied to attachmentContextID (thread or project) cancel stale picker, camera, file, and paste work on context change or send; NewThreadView shares one lifecycle across project switches.

Composer UX: Trigger replacements and empty-to-restored draft updates set caret position with UTF-16-aware selection policy; the text field grows within a bounded viewport. Focused unit tests and brief user docs cover the new behavior.

Reviewed by Cursor Bugbot for commit 9fc22e1. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Add image paste support to the iOS chat composer

  • Subclasses UITextView as FeatureComposerUITextView to intercept paste events, exposing the system paste menu for images and inserting any coexisting plain text before queuing image attachments.
  • Introduces FeatureComposerPasteQueue to serialize and cancel pending paste operations when the attachment context changes or a message is sent.
  • Enforces an 8-image limit across concurrent picker and paste flows via FeatureImageAttachmentPolicy and FeatureAttachmentPreparationState.reserve; excess images are dropped and the user sees an alert.
  • Replaces the SwiftUI TextField with a new FeatureComposerTextInput (UIViewRepresentable) that grows to a viewport-dependent max height and preserves caret position after autocomplete insertions.
  • Attachment context is now bound to thread/project ID so in-flight async operations are invalidated on context changes.

Macroscope summarized 9fc22e1.

Delivery: direct
Validated against Theo commit: f98cab5
Depends on: none
Merge order: this PR only
Validation status: Mergeable; native/repository checks and current review are green. The unrelated Vercel authorization failure is a maintainer-side gate.

@coderabbitai

coderabbitaiBot commented Aug 7, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 3b9d22c2-4390-4d41-9896-e3e89f4adb83

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:L 100-499 changed lines (additions + deletions). size:XL 500-999 changed lines (additions + deletions). and removed size:L 100-499 changed lines (additions + deletions). labels Aug 7, 2026
Comment threadapps/swift-ios/Features/Chat/FeatureComposerView.swift
@saphid
saphidforce-pushed the agent/swiftui-image-paste branch from 0f6efd1 to 7ea541dCompareAugust 8, 2026 01:16
@github-actionsgithub-actionsBot added size:XXL 1,000+ changed lines (additions + deletions). and removed size:XL 500-999 changed lines (additions + deletions). labels Aug 8, 2026
@saphid
saphidforce-pushed the agent/swiftui-image-paste branch 2 times, most recently from 8f34edd to 388ce56CompareAugust 8, 2026 22:47
@t3dotgg

Copy link
Copy Markdown
Member

Note

🤖 GPT-5.6 responding on behalf of Theo

/recheck-vouch

@github-actionsgithub-actionsBot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. and removed vouch:unvouched PR author is not yet trusted in the VOUCHED list. labels Aug 9, 2026
@t3dotgg
t3dotggforce-pushed the t3code/rebuild-mobile-app-swift branch from 65e66ee to 4df1e9bCompareAugust 9, 2026 02:26
@saphid
saphidforce-pushed the agent/swiftui-image-paste branch from 388ce56 to 08cc37cCompareAugust 9, 2026 03:26
@saphid

Copy link
Copy Markdown
ContributorAuthor

Rebased this draft onto the signed SwiftUI base rewrite at 4df1e9b. All nine PR commits replayed cleanly and range-diff is patch-identical. GitHub now reports the intended 7-file diff (1,118 additions, 74 deletions). Verification: 24 focused Xcode tests passed, 0 failed; git diff --check passed. New tip: 08cc37c15.

Comment threadapps/swift-ios/Features/Chat/FeatureComposerView.swift
@saphid
saphidforce-pushed the agent/swiftui-image-paste branch from 08cc37c to f5da001CompareAugust 9, 2026 12:32
@github-actionsgithub-actionsBot added size:XL 500-999 changed lines (additions + deletions). and removed size:XXL 1,000+ changed lines (additions + deletions). labels Aug 9, 2026
@saphid
saphidforce-pushed the agent/swiftui-image-paste branch from f5da001 to 46b4c62CompareAugust 9, 2026 12:39
@saphid
saphid marked this pull request as ready for review August 9, 2026 12:43
@saphid

saphid commented Aug 9, 2026

Copy link
Copy Markdown
ContributorAuthor

Ready for maintainer review at 7dd058199 on base 0d0c77431.

  • The late exact-head Cursor caret finding was reproduced, fixed, regression-tested, replied to, and resolved.
  • Focused attachment/composer suites: 22 passed. Full apps/swift-ios/Scripts/ci-test.sh: 228 tests in 27 suites passed. Signed simulator build/install/launch passed.
  • Exact-head SwiftUI native tests, CI Check/Test, Mobile Native Static Analysis, Release Smoke, Macroscope Correctness, and Cursor Bugbot passed.
  • Macroscope Approvability completed neutral with the expected verdict that this user-facing feature needs human review; it reported no new correctness issue. CodeRabbit still explicitly says its review was skipped and is not counted as a review.
  • The remaining Vercel marketing status is the same authorization failure, unrelated to this seven-file SwiftUI-only range. GitHub reports the PR non-draft, mergeable, vouch:trusted, and size:XL at 999 changed lines.
  • The PR body retains immutable publicly rendered screenshots and a verified playable interaction video. The current live audit has no unresolved review threads.

Only human maintainer review/merge remains.

Comment threadapps/swift-ios/Features/Chat/FeatureComposerView.swift
@macroscopeapp

macroscopeappBot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

This PR adds a substantial new feature (image paste support from iOS edit menu) with ~900 lines of new code including custom UITextView paste handling, lifecycle management, and batch image processing. New user-facing capabilities of this scope warrant human review.

You can customize Macroscope's approvability policy. Learn more.

@saphid

Copy link
Copy Markdown
ContributorAuthor

@t3dotgg This SwiftUI PR is ready for your review. Its exact head is mergeable; repository/native CI, MacroScope, Cursor, and review-thread audits are clean with zero unresolved threads. The only red status is the unrelated Vercel marketing authorization check.

@t3dotgg
t3dotggforce-pushed the t3code/rebuild-mobile-app-swift branch from 4cb3307 to 497f54fCompareAugust 10, 2026 03:58
@github-actionsgithub-actionsBot added size:XXL 1,000+ changed lines (additions + deletions). and removed size:XL 500-999 changed lines (additions + deletions). labels Aug 10, 2026
@saphid

Copy link
Copy Markdown
ContributorAuthor

Added the tall-draft follow-up in a6d78788e. The UIKit composer now remains internally scrollable, keeps programmatic caret moves visible, and grows only up to half the proposed viewport (with a 12-line fallback when the proposal is unavailable), so long drafts stay reachable without displacing the transcript. apps/swift-ios/Scripts/ci-test.sh passes 230 tests. A fresh Claude Opus 5 high review found no remaining defect in the paste/tall-composer interaction.

@saphid

Copy link
Copy Markdown
ContributorAuthor

Follow-up simulator evidence for the tall-composer continuation:

Very tall draft remains reachable above the software keyboard

Verified on iOS 26.5 with the software keyboard enabled: the restored multi-line draft scrolls/grows without making its bottom controls unreachable.

@saphid
saphidforce-pushed the agent/swiftui-image-paste branch from a6d7878 to f7987c6CompareAugust 10, 2026 10:23
Comment threadapps/swift-ios/Features/Chat/FeatureComposerView.swift Outdated
Comment threadapps/swift-ios/Features/Chat/FeatureComposerView.swift

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit d3c6ddc. Configure here.

Comment threadapps/swift-ios/Features/Chat/FeatureComposerView.swift Outdated
@saphid

Copy link
Copy Markdown
ContributorAuthor

Added two focused acceptance tests for the final editor outcome, on top of the current live PR head (including its latest UTF-16/NUL paste fix). No production code changed in this update.

The tests prove that visible composer height grows beyond three lines before its viewport bound, while content remains unlimited after visible height caps.

Integrated iOS 26.5 proof used a 516-character New Task draft: it grew, capped at 50% of the viewport, scrolled internally with the caret at the end, and kept attachment/model/send semantic targets reachable. Private video: https://alexs-macbook-pro-1.tail4e5636.ts.net:8766/swiftui-final-editor-growth-keyboard-proof-20260810.mp4

Post-update verification: focused Composer+Attachment 26/26; full native 237 tests/28 suites; git diff --check clean. Direct Opus review was attempted twice but unavailable: one aborted stream and one real exit 1 / HTTP 429 session limit. No completed independent verdict is claimed; the change is test-only and parent self-audit found no actionable issue.

This is the acceptance evidence for closing #5801 as superseded. #5829's one-line keyboard cap remains intentionally excluded because it conflicts with this final invariant.

t3-code[bot]
t3-codeBot approved these changes Aug 12, 2026

@t3-codet3-codeBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reviewed the full composer paste and attachment lifecycle diff, including context rotation, capacity handling, text decoding, caret restoration, and focused tests. no blocking issues found.

@t3dotgg

Copy link
Copy Markdown
Member

Resolve conflicts and re-run ci

@saphid

Copy link
Copy Markdown
ContributorAuthor

Closing this version while I rebuild the upstream contribution set from the latest base. Clean versions are coming soon.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL1,000+ changed lines (additions + deletions).vouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@saphid@t3dotgg