mafdet 0.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. mafdet-0.3.0/LICENSE +201 -0
  2. mafdet-0.3.0/PKG-INFO +330 -0
  3. mafdet-0.3.0/README.md +295 -0
  4. mafdet-0.3.0/mafdet/__init__.py +12 -0
  5. mafdet-0.3.0/mafdet/__main__.py +6 -0
  6. mafdet-0.3.0/mafdet/awaken.py +64 -0
  7. mafdet-0.3.0/mafdet/catalog.json +742 -0
  8. mafdet-0.3.0/mafdet/cli.py +448 -0
  9. mafdet-0.3.0/mafdet/core/__init__.py +1 -0
  10. mafdet-0.3.0/mafdet/core/bench.py +57 -0
  11. mafdet-0.3.0/mafdet/core/catalog.py +242 -0
  12. mafdet-0.3.0/mafdet/core/chat.py +250 -0
  13. mafdet-0.3.0/mafdet/core/config.py +104 -0
  14. mafdet-0.3.0/mafdet/core/downloads.py +81 -0
  15. mafdet-0.3.0/mafdet/core/hardware.py +394 -0
  16. mafdet-0.3.0/mafdet/core/llama_setup.py +181 -0
  17. mafdet-0.3.0/mafdet/core/tasks.py +108 -0
  18. mafdet-0.3.0/mafdet/doctor.py +56 -0
  19. mafdet-0.3.0/mafdet/engine.py +413 -0
  20. mafdet-0.3.0/mafdet/gui.py +188 -0
  21. mafdet-0.3.0/mafdet/hunt.py +259 -0
  22. mafdet-0.3.0/mafdet/identity.py +69 -0
  23. mafdet-0.3.0/mafdet/judge.py +111 -0
  24. mafdet-0.3.0/mafdet/llama_backend.py +396 -0
  25. mafdet-0.3.0/mafdet/models.py +76 -0
  26. mafdet-0.3.0/mafdet/progress.py +100 -0
  27. mafdet-0.3.0/mafdet/race.py +120 -0
  28. mafdet-0.3.0/mafdet/samples/documento.txt +22 -0
  29. mafdet-0.3.0/mafdet/samples/domanda.txt +1 -0
  30. mafdet-0.3.0/mafdet/samples/messaggio_breve.txt +1 -0
  31. mafdet-0.3.0/mafdet/samples/messaggio_medio.txt +1 -0
  32. mafdet-0.3.0/mafdet/strike.py +13 -0
  33. mafdet-0.3.0/mafdet/text.py +66 -0
  34. mafdet-0.3.0/mafdet/tui/__init__.py +6 -0
  35. mafdet-0.3.0/mafdet/tui/app.py +1321 -0
  36. mafdet-0.3.0/mafdet/tui/art.py +88 -0
  37. mafdet-0.3.0/mafdet/tui/fx.py +153 -0
  38. mafdet-0.3.0/mafdet/tui/launcher.py +140 -0
  39. mafdet-0.3.0/mafdet/tui/mathtext.py +51 -0
  40. mafdet-0.3.0/mafdet/ui/app.css +855 -0
  41. mafdet-0.3.0/mafdet/ui/app.js +279 -0
  42. mafdet-0.3.0/mafdet/ui/chat.js +552 -0
  43. mafdet-0.3.0/mafdet/ui/fonts/OFL-Archivo.txt +93 -0
  44. mafdet-0.3.0/mafdet/ui/fonts/OFL-JetBrainsMono.txt +93 -0
  45. mafdet-0.3.0/mafdet/ui/fonts/archivo.woff2 +0 -0
  46. mafdet-0.3.0/mafdet/ui/fonts/jetbrains-mono.woff2 +0 -0
  47. mafdet-0.3.0/mafdet/ui/i18n/de.json +226 -0
  48. mafdet-0.3.0/mafdet/ui/i18n/en.json +226 -0
  49. mafdet-0.3.0/mafdet/ui/i18n/fr.json +226 -0
  50. mafdet-0.3.0/mafdet/ui/i18n/it.json +226 -0
  51. mafdet-0.3.0/mafdet/ui/index.html +125 -0
  52. mafdet-0.3.0/mafdet/ui/mafdet.ico +0 -0
  53. mafdet-0.3.0/mafdet/ui/views.js +516 -0
  54. mafdet-0.3.0/mafdet/watch.py +1101 -0
  55. mafdet-0.3.0/mafdet.egg-info/PKG-INFO +330 -0
  56. mafdet-0.3.0/mafdet.egg-info/SOURCES.txt +66 -0
  57. mafdet-0.3.0/mafdet.egg-info/dependency_links.txt +1 -0
  58. mafdet-0.3.0/mafdet.egg-info/entry_points.txt +2 -0
  59. mafdet-0.3.0/mafdet.egg-info/requires.txt +11 -0
  60. mafdet-0.3.0/mafdet.egg-info/top_level.txt +1 -0
  61. mafdet-0.3.0/pyproject.toml +60 -0
  62. mafdet-0.3.0/setup.cfg +4 -0
  63. mafdet-0.3.0/tests/test_branches.py +55 -0
  64. mafdet-0.3.0/tests/test_hardware_catalog.py +117 -0
  65. mafdet-0.3.0/tests/test_i18n.py +32 -0
  66. mafdet-0.3.0/tests/test_mathtext.py +19 -0
  67. mafdet-0.3.0/tests/test_setup_downloads.py +118 -0
  68. mafdet-0.3.0/tests/test_tui.py +114 -0
