Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
96 commits
Select commit Hold shift + click to select a range
b6898bc
The session picker asked when a session last wrote, not whether it is…
avatasia Oct 20, 2026
211a4dd
The picker had no guard that could fail about any of this
avatasia Oct 20, 2026
5b6f091
The picker claimed more than the code could establish
avatasia Oct 20, 2026
a0150b8
The picker listed runs among the conversations, and nothing said whic…
avatasia Oct 20, 2026
2147741
The two layers of the picker had no guard of their own
avatasia Oct 20, 2026
3249425
A run that won the current conversation was promoted into the convers…
avatasia Oct 21, 2026
e985d9e
The two layers are guarded where the promise is kept, not where it is…
avatasia Oct 21, 2026
bbe2dc9
A parent id from the runtime database could break the session picker
avatasia Oct 21, 2026
2066c91
The two ends of the parent-id boundary are guarded where they are kept
avatasia Oct 21, 2026
98c9253
A late 304 could overwrite the validator the newer answer installed
avatasia Oct 21, 2026
7c5da47
The two rules that were only half-covered now have owners that can fail
avatasia Oct 21, 2026
0fc9f6f
A recorded path is checked against the session it names, and a sessio…
avatasia Oct 21, 2026
5803ae3
The recorded path and the chain of parents now have owners that can fail
avatasia Oct 21, 2026
89375ef
The rows a session list publishes are built, and a directory is a ses…
avatasia Oct 21, 2026
576a271
Four rules about what a row may say get owners that can fail
avatasia Oct 21, 2026
4e58d8d
A directory is a session's directory only when its name and its manif…
avatasia Oct 21, 2026
c02fde8
The rules about which directory is a session's get owners that can fail
avatasia Oct 21, 2026
7f74dcc
A directory is published under one id, and everything downstream read…
avatasia Oct 21, 2026
3576cb5
The rules about the published id get owners that can fail
avatasia Oct 21, 2026
ca78443
A cache that holds an answer has to say which answer it is holding
avatasia Oct 21, 2026
eea9c0f
Guard the id in the validator, in the cache key and in the fallback
avatasia Oct 21, 2026
44b1c46
A replaced request writes nothing, and a read names the session it is…
avatasia Oct 21, 2026
401d66e
Ask the trajectory poll and the secondary reads what they are about
avatasia Oct 21, 2026
a47482d
The READMEs say what the layer rule is, not the earlier version of it
avatasia Oct 21, 2026
b19e862
The family finds the body, and the search names the session on screen
avatasia Oct 21, 2026
00c16aa
The body of the session on screen is reachable, and the answer has to…
avatasia Oct 21, 2026
34b1e0e
The body on screen says which slice it is, and the handoff keeps its …
avatasia Oct 21, 2026
6739f89
The guards that own the slice, the session identity and the handoff
avatasia Oct 21, 2026
beba2b5
A position read says which record of the body it means
avatasia Oct 22, 2026
80cae52
The guards that own a record's version and the route's slice
avatasia Oct 22, 2026
6eb841b
The runtime refuses a data dir that would put its artifacts inside th…
avatasia Oct 22, 2026
a786b6b
The guard that owns where the derived artifacts may land
avatasia Oct 22, 2026
7c5eeaa
The ledger holds its rows only for the groups the reader is on, and a…
avatasia Oct 22, 2026
72759e9
The guards that own the ledger's rows and the search route's version
avatasia Oct 22, 2026
1f296ed
An answer that is standing is retired when the records behind it chan…
avatasia Oct 22, 2026
0cee0b3
The guards that own the two rules, and the controls that break them
avatasia Oct 22, 2026
c27557d
A rebuild does not keep a group the reader has left alive, and a tail…
avatasia Oct 22, 2026
cf8dae2
The guards that own the rebuild's lease and the tail's record set
avatasia Oct 22, 2026
94ebdf1
A released group keeps the height it had, brought up to date with wha…
avatasia Oct 22, 2026
6e84ab0
The guards that own the height a released group keeps
avatasia Oct 22, 2026
4df9a45
A compaction band is charged as a band, and not as a row as well
avatasia Oct 22, 2026
b2e0be1
The guards that own a band being charged once
avatasia Oct 22, 2026
073b804
The height a released group keeps now survives the default view
avatasia Oct 22, 2026
28375e4
The guards that own the held height in the first batch
avatasia Oct 22, 2026
fabda81
A limit of zero is zero records, on both paths
avatasia Oct 22, 2026
b2a9bd9
The badge says what the runtime marked it, not what it did not do
avatasia Oct 22, 2026
9f50822
客户端:活组量到的高度进状态;持有行的组数上限在访客路径上也成立
avatasia Oct 22, 2026
948c5e5
客户端:活组测量与访客路径封顶的守卫与变异
avatasia Oct 22, 2026
29b8b5d
服务端:缓存搜索按台里序折前 N,命中同序;段盖不满 body 时不硬答
avatasia Oct 22, 2026
394ba76
服务端:台里序折、命中同序、段盖不满时退回重建的守卫与变异
avatasia Oct 22, 2026
8adf329
Search: cap the cached path's hits AFTER the ledger's order, not duri…
avatasia Oct 22, 2026
b751f38
Search: pin the cached path's hit set and order, and the cap's place …
avatasia Oct 22, 2026
6e2b106
Ledger: keep the window's first group on both paths, and price the ro…
avatasia Oct 22, 2026
35755c4
Ledger: pin the window's first group on both paths, and the height th…
avatasia Oct 22, 2026
b9fe499
A live ledger group measures itself again when its layout changes, an…
avatasia Oct 22, 2026
9b67991
Two rules about the ledger's measurements get an owner each, and a th…
avatasia Oct 22, 2026
4b45568
A rule in the search-segments guard could not fail, and now it can.
avatasia Oct 22, 2026
cdfd81e
The two search mutation controls now say which rule each case is abou…
avatasia Oct 22, 2026
a0c83b0
A mutation control has to decide a case by the NAME of the rule that …
avatasia Oct 22, 2026
e6e059d
Seven controls now judge a case by the NAME of the rule that case broke.
avatasia Oct 22, 2026
8939b74
A control that says it caught its cases by name has to mean it, and n…
avatasia Oct 22, 2026
f996ff8
The rule about a build that stopped watching now has an owner, and th…
avatasia Oct 23, 2026
17e77a5
tests: make the rebuilt-observer owner discriminate re-registration
avatasia Oct 23, 2026
1ca4413
The service keeps the rendered body as bytes instead of as one string.
avatasia Oct 23, 2026
2cbad75
Five ways to undo the new body serialization, and an owner for each o…
avatasia Oct 23, 2026
01c5dcf
Give the parsed-rows cache a time limit, and say what its budget counts
avatasia Oct 23, 2026
28e3aec
Pin the parsed-rows cache's own contract, and name every mutation
avatasia Oct 23, 2026
ff232b9
Say when the rows are really released, and mean one thing by a limit …
avatasia Oct 23, 2026
49df7ac
The pieces reach the socket as pieces, and the closing bracket is cou…
avatasia Oct 23, 2026
63589d6
Write N has to be piece N, and the records are compared one by one
avatasia Oct 23, 2026
7b28b14
The byte owner has an escape of its own, and the overlap is spelled out
avatasia Oct 23, 2026
0dc9190
The timer that releases the rows runs on the interval the cache reports
avatasia Oct 23, 2026
20272b4
The timer that releases the rows runs on the interval the cache reports
avatasia Oct 23, 2026
803e10f
The two owners that read the source now watch the thing they are about
avatasia Oct 23, 2026
adab5c7
The two owners that accused each other now rule about their own rule
avatasia Oct 23, 2026
b6aba3c
The owners that answered from the text now answer from what the code …
avatasia Oct 23, 2026
e866428
An owner that cannot read what it needs stops accusing the rules it i…
avatasia Oct 23, 2026
05942ef
The three owners that read the text now read what the service and the…
avatasia Oct 23, 2026
aae3468
The promise is read as the whole phrase it is written in, and a numbe…
avatasia Oct 23, 2026
adb74b9
The control's cases are tuples again, so the guard that reads them ca…
avatasia Oct 23, 2026
dfc0db8
Read the whole phrase, locate the promise itself, and accuse nothing …
avatasia Oct 23, 2026
3f9d45a
Hold the three new owner escapes by name, and sync the one frozen entry
avatasia Oct 23, 2026
a8abecf
Give the reader's own assertion an owner
avatasia Oct 23, 2026
049d7f8
Give the promise's own reader an owner for what it cannot read
avatasia Oct 23, 2026
b801a78
Give the promise's owners a diagnosis instead of a guess
avatasia Oct 23, 2026
84f7cb3
Give the promise's numbers a name of their own
avatasia Oct 23, 2026
41293e3
Give the promise's signs, fractions and decoys a name of their own
avatasia Oct 24, 2026
176f414
State the cache's rule instead of a number a reader has to check
avatasia Oct 24, 2026
9a2840c
Comment: drop the number the client already declares
avatasia Oct 24, 2026
980094f
Comment: state the ledger's rule instead of one session's numbers
avatasia Oct 24, 2026
4e8c850
Comment: stop quoting the constants the code declares next to them
avatasia Oct 24, 2026
1918e20
Merge upstream/main into the pull request branch so the base is not b…
avatasia Oct 24, 2026
3d30e5d
Comment: name the constant the heap multiple belongs to
avatasia Oct 24, 2026
1a04e4d
Comment: the dock's default is the share the constant declares
avatasia Oct 24, 2026
3202fcd
Comment: name the share the dock and the ledger take of the window
avatasia Oct 25, 2026
f880e1e
Comments: drop one machine's readings, and hold the constant names
avatasia Oct 25, 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
8 changes: 7 additions & 1 deletion plugins/avatasia/mmc-trajectory/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,10 @@ __pycache__/
# mid-mutation is caught on the next one instead of being inferred from whatever the source looks
# like afterwards. The snapshot is machine-specific bookkeeping and this directory is the package
# that ships to readers, so it must never be tracked.
tests/.shipped-snapshot.json
tests/.shipped-snapshot.json

