ios: add Agent attachments and shared transcript fade
TestFlight / Build and upload (push) Successful in 1m48s
TestFlight / Build and upload (push) Successful in 1m48s
This commit is contained in:
+74
-3
@@ -30,10 +30,69 @@ even if the HTTP acknowledgement is lost. Raw tool calls and results are hidden
|
||||
in the Agent transcript, including loaded history and live updates. History windows,
|
||||
date separators and scroll anchors use visible messages; raw merged history and
|
||||
cursors remain intact. Send failures, room errors and activity indicators remain
|
||||
visible. Attachments, model selection and tool cards belong to ordinary chats.
|
||||
visible. Model selection and tool cards continue to belong to ordinary chats.
|
||||
|
||||
Agent contracts remain in `../docs/api/rest.md` and
|
||||
`../docs/api/streaming-chat.md`; this client requires no backend deployment.
|
||||
`../docs/api/streaming-chat.md`. ROOT attachments consume the coordinated v1
|
||||
contract (2026-10-14), now documented in the integrated API sources above.
|
||||
Attachment readiness requires the coordinated backend/runtime and existing public
|
||||
API bearer authentication. This iOS change does not deploy or configure them.
|
||||
|
||||
### ROOT attachments
|
||||
|
||||
The Agent composer exposes Files and Photo Library only when the authenticated
|
||||
descriptor advertises supported `capabilities.attachments.version == 1`. Missing,
|
||||
malformed, or unsupported capability keeps the client text-only. Ordinary chat
|
||||
attachments retain their existing inline format and behavior.
|
||||
Open-proxy HTTP 503 / WebSocket 4503 failures disable attachment selection while
|
||||
retaining draft descriptors and outbox retry identities; reconnect checks support.
|
||||
|
||||
Files preserve their original bytes, including PDF, archives, text and HEIC files.
|
||||
Photo Library HEIC/HEIF selections are intentionally converted to bounded JPEG
|
||||
visual input with a matching `.jpg` filename. PNG/JPEG/GIF/WebP are validated as
|
||||
raster images; model input is static, with no claim of document or animation
|
||||
understanding. Safe original names supplied by the picker are retained; PhotosPicker
|
||||
may provide an export filename rather than the original Photo Library asset name.
|
||||
The production app does not request broad Photo Library access.
|
||||
|
||||
Selection order is stable. One preparation/upload runs at a time, with per-item
|
||||
loading, upload, error, retry and removal. Sending requires every item to be ready;
|
||||
an empty caption can send ready attachments. Advertised limits are checked against
|
||||
v1 hard ceilings (8 files, 32 MiB total, 6 MiB/image, 8 MiB/file, 50 million pixels,
|
||||
16,384 pixels/axis). Quota snapshots are decoded but do not reserve space. Server
|
||||
messages/codes, quota details and Retry-After survive failures, including 409, 413,
|
||||
429 and 507. Removal cancels local work and removes the reference; it does not
|
||||
delete an uploaded server original.
|
||||
|
||||
The caption, ordered upload UUIDs and ready descriptors are saved in a small atomic
|
||||
manifest under Application Support, scoped to the API base URL. Prepared bytes are
|
||||
staged in app-owned files (at most 8 MiB each and 32 MiB per draft); no inline bytes
|
||||
or tokens enter the outbox. Relaunch restores ready drafts and offers explicit retry
|
||||
for interrupted staged uploads with the same upload UUID. A selection interrupted
|
||||
before staging must be removed and selected again. Uploads suspend when the room
|
||||
stops; failed work does not automatically retry. Uploaded originals have no client
|
||||
expiration. After submission, the outbox owns the caption, ordered descriptors and
|
||||
stable request ID. A persisted draft identity recovers a crash during this handoff
|
||||
without creating a second send. Storage failure blocks submission rather than
|
||||
discarding a draft. Attachment receipts must acknowledge exactly the submitted IDs
|
||||
in order; matching canonical echoes still win ambiguous HTTP failures.
|
||||
|
||||
History and queued/live messages decode only `metadata.agentAttachments` for ROOT.
|
||||
Cards retain filename, MIME, size and the optional server-provided `workspacePath`,
|
||||
which can be copied. The client never constructs a runtime path or sends one as a
|
||||
reference; leading-dot display filenames remain unchanged. Captions remain public
|
||||
text, including the server's fallback for attachment-only messages.
|
||||
|
||||
Original downloads use the configured authenticated URLSession and API base
|
||||
(including `/api`), reject redirects, and verify exact size and SHA-256. At most two
|
||||
downloads run concurrently, with a 16 MiB in-memory cache discarded on configuration
|
||||
change. Queued/active cancellation and generation checks prevent stale previews
|
||||
from crossing configurations. Raster previews use bounded thumbnails; text previews
|
||||
are plain text, including HTML/SVG. Save/share exports exact original bytes to a
|
||||
temporary file removed when its card disappears or configuration changes. An app
|
||||
crash may leave a temporary export for normal OS temporary-directory cleanup.
|
||||
Image preview frames have fixed height to preserve scroll anchors during loading.
|
||||
Attachment modals track their own visibility without changing Quick Question state.
|
||||
|
||||
### Agent regression and Simulator checks
|
||||
|
||||
@@ -47,7 +106,10 @@ just screenshot build/agent-evidence/simulator.png
|
||||
```
|
||||
|
||||
`just test` runs reducer, cursor, outbox, presentation, shared-read and lifecycle
|
||||
regressions along with the existing app tests through Xcode on iPhone 16e.
|
||||
regressions along with attachment capability/metadata, multipart/auth/bytes/errors,
|
||||
HEIC conversion versus original-file preservation, ordered receipts, draft/outbox
|
||||
relaunch, cancellation, two-transfer concurrency and configuration isolation tests
|
||||
through Xcode on iPhone 16e.
|
||||
For interactive UI coverage, start the local fixture (Python with `aiohttp`):
|
||||
|
||||
```sh
|
||||
@@ -71,6 +133,15 @@ admission/retry, tools, asynchronous replies, inactive sidebar unread counts,
|
||||
shared reads, reconnect/malformed replay, foreground recovery, long-history scroll
|
||||
anchors and multiline keyboard layout. The launch arguments select the fixture
|
||||
through ordinary API settings; no fixture mode is compiled into the application.
|
||||
Attachment cases exercise authenticated originals, safe text/raster display,
|
||||
history reload, capability absence and picker cancellation. The real Photo Library
|
||||
selection-to-send test is explicitly skipped: this iOS 26.5 XCTest environment has
|
||||
unreliable Photos authorization, callback isolation and synthetic-asset cleanup.
|
||||
Selection-to-send remains a manual/device pre-release check, not a validated UI
|
||||
path. The gate prevents photo mutations during the general UI suite. Synthetic
|
||||
HEIC conversion and original HEIC file preservation are covered by package tests.
|
||||
The fixture accepts multipart uploads, stable upload/message retries, structured
|
||||
errors and attachment receipts; it is not a runtime image-decoder or quota test.
|
||||
Use a fresh result-bundle path for each run. Check the same UI on iPad and with
|
||||
Simulator Reduce Motion enabled before release.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user