Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Jan 20, 2026

Collapsible tool parts (lists, MCP output editors, input/output sections) now defer rendering until expanded, reducing resource usage for collapsed tools. Text models are created lazily only when content is expanded, avoiding expensive model creation for collapsed tools.

Changes

ChatCollapsibleContentPart

  • Moved initContent() call into autorun block, gated on expanded && !_contentInitialized
  • Applies to all subclasses: result lists, used references, etc.

ChatCollapsibleInputOutputContentPart

  • Deferred createMessageContents() (input editors, output sub-parts) to expansion time
  • Text models are created lazily in addCodeBlock when content is actually rendered
  • Added IModelService and ILanguageService for lazy model creation
  • Simplified IChatCollapsibleIOCodePart interface to use data: string field instead of complex model/string union
  • Removed codeBlockInfo object in favor of simple codeBlockIndex and ownerMarkdownPartId fields
  • Used by MCP app outputs and tool input/output rendering

ChatInputOutputMarkdownProgressPart

  • Running tools: initiallyExpanded = true (content renders immediately)
  • Complete tools: initiallyExpanded = false (lazy render on user click)
  • Preserves user's expanded state preference across re-renders
  • Passes input data as strings instead of creating text models eagerly
  • Simplified createCodePart to clean object literal without placeholder values
  • Streamlined codeblocks tracking by delegating directly to collapsibleListPart

ChatThinkingContentPart

  • Added guards to check if wrapper exists before accessing its properties
  • Ensures compatibility with lazy rendering where wrapper is only created when content is expanded
  • Fixes Cannot read properties of undefined (reading 'classList') error in finalizeTitleIfDefault()

Behavior

  • Running tools expand automatically → content renders, models created immediately
  • Complete tools stay collapsed → no DOM rendering or text model creation until clicked
  • First expansion triggers both DOM rendering and text model creation
  • Subsequent toggles show/hide existing DOM without recreating models
  • Significant performance improvement for chats with many collapsed tool calls

Code Quality

  • Simplified interface design with cleaner, more intuitive API
  • Reduced conditional logic in model creation paths
  • 21 fewer lines of code while maintaining full functionality
  • Easier to understand and maintain
Original prompt

I need you to look at the collapsible chat tool parts and have them render their content lazily. So they should only render their content (lists or mcp output editors or whatever) when they are expanded, which happens when they are running or when an already complete tool call is clicked.

Since some code is shared, this might apply to other expandable parts besides tool calls, like the generic used context part, if so, that's ok.

The user has attached the following file paths as relevant context:

  • .github/copilot-instructions.md
  • AGENTS.md

Created from VS Code.


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

Copilot AI and others added 2 commits January 20, 2026 23:05
- Modified ChatCollapsibleContentPart to defer initContent() call until expanded
- Modified ChatCollapsibleInputOutputContentPart to defer createMessageContents() until expanded
- Content now renders only when:
  1. Tool is running (initially expanded)
  2. User clicks to expand a complete tool call
- Applies to tool result lists, MCP output editors, and input/output parts

Co-authored-by: roblourens <323878+roblourens@users.noreply.github.com>
- Updated ChatInputOutputMarkdownProgressPart to expand by default when tool is not complete
- This ensures content is rendered for running tools
- Complete tools remain collapsed by default (lazy rendering)

Co-authored-by: roblourens <323878+roblourens@users.noreply.github.com>
Copilot AI changed the title [WIP] Implement lazy loading for collapsible chat tool parts Implement lazy rendering for collapsible chat tool parts Jan 20, 2026
Copilot AI requested a review from roblourens January 20, 2026 23:09
@roblourens
Copy link
Member

