Commit Graph

275 Commits

Author SHA1 Message Date
Hypatia May
8a8c1965d7 feat(web): show durable token usage and context occupancy in the stats line
The chat stats line took its token totals from the loaded conversation nodes,
so paging changed them and compaction erased the billing behind replaced
content. It also had no way to show context occupancy: the numerator and
capacity never reached the browser.

Both now come from token-meter session projections read through the standard
useProjection seat. Window nodes keep supplying turn and step counts plus LLM
and tool wall times, which are correctly window-scoped facts about what is on
screen; accounting no longer comes from there.

`tokenUsage` supplies billing and cache hit. `contextPressure` supplies
occupancy, pairing the newest provider-reported prompt size with the newest
capacity recorded by `request/context`. Deployments without token-meter drop
the token groups; a route whose adapter advertises no capacity drops the
occupancy group rather than rendering a placeholder.

Occupancy is deliberately approximate: the numerator and capacity are
independent last-wins fields, not one atomic request observation, so switching
models pairs a fresh capacity with the prior route's pressure until the next
request reports usage. It is a user-facing reference figure that nothing in the
harness makes decisions from, and it matches how the TUI status line has always
computed occupancy. The Agent Note and token-meter README state this as a
decision, including why the atomic alternative was implemented and rejected, so
it is not re-litigated as a defect.

Snapshot delta is one added `Context N% of 128K` segment across eight web
goldens; the preceding commit absorbed master's pre-existing golden drift.
2026-07-30 14:48:19 +08:00
Hypatia May
7f30a7e30c Merge remote-tracking branch 'origin/master' into codex/status-bar-token-metrics
Conflict resolution notes:

- StatsLine: master redesigned the row into pipe-separated groups with LLM and
  tool wall times. Kept that design and swapped only the token accounting
  source, so counts and durations stay window-scoped while billing and context
  occupancy read the durable projections.
- Generated artifacts (cordis catalog, module graph, event producer/consumer,
  i18n pairing hashes) and web snapshots took master's side; they are
  regenerated and re-recorded after this merge.
- Web e2e goldens and details-panel/timeline assertions took master's side:
  that evolution is unrelated to this branch.
- ui-conversation package.json: kept master's devDependency ordering, re-adding
  only the token-meter entry this branch needs.
2026-07-30 13:56:39 +08:00
Hypatia May
4819210142 refactor(token-meter): make context occupancy durable projection state
Replace the transient `session/model-request` mux frame with ordinary durable
session state. Occupancy now rides two last-wins projection fields instead of a
non-replayable frame that needed removal tombstones and cross-stream fencing.

The frame was the only non-replayable class on the mux stream. Because host and
mux are independent SSE streams with no cross-stream order, a request emitted
before a removal could arrive after `host/session-removed`, and a legitimate
request for a new lifecycle reusing the same id could be fenced by a late
removal. Fixing that needed a lifecycle generation on every frame; the frame
itself was the problem.

Removed: the `session/model-request` frame and schema, the `agent/model-request`
core event, the ApiProxy measurement point, the client-side telemetry map and
removal tombstone, and the synthetic `cancelled` open error used to signal
reconnect through the error channel.

Added: `request/context`, a log-only session event recording the
registration-bound capacity of the route a request resolved to, appended beside
`request/header` from the lookup that already prepared the call and skipped when
the route is unchanged. Capacity stays out of `EpochHeader` because it is
adapter metadata about a route, not an input the request was built from, so it
must not join request reconstruction or header equality.

