Add "verbose limit" support for configuring exec tool display truncat…#55770
Add "verbose limit" support for configuring exec tool display truncat…#55770hiqiuyi wants to merge 3 commits into
Conversation
Greptile SummaryThis PR adds a Key findings:
Confidence Score: 4/5Safe to merge after fixing the two TUI stale-state issues; web UI and backend paths are correct. Two P1 defects in the TUI path: (1) loadHistory falls back to the previous session's verboseLimit on switch, causing the wrong truncation length for the newly loaded session; (2) applySessionInfo's conditional guard means chatLog is never reset when a session entry lacks a verboseLimit. Both produce incorrect display state. The rest of the implementation — directive parsing, gateway schema, sessions-patch, web UI, and backend threading — is solid. src/tui/tui-session-actions.ts — both the loadHistory (line 310) and applySessionInfo (line 180) verboseLimit update paths need attention.
|
| Filename | Overview |
|---|---|
| src/tui/tui-session-actions.ts | Two stale-state issues: loadHistory falls back to the previous session's verboseLimit on switch, and applySessionInfo never calls setVerboseLimit(undefined) to clear the chatLog limit when an entry lacks the field. |
| src/agents/tool-display-exec.ts | Extracts DEFAULT_VERBOSE_LIMIT = 120 constant and threads optional maxLength through resolveExecDetail → compactRawCommand; logic is correct with one minor redundancy in the ?? fallback. |
| src/auto-reply/reply/directives.ts | Correctly extends matchLevelDirective/extractLevelDirective to optionally consume a numeric suffix (e.g. 'limit 50') for specified keyword levels. |
| src/auto-reply/reply/directive-handling.impl.ts | Handles 'limit [n]' branch cleanly; integer validation (Number.isInteger + n >= 1) is correct, and session store update pattern matches existing code. |
| src/gateway/sessions-patch.ts | verboseLimit patch handling (set / null-clear) is consistent with the pattern used for every other optional session field. |
| ui/src/ui/views/chat.ts | Passes activeSession?.verboseLimit as execDetailMaxLength directly from the session row, so the web UI correctly resets to undefined on session switch (no stale-state issue). |
Prompt To Fix All With AI
This is a comment left during a code review.
Path: src/tui/tui-session-actions.ts
Line: 310-311
Comment:
**Stale `verboseLimit` on session switch**
When a user switches to a session that has no saved `verboseLimit`, `record.verboseLimit` is `undefined`. The `?? state.sessionInfo.verboseLimit` fallback then preserves the *previous* session's limit, so `chatLog.setVerboseLimit` is called with a stale value. Every exec tool card shown in the new session will use the wrong truncation length.
The same session-switch fallback pattern is used for `verboseLevel` / `thinkingLevel` / etc. on the lines above and is a pre-existing quirk, but those fields don't feed `chatLog` state; `verboseLimit` does, making this observable.
Because `loadHistory` is the "cold" session-load path (full reload, `chatLog.clearAll()` follows immediately), the right behaviour here is to take whatever the server returned — `undefined` meaning "use the default":
```suggestion
state.sessionInfo.verboseLimit = record.verboseLimit;
chatLog.setVerboseLimit(state.sessionInfo.verboseLimit);
```
How can I resolve this? If you propose a fix, please make it concise.
---
This is a comment left during a code review.
Path: src/tui/tui-session-actions.ts
Line: 180-183
Comment:
**`chatLog` limit not reset when entry clears `verboseLimit`**
`applySessionInfo` is also called by the live-session-update path (e.g. after a session reload or when the gateway pushes a new entry). If the incoming `entry` doesn't carry `verboseLimit` (e.g. because it was null-patched to remove the limit), the `if` guard means `chatLog.setVerboseLimit` is never called with `undefined`, so the chatLog silently retains the previously-applied limit for all future tool cards.
The same concern applies if the user ever sets `verboseLimit: null` via `sessions.patch` — `applySessionInfo` would receive an entry with `verboseLimit === undefined` and leave chatLog unchanged.
Consider calling `setVerboseLimit` unconditionally so the chatLog always reflects the resolved session state:
```suggestion
next.verboseLimit = entry?.verboseLimit;
chatLog.setVerboseLimit(next.verboseLimit);
```
How can I resolve this? If you propose a fix, please make it concise.
---
This is a comment left during a code review.
Path: src/agents/tool-display-exec.ts
Line: 418
Comment:
**Redundant default in `compactRawCommand` call**
`compactRawCommand` already declares `maxLength = DEFAULT_VERBOSE_LIMIT` as a default parameter, so passing `maxLength ?? DEFAULT_VERBOSE_LIMIT` is redundant — when `maxLength` is `undefined` both expressions produce the same result. Simplifying removes the need to keep two places in sync if the default ever changes:
```suggestion
const compact = compactRawCommand(unwrapped, maxLength);
```
How can I resolve this? If you propose a fix, please make it concise.Reviews (1): Last reviewed commit: "Add "verbose limit" support for configur..." | Re-trigger Greptile
| state.sessionInfo.verboseLimit = record.verboseLimit ?? state.sessionInfo.verboseLimit; | ||
| chatLog.setVerboseLimit(state.sessionInfo.verboseLimit); |
There was a problem hiding this comment.
Stale
verboseLimit on session switch
When a user switches to a session that has no saved verboseLimit, record.verboseLimit is undefined. The ?? state.sessionInfo.verboseLimit fallback then preserves the previous session's limit, so chatLog.setVerboseLimit is called with a stale value. Every exec tool card shown in the new session will use the wrong truncation length.
The same session-switch fallback pattern is used for verboseLevel / thinkingLevel / etc. on the lines above and is a pre-existing quirk, but those fields don't feed chatLog state; verboseLimit does, making this observable.
Because loadHistory is the "cold" session-load path (full reload, chatLog.clearAll() follows immediately), the right behaviour here is to take whatever the server returned — undefined meaning "use the default":
| state.sessionInfo.verboseLimit = record.verboseLimit ?? state.sessionInfo.verboseLimit; | |
| chatLog.setVerboseLimit(state.sessionInfo.verboseLimit); | |
| state.sessionInfo.verboseLimit = record.verboseLimit; | |
| chatLog.setVerboseLimit(state.sessionInfo.verboseLimit); |
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/tui/tui-session-actions.ts
Line: 310-311
Comment:
**Stale `verboseLimit` on session switch**
When a user switches to a session that has no saved `verboseLimit`, `record.verboseLimit` is `undefined`. The `?? state.sessionInfo.verboseLimit` fallback then preserves the *previous* session's limit, so `chatLog.setVerboseLimit` is called with a stale value. Every exec tool card shown in the new session will use the wrong truncation length.
The same session-switch fallback pattern is used for `verboseLevel` / `thinkingLevel` / etc. on the lines above and is a pre-existing quirk, but those fields don't feed `chatLog` state; `verboseLimit` does, making this observable.
Because `loadHistory` is the "cold" session-load path (full reload, `chatLog.clearAll()` follows immediately), the right behaviour here is to take whatever the server returned — `undefined` meaning "use the default":
```suggestion
state.sessionInfo.verboseLimit = record.verboseLimit;
chatLog.setVerboseLimit(state.sessionInfo.verboseLimit);
```
How can I resolve this? If you propose a fix, please make it concise.| if (entry?.verboseLimit !== undefined) { | ||
| next.verboseLimit = entry.verboseLimit; | ||
| chatLog.setVerboseLimit(entry.verboseLimit); | ||
| } |
There was a problem hiding this comment.
chatLog limit not reset when entry clears verboseLimit
applySessionInfo is also called by the live-session-update path (e.g. after a session reload or when the gateway pushes a new entry). If the incoming entry doesn't carry verboseLimit (e.g. because it was null-patched to remove the limit), the if guard means chatLog.setVerboseLimit is never called with undefined, so the chatLog silently retains the previously-applied limit for all future tool cards.
The same concern applies if the user ever sets verboseLimit: null via sessions.patch — applySessionInfo would receive an entry with verboseLimit === undefined and leave chatLog unchanged.
Consider calling setVerboseLimit unconditionally so the chatLog always reflects the resolved session state:
| if (entry?.verboseLimit !== undefined) { | |
| next.verboseLimit = entry.verboseLimit; | |
| chatLog.setVerboseLimit(entry.verboseLimit); | |
| } | |
| next.verboseLimit = entry?.verboseLimit; | |
| chatLog.setVerboseLimit(next.verboseLimit); |
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/tui/tui-session-actions.ts
Line: 180-183
Comment:
**`chatLog` limit not reset when entry clears `verboseLimit`**
`applySessionInfo` is also called by the live-session-update path (e.g. after a session reload or when the gateway pushes a new entry). If the incoming `entry` doesn't carry `verboseLimit` (e.g. because it was null-patched to remove the limit), the `if` guard means `chatLog.setVerboseLimit` is never called with `undefined`, so the chatLog silently retains the previously-applied limit for all future tool cards.
The same concern applies if the user ever sets `verboseLimit: null` via `sessions.patch` — `applySessionInfo` would receive an entry with `verboseLimit === undefined` and leave chatLog unchanged.
Consider calling `setVerboseLimit` unconditionally so the chatLog always reflects the resolved session state:
```suggestion
next.verboseLimit = entry?.verboseLimit;
chatLog.setVerboseLimit(next.verboseLimit);
```
How can I resolve this? If you propose a fix, please make it concise.| const cwd = cwdRaw?.trim() || result?.chdirPath || undefined; | ||
|
|
||
| const compact = compactRawCommand(unwrapped); | ||
| const compact = compactRawCommand(unwrapped, maxLength ?? DEFAULT_VERBOSE_LIMIT); |
There was a problem hiding this comment.
Redundant default in
compactRawCommand call
compactRawCommand already declares maxLength = DEFAULT_VERBOSE_LIMIT as a default parameter, so passing maxLength ?? DEFAULT_VERBOSE_LIMIT is redundant — when maxLength is undefined both expressions produce the same result. Simplifying removes the need to keep two places in sync if the default ever changes:
| const compact = compactRawCommand(unwrapped, maxLength ?? DEFAULT_VERBOSE_LIMIT); | |
| const compact = compactRawCommand(unwrapped, maxLength); |
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/agents/tool-display-exec.ts
Line: 418
Comment:
**Redundant default in `compactRawCommand` call**
`compactRawCommand` already declares `maxLength = DEFAULT_VERBOSE_LIMIT` as a default parameter, so passing `maxLength ?? DEFAULT_VERBOSE_LIMIT` is redundant — when `maxLength` is `undefined` both expressions produce the same result. Simplifying removes the need to keep two places in sync if the default ever changes:
```suggestion
const compact = compactRawCommand(unwrapped, maxLength);
```
How can I resolve this? If you propose a fix, please make it concise.Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 0a40672f2a
ℹ️ About Codex in GitHub
Codex has been enabled to automatically 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 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| await client.request("sessions.patch", { key: sessionKey, verboseLimit: n }); | ||
| return { content: `Verbose limit set to **${n}**.` }; |
There was a problem hiding this comment.
Trigger refresh after applying /verbose limit
executeVerbose patches verboseLimit but returns only content, while dispatchSlashCommand only reloads sessions/history when result.action === "refresh" (ui/src/ui/app-chat.ts). As a result, the active session snapshot keeps the old verboseLimit, so tool cards continue truncating exec commands at the previous length until a manual refresh or navigation occurs.
Useful? React with 👍 / 👎.
| state.sessionInfo.verboseLimit = record.verboseLimit ?? state.sessionInfo.verboseLimit; | ||
| chatLog.setVerboseLimit(state.sessionInfo.verboseLimit); |
There was a problem hiding this comment.
Clear stale verboseLimit when history omits it
When loading a different session, this assignment keeps the prior session’s verboseLimit whenever the new session has no override (undefined). That leaks truncation settings across sessions (e.g., session A set to 500, session B unset still renders at 500), which breaks per-session behavior and makes TUI tool display inconsistent with stored session state.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ae2bd61f1b
ℹ️ About Codex in GitHub
Codex has been enabled to automatically 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 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| if (entry?.verboseLimit !== undefined) { | ||
| next.verboseLimit = entry.verboseLimit; | ||
| chatLog.setVerboseLimit(entry.verboseLimit); | ||
| } |
There was a problem hiding this comment.
Reset verboseLimit when session entry omits override
This update only applies verboseLimit when the field is present, so a previously set limit is never cleared on refresh paths that return verboseLimit as undefined (for example after sessions.patch clears it with null, or when a session has no override). In that case state.sessionInfo.verboseLimit and tool rendering keep using the stale old value, so truncation no longer matches persisted session state.
Useful? React with 👍 / 👎.
|
What could be causing this? It works fine locally when I run pnpm check and pnpm build. |
|
Thanks for the context here. I swept through the related work, and this is now duplicate or superseded. Keep open: the requested configurable verbose exec-display limit is not on current main, but this branch still has source-proven blockers around current exec detail options, stale session state, Web refresh, invalid argument parsing, and missing real behavior proof. Canonical path: Close this stale PR. The latest review rated it F, the branch still lacks merge-ready proof, and there has been no human follow-up after the durable review. So I’m closing this here because the remaining work is already tracked in the canonical issue. Review detailsBest possible solution: Close this stale PR. The latest review rated it F, the branch still lacks merge-ready proof, and there has been no human follow-up after the durable review. Do we have a high-confidence way to reproduce the issue? Yes for the review blockers from source: the PR's Web Is this the best way to solve the issue? No: the configurable limit is a plausible feature, but this branch is not the best merge shape until it is rebased onto the current display/session APIs, fixes stale state, and supplies real behavior proof. Security review: Security review cleared: No dependency, workflow, secret, permission, or supply-chain change was found; the concrete concerns are functional session-state and compatibility risks covered separately. AGENTS.md: found and applied where relevant. What I checked:
Likely related people:
Codex review notes: model gpt-5.5, reasoning high; reviewed against 6fcc9457020e. |
|
ClawSweeper PR egg 🎁 Pass real behavior proof to wake the egg and unlock a hatchable treat. Where did the egg go?
|
|
This pull request has been automatically marked as stale due to inactivity. |
● Summary
per session.
tool logs to understand what was executed.
stored in the session entry (verboseLimit), persisted via sessions.patch, and threaded to compactRawCommand() through
resolveToolDisplay → resolveExecDetail. A single DEFAULT_VERBOSE_LIMIT = 120 constant replaces the previous inline
magic number.
on/off/full logic is untouched.
Change Type
Scope
Linked Issue/PR
N/A
Root Cause / Regression History
N/A
Regression Test Plan
N/A — new feature, no prior behavior to regress.
behavior or data integrity.
User-visible / Behavior Changes
Diagram
Before:
/verbose on → exec tool log always truncated at 120 chars
After:
/verbose limit 300 → stored in session
exec tool log → compactRawCommand(cmd, 300) → truncated at 300 chars
Security Impact
Repro + Verification
Steps
Expected
Human Verification
Compatibility / Migration
Risks and Mitigations
gateway-side ACP runs).
behavior.