feat(go): composer + attachment UX overhaul#373
Merged
zomux merged 2 commits intoMay 12, 2026
Conversation
Native Swift composer rebuild that addresses a stack of macOS/iOS issues surfaced during dogfooding. Single round of work covering input, send, and attachment paths. Composer (ComposerTextView) - Replace SwiftUI TextEditor with NSViewRepresentable / UIViewRepresentable wrapping NSTextView / UITextView so we can intercept Return-to-send around IME composition (hasMarkedText / markedTextRange) — fixes false sends mid-Pinyin / Kana composition. - macOS: extend readablePasteboardTypes + acceptableDragTypes to include PNG / JPEG / TIFF / public.image / fileURL so Cmd+V validates and our paste(_:) override actually runs (was previously rejected at the menu validator → system bonk). - macOS: paste(_:) handles PNG → JPEG → TIFF → NSImage fallback; file URL paste from Finder. - iOS: subclass UITextView; canPerformAction / paste(_:) read UIPasteboard.images. Hardware Cmd+V works; soft Return inserts newline to match iMessage. Bubble layout (Issue: empty padding on user bubbles) - MessageBubble drops maxWidth: .infinity on the prose-only path so short messages hug their text; code/table content still claims full row. Toolbar titles - macOS: ChatView sets navigationTitle = current session title (replaces default "OpenAgents Go" in the window toolbar) with agent names as subtitle. - ThreadListView gets a visible workspace name + slug header at the top on macOS (split-view sidebar doesn't surface .navigationTitle). Stop button - Add WorkspaceAPI.sendAgentControl mirroring the React app's pattern. - WorkspaceStore.stopAllAgents fans out workspace.agent.control events with optimistic "Stopping..." status; retries once after 3s; clears the flag on terminal status from the message poll. - ChatGPT-style: send arrow swaps to a red stop circle while an agent is working; grays out while a stop is in flight. Attachment UX - Dedup optimistic vs real attachment messages: rewrite optimistic content to finalContent in-place after api.sendMessage returns so the poll's content-equality dedup matches. Fallback matcher compares the set of attached filenames if exact-equality misses (mid-upload race). Fixes the "two bubbles per upload" symptom. - ImageDownsampler (ImageIO-based): any pasted/picked/imported image whose longest side is > 2000px gets resized to 2000 and re-encoded as PNG. Targets the exact Anthropic many-image-request limit so a Retina screenshot can't poison the conversation. - AttachmentChip: image variant shows a 48x48 thumbnail with X overlay (decoded via ImageIO, cached on the chip). Non-image keeps the Slack-style filename + size row. - Long text paste >= 5000 chars converts to a Pasted-text-<ts>.txt attachment chip instead of dumping into the input field (matches ChatGPT's published threshold). Bumps MARKETING_VERSION 0.2.1 -> 0.2.2.
|
@baryhuang is attempting to deploy a commit to the Raphael's projects Team on Vercel. A member of the Team first needs to authorize it. |
abdcf1f to
57bc369
Compare
8 tasks
Collaborator
Author
|
Ready to review. This is package version 0.2.2 |
zomux
approved these changes
May 12, 2026
Contributor
zomux
left a comment
There was a problem hiding this comment.
Excellent overhaul of the composer and attachment pipeline. Good use of platform-native text views for IME-safe input, proper image downsampling, and clean separation of concerns. Minor nit: iOS force-unwrap in insertHardwareNewline (textRange(from: endOfDocument, to: endOfDocument)!) — low risk but could be guarded.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Rebuild of the OpenAgents Go composer (macOS + iOS) plus a top-to-bottom attachment-pipeline overhaul. Cleared a stack of dogfooding issues in one cohesive change. v0.2.1 → 0.2.2.
Composer
TextEditorwith a platform-nativeNSTextView/UITextViewrepresentable so we own the responder.hasMarkedText()(macOS) /markedTextRange(iOS) so pressing Enter mid-Pinyin or mid-Kana confirms the candidate instead of false-sending.readablePasteboardTypes+acceptableDragTypesso Cmd+V actually validates for image-only pasteboards (the system bonk before this change came from menu-validation, not from ourpaste(_:)override). Override handles PNG → JPEG → TIFF → NSImage fallback, plus file URLs from Finder.UITextView;canPerformAction+paste(_:)readUIPasteboard.images. Hardware Cmd+V works; soft Return inserts newline to match iMessage.Bubble layout
MessageBubbledropsmaxWidth: .infinityon the prose-only path so short user messages hug their text. Code / table content still claims the full row.Toolbar titles
navigationTitleset to the current thread title (replaces the default "OpenAgents Go" in the window toolbar). Subtitle shows participating agents.ThreadListViewgets a visible workspace name + slug header at the top of the sidebar on macOS (NavigationSplitView doesn't surface a sidebar.navigationTitleanywhere visible).Stop button
WorkspaceAPI.sendAgentControlmirrors the React app.WorkspaceStore.stopAllAgentsfans outworkspace.agent.controlevents with optimistic "Stopping…" status, retries once after 3s, clears the flag on terminal status from the message poll.Attachment UX
finalContentafterapi.sendMessagereturns so the existing poll dedup matches. Fallback matcher compares the set of attached filenames for the mid-upload race. Fixes the "two bubbles per upload" symptom.ImageDownsampler(ImageIO-based) wired into every ingest site (paste, photo picker, file import). Targets the exact Anthropic many-image-request limit so a Retina screenshot can't poison the conversation downstream.Pasted-text-<ts>.txtattachment instead of dumping into the input. Threshold matches ChatGPT's published behavior.Test plan
OpenAgentsGo_macOSandOpenAgentsGo_iOS(Debug + Release).Readno longer trips Anthropic's 2000px limit.Pasted-text-…txtchip; the text view stays empty.Files
New:
packages/go/OpenAgents/Views/ComposerTextView.swiftpackages/go/OpenAgents/Helpers/ImageDownsampler.swiftModified:
packages/go/OpenAgents/Views/ChatView.swift— bubble layout, composer wiring, send/stop button, chip redesign, downsample at ingest sites.packages/go/OpenAgents/Views/ThreadListView.swift— workspace header.packages/go/OpenAgents/State/WorkspaceStore.swift— stop state + dedup.packages/go/OpenAgents/Networking/WorkspaceAPI.swift—sendAgentControl.packages/go/OpenAgents/Models/Attachment.swift—makeThumbnail.packages/go/OpenAgents/Models/Message.swift—localStoppingStatushelper.packages/go/project.yml+ regeneratedproject.pbxproj— version bump.Deferred
[file.png](url)lines as proper thumbnail cards inside the message bubble) — explicitly punted to keep the diff bounded; markdown link rendering is acceptable now that dedup makes it a single line.