Skip to content

Open chat visuals full screen on iOS and Android (Remote revision 35) - #514

Merged
sambitcreate merged 8 commits into
mainfrom
claude/project-thread-jxkc0z
Oct 19, 2026
Merged

sambitcreate merged 8 commits into
mainfrom
claude/project-thread-jxkc0z

Conversation

@sambitcreate

@sambitcreate sambitcreate commented Oct 16, 2026 •

Copy link
Copy Markdown
Owner

Requested by sbt · project thread

Before: on iOS and Android, charts and widgets in a reply are a still, light-theme picture from the Mac. Tapping one only opens the image viewer.

After: when the paired Mac runs this build, tapping a visual opens it full screen in a locked-down web view. Tooltips, tabs, sliders and Plotly interactions work, in the phone's own theme, light or dark.

  • If the visual asks for a follow-up or wants to open a link, the phone asks first. A follow-up only goes into the composer.
  • Tall visuals scroll.
  • A visual opened before can be reopened when the Mac is out of reach, even after the app restarts.
  • Older phones and older Macs keep the snapshot.

It works for both kinds of visual:

  • render_ui is drawn by the same AidenUiBlock the desktop uses.
  • render_artifact HTML runs in the same opaque-origin sandbox and CSP as on desktop, with only the libraries it calls inlined.

How

  • Mac: new GET /chats/{chatId}/visuals/{visualId}/document?scheme&theme behind feature token chat-visual-viewer-v1.

    • This is contract revision 35, because main took 34 for speech-request-gzip-v1. It is provisional and gets re-claimed at merge.
    • The endpoint returns one self-contained HTML document, built by main/services/visual-viewer-document.ts from a new viewer bundle. vite.visual-viewer.config.ts builds that bundle into build/renderer/visual-viewer/ as part of npm run build.
    • The viewer scrolls inside its own full-viewport surface, because the desktop stylesheet pins html, body and #root with overflow hidden.
    • Visual entries gain no new key. Every client parses them with a closed key set, so a new key would hide all visuals on older phones.
    • Responses are no-store, with a strong ETag and gzip.
  • Bridge: the page talks to the phone through one channel only, aidenVisual on iOS and AidenVisualBridge on Android. It carries three message types: ready, prompt and openUrl.

    • AidenUiBlock gains onFollowUp, so the viewer hands prompts to the phone instead of drawing its own Send chip.
    • Links in the viewer go through a new ExternalLinkOpenerProvider.
    • Android accepts https in any letter case and opens the link with a lowercase scheme.
  • Export refactor: library inlining moved into inlineGenerativeUiHostLibraries, which export and the CLI also use. It now replaces with a function, so $& in library source stays literal.

  • iOS and Android: each app has a full-screen viewer:

    • a non-persistent store and no file access;
    • every navigation and new window denied;
    • native confirmation for prompts and links;
    • an offline cache (20 files / 40 MB, LRU).

    The image viewer is still reachable from the viewer.

    • The cache is purged when a pairing is removed or its credential is revoked.
    • The saved copy is shown only when the Mac is unreachable: a network error, 408, 429 or 5xx.
    • A generation fence stops a load that is in flight from writing a document back after a purge.
    • On iOS, a pairing with saved documents keeps the viewer available until a live /server answer decides.
  • CI: the viewer's Vite build is registered as a generative-ui-chromium prerequisite, and the new iOS sources are on the shipping allowlist.

  • Docs: the plan is in docs/plans/phone-visual-viewer-plan.md. The API notes and OpenAPI are updated.

Testing

  • Builder units, chat-service lookups, router register-and-invoke (auth, query validation, 304, gzip, feature gating) and OpenAPI path coverage.

  • A Chromium spec loads the real built document with the network blocked. It checks:

    • a native chart and an HTML Chart.js visual draw in dark mode;
    • the guest can't read the parent;
    • prompts and links reach the host channel, and prompts are rate-limited;
    • on a 390x600 screen, tall visuals scroll to their bottom actions.
  • iOS and Android unit tests cover:

    • the client request and decoding;
    • message parsing;
    • the cache, including revocation, refusal, transient fallback, a purge during a load and installation removal;
    • the feature gate;
    • on iOS, a cold start without the Mac.

    Both pass in CI (iOS simulator XCTest, Android verify and Compose UI tests).

Flaky test record

🤖 Generated with Claude Code

https://claude.ai/code/session_01KPgvZHFWvJ95VRjuu4p9LL

Phones keep the inline snapshot; with the new chat-visual-viewer-v1 token,
tapping it opens the visual in a locked-down web view. The Mac serves
GET /chats/{chatId}/visuals/{visualId}/document: one self-contained HTML
document built from a new viewer bundle (render_ui via AidenUiBlock,
render_artifact as the sandboxed guest with only the libraries it uses).
Follow-ups and links go to the phone, which confirms; prompts only fill
the composer.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KPgvZHFWvJ95VRjuu4p9LL
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KPgvZHFWvJ95VRjuu4p9LL
@sambitcreate sambitcreate self-assigned this Oct 16, 2026
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KPgvZHFWvJ95VRjuu4p9LL
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KPgvZHFWvJ95VRjuu4p9LL
Main took revision 34 for speech-request-gzip-v1.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KPgvZHFWvJ95VRjuu4p9LL
@sambitcreate sambitcreate changed the title Open chat visuals full screen on iOS and Android (Remote revision 34) Open chat visuals full screen on iOS and Android (Remote revision 35) Oct 19, 2026
@sambitcreate
sambitcreate marked this pull request as ready for review October 19, 2026 20:10

