|
|
|
@ -3,13 +3,13 @@
|
|
|
|
|
## Problem
|
|
|
|
|
|
|
|
|
|
Threading allows users to branch out a new conversation from the main timeline of a room
|
|
|
|
|
to each other. This is particularly useful in high traffic rooms where multiple
|
|
|
|
|
conversations can happen in parallel or when a single discussion might stretch
|
|
|
|
|
to each other. This is particularly useful in high traffic rooms where multiple
|
|
|
|
|
conversations can happen in parallel or when a single discussion might stretch
|
|
|
|
|
over a very long period of time.
|
|
|
|
|
|
|
|
|
|
The main goal of implementing threads is to facilitate conversations that are easier
|
|
|
|
|
The main goal of implementing threads is to facilitate conversations that are easier
|
|
|
|
|
to follow and smoother to read.
|
|
|
|
|
Threading is very clearly a core requirement for any modern messaging
|
|
|
|
|
Threading is very clearly a core requirement for any modern messaging
|
|
|
|
|
solution, and Matrix uptake is suffering due to the lack of progress.
|
|
|
|
|
|
|
|
|
|
## Proposal
|
|
|
|
@ -27,10 +27,10 @@ A new relation type (see [MSC2674](https://github.com/matrix-org/matrix-doc/pull
|
|
|
|
|
```
|
|
|
|
|
Where $thread_root is the event ID of the root message in the thread.
|
|
|
|
|
|
|
|
|
|
When a thread root is aggregated (as in MSC2675), it returns a summary of the thread:
|
|
|
|
|
the latest message, a list of participants and the total count of messages.
|
|
|
|
|
I.e. in places which include bundled relations (per
|
|
|
|
|
[MSC2675](https://github.com/matrix-org/matrix-doc/pull/2675)), the thread root
|
|
|
|
|
When a thread root is aggregated (as in MSC2675), it returns a summary of the thread:
|
|
|
|
|
the latest message, a list of participants and the total count of messages.
|
|
|
|
|
I.e. in places which include bundled relations (per
|
|
|
|
|
[MSC2675](https://github.com/matrix-org/matrix-doc/pull/2675)), the thread root
|
|
|
|
|
would include additional information in the `unsigned` field:
|
|
|
|
|
|
|
|
|
|
```jsonc
|
|
|
|
@ -51,7 +51,7 @@ would include additional information in the `unsigned` field:
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
* `latest_event`: The most recent event which relates to this event, with
|
|
|
|
|
* `latest_event`: The most recent event which relates to this event, with
|
|
|
|
|
`rel_type` of `m.thread`.
|
|
|
|
|
|
|
|
|
|
The latest event should be serialised in the same form as the event itself;
|
|
|
|
@ -60,7 +60,7 @@ would include additional information in the `unsigned` field:
|
|
|
|
|
* `current_user_participated`: A flag set to `true` if the current logged in user
|
|
|
|
|
has participated in the thread
|
|
|
|
|
|
|
|
|
|
#### Rich replies in a thread
|
|
|
|
|
#### Rich replies in a thread
|
|
|
|
|
|
|
|
|
|
Rich replies are still handled via the `m.in_reply_to` field of `m.relates_to`.
|
|
|
|
|
However clients should specify that this is not a thread fallback by setting
|
|
|
|
@ -89,9 +89,9 @@ in the room.
|
|
|
|
|
|
|
|
|
|
A thread will be displayed as a chain of replies on clients unaware of threads.
|
|
|
|
|
|
|
|
|
|
Thread-ready clients should always include an `m.in_reply_to` property when sending
|
|
|
|
|
Thread-ready clients should always include an `m.in_reply_to` property when sending
|
|
|
|
|
a threaded event. Unless the user is explicitly replying to another event (see "Rich replies in a thread", above),
|
|
|
|
|
the `m.in_reply_to` property should reference the latest message-like event in the
|
|
|
|
|
the `m.in_reply_to` property should reference the latest message-like event in the
|
|
|
|
|
thread, and clients should also specify that `m.in_reply_to`
|
|
|
|
|
is a fallback mechanism (rather than a genuine reply) by setting the `is_falling_back` property to `true`.
|
|
|
|
|
|
|
|
|
@ -110,13 +110,13 @@ is a fallback mechanism (rather than a genuine reply) by setting the `is_falling
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Historically replies have been limited to text messages due to the legacy fallback
|
|
|
|
|
prepended to `formatted_body`. This MSC is dependant on
|
|
|
|
|
[MSC3676](https://github.com/matrix-org/matrix-doc/pull/3676) which strips that
|
|
|
|
|
prepended to `formatted_body`. This MSC is dependant on
|
|
|
|
|
[MSC3676](https://github.com/matrix-org/matrix-doc/pull/3676) which strips that
|
|
|
|
|
requirement to unlock use of any event type in this context.
|
|
|
|
|
|
|
|
|
|
### Fetch all relations to a thread root
|
|
|
|
|
|
|
|
|
|
To fetch an entire thread, the `/relations` API can be used as defined in
|
|
|
|
|
To fetch an entire thread, the `/relations` API can be used as defined in
|
|
|
|
|
[MSC2675](https://github.com/matrix-org/matrix-doc/pull/2675)
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
@ -125,31 +125,31 @@ GET /_matrix/client/unstable/rooms/!room_id:domain/relations/$thread_root/m.thre
|
|
|
|
|
|
|
|
|
|
Where `$thread_root` is the event ID of the root message in the thread.
|
|
|
|
|
|
|
|
|
|
> Any API which receives events should bundle relations (apart from non-gappy
|
|
|
|
|
incremental syncs), for instance: initial sync, gappy incremental sync,
|
|
|
|
|
> Any API which receives events should bundle relations (apart from non-gappy
|
|
|
|
|
incremental syncs), for instance: initial sync, gappy incremental sync,
|
|
|
|
|
/messages and /context.
|
|
|
|
|
|
|
|
|
|
### Fetch all threads in a room
|
|
|
|
|
|
|
|
|
|
[Event filters](https://spec.matrix.org/v1.2/client-server-api/#filtering) (as
|
|
|
|
|
used by endpoints including `/messages`, `/sync` and `/context`) are extended
|
|
|
|
|
[Event filters](https://spec.matrix.org/v1.2/client-server-api/#filtering) (as
|
|
|
|
|
used by endpoints including `/messages`, `/sync` and `/context`) are extended
|
|
|
|
|
with new options to allow filtering events by their relating events:
|
|
|
|
|
|
|
|
|
|
* `related_by_rel_types`: A list of relation types to include. An event `A` is included
|
|
|
|
|
in the filter only if there exists another event `B` which relates to `A` with a
|
|
|
|
|
* `related_by_rel_types`: A list of relation types to include. An event `A` is included
|
|
|
|
|
in the filter only if there exists another event `B` which relates to `A` with a
|
|
|
|
|
`rel_type` which is defined in the list
|
|
|
|
|
* `related_by_senders`: A list of senders to include. An event `A` is included in
|
|
|
|
|
* `related_by_senders`: A list of senders to include. An event `A` is included in
|
|
|
|
|
the filter only if there exists another event `B` which relates to `A`, and
|
|
|
|
|
which has a `sender` which is in the list.
|
|
|
|
|
|
|
|
|
|
This can also be combined with the `sender` field to search for threads which a
|
|
|
|
|
This can also be combined with the `sender` field to search for threads which a
|
|
|
|
|
user has participated in (or not participated in).
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
GET /_matrix/client/v3/rooms/!room_id:domain/messages?filter=...
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
The filter string includes the new fields, above. In this example, the URL
|
|
|
|
|
The filter string includes the new fields, above. In this example, the URL
|
|
|
|
|
encoded JSON is presented unencoded and formatted for legibility:
|
|
|
|
|
|
|
|
|
|
```jsonc
|
|
|
|
@ -176,7 +176,7 @@ as it has another event which relates to it sent by `bob`.
|
|
|
|
|
|
|
|
|
|
### Server capabilities
|
|
|
|
|
|
|
|
|
|
Threads might have sporadic support across servers, to simplify feature
|
|
|
|
|
Threads might have sporadic support across servers, to simplify feature
|
|
|
|
|
detections for clients, a homeserver must advertise unstable support for threads
|
|
|
|
|
as part of the `/versions` API:
|
|
|
|
|
|
|
|
|
@ -193,11 +193,11 @@ as part of the `/versions` API:
|
|
|
|
|
|
|
|
|
|
#### Read receipts
|
|
|
|
|
|
|
|
|
|
Read receipts and read markers assume a single chronological timeline. Threading
|
|
|
|
|
Read receipts and read markers assume a single chronological timeline. Threading
|
|
|
|
|
changes that assumption making the current API not very practical.
|
|
|
|
|
|
|
|
|
|
Clients can synthesize read receipts but it is possible that some notifications get
|
|
|
|
|
lost on a fresh start where the clients have to start off the `m.read`
|
|
|
|
|
Clients can synthesize read receipts but it is possible that some notifications get
|
|
|
|
|
lost on a fresh start where the clients have to start off the `m.read`
|
|
|
|
|
information received from the homeserver.
|
|
|
|
|
|
|
|
|
|
Synchronising the synthesized notification count across devices is out of scope and deferred to a later MSC.
|
|
|
|
@ -244,7 +244,7 @@ Given the above list of events, only `ev1` would be a valid target for an `m.thr
|
|
|
|
|
relation event.
|
|
|
|
|
|
|
|
|
|
Servers should reject attempts to send events with invalid thread relations via the
|
|
|
|
|
Client-Server API with an HTTP `400` status code and a
|
|
|
|
|
Client-Server API with an HTTP `400` status code and a
|
|
|
|
|
`M_UNKNOWN` error code.
|
|
|
|
|
Events received over federation should always be accepted without checking
|
|
|
|
|
the validity of the relations as it would break the extensibility of this proposal
|
|
|
|
@ -256,8 +256,8 @@ receives such events, it should hide them as soon as it can determine for certai
|
|
|
|
|
that the associated event is not a valid target.
|
|
|
|
|
|
|
|
|
|
Servers are expected to not filter out invalid `m.thread` relations from the results when
|
|
|
|
|
serving endpoints that deal with message relations. Clients that call those
|
|
|
|
|
endpoints should be aware that they may return events with invalid relations,
|
|
|
|
|
serving endpoints that deal with message relations. Clients that call those
|
|
|
|
|
endpoints should be aware that they may return events with invalid relations,
|
|
|
|
|
and deal with them appropriately.
|
|
|
|
|
|
|
|
|
|
### Client considerations
|
|
|
|
@ -271,7 +271,7 @@ continuity of conversation in the ecosystem.
|
|
|
|
|
|
|
|
|
|
Clients that do not offer a threading UI should behave as follows when replying, for
|
|
|
|
|
best interaction with those that do.
|
|
|
|
|
They should set the `m.in_reply_to` part as usual, and then add on
|
|
|
|
|
They should set the `m.in_reply_to` part as usual, and then add on
|
|
|
|
|
`"rel_type": "m.thread"` and `"event_id": "$thread_root"`, copying `$thread_root`
|
|
|
|
|
from the replied-to event.
|
|
|
|
|
|
|
|
|
@ -281,7 +281,7 @@ separate area for displaying threads, clients can render the event in the main
|
|
|
|
|
room timeline as a rich reply that will open and highlight the event in the
|
|
|
|
|
thread context when clicked.
|
|
|
|
|
|
|
|
|
|
When replying to the following event, a client that does not support threads should
|
|
|
|
|
When replying to the following event, a client that does not support threads should
|
|
|
|
|
copy in `rel_type` and `event_id` properties in their reply mixin.
|
|
|
|
|
|
|
|
|
|
```jsonc
|
|
|
|
@ -302,13 +302,13 @@ copy in `rel_type` and `event_id` properties in their reply mixin.
|
|
|
|
|
|
|
|
|
|
"Threading as rooms", building on `m.in_reply_to`, and [MSC2836](https://github.com/matrix-org/matrix-doc/pull/2836) are the main alternatives here.
|
|
|
|
|
|
|
|
|
|
It is also worth noting that relations in this MSC could be expressed using the
|
|
|
|
|
It is also worth noting that relations in this MSC could be expressed using the
|
|
|
|
|
scalable relation format described in [MSC3051](https://github.com/matrix-org/matrix-doc/pull/3051).
|
|
|
|
|
|
|
|
|
|
### Threads as rooms
|
|
|
|
|
|
|
|
|
|
Threads as rooms could provide full server-side APIs for navigating trees of events,
|
|
|
|
|
and could be considered an extension of this MSC for scenarios which require that
|
|
|
|
|
Threads as rooms could provide full server-side APIs for navigating trees of events,
|
|
|
|
|
and could be considered an extension of this MSC for scenarios which require that
|
|
|
|
|
capability
|
|
|
|
|
|
|
|
|
|
"Threads as rooms" is the idea that each thread could just get its own Matrix room.
|
|
|
|
@ -319,27 +319,27 @@ Advantages to "Threads as rooms" include:
|
|
|
|
|
* Ability to create read-only threads
|
|
|
|
|
|
|
|
|
|
Disadvantages include:
|
|
|
|
|
* Access control, membership, history visibility, room versions etc needs to be
|
|
|
|
|
* Access control, membership, history visibility, room versions etc needs to be
|
|
|
|
|
synced between the thread-room and the parent room
|
|
|
|
|
* Harder to control lifetime of threads in the context of the parent room if
|
|
|
|
|
* Harder to control lifetime of threads in the context of the parent room if
|
|
|
|
|
they're completely split off
|
|
|
|
|
* Clients which aren't aware of them are going to fill up with a lot of rooms.
|
|
|
|
|
* Bridging to non-threaded chat systems is trickier as you may have to splice
|
|
|
|
|
* Bridging to non-threaded chat systems is trickier as you may have to splice
|
|
|
|
|
together rooms
|
|
|
|
|
|
|
|
|
|
### Threads via m.in_reply_to
|
|
|
|
|
|
|
|
|
|
The rationale for using a new relation type instead of building on `m.in_reply_to`
|
|
|
|
|
is to re-use the event relationship APIs provided by
|
|
|
|
|
[MSC2675](https://github.com/matrix-org/matrix-doc/pull/2675). The MSC3267 definition
|
|
|
|
|
of `m.reference` relationships could be updated to mention threads (perhaps by
|
|
|
|
|
using the key field from [MSC2677](https://github.com/matrix-org/matrix-doc/pull/2677)
|
|
|
|
|
as the thread ID), but it is clearer to define a new relation type. It is unclear
|
|
|
|
|
what impact this would have on [MSC3267](https://github.com/matrix-org/matrix-doc/pull/3267),
|
|
|
|
|
The rationale for using a new relation type instead of building on `m.in_reply_to`
|
|
|
|
|
is to re-use the event relationship APIs provided by
|
|
|
|
|
[MSC2675](https://github.com/matrix-org/matrix-doc/pull/2675). The MSC3267 definition
|
|
|
|
|
of `m.reference` relationships could be updated to mention threads (perhaps by
|
|
|
|
|
using the key field from [MSC2677](https://github.com/matrix-org/matrix-doc/pull/2677)
|
|
|
|
|
as the thread ID), but it is clearer to define a new relation type. It is unclear
|
|
|
|
|
what impact this would have on [MSC3267](https://github.com/matrix-org/matrix-doc/pull/3267),
|
|
|
|
|
but that is unimplemented by clients.
|
|
|
|
|
|
|
|
|
|
A big advantage of relations over rich replies is that they can be server-side
|
|
|
|
|
aggregated. It means that a client is not bound to download the entire history of
|
|
|
|
|
A big advantage of relations over rich replies is that they can be server-side
|
|
|
|
|
aggregated. It means that a client is not bound to download the entire history of
|
|
|
|
|
a room to have a comprehensive list of events being part of a thread.
|
|
|
|
|
|
|
|
|
|
### Threads via serverside traversal of relationships MSC2836
|
|
|
|
@ -349,12 +349,12 @@ Advantages include:
|
|
|
|
|
* Simple possible API shape to implement threading in a useful way
|
|
|
|
|
|
|
|
|
|
Disadvantages include:
|
|
|
|
|
* Relationships are queried using `/event_relationships` which is outside the
|
|
|
|
|
bounds of the `/sync` API so lacks the nice things /sync gives you (live updates).
|
|
|
|
|
That being said, the event will come down `/sync`, you just may not have the
|
|
|
|
|
* Relationships are queried using `/event_relationships` which is outside the
|
|
|
|
|
bounds of the `/sync` API so lacks the nice things /sync gives you (live updates).
|
|
|
|
|
That being said, the event will come down `/sync`, you just may not have the
|
|
|
|
|
context required to see parents/siblings/children.
|
|
|
|
|
* Threads can be of arbitrary width (unlimited direct replies to a single message)
|
|
|
|
|
and depth (unlimited chain of replies) which complicates UI design when you just
|
|
|
|
|
* Threads can be of arbitrary width (unlimited direct replies to a single message)
|
|
|
|
|
and depth (unlimited chain of replies) which complicates UI design when you just
|
|
|
|
|
want "simple" threading.
|
|
|
|
|
* Does not consider use cases like editing or reactions
|
|
|
|
|
|
|
|
|
@ -364,14 +364,14 @@ None
|
|
|
|
|
|
|
|
|
|
## Unstable prefix
|
|
|
|
|
|
|
|
|
|
Clients and servers should use list of unstable prefixes listed below while this
|
|
|
|
|
Clients and servers should use list of unstable prefixes listed below while this
|
|
|
|
|
MSC has not been included in a spec release.
|
|
|
|
|
|
|
|
|
|
* `io.element.thread` should be used in place of `m.thread` as relation type
|
|
|
|
|
* `io.element.thread` should be used in place of `m.thread` as a capability entry
|
|
|
|
|
* `io.element.relation_senders` should be used in place of `related_by_senders`
|
|
|
|
|
* `io.element.relation_senders` should be used in place of `related_by_senders`
|
|
|
|
|
in the `RoomEventFilter`
|
|
|
|
|
* `io.element.relation_types` should be used in place of `related_by_rel_types`
|
|
|
|
|
* `io.element.relation_types` should be used in place of `related_by_rel_types`
|
|
|
|
|
in the `RoomEventFilter`
|
|
|
|
|
* `io.element.show_reply` should be used in place of `is_falling_back`
|
|
|
|
|
|
|
|
|
@ -384,10 +384,10 @@ was decided to move it to a later release.
|
|
|
|
|
|
|
|
|
|
## Dependencies
|
|
|
|
|
|
|
|
|
|
This MSC builds on [MSC2674](https://github.com/matrix-org/matrix-doc/pull/2674),
|
|
|
|
|
[MSC2675](https://github.com/matrix-org/matrix-doc/pull/2675),
|
|
|
|
|
This MSC builds on [MSC2674](https://github.com/matrix-org/matrix-doc/pull/2674),
|
|
|
|
|
[MSC2675](https://github.com/matrix-org/matrix-doc/pull/2675),
|
|
|
|
|
[MSC3567](https://github.com/matrix-org/matrix-doc/pull/3567) and,
|
|
|
|
|
[MSC3676](https://github.com/matrix-org/matrix-doc/pull/3676) (which at the
|
|
|
|
|
[MSC3676](https://github.com/matrix-org/matrix-doc/pull/3676) (which at the
|
|
|
|
|
time of writing have not yet been accepted into the spec).
|
|
|
|
|
|
|
|
|
|
[^1]: It might seem like this could cause a loop where each latest event then
|
|
|
|
|