Skip to content

fix(matrix): keep a user's leading quote in an explicit reply - #128621

Draft
iainlane wants to merge 5 commits into
NousResearch:mainfrom
iainlane:fix/matrix-reply-own-quote
Draft

iainlane wants to merge 5 commits into
NousResearch:mainfrom
iainlane:fix/matrix-reply-own-quote

Conversation

@iainlane

@iainlane iainlane commented Sep 29, 2026 •

Copy link
Copy Markdown

Stack

This PR has no prerequisite PRs. The nested PR depends on this change and
must merge afterwards.

Preserve an authored leading blockquote in a modern Matrix reply. Strip
the leading block only when the message contains a legacy reply fallback.
Legacy fallbacks include ordinary and emote author pills, so both forms
retain the quoted author's identity in the reply metadata.

When mention gating removes a bot mention from an explicit reply, preserve
the leading quotation verbatim and remove the mention from the text
outside that quotation. This also preserves a bot mention that the sender
included inside an authored quote.

A reproduced conflict with the Matrix crypto-store extraction required a
rebase onto 56f7986. The adapter uses the
upstream crypto-store owner and includes the reply-context mixin in its
current inheritance. The mention-gating quote correction is folded into
its original reply contribution. The later emote and typing contributions
remain separate, and the final source tree matches the tested tree. All
five contributions preserve their authors, committer dates and complete
messages.

Before the rebase, both focused quote cases failed on the previous head
and passed after the correction. The canonical isolated runner passed all
15 metadata tests and all 105 adapter tests without retries. Those results
apply to the earlier base. On the conflict-resolved base, the same two
complete files passed all 120 tests without retries. Scoped Ruff lint and
committed whitespace checks passed. The paired scoped type checks report
the same 20 inherited diagnostics before and after the quote correction,
with no new diagnostics.

The changed quote scopes match Ruff formatting. Unrelated formatting
differences remain qualified. The unchanged quote source and test scopes
retain their earlier formatting validation.

A hand-authored block that exactly imitates an MXID-pill fallback followed
by a blank line remains ambiguous without HTML metadata. Plain CRLF
fallback handling remains the existing behaviour.

@whyyagswhy

Copy link
Copy Markdown

Independent verification on the PR head (528fcda): matrix metadata suite 12/12 green on Linux. Keeping a user's leading quote in an explicit reply is intact. No findings.

@alt-glitch alt-glitch added type/bug Something isn't working P3 Low — cosmetic, nice to have comp/plugins Plugin system and bundled plugins platform/matrix Matrix adapter (E2EE) sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages labels Sep 29, 2026
@iainlane
iainlane force-pushed the fix/matrix-reply-own-quote branch from 528fcda to c25ea71 Compare September 30, 2026 00:16
iainlane added a commit to iainlane/hermes-agent that referenced this pull request Sep 30, 2026
After the merge of NousResearch#128621, the adapter had two rules for one question:
whether a leading "> " block is a legacy reply fallback or the user's
own quote. NousResearch#128621 added _has_reply_fallback, which requires an
<mx-reply> element at the start of the HTML body, or a plain quote block
that starts with the quoted sender's pill and ends with a blank line.
This branch's _strip_thread_reply_fallback used its own copy of the pill
regex and checked the pill alone. The explicit-reply path in
_extract_reply_context still treated any leading "> " as a fallback,
because this branch's signature passed only formatted_body, and
_has_reply_fallback needs the whole content.

Use _has_reply_fallback for thread messages and for explicit replies,
and remove _strip_thread_reply_fallback and its duplicate regex.
_extract_reply_context now takes source_content as a positional
argument before relates_to, as in NousResearch#128621, and reads formatted_body from
it. The sender and chat_type keywords remain.

Two test expectations change:

- In NousResearch#128621's test_reply_strips_only_a_reply_fallback, the
  thread-message-own-quote case now expects no reply_to_message_id.
  This branch treats m.in_reply_to under is_falling_back as the thread's
  fallback target, not an explicit reply, so the event is not a reply.
  The message text, which is what that case checks, is unchanged.
- test_thread_message_strips_only_the_reply_fallback gains a case for a
  thread message whose quote starts with a pill but has no blank line
  after it. The pill-only rule stripped that quote; the shared rule
  keeps it as the user's text.

The shared rule also strips a thread message's plain quote when the HTML
body starts with <mx-reply>, even without a pill, as it already does for
explicit replies.
iainlane added a commit to iainlane/hermes-agent that referenced this pull request Sep 30, 2026
Two helpers decided whether a reply's HTML body starts with an
<mx-reply> fallback, and they disagreed. _has_reply_fallback required
format == "org.matrix.custom.html" and a bare "<mx-reply>" tag.
extract_mx_reply_quote accepted "<mx-reply" followed by anything and
ignored format. For an explicit reply whose tag has an attribute, such
as <mx-reply data-x="1">, and whose plain quote has no pill,
_has_reply_fallback kept the quote in the message text while
extract_mx_reply_quote also returned it as reply_to_text. The model
then saw the quote twice. A formatted_body without format gave the same
result.

Add starts_with_mx_reply(content) in reply_context.py. It requires the
HTML format and matches an <mx-reply> start tag with or without
attributes, ignoring case because the quote extractor reads tag names
lower-cased. Both helpers now call it, and extract_mx_reply_quote takes
the event content in place of the formatted body. The spec's condition
is a formatted_body that "begins with an <mx-reply> start tag", which
includes a tag with attributes. NousResearch#128621's _has_reply_fallback could
take the same tolerance; here it changes only by calling the shared
helper.

Tests:

- test_reply_strips_only_a_reply_fallback gains two cases: an
  <mx-reply> tag with an attribute is one fallback, and an <mx-reply>
  formatted_body without format is not a fallback.
- test_thread_message_strips_only_the_reply_fallback now takes the
  event content, and gains a case where a thread message's pill-less
  quote is stripped because the HTML body starts with <mx-reply>. No
  test covered that path, so requiring a pill there went unnoticed.
- test_formatted_reply_fallback_supplies_quote_without_parent_fetch
  adds the format field to its content, because a formatted_body is
  read as HTML only when format says so.