@pullfrog pullfrog Bot 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.

Important

Tall visuals cannot be scrolled, Android treats revoked access as an offline cache hit, and iOS cannot reopen cached visuals after an offline relaunch.

Reviewed changes
Reviewed the complete phone visual viewer implementation and its Remote revision 35 contract.

  • Remote document endpoint: Authenticated visual lookup, bounded self-contained HTML, appearance queries, feature negotiation, CSP, ETags, and gzip.
  • Shared viewer: A new bundled React page reuses native visual components, hosts sandboxed HTML, forwards follow-ups and links, and shares library inlining with exports.
  • Native clients: iOS and Android full-screen WebViews add confirmation flows, snapshot fallback, appearance selection, and bounded offline document caches.
  • Integration and coverage: Build/CI registration, Xcode shipping inventory, protocol/OpenAPI updates, documentation, and focused server, browser, and mobile tests.

Validation: the viewer build, 221 focused TypeScript tests, both new Chromium tests, TypeScript checking, iOS release-policy checks, and Swift syntax parsing passed. Local Android execution was blocked by unavailable offline runtime dependencies; native XCTest requires macOS. Hosted Android, iOS, and required CI checks are green on the reviewed head.

Pullfrog  | Fix all ➔ | Fix 👍s ➔ | View workflow run | Using gpt-6.1-sol | 𝕏

Comment thread renderer/visual-viewer/main.tsx
Comment thread ios/AidenOnTheGo/Features/Remote/AidenChatFeature.swift Outdated
@very-hermes-bot

very-hermes-bot commented Oct 19, 2026 •

Copy link
Copy Markdown
Collaborator

Hermes Review Bot

Confidence: 5

Engine: agy/gemini-3.8-flash-high
Review mode: full
Head: 0a652797022499bc276e865d7ea9ee87bd5720f5
Generated: 2026-10-19T22:51:26+00:00
Reviews: 1

Summary

Remote contract revision 35 introduces interactive full-screen rendering for inline visuals (render_ui components and render_artifact HTML) on iOS and Android behind feature token chat-visual-viewer-v1. The desktop serves a self-contained, gzip-compressed HTML document embedding the viewer bundle and inlined host libraries (Chart.js, Plotly, KaTeX) under a strict default-src 'none' Content Security Policy. Native clients load the document into locked-down WebViews (disabling network, file access, storage, and arbitrary navigation) and communicate strictly over a minimal bridged message protocol (ready, prompt, openUrl) requiring explicit user confirmation before touching the composer draft or system browser. Maintainers should double-check the timing of re-claiming the provisional contract revision 35 at merge time to ensure it claims the exact next revision after main.

Confidence Score: 5/5

Full end-to-end trace verified across Mac document generation, desktop router gating, WebKit/WebView sandbox configurations, native bridge message parsing/throttling, and LRU cache eviction and generation fencing on both iOS and Android.

📁 Important Files Changed
  • main/services/visual-viewer-document.ts: Builds self-contained HTML documents for ui and html visuals with inlined theme tokens and referenced host libraries.
  • main/services/aiden-remote-router.ts: Exposes GET /chats/:id/visuals/:visualId/document gated by chat:read and chat-visual-viewer-v1, with ETag conditional validation (304) and gzip compression.
  • renderer/visual-viewer/main.tsx: Standalone viewer entry point executing AidenUiBlock or sandboxed srcdoc iframes and bridging interactions (ready, prompt, openUrl) to native containers.
  • ios/AidenOnTheGo/Features/Remote/AidenVisualViewer.swift: SwiftUI full-screen sheet and WKWebView container with strict navigation policy and confirmation dialogs for prompts and external links.
  • ios/AidenOnTheGo/Features/Remote/AidenVisualDocument.swift: Actor-backed LRU offline document cache (20 entries / 40 MB max) keyed by instance, device, chat, visual, and appearance scheme/preset.
  • android/app/src/main/java/sbtbiswas/AidenOnTheGo/features/chat/AidenVisualViewerScreen.kt: Jetpack Compose full-screen dialog and WebView setup with JavascriptInterface bridge, render process recovery, and rate-limited user confirmation flows.
  • android/app/src/main/java/sbtbiswas/AidenOnTheGo/persistence/AidenVisualDocumentCache.kt: Thread-safe offline visual document cache with generation fencing to prevent stale cache writes following a purge.
  • protocol/aiden-remote/v1/openapi.json: Documents endpoint schemas, parameter validations, and 200/304 response contracts for contract revision 35.

Findings

No findings.

Sequence Diagram