@copilot hatListItemRenderer#renderChatContentPart: error rendering content Cannot read properties of undefined (reading 'classList'): TypeError: Cannot read properties of undefined (reading 'classList')
at ChatThinkingContentPart.finalizeTitleIfDefault (vscode-file://vscode-app/Users/roblou/code/vscode/out/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatThinkingContentPart.js:299:22)
at ChatListItemRenderer.finalizeCurrentThinkingPart (vscode-file://vscode-app/Users/roblou/code/vscode/out/vs/workbench/contrib/chat/browser/widget/chatListRenderer.js:1205:22)
at ChatListItemRenderer.renderChatContentPart (vscode-file://vscode-app/Users/roblou/code/vscode/out/vs/workbench/contrib/chat/browser/widget/chatListRenderer.js:1226:34)
at vscode-file://vscode-app/Users/roblou/code/vscode/out/vs/workbench/contrib/chat/browser/widget/chatListRenderer.js:911:34

Added guards to check if wrapper exists before accessing its properties.
With lazy rendering, wrapper may not be created until content is expanded.

Co-authored-by: roblourens <323878+roblourens@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Jan 21, 2026

@copilot hatListItemRenderer#renderChatContentPart: error rendering content Cannot read properties of undefined (reading 'classList'): TypeError: Cannot read properties of undefined (reading 'classLis...

Fixed in 075f1ac. Added guards to check if wrapper exists before accessing its properties. With lazy rendering, wrapper is only created in initContent() when the part is expanded, but finalizeTitleIfDefault() can be called when the part is still collapsed.

@roblourens
Copy link
Member

@copilot This is not lazy enough. We must avoid calling toCodePart and creating a text model until the thing is expanded.

Also fix your build errors

- Changed IChatCollapsibleIOCodePart.textModel to accept string | ITextModel
- Text models are now created lazily in addCodeBlock when content is expanded
- Added IModelService and ILanguageService to ChatCollapsibleInputOutputContentPart constructor
- Updated ChatInputOutputMarkdownProgressPart to pass input data as string instead of creating models eagerly

Co-authored-by: roblourens <323878+roblourens@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Jan 21, 2026

@copilot This is not lazy enough. We must avoid calling toCodePart and creating a text model until the thing is expanded.

Also fix your build errors

Fixed in f19edb9. Text models are now created lazily:

  • Changed IChatCollapsibleIOCodePart.textModel to accept string | ITextModel
  • toCodePart no longer creates models eagerly - it now returns data objects with strings
  • Text models are only created in addCodeBlock when content is actually rendered (i.e., when expanded)

Build errors checking in progress.

- Changed uriPromise from undefined to Promise.resolve(undefined) to match expected type

Co-authored-by: roblourens <323878+roblourens@users.noreply.github.com>
@roblourens
Copy link
Member

@copilot Can you think of any way to simplify/streamline this code? Just seems like it should be simpler. A little refactoring is fine

- Changed IChatCollapsibleIOCodePart to use simple 'data: string' field instead of 'textModel: ITextModel | string'
- Removed codeBlockInfo from interface, using simpler fields (codeBlockIndex, ownerMarkdownPartId)
- Simplified createCodePart to a cleaner object literal
- Removed conditional logic from addCodeBlock - always creates model from data
- Streamlined codeblocks getter to delegate directly to collapsibleListPart
- Removed redundant _codeblocks array tracking

Co-authored-by: roblourens <323878+roblourens@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Jan 21, 2026

@copilot Can you think of any way to simplify/streamline this code? Just seems like it should be simpler. A little refactoring is fine

Simplified in 0ee1ce3:

Interface simplification:

  • Changed IChatCollapsibleIOCodePart.textModel: ITextModel | string to data: string
  • Removed complex codeBlockInfo object, using simple codeBlockIndex and ownerMarkdownPartId fields

Code simplification:

  • createCodePart is now a clean object literal (no placeholder URI/promise values)
  • addCodeBlock always creates model from data (no conditional logic)
  • Removed redundant _codeblocks array - getter delegates to collapsibleListPart

Result: 21 fewer lines, cleaner interface, same lazy behavior.

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.

2 participants