iainlane added a commit to iainlane/hermes-agent that referenced this pull request Sep 30, 2026
Merge fix/matrix-effective-event-state at 666a75b (NousResearch#126282). It now
includes NousResearch#125735, NousResearch#125697, NousResearch#125660, NousResearch#125648, NousResearch#62088, NousResearch#51804, NousResearch#128621 and
main at 02e4118.

Conflicts:

- plugins/platforms/matrix/adapter.py: main removed the unused
  EA_HEADER_TEXT import. Take the removal and keep the room inspection
  import.
- tools/matrix_read_tool.py: the parent schedules every read with
  safe_schedule_threadsafe and a named deadline, and it drops the
  same-loop branch. Inspection kinds go through the same scheduling
  path, and history kinds call the parent's read_context. The tool
  description keeps this layer's list of kinds, followed by the parent's
  sentences about event order, skipped events and errors.
- tests/integration/matrix_live/conftest.py: the gateway runs as the
  host user and the model server binds to the host route. The
  inspection mode keeps its empty script and its default reply, now
  taken from GatewaySettings.reply.
- tests/gateway/test_matrix_read_context.py: take the parent's _client
  and _adapter helpers in each hunk.
- tests/gateway/test_matrix_reaction_context.py: import _make_adapter
  and the parent's _rendered together.
- tests/tools/test_matrix_read_tool.py: keep this layer's inspection
  test and the parent's parametrised argument and session tests.

Later commits adapt the tests and the inspection module to the parent's
interfaces.
iainlane added a commit to iainlane/hermes-agent that referenced this pull request Sep 30, 2026
Merge fix/matrix-effective-event-state at 666a75b (NousResearch#126282). It now
includes NousResearch#125735, NousResearch#125697, NousResearch#125660, NousResearch#125648, NousResearch#62088, NousResearch#51804, NousResearch#128621 and
main at 02e4118. This branch still carries room inspection at
8b87573 and receipts lifecycle at f2c50f7.

Conflicts:

- gateway/platforms/event.py: keep the receipts processing state and
  voice preparation fields beside the parent's merged message IDs and
  channel state, and both TYPE_CHECKING imports. absorb_media and
  authored_media sit beside absorb_turn_input and receipt_message_id.
- gateway/platforms/base.py: the three merge paths take the parent's
  absorb_media and absorb_message_ids and drop append_channel_context,
  which the parent removed. absorb_turn_input replaces
  absorb_reply_expected, because it calls it and also moves the receipt
  target.
- gateway/run_busy.py: main translated the busy and steer replies. Keep
  the translations with the receipts layer's approval outcome hook, its
  finished-turn steer fallback and input_text. The approval routing
  reads main's per-language word list. /queue keeps the receipts
  layer's dataclasses.replace copy, so it shares the processing state
  and carries the parent's quoted-media and inbound-context
  dependencies; the merged message IDs are copied as a new list, like
  the media lists.
- gateway/run_turn.py: keep processing_event beside the parent's
  input_snapshot and main's title_user_message, and record the agent
  outcome before the parent copies the prepared input back.
- gateway/run_inbound.py: re-home inbound media first, then read the
  voice preparation text.
- hermes_cli/config_defaults.py: keep room_backfill_limit and the
  receipt and reaction defaults.
- plugins/platforms/matrix/adapter.py: main removed the unused
  EA_HEADER_TEXT import. Keep the inspection, feedback, session and
  room-context imports; the immediate-receipt gate with the parent's
  seven-field context; receipt_event_id and reply_parent as keyword
  arguments of _handle_media_message; and inspect_matrix_room. The
  parent removed fetch_thread_context.
- tools/matrix_read_tool.py and tests/tools/test_matrix_read_tool.py:
  resolved as on the room inspection branch. Inspection kinds use the
  parent's scheduling path, and both tests are kept.
- tests/integration/matrix_live/conftest.py: take the foundation's host
  user, host route and HOME, and the parent's modes and plugins, with
  the receipts layer's feedback settings, busy mode, approvals and
  delivery probe. The model_responder fixture now defaults to None, and
  the gateway then scripts GatewaySettings.reply as the parent does. A
  test that overrides model_responder keeps its callable. The queued
  context mode keeps its queue busy mode; every other mode writes the
  receipts layer's busy settings.
- tests/integration/matrix_live/test_read_tools.py: keep the inspection
  test and the parent's encrypted edit test.
iainlane added a commit to iainlane/hermes-agent that referenced this pull request Sep 30, 2026
Merge feat/matrix-unread-base at 2a4c4e6. It now includes the
effective-state parent at 666a75b (NousResearch#126282), with NousResearch#125735, NousResearch#125697,
NousResearch#125660, NousResearch#125648, NousResearch#62088, NousResearch#51804, NousResearch#128621 and main at 02e4118.

Conflicts:

- hermes_cli/tools_config.py and hermes_cli/toolset_scope.py: the
  parent adds matrix_read to CONFIGURABLE_TOOLSETS and restricts it to
  Matrix. Keep matrix_unread beside it in both.
- plugins/platforms/matrix/read_context.py: take the parent's reader.
  It decrypts through client_events, so this layer's _decrypted_event
  and _raw_event are gone; a later commit moves unread.py to the
  client_events helpers.
- plugins/platforms/matrix/adapter.py: main removed the unused
  EA_HEADER_TEXT import, and the parent removed fetch_thread_context.
  Keep the unread import and the read_matrix_unread and
  mark_matrix_read methods.
- tests/integration/matrix_live/conftest.py: take the parent's host
  route, host user and model script. Its model_responder defaults to
  None and the gateway then scripts GatewaySettings.reply, which is
  "Matrix live reply" by default, so the unread test's first reply is
  unchanged and later replies come from its pushed script. Keep this
  layer's gateway_auxiliary_config fixture.
iainlane added a commit to iainlane/hermes-agent that referenced this pull request Sep 30, 2026
After the merge of NousResearch#128621, the adapter had two rules for one question:
whether a leading "> " block is a legacy reply fallback or the user's
own quote. NousResearch#128621 added _has_reply_fallback, which requires an
<mx-reply> element at the start of the HTML body, or a plain quote block
that starts with the quoted sender's pill and ends with a blank line.
This branch's _strip_thread_reply_fallback used its own copy of the pill
regex and checked the pill alone. The explicit-reply path in
_extract_reply_context still treated any leading "> " as a fallback,
because this branch's signature passed only formatted_body, and
_has_reply_fallback needs the whole content.

Use _has_reply_fallback for thread messages and for explicit replies,
and remove _strip_thread_reply_fallback and its duplicate regex.
_extract_reply_context now takes source_content as a positional
argument before relates_to, as in NousResearch#128621, and reads formatted_body from
it. The sender and chat_type keywords remain.

Two test expectations change:

- In NousResearch#128621's test_reply_strips_only_a_reply_fallback, the
  thread-message-own-quote case now expects no reply_to_message_id.
  This branch treats m.in_reply_to under is_falling_back as the thread's
  fallback target, not an explicit reply, so the event is not a reply.
  The message text, which is what that case checks, is unchanged.
- test_thread_message_strips_only_the_reply_fallback gains a case for a
  thread message whose quote starts with a pill but has no blank line
  after it. The pill-only rule stripped that quote; the shared rule
  keeps it as the user's text.

The shared rule also strips a thread message's plain quote when the HTML
body starts with <mx-reply>, even without a pill, as it already does for
explicit replies.
@iainlane
iainlane force-pushed the fix/matrix-reply-own-quote branch from c25ea71 to 52c7439 Compare October 1, 2026 11:56
iainlane added a commit to iainlane/hermes-agent that referenced this pull request Oct 1, 2026
After the merge of NousResearch#128621, the adapter had two rules for one question:
whether a leading "> " block is a legacy reply fallback or the user's
own quote. NousResearch#128621 added _has_reply_fallback, which requires an
<mx-reply> element at the start of the HTML body, or a plain quote block
that starts with the quoted sender's pill and ends with a blank line.
This branch's _strip_thread_reply_fallback used its own copy of the pill
regex and checked the pill alone. The explicit-reply path in
_extract_reply_context still treated any leading "> " as a fallback,
because this branch's signature passed only formatted_body, and
_has_reply_fallback needs the whole content.

Use _has_reply_fallback for thread messages and for explicit replies,
and remove _strip_thread_reply_fallback and its duplicate regex.
_extract_reply_context now takes source_content as a positional
argument before relates_to, as in NousResearch#128621, and reads formatted_body from
it. The sender and chat_type keywords remain.

Two test expectations change:

- In NousResearch#128621's test_reply_strips_only_a_reply_fallback, the
  thread-message-own-quote case now expects no reply_to_message_id.
  This branch treats m.in_reply_to under is_falling_back as the thread's
  fallback target, not an explicit reply, so the event is not a reply.
  The message text, which is what that case checks, is unchanged.
- test_thread_message_strips_only_the_reply_fallback gains a case for a
  thread message whose quote starts with a pill but has no blank line
  after it. The pill-only rule stripped that quote; the shared rule
  keeps it as the user's text.

The shared rule also strips a thread message's plain quote when the HTML
body starts with <mx-reply>, even without a pill, as it already does for
explicit replies.
Reply fallbacks, mention gating and event construction share the same
inbound body in the large Matrix adapter. Move that existing pipeline
into a topical sibling before integrating the reviewed fallback fixes.

Keep adapter-specific command and media classification at their
existing runtime lookup seams. MatrixAdapter inherits the context
methods, so receipt, thread and voice admission behaviour is unchanged.
When an explicit reply (m.in_reply_to) had a body starting with "> ",
the adapter treated every leading "> " line as the legacy reply
fallback. It removed those lines from the message text and reported
them as the text of the replied-to message. Matrix 1.13 (MSC2781)
removed reply fallbacks, and current clients such as Element X send a
reply exactly as the user typed it. A user who began a reply with a
quotation therefore lost the quotation, and the agent saw it as the
message being replied to. Element also sets m.in_reply_to, with
is_falling_back, on ordinary thread messages, so a quote at the start
of a thread message was lost in the same way.

Treat the leading quote as a fallback only when the event has one: the
HTML body starts with an <mx-reply> element, or the plain quote block
starts with the quoted sender's pill ("> <@user:server>", or
"> * <@user:server>" for an emote) and ends with a blank line. Older
clients generate both forms. The reply-context parse and the mention
strip under require_mention use the same check, so a quote without a
fallback stays in the text with any bot mention removed, as it does in
a message that is not a reply.

The plain-body check is deliberately narrower than the spec. The
spec's stripping note still says to remove every leading "> " line of
a reply without condition, and that rule cannot tell a fallback from a
quote now that clients no longer send fallbacks. Ruma's
remove_plain_reply_fallback, which matrix-rust-sdk and Element X use,
narrows it in the same way: it strips only a body that starts with
"> <" or "> * <". The HTML check follows the spec's rule for
formatted_body, which applies only when it starts with <mx-reply>.

A hand-typed quote that starts with a pill and ends with a blank line
has the same shape as a plain fallback and is still stripped.

Original-campaign-source: c1c77db
A reply to an m.emote message has a fallback that starts with
"> * <@user:server>". The regex that parses the fallback's pill
expected "<" straight after "> ", so it did not match this form. The
reply lost its author (reply_to_author_id and reply_to_author_name were
None), and the quoted text kept "* <@user:server>" at its start.

Accept the optional "* " before the pill. The fallback detector
already recognised the emote form with a second regex that described
the same line, so both now use the one pattern.

Original-campaign-source: 52c7439
Reply preparation moved into sibling mixins, but their untyped
receivers no longer expose platform adapter state to static checking.
Specify the concrete adapter types through imports that run only
during static checking. SDK loading and reply behaviour are unchanged.
@iainlane
iainlane force-pushed the fix/matrix-reply-own-quote branch from 52c7439 to 60b96b2 Compare October 1, 2026 21:27
iainlane added a commit to iainlane/hermes-agent that referenced this pull request Oct 2, 2026
After the merge of NousResearch#128621, the adapter had two rules for one question:
whether a leading "> " block is a legacy reply fallback or the user's
own quote. NousResearch#128621 added _has_reply_fallback, which requires an
<mx-reply> element at the start of the HTML body, or a plain quote block
that starts with the quoted sender's pill and ends with a blank line.
This branch's _strip_thread_reply_fallback used its own copy of the pill
regex and checked the pill alone. The explicit-reply path in
_extract_reply_context still treated any leading "> " as a fallback,
because this branch's signature passed only formatted_body, and
_has_reply_fallback needs the whole content.

Use _has_reply_fallback for thread messages and for explicit replies,
and remove _strip_thread_reply_fallback and its duplicate regex.
_extract_reply_context now takes source_content as a positional
argument before relates_to, as in NousResearch#128621, and reads formatted_body from
it. The sender and chat_type keywords remain.

Two test expectations change:

- In NousResearch#128621's test_reply_strips_only_a_reply_fallback, the
  thread-message-own-quote case now expects no reply_to_message_id.
  This branch treats m.in_reply_to under is_falling_back as the thread's
  fallback target, not an explicit reply, so the event is not a reply.
  The message text, which is what that case checks, is unchanged.
- test_thread_message_strips_only_the_reply_fallback gains a case for a
  thread message whose quote starts with a pill but has no blank line
  after it. The pill-only rule stripped that quote; the shared rule
  keeps it as the user's text.

The shared rule also strips a thread message's plain quote when the HTML
body starts with <mx-reply>, even without a pill, as it already does for
explicit replies.
iainlane added a commit to iainlane/hermes-agent that referenced this pull request Oct 2, 2026
After the merge of NousResearch#128621, the adapter had two rules for one question:
whether a leading "> " block is a legacy reply fallback or the user's
own quote. NousResearch#128621 added _has_reply_fallback, which requires an
<mx-reply> element at the start of the HTML body, or a plain quote block
that starts with the quoted sender's pill and ends with a blank line.
This branch's _strip_thread_reply_fallback used its own copy of the pill
regex and checked the pill alone. The explicit-reply path in
_extract_reply_context still treated any leading "> " as a fallback,
because this branch's signature passed only formatted_body, and
_has_reply_fallback needs the whole content.

Use _has_reply_fallback for thread messages and for explicit replies,
and remove _strip_thread_reply_fallback and its duplicate regex.
_extract_reply_context now takes source_content as a positional
argument before relates_to, as in NousResearch#128621, and reads formatted_body from
it. The sender and chat_type keywords remain.

Two test expectations change:

- In NousResearch#128621's test_reply_strips_only_a_reply_fallback, the
  thread-message-own-quote case now expects no reply_to_message_id.
  This branch treats m.in_reply_to under is_falling_back as the thread's
  fallback target, not an explicit reply, so the event is not a reply.
  The message text, which is what that case checks, is unchanged.
- test_thread_message_strips_only_the_reply_fallback gains a case for a
  thread message whose quote starts with a pill but has no blank line
  after it. The pill-only rule stripped that quote; the shared rule
  keeps it as the user's text.

The shared rule also strips a thread message's plain quote when the HTML
body starts with <mx-reply>, even without a pill, as it already does for
explicit replies.
iainlane added a commit to iainlane/hermes-agent that referenced this pull request Oct 2, 2026
After the merge of NousResearch#128621, the adapter had two rules for one question:
whether a leading "> " block is a legacy reply fallback or the user's
own quote. NousResearch#128621 added _has_reply_fallback, which requires an
<mx-reply> element at the start of the HTML body, or a plain quote block
that starts with the quoted sender's pill and ends with a blank line.
This branch's _strip_thread_reply_fallback used its own copy of the pill
regex and checked the pill alone. The explicit-reply path in
_extract_reply_context still treated any leading "> " as a fallback,
because this branch's signature passed only formatted_body, and
_has_reply_fallback needs the whole content.

Use _has_reply_fallback for thread messages and for explicit replies,
and remove _strip_thread_reply_fallback and its duplicate regex.
_extract_reply_context now takes source_content as a positional
argument before relates_to, as in NousResearch#128621, and reads formatted_body from
it. The sender and chat_type keywords remain.

Two test expectations change:

- In NousResearch#128621's test_reply_strips_only_a_reply_fallback, the
  thread-message-own-quote case now expects no reply_to_message_id.
  This branch treats m.in_reply_to under is_falling_back as the thread's
  fallback target, not an explicit reply, so the event is not a reply.
  The message text, which is what that case checks, is unchanged.
- test_thread_message_strips_only_the_reply_fallback gains a case for a
  thread message whose quote starts with a pill but has no blank line
  after it. The pill-only rule stripped that quote; the shared rule
  keeps it as the user's text.

The shared rule also strips a thread message's plain quote when the HTML
body starts with <mx-reply>, even without a pill, as it already does for
explicit replies.
iainlane added a commit to iainlane/hermes-agent that referenced this pull request Oct 2, 2026
After the merge of NousResearch#128621, the adapter had two rules for one question:
whether a leading "> " block is a legacy reply fallback or the user's
own quote. NousResearch#128621 added _has_reply_fallback, which requires an
<mx-reply> element at the start of the HTML body, or a plain quote block
that starts with the quoted sender's pill and ends with a blank line.
This branch's _strip_thread_reply_fallback used its own copy of the pill
regex and checked the pill alone. The explicit-reply path in
_extract_reply_context still treated any leading "> " as a fallback,
because this branch's signature passed only formatted_body, and
_has_reply_fallback needs the whole content.

Use _has_reply_fallback for thread messages and for explicit replies,
and remove _strip_thread_reply_fallback and its duplicate regex.
_extract_reply_context now takes source_content as a positional
argument before relates_to, as in NousResearch#128621, and reads formatted_body from
it. The sender and chat_type keywords remain.

Two test expectations change:

- In NousResearch#128621's test_reply_strips_only_a_reply_fallback, the
  thread-message-own-quote case now expects no reply_to_message_id.
  This branch treats m.in_reply_to under is_falling_back as the thread's
  fallback target, not an explicit reply, so the event is not a reply.
  The message text, which is what that case checks, is unchanged.
- test_thread_message_strips_only_the_reply_fallback gains a case for a
  thread message whose quote starts with a pill but has no blank line
  after it. The pill-only rule stripped that quote; the shared rule
  keeps it as the user's text.

The shared rule also strips a thread message's plain quote when the HTML
body starts with <mx-reply>, even without a pill, as it already does for
explicit replies.
iainlane added a commit to iainlane/hermes-agent that referenced this pull request Oct 2, 2026
After the merge of NousResearch#128621, the adapter had two rules for one question:
whether a leading "> " block is a legacy reply fallback or the user's
own quote. NousResearch#128621 added _has_reply_fallback, which requires an
<mx-reply> element at the start of the HTML body, or a plain quote block
that starts with the quoted sender's pill and ends with a blank line.
This branch's _strip_thread_reply_fallback used its own copy of the pill
regex and checked the pill alone. The explicit-reply path in
_extract_reply_context still treated any leading "> " as a fallback,
because this branch's signature passed only formatted_body, and
_has_reply_fallback needs the whole content.

Use _has_reply_fallback for thread messages and for explicit replies,
and remove _strip_thread_reply_fallback and its duplicate regex.
_extract_reply_context now takes source_content as a positional
argument before relates_to, as in NousResearch#128621, and reads formatted_body from
it. The sender and chat_type keywords remain.

Two test expectations change:

- In NousResearch#128621's test_reply_strips_only_a_reply_fallback, the
  thread-message-own-quote case now expects no reply_to_message_id.
  This branch treats m.in_reply_to under is_falling_back as the thread's
  fallback target, not an explicit reply, so the event is not a reply.
  The message text, which is what that case checks, is unchanged.
- test_thread_message_strips_only_the_reply_fallback gains a case for a
  thread message whose quote starts with a pill but has no blank line
  after it. The pill-only rule stripped that quote; the shared rule
  keeps it as the user's text.

The shared rule also strips a thread message's plain quote when the HTML
body starts with <mx-reply>, even without a pill, as it already does for
explicit replies.
iainlane added a commit to iainlane/hermes-agent that referenced this pull request Oct 4, 2026
After the merge of NousResearch#128621, the adapter had two rules for one question:
whether a leading "> " block is a legacy reply fallback or the user's
own quote. NousResearch#128621 added _has_reply_fallback, which requires an
<mx-reply> element at the start of the HTML body, or a plain quote block
that starts with the quoted sender's pill and ends with a blank line.
This branch's _strip_thread_reply_fallback used its own copy of the pill
regex and checked the pill alone. The explicit-reply path in
_extract_reply_context still treated any leading "> " as a fallback,
because this branch's signature passed only formatted_body, and
_has_reply_fallback needs the whole content.

Use _has_reply_fallback for thread messages and for explicit replies,
and remove _strip_thread_reply_fallback and its duplicate regex.
_extract_reply_context now takes source_content as a positional
argument before relates_to, as in NousResearch#128621, and reads formatted_body from
it. The sender and chat_type keywords remain.

Two test expectations change:

- In NousResearch#128621's test_reply_strips_only_a_reply_fallback, the
  thread-message-own-quote case now expects no reply_to_message_id.
  This branch treats m.in_reply_to under is_falling_back as the thread's
  fallback target, not an explicit reply, so the event is not a reply.
  The message text, which is what that case checks, is unchanged.
- test_thread_message_strips_only_the_reply_fallback gains a case for a
  thread message whose quote starts with a pill but has no blank line
  after it. The pill-only rule stripped that quote; the shared rule
  keeps it as the user's text.

The shared rule also strips a thread message's plain quote when the HTML
body starts with <mx-reply>, even without a pill, as it already does for
explicit replies.
iainlane added a commit to iainlane/hermes-agent that referenced this pull request Oct 4, 2026
After the merge of NousResearch#128621, the adapter had two rules for one question:
whether a leading "> " block is a legacy reply fallback or the user's
own quote. NousResearch#128621 added _has_reply_fallback, which requires an
<mx-reply> element at the start of the HTML body, or a plain quote block
that starts with the quoted sender's pill and ends with a blank line.
This branch's _strip_thread_reply_fallback used its own copy of the pill
regex and checked the pill alone. The explicit-reply path in
_extract_reply_context still treated any leading "> " as a fallback,
because this branch's signature passed only formatted_body, and
_has_reply_fallback needs the whole content.

Use _has_reply_fallback for thread messages and for explicit replies,
and remove _strip_thread_reply_fallback and its duplicate regex.
_extract_reply_context now takes source_content as a positional
argument before relates_to, as in NousResearch#128621, and reads formatted_body from
it. The sender and chat_type keywords remain.

Two test expectations change:

- In NousResearch#128621's test_reply_strips_only_a_reply_fallback, the
  thread-message-own-quote case now expects no reply_to_message_id.
  This branch treats m.in_reply_to under is_falling_back as the thread's
  fallback target, not an explicit reply, so the event is not a reply.
  The message text, which is what that case checks, is unchanged.
- test_thread_message_strips_only_the_reply_fallback gains a case for a
  thread message whose quote starts with a pill but has no blank line
  after it. The pill-only rule stripped that quote; the shared rule
  keeps it as the user's text.

The shared rule also strips a thread message's plain quote when the HTML
body starts with <mx-reply>, even without a pill, as it already does for
explicit replies.
iainlane added a commit to iainlane/hermes-agent that referenced this pull request Oct 5, 2026
After the merge of NousResearch#128621, the adapter had two rules for one question:
whether a leading "> " block is a legacy reply fallback or the user's
own quote. NousResearch#128621 added _has_reply_fallback, which requires an
<mx-reply> element at the start of the HTML body, or a plain quote block
that starts with the quoted sender's pill and ends with a blank line.
This branch's _strip_thread_reply_fallback used its own copy of the pill
regex and checked the pill alone. The explicit-reply path in
_extract_reply_context still treated any leading "> " as a fallback,
because this branch's signature passed only formatted_body, and
_has_reply_fallback needs the whole content.

Use _has_reply_fallback for thread messages and for explicit replies,
and remove _strip_thread_reply_fallback and its duplicate regex.
_extract_reply_context now takes source_content as a positional
argument before relates_to, as in NousResearch#128621, and reads formatted_body from
it. The sender and chat_type keywords remain.

Two test expectations change:

- In NousResearch#128621's test_reply_strips_only_a_reply_fallback, the
  thread-message-own-quote case now expects no reply_to_message_id.
  This branch treats m.in_reply_to under is_falling_back as the thread's
  fallback target, not an explicit reply, so the event is not a reply.
  The message text, which is what that case checks, is unchanged.
- test_thread_message_strips_only_the_reply_fallback gains a case for a
  thread message whose quote starts with a pill but has no blank line
  after it. The pill-only rule stripped that quote; the shared rule
  keeps it as the user's text.

The shared rule also strips a thread message's plain quote when the HTML
body starts with <mx-reply>, even without a pill, as it already does for
explicit replies.
iainlane added a commit to iainlane/hermes-agent that referenced this pull request Oct 8, 2026
After the merge of NousResearch#128621, the adapter had two rules for one question:
whether a leading "> " block is a legacy reply fallback or the user's
own quote. NousResearch#128621 added _has_reply_fallback, which requires an
<mx-reply> element at the start of the HTML body, or a plain quote block
that starts with the quoted sender's pill and ends with a blank line.
This branch's _strip_thread_reply_fallback used its own copy of the pill
regex and checked the pill alone. The explicit-reply path in
_extract_reply_context still treated any leading "> " as a fallback,
because this branch's signature passed only formatted_body, and
_has_reply_fallback needs the whole content.

Use _has_reply_fallback for thread messages and for explicit replies,
and remove _strip_thread_reply_fallback and its duplicate regex.
_extract_reply_context now takes source_content as a positional
argument before relates_to, as in NousResearch#128621, and reads formatted_body from
it. The sender and chat_type keywords remain.

Two test expectations change:

- In NousResearch#128621's test_reply_strips_only_a_reply_fallback, the
  thread-message-own-quote case now expects no reply_to_message_id.
  This branch treats m.in_reply_to under is_falling_back as the thread's
  fallback target, not an explicit reply, so the event is not a reply.
  The message text, which is what that case checks, is unchanged.
- test_thread_message_strips_only_the_reply_fallback gains a case for a
  thread message whose quote starts with a pill but has no blank line
  after it. The pill-only rule stripped that quote; the shared rule
  keeps it as the user's text.

The shared rule also strips a thread message's plain quote when the HTML
body starts with <mx-reply>, even without a pill, as it already does for
explicit replies.
iainlane added a commit to iainlane/hermes-agent that referenced this pull request Oct 8, 2026
After the merge of NousResearch#128621, the adapter had two rules for one question:
whether a leading "> " block is a legacy reply fallback or the user's
own quote. NousResearch#128621 added _has_reply_fallback, which requires an
<mx-reply> element at the start of the HTML body, or a plain quote block
that starts with the quoted sender's pill and ends with a blank line.
This branch's _strip_thread_reply_fallback used its own copy of the pill
regex and checked the pill alone. The explicit-reply path in
_extract_reply_context still treated any leading "> " as a fallback,
because this branch's signature passed only formatted_body, and
_has_reply_fallback needs the whole content.

Use _has_reply_fallback for thread messages and for explicit replies,
and remove _strip_thread_reply_fallback and its duplicate regex.
_extract_reply_context now takes source_content as a positional
argument before relates_to, as in NousResearch#128621, and reads formatted_body from
it. The sender and chat_type keywords remain.

Two test expectations change:

- In NousResearch#128621's test_reply_strips_only_a_reply_fallback, the
  thread-message-own-quote case now expects no reply_to_message_id.
  This branch treats m.in_reply_to under is_falling_back as the thread's
  fallback target, not an explicit reply, so the event is not a reply.
  The message text, which is what that case checks, is unchanged.
- test_thread_message_strips_only_the_reply_fallback gains a case for a
  thread message whose quote starts with a pill but has no blank line
  after it. The pill-only rule stripped that quote; the shared rule
  keeps it as the user's text.

The shared rule also strips a thread message's plain quote when the HTML
body starts with <mx-reply>, even without a pill, as it already does for
explicit replies.
iainlane added a commit to iainlane/hermes-agent that referenced this pull request Oct 8, 2026
After the merge of NousResearch#128621, the adapter had two rules for one question:
whether a leading "> " block is a legacy reply fallback or the user's
own quote. NousResearch#128621 added _has_reply_fallback, which requires an
<mx-reply> element at the start of the HTML body, or a plain quote block
that starts with the quoted sender's pill and ends with a blank line.
This branch's _strip_thread_reply_fallback used its own copy of the pill
regex and checked the pill alone. The explicit-reply path in
_extract_reply_context still treated any leading "> " as a fallback,
because this branch's signature passed only formatted_body, and
_has_reply_fallback needs the whole content.

Use _has_reply_fallback for thread messages and for explicit replies,
and remove _strip_thread_reply_fallback and its duplicate regex.
_extract_reply_context now takes source_content as a positional
argument before relates_to, as in NousResearch#128621, and reads formatted_body from
it. The sender and chat_type keywords remain.

Two test expectations change:

- In NousResearch#128621's test_reply_strips_only_a_reply_fallback, the
  thread-message-own-quote case now expects no reply_to_message_id.
  This branch treats m.in_reply_to under is_falling_back as the thread's
  fallback target, not an explicit reply, so the event is not a reply.
  The message text, which is what that case checks, is unchanged.
- test_thread_message_strips_only_the_reply_fallback gains a case for a
  thread message whose quote starts with a pill but has no blank line
  after it. The pill-only rule stripped that quote; the shared rule
  keeps it as the user's text.

The shared rule also strips a thread message's plain quote when the HTML
body starts with <mx-reply>, even without a pill, as it already does for
explicit replies.
iainlane added a commit to iainlane/hermes-agent that referenced this pull request Oct 8, 2026
After the merge of NousResearch#128621, the adapter had two rules for one question:
whether a leading "> " block is a legacy reply fallback or the user's
own quote. NousResearch#128621 added _has_reply_fallback, which requires an
<mx-reply> element at the start of the HTML body, or a plain quote block
that starts with the quoted sender's pill and ends with a blank line.
This branch's _strip_thread_reply_fallback used its own copy of the pill
regex and checked the pill alone. The explicit-reply path in
_extract_reply_context still treated any leading "> " as a fallback,
because this branch's signature passed only formatted_body, and
_has_reply_fallback needs the whole content.

Use _has_reply_fallback for thread messages and for explicit replies,
and remove _strip_thread_reply_fallback and its duplicate regex.
_extract_reply_context now takes source_content as a positional
argument before relates_to, as in NousResearch#128621, and reads formatted_body from
it. The sender and chat_type keywords remain.

Two test expectations change:

- In NousResearch#128621's test_reply_strips_only_a_reply_fallback, the
  thread-message-own-quote case now expects no reply_to_message_id.
  This branch treats m.in_reply_to under is_falling_back as the thread's
  fallback target, not an explicit reply, so the event is not a reply.
  The message text, which is what that case checks, is unchanged.
- test_thread_message_strips_only_the_reply_fallback gains a case for a
  thread message whose quote starts with a pill but has no blank line
  after it. The pill-only rule stripped that quote; the shared rule
  keeps it as the user's text.

The shared rule also strips a thread message's plain quote when the HTML
body starts with <mx-reply>, even without a pill, as it already does for
explicit replies.
iainlane added a commit to iainlane/hermes-agent that referenced this pull request Oct 8, 2026
After the merge of NousResearch#128621, the adapter had two rules for one question:
whether a leading "> " block is a legacy reply fallback or the user's
own quote. NousResearch#128621 added _has_reply_fallback, which requires an
<mx-reply> element at the start of the HTML body, or a plain quote block
that starts with the quoted sender's pill and ends with a blank line.
This branch's _strip_thread_reply_fallback used its own copy of the pill
regex and checked the pill alone. The explicit-reply path in
_extract_reply_context still treated any leading "> " as a fallback,
because this branch's signature passed only formatted_body, and
_has_reply_fallback needs the whole content.

Use _has_reply_fallback for thread messages and for explicit replies,
and remove _strip_thread_reply_fallback and its duplicate regex.
_extract_reply_context now takes source_content as a positional
argument before relates_to, as in NousResearch#128621, and reads formatted_body from
it. The sender and chat_type keywords remain.

Two test expectations change:

- In NousResearch#128621's test_reply_strips_only_a_reply_fallback, the
  thread-message-own-quote case now expects no reply_to_message_id.
  This branch treats m.in_reply_to under is_falling_back as the thread's
  fallback target, not an explicit reply, so the event is not a reply.
  The message text, which is what that case checks, is unchanged.
- test_thread_message_strips_only_the_reply_fallback gains a case for a
  thread message whose quote starts with a pill but has no blank line
  after it. The pill-only rule stripped that quote; the shared rule
  keeps it as the user's text.

The shared rule also strips a thread message's plain quote when the HTML
body starts with <mx-reply>, even without a pill, as it already does for
explicit replies.
iainlane added a commit to iainlane/hermes-agent that referenced this pull request Oct 8, 2026
After the merge of NousResearch#128621, the adapter had two rules for one question:
whether a leading "> " block is a legacy reply fallback or the user's
own quote. NousResearch#128621 added _has_reply_fallback, which requires an
<mx-reply> element at the start of the HTML body, or a plain quote block
that starts with the quoted sender's pill and ends with a blank line.
This branch's _strip_thread_reply_fallback used its own copy of the pill
regex and checked the pill alone. The explicit-reply path in
_extract_reply_context still treated any leading "> " as a fallback,
because this branch's signature passed only formatted_body, and
_has_reply_fallback needs the whole content.

Use _has_reply_fallback for thread messages and for explicit replies,
and remove _strip_thread_reply_fallback and its duplicate regex.
_extract_reply_context now takes source_content as a positional
argument before relates_to, as in NousResearch#128621, and reads formatted_body from
it. The sender and chat_type keywords remain.

Two test expectations change:

- In NousResearch#128621's test_reply_strips_only_a_reply_fallback, the
  thread-message-own-quote case now expects no reply_to_message_id.
  This branch treats m.in_reply_to under is_falling_back as the thread's
  fallback target, not an explicit reply, so the event is not a reply.
  The message text, which is what that case checks, is unchanged.
- test_thread_message_strips_only_the_reply_fallback gains a case for a
  thread message whose quote starts with a pill but has no blank line
  after it. The pill-only rule stripped that quote; the shared rule
  keeps it as the user's text.

The shared rule also strips a thread message's plain quote when the HTML
body starts with <mx-reply>, even without a pill, as it already does for
explicit replies.
iainlane added a commit to iainlane/hermes-agent that referenced this pull request Oct 8, 2026
After the merge of NousResearch#128621, the adapter had two rules for one question:
whether a leading "> " block is a legacy reply fallback or the user's
own quote. NousResearch#128621 added _has_reply_fallback, which requires an
<mx-reply> element at the start of the HTML body, or a plain quote block
that starts with the quoted sender's pill and ends with a blank line.
This branch's _strip_thread_reply_fallback used its own copy of the pill
regex and checked the pill alone. The explicit-reply path in
_extract_reply_context still treated any leading "> " as a fallback,
because this branch's signature passed only formatted_body, and
_has_reply_fallback needs the whole content.

Use _has_reply_fallback for thread messages and for explicit replies,
and remove _strip_thread_reply_fallback and its duplicate regex.
_extract_reply_context now takes source_content as a positional
argument before relates_to, as in NousResearch#128621, and reads formatted_body from
it. The sender and chat_type keywords remain.

Two test expectations change:

- In NousResearch#128621's test_reply_strips_only_a_reply_fallback, the
  thread-message-own-quote case now expects no reply_to_message_id.
  This branch treats m.in_reply_to under is_falling_back as the thread's
  fallback target, not an explicit reply, so the event is not a reply.
  The message text, which is what that case checks, is unchanged.
- test_thread_message_strips_only_the_reply_fallback gains a case for a
  thread message whose quote starts with a pill but has no blank line
  after it. The pill-only rule stripped that quote; the shared rule
  keeps it as the user's text.

The shared rule also strips a thread message's plain quote when the HTML
body starts with <mx-reply>, even without a pill, as it already does for
explicit replies.
iainlane added a commit to iainlane/hermes-agent that referenced this pull request Oct 9, 2026
After the merge of NousResearch#128621, the adapter had two rules for one question:
whether a leading "> " block is a legacy reply fallback or the user's
own quote. NousResearch#128621 added _has_reply_fallback, which requires an
<mx-reply> element at the start of the HTML body, or a plain quote block
that starts with the quoted sender's pill and ends with a blank line.
This branch's _strip_thread_reply_fallback used its own copy of the pill
regex and checked the pill alone. The explicit-reply path in
_extract_reply_context still treated any leading "> " as a fallback,
because this branch's signature passed only formatted_body, and
_has_reply_fallback needs the whole content.

Use _has_reply_fallback for thread messages and for explicit replies,
and remove _strip_thread_reply_fallback and its duplicate regex.
_extract_reply_context now takes source_content as a positional
argument before relates_to, as in NousResearch#128621, and reads formatted_body from
it. The sender and chat_type keywords remain.

Two test expectations change:

- In NousResearch#128621's test_reply_strips_only_a_reply_fallback, the
  thread-message-own-quote case now expects no reply_to_message_id.
  This branch treats m.in_reply_to under is_falling_back as the thread's
  fallback target, not an explicit reply, so the event is not a reply.
  The message text, which is what that case checks, is unchanged.
- test_thread_message_strips_only_the_reply_fallback gains a case for a
  thread message whose quote starts with a pill but has no blank line
  after it. The pill-only rule stripped that quote; the shared rule
  keeps it as the user's text.

The shared rule also strips a thread message's plain quote when the HTML
body starts with <mx-reply>, even without a pill, as it already does for
explicit replies.
iainlane added a commit to iainlane/hermes-agent that referenced this pull request Oct 9, 2026
After the merge of NousResearch#128621, the adapter had two rules for one question:
whether a leading "> " block is a legacy reply fallback or the user's
own quote. NousResearch#128621 added _has_reply_fallback, which requires an
<mx-reply> element at the start of the HTML body, or a plain quote block
that starts with the quoted sender's pill and ends with a blank line.
This branch's _strip_thread_reply_fallback used its own copy of the pill
regex and checked the pill alone. The explicit-reply path in
_extract_reply_context still treated any leading "> " as a fallback,
because this branch's signature passed only formatted_body, and
_has_reply_fallback needs the whole content.

Use _has_reply_fallback for thread messages and for explicit replies,
and remove _strip_thread_reply_fallback and its duplicate regex.
_extract_reply_context now takes source_content as a positional
argument before relates_to, as in NousResearch#128621, and reads formatted_body from
it. The sender and chat_type keywords remain.

Two test expectations change:

- In NousResearch#128621's test_reply_strips_only_a_reply_fallback, the
  thread-message-own-quote case now expects no reply_to_message_id.
  This branch treats m.in_reply_to under is_falling_back as the thread's
  fallback target, not an explicit reply, so the event is not a reply.
  The message text, which is what that case checks, is unchanged.
- test_thread_message_strips_only_the_reply_fallback gains a case for a
  thread message whose quote starts with a pill but has no blank line
  after it. The pill-only rule stripped that quote; the shared rule
  keeps it as the user's text.

The shared rule also strips a thread message's plain quote when the HTML
body starts with <mx-reply>, even without a pill, as it already does for
explicit replies.
iainlane added a commit to iainlane/hermes-agent that referenced this pull request Oct 9, 2026
After the merge of NousResearch#128621, the adapter had two rules for one question:
whether a leading "> " block is a legacy reply fallback or the user's
own quote. NousResearch#128621 added _has_reply_fallback, which requires an
<mx-reply> element at the start of the HTML body, or a plain quote block
that starts with the quoted sender's pill and ends with a blank line.
This branch's _strip_thread_reply_fallback used its own copy of the pill
regex and checked the pill alone. The explicit-reply path in
_extract_reply_context still treated any leading "> " as a fallback,
because this branch's signature passed only formatted_body, and
_has_reply_fallback needs the whole content.

Use _has_reply_fallback for thread messages and for explicit replies,
and remove _strip_thread_reply_fallback and its duplicate regex.
_extract_reply_context now takes source_content as a positional
argument before relates_to, as in NousResearch#128621, and reads formatted_body from
it. The sender and chat_type keywords remain.

Two test expectations change:

- In NousResearch#128621's test_reply_strips_only_a_reply_fallback, the
  thread-message-own-quote case now expects no reply_to_message_id.
  This branch treats m.in_reply_to under is_falling_back as the thread's
  fallback target, not an explicit reply, so the event is not a reply.
  The message text, which is what that case checks, is unchanged.
- test_thread_message_strips_only_the_reply_fallback gains a case for a
  thread message whose quote starts with a pill but has no blank line
  after it. The pill-only rule stripped that quote; the shared rule
  keeps it as the user's text.

The shared rule also strips a thread message's plain quote when the HTML
body starts with <mx-reply>, even without a pill, as it already does for
explicit replies.
iainlane added a commit to iainlane/hermes-agent that referenced this pull request Oct 9, 2026
After the merge of NousResearch#128621, the adapter had two rules for one question:
whether a leading "> " block is a legacy reply fallback or the user's
own quote. NousResearch#128621 added _has_reply_fallback, which requires an
<mx-reply> element at the start of the HTML body, or a plain quote block
that starts with the quoted sender's pill and ends with a blank line.
This branch's _strip_thread_reply_fallback used its own copy of the pill
regex and checked the pill alone. The explicit-reply path in
_extract_reply_context still treated any leading "> " as a fallback,
because this branch's signature passed only formatted_body, and
_has_reply_fallback needs the whole content.

Use _has_reply_fallback for thread messages and for explicit replies,
and remove _strip_thread_reply_fallback and its duplicate regex.
_extract_reply_context now takes source_content as a positional
argument before relates_to, as in NousResearch#128621, and reads formatted_body from
it. The sender and chat_type keywords remain.

Two test expectations change:

- In NousResearch#128621's test_reply_strips_only_a_reply_fallback, the
  thread-message-own-quote case now expects no reply_to_message_id.
  This branch treats m.in_reply_to under is_falling_back as the thread's
  fallback target, not an explicit reply, so the event is not a reply.
  The message text, which is what that case checks, is unchanged.
- test_thread_message_strips_only_the_reply_fallback gains a case for a
  thread message whose quote starts with a pill but has no blank line
  after it. The pill-only rule stripped that quote; the shared rule
  keeps it as the user's text.

The shared rule also strips a thread message's plain quote when the HTML
body starts with <mx-reply>, even without a pill, as it already does for
explicit replies.
iainlane added a commit to iainlane/hermes-agent that referenced this pull request Oct 9, 2026
After the merge of NousResearch#128621, the adapter had two rules for one question:
whether a leading "> " block is a legacy reply fallback or the user's
own quote. NousResearch#128621 added _has_reply_fallback, which requires an
<mx-reply> element at the start of the HTML body, or a plain quote block
that starts with the quoted sender's pill and ends with a blank line.
This branch's _strip_thread_reply_fallback used its own copy of the pill
regex and checked the pill alone. The explicit-reply path in
_extract_reply_context still treated any leading "> " as a fallback,
because this branch's signature passed only formatted_body, and
_has_reply_fallback needs the whole content.

Use _has_reply_fallback for thread messages and for explicit replies,
and remove _strip_thread_reply_fallback and its duplicate regex.
_extract_reply_context now takes source_content as a positional
argument before relates_to, as in NousResearch#128621, and reads formatted_body from
it. The sender and chat_type keywords remain.

Two test expectations change:

- In NousResearch#128621's test_reply_strips_only_a_reply_fallback, the
  thread-message-own-quote case now expects no reply_to_message_id.
  This branch treats m.in_reply_to under is_falling_back as the thread's
  fallback target, not an explicit reply, so the event is not a reply.
  The message text, which is what that case checks, is unchanged.
- test_thread_message_strips_only_the_reply_fallback gains a case for a
  thread message whose quote starts with a pill but has no blank line
  after it. The pill-only rule stripped that quote; the shared rule
  keeps it as the user's text.

The shared rule also strips a thread message's plain quote when the HTML
body starts with <mx-reply>, even without a pill, as it already does for
explicit replies.
iainlane added a commit to iainlane/hermes-agent that referenced this pull request Oct 9, 2026
After the merge of NousResearch#128621, the adapter had two rules for one question:
whether a leading "> " block is a legacy reply fallback or the user's
own quote. NousResearch#128621 added _has_reply_fallback, which requires an
<mx-reply> element at the start of the HTML body, or a plain quote block
that starts with the quoted sender's pill and ends with a blank line.
This branch's _strip_thread_reply_fallback used its own copy of the pill
regex and checked the pill alone. The explicit-reply path in
_extract_reply_context still treated any leading "> " as a fallback,
because this branch's signature passed only formatted_body, and
_has_reply_fallback needs the whole content.

Use _has_reply_fallback for thread messages and for explicit replies,
and remove _strip_thread_reply_fallback and its duplicate regex.
_extract_reply_context now takes source_content as a positional
argument before relates_to, as in NousResearch#128621, and reads formatted_body from
it. The sender and chat_type keywords remain.

Two test expectations change:

- In NousResearch#128621's test_reply_strips_only_a_reply_fallback, the
  thread-message-own-quote case now expects no reply_to_message_id.
  This branch treats m.in_reply_to under is_falling_back as the thread's
  fallback target, not an explicit reply, so the event is not a reply.
  The message text, which is what that case checks, is unchanged.
- test_thread_message_strips_only_the_reply_fallback gains a case for a
  thread message whose quote starts with a pill but has no blank line
  after it. The pill-only rule stripped that quote; the shared rule
  keeps it as the user's text.

The shared rule also strips a thread message's plain quote when the HTML
body starts with <mx-reply>, even without a pill, as it already does for
explicit replies.
iainlane added a commit to iainlane/hermes-agent that referenced this pull request Oct 9, 2026
After the merge of NousResearch#128621, the adapter had two rules for one question:
whether a leading "> " block is a legacy reply fallback or the user's
own quote. NousResearch#128621 added _has_reply_fallback, which requires an
<mx-reply> element at the start of the HTML body, or a plain quote block
that starts with the quoted sender's pill and ends with a blank line.
This branch's _strip_thread_reply_fallback used its own copy of the pill
regex and checked the pill alone. The explicit-reply path in
_extract_reply_context still treated any leading "> " as a fallback,
because this branch's signature passed only formatted_body, and
_has_reply_fallback needs the whole content.

Use _has_reply_fallback for thread messages and for explicit replies,
and remove _strip_thread_reply_fallback and its duplicate regex.
_extract_reply_context now takes source_content as a positional
argument before relates_to, as in NousResearch#128621, and reads formatted_body from
it. The sender and chat_type keywords remain.

Two test expectations change:

- In NousResearch#128621's test_reply_strips_only_a_reply_fallback, the
  thread-message-own-quote case now expects no reply_to_message_id.
  This branch treats m.in_reply_to under is_falling_back as the thread's
  fallback target, not an explicit reply, so the event is not a reply.
  The message text, which is what that case checks, is unchanged.
- test_thread_message_strips_only_the_reply_fallback gains a case for a
  thread message whose quote starts with a pill but has no blank line
  after it. The pill-only rule stripped that quote; the shared rule
  keeps it as the user's text.

The shared rule also strips a thread message's plain quote when the HTML
body starts with <mx-reply>, even without a pill, as it already does for
explicit replies.
iainlane added a commit to iainlane/hermes-agent that referenced this pull request Oct 9, 2026
After the merge of NousResearch#128621, the adapter had two rules for one question:
whether a leading "> " block is a legacy reply fallback or the user's
own quote. NousResearch#128621 added _has_reply_fallback, which requires an
<mx-reply> element at the start of the HTML body, or a plain quote block
that starts with the quoted sender's pill and ends with a blank line.
This branch's _strip_thread_reply_fallback used its own copy of the pill
regex and checked the pill alone. The explicit-reply path in
_extract_reply_context still treated any leading "> " as a fallback,
because this branch's signature passed only formatted_body, and
_has_reply_fallback needs the whole content.

Use _has_reply_fallback for thread messages and for explicit replies,
and remove _strip_thread_reply_fallback and its duplicate regex.
_extract_reply_context now takes source_content as a positional
argument before relates_to, as in NousResearch#128621, and reads formatted_body from
it. The sender and chat_type keywords remain.

Two test expectations change:

- In NousResearch#128621's test_reply_strips_only_a_reply_fallback, the
  thread-message-own-quote case now expects no reply_to_message_id.
  This branch treats m.in_reply_to under is_falling_back as the thread's
  fallback target, not an explicit reply, so the event is not a reply.
  The message text, which is what that case checks, is unchanged.
- test_thread_message_strips_only_the_reply_fallback gains a case for a
  thread message whose quote starts with a pill but has no blank line
  after it. The pill-only rule stripped that quote; the shared rule
  keeps it as the user's text.

The shared rule also strips a thread message's plain quote when the HTML
body starts with <mx-reply>, even without a pill, as it already does for
explicit replies.
iainlane added a commit to iainlane/hermes-agent that referenced this pull request Oct 9, 2026
After the merge of NousResearch#128621, the adapter had two rules for one question:
whether a leading "> " block is a legacy reply fallback or the user's
own quote. NousResearch#128621 added _has_reply_fallback, which requires an
<mx-reply> element at the start of the HTML body, or a plain quote block
that starts with the quoted sender's pill and ends with a blank line.
This branch's _strip_thread_reply_fallback used its own copy of the pill
regex and checked the pill alone. The explicit-reply path in
_extract_reply_context still treated any leading "> " as a fallback,
because this branch's signature passed only formatted_body, and
_has_reply_fallback needs the whole content.

Use _has_reply_fallback for thread messages and for explicit replies,
and remove _strip_thread_reply_fallback and its duplicate regex.
_extract_reply_context now takes source_content as a positional
argument before relates_to, as in NousResearch#128621, and reads formatted_body from
it. The sender and chat_type keywords remain.

Two test expectations change:

- In NousResearch#128621's test_reply_strips_only_a_reply_fallback, the
  thread-message-own-quote case now expects no reply_to_message_id.
  This branch treats m.in_reply_to under is_falling_back as the thread's
  fallback target, not an explicit reply, so the event is not a reply.
  The message text, which is what that case checks, is unchanged.
- test_thread_message_strips_only_the_reply_fallback gains a case for a
  thread message whose quote starts with a pill but has no blank line
  after it. The pill-only rule stripped that quote; the shared rule
  keeps it as the user's text.

The shared rule also strips a thread message's plain quote when the HTML
body starts with <mx-reply>, even without a pill, as it already does for
explicit replies.
iainlane added a commit to iainlane/hermes-agent that referenced this pull request Oct 9, 2026
After the merge of NousResearch#128621, the adapter had two rules for one question:
whether a leading "> " block is a legacy reply fallback or the user's
own quote. NousResearch#128621 added _has_reply_fallback, which requires an
<mx-reply> element at the start of the HTML body, or a plain quote block
that starts with the quoted sender's pill and ends with a blank line.
This branch's _strip_thread_reply_fallback used its own copy of the pill
regex and checked the pill alone. The explicit-reply path in
_extract_reply_context still treated any leading "> " as a fallback,
because this branch's signature passed only formatted_body, and
_has_reply_fallback needs the whole content.

Use _has_reply_fallback for thread messages and for explicit replies,
and remove _strip_thread_reply_fallback and its duplicate regex.
_extract_reply_context now takes source_content as a positional
argument before relates_to, as in NousResearch#128621, and reads formatted_body from
it. The sender and chat_type keywords remain.

Two test expectations change:

- In NousResearch#128621's test_reply_strips_only_a_reply_fallback, the
  thread-message-own-quote case now expects no reply_to_message_id.
  This branch treats m.in_reply_to under is_falling_back as the thread's
  fallback target, not an explicit reply, so the event is not a reply.
  The message text, which is what that case checks, is unchanged.
- test_thread_message_strips_only_the_reply_fallback gains a case for a
  thread message whose quote starts with a pill but has no blank line
  after it. The pill-only rule stripped that quote; the shared rule
  keeps it as the user's text.

The shared rule also strips a thread message's plain quote when the HTML
body starts with <mx-reply>, even without a pill, as it already does for
explicit replies.
iainlane added a commit to iainlane/hermes-agent that referenced this pull request Oct 9, 2026
After the merge of NousResearch#128621, the adapter had two rules for one question:
whether a leading "> " block is a legacy reply fallback or the user's
own quote. NousResearch#128621 added _has_reply_fallback, which requires an
<mx-reply> element at the start of the HTML body, or a plain quote block
that starts with the quoted sender's pill and ends with a blank line.
This branch's _strip_thread_reply_fallback used its own copy of the pill
regex and checked the pill alone. The explicit-reply path in
_extract_reply_context still treated any leading "> " as a fallback,
because this branch's signature passed only formatted_body, and
_has_reply_fallback needs the whole content.

Use _has_reply_fallback for thread messages and for explicit replies,
and remove _strip_thread_reply_fallback and its duplicate regex.
_extract_reply_context now takes source_content as a positional
argument before relates_to, as in NousResearch#128621, and reads formatted_body from
it. The sender and chat_type keywords remain.

Two test expectations change:

- In NousResearch#128621's test_reply_strips_only_a_reply_fallback, the
  thread-message-own-quote case now expects no reply_to_message_id.
  This branch treats m.in_reply_to under is_falling_back as the thread's
  fallback target, not an explicit reply, so the event is not a reply.
  The message text, which is what that case checks, is unchanged.
- test_thread_message_strips_only_the_reply_fallback gains a case for a
  thread message whose quote starts with a pill but has no blank line
  after it. The pill-only rule stripped that quote; the shared rule
  keeps it as the user's text.

The shared rule also strips a thread message's plain quote when the HTML
body starts with <mx-reply>, even without a pill, as it already does for
explicit replies.
iainlane added a commit to iainlane/hermes-agent that referenced this pull request Oct 9, 2026
After the merge of NousResearch#128621, the adapter had two rules for one question:
whether a leading "> " block is a legacy reply fallback or the user's
own quote. NousResearch#128621 added _has_reply_fallback, which requires an
<mx-reply> element at the start of the HTML body, or a plain quote block
that starts with the quoted sender's pill and ends with a blank line.
This branch's _strip_thread_reply_fallback used its own copy of the pill
regex and checked the pill alone. The explicit-reply path in
_extract_reply_context still treated any leading "> " as a fallback,
because this branch's signature passed only formatted_body, and
_has_reply_fallback needs the whole content.

Use _has_reply_fallback for thread messages and for explicit replies,
and remove _strip_thread_reply_fallback and its duplicate regex.
_extract_reply_context now takes source_content as a positional
argument before relates_to, as in NousResearch#128621, and reads formatted_body from
it. The sender and chat_type keywords remain.

Two test expectations change:

- In NousResearch#128621's test_reply_strips_only_a_reply_fallback, the
  thread-message-own-quote case now expects no reply_to_message_id.
  This branch treats m.in_reply_to under is_falling_back as the thread's
  fallback target, not an explicit reply, so the event is not a reply.
  The message text, which is what that case checks, is unchanged.
- test_thread_message_strips_only_the_reply_fallback gains a case for a
  thread message whose quote starts with a pill but has no blank line
  after it. The pill-only rule stripped that quote; the shared rule
  keeps it as the user's text.

The shared rule also strips a thread message's plain quote when the HTML
body starts with <mx-reply>, even without a pill, as it already does for
explicit replies.
iainlane added a commit to iainlane/hermes-agent that referenced this pull request Oct 9, 2026
After the merge of NousResearch#128621, the adapter had two rules for one question:
whether a leading "> " block is a legacy reply fallback or the user's
own quote. NousResearch#128621 added _has_reply_fallback, which requires an
<mx-reply> element at the start of the HTML body, or a plain quote block
that starts with the quoted sender's pill and ends with a blank line.
This branch's _strip_thread_reply_fallback used its own copy of the pill
regex and checked the pill alone. The explicit-reply path in
_extract_reply_context still treated any leading "> " as a fallback,
because this branch's signature passed only formatted_body, and
_has_reply_fallback needs the whole content.

Use _has_reply_fallback for thread messages and for explicit replies,
and remove _strip_thread_reply_fallback and its duplicate regex.
_extract_reply_context now takes source_content as a positional
argument before relates_to, as in NousResearch#128621, and reads formatted_body from
it. The sender and chat_type keywords remain.

Two test expectations change:

- In NousResearch#128621's test_reply_strips_only_a_reply_fallback, the
  thread-message-own-quote case now expects no reply_to_message_id.
  This branch treats m.in_reply_to under is_falling_back as the thread's
  fallback target, not an explicit reply, so the event is not a reply.
  The message text, which is what that case checks, is unchanged.
- test_thread_message_strips_only_the_reply_fallback gains a case for a
  thread message whose quote starts with a pill but has no blank line
  after it. The pill-only rule stripped that quote; the shared rule
  keeps it as the user's text.

The shared rule also strips a thread message's plain quote when the HTML
body starts with <mx-reply>, even without a pill, as it already does for
explicit replies.
iainlane added a commit to iainlane/hermes-agent that referenced this pull request Oct 9, 2026
After the merge of NousResearch#128621, the adapter had two rules for one question:
whether a leading "> " block is a legacy reply fallback or the user's
own quote. NousResearch#128621 added _has_reply_fallback, which requires an
<mx-reply> element at the start of the HTML body, or a plain quote block
that starts with the quoted sender's pill and ends with a blank line.
This branch's _strip_thread_reply_fallback used its own copy of the pill
regex and checked the pill alone. The explicit-reply path in
_extract_reply_context still treated any leading "> " as a fallback,
because this branch's signature passed only formatted_body, and
_has_reply_fallback needs the whole content.

Use _has_reply_fallback for thread messages and for explicit replies,
and remove _strip_thread_reply_fallback and its duplicate regex.
_extract_reply_context now takes source_content as a positional
argument before relates_to, as in NousResearch#128621, and reads formatted_body from
it. The sender and chat_type keywords remain.

Two test expectations change:

- In NousResearch#128621's test_reply_strips_only_a_reply_fallback, the
  thread-message-own-quote case now expects no reply_to_message_id.
  This branch treats m.in_reply_to under is_falling_back as the thread's
  fallback target, not an explicit reply, so the event is not a reply.
  The message text, which is what that case checks, is unchanged.
- test_thread_message_strips_only_the_reply_fallback gains a case for a
  thread message whose quote starts with a pill but has no blank line
  after it. The pill-only rule stripped that quote; the shared rule
  keeps it as the user's text.

The shared rule also strips a thread message's plain quote when the HTML
body starts with <mx-reply>, even without a pill, as it already does for
explicit replies.
iainlane added a commit to iainlane/hermes-agent that referenced this pull request Oct 9, 2026
After the merge of NousResearch#128621, the adapter had two rules for one question:
whether a leading "> " block is a legacy reply fallback or the user's
own quote. NousResearch#128621 added _has_reply_fallback, which requires an
<mx-reply> element at the start of the HTML body, or a plain quote block
that starts with the quoted sender's pill and ends with a blank line.
This branch's _strip_thread_reply_fallback used its own copy of the pill
regex and checked the pill alone. The explicit-reply path in
_extract_reply_context still treated any leading "> " as a fallback,
because this branch's signature passed only formatted_body, and
_has_reply_fallback needs the whole content.

Use _has_reply_fallback for thread messages and for explicit replies,
and remove _strip_thread_reply_fallback and its duplicate regex.
_extract_reply_context now takes source_content as a positional
argument before relates_to, as in NousResearch#128621, and reads formatted_body from
it. The sender and chat_type keywords remain.

Two test expectations change:

- In NousResearch#128621's test_reply_strips_only_a_reply_fallback, the
  thread-message-own-quote case now expects no reply_to_message_id.
  This branch treats m.in_reply_to under is_falling_back as the thread's
  fallback target, not an explicit reply, so the event is not a reply.
  The message text, which is what that case checks, is unchanged.
- test_thread_message_strips_only_the_reply_fallback gains a case for a
  thread message whose quote starts with a pill but has no blank line
  after it. The pill-only rule stripped that quote; the shared rule
  keeps it as the user's text.

The shared rule also strips a thread message's plain quote when the HTML
body starts with <mx-reply>, even without a pill, as it already does for
explicit replies.
iainlane added a commit to iainlane/hermes-agent that referenced this pull request Oct 9, 2026
After the merge of NousResearch#128621, the adapter had two rules for one question:
whether a leading "> " block is a legacy reply fallback or the user's
own quote. NousResearch#128621 added _has_reply_fallback, which requires an
<mx-reply> element at the start of the HTML body, or a plain quote block
that starts with the quoted sender's pill and ends with a blank line.
This branch's _strip_thread_reply_fallback used its own copy of the pill
regex and checked the pill alone. The explicit-reply path in
_extract_reply_context still treated any leading "> " as a fallback,
because this branch's signature passed only formatted_body, and
_has_reply_fallback needs the whole content.

Use _has_reply_fallback for thread messages and for explicit replies,
and remove _strip_thread_reply_fallback and its duplicate regex.
_extract_reply_context now takes source_content as a positional
argument before relates_to, as in NousResearch#128621, and reads formatted_body from
it. The sender and chat_type keywords remain.

Two test expectations change:

- In NousResearch#128621's test_reply_strips_only_a_reply_fallback, the
  thread-message-own-quote case now expects no reply_to_message_id.
  This branch treats m.in_reply_to under is_falling_back as the thread's
  fallback target, not an explicit reply, so the event is not a reply.
  The message text, which is what that case checks, is unchanged.
- test_thread_message_strips_only_the_reply_fallback gains a case for a
  thread message whose quote starts with a pill but has no blank line
  after it. The pill-only rule stripped that quote; the shared rule
  keeps it as the user's text.

The shared rule also strips a thread message's plain quote when the HTML
body starts with <mx-reply>, even without a pill, as it already does for
explicit replies.
iainlane added a commit to iainlane/hermes-agent that referenced this pull request Oct 9, 2026
After the merge of NousResearch#128621, the adapter had two rules for one question:
whether a leading "> " block is a legacy reply fallback or the user's
own quote. NousResearch#128621 added _has_reply_fallback, which requires an
<mx-reply> element at the start of the HTML body, or a plain quote block
that starts with the quoted sender's pill and ends with a blank line.
This branch's _strip_thread_reply_fallback used its own copy of the pill
regex and checked the pill alone. The explicit-reply path in
_extract_reply_context still treated any leading "> " as a fallback,
because this branch's signature passed only formatted_body, and
_has_reply_fallback needs the whole content.

Use _has_reply_fallback for thread messages and for explicit replies,
and remove _strip_thread_reply_fallback and its duplicate regex.
_extract_reply_context now takes source_content as a positional
argument before relates_to, as in NousResearch#128621, and reads formatted_body from
it. The sender and chat_type keywords remain.

Two test expectations change:

- In NousResearch#128621's test_reply_strips_only_a_reply_fallback, the
  thread-message-own-quote case now expects no reply_to_message_id.
  This branch treats m.in_reply_to under is_falling_back as the thread's
  fallback target, not an explicit reply, so the event is not a reply.
  The message text, which is what that case checks, is unchanged.
- test_thread_message_strips_only_the_reply_fallback gains a case for a
  thread message whose quote starts with a pill but has no blank line
  after it. The pill-only rule stripped that quote; the shared rule
  keeps it as the user's text.

The shared rule also strips a thread message's plain quote when the HTML
body starts with <mx-reply>, even without a pill, as it already does for
explicit replies.
iainlane added a commit to iainlane/hermes-agent that referenced this pull request Oct 9, 2026
After the merge of NousResearch#128621, the adapter had two rules for one question:
whether a leading "> " block is a legacy reply fallback or the user's
own quote. NousResearch#128621 added _has_reply_fallback, which requires an
<mx-reply> element at the start of the HTML body, or a plain quote block
that starts with the quoted sender's pill and ends with a blank line.
This branch's _strip_thread_reply_fallback used its own copy of the pill
regex and checked the pill alone. The explicit-reply path in
_extract_reply_context still treated any leading "> " as a fallback,
because this branch's signature passed only formatted_body, and
_has_reply_fallback needs the whole content.

Use _has_reply_fallback for thread messages and for explicit replies,
and remove _strip_thread_reply_fallback and its duplicate regex.
_extract_reply_context now takes source_content as a positional
argument before relates_to, as in NousResearch#128621, and reads formatted_body from
it. The sender and chat_type keywords remain.

Two test expectations change:

- In NousResearch#128621's test_reply_strips_only_a_reply_fallback, the
  thread-message-own-quote case now expects no reply_to_message_id.
  This branch treats m.in_reply_to under is_falling_back as the thread's
  fallback target, not an explicit reply, so the event is not a reply.
  The message text, which is what that case checks, is unchanged.
- test_thread_message_strips_only_the_reply_fallback gains a case for a
  thread message whose quote starts with a pill but has no blank line
  after it. The pill-only rule stripped that quote; the shared rule
  keeps it as the user's text.

The shared rule also strips a thread message's plain quote when the HTML
body starts with <mx-reply>, even without a pill, as it already does for
explicit replies.
iainlane added a commit to iainlane/hermes-agent that referenced this pull request Oct 10, 2026
After the merge of NousResearch#128621, the adapter had two rules for one question:
whether a leading "> " block is a legacy reply fallback or the user's
own quote. NousResearch#128621 added _has_reply_fallback, which requires an
<mx-reply> element at the start of the HTML body, or a plain quote block
that starts with the quoted sender's pill and ends with a blank line.
This branch's _strip_thread_reply_fallback used its own copy of the pill
regex and checked the pill alone. The explicit-reply path in
_extract_reply_context still treated any leading "> " as a fallback,
because this branch's signature passed only formatted_body, and
_has_reply_fallback needs the whole content.

Use _has_reply_fallback for thread messages and for explicit replies,
and remove _strip_thread_reply_fallback and its duplicate regex.
_extract_reply_context now takes source_content as a positional
argument before relates_to, as in NousResearch#128621, and reads formatted_body from
it. The sender and chat_type keywords remain.

Two test expectations change:

- In NousResearch#128621's test_reply_strips_only_a_reply_fallback, the
  thread-message-own-quote case now expects no reply_to_message_id.
  This branch treats m.in_reply_to under is_falling_back as the thread's
  fallback target, not an explicit reply, so the event is not a reply.
  The message text, which is what that case checks, is unchanged.
- test_thread_message_strips_only_the_reply_fallback gains a case for a
  thread message whose quote starts with a pill but has no blank line
  after it. The pill-only rule stripped that quote; the shared rule
  keeps it as the user's text.

The shared rule also strips a thread message's plain quote when the HTML
body starts with <mx-reply>, even without a pill, as it already does for
explicit replies.
iainlane added a commit to iainlane/hermes-agent that referenced this pull request Oct 10, 2026
After the merge of NousResearch#128621, the adapter had two rules for one question:
whether a leading "> " block is a legacy reply fallback or the user's
own quote. NousResearch#128621 added _has_reply_fallback, which requires an
<mx-reply> element at the start of the HTML body, or a plain quote block
that starts with the quoted sender's pill and ends with a blank line.
This branch's _strip_thread_reply_fallback used its own copy of the pill
regex and checked the pill alone. The explicit-reply path in
_extract_reply_context still treated any leading "> " as a fallback,
because this branch's signature passed only formatted_body, and
_has_reply_fallback needs the whole content.

Use _has_reply_fallback for thread messages and for explicit replies,
and remove _strip_thread_reply_fallback and its duplicate regex.
_extract_reply_context now takes source_content as a positional
argument before relates_to, as in NousResearch#128621, and reads formatted_body from
it. The sender and chat_type keywords remain.

Two test expectations change:

- In NousResearch#128621's test_reply_strips_only_a_reply_fallback, the
  thread-message-own-quote case now expects no reply_to_message_id.
  This branch treats m.in_reply_to under is_falling_back as the thread's
  fallback target, not an explicit reply, so the event is not a reply.
  The message text, which is what that case checks, is unchanged.
- test_thread_message_strips_only_the_reply_fallback gains a case for a
  thread message whose quote starts with a pill but has no blank line
  after it. The pill-only rule stripped that quote; the shared rule
  keeps it as the user's text.

The shared rule also strips a thread message's plain quote when the HTML
body starts with <mx-reply>, even without a pill, as it already does for
explicit replies.
iainlane added a commit to iainlane/hermes-agent that referenced this pull request Oct 10, 2026
After the merge of NousResearch#128621, the adapter had two rules for one question:
whether a leading "> " block is a legacy reply fallback or the user's
own quote. NousResearch#128621 added _has_reply_fallback, which requires an
<mx-reply> element at the start of the HTML body, or a plain quote block
that starts with the quoted sender's pill and ends with a blank line.
This branch's _strip_thread_reply_fallback used its own copy of the pill
regex and checked the pill alone. The explicit-reply path in
_extract_reply_context still treated any leading "> " as a fallback,
because this branch's signature passed only formatted_body, and
_has_reply_fallback needs the whole content.

Use _has_reply_fallback for thread messages and for explicit replies,
and remove _strip_thread_reply_fallback and its duplicate regex.
_extract_reply_context now takes source_content as a positional
argument before relates_to, as in NousResearch#128621, and reads formatted_body from
it. The sender and chat_type keywords remain.

Two test expectations change:

- In NousResearch#128621's test_reply_strips_only_a_reply_fallback, the
  thread-message-own-quote case now expects no reply_to_message_id.
  This branch treats m.in_reply_to under is_falling_back as the thread's
  fallback target, not an explicit reply, so the event is not a reply.
  The message text, which is what that case checks, is unchanged.
- test_thread_message_strips_only_the_reply_fallback gains a case for a
  thread message whose quote starts with a pill but has no blank line
  after it. The pill-only rule stripped that quote; the shared rule
  keeps it as the user's text.

The shared rule also strips a thread message's plain quote when the HTML
body starts with <mx-reply>, even without a pill, as it already does for
explicit replies.
iainlane added a commit to iainlane/hermes-agent that referenced this pull request Oct 11, 2026
After the merge of NousResearch#128621, the adapter had two rules for one question:
whether a leading "> " block is a legacy reply fallback or the user's
own quote. NousResearch#128621 added _has_reply_fallback, which requires an
<mx-reply> element at the start of the HTML body, or a plain quote block
that starts with the quoted sender's pill and ends with a blank line.
This branch's _strip_thread_reply_fallback used its own copy of the pill
regex and checked the pill alone. The explicit-reply path in
_extract_reply_context still treated any leading "> " as a fallback,
because this branch's signature passed only formatted_body, and
_has_reply_fallback needs the whole content.

Use _has_reply_fallback for thread messages and for explicit replies,
and remove _strip_thread_reply_fallback and its duplicate regex.
_extract_reply_context now takes source_content as a positional
argument before relates_to, as in NousResearch#128621, and reads formatted_body from
it. The sender and chat_type keywords remain.

Two test expectations change:

- In NousResearch#128621's test_reply_strips_only_a_reply_fallback, the
  thread-message-own-quote case now expects no reply_to_message_id.
  This branch treats m.in_reply_to under is_falling_back as the thread's
  fallback target, not an explicit reply, so the event is not a reply.
  The message text, which is what that case checks, is unchanged.
- test_thread_message_strips_only_the_reply_fallback gains a case for a
  thread message whose quote starts with a pill but has no blank line
  after it. The pill-only rule stripped that quote; the shared rule
  keeps it as the user's text.

The shared rule also strips a thread message's plain quote when the HTML
body starts with <mx-reply>, even without a pill, as it already does for
explicit replies.
HarshitRuwali pushed a commit to HarshitRuwali/hermes-agent that referenced this pull request Oct 13, 2026
After the merge of NousResearch#128621, the adapter had two rules for one question:
whether a leading "> " block is a legacy reply fallback or the user's
own quote. NousResearch#128621 added _has_reply_fallback, which requires an
<mx-reply> element at the start of the HTML body, or a plain quote block
that starts with the quoted sender's pill and ends with a blank line.
This branch's _strip_thread_reply_fallback used its own copy of the pill
regex and checked the pill alone. The explicit-reply path in
_extract_reply_context still treated any leading "> " as a fallback,
because this branch's signature passed only formatted_body, and
_has_reply_fallback needs the whole content.

Use _has_reply_fallback for thread messages and for explicit replies,
and remove _strip_thread_reply_fallback and its duplicate regex.
_extract_reply_context now takes source_content as a positional
argument before relates_to, as in NousResearch#128621, and reads formatted_body from
it. The sender and chat_type keywords remain.

Two test expectations change:

- In NousResearch#128621's test_reply_strips_only_a_reply_fallback, the
  thread-message-own-quote case now expects no reply_to_message_id.
  This branch treats m.in_reply_to under is_falling_back as the thread's
  fallback target, not an explicit reply, so the event is not a reply.
  The message text, which is what that case checks, is unchanged.
- test_thread_message_strips_only_the_reply_fallback gains a case for a
  thread message whose quote starts with a pill but has no blank line
  after it. The pill-only rule stripped that quote; the shared rule
  keeps it as the user's text.

The shared rule also strips a thread message's plain quote when the HTML
body starts with <mx-reply>, even without a pill, as it already does for
explicit replies.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/plugins Plugin system and bundled plugins P3 Low — cosmetic, nice to have platform/matrix Matrix adapter (E2EE) sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants