Skip to content

feat: let people delete their messages and react to messages - #467

Merged
iamnbutler merged 2 commits into
mainfrom
message-actions
Oct 16, 2026
Merged

iamnbutler merged 2 commits into
mainfrom
message-actions

Conversation

@iamnbutler

Copy link
Copy Markdown
Contributor

Part of #25: deletion and reactions. Editing stays hidden and is left for later.

  • Delete: only a message's author can delete their own message. Everyone then sees "Message deleted". The original pi entry is never rewritten. A new ace.deletion entry carries a pi context edit that replaces the message with <author>: [deleted this message] in later model requests. Runs that already read it keep what they learned, and text already folded into a compaction summary stays there.
  • Reactions: anyone who can write to the chat can add or remove an emoji on a person's message or an agent's reply. They're stored in old Ace's flat { from, emoji } shape in a new ace.messages v1 conversation document. react takes an explicit remove, as old Ace's chat:react did, so repeating a request does nothing.
  • Protocol: new react and delete ops. Watches that pass actions: true receive deleted events and complete reactions snapshots. Older clients get neither, but replay still drops a deleted message's text. Authors are stamped by the gateway and peer hosts, and hosted channels run the same Channel.handle. Archived channels refuse both ops.
  • App: wires the existing Timeline toolbar (onReact, onCopy, onDelete, actions), MessageToolbar, and Reactions chips in conversation.tsx. Delete asks for confirmation in a Dialog, following the DeleteChannel pattern.
  • Storage: one new document kind and one new entry kind. No existing format changes, so no migration. Checked against a backup made by the previous build (see the October 16 entry in docs/data.md).

Smoke-tested on an isolated host (ace serve --loopback) with a channel restored from that backup:

  • through the gateway, a worker socket, and headless Chrome on the built app: add and remove reactions, chips, the delete dialog, the live tombstone
  • refusals: deleting someone else's message, reacting to a deleted message, bad emoji, unknown entry
  • replay for opted-in and older watches
  • a pi harness deriving the placeholder

Not tested: reactions on agent replies (no model was called), hosted channels, and peer hosts.

Built in Ace

Built with Claude Code outside Ace, in a session already running there; no Ace gap involved.

Only a message's author deletes it, leaving "Message deleted" for everyone. A pi context edit
replaces it for later model requests; runs that already read it keep what they learned. Anyone
in the channel can add or remove emoji reactions on people's messages and agents' replies,
using old Ace's flat { from, emoji } shape. Both are live on watches that opt in with `actions`.
Editing stays hidden for now.

Why: packages/channel/src/messages.ts#function remove | only a message's author deletes it, and deletion replaces it in later model context through a pi context edit, never by rewriting or removing entries
Why: packages/channel/src/messages.ts#function react | add and remove name the result rather than toggling, so repeated requests are no-ops; build the list before assigning it into the document, since later mutation is lost
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.

1 participant