feat(ui/output): add max_messages option to limit rendered messages#354
feat(ui/output): add max_messages option to limit rendered messages#354
Conversation
There was a problem hiding this comment.
Pull request overview
Adds a configurable cap (ui.output.max_messages) for how many messages remain rendered in the output buffer, evicting older messages and showing a “hidden messages” notice to reduce UI slowdown for long sessions (fixes #320).
Changes:
- Introduces
ui.output.max_messagesconfig/default/types and documents it in the README. - Implements rendered-message eviction + a pinned “hidden messages” notice in the renderer/buffer/formatter.
- Adds renderer replay tests covering limiting, eviction during streaming, and notice updates on removals.
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
lua/opencode/ui/renderer.lua |
Core logic for computing visible messages, eviction, and hidden-messages notice lifecycle. |
lua/opencode/ui/renderer/events.lua |
Triggers reconciliation on message updates/removals; improves handling when state vs render_state diverge. |
lua/opencode/ui/renderer/buffer.lua |
Pins the hidden-messages notice to the top of the buffer via insertion logic. |
lua/opencode/ui/formatter.lua |
Adds formatting for the hidden-messages notice and suppresses its header. |
lua/opencode/config.lua |
Adds max_messages default under ui.output. |
lua/opencode/types.lua |
Adds max_messages to UI output config type. |
README.md |
Documents the new ui.output.max_messages option. |
tests/replay/renderer_spec.lua |
Adds unit tests for limiting/eviction/notice update behaviors. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| local rendered_message = ctx.render_state:get_message(part.messageID) | ||
| if not rendered_message then | ||
| local existing_message = find_message_in_state(part.messageID) | ||
| if existing_message then | ||
| ctx.render_state:set_message(existing_message) | ||
| rendered_message = ctx.render_state:get_message(part.messageID) | ||
| end | ||
| end |
There was a problem hiding this comment.
When max_messages is enabled, a message.part.updated event for an older (currently hidden/evicted) message can cause that message to be re-inserted into ctx.render_state here (ctx.render_state:set_message(existing_message)), making it visible again and potentially violating the configured render limit until the next message.updated/message.removed triggers reconciliation. Consider checking require('opencode.ui.renderer').is_message_visible(part.messageID) (or the active limit) before calling set_message, and if not visible, update the in-memory state.messages entry and keep the part as orphan/unrendered until the message becomes visible again.
Add support for ui.output.max_messages to cap how many messages are kept rendered in the output buffer. When the configured limit is exceeded the oldest messages for the active session are evicted and a hidden-messages notice is inserted/updated to indicate how many older messages are not displayed. This should fix #320
Add a workflow action and command to toggle ui.output.max_messages between a finite number and nil (no limit). Wire the action into the API, keymaps (<leader>otm), types, and UI so users can enable/disable the message limit from the output notice or via command. The toggle notifies the user of the current state. Also ensure render_output returns its promise/value so callers can await rendering when requested.
d10eef2 to
3f640d1
Compare
Add support for ui.output.max_messages to cap how many messages are kept rendered in the output buffer. When the configured limit is exceeded the oldest messages for the active session are evicted and a hidden-messages notice is inserted/updated to indicate how many older messages are not displayed.
This should fix #320