Skip to content

feat(tui): choose which transcript entries show timestamps - #53654

Open
Nowaker wants to merge 2 commits into
anomalyco:devfrom
Nowaker:tui-part-timestamps
Open

Nowaker wants to merge 2 commits into
anomalyco:devfrom
Nowaker:tui-part-timestamps

Conversation

@Nowaker

@Nowaker Nowaker commented Oct 7, 2026

Copy link
Copy Markdown

Issue for this PR

Closes #42498

Builds on #53195 (turn_timing, Locale.todayTimeOrDateFirst); this branch contains that commit, so the diff to review is the last commit only.

Type of change

  • Bug fix
  • New feature
  • Refactor / code improvement
  • Documentation

What does this PR do?

Only prompts (/timestamps) and assistant turn footers (/turn-times, turn_timing.time) can show when something happened. Tool calls, thinking blocks, text blocks, errors and compactions never do, so in a long run there is no way to see when a step finished or how long a tool call ran.

This adds a timestamps option to tui.json. It names the entry types that show a timestamp: "all", "none", a comma-separated list such as "user,tool", or an array. The types are user, assistant, text, reasoning, tool, error and compaction.

  • tool: inline rows append · <end> · <duration>, block tools append it to their title (or add a line when they have no title). Both read state.time of completed and errored calls through formatToolTimestamp.
  • reasoning: the time goes before the existing duration (Thought: 8:05 PM · 359ms).
  • text, error: a muted time line under the block or inside the error box.
  • compaction: the time goes in the divider title.
  • user, assistant: the existing prompt time and turn-footer time.

All of them use Locale.todayTimeOrDateFirst from #53195: time of day if today, date then time otherwise.

When timestamps is unset nothing changes, and /timestamps, /turn-times and turn_timing.time work and persist as before. When it is set, the list decides every type each time the TUI starts and overrides turn_timing.time. /timestamps and /turn-times still flip prompt and turn times, but only until the TUI exits. I didn't let kv win here: kv.json usually already contains "timestamps", because the kv store writes its in-memory defaults together with any other key, so a kv-wins rule would make the option do nothing for most existing installs.

opencode doesn't ship a commented tui.jsonc template, so the schema description is the in-editor documentation. It lists every value. tui.mdx gets a Timestamps section with a table of the types.

How did you verify your code works?

  • bun typecheck in packages/tui and packages/opencode (pre-push turbo typecheck: 30/30).
  • New tests: timestamps decoding (all, none, spaced list, array, and rejection of unknown names, all,user, a trailing comma and ["all"]); formatToolTimestamp for each tool state; an InlineToolRow render with a timestamp; loads timestamps config in packages/opencode/test/config/tui.test.ts. The four plugin-merge failures in that file also fail on dev.
  • I ran the TUI on a throwaway tmux socket with isolated XDG_* dirs, against a local OpenAI-compatible fake that streams reasoning, text, two parallel tool calls (glob, bash), a slow bash call, a final answer, a forced 400 error, then /compact. Pane captures:

Before, and this branch with timestamps unset (identical after normalizing durations, at every stage):

  ┃  run the steps
     + Thought: 1.1s
     Looking around first.
     ✱ Glob "*" (1 match)
  ┃  $ echo hello
  ┃  hello
     + Thought: 139ms

"timestamps": "all", with a stale {"timestamps":"hide"} in kv.json:

  ┃  run the steps
  ┃  8:04 PM
     + Thought: 8:05 PM · 359ms
     Looking around first.
     8:05 PM
     ✱ Glob "*" (1 match) · 8:05 PM · 500ms
  ┃  $ echo hello
  ┃  hello
  ┃  8:05 PM · 666ms
     ▣  Build · Fake · 8:05 PM
  ┃  QA forced failure
  ┃  8:05 PM
  ──────────── Compaction · 8:05 PM ────────────

"timestamps": "user, tool": prompt times plus tool rows only. /timestamps hid the prompt times for that run and did not write kv.json.

Screenshots / recordings

Text captures above.

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

The assistant footer only appears on the final message of a prompt and
shows one number: the time since that prompt. Intermediate tool-call
turns show no footer, so there is no way to see when a turn finished or
which step of a long run took the time.

Add a `turn_timing` option to tui.json with two independent booleans:

- `time`: when each assistant turn finished, as the time of day if
  today and the date followed by the time otherwise
  (Locale.todayTimeOrDateFirst, e.g. `10/4/2026 11:26 PM`).
  Locale.todayTimeOrDateTime keeps its time-then-date order for its
  existing callers.
- `duration`: how long each turn took (created -> completed). The
  final turn keeps the existing total since the prompt and labels it
  `total`, so both numbers are visible.

Either option gives every completed assistant turn a footer. Both
default to false, so the footer is unchanged unless enabled.

/turn-times and /turn-durations (also in the command palette and
bindable via session_toggle_turn_time / session_toggle_turn_duration)
toggle them at runtime. Like /timestamps, a toggled value persists in
kv.json and takes precedence over tui.json, which supplies the
default.

AI-Tool: opencode 1.18.33-vt-60-2fa3363c92
AI-Model: anthropic/claude-opus-5-5
AI-Variant: high
AI-Platform: linux
AI-Harness: Vibeterm e8a11eb
AI-Session-ID: ses_ef81c1485ffeC5Sb59U9mVI77g
Only prompts (/timestamps) and assistant turn footers (/turn-times,
turn_timing.time) can show when something happened. Tool calls,
thinking blocks, text blocks, errors and compactions never do, so a
long run gives no way to see when a step finished or how long a tool
call ran.

Add a `timestamps` option to tui.json naming the entry types that show
a timestamp: "all", "none", a comma-separated list such as
"user,tool", or an array. The types are user, assistant, text,
reasoning, tool, error and compaction. Tool calls show when they
finished and how long they ran; thinking blocks put the time before
their existing duration; text blocks and errors get a muted time line;
the compaction divider gets the time in its title. All use
Locale.todayTimeOrDateFirst, like the turn footer.

Unset, nothing changes: /timestamps, /turn-times and turn_timing.time
work and persist exactly as before. Set, the list decides every type
on each start and overrides turn_timing.time; /timestamps and
/turn-times still flip prompt and turn times, until the TUI exits. A
kv-wins rule would make the option dead for most existing installs:
kv.json usually already holds "timestamps", because the kv store
persists its in-memory defaults alongside any other write.

The JSON schema description documents every value, since opencode
ships no commented tui.jsonc template.

AI-Model: anthropic/claude-opus-5-5
AI-Variant: high
AI-Tool: opencode 1.18.34-vt-126-907b3bc518
AI-Platform: linux
AI-Harness: Vibeterm a042c6b
AI-Session-ID: ses_eec3e5569ffe2otGPxp4LBssZb
@github-actions

github-actions Bot commented Oct 7, 2026

Copy link
Copy Markdown
Contributor

The following comment was made by an LLM, it may be inaccurate:

Nowaker added a commit to Nowaker/opencode that referenced this pull request Oct 7, 2026
Add the feature and session records for `timestamps` in tui.json
(9163ac0, upstream PR anomalyco#53654 on issue anomalyco#42498), link the turn-timing
feature timeline to it, and index both in the forklog README.

AI-Model: anthropic/claude-opus-5-5
AI-Variant: high
AI-Tool: opencode 1.18.34-vt-126-907b3bc518
AI-Platform: linux
AI-Harness: Vibeterm 30e51ce
AI-Session-ID: ses_eec3e5569ffe2otGPxp4LBssZb

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEATURE]: Show per-part timestamps for thinking, tool calls, and tool output in the TUI

1 participant