The `contextPressure` projection pairs the newest provider-reported prompt size
with the newest recorded capacity. The two are deliberately not one atomic
request observation: switching models can pair a fresh capacity with the prior
route's pressure until the next request reports usage. The figure is a
user-facing reference, and this matches how the TUI status line has always
computed occupancy.
2026-07-30 13:53:08 +08:00
imccyu
6e99027917 Merge remote-tracking branch 'origin/master' into mergebot/pr937
# Conflicts:
#	packages/client/ui-conversation/README.i18n.yaml
#	packages/client/ui-conversation/src/client/queue/QueueDock.module.css
2026-07-30 11:59:59 +08:00
kingwl
ad1bb84425 Merge remote-tracking branch 'origin/master' into codex/web-queue-actions
# Conflicts:
#	packages/client/ui-conversation/README.i18n.yaml
2026-07-30 11:38:54 +08:00
07akioni
b92c6bcc66 Merge branch 'master' into fix/ui-action-display 2026-07-30 11:15:35 +08:00
imccyu
60620ec36c Green the jsdom lane for the composer-seat ResizeObserver and new StatsLine format
The seat's height publisher needs a ResizeObserver stub in every spec that
renders ConversationRoot (jsdom has none), and the two branch-tail StatsLine
assertions move to the grouped detail-row output.
2026-07-30 11:09:03 +08:00
Yif
04f6dfdc29 Web composer stats detail row and input-zone polish
Stats line moves into the InputBar's new footer slot (sharing the card's
width column) and expands to the design's grouped detail row: turns/steps,
LLM and tool wall time, cache hit, and input/output token split, all
derived client-side from the snapshot. The composer stack owns one 8px
rhythm, the seat fades the transcript through a fixed 36px gradient band,
back-to-bottom follows a live --dsh-composer-height, and goal/todo strips
share one 752px tip-fill column.
2026-07-30 10:22:44 +08:00
kingwl
112b0fbad1 fix(web): address queue review feedback 2026-07-30 04:12:38 +08:00
kingwl
ebbcfdd03b Merge remote-tracking branch 'origin/master' into codex/web-queue-actions
# Conflicts:
#	packages/core/agent-loop/src/agent.ts
2026-07-30 03:33:41 +08:00
kingwl
7ce330f0e4 refactor(agent): scope queue actions to edit and remove 2026-07-30 01:58:51 +08:00
imccyu
e56c0699a9 Merge branch 'master' into codex/web-queue-actions 2026-07-30 01:21:13 +08:00
Tianyi Cui
4582e1425c Merge commit 'refs/codex/pr885/master-20260730' into worktree/retarget-pr885-20260729
# Conflicts:
#	eslint.config.mjs
2026-07-30 01:18:28 +08:00
kingwl
c97b1d025e Merge remote-tracking branch 'origin/master' into codex/web-queue-actions
# Conflicts:
#	apps/web/tsconfig.json
#	docs/architecture.i18n.yaml
#	docs/event-producer-consumer.md
#	packages/client/runtime/README.i18n.yaml
#	packages/client/tsdown.client.ts
#	packages/client/ui-conversation/README.i18n.yaml
#	packages/core/agent-loop/README.i18n.yaml
#	packages/core/agent/README.i18n.yaml
#	packages/core/agent/README.zh.md
#	packages/host/apiproxy/README.i18n.yaml
#	tsconfig.host.json
2026-07-30 00:30:38 +08:00
Tianyi Cui
0440c4cc0c Merge latest master into codex/migrate-to-oxlint 2026-07-30 00:13:30 +08:00
07akioni
b71fbe770d fix: ci 2026-07-30 00:08:59 +08:00
kingwl
f893e2281d feat(agent): add addressable queue operations 2026-07-30 00:05:00 +08:00
07akioni
4e7f90667a fix: chat agent message actions display 2026-07-30 00:01:49 +08:00
imccyu
3980de695e test(client): pin assembled-app journeys at package level on SlotTestRuntime
Sink the behavior previously held only by the apps/web jsdom snapshots
into the owning packages, each bench mounting the real apply on the
production slot machinery with fixture-fed data:

- ui-conversation/assembly-surfaces: the todo_write turn reaches both
  product surfaces (keyed toolview row + dock plan strip via the todos
  projection) and the strip follows projection retirement; the keyed
  bash row carries its resident terminal card while the fallback row
  reaches one through expand; the locked no-session view state; the
  composer textarea surviving the blank→active conversion as the same
  DOM node; the promptError alert strip with the machine-restored
  draft; one summary update re-labeling the breadcrumb.
