153 lines
8.2 KiB
Markdown
153 lines
8.2 KiB
Markdown
# Sybil for iOS and Mac Catalyst
|
|
|
|
Run `just run` for the iPhone simulator, or `just run-mac` for Mac Catalyst.
|
|
`just build-mac` builds without launching the Mac app. Both regenerate the Xcode
|
|
project from `project.yml`. The Mac recipes use ad-hoc signing for local development;
|
|
release/archive signing settings are unchanged.
|
|
|
|
The conversation sidebar includes **Search chats and web searches** on iPhone,
|
|
iPad, and Mac. It searches all saved history by title, conversation text, and saved
|
|
web-search query/answer, with single-line excerpts that bold matching words and
|
|
truncate in the middle. Search waits briefly while typing,
|
|
cancels superseded requests, and leaves the current conversation open. Clear the
|
|
field to return to recent items. Searches use word prefixes (for example, `plan`
|
|
finds `planning`); if more than 100 items match, refine the query.
|
|
|
|
## Sybil Agent
|
|
|
|
The permanent **Sybil Agent** sidebar item opens the persistent room on both
|
|
phone and iPad. It uses the configured Sybil API URL (including an explicit
|
|
`/api` path) and token. The room stays subscribed while other chats are selected;
|
|
foreground and network recovery replay from the last merged cursor. Shared unread
|
|
counts include only public assistant replies and are acknowledged after the
|
|
visible transcript reaches the bottom and its entrance animation finishes.
|
|
|
|
Multiple messages can be queued while the Agent works. The local outbox is saved
|
|
atomically under Application Support before submission and is scoped to the API
|
|
base URL. An interrupted send stays on its original bubble with **Retry**, retaining
|
|
its request ID and timestamp across relaunch. A canonical server echo confirms it
|
|
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.
|
|
|
|
Agent contracts remain in `../docs/api/rest.md` and
|
|
`../docs/api/streaming-chat.md`; this client requires no backend deployment.
|
|
|
|
### Agent regression and Simulator checks
|
|
|
|
Run these commands from this worktree's `ios/` directory:
|
|
|
|
```sh
|
|
just build
|
|
just test
|
|
just run
|
|
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.
|
|
For interactive UI coverage, start the local fixture (Python with `aiohttp`):
|
|
|
|
```sh
|
|
python3 Tests/Fixtures/agent_server.py
|
|
```
|
|
|
|
In a second terminal, run:
|
|
|
|
```sh
|
|
just generate
|
|
xcodebuild test -scheme SybilAgentUI \
|
|
-destination 'platform=iOS Simulator,name=iPhone 16e,OS=latest' \
|
|
-parallel-testing-enabled NO \
|
|
-resultBundlePath build/agent-evidence/phone-ui.xcresult
|
|
```
|
|
|
|
The fixture binds only to `127.0.0.1:8799`, uses `fixture-token`, and never contacts
|
|
external services. UI tests exercise the real REST/WebSocket client and retain
|
|
screenshots in the result bundle. They cover queued submissions, uncertain
|
|
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.
|
|
Use a fresh result-bundle path for each run. Check the same UI on iPad and with
|
|
Simulator Reduce Motion enabled before release.
|
|
|
|
## Quick Question on macOS
|
|
|
|
While the Catalyst app is running, **Option+Space** toggles a floating Quick
|
|
Question panel, including over other applications. The prompt is focused as soon
|
|
as it opens, with any existing prompt selected so typing replaces it. The same
|
|
select-on-open behavior applies to Quick Question on iPhone and iPad.
|
|
**Return** submits; **Shift+Return** inserts a new line. **Escape**, a
|
|
second **Option+Space**, the close button, or clicking outside dismisses it.
|
|
Hiding the panel preserves the draft and answer and lets an in-flight answer finish.
|
|
**Open in Chat** saves the question and answer in the regular workspace.
|
|
|
|
Quick Question defaults to OpenAI `chat-latest` on iPhone, iPad, and Mac. Its saved
|
|
provider/model selection takes precedence and is separate from regular chat preferences.
|
|
|
|
The regular Mac chat/search composer uses the same Return/Shift+Return rules.
|
|
Holding Return does not repeatedly submit. On iOS, Return submits from Quick
|
|
Question, while the normal chat/search composer continues to use Return for a
|
|
new line.
|
|
|
|
Closing the last Mac window leaves Sybil running, so Option+Space still works.
|
|
Use **Sybil → Quit Sybil** or **Command+Q** to quit the application. The Catalyst
|
|
build opts out of automatic termination, and the native shortcut service holds a
|
|
matching automatic-termination activity until it stops. No hidden keep-alive
|
|
window or sleep-preventing activity is used. Mac scene support also allows the
|
|
workspace to reopen after its last window is closed.
|
|
|
|
When Catalyst is backgrounded, opening Quick Question first requests app
|
|
activation and waits for UIKit to enter the foreground before creating or ordering
|
|
the native panel. Presentation is deferred out of the hotkey event callback.
|
|
Pressing Option+Space again cancels a pending presentation. Dismissing a panel
|
|
that required activation returns focus to the previous app; explicitly opening
|
|
the workspace keeps focus in Sybil.
|
|
|
|
On Mac, **Command+N** starts a new chat in the focused workspace, or opens a new
|
|
workspace window when none are open. **Command+Shift+N** always opens a new window,
|
|
including while signed out. **Command+Option+N** starts a new search; iOS retains
|
|
its existing Command+Shift+N search shortcut.
|
|
|
|
The shortcut is also shown under **File → Quick Question**. If another application
|
|
already owns Option+Space, the panel reports that the shortcut is unavailable;
|
|
the menu item can still be clicked. No Accessibility or Input Monitoring grant is
|
|
needed for the registered hotkey.
|
|
|
|
The native AppKit panel and Carbon hotkey live in `Apps/SybilMacQuickQuestion`,
|
|
a macOS bundle embedded only for the Mac Catalyst destination. Catalyst loads it
|
|
through the Foundation-only `SybilMacQuickQuestionBridge` contract. Requests,
|
|
provider/model preferences, streaming, and conversion to chat remain in the
|
|
existing `SybilViewModel`; there is no separate backend or API contract. The panel
|
|
uses AppKit controls rather than trying to load the macOS SwiftUI runtime into a
|
|
Catalyst process.
|
|
|
|
The iPhone/iPad app keeps its existing Quick Question sheet and Home Screen quick
|
|
action, and does not build or embed the macOS helper.
|
|
|
|
## Verification
|
|
|
|
- `just test`: existing Swift package tests on the iPhone simulator.
|
|
- From `Packages/Sybil`, run `xcodebuild test -scheme Sybil -destination 'platform=macOS,variant=Mac Catalyst' -parallel-testing-enabled NO` for package tests including the Catalyst panel controller.
|
|
- For a manual Mac check, open the panel from another app, type immediately,
|
|
submit, hide/reopen during streaming, and verify Escape/outside-click dismissal
|
|
returns input to the previous app. Check a second display and a full-screen Space
|
|
when available.
|
|
- Close every Mac window, invoke Option+Space, and verify the saved question and
|
|
answer remain available. Reopen the workspace from the panel, then explicitly
|
|
quit with Command+Q. Rebuild and relaunch after changing lifecycle plist keys.
|
|
- In both Mac and iOS Quick Question, reopen an existing prompt and type to replace
|
|
it. On iOS, verify Return submits Quick Question while Return in the normal
|
|
prompt adds a newline. In the Mac workspace, verify Return submits and
|
|
Shift+Return adds a newline.
|
|
- Check Command+N both with a workspace open and after closing every workspace.
|
|
Command+Shift+N must open another window even when one already exists, and
|
|
Command+Option+N must start a search without opening a window.
|
|
- With all workspace windows closed, switch to another app and repeatedly open
|
|
and dismiss Quick Question, including two quick Option+Space presses while it
|
|
is opening. Check that no late panel appears after cancellation and that no
|
|
`UINSAppLifecycleStateRunningNoOpenWindows` assertion occurs.
|