Skip to content

ADFA-6247 | Export and import chats as .txt - #110

Merged
jatezzz merged 6 commits into
mainfrom
feat/ADFA-6247-export-import-chats-txt
Sep 29, 2026
Merged

jatezzz merged 6 commits into
mainfrom
feat/ADFA-6247-export-import-chats-txt

Conversation

@jatezzz

@jatezzz jatezzz commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor

Description

Implemented the ability to export and import Agent conversations as plain .txt files. This ensures users can back up important chats, share them with teammates, or continue conversations across different devices. To support the UI requirements, the standard options menu was replaced with a custom Material 3 menu.

Details

  • Added an Export option to the chat row options menu (⋮), saving transcripts locally via the system file picker.
  • Replaced the "New chat" button with a + menu that contains both New chat and Import chat.
  • Created the ChatTranscript model to handle strict parsing, ensuring imported chats accurately retain senders, timestamps, and order while assigning fresh IDs to prevent overwriting existing chats.
  • Updated ChatFragment with ActivityResultContracts to handle system file picker intents for creating and opening documents.
Screen_Recording_20260925_151127_Code.on.the.Go.mp4

Ticket

ADFA-6247

Observation

The standard PopupMenu was replaced with a custom SidebarPopupMenu because the host's tooltip relies on a PopupWindow. Anchoring a tooltip inside a standard popup menu throws a BadTokenException that crashes the IDE. The custom menu safely handles long-press tooltips and supports displaying disabled state explanations, such as when attempting to export an empty chat.

Chat row menu: Rename, Export, Delete; Export saves via the system file picker and is dimmed for an empty chat.
The + menu adds Import chat, which opens an exported file as a new chat.
Transcript I/O runs in ChatViewModel off the main thread; menus are a shared Material 3 popup that TalkBack can read.
@jatezzz
jatezzz requested review from a team, Daniel-ADFA and itsaky-adfa September 25, 2026 20:39

@alome007 alome007 left a comment

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.

IMPORTANT

  • ChatTranscript.kt:180 - historyText not exported, so an imported chat feeds the model its bubble text

MINOR

  • ChatTranscript.kt:147 - trimEnd loses a message's own trailing newlines

Reviewed at medium effort. Each finding was re-checked against 49d64cd. This repo has no written approve/request-changes rule, so the default applied. Checked and clean: header-lookalike escaping (leading backslashes, trailing whitespace), timestamp round trip, preamble keys (a name containing :), ActivityNotFoundException handling, the pending-export id across process death, the snackbar after view destroy, cancellation during export, popup dismissal with the sidebar, and tooltip anchoring on the menu button.

@Daniel-ADFA Daniel-ADFA left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

IMPORTANT

  • ChatTranscript.kt:180 - historyText not exported, so an imported chat feeds the model its bubble text

MINOR

  • ChatTranscript.kt:147 - trimEnd loses a message's own trailing newlines

Reviewed at medium effort. Each finding was re-checked against 49d64cd. This repo has no written approve/request-changes rule, so the default applied. Checked and clean: header-lookalike escaping (leading backslashes, trailing whitespace), timestamp round trip, preamble keys (a name containing :), ActivityNotFoundException handling, the pending-export id across process death, the snackbar after view destroy, cancellation during export, popup dismissal with the sidebar, and tooltip anchoring on the menu button.

…pts (ADFA-6247)

Export the model's own words under a `--- MODEL WROTE` marker when they differ from the bubble, so an imported chat doesn't hand the model its rendered text as its earlier turn. On import, drop only the one blank separator line instead of every trailing newline.
@jatezzz
jatezzz requested a review from Daniel-ADFA September 28, 2026 15:22

@Daniel-ADFA Daniel-ADFA left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Round 2, verified against 3a5361e.

MINOR

  • viewmodel/ChatViewModel.kt:1679 - import buffers up to 20 MB of any text/* file before the header check (plausible, not reproduced)

Re-check of round 1

  • historyText dropped: fixed. Written after a --- MODEL WROTE line and read back into message(). Body lines that look like the marker or a header are escaped (isStructural), including lines with leading backslashes.
  • trimEnd losing trailing newlines: fixed. Parse drops exactly one trailing empty line, so "foo\n\n", "\n\n" and "" round-trip, including as the last message.

Only a plausible MINOR remains, which does not block by itself. The round-1 CHANGES_REQUESTED review is still on the PR.

@jatezzz
jatezzz requested a review from Daniel-ADFA September 28, 2026 16:59

@Daniel-ADFA Daniel-ADFA left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Round 3, verified against 271ea29. Approving: what remains is MINOR.

MINOR

  • models/ChatTranscript.kt:41 - export can write a chat the 4 MB import limit then refuses

Re-check of round 2

  • Import buffered 20 MB before the header check: fixed. read() runs opensWithMagic as the stream arrives and throws InvalidTranscriptException once the first non-blank line is not MAGIC, or after MAX_MAGIC_SEARCH_BYTES with no complete line. It finds that line the way parse does (BOM removed, same whitespace rule), and it re-decodes the whole prefix, so a line or BOM split across reads is handled.

@jatezzz
jatezzz merged commit 5bac6ee into main Sep 29, 2026
1 check passed
@jatezzz
jatezzz deleted the feat/ADFA-6247-export-import-chats-txt branch September 29, 2026 13:13
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.

3 participants