# Derived artifacts. The runtime writes the search segments under its own data dir, which is
# outside this package; the runtime refuses a data dir that lands in here (see `start()` in
# miniapp/node/server.mjs). This entry is the second half of that rule: if a caller ever got
# through, the directory must not be tracked and must not be part of what ships.
trajectory-artifacts/
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"schemaVersion": 1,
"name": "mmc-trajectory",
"displayName": "会话轨迹",
"version": "1.2.0",
"version": "1.3.0",
"description": "按轮次浏览当前会话的模型轨迹:消息流、思考过程、工具调用与结果、token 与耗时统计。",
"author": "avatasia",
"icon": "icon.png",
Expand Down
5 changes: 3 additions & 2 deletions plugins/avatasia/mmc-trajectory/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ English | [简体中文](README.zh-CN.md)

Browse the model trajectory of a MiniMax Code conversation: messages, reasoning, tool calls and their results, Token usage, and per-turn timing.

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

### Before you change this page

Expand Down Expand Up @@ -131,7 +131,8 @@ The runtime database is opened in read-only mode. If it is missing, unreadable,
- A single `messages.jsonl` is read up to 64 MB. Larger sessions are truncated and the page says so.
- The ledger does not use virtual scrolling; every rendered row is a real element. The page therefore opens on the newest 200 records, and the window bar button switches to the whole session. The button names what pressing it will do, not the current state: 「显示全部」 at the default and 「显示最新 200 条」 once everything is showing, while the count beside it reports what is on screen. That full view is opt-in for a reason: on a 9,900-record session it is roughly 57,000 elements rebuilt every 2.5s poll, which was measured to freeze the page rather than be read. 「向上加载更早的 N 条」 widens the window in steps and a poll does not undo it. A sticky window bar under the overview strip offers that choice behind four explicit controls: switch the strip between equal width and a real time axis, load 200 earlier records, jump back to the latest 200, and show everything. "Show everything" builds every record in the session into the DOM at once and gets noticeably slower on large sessions; incoming records do not knock it back down to 200.
- `messageCount` and `turnCount` in the session picker are estimates derived from a bounded prefix of the file; exact values come from the selected session.
- A session the runtime spawned from another one is marked 「子会话」 in the picker. The parent is deliberately not named: a branch is always newer than the session that spawned it, so its parent has usually aged out of the most-recent-N window this list is built from, and a lookup that fails quietly is how a picker ends up asserting something it cannot see.
- The session picker is **two selects in a cascade**. The upper one, 「会话」, lists conversations only — the sessions whose parent, followed up the chain, is a conversation. A session with no parent is one of them, and so is one whose parent names no session, whose parent chain ends in a cycle, or whose parent is itself a run: the layer follows the chain rather than the one column, and a row that ends up in the conversation layer carries no parent. The lower one, 「子代理」, lists the runs of the conversation that was picked: it is **empty by default**, it has values once a conversation is picked, and it is empty and disabled while the page follows the newest conversation. Measured on this machine, 13 of the 20 rows were sub-agent runs, so a reader could not tell which row was their own conversation; those 13 runs were also where that conversation actually happened. Nothing is hidden, only moved — the runs are not rows of the conversation list any more, they are rows of the run list under it, and the conversation list is now the twenty most recent conversations rather than the twenty most recent sessions of any kind. Every run is listed, most recently active first, and pressing one switches the page to it. The layer is decided by the chain of parents, which is independent of the 「定时 / 任务 / 轻量」 markers. The parent's name is still not written out: the parent id comes down with the row, and the page groups by that one id rather than doing a lookup that could fail quietly. Picking a run shows **that run's own trajectory** — a run is a session with its own transcript, and the parent's transcript does not contain its turns — and the conversation select stays on its parent.
- The picker also says what a session **is**, not only what it is called: a scheduled run carries 「定时」, a background task 「任务」, and a lightweight conversation 「轻量」 — the markers come from the runtime's own record of the session, not from anything this app checks — so none of them can be mistaken for a conversation you wrote. They stay in the list and stay selectable — a marker is a marker, not a filter. The conversation the runtime database reports as current comes first, then the sessions of its own workspace, then the rest; the workspace path and the raw purpose string are compared on the server and never reach the page.
- Light theme token coverage is verified — every `--mcode-*` token the page consumes is defined for both themes — but its rendered appearance was not visually checked; the page was exercised under a dark system preference.