mafdet-0.3.0/LICENSE ADDED
@@ -0,0 +1,201 @@
1
+
2
+ Apache License
3
+ Version 2.0, January 2004
4
+ http://www.apache.org/licenses/
5
+
6
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7
+
8
+ 1. Definitions.
9
+
10
+ "License" shall mean the terms and conditions for use, reproduction,
11
+ and distribution as defined by Sections 1 through 9 of this document.
12
+
13
+ "Licensor" shall mean the copyright owner or entity authorized by
14
+ the copyright owner that is granting the License.
15
+
16
+ "Legal Entity" shall mean the union of the acting entity and all
17
+ other entities that control, are controlled by, or are under common
18
+ control with that entity. For the purposes of this definition,
19
+ "control" means (i) the power, direct or indirect, to cause the
20
+ direction or management of such entity, whether by contract or
21
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
22
+ outstanding shares, or (iii) beneficial ownership of such entity.
23
+
24
+ "You" (or "Your") shall mean an individual or Legal Entity
25
+ exercising permissions granted by this License.
26
+
27
+ "Source" form shall mean the preferred form for making modifications,
28
+ including but not limited to software source code, documentation
29
+ source, and configuration files.
30
+
31
+ "Object" form shall mean any form resulting from mechanical
32
+ transformation or translation of a Source form, including but
33
+ not limited to compiled object code, generated documentation,
34
+ and conversions to other media types.
35
+
36
+ "Work" shall mean the work of authorship, whether in Source or
37
+ Object form, made available under the License, as indicated by a
38
+ copyright notice that is included in or attached to the work
39
+ (an example is provided in the Appendix below).
40
+
41
+ "Derivative Works" shall mean any work, whether in Source or Object
42
+ form, that is based on (or derived from) the Work and for which the
43
+ editorial revisions, annotations, elaborations, or other modifications
44
+ represent, as a whole, an original work of authorship. For the purposes
45
+ of this License, Derivative Works shall not include works that remain
46
+ separable from, or merely link (or bind by name) to the interfaces of,
47
+ the Work and Derivative Works thereof.
48
+
49
+ "Contribution" shall mean any work of authorship, including
50
+ the original version of the Work and any modifications or additions
51
+ to that Work or Derivative Works thereof, that is intentionally
52
+ submitted to Licensor for inclusion in the Work by the copyright owner
53
+ or by an individual or Legal Entity authorized to submit on behalf of
54
+ the copyright owner. For the purposes of this definition, "submitted"
55
+ means any form of electronic, verbal, or written communication sent
56
+ to the Licensor or its representatives, including but not limited to
57
+ communication on electronic mailing lists, source code control systems,
58
+ and issue tracking systems that are managed by, or on behalf of, the
59
+ Licensor for the purpose of discussing and improving the Work, but
60
+ excluding communication that is conspicuously marked or otherwise
61
+ designated in writing by the copyright owner as "Not a Contribution."
62
+
63
+ "Contributor" shall mean Licensor and any individual or Legal Entity
64
+ on behalf of whom a Contribution has been received by Licensor and
65
+ subsequently incorporated within the Work.
66
+
67
+ 2. Grant of Copyright License. Subject to the terms and conditions of
68
+ this License, each Contributor hereby grants to You a perpetual,
69
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70
+ copyright license to reproduce, prepare Derivative Works of,
71
+ publicly display, publicly perform, sublicense, and distribute the
72
+ Work and such Derivative Works in Source or Object form.
73
+
74
+ 3. Grant of Patent License. Subject to the terms and conditions of
75
+ this License, each Contributor hereby grants to You a perpetual,
76
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77
+ (except as stated in this section) patent license to make, have made,
78
+ use, offer to sell, sell, import, and otherwise transfer the Work,
79
+ where such license applies only to those patent claims licensable
80
+ by such Contributor that are necessarily infringed by their
81
+ Contribution(s) alone or by combination of their Contribution(s)
82
+ with the Work to which such Contribution(s) was submitted. If You
83
+ institute patent litigation against any entity (including a
84
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
85
+ or a Contribution incorporated within the Work constitutes direct
86
+ or contributory patent infringement, then any patent licenses
87
+ granted to You under this License for that Work shall terminate
88
+ as of the date such litigation is filed.
89
+
90
+ 4. Redistribution. You may reproduce and distribute copies of the
91
+ Work or Derivative Works thereof in any medium, with or without
92
+ modifications, and in Source or Object form, provided that You
93
+ meet the following conditions:
94
+
95
+ (a) You must give any other recipients of the Work or
96
+ Derivative Works a copy of this License; and
97
+
98
+ (b) You must cause any modified files to carry prominent notices
99
+ stating that You changed the files; and
100
+
101
+ (c) You must retain, in the Source form of any Derivative Works
102
+ that You distribute, all copyright, patent, trademark, and
103
+ attribution notices from the Source form of the Work,
104
+ excluding those notices that do not pertain to any part of
105
+ the Derivative Works; and
106
+
107
+ (d) If the Work includes a "NOTICE" text file as part of its
108
+ distribution, then any Derivative Works that You distribute must
109
+ include a readable copy of the attribution notices contained
110
+ within such NOTICE file, excluding those notices that do not
111
+ pertain to any part of the Derivative Works, in at least one
112
+ of the following places: within a NOTICE text file distributed
113
+ as part of the Derivative Works; within the Source form or
114
+ documentation, if provided along with the Derivative Works; or,
115
+ within a display generated by the Derivative Works, if and
116
+ wherever such third-party notices normally appear. The contents
117
+ of the NOTICE file are for informational purposes only and
118
+ do not modify the License. You may add Your own attribution
119
+ notices within Derivative Works that You distribute, alongside
120
+ or as an addendum to the NOTICE text from the Work, provided
121
+ that such additional attribution notices cannot be construed
122
+ as modifying the License.
123
+
124
+ You may add Your own copyright statement to Your modifications and
125
+ may provide additional or different license terms and conditions
126
+ for use, reproduction, or distribution of Your modifications, or
127
+ for any such Derivative Works as a whole, provided Your use,
128
+ reproduction, and distribution of the Work otherwise complies with
129
+ the conditions stated in this License.
130
+
131
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
132
+ any Contribution intentionally submitted for inclusion in the Work
133
+ by You to the Licensor shall be under the terms and conditions of
134
+ this License, without any additional terms or conditions.
135
+ Notwithstanding the above, nothing herein shall supersede or modify
136
+ the terms of any separate license agreement you may have executed
137
+ with Licensor regarding such Contributions.
138
+
139
+ 6. Trademarks. This License does not grant permission to use the trade
140
+ names, trademarks, service marks, or product names of the Licensor,
141
+ except as required for reasonable and customary use in describing the
142
+ origin of the Work and reproducing the content of the NOTICE file.
143
+
144
+ 7. Disclaimer of Warranty. Unless required by applicable law or
145
+ agreed to in writing, Licensor provides the Work (and each
146
+ Contributor provides its Contributions) on an "AS IS" BASIS,
147
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148
+ implied, including, without limitation, any warranties or conditions
149
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150
+ PARTICULAR PURPOSE. You are solely responsible for determining the
151
+ appropriateness of using or redistributing the Work and assume any
152
+ risks associated with Your exercise of permissions under this License.
153
+
154
+ 8. Limitation of Liability. In no event and under no legal theory,
155
+ whether in tort (including negligence), contract, or otherwise,
156
+ unless required by applicable law (such as deliberate and grossly
157
+ negligent acts) or agreed to in writing, shall any Contributor be
158
+ liable to You for damages, including any direct, indirect, special,
159
+ incidental, or consequential damages of any character arising as a
160
+ result of this License or out of the use or inability to use the
161
+ Work (including but not limited to damages for loss of goodwill,
162
+ work stoppage, computer failure or malfunction, or any and all
163
+ other commercial damages or losses), even if such Contributor
164
+ has been advised of the possibility of such damages.
165
+
166
+ 9. Accepting Warranty or Additional Liability. While redistributing
167
+ the Work or Derivative Works thereof, You may choose to offer,
168
+ and charge a fee for, acceptance of support, warranty, indemnity,
169
+ or other liability obligations and/or rights consistent with this
170
+ License. However, in accepting such obligations, You may act only
171
+ on Your own behalf and on Your sole responsibility, not on behalf
172
+ of any other Contributor, and only if You agree to indemnify,
173
+ defend, and hold each Contributor harmless for any liability
174
+ incurred by, or claims asserted against, such Contributor by reason
175
+ of your accepting any such warranty or additional liability.
176
+
177
+ END OF TERMS AND CONDITIONS
178
+
179
+ APPENDIX: How to apply the Apache License to your work.
180
+
181
+ To apply the Apache License to your work, attach the following
182
+ boilerplate notice, with the fields enclosed by brackets "[]"
183
+ replaced with your own identifying information. (Don't include
184
+ the brackets!) The text should be enclosed in the appropriate
185
+ comment syntax for the file format. We also recommend that a
186
+ file or class name and description of purpose be included on the
187
+ same "printed page" as the copyright notice for easier
188
+ identification within third-party archives.
189
+
190
+ Copyright 2026 Simone Di Natale
191
+ Licensed under the Apache License, Version 2.0 (the "License");
192
+ you may not use this file except in compliance with the License.
193
+ You may obtain a copy of the License at
194
+
195
+ http://www.apache.org/licenses/LICENSE-2.0
196
+
197
+ Unless required by applicable law or agreed to in writing, software
198
+ distributed under the License is distributed on an "AS IS" BASIS,
199
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200
+ See the License for the specific language governing permissions and
201
+ limitations under the License.
mafdet-0.3.0/PKG-INFO ADDED
@@ -0,0 +1,330 @@
1
+ Metadata-Version: 2.4
2
+ Name: mafdet
3
+ Version: 0.3.0
4
+ Summary: You type. It already knows. Local LLMs that read and think while you type.
5
+ License-Expression: Apache-2.0
6
+ Project-URL: Homepage, https://github.com/TheLastOxygen/mafdet
7
+ Project-URL: Issues, https://github.com/TheLastOxygen/mafdet/issues
8
+ Project-URL: Releases, https://github.com/TheLastOxygen/mafdet/releases
9
+ Project-URL: Research, https://github.com/TheLastOxygen/mafdet/blob/main/research/LOG.md
10
+ Keywords: llm,llama.cpp,local,inference,prefill,reasoning,qwen3,chat
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Environment :: Console
13
+ Classifier: Environment :: GPU
14
+ Classifier: Intended Audience :: End Users/Desktop
15
+ Classifier: Intended Audience :: Science/Research
16
+ Classifier: Operating System :: Microsoft :: Windows
17
+ Classifier: Operating System :: MacOS
18
+ Classifier: Operating System :: POSIX :: Linux
19
+ Classifier: Programming Language :: Python :: 3
20
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
21
+ Requires-Python: >=3.10
22
+ Description-Content-Type: text/markdown
23
+ License-File: LICENSE
24
+ Requires-Dist: transformers>=4.51
25
+ Requires-Dist: huggingface_hub>=0.30
26
+ Requires-Dist: jinja2>=3.1
27
+ Requires-Dist: packaging
28
+ Requires-Dist: psutil>=5.9
29
+ Requires-Dist: pywebview>=5
30
+ Requires-Dist: textual>=8.0
31
+ Provides-Extra: research
32
+ Requires-Dist: torch>=2.4; extra == "research"
33
+ Requires-Dist: rich; extra == "research"
34
+ Dynamic: license-file
35
+
36
+ <div align="center">
37
+
38
+ <picture>
39
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/TheLastOxygen/mafdet/main/assets/mafdet-logo-dark.svg">
40
+ <img src="https://raw.githubusercontent.com/TheLastOxygen/mafdet/main/assets/mafdet-logo.svg" alt="" width="112">
41
+ </picture>
42
+
43
+ <h1>
44
+ <picture>
45
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/TheLastOxygen/mafdet/main/assets/mafdet-wordmark-dark.svg">
46
+ <img src="https://raw.githubusercontent.com/TheLastOxygen/mafdet/main/assets/mafdet-wordmark.svg" alt="MAFDET" height="30">
47
+ </picture>
48
+ </h1>
49
+
50
+ ### You type. It already knows.
51
+
52
+ MAFDET reads your message while you type it, and **starts thinking about it before you send it**.<br>
53
+ Hit Enter, and most of the work is already done.
54
+
55
+ [![License: Apache-2.0](https://img.shields.io/badge/license-Apache--2.0-EEEAE2?labelColor=0E0D0C)](https://github.com/TheLastOxygen/mafdet/blob/main/LICENSE)
56
+ [![Runtime: local](https://img.shields.io/badge/runtime-local-D4892A?labelColor=0E0D0C)](#requirements)
57
+ [![Status: prototype](https://img.shields.io/badge/status-prototype-6A655D?labelColor=0E0D0C)](#roadmap)
58
+
59
+ [Italiano](https://github.com/TheLastOxygen/mafdet/blob/main/README.it.md)
60
+
61
+ </div>
62
+
63
+ ---
64
+
65
+ ## Why
66
+
67
+ Chat interfaces make the model wait for you to press Enter before it does anything. While you type, the GPU sits idle. When you send, the model first has to *read* your whole message (prefill). Then a reasoning model, like Qwen3 in thinking mode, *thinks* for hundreds of tokens before the first word of its answer. On a mid-range GPU that thinking is the longest wait of all: ten seconds and more on a word problem, minutes on a model larger than the VRAM.
68
+
69
+ MAFDET uses the time you spend typing for both. It **reads** your message as you write it, so the prefill is done before Enter. And it **thinks ahead**: the model starts reasoning about your message while you are still typing it, and keeps that reasoning when you change the text. On Qwen3-4B, with 24 word problems typed in real time, the mean wait after Enter goes from **12.2 s to 3.2 s**, with the same 24/24 correct answers; on Qwen3-14B, from **108 s to 47 s**. On a MacBook Pro M2 Pro, from **18.1 s to 5.6 s** (4B, 24/24 both ways) and from **32.7 s to 12.1 s** (14B).
70
+
71
+ MAFDET is built for the hardware most people actually own. The reference machine is an **RTX 2060 with 6 GB of VRAM**; it also runs on **Apple Silicon Macs** (Metal, measured on an M2 Pro with 16 GB), and everything also runs on **CPU only**. **AMD Radeon** cards run through Vulkan, not measured yet: [help wanted](#help-wanted-benchmarks-on-an-amd-radeon).
72
+
73
+ > Named after Mafdet, the ancient Egyptian feline goddess known as "the runner", who struck snakes and scorpions before they could attack.
74
+
75
+ ## How it works
76
+
77
+ ### Reading ahead
78
+
79
+ An LLM processes text in two phases:
80
+
81
+ | Phase | What happens | Speed |
82
+ |---|---|---|
83
+ | **Prefill** | reads the prompt; all tokens are processed in parallel | fast |
84
+ | **Decode** | generates the answer, one token at a time | slow |
85
+
86
+ While reading, the model stores intermediate results for every token in the **KV cache**. Those results never change for a given prefix, so they can be computed ahead of time.
87
+
88
+ MAFDET keeps the KV cache in sync with the text **while you type**:
89
+
90
+ 1. On every pause, it tokenizes the current text.
91
+ 2. It holds back the last few tokens, because a word you are still typing can still change how the text is split into tokens.
92
+ 3. It finds the **longest common prefix** between the new tokens and the ones already in cache, trims the cache there, and prefills only what is new.
93
+ 4. When you hit enter, only a handful of tokens are left to process.
94
+
95
+ **Correctness does not depend on how you type.** Backspaces, edits in the middle of the text, pasted blocks, missing punctuation or spaces: the common-prefix check always brings the cache back to exactly what a from-scratch computation would produce. Heuristics such as hold-back and debounce only affect how much work is wasted, never the result.
96
+
97
+ ### Thinking ahead
98
+
99
+ Reading ahead takes the prefill out of the wait; the reasoning is still there. So the model also **reasons while you type**: in short chunks, on the message as it is at that moment. When you change the text, the reasoning is not thrown away. It stays in the prompt as notes after the new version of the message, which costs only a prefill, and the model goes on from there. On Enter it finishes reasoning from where it got to and answers. On Qwen3-4B about two thirds of the reasoning is done before Enter. How the notes are framed, and what that changed, is in [Thinking ahead, in detail](#thinking-ahead-in-detail) below.
100
+
101
+ Reading ahead is exact. Thinking ahead is not, because the model reasons on versions of the message that are not final yet; that is why it was measured on answers that can be checked.
102
+
103
+ ## Quick start
104
+
105
+ **On Windows, with a double-click.** Download MAFDET (on GitHub, *Code → Download ZIP*, and unzip it; or `git clone https://github.com/TheLastOxygen/mafdet.git`) and double-click **`start_mafdet.bat`**. The first time it creates a Python environment in `.venv` and installs MAFDET in it, which takes about a minute and needs [Python](https://www.python.org/downloads/) 3.10 or later. After that, a double-click opens MAFDET in under a second, and after an update it installs the new libraries by itself. The terminal shows what is being downloaded as it goes: each library, and later llama.cpp and the models you pick in the app, with size, a progress bar, speed and time left.
106
+
107
+ **On macOS, with a double-click.** The same, with **`start_mafdet.command`** (Python 3.10 or later: from python.org, or `brew install python@3.12`). If the Finder says it cannot verify the file, right-click it, *Open*, then *Open* again; this is needed only the first time.
108
+
109
+ **From a terminal:**
110
+
111
+ ```bash
112
+ git clone https://github.com/TheLastOxygen/mafdet.git
113
+ cd mafdet
114
+ python -m venv .venv # Windows: py -3.12 -m venv .venv
115
+ source .venv/bin/activate # Windows: .venv\Scripts\Activate.ps1
116
+ pip install -e .
117
+ mafdet
118
+ ```
119
+
120
+ Either way, no PyTorch and no manual downloads: MAFDET asks whether to open the **window** or the **terminal app**, and the first start guides you through the rest. It looks at your machine, installs the right build of llama.cpp by itself (CUDA for an NVIDIA card, Vulkan for an AMD Radeon, Metal on an Apple Silicon Mac, CPU otherwise) and downloads the model that runs best on your hardware.
121
+
122
+ <p align="center">
123
+ <img src="https://raw.githubusercontent.com/TheLastOxygen/mafdet/main/assets/screenshots/gui-chat.png" alt="The MAFDET window: the model reasoned ahead while the message was typed (455 of 571 reasoning tokens) and answered 1.6 s after Enter" width="49%">
124
+ <img src="https://raw.githubusercontent.com/TheLastOxygen/mafdet/main/assets/screenshots/gui-models.png" alt="The model catalog: for each model, where it runs on this machine, its speed and the wait after Enter with and without MAFDET" width="49%">
125
+ </p>
126
+
127
+ ## The app
128
+
129
+ The same app comes in two forms, on the same engine:
130
+
131
+ | | Command | What it is |
132
+ |---|---|---|
133
+ | <img src="https://raw.githubusercontent.com/TheLastOxygen/mafdet/main/assets/icons/watch.svg" width="22" alt=""> | `mafdet gui` | **The window**: chat, models, hardware and settings, in English, Italian, French or German |
134
+ | <img src="https://raw.githubusercontent.com/TheLastOxygen/mafdet/main/assets/icons/strike.svg" width="22" alt=""> | `mafdet tui` | **The terminal app**: the same views in the terminal, keyboard first (F1 to F4), on an amber phosphor screen with a boot sequence (Settings, *Cinematic effects*, turns the animations off) |
135
+ | <img src="https://raw.githubusercontent.com/TheLastOxygen/mafdet/main/assets/icons/race.svg" width="22" alt=""> | `mafdet models` | the model catalog for this machine (`--family`, `--download`) |
136
+ | <img src="https://raw.githubusercontent.com/TheLastOxygen/mafdet/main/assets/icons/awaken.svg" width="22" alt=""> | `mafdet doctor` | checks the GPU, memory, llama.cpp and the models; `--install` installs llama.cpp (`--build 12`, `13`, `vulkan` or `cpu` to pick the build) |
137
+
138
+ `mafdet` alone opens the launcher, which can remember your choice (`mafdet --ask` shows it again).
139
+
140
+ **Chat.** While you type, a status line under the message shows what the model is doing with it: how much it has read, and how many reasoning tokens it has written ahead (the field glows amber while it thinks). On Enter only the tail is left to compute. The reasoning is shown folded above the answer, and every answer ends with its numbers: first word after Enter, tokens read while you typed, reasoning done before Enter, speed.
141
+
142
+ **Models.** Five families: **Qwen3**, **Llama 3**, **Gemma 3**, **Mistral** and **Phi-4**, from 0.6B to 32B parameters, each in several quantizations. With every model, MAFDET reads your message while you type and, at a pause, writes the answer ahead; Qwen3 also **reasons ahead**, the one family whose reasoning frame was measured. Every model of the catalog comes with what it does on *your* machine, before you download it: whether it fits in VRAM or runs partly on the CPU, how fast it writes and reads, and for Qwen3 how long the answer takes after Enter with and without MAFDET (for the other families, how long a typical answer takes to write). The estimate comes from your hardware (GPU and RAM bandwidth, VRAM, llama.cpp's split of layers between GPU and CPU) and is within 12% of the measured speeds on the reference PC (Qwen3-4B 89.6 estimated / 87.1 measured tok/s, 8B 16.2 / 16.2, 14B 5.1 / 4.9) and on an M2 Pro (Qwen3-4B 53 / 57 tok/s). Once a model is downloaded, **Measure** benchmarks it in half a minute and the real numbers replace the estimate. The model that runs best here is marked *Best for you*, and each family has its own best pick. To add a model, add a line to `tools/build_catalog.py`: it reads the file sizes and the shape of the model from Hugging Face.
143
+
144
+ **Hardware and settings.** The Hardware view shows the GPU, CPU, memory and the llama.cpp runtime, with a button to install or reinstall it. Settings keep the chat options from one start to the next (in `~/.mafdet`, or `$MAFDET_HOME`).
145
+
146
+ <p align="center">
147
+ <img src="https://raw.githubusercontent.com/TheLastOxygen/mafdet/main/assets/screenshots/tui-models.png" alt="The terminal app: the model catalog as a table" width="49%">
148
+ <img src="https://raw.githubusercontent.com/TheLastOxygen/mafdet/main/assets/screenshots/launcher.png" alt="The launcher: window or terminal" width="49%">
149
+ </p>
150
+
151
+ ## Requirements
152
+
153
+ - **Windows**, with an **NVIDIA GPU** and up-to-date drivers (tested target: RTX 2060, 6 GB), an **AMD Radeon** through Vulkan (in place, not measured yet: [help wanted](#help-wanted-benchmarks-on-an-amd-radeon)), or just a CPU. **Linux** has its llama.cpp builds and code paths in place, but has not been tested yet
154
+ - **macOS** on Apple Silicon (M1 or later): the models run on the GPU through Metal, in the unified memory (tested: M2 Pro, 16 GB, macOS 26.2; Qwen3-4B reads 593 tokens/s and writes 57). Intel Macs run on the CPU
155
+ - **Python 3.10 or later** (tested with 3.12)
156
+ - Disk space: about 0.7 GB for llama.cpp with CUDA (100 MB with Vulkan, 60 MB for the CPU), plus the models, from 0.6 GB (Qwen3-0.6B) to 2.3 GB for the 4B recommended on 6-8 GB cards
157
+ - **16 GB of RAM** recommended for CPU-only runs and for models larger than the VRAM
158
+
159
+ The app needs no PyTorch: llama.cpp runs the models, and transformers only provides the tokenizers. PyTorch is needed only for the measurements on the PyTorch backend (below): install it first from the CUDA index, then `pip install -e ".[research]"`.
160
+
161
+ ## Thinking ahead, in detail
162
+
163
+ In the app this is on by default for Qwen3 (Settings, *Reason while I type*); from the command line it is `mafdet strike`, with the options below. The model **starts thinking about your message while you are still typing it**. It runs Qwen3 in thinking mode, so before answering the model reasons in a hidden block (shown folded above the answer). That reasoning is usually the longest wait, and `strike` moves as much of it as possible to before Enter:
164
+
165
+ 1. **While you type**, the model reasons in short chunks of 32 tokens, on the message as it is at that moment, on whole words (after a space or punctuation, or at a pause).
166
+ 2. **When the text changes**, the reasoning is not thrown away. It stays in the prompt as notes, after the new version of the message. Moving it there only costs a prefill: the fast, parallel phase, about 60 times faster than writing the same tokens again for the 14B on the RTX 2060. A new line of the notes names the words just typed, so the model goes on gathering material on them instead of starting over.
167
+ 3. **On Enter**, a last sentence tells the model that the message is now complete. It finishes reasoning from where it got to and answers. Rarely (Qwen3-4B: once in the 24 problems on the Mac, once before on the RTX 2060) the model writes its answer among its thoughts and ends its turn without leaving the reasoning: the app then closes the reasoning as Qwen3's template does, and the model writes the answer, a few seconds later instead of an empty one.
168
+
169
+ The notes are a list of **material for the answer**, started by a frame: *"The user is still typing. I will not wonder what they will ask, nor remark that the text is unfinished. While I wait, I collect material for the answer: for each key term, name or number already written, one line with what it is and the facts I know about it, or a partial result."* followed by one example line from a different message. Each time you type more, a new line names the new words: `- New words "finestra di contesto": `. So from *"Quando finisce la finestra di contesto degli LLM?"* the notes already hold what a context window is and what LLM stands for, and from a word problem the partial results (`3 × 12 = 36`) before the question has been typed.
170
+
171
+ The frame matters. Without one, the model spent its notes remarking that the message was unfinished, and after every edit it copied its last paragraph again. On six messages typed in real time, the share of sentences in the notes about the user or the message itself (instead of its content) went from 86% with a generic frame (*"work out what you can"*) to 41-54% with this list, and to 17-26% with the example line and a logit bias that, while reasoning ahead and only then, makes words such as *user*, *incomplete*, *typing* less likely (their token ids come from the tokenizer of the model loaded, so it works with any model). Thinking mode also uses the presence penalty suggested by Qwen3's authors, which keeps the 4B out of loops that repeat a sentence until the token limit.
172
+
173
+ **If you pause and send the message unchanged**, `strike` goes further and also writes the answer itself. That part is exact: the answer only holds for the exact text it was written for, and any change drops it. With `--no-think` (no reasoning) this is all `strike` does, and with greedy decoding the answer is identical token by token to the one started after Enter (checked).
174
+
175
+ Reasoning ahead is **not exact**: the model reasons on intermediate versions of the message, so the answer can differ from the one it would give starting from scratch. That is why it was measured on answers that can be checked (below).
176
+
177
+ | Option | What it does |
178
+ |---|---|
179
+ | `--no-think` | no reasoning: answer right away, and write ahead only the exact answer |
180
+ | `--think-ahead N` | longest reasoning kept across edits (default 1024 tokens) |
181
+ | `--ahead N` | answer tokens written ahead when the text does not change (default 512) |
182
+ | `--branches N` | experimental: the model also guesses how you will finish the message and, on a slot of its own, reasons on the guess; if it guessed the exact message, that reasoning (and the answer, if it got that far) is ready on Enter. 1 is the measured setting, see below |
183
+ | `--recycle` | reuse the answers written for earlier versions of the message as n-gram drafts for speculative decoding (+4% decode speed measured with natural typing, +20% on code) |
184
+ | `--draft repo:file` | a small model of the same family drafts tokens for speculative decoding (no gain measured on the RTX 2060, see below) |
185
+
186
+ `mafdet watch` and `mafdet strike` open the window with the model and options given on the command line (`--gguf repo:file`), instead of the app's settings. `demo_live.py` (`start_demo.bat`) is the step-by-step view for debugging: tokens, cache, hold-back and timings, live in the terminal (`--auto` types an example by itself).
187
+
188
+ ## Measure and verify
189
+
190
+ | | Command | | What it does |
191
+ |---|---|---|---|
192
+ | <img src="https://raw.githubusercontent.com/TheLastOxygen/mafdet/main/assets/icons/hunt.svg" width="22" alt=""> | `mafdet hunt` | the hunt | simulates people typing and measures the wait after sending |
193
+ | <img src="https://raw.githubusercontent.com/TheLastOxygen/mafdet/main/assets/icons/race.svg" width="22" alt=""> | `mafdet race` | the race | benchmarks prefill and decode on your machine |
194
+ | <img src="https://raw.githubusercontent.com/TheLastOxygen/mafdet/main/assets/icons/judge.svg" width="22" alt=""> | `mafdet judge` | the judgement | checks results against a from-scratch computation: must end with 0 errors |
195
+ | <img src="https://raw.githubusercontent.com/TheLastOxygen/mafdet/main/assets/icons/awaken.svg" width="22" alt=""> | `mafdet awaken` | the awakening | checks PyTorch and the GPU, for the PyTorch backend |
196
+
197
+ They run on llama.cpp with `--backend llama` (no PyTorch needed), or on PyTorch/transformers with the default `--backend hf` (`pip install -e ".[research]"` after installing PyTorch from the CUDA index: from PyPI, on Windows, pip would get the CPU-only build). `mafdet --help` is the full guide, `mafdet <command> --help` the options of one. Add `--device cpu` to any command to measure the no-GPU case. Results are saved as CSV files in `results/` (change it with `--out`).
198
+
199
+ ### Typing scenarios
200
+
201
+ `mafdet hunt` replays three scenarios (pick them with `--scenario`):
202
+
203
+ - **clean**: a message typed from start to finish
204
+ - **messy**: typos fixed with backspace, a word deleted and retyped, an insertion in the middle, little punctuation
205
+ - **paste**: a long document pasted in, followed by a typed question. This is where the gain is largest.
206
+
207
+ The typing is not replayed in real time. Each prefill really runs on the model, and its measured duration is placed on the typing timeline. If the model falls behind the typist, the delay piles up and is added to the final wait, just as in a real system.
208
+
209
+ ## Results
210
+
211
+ On an RTX 2060 (6 GB) unless stated (the Mac has [its own table](#on-a-mac)), llama.cpp, Q4_K_M models, real-time typing (5 to 8 characters per second, a few natural pauses, Enter right after the last character, no rereading).
212
+
213
+ **Reasoning ahead, Qwen3-4B** (fits in VRAM, 83 tok/s): 24 word problems with a known numeric answer, typed in Italian (script and data: `research/thinking_ahead.py`).
214
+
215
+ | | Without reasoning ahead | `mafdet strike` |
216
+ |---|---|---|
217
+ | Correct answers | 24/24 | 24/24 |
218
+ | Median wait for the first word of the answer | 10.7 s | **2.9 s** |
219
+ | Mean wait | 12.2 s | **3.2 s** |
220
+ | Faster | | in 24 of 24 problems |
221
+ | Reasoning in total | 944 tokens | **662 tokens** |
222
+ | Reasoning left after Enter | 944 tokens | **244 tokens** |
223
+
224
+ Same accuracy, less reasoning in total (the material gathered while typing saves the model from starting over), and almost two thirds of it done before Enter. The two earlier frames, measured the same way: a generic frame gave 22/24 and a median of 4.4 s; no frame gave 22/24, 6.9 s and 70% more reasoning.
225
+
226
+ **Exact answer ahead, Qwen3-4B, no reasoning** (pause before Enter, text unchanged):
227
+
228
+ | Answer | Written before Enter | Full answer on screen after Enter, strike | Without strike |
229
+ |---|---|---|---|
230
+ | 300 tokens | 200 | 1.2 s | 3.5 s |
231
+ | 168 tokens | 168 (all of it) | instant | 1.9 s |
232
+
233
+ **Larger models.** What the model can do before Enter is bounded by typing time × its writing speed:
234
+
235
+ | Model | Fits in 6 GB? | Writes | Reasoning written while typing a 30 s message |
236
+ |---|---|---|---|
237
+ | Qwen3-4B | yes | 83 tok/s | most of it |
238
+ | Qwen3-8B | no, partly on the CPU | 13 to 16 tok/s | 130 to 280 tokens |
239
+ | Qwen3-14B | no, partly on the CPU | 5 tok/s | about 160 tokens |
240
+
241
+ Even so, on the 14B (6 word problems typed in real time, 6/6 correct both ways) reasoning ahead halves the mean wait after Enter: **108 s → 47 s**, with 164 reasoning tokens written before Enter on average. Single runs vary a lot (the same problem took 106 s once and 154 s another time), so 6 problems give the order of magnitude, not a precise figure. Reading ahead gains more the larger the model: the 14B reads a 3,000-token pasted document in about 10 s, all of it hidden while you type.
242
+
243
+ ### On a Mac
244
+
245
+ MacBook Pro M2 Pro, 16 GB, macOS 26.2, llama.cpp with Metal: the same scripts and problems as above.
246
+
247
+ | M2 Pro | Without reasoning ahead | `mafdet strike` |
248
+ |---|---|---|
249
+ | **Qwen3-4B**, 24 problems: correct answers | 24/24 | 24/24 |
250
+ | Median wait for the first word of the answer | 16.7 s | **4.1 s** |
251
+ | Mean wait | 18.1 s | **5.6 s** |
252
+ | Faster | | in 24 of 24 problems |
253
+ | Reasoning in total / left after Enter | 966 / 966 tokens | **773 / 248 tokens** |
254
+ | **Qwen3-14B**, 6 problems: correct answers | 6/6 | 6/6 |
255
+ | Median wait | 26.5 s | **11.7 s** |
256
+ | Mean wait | 32.7 s | **12.1 s** |
257
+
258
+ The 4B writes at 54 tok/s on the M2 Pro (83-87 on the RTX 2060), so both waits are longer than on the PC, and reasoning ahead takes about the same share of them away. The 14B is where the Mac differs: Metal may use 12 GB of the 16 GB of unified memory, so the whole model is on the GPU and writes at 18 tok/s (4.5-5 on the RTX 2060, with 62% of it on the CPU). The wait after Enter is 12 s instead of 47 s. The column without reasoning ahead comes from an earlier run of the same day; in that run one answer came out empty (the model ended its turn inside its reasoning, see [Thinking ahead, in detail](#thinking-ahead-in-detail)), which the app now handles, and the column with reasoning ahead is the run after the fix. During the runs the Mac reached thermal pressure *Heavy* for a few minutes (54 → 51 tok/s). Data: `research/data/thinking_ahead_4b_m2pro.json`, `thinking_ahead_4b_m2pro_fixed.json`, `thinking_ahead_14b_m2pro.json`.
259
+
260
+ **A small model gathering for a large one (`--gatherer`, experimental).** For models larger than the VRAM we tried having a small, fast model (Qwen3-0.6B, also fine-tuned for it with `training/`) write material while you type, for the 14B to read on Enter. On the RTX 2060 it does not beat the 14B reasoning ahead by itself:
261
+
262
+ | 14B, mean wait after Enter | |
263
+ |---|---|
264
+ | No reasoning ahead | 108 s |
265
+ | **Reasoning ahead by itself** | **47 s** |
266
+ | Gatherer, untrained Qwen3-0.6B | 60 s |
267
+ | Gatherer, fine-tuned Qwen3-0.6B | 79-86 s |
268
+ | Ideal material, written by hand (every partial result right), presented as "from a fast assistant" | 62 s |
269
+ | The same ideal material, presented as the model's own reasoning | 49 s |
270
+
271
+ Even perfect material only matches reasoning ahead: the 14B reads it, then redoes and double-checks the calculations, except on the easiest problems (17-24 s instead of 37-63 s). How the material is presented matters more than its quality (62 s → 49 s). Open questions for anyone who wants to take this further: combining both (the large model reasons ahead *and* reads the material as its own), teaching the large model to trust partial results, or a gatherer where the large model cannot reason ahead at all (CPU only).
272
+
273
+ **Guessing the ending (`--branches`, experimental).** The reasoning left after Enter is mostly about the end of the message, which arrives last: in a word problem, the question. Qwen3-4B often guesses it before you type it: in one run, with the text at *"…e una penna da 2"*, one of its guesses was already the exact rest of the message, *"euro. Quanti euro gli restano?"*. So with `--branches 1` the model also guesses how you will finish the message (only when few words are left, and only when two guesses in a row agree), and on a llama-server slot of its own reasons on the guessed message as if you had sent it, while its main reasoning waits. If you then send exactly that message, its reasoning and answer were written for that very prompt and are taken as they are. Same 24 problems, two runs each (48 messages; script and data in `research/`):
274
+
275
+ | | Reasoning ahead | `--branches 1` |
276
+ |---|---|---|
277
+ | Correct answers | 48/48 | 48/48 |
278
+ | Mean wait for the first word of the answer | 4.17 s | **3.51 s** |
279
+ | Median wait | 2.98 s | 2.85 s |
280
+ | Slowest tenth | 7.9 s | **5.3 s** |
281
+ | Messages guessed exactly | | 14 of 48 |
282
+
283
+ The reasoning-ahead column was measured again for this comparison, the same day and on the same code: 4.17 s against the 3.2 s of the table above, two runs of the same 24 problems differ that much. A modest gain, mostly on the slowest answers, and on 24 problems not yet a significant one (faster on 16 of 24, sign test p = 0.15). What did not work: adopting a guess that was only close (*"ha rimasto"* for *"gli restano"*), with a line asking the model to check its reasoning against the real message, gave 2 wrong answers out of 4: the guess had another number (32 for 41), or a word that changed the problem (*"current age"*). Two branches at once are slower than none (median 4.50 s against 2.94 s on half the problems): on the RTX 2060 two sequences write 1.7 times as many tokens as one, four 2.2 times, so each branch slows the others down.
284
+
285
+ **Larger than the VRAM.** On Qwen3-14B (partly on the CPU, 4.5 tok/s through llama-server) a second sequence is not free either: two run at 77% of the speed of one each, three at 55%. And each guess takes seconds: 1 or 2 per message instead of 10 to 20 on the 4B, so on 4 problems no branch ever started reasoning before Enter (mean wait 44.7 s with the option, 43.9 s without: noise, single problems vary from 24 s to 73 s). The arithmetic does not leave much room anyway: between the moment the question can be guessed and Enter there are a few seconds, about 20 tokens of the 14B, against about 200 left after Enter. So in the app *Guess the ending* gives a branch only to models that fit in VRAM, and none to the others.
286
+
287
+ **Tried, and why they are not on by default:**
288
+
289
+ - `--recycle` (answers to earlier versions of the message as n-gram drafts): +4% decode speed with natural typing, +20% on code, slightly later first token.
290
+ - `--draft` (Qwen3-0.6B drafting for the 14B): on the GPU it takes VRAM from the 14B, which then runs more of its layers on the CPU (4.8 → 3.5 tok/s); on the CPU it gains 8% with 4-token drafts and halves the reading speed.
291
+ - The reasoning ahead as the draft for speculative decoding after Enter (`--spec-type ngram-simple`: the notes are in the prompt, and after Enter the model works the same steps out again). Replayed offline, prompt lookup would write 1.5 to 1.7 tokens per decoding step on Qwen3-4B, against 1.3 to 1.5 without notes. For real it is no faster on the 4B (73 tok/s either way) and slower on the 14B (5.0 → 3.1 tok/s): checking a 9-token draft costs the 14B 2.4 decoding steps, because its layers on the CPU compute every token of the draft, and only 11% of the drafted tokens were right. Script and data: `research/notes_as_draft.py`.
292
+
293
+ ## Help wanted: benchmarks on an AMD Radeon
294
+
295
+ MAFDET runs on AMD Radeon cards through llama.cpp's Vulkan build, but nobody has measured it on one yet: the machines here are an RTX 2060 and an M2 Pro. The Vulkan path itself is checked, on the RTX 2060 (Qwen3-4B reads 2,103 tokens/s and writes 83, about as with CUDA; 3/3 word problems correct, reasoning ahead working). What is missing is a Radeon. If you have one (a dedicated card, RX 5000 or later; 8 GB or more is ideal), about half an hour of it would fill this page:
296
+
297
+ 1. Install MAFDET ([Quick start](#quick-start)) and open it once: it should find your card, install llama.cpp *Windows · Vulkan* (or *Linux · Vulkan*) and download Qwen3-4B. `mafdet doctor` shows what it found.
298
+ 2. In the app, *Models*, **Measure** Qwen3-4B.
299
+ 3. From the MAFDET folder, with its environment active: `python research/thinking_ahead.py radeon_4b.json`. It types 24 word problems in real time, with and without reasoning ahead, and takes about 20 minutes; leave the machine otherwise idle.
300
+ 4. [Open an issue](https://github.com/TheLastOxygen/mafdet/issues/new) with the output of `mafdet doctor`, the numbers of *Measure* and `radeon_4b.json`.
301
+
302
+ If something does not work (the card not found, llama.cpp not starting, the model running on the CPU), an issue with the output of `mafdet doctor` and the `server*.log` files next to llama-server (in `~/.mafdet/llama.cpp`) is just as useful. Integrated Radeons (Ryzen APUs) are not used yet: they keep the CPU build. Any card with a Vulkan driver can try it with `mafdet doctor --install --build vulkan`.
303
+
304
+ ## Roadmap
305
+
306
+ - [x] Incremental prefill engine with common-prefix sync and token hold-back
307
+ - [x] Benchmarks, typing simulation and correctness checks
308
+ - [x] Unified `mafdet` CLI
309
+ - [x] `mafdet watch`: the chat window
310
+ - [x] llama.cpp backend with quantized (GGUF) models
311
+ - [x] `mafdet strike`: reasoning ahead while you type, kept across edits; the exact answer ahead at a pause
312
+ - [x] The app: window and terminal, model catalog with estimates for your hardware, automatic llama.cpp setup, guided first start, four languages
313
+ - [x] Five model families: Qwen3, Llama 3, Gemma 3, Mistral, Phi-4
314
+ - [x] A small model gathers while you type, a large one answers: tried and measured (no gain on the RTX 2060, see Results)
315
+ - [ ] Reasoning ahead for models larger than the VRAM that beats the large model thinking by itself
316
+ - [ ] Reasoning ahead beyond Qwen3, including the thinking models with their own formats (DeepSeek-R1, gpt-oss): each needs its frame measured
317
+ - [x] macOS on Apple Silicon (Metal)
318
+ - [x] AMD Radeon through Vulkan (in place; measured on a Radeon: help wanted, above)
319
+ - [ ] Linux tested
320
+
321
+ ## Related research
322
+
323
+ - [LiveMind: Low-latency Large Language Models with Simultaneous Inference](https://arxiv.org/abs/2406.14319)
324
+ - [StreamingThinker: Large Language Models Can Think While Reading](https://arxiv.org/abs/2510.17238)
325
+ - [SHANKS: Simultaneous Hearing and Thinking for Spoken Language Models](https://arxiv.org/abs/2510.06917)
326
+ - [Asynchronous Reasoning: Training-Free Interactive Thinking LLMs](https://arxiv.org/abs/2512.10931)
327
+
328
+ ## License
329
+
330
+ [Apache-2.0](https://github.com/TheLastOxygen/mafdet/blob/main/LICENSE)