Skip to content

Add per-message export feature for Markdown and Word formats#783

Open
eldong wants to merge 17 commits intoDevelopmentfrom
export-message
Open

Add per-message export feature for Markdown and Word formats#783
eldong wants to merge 17 commits intoDevelopmentfrom
export-message

Conversation

@eldong
Copy link
Collaborator

@eldong eldong commented Mar 9, 2026

  • Implemented export options in the dropdown menu for individual chat messages.
  • Added backend endpoint for exporting messages as Word documents.
  • Created client-side functions for exporting messages to Markdown and Word.
  • Updated release notes and documentation to reflect new features.

- Implemented export options in the dropdown menu for individual chat messages.
- Added backend endpoint for exporting messages as Word documents.
- Created client-side functions for exporting messages to Markdown and Word.
- Updated release notes and documentation to reflect new features.
Copilot AI review requested due to automatic review settings March 9, 2026 23:22
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds per-message actions to the chat message “three dots” menu, enabling single-message export to Markdown (client-side) and Word (via a new backend endpoint), plus quick “Use as Prompt” and “Open in Email” actions.

Changes:

  • Adds new per-message dropdown actions for both AI and user messages in the chat UI.
  • Introduces POST /api/message/export-word to generate a .docx export for a single message.
  • Adds feature documentation and release note entry; bumps app version to 0.239.007.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
docs/explanation/release_notes.md Adds release note entry for per-message export feature in v0.239.007.
docs/explanation/features/MESSAGE_EXPORT.md New feature documentation describing per-message export options and architecture.
application/single_app/static/js/chat/chat-messages.js Adds dropdown items + click handlers (dynamic import) for new per-message actions.
application/single_app/static/js/chat/chat-message-export.js New client-side module implementing Markdown export, Word export call, prompt insertion, and mailto.
application/single_app/route_backend_conversation_export.py Adds /api/message/export-word endpoint and basic Markdown→DOCX formatting helpers.
application/single_app/config.py Bumps VERSION to 0.239.007.

You can also share your feedback on Copilot code review. Take the survey.

Comment on lines +403 to +405
except Exception as e:
debug_print(f"Message export error: {str(e)}")
return jsonify({'error': f'Export failed: {str(e)}'}), 500
Copy link

Copilot AI Mar 9, 2026

Choose a reason for hiding this comment

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

The error response includes the raw exception string (Export failed: {str(e)}), which can leak internal details to the client. Consider logging the exception server-side and returning a generic message (optionally with a correlation id) to the caller.

Copilot uses AI. Check for mistakes.
## Overview
The Per-Message Export feature adds export and action options directly to the three-dots dropdown menu on individual chat messages. Users can export a single message to Markdown or Word, insert it into the chat prompt, or open it in their default email client — all without leaving the chat interface.

**Version Implemented:** 0.239.005–0.239.007
Copy link

Copilot AI Mar 9, 2026

Choose a reason for hiding this comment

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

The version metadata here is a range (0.239.005–0.239.007), but the feature is being released as part of v0.239.007 (and config.py was bumped to that). To keep docs unambiguous, please switch this to a single implemented version (e.g., 0.239.007) and align it with the release notes entry.

Suggested change
**Version Implemented:** 0.239.005–0.239.007
**Version Implemented:** 0.239.007

Copilot uses AI. Check for mistakes.
(Pt, RGBColor, WD_ALIGN_PARAGRAPH, and _re) are not sued so removed them

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings March 10, 2026 13:22
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 6 comments.


You can also share your feedback on Copilot code review. Take the survey.

Comment on lines +400 to +402
except Exception as e:
debug_print(f"Message export error: {str(e)}")
return jsonify({'error': f'Export failed: {str(e)}'}), 500
Copy link

Copilot AI Mar 10, 2026

Choose a reason for hiding this comment

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

The 500 error response includes the raw exception text (Export failed: {str(e)}), which can leak internal details to the browser. Log the exception server-side and return a generic error message to the client instead.

