Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
5894329
test(mmc-trajectory): ship the guards that were only on one machine
avatasia Oct 11, 2026
3547053
test(mmc-trajectory): make the session-store guards machine-independent
avatasia Oct 11, 2026
af3375e
test(mmc-trajectory): guard the rest, with no service and no machine …
avatasia Oct 11, 2026
6e57455
Remove the commit-message scratch file that git add swept in
avatasia Oct 11, 2026
a4b6717
Give 异常 its own axis, and make its counts mean what they say
avatasia Oct 11, 2026
64ba78b
Make 重置 a reset, and put the row above back when a rule is ticked
avatasia Oct 11, 2026
905c5c9
异常轴加「多选」:默认单选,勾选后可叠加
avatasia Oct 11, 2026
7a92cef
异常轴复审:修正三处控件状态与合计口径,并沉淀验证方法论
avatasia Oct 11, 2026
cc42f8b
把两条筛选轴钉成一块,并把下方每层的偏移改成实测
avatasia Oct 11, 2026
5a283da
补一份分层设计:功能类型 → 层 → 归属
avatasia Oct 11, 2026
3be59b6
Stage 1 冻结 spec:先写清四问与不变量,再动结构
avatasia Oct 11, 2026
816c2d2
Stage 1 spec 修订:跨家族查漏的 15 条结论,改了 6 条断言、加了 3 条后果
avatasia Oct 11, 2026
ab717e3
Make the inspector follow the table, and own the re-measure at one exit
avatasia Oct 11, 2026
7f2eff8
Stop rebuilding the whole lineage on every poll
avatasia Oct 11, 2026
5b3f29b
Build the ledger in batches, and stop the inspector widening the window
Oct 11, 2026
1ec2469
Record the eight undone items, and one measured option that was rolle…
Oct 12, 2026
ed7e872
docs(mmc-trajectory): 归因滚动跳转为既有缺陷 D14,解除 content-visibility 路的阻塞
avatasia Oct 12, 2026
2f6a6ba
fix(mmc-trajectory): 滚动意图跨建行转交,点行不再把读者留在第 1 轮(D14)
avatasia Oct 12, 2026
e2f7560
perf(mmc-trajectory): 逐轮组推导 contain-intrinsic-size,「显示全部」建行 3,437 → 8…
avatasia Oct 12, 2026
c4992bc
test(mmc-trajectory): 声明 R6 的两处跨层配对,Stage 3 完成(未做清单 #5)
avatasia Oct 12, 2026
694cd8a
refactor(mmc-trajectory): 异常轴收成一个字段 state.anomaly {mode, rules, last}…
avatasia Oct 12, 2026
5d9c124
refactor(mmc-trajectory): 可见性收成一个入口 recordVisible(record, turn, selec…
avatasia Oct 12, 2026
ec7c45a
refactor(mmc-trajectory): 删掉 D2 那三句互相矛盾的设计声明,并补上它自己的变异控制(Stage 2-c 注释半)
avatasia Oct 12, 2026
ee85f7f
feat(mmc-trajectory): 增量协议 ?since=,会话增长时只传尾部(Stage 4)
avatasia Oct 12, 2026
52d592c
docs(mmc-trajectory): LAYERS.md 三处已过时——D5 重新计数、第 6 节状态、D15 标题
avatasia Oct 12, 2026
8c6265c
test(mmc-trajectory): 补上搜索框清空的覆盖——那条变异一直在测 state 而不是控件
avatasia Oct 12, 2026
730100d
fix(mmc-trajectory): 三处探针残留的空注释块,补结构守卫 + 2-b 浏览器实测
avatasia Oct 12, 2026
c5c1119
fix(mmc-trajectory): skipping class 跨重建留存,账本塌成 0px,小幅上滚直接到顶
avatasia Oct 12, 2026
192356d
docs(mmc-trajectory): 记 D17 —— 19 行空白系统记录,已查实成因与修法边界
avatasia Oct 12, 2026
7801484
feat(mmc-trajectory): 结算记录成为可筛查的异常规则(D17 修复)
avatasia Oct 12, 2026
d0f9cdb
feat(mmc-trajectory): 上下文代钉在类型行末(D18)——它没有「没有了」,只是住在会滚走的工具栏里
avatasia Oct 12, 2026
3f65f1b
feat(mmc-trajectory): 上下文代随连续下滚让位(D19)——位置对了,但不该在读长账本时白占一行
avatasia Oct 12, 2026
f35cf60
fix(mmc-trajectory): 概览条与窗口条之间的漏行——根因是守卫一直在断言错误的那个元素(D20)
avatasia Oct 12, 2026
e5e847f
revert(mmc-trajectory): 撤回 D19 下滚让位——picker 一滚动就消失
avatasia Oct 12, 2026
f11a967
docs(mmc-trajectory): 收口「滚动时全部/图表行变矮」——成因是 D19 自己,不是抓不到
avatasia Oct 12, 2026
29d6bb3
docs(mmc-trajectory): 关闭未做清单 1c——位置跳变已解释,不再是「很可能」
avatasia Oct 12, 2026
d7f7e23
fix(mmc-trajectory): 窗口条补上缺失的那个口径——加数,不改口径
avatasia Oct 12, 2026
c1609c0
fix(mmc-trajectory): 窄视口整页横向滚动,并撤回一个会骗人的修法(D21)
avatasia Oct 12, 2026
9794952
fix(mmc-trajectory): 空态「清除筛选」漏掉概览条刷选,顺带让基础轴默认值只剩一个写者
avatasia Oct 12, 2026
6f55019
窄屏检视面板三态:文档流 / 半高吸底 / 完全展开吸底
avatasia Oct 12, 2026
6f166cf
D23:吸底断点比单列断点更窄,功能在真实窗口里等于不存在
avatasia Oct 12, 2026
833b55a
D24:检视改成 1/4 高、可拖拽调高、无选中时不可见
avatasia Oct 12, 2026
12f26e9
Revert a mutation that leaked into 833b55a
avatasia Oct 12, 2026
b14595e
D25:「完全展开」不再把账本吃干净
avatasia Oct 12, 2026
c3c07f5
D26:「窗口的1/4」和「检视的高度」取大还是取小 —— 取最小,且机制变成守卫
avatasia Oct 12, 2026
e9920b8
D27 + D28:抓手从来没渲染过(resize 确实等于没做),中间高度 1/4 → 2/5
avatasia Oct 12, 2026
ddbc1ab
fix: 回应 PR #16 的 review —— 4 条必改全部确认存在并修掉,4 条建议采纳 3 条
avatasia Oct 12, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"schemaVersion": 1,
"name": "mmc-trajectory",
"displayName": "会话轨迹",
"version": "1.0.0",
"version": "1.1.0",
"description": "按轮次浏览当前会话的模型轨迹:消息流、思考过程、工具调用与结果、token 与耗时统计。",
"author": "avatasia",
"icon": "icon.png",
Expand Down
8 changes: 7 additions & 1 deletion plugins/avatasia/mmc-trajectory/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ Browse the model trajectory of a MiniMax Code conversation: messages, reasoning,

Author: [avatasia](https://github.com/avatasia) · Version: `1.0.0`

Before changing the page, read [docs/LAYERS.md](docs/LAYERS.md): which functional layer a control belongs to, what it may read, and the four questions to answer before implementing a new one. It exists because this page's filter logic grew one feature at a time, and the defects that produced are all traceable to that.

## Install and use

Copy this entire directory into your active MiniMax Code data directory, including the hidden `.minimax-plugin` directory. By default, `<dataDir>` is the `.minimax` directory in your home folder (`~/.minimax`), so plugins go in `~/.minimax/plugins/`. If you have configured a different data directory, use that directory instead:
Expand All @@ -18,11 +20,15 @@ The author directory is only used to group contributions in the community reposi

The page follows the most recent conversation by default and re-reads it every 2.5 seconds, so it stays live while you work; it pauses while the page is hidden. Each read is validated with an HTTP `ETag`: when the session file has not grown, the service answers `304 Not Modified` with no body and the page keeps what it already rendered. An idle tab therefore costs a few bytes per poll instead of the whole trajectory. Use the session picker to switch to any other conversation. No API key and no dependency installation are required — the package is dependency-free and needs no build step.

When the session *has* grown, the poll carries `?since=<cursor>` alongside its validator and the service answers with the tail instead of the whole session: a payload of the same shape plus a `delta` marker, with `turns` holding only the turns that gained records. On a session of 21,000 records that is roughly 20 KB instead of 43 MB. The cursor is the highest `record.index` the page already holds — the same key `raw?index=` answers on — and it travels only with the validator it was taken against, so a session switch or a manual refresh sends the whole payload instead. `stats` and `session` travel whole in every tail: `stats` is an accumulator over all rows, so a tail cannot be added to it. A page that is ahead of the service (which is what a context-generation switch looks like from here) is answered with the whole payload, since a tail from there is empty and an empty tail is indistinguishable from "nothing to add". This saves transfer and the page's parsing, not the service's work — it still reads, parses and serializes the whole session to build the cache entry and to answer `raw`.

## What it shows

The ledger groups records by turn, following the `turn_id` recorded in the session file. Each record is classified as user, answer, narration, thinking, tool call, tool result, system, or compaction, and each turn header carries that turn's own Token counts and elapsed time. Selecting a record opens a detail panel with summary, raw JSON, tool arguments, tool result, and reasoning, plus a button that hands the record to the Agent's chat input.

**The type chips are the only filter over kinds.** One thing is being filtered — which record kinds are visible — and it is one array in the client, written from exactly three controls: the eight kind buttons, 全部, and 清除筛选. An earlier version also had a row of layer buttons (turn / thinking / call) sitting above the list as presets over those same chips. They were removed, because any preset a reader outgrows becomes a button that contradicts the chips it was supposed to summarise: untick 问答 while leaving 用户 ticked, and the turn button goes dark and claims the conversation is hidden when in fact it was narrowed. One control that cannot drift is worth more than three convenient ones that can. Two further controls cut across kinds instead of over them: a time range, which bounds the ledger to a wall-clock window, and an anomaly filter, whose rules pick out records that are wrong — a failed tool call, a compaction, a turn that never got an answer, an answer that came back empty — rather than records of a particular kind. Neither rewrites the kind array, so every kind chip still answers exactly one question.
**The type chips are the only filter over kinds.** One thing is being filtered — which record kinds are visible — and it is one array in the client, written from exactly four controls: the eight kind buttons, 全部, 清除筛选, and the anomaly filter. An earlier version also had a row of layer buttons (turn / thinking / call) sitting above the list as presets over those same chips. They were removed, because any preset a reader outgrows becomes a button that contradicts the chips it was supposed to summarise: untick 问答 while leaving 用户 ticked, and the turn button goes dark and claims the conversation is hidden when in fact it was narrowed. One control that cannot drift is worth more than three convenient ones that can. Two further controls cut across kinds instead of over them: a time range, which bounds the ledger to a wall-clock window, and an anomaly filter, whose rules pick out records that are wrong — a failed tool call, a compaction, a turn that never got an answer, an answer that came back empty — rather than records of a particular kind.

**The anomaly filter is the one cut-across control that also rewrites the kind array**, and deliberately so: ticking an anomaly rule calls the same `resetBaseFilters()` the 清除筛选 button calls, which returns kinds to all, clears the search box, drops any brush on the overview strip, and clears the time range. Without that, a reader could tick 工具失败 with 问答 unticked, see nothing, and have no way back except hunting for which of five controls to undo. The cost is stated here because it is a real cost: the chips stop being a filter you keep while you narrow by error — so 「只回答一个问题」 holds for the chips only outside anomaly mode, which is also when they are the only thing still in play. A time range and a search term still never rewrite the kind array.

Naming kinds directly costs one extra click and reaches everything a preset did — tick 用户 *and* 答复 for the conversation, untick both for its absence, and any scattered subset in between, such as only the user's questions or only system records.

Expand Down
6 changes: 5 additions & 1 deletion plugins/avatasia/mmc-trajectory/README.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

作者:[avatasia](https://github.com/avatasia) · 版本:`1.0.0`

改动这个页面前,先读 [docs/LAYERS.md](docs/LAYERS.md):一个控件属于哪一层、能读什么、以及实现新功能之前必须先答的四个问题。它存在的原因是这个页面的筛选逻辑是一次加一个功能长出来的,产出的缺陷都能追溯到这一点。

## 安装与使用

把整个目录(含隐藏的 `.minimax-plugin`)复制到你的 MiniMax Code 活跃数据目录下。默认情况下 `<dataDir>` 是家目录下的 `.minimax`(即 `~/.minimax`),所以插件放在 `~/.minimax/plugins/`。如果你配置过其它数据目录,请用那个目录:
Expand All @@ -22,7 +24,9 @@

台账按 `turn_id` 把记录分组,轮次划分完全依据会话文件中记录的 `turn_id`。每条记录被归类为用户、答复、过程、思考、工具调用、工具结果、系统或压缩;每个轮次表头带该轮自己的 token 计数与耗时。选中任意记录会打开详情面板,含摘要、原始 JSON、工具入参、工具结果与思考内容,并提供一个把该记录内容送回 Agent 对话输入框的按钮。

**类型选项是唯一针对「类型」的筛选。** 被过滤的始终只有一件事——哪些记录类型可见——客户端里它是同一个数组,只由三个控件写入:八个类型按钮、「全部」和「清除筛选」。早期版本在列表上方还排了一行图层按钮(轮次 / 思考 / 调用),作为同一批类型选项的快捷预设,已经删除。任何读者能走偏的预设,最终都会变成一个与它本该概括的选项自相矛盾的按钮:只取消「过程」而保留「用户」,轮次按钮就熄灭并声称整个对话已隐藏,而实际上你只是收窄了它。一个不会跑偏的控件,比三个方便的控件更值钱。 另外两个控件并不在类型之上做筛选,而是横跨类型:时间区间把台账限制在一个墙上时钟窗口内;异常筛选挑出的是「出了问题的记录」—— 工具失败、上下文压缩、整轮没有答复、答复是空的 —— 而不是某一类记录。两者都不改写类型数组,所以每个类型选项始终只回答一个问题。
**类型选项是唯一针对「类型」的筛选。** 被过滤的始终只有一件事——哪些记录类型可见——客户端里它是同一个数组,只由四个控件写入:八个类型按钮、「全部」、「清除筛选」,以及异常筛选。早期版本在列表上方还排了一行图层按钮(轮次 / 思考 / 调用),作为同一批类型选项的快捷预设,已经删除。任何读者能走偏的预设,最终都会变成一个与它本该概括的选项自相矛盾的按钮:只取消「过程」而保留「用户」,轮次按钮就熄灭并声称整个对话已隐藏,而实际上你只是收窄了它。一个不会跑偏的控件,比三个方便的控件更值钱。 另外两个控件并不在类型之上做筛选,而是横跨类型:时间区间把台账限制在一个墙上时钟窗口内;异常筛选挑出的是「出了问题的记录」—— 工具失败、上下文压缩、整轮没有答复、答复是空的 —— 而不是某一类记录。

**异常筛选是唯一一个会改写类型数组的横跨控件,而且是故意的**:勾选任一异常规则时,它调用的是「清除筛选」按钮调的那个 `resetBaseFilters()`,把类型恢复为全选、清空搜索框、丢掉总览条上的刷选、并清掉时间区间。否则读者会勾上「工具失败」而「问答」还取消着,看到一片空白,却不知道该回去改哪一个——一共五个控件可以撤销。代价必须写出来,因为它是真代价:异常模式下类型选项就不再是「一边保留一边按错误收窄」的筛选器 —— 所以「每个类型选项只回答一个问题」这句话只在异常模式之外成立,而异常模式之外也正是类型选项唯一还在起作用的时候。时间区间和搜索词仍然不改写类型数组。

直接点名类型只多花一次点击,却能到达预设原本覆盖的全部范围:勾选「用户」**和**「答复」就是对话,两个都取消就是没有对话,中间任意散落的子集(只看用户提问、只看系统记录)同样可以。

Expand Down
Loading
Loading