Port EvanBacon/chat-template to SwiftUI and adopt it as the Mference Mac app UI - #6
Draft
NeelM0906 wants to merge 10 commits into
Draft
Port EvanBacon/chat-template to SwiftUI and adopt it as the Mference Mac app UI#6NeelM0906 wants to merge 10 commits into
NeelM0906 wants to merge 10 commits into
Conversation
…emplate New additive targets (no changes to existing Mference code): - ChatTemplateCore: chat/store models with throttled ~30fps streaming, mock word-by-word backend (template's MOCK_RESPONSES), OpenAI-compatible SSE streaming backend defaulting to the local MferenceServer at http://127.0.0.1:8080/v1, SSE line parser, block-level markdown parser (fenced code, GFM tables, headings, lists, quotes; tolerates unclosed fences while streaming). - ChatTemplateMac: NavigationSplitView chat UI with grouped sidebar (starred/recency buckets, star/rename/delete), streaming markdown messages with shimmer loading and scroll-to-bottom, glass prompt composer with send/stop, model picker menu with extended-thinking toggle, settings (mock mode default; API key kept in login keychain). - ChatTemplateCoreTests: 22 tests covering SSE parsing, markdown blocks, and the streaming lifecycle (send/stop/error/partial-commit/delete).
- New ChatTemplateUI library target: shared SwiftUI chat views (MessageView, MarkdownView, CodeBlockView, TableBlockView, shimmer) used by both ChatTemplateMac and MferenceMac. - MferenceMac OutputPaneView: replace the NSTextView incremental transcript with the template conversation — user bubbles, per-message markdown blocks with code-copy, shimmer during prefill, scroll-to- bottom button. Streaming still drains GenerationTranscriptMailbox on the same 0.1s cadence; live response resolution (mailbox while running, committed outputText when terminal) matches the previous transcript exactly. Placeholder, copy actions, and context menu are unchanged. - MferenceMac PromptComposerView: glass (ultraThinMaterial) composer with auto-growing input and Return-to-send; attachments, prompt tips, clear, and the GenerateControl (tok/s + stop) are preserved.
- RootView: NavigationSplitView with a native toolbar replacing the fixed HStack layout and the status HUD strip. Toolbar carries the model status menu (principal), New Chat, and an inspector toggle; the inspector panel now uses SwiftUI's .inspector presentation. - TemplateSidebarView: source-list sidebar grouped by recency (Today / 7 days / 30 days / Older) with rename/delete context menus and the same guarded selection semantics as before; keeps the local-chats footer and appearance picker. - ModelStatusMenu: model name + status dot in the toolbar, with load/reload/cancel/unload actions and the presentation state line. - Empty state now uses the template copy; prompt example cards no longer show (PromptExamplesView, StatusHUDView, and ChatSidebarView remain in-tree for easy revert but are no longer referenced). - Window uses the standard title bar so the toolbar renders natively.
Fixes the scattered-folders model UX: - ModelLibrary (AppCore): one dedicated, auto-detected place for models. Scans prioritized roots (Mference.libraryRoot override, the package checkout's scratch/ in dev trees, ~/Library/Application Support/ Mference, and the parent of the last remembered directory) for .gturbo directories, identifying each by the family its own manifest declares — so dsv4.gturbo is recognized as DeepSeek-V4-Flash even though the name is not canonical. Downloads always target the first library root; no folder choice required. - AppModel: on launch (persisted app only), when the remembered directory holds no complete install, the first installed library model is adopted automatically instead of showing 'Model required' for a phantom path. New selectModel(family:) switches between shipped models — installed ones activate at their detected location; missing ones route to the install screen targeted at the library root. The installer client is now swapped per family via an injectable factory. Catalog refreshes on path changes and after installs. - ModelStatusMenu: the toolbar picker now lists the whole model family. Installed models activate directly (checkmark on the active one); missing models show a Download row with size, quant type, and parameter markers (e.g. 'Gemma 4 26B-A4B IT 4-bit · 14.6 GB'). - Tests: ModelLibraryTests cover per-family entries, manifest-based (not name-based) detection, root priority, incomplete-install skipping, and candidate-root ordering/dedup.
…-template-swift-desktop-3b0dc7
Merges claude/inkling-small-mlx-quant-fae643 (clean, no conflicts) so the runtime on this branch can run Inkling-Small, and adds the inklingSmall descriptor to ModelLibrary.shippedDescriptors and the family-preference mapping. The toolbar picker now lists all four models; an installed inklingsmall.gturbo is auto-detected by its manifest family like the others.
Install receipts bind to the directory a model was verified at, so a symlinked library entry (scratch/inklingsmall.gturbo -> ~/Downloads/inklingsmall.gturbo) failed the probe's directory-binding check and showed as downloadable. The library scan now resolves symlinks before probing, so verification and activation both use the model's real path.
Restores the HUD's tok/s / tokens / memory readouts, dropped in the shell reskin, as the top of the inspector — replacing the Path, Choose Model Folder, Unload Model, and State rows the model library and toolbar menu made redundant. Live token rate and count stream during decode (last-run values when idle), and inference memory is resampled every second via a TimelineView tick. Install size rows still appear while a download is required.
…swift-desktop-3b0dc7
…swift-desktop-3b0dc7
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.
What changed
Three commits, building on each other:
ChatTemplateMac— a SwiftUI desktop port of EvanBacon/chat-template (new, additive)ChatTemplateCorelibrary: chat/store models with the template's throttled ~30 fps streaming-store pattern, the template's mock word-by-word streaming backend, an OpenAI-compatible SSE streaming backend (defaults to the local MferenceServer athttp://127.0.0.1:8080/v1), an SSE line parser, and a block-level markdown parser (fenced code, GFM tables, headings, lists, quotes; tolerates unclosed fences mid-stream).ChatTemplateMacapp: split-view chat UI with grouped sidebar (starred/recency, star/rename/delete), streaming markdown messages with shimmer loading and scroll-to-bottom, glass prompt composer, model-picker menu, Settings (mock mode by default; API key kept in the login keychain).swift run ChatTemplateMacWire the template UI into the Mference Mac app
ChatTemplateUIlibrary target shares the template's SwiftUI views (message bubbles, markdown renderer with code-copy, shimmer) between both apps.OutputPaneView: the NSTextView incremental transcript is replaced with the template conversation. Streaming still drainsGenerationTranscriptMailboxon the same 0.1 s cadence, and live/committed response resolution (mailbox while running,outputTextwhen terminal) matches the previous transcript exactly. Placeholder, copy actions, and the context menu are unchanged.PromptComposerView: glass (ultraThinMaterial) composer with auto-growing input and Return-to-send; attachments, prompt tips, clear, and the GenerateControl (live tok/s + stop) are preserved.Reskin the Mference app shell to the template design
RootViewbecomes aNavigationSplitViewwith a native toolbar: model status menu (name + status dot, load/reload/cancel/unload actions), New Chat, and an inspector toggle; the runtime-controls panel now presents via SwiftUI.inspector.TemplateSidebarView: native source list grouped by recency with rename/delete context menus and the same guarded selection semantics; keeps the local-chats footer and appearance picker.Why
Requested: implement chat-template as a Swift desktop app, then wire it into the Mference Mac app as its working chat UI.
Notes for reviewers
AppModel, the decode service, and the mailbox protocol are untouched.StatusHUDView,ChatSidebarView, andPromptExamplesViewremain in-tree but unreferenced, to keep reverting or blending the old design cheap. Happy to delete them instead if preferred.ChatTemplateCoreTests(22 tests — SSE parsing, markdown blocks, streaming lifecycle incl. stop/partial-commit/error/delete-cancels). Full run: 269 tests in the affected suites pass viaScripts/test.sh.generatingChatID), no silent mock fallback on a bad base URL, server error bodies survive into the error banner, API key stored in the keychain rather than UserDefaults.Test plan
Scripts/test.sh --filter "ChatTemplateCoreTests|MferenceMacPresentationTests|MferenceAppCoreTests"— 269 tests passswift build(all targets, debug + release) cleanMferenceMaclaunches with the new shell; model-load placeholder, sidebar, toolbar, and composer verified