Copilot uses AI. Check for mistakes.
Comment on lines +294 to +299
@app.route('/api/message/export-word', methods=['POST'])
@swagger_route(security=get_auth_security())
@login_required
@user_required
def api_export_message_word():
"""
Copy link

Copilot AI Mar 10, 2026

Choose a reason for hiding this comment

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

This PR adds a new user-facing export endpoint (/api/message/export-word) and Markdown-to-DOCX conversion logic, but there’s no corresponding functional test alongside the existing functional_tests/test_conversation_export.py coverage. Please add a functional test (e.g., functional_tests/test_message_export.py) that validates permission checks (403), not-found cases (404), and successful .docx generation for a simple message.

Copilot generated this review using guidance from repository custom instructions.
Comment on lines +6 to +7
**Version Implemented:** 0.239.005–0.239.007

Copy link

Copilot AI Mar 10, 2026

Choose a reason for hiding this comment

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

For consistency with other feature docs (and the version bump/release note entry in this PR), the feature should list a single implemented version. Consider changing 0.239.005–0.239.007 to 0.239.007 so it’s clear which release introduced the feature.

Copilot uses AI. Check for mistakes.
Comment on lines +40 to +42
- **Icon:** `bi-markdown`
- **Behavior:** Entirely client-side. Grabs the message content from the existing hidden textarea (AI messages) or `.message-text` element (user messages), wraps it with a role/timestamp header, and triggers a `.md` file download via Blob URL.
- **Filename pattern:** `message_export_YYYYMMDD_HHMMSS.md`
Copy link

Copilot AI Mar 10, 2026

Choose a reason for hiding this comment

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

The doc says Markdown export includes a role/timestamp header, but the current frontend implementation doesn’t have access to a rendered timestamp (no .message-timestamp in message DOM), so the timestamp will be blank. Either adjust the implementation to reliably include timestamps or update this doc to reflect actual behavior.

Copilot uses AI. Check for mistakes.
Copy link
Contributor

Copilot AI commented Mar 10, 2026

@eldong I've opened a new pull request, #784, to work on those changes. Once the pull request is ready, I'll request review from you.

Copilot AI and others added 3 commits March 10, 2026 14:45
Co-authored-by: eldong <11573590+eldong@users.noreply.github.com>
Move `python-docx` import to top-level in route_backend_conversation_export.py
Copy link
Contributor

Copilot AI commented Mar 10, 2026

@eldong I've opened a new pull request, #785, to work on those changes. Once the pull request is ready, I'll request review from you.

Copy link
Contributor

Copilot AI commented Mar 10, 2026

@eldong I've opened a new pull request, #786, to work on those changes. Once the pull request is ready, I'll request review from you.

Copilot AI and others added 2 commits March 10, 2026 14:50
Co-authored-by: eldong <11573590+eldong@users.noreply.github.com>
Fix misleading JSDoc comment on `copyAsPrompt()` to match actual behavior
Copilot AI review requested due to automatic review settings March 10, 2026 14:52
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 3 comments.


You can also share your feedback on Copilot code review. Take the survey.

Comment on lines +16 to +30
function getMessageMarkdown(messageDiv, role) {
if (role === 'assistant') {
// AI messages have a hidden textarea with the markdown content
const hiddenTextarea = messageDiv.querySelector('textarea[id^="copy-md-"]');
if (hiddenTextarea) {
return hiddenTextarea.value;
}
}
// For user messages (or fallback), grab the text from the message bubble
const messageText = messageDiv.querySelector('.message-text');
if (messageText) {
return messageText.innerText;
}
return '';
}
Copy link

Copilot AI Mar 10, 2026

Choose a reason for hiding this comment

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

This new module uses 4-space indentation, but the surrounding JS code in this repo (e.g., chat-toast.js and chat-messages.js) consistently uses 2 spaces. For consistency/readability, please reformat this file to match the existing indentation style used in the static/js codebase.

Copilot uses AI. Check for mistakes.
Comment on lines +5 to +16
### **(v0.239.007)**

#### New Features

* **Per-Message Export**
* Added export and action options to the three-dots dropdown menu on individual chat messages (both AI and user messages).
* **Export to Markdown**: Downloads the message as a `.md` file with role/timestamp header. Entirely client-side.
* **Export to Word**: Generates a styled `.docx` document via a new backend endpoint (`POST /api/message/export-word`). Includes Markdown-to-Word formatting (headings, bold, italic, code blocks, lists) and a citations section when present.
* **Use as Prompt**: Inserts the raw message content directly into the chat input box for reuse — no clipboard, one click and it's ready to edit and send.
* **Open in Email**: Opens the user's default email client with the message pre-filled in the subject and body via `mailto:`.
* New options appear below a divider in the dropdown, preserving existing actions (Delete, Retry, Edit, Feedback).
* (Ref: `chat-message-export.js`, `chat-messages.js`, `route_backend_conversation_export.py`, per-message export)
Copy link

Copilot AI Mar 10, 2026

Choose a reason for hiding this comment

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

Release notes entry is under v0.239.007, but this PR bumps config VERSION to 0.239.009. Please align the release notes section header to the version being released (and keep version numbers consistent across config + release notes).

Copilot uses AI. Check for mistakes.
EXECUTOR_MAX_WORKERS = 30
SESSION_TYPE = 'filesystem'
VERSION = "0.239.005"
VERSION = "0.239.009"
Copy link

Copilot AI Mar 10, 2026

Choose a reason for hiding this comment

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

VERSION was bumped from 0.239.005 to 0.239.009 in a single PR. Repo versioning guidance is to increment only the patch (third) component by 1 per change; please adjust the version accordingly and ensure it matches the release notes section header.

Suggested change
VERSION = "0.239.009"
VERSION = "0.239.006"

Copilot uses AI. Check for mistakes.
Copilot AI and others added 3 commits March 10, 2026 14:58
…ownership failures)

Co-authored-by: eldong <11573590+eldong@users.noreply.github.com>
[WIP] Add functional test script for export feature
Copy link
Contributor

Copilot AI commented Mar 10, 2026

@eldong I've opened a new pull request, #787, to work on those changes. Once the pull request is ready, I'll request review from you.

Copilot AI and others added 2 commits March 10, 2026 15:09
Co-authored-by: eldong <11573590+eldong@users.noreply.github.com>
Remove false timestamp claims from per-message export feature
Copilot AI review requested due to automatic review settings March 10, 2026 15:11
Copy link
Contributor

Copilot AI commented Mar 10, 2026

@eldong I've opened a new pull request, #788, to work on those changes. Once the pull request is ready, I'll request review from you.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated 5 comments.


You can also share your feedback on Copilot code review. Take the survey.

Comment on lines +71 to +80
def _build_markdown_export(role, content, sender, timestamp):
"""Replicate the client-side Markdown export logic from chat-message-export.js."""
lines = []
lines.append(f"### {sender}")
if timestamp:
lines.append(f"*{timestamp}*")
lines.append('')
lines.append(content)
lines.append('')
return '\n'.join(lines)
Copy link

Copilot AI Mar 10, 2026

Choose a reason for hiding this comment

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

The Markdown export helper/test currently expects a timestamp line (and test_happy_path_markdown_export asserts it), but the actual client implementation in chat-message-export.js does not include timestamps in Markdown exports (only a role header + content). This makes the functional test incorrect; either update the test/helper to match the shipped behavior, or add timestamp support in the client export and update docs/release notes accordingly.

Copilot uses AI. Check for mistakes.
## Cross-References
- Related feature: [Conversation Export](CONVERSATION_EXPORT.md) — exports entire conversations
- Backend shares infrastructure with conversation export (`route_backend_conversation_export.py`)
- Functional tests: `functional_tests/test_message_export.py` (when created)
Copy link

Copilot AI Mar 10, 2026

Choose a reason for hiding this comment

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

The cross-reference to functional_tests/test_message_export.py appears to be stale—this PR adds functional_tests/test_per_message_export.py. Update this link so readers can find the actual functional test script.

Suggested change
- Functional tests: `functional_tests/test_message_export.py` (when created)
- Functional tests: `functional_tests/test_per_message_export.py`

Copilot uses AI. Check for mistakes.
Comment on lines +5 to +16
### **(v0.239.007)**

#### New Features

* **Per-Message Export**
* Added export and action options to the three-dots dropdown menu on individual chat messages (both AI and user messages).
* **Export to Markdown**: Downloads the message as a `.md` file with a role header. Entirely client-side.
* **Export to Word**: Generates a styled `.docx` document via a new backend endpoint (`POST /api/message/export-word`). Includes Markdown-to-Word formatting (headings, bold, italic, code blocks, lists) and a citations section when present.
* **Use as Prompt**: Inserts the raw message content directly into the chat input box for reuse — no clipboard, one click and it's ready to edit and send.
* **Open in Email**: Opens the user's default email client with the message pre-filled in the subject and body via `mailto:`.
* New options appear below a divider in the dropdown, preserving existing actions (Delete, Retry, Edit, Feedback).
* (Ref: `chat-message-export.js`, `chat-messages.js`, `route_backend_conversation_export.py`, per-message export)
Copy link

Copilot AI Mar 10, 2026

Choose a reason for hiding this comment

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

Release notes add Per-Message Export under v0.239.007, but this PR also bumps VERSION in config.py to 0.239.010. Please align the release notes section with the actual version being released (either adjust the version bump, or move/add the entry under the correct version heading).

Copilot uses AI. Check for mistakes.
Comment on lines +399 to +401
except Exception as e:
debug_print(f"Message export error: {str(e)}")
return jsonify({'error': f'Export failed: {str(e)}'}), 500
Copy link

Copilot AI Mar 10, 2026

Choose a reason for hiding this comment

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

The 500 handler returns the raw exception string to the client (Export failed: {str(e)}), which can leak internal details (Cosmos errors, stack context, etc.). Consider logging the exception server-side and returning a generic error message to the browser while keeping the status code 500.

Copilot uses AI. Check for mistakes.
Comment on lines +6 to +7
Version: 0.239.008
Implemented in: 0.239.008
Copy link

Copilot AI Mar 10, 2026

Choose a reason for hiding this comment

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

Functional test header versions are out of sync with the current app version in application/single_app/config.py (currently 0.239.010). Per the repo’s functional test versioning convention, update the Version: field to the current config version and set Implemented in: to the version where this feature is introduced in this PR.

Copilot generated this review using guidance from repository custom instructions.
docs: remove overstated timestamp claim from per-message Markdown export release note
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.

4 participants