## Tested environment
Expand Down
5 changes: 3 additions & 2 deletions plugins/avatasia/mmc-trajectory/README.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

按轮次浏览一段 MiniMax Code 对话的模型轨迹:消息流、思考过程、工具调用与结果、token 消耗与每轮耗时。

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

### 动手改这个页面前

Expand Down Expand Up @@ -117,7 +117,8 @@ MiniMax Code 不会告诉 Mini App 是哪段对话打开了它的页面:传给
- 单个 `messages.jsonl` 最多读取 64 MB。更大的会话会被截断,页面会明确说明。
- 台里没有用虚拟滚动,每一行都是真实的 DOM 元素。页面默认只展示最新 200 条,窗口条上的按钮可以切到全量;全量是可选的,因为它很贵 —— 在这个会话上约 9,900 条、约 5.7 万个元素,每 2.5 秒轮询重建一次,实测会直接卡死页面。总览条正下方的吸顶窗口栏提供三个显式控件:「总览轴」「向上加载更早的 200 条」,以及在最新 200 条与全量之间切换的那一个按钮(它写的是按下去会变成什么,默认为「显示全部」,全量时为「显示最新 200 条」;当前窗口由右边的计数条报告,两者回答的是不同问题)。「总览轴」只改总览条的横轴——等宽(每条记录一样宽,完全忽略时间)或真实时间轴(宽度等于该记录的真实耗时);它不筛选、不排序,台账里的行和页面上的任何计数都不变。「向上加载更早的 200 条」每点一次就多加一页,轮询不会把已经加宽的窗口重置回去;点切换按钮也不会自动滚动页面,读者正在看的那一行会留在原地。
- 会话选择器里的 `messageCount` / `turnCount` 是从文件的有界前缀估算的;精确值以选中会话后展示的为准。
- 会话选择器里,被运行时从另一个会话派生出来的会话标为「子会话」,但不写父会话的名字:分支一定比派生它的会话新,而列表按最近活动取前 30 个,父会话通常已经掉出这个窗口。静默失败的查找,最终会让列表声称一个它看不见的东西。
- 会话选择器是**级联的两个下拉框**。上面那个「会话」只列主会话 —— 沿父链往上走、终点是一段主会话的那些。父会话为空的是主会话;父会话指向一个不存在的会话、父链成环、或者父本身是子代理的,也是主会话 —— 层级看的是链,不是那一列,而落到会话层的行不带父会话。下面那个「子代理」只列所选那段对话的子代理,**默认是空**,选中主会话之后才有值,跟随最新时是空的且不可选。实测本机 20 行里有 13 行是子代理,读者根本分不出哪一行是自己的对话,而那 13 行恰恰就是这段对话真正发生的地方。它们没有被藏起来,只是从「平铺在会话里」变成「会话列表下面的子代理列表」:会话列表现在列的是最近 20 段主会话,而不是最近 20 个任意种类的会话;子代理有多少列多少,按各自最后一次活跃的时间倒序,最活跃的排在最上面,点其中一条就切到那一条。层级由父链决定,与「定时 / 任务 / 轻量」那套标记互相独立。父会话的名字仍然不写:父 id 由服务端随这一行带下来,页面按同一个 id 归组,不做一次可能悄悄失败的查找。选了子代理就显示**那一次运行自己的**轨迹 —— 每个子代理是一段独立的会话,有自己的 transcript,父会话的轨迹里并不包含它的轮次;此时上面那个下拉框停在它的父会话上。
- 会话选择器不只说会话**叫什么**,还说它**是什么**:定时任务标「定时」,后台任务标「任务」,轻量会话标「轻量」(标记来自运行时对会话自己的记录,不是这个应用检查出来的),于是它们不会被误认成你自己开的对话。它们仍然在列表里、仍然可以选 —— 标记是标记,不是过滤。运行时库报告为当前的那段对话排在最前,然后是同一工作区的会话,再然后是其它;工作区路径和 purpose 原文只在服务端比较,不会发到页面。
- 浅色主题的 token 覆盖已验证(页面用到的每个 `--mcode-*` 变量在两套主题下都有定义),但渲染外观未做视觉检查;功能验收是在深色系统偏好下进行的。

## 测试环境
Expand Down
Loading
Loading