- ui-workspace/rename-assembly: the session-rename chain (row menu →
  dialog → the injected renameSession hop → ISession.rename with the
  edge-trimmed draft → dialog close and row re-label from the list),
  plus the rejected arm keeping the dialog open with the error.
- runtime/workspaces-service: startInitialSelection — connects the
  recent Workspace once both baselines are ready and opens the session,
  stays idle with a current session or no recent target (double start
  fails loud), and a failed connect returns to waiting and retries on
  the next list change.

Component-level arms stay in the existing package suites; these files
prove only the assembled wiring.
2026-07-29 23:51:21 +08:00
ZiyaZhang
3dd0ce33f4 Merge remote-tracking branch 'upstream/master' into fix/gui-todo-default-collapsed
# Conflicts:
#	packages/client/ui-conversation/README.i18n.yaml
2026-07-29 08:10:13 -07:00
Tianyi Cui
1f7f5f2d53 Merge latest master into codex/migrate-to-oxlint 2026-07-29 22:43:10 +08:00
Tianyi Cui
2d3338a03b Merge latest master into codex/migrate-to-oxlint 2026-07-29 22:39:06 +08:00
imccyu
b0ee207a2a Merge remote-tracking branch 'origin/master' into mergebot/pr908
# Conflicts:
#	packages/client/ui-conversation/README.i18n.yaml
2026-07-29 22:27:37 +08:00
imccyu
2b56d972eb Merge remote-tracking branch 'origin/master' into mergebot/pr908
# Conflicts:
#	packages/client/ui-conversation/README.i18n.yaml
#	packages/client/ui-trajectory/src/client/views.module.css
2026-07-29 22:15:22 +08:00
imccyu
f4bc0a4a86 Merge remote-tracking branch 'origin/master' into feat/input-command-interaction 2026-07-29 21:40:28 +08:00
Tianyi Cui
e1984cbfd9 Merge commit '90bc53cc64dc684dc3d741f45ae6a8d548c188f9' into worktree/retarget-pr885-20260729 2026-07-29 21:40:13 +08:00
Tianyi Cui
32aaa8983e Merge commit 'ecbf75a5e70f662b6420375140cf12eb6bac7860' into worktree/retarget-pr885-20260729
# Conflicts:
#	docs/development.i18n.yaml
#	packages/client/ui-conversation/src/client/chat/MessageItem.tsx
#	packages/client/ui-primitives/src/markdown/CodeBlock.tsx
#	scripts/snapshots/translation-prompt-v4/request-response.expected.json
2026-07-29 21:37:43 +08:00
imccyu
76b4563380 Merge remote-tracking branch 'origin/master' into feat/input-command-interaction 2026-07-29 21:23:13 +08:00
07akioni
08d097077e fix: cr 2026-07-29 21:03:40 +08:00
imccyu
b23c3d596a Merge remote-tracking branch 'origin/master' into trajectory-history-source 2026-07-29 20:58:04 +08:00
07akioni
2a12057345 fix: ci 2026-07-29 20:56:56 +08:00
Yif
be9042e5a1 docs(client): sync package READMEs and agent notes with the input interaction rework
Update the six touched client package README pairs (slash menu ordering,
localized group titles and dismiss, permission label twin, goal pause,
plan hint localization, useAnchoredMaxHeight) and keep the owning agent
notes current: SlashSource.order and the MenuView dismiss/localize/clamp
face in the slash-pipeline note, the pause verb in the goal bar note.
2026-07-29 20:46:29 +08:00
07akioni
382884e237 fix: scroll to bottom 2026-07-29 20:39:45 +08:00
07akioni
a4602b959e feat: optimize chat page scroll area 2026-07-29 20:26:48 +08:00
imccyu
e0022ff19e refactor(client): isolate trajectory history 2026-07-29 20:21:37 +08:00
Yif
45c9205caf feat(client): localize composer hints and rework input command interaction
Unify the /plan claimed hint with the plan placeholder through a locale
namespace, localize slash menu group titles, replace the PermissionSelect
native select with the Menu primitive, add a goal pause verb chain, clamp
anchored popups to the viewport with scroll-into-view and outside-dismiss,
and fix onPasteUpgrade insertedRange to account for the chip trailing gap.
2026-07-29 19:46:48 +08:00
Hypatia May
fdccc58cef fix(web): narrow request lifecycle fences 2026-07-29 17:46:25 +08:00
_Kerman
859452d807 Merge remote-tracking branch 'github/master' into xtr/trajectory-inspection-ui
# Conflicts:
#	apps/web/tests/snapshots/code-mode-round/ui.expected.md
#	apps/web/tests/snapshots/cordis-tool-round/ui.expected.md
#	apps/web/tests/snapshots/fresh-round-trip/ui.expected.md
#	apps/web/tests/snapshots/lifecycle-chrome/hero.expected.md
#	apps/web/tests/snapshots/lifecycle-chrome/reloaded.expected.md
#	apps/web/tests/snapshots/live-interactions/cancel.expected.md
#	apps/web/tests/snapshots/live-interactions/error-auth.expected.md
#	apps/web/tests/snapshots/live-interactions/retry.expected.md
#	apps/web/tests/snapshots/question-composer/answered.expected.md
#	apps/web/tests/snapshots/seeded-history/ui.expected.md
#	apps/web/tests/snapshots/steering/mid-steer.expected.md
#	apps/web/tests/snapshots/steering/settled.expected.md
#	packages/client/runtime/src/client/contract/session.ts
#	packages/client/ui-conversation/README.i18n.yaml
2026-07-29 17:31:33 +08:00
Hypatia May
872cdfc774 refactor(llm): clarify request context immutability 2026-07-29 16:45:08 +08:00
Chinesezjc
fdcb45b619 fix(web): bound the SGR state and follow real terminal widths
Nine findings, one critical. Terminal cases verified in a real terminal first.

