Skip to content

Add chat history and document attachments to the Mac app - #15

Open
dmitrymalakhov wants to merge 5 commits into
drumih:mainfrom
dmitrymalakhov:agent/add-chat-history-and-document-attachments
Open

Add chat history and document attachments to the Mac app#15
dmitrymalakhov wants to merge 5 commits into
drumih:mainfrom
dmitrymalakhov:agent/add-chat-history-and-document-attachments

Conversation

@dmitrymalakhov

@dmitrymalakhov dmitrymalakhov commented Jul 28, 2026

Copy link
Copy Markdown

Summary

  • add persistent multi-turn chat history to the Mac app
  • support document attachments with local text extraction for PDF, DOCX, PPTX, and XLSX files
  • fit retained conversations into the available model context window using bounded rolling summaries
  • add System, Light, and Dark appearance preferences
  • add collapsible chat and settings sidebars
  • integrate the new chat experience with the latest upstream prompt, runtime, model-selection, and decode-service behavior
  • add coverage for conversation state, context fitting, document extraction, settings, and presentation behavior

Motivation

The Mac app previously focused on isolated prompt-and-response runs and could not incorporate document content into a conversation.

This change adds persistent multi-turn conversations and bounded document ingestion while preserving the runtime’s context and memory constraints. It also improves the app layout, provides explicit appearance controls, and keeps the chat workflow compatible with the latest upstream runtime and prompt settings.

User impact

Users can:

  • continue conversations across multiple turns
  • create, rename, select, and delete independent chats
  • attach supported documents as prompt context
  • retain full transcripts while older context is compressed into a rolling summary
  • choose whether sent prompts are kept or cleared
  • choose Return or Command-Return for message submission
  • select System, Light, or Dark appearance
  • hide or restore the chat and settings sidebars

Document text is extracted locally. The current user turn is never silently discarded when fitting conversation history into the model context.

Upstream integration

The branch has been merged with the current upstream/main.

Conflict resolution preserves both the PR functionality and newer upstream behavior, including:

  • prompt submission preferences
  • prompt example visibility settings
  • About panel and model reveal actions
  • updated runtime controls
  • decode-service response routing
  • current CLI and local server behavior

Validation

  • Scripts/test.sh — 777 tests in 132 suites passed on fd5069c
  • ruby Scripts/check_markdown_links.rb — 22 Markdown files passed
  • ruby Scripts/check_app_version.rb — app version 0.4.3 matches the latest release
TurboFieldfare Mac app with chat history and document attachments

Add multi-turn chat state, context-window management, document text extraction, attachment handling, app presentation updates, and comprehensive test coverage.
@dmitrymalakhov
dmitrymalakhov marked this pull request as ready for review July 28, 2026 20:21
NeelM0906 added a commit to NeelM0906/Mference that referenced this pull request Aug 1, 2026
Replace the single prompt string in AppGenerationRequest with an ordered
[AppGenerationMessage] list and extend the decode-service request the same
way, keeping the old prompt-based initializers and a computed `prompt`
accessor for existing callers.

AppGenerationContextWindow fits a conversation into the available context by
binary-searching user-turn suffixes and measuring each candidate with the
model tokenizer. Rendering stays behind MFTokenizer.applyChatTemplate, so the
same code path produces Gemma turn markers or Qwen 3.6 ChatML depending on the
installed checkpoint's tokenizer.

AppPromptContext composes attachment text into a bounded prompt block and
marks documents that were trimmed to fit.

Ports drumih/turbo-fieldfare#15 by @dmitrymalakhov.
NeelM0906 added a commit to NeelM0906/Mference that referenced this pull request Aug 1, 2026
AppModel now owns a list of AppChats instead of a single prompt field. Each
chat keeps its messages, draft, draft attachments, and a rolling context
summary; the archive is written next to the model directory on a serialized
background queue and flushed on termination. An unreadable archive is
quarantined as mac-app-chats.recovery-*.json rather than deleted.

Before a turn is committed to history the client prepares the request with the
real tokenizer. Turns that no longer fit are replaced in model context by a
locally generated rolling summary, surfaced as the new .compressing generation
phase. The pending user turn is never silently dropped: if it alone overflows,
the run fails and the text stays in the composer.

AppModelLocation remembers an explicitly chosen model directory in
UserDefaults while keeping Mference's per-family install-directory resolution,
so the remembered path wins over the gemma4/qwen36 default without changing
which family the descriptor selects.

Ports drumih/turbo-fieldfare#15 by @dmitrymalakhov.
NeelM0906 added a commit to NeelM0906/Mference that referenced this pull request Aug 1, 2026
DocumentTextExtractor reads PDF via PDFKit and DOCX/PPTX/XLSX by streaming
selected archive members through /usr/bin/unzip into a SAX parser. Extraction
is bounded at every step — 32 MiB per archive member, 64 MiB of selected XML,
240k extracted characters, and an early break once a PDF exceeds twice that —
so a large document cannot pull unbounded content into the app process.

AppChromePresentation carries the sidebar toggle copy, header layout metrics,
and model action labels; AppAppearance persists the System/Light/Dark choice.
The transcript document controller renders prior turns before the streaming
answer and rebuilds cleanly when the selected chat changes.

Ports drumih/turbo-fieldfare#15 by @dmitrymalakhov.
NeelM0906 added a commit to NeelM0906/Mference that referenced this pull request Aug 1, 2026
Add a collapsible chat sidebar with rename/delete, a paperclip importer that
extracts document text off the main actor, a Choose Model Folder… picker in
the Model menu and install view, and System/Light/Dark appearance commands.
The status header now hosts both sidebar toggles with symmetric padding, and
the output pane renders the full chat transcript instead of a single turn.

Document the chat sidebar, attachments, and history compression in the README
and docs/RUNTIME_CONTROLS.md.

Ports drumih/turbo-fieldfare#15 by @dmitrymalakhov.
he-be added a commit to he-be/turbo-fieldfare that referenced this pull request Aug 21, 2026
本線 oQ4e-g64 の lm_head は 8-bit g64 で、既存の融合ヘッドは INT4 しか
読めなかった。INT4 版 (logit.metal) と同じ 2 段の形で INT8 を書いた:
語彙幅の logit をどこにも書かず、8 行ごとの argmax を summaries に落として畳む。

INT4 から写すときに変わるのは 2 か所だけで、どちらも静かに壊れる。
行の刻みが N/2 ではなく N であること、そして 4-bit の sym と違って
INT8 の零点は本物のデータなので b·Σx を落とせないこと。両方とも負例にした。

- qwen_lm_head_greedy_int8_rows_chunk_raw / _reduce (qwen.metal)
- QwenLMHeadChainInt8。vocab には 248,077 を渡す。末尾 243 行は未学習で、
  マスクのコードは要らず引数だけで済むことを検査で確かめた
- --qwen は 39 本 (drumih#15 で 10 本増、うち 4 本は負例)。
  dequant_int8_gemv_simd を二人目の証人にして、参照との一致と
  chain との直接比較の 2 通りに使う

実物の語彙 (248,077 x 2048) で 1 トークン 4.008/4.039/4.047 ms、
540 MB を 133〜135 GB/s。LM head だけで decode の天井が約 248 tok/s。
帯域の実測が導出の前提 150 GB/s より 11% 低いので、01-MODEL §5-5 の
79 tok/s は 71 tok/s の側で読む。

docs/qwen35moe/19-LM-HEAD-INT8.md

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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.

1 participant