feat(tui): show message timestamps and response duration - #2795
Conversation
…ration and config toggle
…hot-reloading show_timestamp config
…imestamp header layout
…d assistant messages
…ecord timestamps during session restore
…imestamps in session replay
🦋 Changeset detectedLatest commit: 7addf06 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
…estamp # Conflicts: # apps/kimi-code/src/tui/commands/config.ts # apps/kimi-code/src/tui/commands/reload.ts # apps/kimi-code/src/tui/config.ts # apps/kimi-code/src/tui/types.ts # apps/kimi-code/test/tui/commands/update-preferences.test.ts # apps/kimi-code/test/tui/config.test.ts
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 161c082bad
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| return block; | ||
| } | ||
|
|
||
| const showTimestamp = this.state.appState.showTimestamp ?? true; |
There was a problem hiding this comment.
Initialize the timestamp preference at startup
When tui.toml contains show_timestamp = false, createInitialAppState never copies input.tuiConfig.showTimestamp alongside the other preferences, so this fallback resolves to true on every normal launch. Timestamps therefore remain enabled until the user manually invokes /reload-tui or /reload; initialize appState.showTimestamp from the loaded TUI config.
Useful? React with 👍 / 👎.
| host.setAppState({ | ||
| editorCommand: config.editorCommand, | ||
| disablePasteBurst: config.disablePasteBurst, | ||
| showTimestamp: config.showTimestamp, |
There was a problem hiding this comment.
Update mounted messages when reloading the preference
When show_timestamp is changed and /reload-tui or /reload is invoked after messages exist, this only updates appState. UserMessageComponent and AssistantMessageComponent capture the setting in their constructors, their new setShowTimestamp methods are never called, and theme invalidation does not change that field; consequently old messages retain the previous visibility while new messages use the reloaded value. Propagate the setting to mounted message components or rebuild the transcript.
Useful? React with 👍 / 👎.
| this._pendingAgentGroup = null; | ||
| this._pendingReadGroup = null; | ||
| const isReplaying = state.appState.isReplaying ?? false; | ||
| const timestamp = createdAt ?? (isReplaying ? undefined : Date.now()); |
There was a problem hiding this comment.
Use the persisted step start for live response duration
For responses with model latency or thinking before the first assistant.delta, appendAssistantDelta creates the component here and stamps Date.now(), whereas replay derives createdAt from the persisted step.begin record. The same response therefore reports a shorter duration while live and a longer duration after reopening the session. Capture the turn.step.started time for the live block, or use an equivalent timing boundary consistently in both live rendering and replay.
Useful? React with 👍 / 👎.
Related Issue
Resolve #2705
Problem
Message timestamps used an indented layout that reduced transcript width, and assistant messages did not report total response duration. More importantly, reopening a session could reconstruct message timing from the current wall clock or an outer replay-record fallback, producing incorrect timestamps and elapsed durations. Legacy journals without timing must remain distinguishable and render without fabricated values.
What changed
show_timestamppreference to~/.kimi-code/tui.toml.The change is scoped to the CLI and replay pipeline; it does not alter the product Web transcript or message API behavior.
Why the core changes are required
The TUI cannot recover authoritative historical timing by itself. During replay, using the current wall clock fabricates a new timestamp, while using only the outer replay-record time can associate a message with the wrong journal event. Either fallback can make a reopened conversation show incorrect input/output times and response durations.
The journal message records are the source of truth for
createdAtandcompletedAt. This PR preserves those optional fields while core reconstructs the session, carries them through replay metadata, and leaves themundefinedfor journals written by older versions. The TUI only formats the values it receives: historical sessions retain their original timing, and legacy sessions without timing display no timestamp or duration.Terminal output
The screenshot below is rendered with the current TUI message components and covers all compatibility cases:
Checklist
gen-changesetsskill, or this PR needs no changeset.gen-docsskill, or this PR needs no doc update.Validation
pnpm lint(0 errors)pnpm --dir docs buildgit diff --check