Repository navigation
Releases
flashCat 1.5.4:新增 flashcat 命令行与本地控制接口,概览指标改为按请求实测
flashCat 1.5.4
这一版把 CLI 与本地控制接口补上:flashcat 能列出/启停引擎、切模型、流式对话、
读日志与网关状态,应用没在跑时也能做离线操作。概览的取数口径同步重做:预填充
与解码优先读引擎按请求自报的 timings,量不出来就画「—」;第四格从内存压力
换成按 token 加权的缓存命中率。
前缀缓存改为落盘,重启应用不用从零预填充;切走对话不再中断生成,回到列表能点
回正在跑的那一段;应用内不再注册任何快捷键,键盘效率交给终端。
新增
命令行与本机控制接口
flashcat命令行。 随.app分发在Contents/Helpers/flashcat,.pkg
安装时链接到/usr/local/bin。支持status、engines(list/start/stop/
restart/use/install/uninstall/port/logs)、models(list/use/download/delete/
path)、chat(stdin、流式、思考过程、JSON)、gateway、logs(级别过滤与
--follow)、config、app、doctor、completion、cli。- 应用侧本机控制接口。 默认
127.0.0.1:9100,端口被占用时自动顺延;每次
启动生成随机令牌,control.json以0600保存。设置页新增「命令行接口」开关
与端口。接口与推理网关分离,网关关闭时仍可驱动应用。 - 共享路径与协议。
FlashCatPaths、EngineInstallations与
FlashCatKit/Control/ControlProtocol.swift收进 Kit,应用和 CLI 使用同一套
支持目录、模型目录、引擎发现规则与控制文档。 - 命令行脚本契约。 结果型命令都支持
--json;结果走 stdout、进度走 stderr;
固定退出码(应用未运行3、找不到4、超时5、冲突6、令牌7);
zsh / bash / fish 补全;--timeout、--quiet、--no-color。 - 离线能力。 应用未运行时仍可
status、列出引擎与磁盘模型、安装/卸载引擎、
读日志与读取/修改纯配置;需要应用的动作明确报错,不伪造成功。
前缀缓存落盘
- 重启后不再从零预填充。 引擎的 hot prefix cache 只在内存里,App 一重启就
清零,上一次会话的整段历史只能重算——同一段 1.5 万 token 的会话,带缓存
恢复是 0.1 秒,重启后无缓存是 13.8 秒,十万 token 级能到 3 分钟。四家引擎
本来都有这条 SSD 层,只是没人打开:Splash 的--persistent-cache、oMLX 的
--paged-ssd-cache-dir(不传这个目录它的前缀缓存等于全关)、MLX-Serve 的
--prefix-cache-disk默认都是关的,MTPLX 默认开着但恢复被自己的
boundary 预算挡掉。现在引擎配置页有「前缀缓存」卡片:开关 + 磁盘预算
(默认 20 GB),关闭后显式下发各家的 off 参数而不是留空。 - 统一缓存根。 各家的落盘快照都收到
Application Support/flashCat/prefix-cache/<engine>/下,容量、清理和备份
只需要管一个目录。MLX-Serve 的路径写死在$HOME/.mlx-serve/kv-cache、没有
对应开关,用符号链接指进来。 - 模型搬家不再作废缓存。 缓存条目按模型的绝对路径做键,所以
ModelStorageMigration把权重从~/.mtplx/models搬进应用目录时,该模型
已有的快照全部失配——实测 23 个条目、约 29 GB 从此再也命中不了,
同时同一个模型在新路径下有 0 命中。迁移现在改写 manifest 里的model_path
而不是放任它变孤儿,并把~/.mtplx/session-bank一并搬到新根下。 - 测试:
PrefixCacheTuningTests钉住每家的参数拼写(Splash 只认20G,
其余认20GB,写错直接被拒绝)与「0 是关闭、不是回退默认」。
变更
- 标题栏去掉「命令」按钮。 胶囊形入口不再占用标题栏宽度;命令面板仍可从
「页面 → 命令面板」菜单打开,行为与之前一致。 - 每个指标格只有一个 owner。 取数口径收进
AppState的 owner 表
(decodeReading/averageDecodeReading/prefillReading,输出
MetricReading/MetricOrigin),曲线、「最近请求」、灵动岛、菜单栏从
同一组函数取数,数值与角标同源。分工按物理边界:当前速度 owner = 网关
(引擎只给聚合口径,五家还各不相同);预填充、TTFT 分布、显存、草稿接受
率、队列、上下文占用、生命周期阶段 owner = 引擎(网关量不到)。引擎
.live只在网关没有会话在跑(客户端直连引擎端口)时兜底;网关读数超过
两拍未刷新同样降级——「过去的现在」不配冒充当前速度。 - 概览第四格从「内存压力」改为「缓存命中率」。 命中量 / 提示词总量由网关
按请求打点累加,按 token 加权而不是逐请求平均(一段 100K 上下文命中 95%
比十次 1K 冷请求更能代表缓存效率);只统计真的收到 usage 的请求,窗口是
会话表最近 ≤32 条,换引擎 / 换模型 / 引擎重启后从「—」重新等样本。客户端
绕过网关直连引擎端口时,退回引擎自报的开机以来比值(mlx-serve / MTPLX 的
cached / prompt计数器,oMLX 的total_cached_tokens / total_prompt_tokens)。
角标只有AVG;0% 是合法读数(有样本、一次都没命中),「没样本」才画「—」。
内存占用仍在菜单栏的读数里。 - hero 只显示模型启动以来平均。 大数字改读网关按会话累计的解码均速:
分子是生成 token,分母是首 token 到末 token 的解码时长(不含 TTFT、排队、
空闲),换引擎 / 换模型 / 引擎重启时清零。曲线继续画实时值,两者回答的
不再混为一谈;没有累计样本时画「—」。 - 取消 LAST 采集入口。 解码与预填充的当前速度只认 LIVE;预填充保留
引擎真的累计过的 AVG(文案写明「开机以来均值」),空闲时画「—」,不再把
上一请求的实测值挂成当前读数。角标只剩「网关」/「引擎实时」与AVG。 - 应用内对话的直播条继续走低通。
DecodeRateMeter(τ=2.5s)服务逐分
片回调的对话页——那边要的是「最后一个脉冲的强度」;概览只在 1 秒节拍上
读网关,分片不再顺带刷新概览。 - 模型广场不再展示推荐引擎标签。 结果卡与详情页去掉那枚强调色的引擎名
(含「无推荐」);量化、已在本机、内存下限、许可与 Hub 标签照旧保留,权重
归属仍由下载条里的「默认授权给 …」交代。 - 对话输入框回车发送、⌘回车换行。 SwiftUI 的
TextField(axis: .vertical)
只会回车换行、没有换行组合键可留,输入框换成NSTextView包装
(UI/ChatComposerField.swift):回车发送、⌘回车换行,输入法组字期间不误发;
仍按内容长高、封顶 6 行后滚动,聚焦上抬一截的动效与点击聚焦不变。这是应用里
唯一的按键判定——属于文本编辑而不是全局快捷键;testReturnKeyIsOnlyHandledByComposer
把keyDown覆盖钉在这一个文件里,UI-SPEC「键盘策略」与发送按钮提示同步写明。 - 应用内取消所有快捷键。 菜单不再带按键等价物;命令面板只响应鼠标点击,
不再接管方向键、回车或 esc;对话输入框回车换行、发送改为点击按钮;搜索框
不再回车提交;设置页端口改为点击「应用」;弹窗去掉.defaultAction。
设置页与 README 的快捷键说明同步删除。 - 设置页新增「命令行接口」卡片。 显示开关、控制端口与
flashcat --help
的复制入口;「恢复默认」会把控制接口恢复为开启、端口 9100。 - 发版产物。
scripts/build-native-app.sh同时编译并嵌入flashcat;
make-installer.sh的.pkgpostinstall 创建/usr/local/bin/flashcat;
install-app.sh在/usr/local/bin可写时同样链接;make uninstall会清掉
指向已安装应用的链接。
修复
- 切走对话会把正在生成的回答弄丢。 以前切去概览、新建对话或从列表点开
另一段,都会直接cancelGeneration(),而它只写conversation.json——
「最近对话」里留着的还是上一轮快照,正在流的那条回答既没了、生成也停了。
现在切走时把整段对话连同它自己的threadID搬到后台继续跑,跑完按自己的
id 落回历史并提示「已在后台生成完成」;开始生成时先把问题写进最近对话,
列表里立刻有一行可点,点回来就是把后台那份接回前台接着写。侧栏给正在生成
的那一行标「生成中」;删除或清空对话会先停掉后台那一轮,别让它跑完再写回来。 - 切页回来对话区是空的。
ChatPage重建时ScrollView报 0 高度,
scrollTo按 0 视口算偏移,等高度补齐就落到内容之外。现在先挂一笔「欠一次
落底」,由onScrollGeometryChange量到真实高度再补;超大回答首次布局只量到
一部分高度,150 ms 后再补一次,读者已经往上翻时不抢回位置。 - 设置页改「默认模型」不再换掉正在跑的引擎。 这一栏的菜单按引擎分组,
选别的引擎的模型以前会直接走一次引擎切换:停掉当前引擎、等待进程退出、
再加载新权重。现在它只是启动偏好:选择记到那台引擎的配置里,当前引擎
继续服务,行内标注「下次启动」;只有显式切换引擎(或下次启动)才会让默认
跟着动。引擎存储里的default与active因此分开,后台的安装/卸载重建
也不会再把activeID挪到默认引擎上。 - 下载中心的删除按钮发糊。 危险色原来交给玻璃
tint
(Native.red.opacity(0.55)):tint 是层半透明色雾,红色图标压在同一片红雾
上,截图取样底色rgb(185,102,93)、图标rgb(244,107,94),对比度只有约
1.4∶1——看上去像失焦。现在危险态不再染玻璃,改成中性玻璃 + 自绘的 12% 红底
与 0.8 pt 发丝边,图标用满饱和的Console.danger;边缘由我们画,不经过玻璃
模糊,深浅色下都清晰。 - 「最近请求」报出 37 769 tok/s 这种数。 非流式响应(agent 客户端、
stream: false的调用)整段正文一口气回来,网关手里只有一个到达点;
「全程平均」却拿到达窗口的下限 0.35 秒当分母,14 155 token 的回答于是被摊成
40 443 tok/s,同一批数字还混进了 hero 的「模型启动以来平均」。现在按请求先读
引擎在响应里自报的timings(prompt_n/cached_n/prompt_ms与
predicted_n/predicted_ms,mlx-serve 在流式末片和非流式正文里都带),
分子分母都只取引擎真正前向/生成的那一段;没有timings的引擎只要没观测到
真实的到达跨度就画「—」,不再拿窗口下限编一个。单点会话同样不再进累计均值。 - 预填充速度始终为空(换到 mlx-serve 后又出现)。 根因是这格只认引擎自报的
预填充字段:MTPLX 在in_flight[].prefill_state/latest.prefill_tok_s里给,
但几百 token 的预填充只要 0.2~0.4 秒,1 Hz 轮询几乎抓不到 LIVE;mlx-serve
干脆不报预填充速率,于是卡片又整格变空。现在同样以逐请求的实测值为准:
引擎给了timings就用(prompt_n − cached_n) / prompt_ms(非流式也有),
没给才退回网关自己的口径——分子是 usage 里的提示词 token 减去
cached_tokens,分母是请求发出到首 token 的墙钟,且只对流式响应成立。
前向不足 128 token 的样本一概不报:命中缓存后剩几十个 token 时,耗时由缓存
恢复的固定开销主导(实测 2195 个 token 里缓存 2164,31 个前向摊 92ms → 334
tok/s),那个数字既不是算力也不是缓存速度。预填充进行中引擎的.live仍然
优先,其余时间标LAST(「网关 · 最近一次预填充实测」),引擎的 LAST/AVG
只在客户端绕过网关直连引擎端口时兜底。AI 服务自己也会报进程级均值,
prometheusJSON现在把generation_tokens_total / decode_time_seconds.sum
与prefill_tokens_total / prefill_time_seconds.sum读成.lifetimeMean,
网关一个样本都没有时 hero 与预填充格也能说出「开机以来多快」。 - Claude 的流式请求只回空正文。 Anthropic 方言翻译出来的上游请求体没有带
stream: true(只有调用方拿到的stream标志),引擎于是按非流式回一整块
JSON,而转发层是按data:行解析 SSE 的——一行都认不出来。Claude Code 这类
客户端只会收到message_start/ping/message_stop,正文全空,概览里
这一路连一个 token 都没有。现在翻译层把stream写进上游请求体,流式时再带
stream_options.include_usage,末片的 usage 才拿得到 completion_tokens 与
缓存命中量。 - 组字中的输入被自动清掉。 输入框原来拿
textView.string直接跟草稿
Binding 比:输入法组字的 marked text 已经在文本视图里、却还没进 Binding,
任何一次视图刷新(每秒指标、焦点变化)一比就把没确认的拼音回写成空串。现在
只在「视图没有未回报的编辑」且「草稿确实被外部改写」时才回写,组字期间一律
不碰,等提交后由textDidChange对齐;也不再由草稿状态反向抢第一响应者——
组字中途被夺焦同样会丢候选。同一份源码跑了对照组:旧逻辑属性一更新就是
marked=false 视图="",新逻辑保持marked=true 视图="zhong"直到提交。 - 背景的透明度与模糊「拖一个条,另一个条的改动才生效」。 窗口表面
(isOpaque/ 底色)和毛玻璃层的强度都只在DesktopBackdrop.updateNSView
里更新,而这个 representable 的入参只有blur:只拖 APP 透明度时它一次
都不会被回调,窗口仍是不透明的,桌面根本不露出来;等到下次拖模糊,才连带
把上一步的透明度一起落下去。现在改由BackgroundSettings的didSet直接
驱动BackgroundSurface,参数一变窗口和毛玻璃层立刻跟上,不再依赖任何视图
的更新时机;透明度为 0、又没有背景图时把模糊滑杆禁用并说明原因,不再留一根
按了没反应的滑杆。 - 图片模式的透明度后半程没有变化。 保底渐变原来写死
max(1 - opacity, floor),深色下超过 58% 之后整段都停在 0.42,滑杆最后
近一半行程是空的;现在把剩余行程线性铺到保底值上,两端数值不变
(BackgroundMath.veilOpacity)。 - 概览解码速度闪烁。 根因不在引擎上报,在我们自己的打点:每个 SSE
分片喂一个脉冲进连续时间低通,逐次读取。低通的输出随取样时刻连续
衰减(τ=2.5s 下 0.5s 静默就掉 18%),秒拍与预填充期的 0.4s 快拍各读
各的,衰减的谷值紧跟着下一个分片的加热峰值——谷—峰交替正是「忽高忽低」
的本体;分片成批到达(SSE 抖动、MTP/DFlash2 一次验证多个 draft token、
下游消费慢时 TCP 背压把上游憋成脉冲串)时更严重。新口径是墙钟窗口:
DecodeWindowMeter.rate(at:)= 窗[t−W, t]的量 ÷ 已观测跨度,分子
分母一起滑,稳态恒等于吞吐,与分片大小、到达分布、轮询相位全部无关;
边缘压着的分片按「铺在自己的到达时刻上」部分计。窗口右缘钳到最后一个
事件——秒拍与快拍共用同一个读数也不会错开,早读几十毫秒不会把窗口
掏空成 0。 - 收尾后曲线冻结,不再挂 LAST。
GatewayMeter.overview只把没收尾的
会话算作isLive;finish一落下,当前速度归零、60 秒曲线的右缘冻结在
那一刻(throughputFrozenAt),不再随挂钟把终点挤出窗口。上一请求的终值
不再冒充当前速度,也不进曲线;新请求开始后自动解冻。 - 总解码曲线按 1 秒一拍。 概览不再被 SSE 分片或预填充 chunk 推着
「立即变化」:引擎轮询统一 1 秒,曲线每拍最多落一个点(≥0.9s 的抖动
余量),静默段不拿 0 填谷。请求收尾停住整张图;横轴上 1~2 个样本的
短请求改画点标记,不再被当成空图。 - 首字时刻不再漏记 role-only 分片。
addTokens的记账顺序修正:旧
实现先guard count > 0再记firstTokenAt,空 delta(role-only 首帧、
finish_reason 帧)整帧忽略——TTFT 被记晚、预填充读数随之偏低。现在
「流开始回东西」的第一帧就记下(0 token 只记时、不计生成量)。 - 灵动岛与概览同口径。 胶囊以前引擎 LIVE 计数优先、再落应用内这一路
的本地测速,与概览 hero 的取数顺序相反,两处数字天然对不上;现在统一
走 owner 表,只认 LIVE(网关或引擎实时),绝不回落 LAST/AVG。
命令行与控制接口
- 退出改为同步收尾。
applicationShouldTerminate不再返回.terminateLater后靠
一个Task去回信:当前 macOS 会在任务被调度前销毁进程,导致引擎仍驻留、最后
一次历史写盘丢失。现在在委托里同步走完网关/引擎/下载收尾,最坏等待仍被 1.5 秒
的引擎宽限期封顶;flashcat app quit因此能真正等到进程消失并清掉control.json。 - 概览保留最后一次请求。
GatewayMeter不再在结束 6 秒后删除会话:
「最近请求」保留完成 / 失败行(最多显示 6 条,底层保留 32 条),直到被后续
请求挤出列表。已结束行的耗时固定在收尾时刻,不会跟着挂钟继续涨;它的全程
均值只留在行内与累计平均里,当前速度与曲线在收尾时归零 / 冻结,不再挂
「网关 LAST」。 - 命令行不再误删版本、也不再误判终端。
engines uninstall omlx@0.7.2在只装了
0.7.3 时报错,而不是确认后删掉 0.7.3;chat -与--yes确认改看 stdin 是否
终端,echo … | flashcat chat -在终端里也能用;重复--for累加而不是只留
最后一个;表格按 CJK 显示宽度对齐;--control-url只接受回环地址或 HTTPS,
不把控制令牌明文发给网络;logs --app --level与服务端日志过滤口径一致;
control.json从创建起就是0600,不再有"先 0644 再 chmod"的窗口。 - 控制接口启停竞态。 关闭开关时,正在绑定端口的启动会被作废并关掉新监听,
不会在设置关闭后留下一个还能驱动应用的接口。 flashcat engines start报「未能就绪:等待超时」,引擎其实已经起来。
startService()把启动丢进一个Task,控制器要到下一次 actor 跳转才进
.starting;等待方第一眼看到的还是.stopped,旧实现直接判失败。现在
.stopped在 5 秒宽限期内不算失败,见过.starting之后再停才是真的停了。
MTPLX 的近前缀恢复
- GDN boundary 撑爆条目。 MTPLX 的 session bank 预算有 1 GiB 下限,而一条
19K token 的条目光 GDN boundary 记录就要 700 MB 以上(每条 90 MB、默认最多
8 条),put()把这份开销计入条目大小后整条拒绝,bank 里只剩不含
boundary 的条目;recurrent_boundary_at_or_below()对这类条目返回 None,
近前缀恢复每次都被判boundary_not_better淘汰,最终报成ssd_prefix_miss
——把 adm...
flashCat 1.5.3 · 实时 · 可比 · 轻量
flashCat 1.5.3 · 实时 · 可比 · 轻量
把概览的速度读数收成一套口径:解码统一走网关,引擎只保留自己真正量过的生命体征;
同时去掉装饰数据,把采样内存收口。
修复
- 预填充那格不再挂着一个恒定不变的大数字。 过去把引擎的「上一请求终值」或
「开机以来均值」当成当前速度:splash 的prefill_tokens_per_second是两个累计
计数器之比;MTPLX 的latest.prefill_tok_s只在请求结束时落一次,空闲时原样重复。
现在按粒度打LIVE/LAST/AVG角标,卡片说明随之改口,空闲时不再冒充当前速度。 - splash 改用真·瞬时批次值。
current_prefill_batch/current_decode_batch
带valid标记;有样本时标LIVE,刚启动没跑过同类批次时退回均值并标AVG。
同时按active_requests[].phase区分「正在跑」与「上一批残留」。 - MTPLX 接上正在预填充的那一路。 实时值在
in_flight[].prefill_state,服务端
每完成一个 chunk 就刷新;多路并发取elapsed_s最大的那一路,和 MTPLX 自己的
仪表盘同口径。兜底从单 chunk 峰值换成tokens / compute_time_s滚动均值,峰值只留诊断。 EngineLiveRates的闩锁降级为 LAST。 值仍然保留,卡片不会空成「—」,但粒度
如实标成「上一个请求的实测值」;真有prefill_tokens_live在涨时才回到LIVE。isLive布尔换成EngineRateKind。 一个 bool 分不出「上一请求」和「累计均值」;
多端点合并时粒度与数值同源,取rank最高的那一路,不会出现「数值是均值、角标写 LIVE」。- 预填充不再回落到网关估算。 网关的
(整段提示词 − 缓存命中) / TTFT分母混着排队
与缓存恢复,分子要等末帧usage,请求进行中算不出可靠值;引擎不上报时显示「—」。
变更
- 概览解码速度统一走网关。 hero 大数字、总解码曲线与「最近请求」改为同一份按请求
低通聚合:大数字 = 活跃会话速率之和,三处数字能对上;「最近请求」明确标「网关估算」。
引擎的LAST/AVG不再参与当前速度;只有网关没有在跑会话(客户端直连引擎端口)时
才用引擎实时计数兜底,且要求activeRequests > 0。 - 来源和值一起显示。 hero 角标区分「网关估算 / 网关 LAST / 引擎实时」;曲线 chip
同样标来源;没有实时值显示「—」,不再拿0.00冒充读数。 SESSIONS改读引擎activeRequests。 直连引擎端口的请求也会算进去;预填充、
首字 p50、内存与上下文上限继续读引擎,说明文字标明「引擎」。- 总解码曲线横轴固定 60 秒。 Swift Charts 默认按样本时间范围铺满宽度,只有两三个
样本时会把一次 1 秒的请求拉成一整条长线;现在短线只占右侧那 1 秒。 - 去掉三张指标卡写死的装饰迷你柱。 上下文卡生成中标
EST,结束后回落到引擎usage。 - 预填充读数改成「最近一小段」的实时值。 只保留最近约 1.2 秒(1~2 个 chunk)的
采样点;chunk 之间保持上一格的实测速度,超过 3 秒没有新 chunk 才退回本轮累计均值。
预填充期间轮询提到 0.4 秒,跟得上 chunk 节奏;其余时间仍是 1 秒。
性能
- 概览采样内存收口。 曲线只服务 60 秒 / 5 分钟,样本保留从 30 分钟降到 10 分钟;
ThroughputSample不再为每个点分配 UUID;网关快照从[String: Any]改成结构体,
每秒刷新少了字典装箱与字符串键;删掉每会话 480 格、但没有任何界面在读的历史桶。
工程
- 本版 258 个单元测试通过(44 个 App + 214 个 Kit),3 个依赖本机运行时包 / 集成环境
的用例自动跳过。 pack-index.json收录 MTPLX 2.12.3。EngineLiveRates、StatusParser、GatewayMeter的回归用例覆盖了 LIVE / LAST / AVG
三态、末帧 usage 不回灌速率、多路速率相加等边界。
安装
flashCat-1.5.3.dmg:打开后把 flashCat 拖进「应用程序」flashCat-1.5.3.pkg:双击一路安装
系统要求:Apple Silicon,macOS 26.0 或更高(splash 引擎自身要求 26.4)。
应用为 ad-hoc 签名、未公证,首次打开请右键 → 打开。
引擎运行时不包含在应用内,首次启动按引导下载(80 MB ~ 600 MB)。
flashCat 1.5.2 · 优雅 · 流畅 · 高能
flashCat 1.5.2 · 优雅 · 流畅 · 高能
把「谁在跑哪个模型」这件事做对:网关按请求里的 model 准备权重,界面能透出桌面,
忙等的时间开始说真话。
新增
- 网关按
model路由并拉起模型。 请求里的模型名不再只是装饰字段:网关先解析它属于哪台引擎,
同引擎换权重走热切换 / 重启,跨引擎先卸载再启动,引擎没跑就把它拉起来,就绪后才向上游转发。
以前把未知模型名原样交给「忽略 model 字段」的引擎,客户端会拿到错误模型的成功响应——
这比报错更糟。并发 API 请求在网关侧串行准备,不会两次 load 抢同一个单飞位。 - 自定义背景。 设置里可选一张图片作为画布背景,带「APP 透明度」与「背景模糊」两档:
图片会复制进应用支持目录,原图移动或删除后仍然可用;无论图片多清晰都保留一层画布渐变保底,
文字对比度不塌。没设图片时透明度控制透出桌面——窗口按同一档强度让位给系统壁纸。 - 图标换脸。 应用图标重画为宽脸颊、尖耳朵、额头一道闪电负形的猫头;菜单栏图标改用
手绘贝塞尔剪影 + 模板渲染(运行中实心、停止描边),由系统按菜单栏明暗自动上色,
缩到 18pt 不再是一坨彩色小色块。五台引擎与 splash 启动图各配一枚品牌图标。 - 命令面板新增「切换外观」与「折叠 / 展开边栏」;⌘K、⌘N、⌘\、⌘⇧A 回到菜单与标题栏提示同源。
修复
- 应用最低系统版本回落到 macOS 26.0。 macOS 27 的
.tabs分段样式改为可用性探测,
运行时不可用时回退.segmented;Info.plist、README、CONTRIBUTING、architecture.md
与Package.swift五处门槛一次对齐。splash 引擎自身仍要 26.4,那是引擎级要求。 - 加载权重的等待时间不再虚报。 热加载引擎的 HTTP 壳子先绿、权重后到,
这段等待此前按进程启动时间计算——引擎跑了几小时后重载模型,界面会报「已等待 4:12:03」。
现在加载阶段单独计时,且从点下启动那一刻起表。 - 切换模型时误杀自己。
sh -c script name a b c把name交给$0而不是$1;
缺占位参数时脚本把应用的 pid 当成引擎,引擎一起来就 SIGINT 了 flashCat 自己。 - 预填充读数虚高两个数量级。 同一会话的第二轮几乎全部命中引擎的前缀缓存,
这些 token 根本没被重新前向。现在从 usage 的cached_tokens扣掉命中量,
全命中时回落到引擎实时计数;几路并发改为各路速率相加。 - agent 会话一直显示 0 tok/s。 工具调用的回复大头在
delta.tool_calls[*].function.arguments,
而打点只读了delta.content;现在正文、思考、工具调用名与参数一起计入生成量。 - 切壁纸后玻璃层留残影。 画布回到不透明底色承载,桌面透出交给全窗口的视觉效果层,
并监听壁纸变更强制重排一次。 - 下载列表不再因重复 id 出现空位;灵动岛收起态只留标题与一行信息;
通知缺标题时按级别兜底命名;旧的推理等级取值在读取时收敛到新范围两端。
性能
- 模型目录扫描加 1 秒 TTL(下载 / 删除 / 重载时立即失效),下载进度刷新不再反复扫盘。
- 网关复用同一个
URLSession,不再每请求建销连接池。 - 空闲时隔秒轮询,忙起来恢复每秒;健康探测响应复用给遥测采集,各端点并发拉取。
- 日志页一次遍历同时得出按级别计数与过滤结果;Markdown 解析分两级缓存;
概览图表按 60 秒窗口取数,不再每秒把约 3600 个样本交给 Swift Charts。 - 对话高频状态拆成独立的
ChatStore,流式分片不再带着概览与模型页一起重算;
长对话只渲染最近若干条。
工程
- strict-concurrency 棘轮基线 36 → 25;
ci.yml说明随之更新。 - 新增
GatewayModelRoutingTests、GatewayMeterTests、EngineLiveRatesTests、
ModelFamilyTests、ModelLibraryTests、DecodeRateTotalTests,以及LocalizationTests
三条契约(每条中文词条都有英文译文;快捷键文案与keyboardShortcut同源;
界面文案在两种语言下都能解析)。 pack-index.json收录 splash 1.6.0、mlx-serve 26.11.2、strata 0.2.11、omlx 0.7.3rc1。- 本版 201 个单元测试,0 失败,3 个依赖本机运行时包 / 集成环境的用例自动跳过。
安装
flashCat-1.5.2.dmg:打开后把 flashCat 拖进「应用程序」flashCat-1.5.2.pkg:双击一路安装
系统要求:Apple Silicon,macOS 26.0 或更高(splash 引擎自身要求 26.4)。
应用为 ad-hoc 签名、未公证,首次打开请右键 → 打开。
引擎运行时不包含在应用内,首次启动按引导下载(80 MB ~ 600 MB)。
flashCat 1.5.1 · 优雅 · 流畅 · 高能
flashCat 1.5.1 · 优雅 · 流畅 · 高能
界面开始说两种语言,模型卡开始标量化。
▶ 观看 1.5.1 介绍片(50 秒,无旁白,1920×1080)
新增
- 中英双语界面。 全部界面文案收敛到
Localizable.xcstrings(435 条,简体中文为源语言、英文全覆盖),
跟随系统语言切换;菜单、弹窗、灵动岛、模型卡、引擎页、日志、toast 都走同一套L10n。
Info.plist声明zh-Hans/en,构建时把 SwiftPM 资源包里的.lproj一并镜像进 app 的Resources,
打包版与swift run都能取到词条。 - 模型量化标识。 模型卡新增
QUANT一行:从文件名、仓库 id、assembly 的files与权重config.json
识别 GGUF(Q4_K_M/IQ3_S/Q2_0)、MLX(oQ4e/3 bpw)、8-bit、BF16/FP16,
公共目录里的共享权重同样标出。量化不用再从仓库名里猜。 - 模型卡标签去掉与
QUANT重复的量词,避免同一个标签印两遍。
修复
- 灵动岛的通知分级改为在本地化之前按源文案判断,英文界面下 “failed / switching” 一类消息
也会归到错误 / 警告,而不是一律信息。 - 格式化文案改用
L10n.format,插值后的字符串不再绕过翻译。
工程
- 新增
LocalizationTests(两种语言都随包发出、核心词条有英文、中文回退到源文案)
与ModelQuantizationTests(GGUF / MLX / bit / 无量化名)。 CFBundleDevelopmentRegion由zh_CN改为zh-Hans,补CFBundleLocalizations。- README 重写「亮点」与宗旨,补上介绍视频。
安装
flashCat-1.5.1.dmg:打开后把 flashCat 拖进「应用程序」flashCat-1.5.1.pkg:双击一路安装
系统要求:Apple Silicon,macOS 27.0 或更高。应用为 ad-hoc 签名、未公证,首次打开请右键 → 打开。
引擎运行时不包含在应用内,首次启动按引导下载(80 MB ~ 600 MB)。
本版 209 个单元测试,0 失败,3 个依赖本机运行时包 / 集成环境的用例自动跳过。
flashCat 1.5.0
flashCat 1.5.0
首个纯原生界面的版本:界面从 WebView 换成 SwiftUI / AppKit,视觉改为 macOS 26 Liquid Glass,
并按引擎的真实生命周期(启动 → 加载权重 → 就绪)来描述状态。
新增
- 灵动岛通知中心。 标题栏中央常驻玻璃胶囊:平时是引擎状态(引擎名、真实阶段、实时 tok/s、启停)。
所有 toast 改从灵动岛弹出,按文案归为信息 / 成功 / 警告 / 错误四类,保留本次会话的通知历史与未读数
(最多 30 条,3.2 秒后自动回到引擎状态)。点开原位展开:有通知时是通知列表(相对时间、清空),
没有通知时是引擎详情(模型、状态、接口、版本、实时速度),点胶囊外任意位置收起。 - 反馈与交流。 侧栏新增入口,弹窗展示 QQ 群号,可一键复制、拉起 QQ;群号留空时显示「待配置」。
- 模型家族识别。 新增
ModelFamily,按仓库 id、标签与提示词认出 Qwen、DeepSeek、Llama、Mistral、Gemma、
Phi、GPT、Nemotron、Granite、GLM、Kimi、Flux、Liquid、MiniMax 等家族,广场列表、详情与模型卡统一显示家族徽标。 - 模型卡渲染。 模型详情把 Hugging Face README 清洗(去 front-matter、徽章与 HTML 标签、还原实体)后
交给 Markdown 渲染,不再是满屏尖括号。 - 日志详情。 日志行可点击展开完整正文,附完整时间、字符数与单行复制;行内改为级别色圆点 + 胶囊标签。
- 引擎生命周期状态。 启动、卸载 / 加载权重、预热、等内存期间,标题栏、概览、菜单栏、引擎页显示真实阶段
与「已等待 m:ss」;权重真正就位才显示「运行中」并允许对话。 - 引擎状态细分。 引擎页区分运行中 / 启动中 / 停止中 / 异常,不再把加载权重误报成「已停止」。
- 模型切换进度。 模型菜单里正在切换的那一项显示转圈与阶段文案(启动引擎 / 停止旧引擎 / 加载权重…)。
- 对话计入网关统计。 应用内对话直连引擎端口时也向网关打点,概览「最近请求」与会话网格不再永远是 0 条。
- 下载中心。 进行中的任务只保留顶部一行,状态标签区分下载中 / 已暂停 / 失败。
界面与交互
- 界面回到纯原生。 六个页面、启动页、下载中心、模型广场、引擎配置与对话参数全部是 SwiftUI / AppKit 视图,
直接读写AppState:没有WKWebView、没有快照桥、没有 token 级 IPC。删除 WebView 壳与整个WebUI/
(14 个 ES module + 8 份 CSS + bundle,约 2.8 万行)及 esbuild 工具链。 - 版式逐页对齐原 WebUI:200 pt 玻璃侧栏、浮层标题栏、概览(hero + 网关 + 四指标 + 总解码 / 最近请求)、
模型(引擎分段 + 搜索 + 两列大卡)、引擎(运行时统计 + 整行卡片)、日志(过滤条 + 玻璃控制台)、设置(左右两列)。 - 窗口 chrome:48 pt 标题栏(折叠边栏、⌘K、外观切换、下载中心徽标)、可拖动调宽侧栏(180–320 pt)、页面切换淡入;
标题栏不再重复放引擎胶囊,红绿灯整体右下挪 6 pt,侧栏收起档 76 → 96 pt。 - ⌘K 命令面板:六页跳转、启停引擎、新对话、生成参数、下载中心、模型广场、切换外观、折叠边栏;↑↓ / ↵ / esc。
- 对话:回车发送、⇧回车换行、滚动离底「回到最新」、思考块流式展开 / 首字后折叠、生成光标与呼吸点;
输入框由TextEditor换成可纵向生长的TextField(没有自带滚动条,点一下就能聚焦);
思考菜单只列当前引擎提供的等级并勾选。 - 模型与引擎:卡片 hover 抬升、当前项强调色描边;「正在使用」状态替代禁用按钮;模型广场支持手填 owner/repo 预检。
- 启动页:与控制台同一套玻璃语言与画布,逐项进场动画,已安装改为玻璃徽标,安装进度显示当前步骤。
优化与变更
- 最低系统版本提高到 macOS 27.0。 按钮组使用 macOS 27 的
.tabs分段控件(Liquid Glass),应用下限随之上移;
splash 引擎自身的 26.4 下限已在这个门槛之下。 - Liquid Glass。 自绘的渐变卡片、顶部高光与冷色投影换成 macOS 26
glassEffect;窗口改为透明、内容区自铺画布,
侧栏与标题栏成为能采到桌面的真玻璃。按钮、卡片、菜单与浮层统一走这一层材质。 - 互斥按钮组改用 macOS 27 原生分段控件(
.tabs):模型页引擎切换、日志级别过滤、设置页外观 / 思考模式 / 思考等级。 - 所有
.plain按钮换成plainHit:整块玻璃底与内边距都算命中区,不再必须点到字形。 - 切换模型的确认文案精简为「将停止 X 并加载 Y,切换期间引擎暂时无法应答」。
- 动效统一到
Motion(140 / 220 ms + 轻弹簧)并服从 reduce-motion;持久化深色外观在启动时即时生效。 - 安装脚本不再把上一版留在
/Applications:备份移出系统目录并注销 LaunchServices 记录,避免旧构建被 Spotlight / Dock 打开。
修复
- 热切换期间引擎已报 ready、权重却还在搬:健康探测失败会让「已等待」停住,现在继续每秒刷新。
- 应用内对话不进网关统计,概览「最近请求」永远 0 条。
- 下载中心进行中的任务同时出现在顶部与列表,看起来像两个下载。
- 删除正在下载的任务时只暂停、留下半成品与任务行;现在真正清理。
- 启动 / 加载权重窗口内仍可发送对话、报错后才提示;现在直接给「模型正在…,请稍候」。
- 旧进程的退出回调不再打断新进程;停止引擎时会真正回收忽略 SIGINT 的子进程。
- 引擎启动增加就绪超时,不再永久停在「启动中」;退出应用改为异步收尾并清理全部引擎。
- 快照序列化失败不再静默;
note()不再关闭运行期日志写入句柄。 - 流式回复改为按消息 id 写入,切换会话不再污染另一条会话。
- 安装脚本失败不再导致
/Applications里没有应用(失败回滚)。
安装
flashCat-1.5.0.dmg:打开后把 flashCat 拖进「应用程序」flashCat-1.5.0.pkg:双击一路安装
系统要求:Apple Silicon,macOS 27.0 或更高。应用为 ad-hoc 签名、未公证,首次打开请右键 → 打开。
引擎运行时不包含在应用内,首次启动按引导下载(80 MB ~ 600 MB)。
本版 202 个单元测试通过,3 个依赖本机运行时包 / 集成环境的用例自动跳过。
flashCat 1.4.2
flashCat 1.4.2
这一版补齐了模型管理与首次使用体验,同时重做了 WebUI 的控件、图标和交互动效。
模型广场与共享目录
- 模型页可以直接搜索 Hugging Face,结果按仓库卡片展示,并支持选择 GGUF 量化。
- 下载到公共模型目录,只保留一份权重;勾选引擎后通过符号链接让它出现在对应引擎的模型目录,不复制文件。
- 已下载但不在内置目录里的权重也会进入模型库,并标为「未收录」;删除正在运行的模型前会先停止引擎。
- 内置目录改用引擎标签归属,不再维护第二套列表。
硬件推荐
- 首次启动根据本机内存与可用磁盘,为 Splash、oMLX、MTPLX 各推荐一档最适合的模型。
- 引擎安装完成后自动下载推荐模型;Splash 会同时准备对应的 DFlash2 draft,缺失时在启动前补齐。
- oMLX 主推三档 Jundot
oQ4e包;MTPLX 主推三档 Qwen,并额外收录 MiMo 9B 与 Qwen3.5 4B 优化包。额外收录项不参与硬件三档评选。
界面与交互
- 统一使用本地 Lucide 图标集,导航、按钮、菜单、状态与空状态采用一致的图形语言和描边。
- 重做按钮、筛选、分段控件、焦点态与按压反馈;可点击的 DIV/SPAN 控件补齐键盘操作与语义。
- 侧栏折叠动画、宽度与手柄移动统一;概览指标顺序调整为解码、预填充、首字延迟、内存。
- 弹层更新改为局部 morph,不再重播入场动画,并保留滚动位置、输入焦点和光标。
- 菜单支持 Escape 关闭,Toast 与状态提示补齐无障碍属性。
修复
- 根目录的拆分 GGUF 不再被误判成一档量化。
- Hub 搜索推送可以正常重绘,量化下拉不再丢失监听。
- 引擎包索引使用相对下载地址,重定向后仍能正确解析。
- 应用最低系统版本统一为 macOS 26.4。
安装
flashCat-1.4.2.dmg:打开后拖进「应用程序」flashCat-1.4.2.pkg:双击一路安装
应用为 ad-hoc 签名、未公证,首次打开请右键 → 打开。运行时包不包含在应用内,首次启动按引导安装。
本版 164 个单元测试通过,3 个依赖本地运行时包或集成包环境的测试自动跳过。
flashCat 1.4.1
flashCat 1.4.1
这一版修的是模型切换的可靠性:跨引擎切换进行中再选一个模型,界面会永久停在「切换中」,只能重启应用。
修复:跨引擎连续切换卡在「切换中」
以 22:02 那次事故为样本,三个漏洞叠在一起:
- 切换完成判得太早:oMLX 的 uvicorn 在权重还没搬完时就返回
application startup complete(/health立刻 200),而 103GB 权重要到下一秒才开始Loading model。旧逻辑只等健康检查,于是把一次 27B 的加载在开头就判成完成——4 秒后再点一个模型,那台还在搬权重的进程直接吃 SIGINT,要等 20 秒强杀才让出显存。现在切换的就绪判据是「目标模型真的进了引擎自己的loaded_models」。 - 第二次选择被静默丢弃:
useModel/applyModelFromAnyEngine/applyModel开头都是guard !isSwitchingModel else { return },换引擎只 toast 一句就返回,点了等于没点。现在跨引擎的新选择立刻接管上一次切换,同引擎的二次选择排队(只保留最后一次),切换中换引擎也不再被拒绝。 - 旧切换任务没人收尾:被跳过的任务走
guard !Task.isCancelled else { return }直接返回,switchingModel永远留着。现在切换状态带代数(generation),被接管/被取消的旧任务静默退出,没有任何路径能把界面留在「切换中」。
生命周期提示补全
「切换中」不再是一句冻结的文案:
- 概览、侧栏、菜单栏一并显示
切换中 · <阶段> · 已等待 m:ss,热引擎权重还在搬时按「加载权重」报阶段而不是「就绪」 - 切换中提供取消等待按钮:放弃等待,引擎继续在后台加载,状态交回引擎自己的启动阶段(进度、秒数、日志继续走),不会打断搬了一半的权重
附带的概览页改动
- 新增会话网格:网关侧按请求打点,一格一路请求,显示解码/预填充速度、首字延迟、输入 token、上下文占用与该路的速度曲线
- 并发口径标注:多路并跑时「解码速度」是引擎聚合值,标签会说明,不再统一标 LIVE
- MTPLX 标注「仅支持串行」并说明并发会排队
- 吞吐曲线保留窗口 5 分钟 → 30 分钟,「全部」档不再等于「5 分钟」
安装
flashCat-1.4.1.dmg:打开拖进「应用程序」flashCat-1.4.1.pkg:双击一路安装
应用为 ad-hoc 签名、未公证,首次打开请右键 → 打开。运行时包不含在应用内,首次启动按引导安装。本版 116 个单元测试全部通过。
flashCat 1.4.0
flashCat 1.4.0
集中在两件事:把 WebUI 的实时指标与列表页从"整页重绘"改成"就地更新",以及菜单栏面板与引擎启动流程的重做。
性能(实测对比,M3 Max / 120Hz 屏)
- 主线程不再同步扫模型目录:
EngineModelStore加 20s TTL 缓存,下载完成/卸载模型时失效。概览页空闲 CPU 20.7% → 约 6%,主线程pushSnapshot采样从 12 秒内 2067 样本降到 258 - 六页渲染改为 keyed DOM morph(
data-key/data-log对齐,输入框内容不再被覆盖):对话页 300 条历史 38ms → 12ms(掉帧 7 → 0)、10Hz 流式 6ms → 3ms、日志页 1Hz 新行 25ms → 4ms(掉帧 4 → 0)、概览页 1Hz/10Hz 4ms/3ms → 2ms - 动画不再被重绘打断:流式期间转圈动画重启次数 57 → 1
- 日志控制台改增量追加(新行插入 + 尾部裁剪),单次推送 DOM 增删 30 → 0
- 事件监听幂等化(
bindOnce),修复节点复用后"点一下等于点两下"的隐患
新增与改进
- 菜单栏面板重做,新增状态栏控制器
- 引擎启动阶段(
EngineStartupStage)独立建模,带单元测试(116 个测试全部通过) - 图标、README、设计系统细节更新
关于 120Hz
WebKit 在 macOS 会把 WKWebView 的渲染上限压在 60Hz(_displayLinkWantsHighFrameRate 恒为 false,无可用 SPI;连 CSS 合成动画也一样)。屏幕是 120Hz 的话,这一层是平台限制,只有原生渲染能突破——已单独规划,不在本版本内。
安装
flashCat-1.4.0.dmg:打开拖进「应用程序」flashCat-1.4.0.pkg:双击一路安装
应用为 ad-hoc 签名、未公证,首次打开请右键 → 打开。运行时包不含在应用内,首次启动按引导安装。
flashCat 1.3.0
flashCat 1.3.0
UI 层整体重写为 WKWebView 混合壳:设计稿 1:1 网页渲染,Swift 引擎管线不变。
新界面
- 六页(概览/对话/模型/引擎/日志/设置)+ 启动页全部按「精密仪器」设计稿 1:1 重做,日/夜双皮肤
- 启动页、下载中心、引擎配置、对话参数全部在网页层完成,原生弹层下线
性能
- 菜单切换提速:乐观导航(点击即切)+ 快照去重跳过空转重绘 + 推送链路压缩
- 日志序列化复用 formatter,心跳空转不再整页重绘
修复
- 启动页塌陷成窄条(网格布局回退)
- 模型/日志搜索框每敲一个字丢焦点
- 对话页实时速率/耗时芯片不更新;流式输出期间上翻阅读不再被拽回底部
- 中文输入法组合期间不再被重绘打断
安装
flashCat-1.3.0.dmg:打开拖进「应用程序」flashCat-1.3.0.pkg:双击一路安装
应用为 ad-hoc 签名、未公证,首次打开请右键 → 打开。运行时包不含在应用内,首次启动按引导安装。
flashCat 1.2.0
新特性
- API 网关(OpenAI + Claude 双格式):内置本地网关默认
http://127.0.0.1:9000/v1,同时提供 OpenAI(/v1/chat/completions)与 Claude(/v1/messages)标准格式与统一模型列表(/v1/models),支持流式输出、工具调用、图片输入;请求自动转发到当前运行中的引擎,引擎切换/换端口都不用改客户端配置。设置页可开关与改端口。 - 菜单栏常驻面板:菜单栏图标实时显示服务状态,点开可看当前模型、解码速率、首字延迟、内存占用,支持启停服务、复制接口地址;关闭主窗口后应用留在菜单栏继续对外服务。
- 模型下载中心:下载任务持久化,支持暂停/继续(断点续传)/取消/重试,显示字节级进度与速度;按本机芯片/内存/磁盘给出模型适配提示与推荐排序。
- 引擎进程治理:退出时整树终止引擎防孤儿进程,启动时自动清扫残留,全引擎接入 detached watchdog(应用崩溃后也能收干净引擎进程)。
改进
- 引擎安装进度改为环形百分比 + 步骤文案,成功/失败弹气泡提示
- 引擎卡片与启动页布局精简;模型库、对话页、概览页、设置页大量视觉与交互打磨
- 上游引擎运行时包构建摆脱 Homebrew 依赖(自举 uv + 上游 wheel 校验下载)
修复
- 对话页 tok/s 偶发虚高、模型卡大小统计错误(符号链接)
- 模型下载进度条不动(tqdm \r 解析、字节级目录监控、半成品目录误判)
- 引擎未安装时切换模型假成功、启动中途退出应用导致引擎进程残留
安装包为 ad-hoc 签名、未公证:首次打开请在 Finder 里右键 flashCat → 打开。
应用不含推理引擎,请自行构建引擎运行时包或把
FLASHCAT_PACK_INDEX_URL指向你自己的索引,见 README。