From fa5266dfd446292ec7ed84b9dad6755860007024 Mon Sep 17 00:00:00 2001 From: abc-nix Date: Sun, 9 Aug 2026 11:04:41 +0200 Subject: [PATCH 1/7] fix(webui): handle multimodal content in message edit box --- channels/webui/assets/js/stores/chat.js | 52 ++++++++++++++++++++++++- 1 file changed, 50 insertions(+), 2 deletions(-) diff --git a/channels/webui/assets/js/stores/chat.js b/channels/webui/assets/js/stores/chat.js index ac83129a..efa6e6c8 100644 --- a/channels/webui/assets/js/stores/chat.js +++ b/channels/webui/assets/js/stores/chat.js @@ -266,20 +266,68 @@ CHAT_STORE = { if (!msg) { return; } this.editingMessageIndex = msg.index; - this.editContent = msg.content; + this.editContent = this._extractEditText(msg); Alpine.store('ui').scrollToTurnIndex = turnIndex; }, + /* + * messages with attached files store their content as an array of blocks + * (text + image_url/input_audio/text blocks for files). + * only the first block is the user's own editable text + * (it is the only one with an empty entry in _metadata.filenames). + */ + _extractEditText(msg) { + if (Array.isArray(msg.content)) { + const filenames = msg._metadata?.filenames; + const isUserTextFirst = Array.isArray(filenames) && filenames[0] === ''; + if (isUserTextFirst) { + const textBlock = msg.content.find(block => block.type === 'text'); + return textBlock?.text ?? ''; + } + // no user text (pure file upload) - nothing editable + return ''; + } + return msg.content; + }, + async cancelEdit() { this.editingMessageIndex = null; this.editContent = ''; }, async saveEdit(index) { + // find the original message so we can preserve any attached files + let origMessage = null; + for (const turn of this.turnHistory) { + const found = (turn.messages || []).find(m => m.index === index); + if (found) { origMessage = found; break; } + } + + let content = this.editContent; + + if (origMessage && Array.isArray(origMessage.content)) { + // keep the file blocks, only replace the first text block (the actual message) + let replacedText = false; + const blocks = origMessage.content.map(block => { + if (block.type === 'text' && !replacedText) { + replacedText = true; + return { ...block, text: content }; + } + return block; + }); + + // if the message had no text block but the user typed something, add one + if (!replacedText && content) { + blocks.unshift({ type: 'text', text: content }); + } + + content = blocks; + } + await simpleSocketSend({ "type": "message_edit", "index": index, - "content": this.editContent + "content": content }); this.editingMessageIndex = null; From 17de62ed71cc6e80eb9ac0e72287e2c1ec967a96 Mon Sep 17 00:00:00 2001 From: abc-nix Date: Sun, 9 Aug 2026 11:05:46 +0200 Subject: [PATCH 2/7] fix(webui): expand edit box to full bubble width --- channels/webui/assets/css/chat/message_bubble.css | 7 +++++++ channels/webui/templates/chat/index.html | 4 ++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/channels/webui/assets/css/chat/message_bubble.css b/channels/webui/assets/css/chat/message_bubble.css index 56db60eb..eb022387 100644 --- a/channels/webui/assets/css/chat/message_bubble.css +++ b/channels/webui/assets/css/chat/message_bubble.css @@ -15,6 +15,13 @@ position: relative; max-width: var(--message-max-width, 75%); width: fit-content; + + /* when a message is being edited, expand the bubble to its max width + so the edit box doesn't collapse to the textarea's intrinsic size */ + &.editing-active { + width: 100%; + } + backdrop-filter: blur(10px); .command { diff --git a/channels/webui/templates/chat/index.html b/channels/webui/templates/chat/index.html index 2772828b..0b0fd38d 100644 --- a/channels/webui/templates/chat/index.html +++ b/channels/webui/templates/chat/index.html @@ -42,7 +42,7 @@