sequenceDiagram
    autonumber
    participant App as Mobile App (iOS / Android)
    participant Mac as Aiden Host (Mac)
    participant WebView as Sandboxed WebView

    App->>Mac: GET /chats/{chatId}/visuals/{visualId}/document?scheme&theme
    Mac-->>App: 200 text/html (Self-contained viewer document + CSP)
    App->>App: Cache document in AidenVisualDocumentCache
    App->>WebView: Load HTML string (opaque origin, no network/storage)
    WebView->>WebView: Render visual (AidenUiBlock / sandboxed srcdoc iframe)
    WebView->>App: Post message: ready
    App->>App: Clear loading indicator and reveal content
    opt Suggested follow-up prompt
        WebView->>App: Post message: prompt(text)
        App->>App: Display native confirmation dialog/banner
        App->>App: Append confirmed prompt to composer draft
    end
    opt External link action
        WebView->>App: Post message: openUrl(https URL)
        App->>App: Display native confirmation prompt
        App->>App: Open URL in external browser
    end
Loading
[]

Last reviewed commit: 0a6527970224
Reviews (1) · Comment /hermes review to trigger a new review · /hermes review full for full re-review

…able offline on iOS

- The viewer scrolls inside its own full-viewport surface, since the desktop
  stylesheet pins html/body/#root with overflow hidden.
- Android: the visual document cache belongs to the coordinator and is purged
  whenever a pairing is removed; a revoked credential removes the pairing; only
  an unreachable Mac falls back to the saved copy, and a purge during a load
  keeps the document from being written back.
- iOS: before any live /server answer, a pairing with saved documents keeps
  its visuals openable after a cold start without the Mac.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KPgvZHFWvJ95VRjuu4p9LL

@pullfrog pullfrog Bot 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.

✅ No new issues found.

Reviewed changes
Reviewed f516bf369 against the prior reviewed head 29fb57cca, focusing on the three fixes and their behavioral coverage.

  • Enabled full-content scrolling: Added a viewer-owned scroll surface and a phone-sized browser test that reaches and activates bottom actions in both native and HTML visuals.
  • Enforced Android cache cleanup: Moved cache ownership to the coordinator, rejected cached fallback after explicit refusals, handled credential revocation, and fenced late cache writes after removal.
  • Restored iOS offline access: Allowed saved visual documents to remain openable after a cold offline launch while preserving authoritative live feature gating.

Validation passed: viewer production build, all three Chromium viewer tests, six document-builder tests, the four focused Android viewer/client/cache/removal suites, TypeScript checking, and changed Swift syntax parsing. Native iOS XCTest was not run locally because this runner is Linux; hosted iOS, Android, and other CI jobs were still pending or running at the last check.

Pullfrog  | View workflow run | Using gpt-6.1-sol | 𝕏

@very-hermes-bot very-hermes-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Inline review — 1 finding(s) anchored to the diff. See the pinned summary comment for the overview.

The URL is opened with a lowercase scheme, since browser intent filters
match the scheme case-sensitively. iOS already compares case-insensitively.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KPgvZHFWvJ95VRjuu4p9LL

@pullfrog pullfrog Bot 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.

✅ No new issues found.

Reviewed changes
Reviewed db36b8986 against the prior reviewed head f516bf369, tracing Android visual links from bridge parsing through confirmation and browser dispatch.

  • Accepted mixed-case HTTPS schemes: Made scheme validation case-insensitive and normalized the accepted scheme to lowercase for Android browser intents, while preserving the existing host, credential, and input restrictions.
  • Extended behavioral coverage: Added an assertion that HTTPS://Example.com/A becomes https://Example.com/A without changing host or path casing.

Validation: all six AidenVisualViewerModelTest tests passed locally. Hosted CI is not yet green: the Android job failed during emulator SDK installation with Error on ZipFile unknown archive, before product tests; other jobs remain running or queued.

Pullfrog  | View workflow run | Using gpt-6.1-sol | 𝕏

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KPgvZHFWvJ95VRjuu4p9LL

@pullfrog pullfrog Bot 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.

✅ No new issues found.

Reviewed changes
Reviewed merge 0a6527970 against the previously reviewed head db36b8986, focusing on integration with the newly merged main changes.

  • Merged shared visual components: Checked compatibility with workspace-artifact actions in AidenUiBlock and the AUM compiler; the phone viewer retains its existing confirmation bridge and gains no command-execution authority.
  • Preserved viewer integration: Verified that the clean merge retains the viewer build prerequisite, both branches' test registrations, Remote revision 35, and the previously reviewed mobile fixes.

Validation passed: viewer production build, 201 focused behavioral tests, all three Chromium viewer tests, TypeScript checking, and 63 CI-policy tests. Chromium initially could not launch because the runner lacked its executable; after installation, all three tests passed with retries disabled. Native sources are unchanged by this merge and were not retested locally. Hosted CI on this exact head is still queued or running, including the native mobile jobs, so merge readiness is not yet established.

Pullfrog  | View workflow run | Using gpt-6.1-sol | 𝕏

@sambitcreate
sambitcreate merged commit 65a5535 into main Oct 19, 2026
49 of 51 checks passed
@sambitcreate
sambitcreate deleted the claude/project-thread-jxkc0z branch October 19, 2026 23:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants