Add on-demand history sync request - #215
Open
osyris wants to merge 3 commits into
Open
Conversation
WhatsApp keeps no server-side archive for a linked device, so messages older than what a client already holds can only be obtained by asking the primary device for them. whatsmeow supports this through BuildHistorySyncRequest + SendPeerMessage, but neither was bound, leaving no way to reach history from Python. Expose the pair as a single call. The request is anchored on a message the client already has; the phone answers with up to `count` messages immediately preceding it, delivered asynchronously as a HistorySync event with syncType ON_DEMAND. Paging further back is a matter of re-anchoring on the oldest message held and calling again. - goneonize: RequestHistorySync export, following the existing pattern - _binder: ctypes signature - client: NewClient.request_history_sync() Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Peer messages carry the whole PeerDataOperationRequest family — on-demand history, full history sync over a time window, placeholder resends for messages that failed to decrypt, chunk retries. whatsmeow ships a builder for only one of them, so binding each operation separately would mean a new export every time a caller needs another. Take a constructed waE2E.Message instead and let the caller choose the operation. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Every message addressed to a person carried a <bot biz_bot="1"/> node, and the recipient's WhatsApp renders it as an "AI" badge. It is also a claim about the account rather than about the message: traffic marked automated is judged as automated. A library cannot know whether its caller wants that claim made. The caller that does can say so; the caller that does not should not have to discover the node exists to be rid of it. So NEONIZE_BOT_TAG turns it on instead of off, and the default is silence. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The gap
A linked device has no server-side archive to read from: WhatsApp hands over a
shallow slice of history once at pairing time and never resends it. Anything
older lives on the phone.
whatsmeow covers this with
BuildHistorySyncRequest+SendPeerMessage, butneither is bound in neonize, so from Python there is currently no way to reach
messages older than whatever arrived at pairing. In practice that means a few
messages per chat.
The change
Exposes the pair as one call.
goneonize:RequestHistorySyncexport, following the surrounding pattern(
ProtoReturnV3,clients,utils.DecodeJidProto,SendMessageReturnFunction)_binder.py: ctypes signatureclient.py:NewClient.request_history_sync(chat, message_id, from_me, timestamp, count=50)The request is anchored on a message the caller already holds; the phone answers
with up to
countmessages immediately preceding it. As documented upstream, theanswer is asynchronous — it arrives as a
HistorySyncEvwhoseData.syncTypeisON_DEMAND, not as this call's return value. Paging furtherback is re-anchoring on the oldest message held and calling again.
Two caveats worth knowing, both inherent to the mechanism rather than to this
binding: the phone must be online to answer, and
count=50is what whatsmeowrecommends per request.
Testing
Verified against a live linked account.
countmessages, roughly 4s round trip.full, taking one group chat from 728 to 2327 messages and its oldest message
from 2026-06-10 back to 2025-11-29.
would expect at a real boundary: a short chunk (42 of 50) followed by an
immediate empty answer. Final state for that chat was 3619 messages spanning a
full year, up from 728 at pairing.
build: request accepted,
syncType=6, 50 messages returned.No existing exports or signatures are touched; the change is additive.