CRITICAL: cells held the accumulated SGR history, so every state boundary
re-emitted the whole chain — output switching color without a full reset
emitted O(n^2) characters. Measured: 3200 such cells produced 25 MB, and the
reviewer's ~90 KB alternating-color case is well under bash's own output cap.
State is now a normalized record (foreground, background, attribute set) with
one canonical sequence per boundary, so the emitted text is linear in cells;
the 90 KB case parses in 36 ms. That also makes the attribute closers every
chalk-based tool writes actually close: `\x1b[1mbold\x1b[22mplain` leaves the
following write PLAIN, which a real terminal confirms.

Width follows emoji presentation, not the U+2600-U+27BF block: `A✓B` redrawn
with `XY` shows `XYB`, so the check every progress line writes is ONE column.
Taking the block as wide misaligned exactly the output this card exists for.

Writing over either half of a wide pair blanks the other, since a terminal
cannot leave one cell of a two-cell glyph standing.

`line\n\x1b[0m` does not end in a newline as a string yet its last parsed line
holds nothing visible, so the terminator check now reads the parsed lines — it
had added a blank row and inflated the collapse count.

A line with no cursor movement no longer builds a column buffer at all; only
its SGR is folded, so an `ls -R` or a 5k-line log allocates nothing per
character.

The `.terminalDescription` rule had been inserted into an existing grouped
selector, silently giving `.codeBody` description typography and changing its
bottom margin from 4px to 0 — a pre-existing surface this PR does not own.
Split out, `.codeBody`'s margin restored.

