Skip to content

FEAT: Improve chat usability - #3276

Open
Richard Lundeen (richlundeen) wants to merge 3 commits into
microsoft:mainfrom
richlundeen:richlundeen-chat-usability
Open

Richard Lundeen (richlundeen) wants to merge 3 commits into
microsoft:mainfrom
richlundeen:richlundeen-chat-usability

Conversation

@richlundeen

@richlundeen Richard Lundeen (richlundeen) commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor

Description

This may not seem like much but I think it makes the chat window way more usable.

  • Add Undo last send, keeping the converter placement and text so you can edit converter specifics in place.
  • Make conversation editing and conversions more intuitive. Double clicking to edit, default same conversation, and a lot of little changes that are hard to see but very noticeable when using
  • Make tests more reliable and reduce overlap.

Undo sits below the converter icon inside the prompt box. Screenshot uses demo data and mocked responses.

Undo last send below the converter icon inside the prompt box

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: c7e3facd-c947-4d49-b77a-4077d471767e
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: c7e3facd-c947-4d49-b77a-4077d471767e
Comment on lines +240 to +246
if (!inputIds.has(piece.draftId)) return piece
const conversion = applied[piece.draftId]
return {
...piece,
converted_value: conversion?.convertedValue,
converted_value_data_type: conversion?.convertedDataType,
applied_converter_ids: conversion?.converterInstanceIds ?? [],

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] Please preserve conversions on pieces that this edit did not touch. applied only contains conversions produced in this editor session, not every existing converted piece in converters.inputs. I reproduced this with one message containing two already-converted text pieces: opening its converter panel and editing the first working input clears the second piece's converted_value, type, and converter IDs. Saving then silently replaces that second piece's converted content with its original. Could this callback apply only the changed piece IDs, with explicit invalidation handled separately?

Comment on lines +1586 to +1590
const conversion = activePieceConversions[piece.draftId]
return conversion ? {
...piece, converted_value: conversion.convertedValue,
converted_value_data_type: conversion.convertedDataType,
applied_converter_ids: conversion.converterInstanceIds,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] Please preserve the pending prompt's original and conversion provenance on the round trip back to the composer. With this new composer-to-editor path, I reproduced: type hello, run Base64 conversion, enter Edit Conversation, Save, then Send. The outgoing piece is only { original_value: "aGVsbG8=" }; hello, converted_value, and applied_converter_ids are lost. draftMessageToInput flattens the conversion and restoreConversions(..., {}, {}) clears it. Restoring a real piece conversion rather than treating the converted output as a new original would keep the saved evidence accurate and retain the converter pipeline.

const pendingPrompt = lastMessage?.role === 'user' ? draftMessageToInput(lastMessage) : undefined
const history = pendingPrompt ? editDraft.messages.slice(0, -1) : editDraft.messages
void editor.save(destination, (response: AddMessageResponse) => {
return editor.save(destination, (response: AddMessageResponse) => {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] Please also synchronize the composer when the edited draft no longer ends in a user message. The composer stays mounted and hidden during editing, and the save callback only updates it inside if (pendingPrompt). I reproduced typing a prompt, entering the editor, deleting that user message, and choosing Save to new attack: the deleted text immediately reappears in the composer. Changing that pending message's role to system has the same stale-draft problem. A successful save should clear or replace the composer from the edited result, while Cancel should retain the original draft.

Comment on lines +24 to 25
if (!systemSetup && (!capabilities?.supports_editable_history || !capabilities.supports_multi_turn)) {
return 'This target does not support editable history.'

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] Please base this gate on replay support, not just native capability flags. supports_editable_history describes native support, while target.validate_history_replay() also accepts configured history adapters and provider restoration callbacks. I checked a real WebsocketTarget with conversation_restore_callback: the new backend replay preflight accepts user/assistant history, but its serialized capabilities still have supports_editable_history: false. This helper therefore disables repeats and branching and hides Undo for a target that can replay that history. Exposing the resolved replay capability from the backend would avoid duplicating a different capability policy in the UI.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: c7e3facd-c947-4d49-b77a-4077d471767e

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.

2 participants