Three comments contradicted their code: the fixture's exit-marker line (still
claiming recovery from a marker deliberately removed), `bash-sample`'s header
(still routing a click to the details panel, and calling the consumer's cap the
block's own), and a DetailsPanel comment stacked above the wrong rule. The
ui-primitives README documented only the CR/BS half of the replay, so a reader
would expect `OK0%` where `100%\r\x1b[KOK` renders `OK`.
2026-07-29 16:42:10 +08:00
Chinesezjc
c87a20b506 Merge remote-tracking branch 'origin/master' into feat/web-terminal-card
# Conflicts:
#	packages/client/ui-conversation/README.i18n.yaml
#	packages/client/ui-conversation/README.md
#	packages/client/ui-conversation/README.zh.md
2026-07-29 15:44:58 +08:00
Hypatia May
d20e531153 Merge remote-tracking branch 'origin/master' into codex/status-bar-token-metrics
# Conflicts:
#	apps/web/tests/snapshots/code-mode-round/ui.expected.md
#	apps/web/tests/snapshots/cordis-tool-round/ui.expected.md
#	apps/web/tests/snapshots/fresh-round-trip/ui.expected.md
#	apps/web/tests/snapshots/lifecycle-chrome/reloaded.expected.md
#	apps/web/tests/snapshots/live-interactions/cancel.expected.md
#	apps/web/tests/snapshots/live-interactions/retry.expected.md
#	apps/web/tests/snapshots/seeded-history/ui.expected.md
#	apps/web/tests/snapshots/steering/mid-steer.expected.md
#	apps/web/tests/snapshots/steering/settled.expected.md
#	packages/client/ui-conversation/README.i18n.yaml
2026-07-29 15:36:38 +08:00
Hypatia May
bf618dabf9 refactor(web): project usage and snapshot request context 2026-07-29 15:27:59 +08:00
07akioni
c8ea9a5204 fix(ui-conversation): share MessageIconActions to clear jscpd clone
User and assistant chrome both rendered copy/branch buttons; one shared
row owns the chrome and keeps clock placement / edit as props.
2026-07-29 15:11:06 +08:00
ZiyaZhang
64d5ce600b Merge remote-tracking branch 'upstream/master' into fix/gui-todo-default-collapsed
# Conflicts:
#	packages/client/ui-conversation/README.i18n.yaml
#	packages/client/ui-conversation/README.zh.md
2026-07-28 23:54:01 -07:00
ZiyaZhang
9e45736298 fix(gui): default todo panel to collapsed 2026-07-28 23:52:08 -07:00
07akioni
972b3f3a30 fix(ui-conversation): document writeClipboard @param for export JSDoc gate 2026-07-29 14:47:26 +08:00
Chinesezjc
612b3c7c4e Merge remote-tracking branch 'origin/master' into feat/web-terminal-card
# Conflicts:
#	packages/client/ui-conversation/README.i18n.yaml
2026-07-29 14:45:23 +08:00
Chinesezjc
f378873b22 fix(web): replay cursor movements the way a terminal paints them
Carriage return and backspace only MOVE the cursor; neither erases. Both of
my earlier approximations were wrong, and I checked each case against a real
terminal rather than reasoning about it:

`100%\rOK` shows `OK0%`, not `OK` — the redraw is shorter than the frame
beneath it, so the tail stands. `abc\b` still shows `abc`, not `ab` — a
trailing backspace has nothing to overwrite. `\x1b[31mgone\rkept` paints
`kept` RED, because a carriage return does not reset the graphic state, which
one of my own tests had asserted the opposite of.

Both now replay into a per-line column buffer with SGR state stamped per
column, as a terminal stores it per cell. That gives the partial-overwrite
case its real result too: red `bad`, three backspaces, then `ok` shows `okd`
with the `d` still red, since `ok` reached only two of the three cells.

The presenter description now also renders at every site. An expanded row
draws it itself — the collapsed summary is hidden while open, so otherwise
the description was visible only collapsed, the opposite of "above the card"
— and the details panel draws it above the card as well.

Three of my own tests encoded the wrong semantics and were corrected with
their behavior, and the emit loop's gap-filling arm was removed as
unreachable: `\r` and backspace only move left, so no column can be unwritten.
2026-07-29 14:39:21 +08:00
Turtle
711efc0a8e Merge remote-tracking branch 'origin/master' into codex/migrate-to-oxlint 2026-07-29 14:32:21 +08:00