@floomhq/signaldash 0.43.0 → 0.43.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -121,7 +121,7 @@ setup installs both from the same pinned npm package
121
121
  the human chose to execute:
122
122
 
123
123
  ```bash
124
- npx -y @floomhq/signaldash@0.43.0 <invite-code>
124
+ npx -y @floomhq/signaldash@0.43.1 <invite-code>
125
125
  ```
126
126
 
127
127
  Run that command in a terminal, not in an agent chat. Do not ask an agent to
@@ -201,7 +201,7 @@ timer, scheduler entry, Buffer item, or provider write.
201
201
  - `sd_withdrawal_batch_approve(withdrawal_batch_id, confirm_token)`
202
202
  - `sd_withdrawal_batch_cancel(withdrawal_batch_id, approval_view_hash, confirm)`
203
203
  - `wa_list_chats`
204
- - `wa_read_messages(chat_id)`
204
+ - `wa_read_messages(chat_id, limit?, cursor?)`
205
205
  - `wa_mark_read(chat_id)`
206
206
  - `wa_get_attachment(chat_id, message_id, attachment_id)`
207
207
  - `wa_transcribe_voice(chat_id, message_id, attachment_id)`
@@ -209,6 +209,42 @@ timer, scheduler entry, Buffer item, or provider write.
209
209
  - `wa_send_message(chat_id, text?, attachments?, expected_watermark?, mark_read?)` — confirmed sends clear unread by default; `mark_read:false` preserves unread.
210
210
  - `wa_delete_message(chat_id, message_id)`
211
211
  - `wa_delete_messages(messages)`
212
+
213
+ WhatsApp history is paginated, not limited to the newest 100 messages. Read
214
+ `wa_read_messages` with `limit:250`, then pass the exact returned `cursor`
215
+ unchanged to the same chat to read older pages. Each call fetches at most one
216
+ provider message page; there is no automatic bulk scan. Pace requests, set a
217
+ finite page/message budget, and stop on provider warnings, authentication
218
+ errors, 403/429, a repeated cursor, or an explicit null cursor. Empty pages
219
+ with a new cursor can still lead to more history.
220
+
221
+ The provider's `items` or `messages` envelope and cursor are preserved.
222
+ `history_pagination` reports `response_shape_supported`, requested limit, returned item count, next cursor,
223
+ `has_more` (null when unknown), `provider_exhausted`, and `cursor_advancing`.
224
+ Only an explicit null cursor on a recognized list proves provider exhaustion;
225
+ missing pagination or an unfamiliar envelope is unknown, never proof that a
226
+ message does not exist. Even exhausted provider history may be incomplete if
227
+ older history was never synchronized by the provider.
228
+
229
+ Continuation cursors must have been issued to this authenticated user, account
230
+ and exact chat. They live in a bounded in-memory registry for 60 minutes;
231
+ restart, expiry or an unissued/wrong-scope cursor requires a fresh first page
232
+ without cursor. At most one read per cursor runs concurrently. Successful
233
+ continuation consumes that receipt and registers the next cursor atomically;
234
+ provider/validation failures preserve it for retry. Registry bounds are 4,096
235
+ globally, 512 per user and 128 per account/chat, with no live-entry eviction.
236
+ Capacity returns an explicit error. Invalid provider cursors, mismatched
237
+ account/chat rows and unsupported historical response shapes are refused
238
+ without returning message contents.
239
+
240
+ Cursor pages return `history_page:true` and `current_watermark:null`. They
241
+ neither create nor refresh a send-read proof nor update reply/contact
242
+ observations or mark the chat read. Existing latest-page proofs are preserved.
243
+ Before sending, read the latest page again **without cursor**. Cursor support
244
+ does not change provider base URLs/API versions, send budgets, or account limits.
245
+ The default stays 30 messages. WhatsApp's explicit per-page maximum is 250,
246
+ matching the [provider's message endpoint](https://developer.unipile.com/reference/chatscontroller_listchatmessages.md);
247
+ LinkedIn/Instagram reads and chat-list caps remain 100.
212
248
  - `ig_list_chats(limit?, cursor?, search?, max_scan?, unread?)`
213
249
  - `ig_read_messages(chat_id, limit?)`
214
250
  - `ig_mark_read(chat_id)`
package/bin/sd.mjs CHANGED
@@ -1504,12 +1504,13 @@ const TOOLS = [
1504
1504
  name: "wa_read_messages",
1505
1505
  ch: "wa",
1506
1506
  action: "read",
1507
- description: "Read messages and the resolved chat in one WhatsApp thread. Messages include sender_name where the exact sender can be resolved. args: chat_id",
1507
+ description: "Read one bounded page of messages and the resolved WhatsApp chat. Use limit up to 250 and the returned cursor to reach older history, one paced page at a time. Cursor pages never authorize sends or update reply observations; read without cursor immediately before sending. Missing history is not proof of absence. args: chat_id, limit, cursor",
1508
1508
  inputSchema: {
1509
1509
  type: "object",
1510
1510
  properties: {
1511
1511
  chat_id: { type: "string", minLength: 1, maxLength: 500 },
1512
- limit: { type: "integer", minimum: 1, maximum: 100 },
1512
+ limit: { type: "integer", minimum: 1, maximum: 250 },
1513
+ cursor: { type: "string", minLength: 1, maxLength: 4000, description: "Exact opaque cursor from the preceding page, unchanged. Omit for the latest page." },
1513
1514
  },
1514
1515
  required: ["chat_id"],
1515
1516
  additionalProperties: false,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@floomhq/signaldash",
3
- "version": "0.43.0",
3
+ "version": "0.43.1",
4
4
  "description": "Secure LinkedIn, WhatsApp, and email access for AI agents",
5
5
  "type": "module",
6
6
  "bin": {
@@ -446,7 +446,7 @@ Use the exact tool names and argument keys below. Limits are optional.
446
446
  | `sd_withdrawal_batch_approve` | `withdrawal_batch_id` required; `confirm_token` required in the exact `sd-xxxx-xxxx-xxxx` form the human read off the approval page | Record the human's approval using the single-use code that authenticated page minted for them. An agent cannot mint, guess, or bypass that code. |
447
447
  | `sd_withdrawal_batch_cancel` | `withdrawal_batch_id` required; `approval_view_hash` required string or null exactly as inspected; `confirm:true` required | Revoke the approval and stop every withdrawal that has not started. It cannot recall one already submitted, and it cannot restore the three-week re-invite block for people already withdrawn. |
448
448
  | `wa_list_chats` | `limit` integer 1-100, default 20; `cursor` optional; `search` optional string, max 200 characters; `max_scan` optional integer 1-500, default 200, and never more than five provider pages | Find an existing WhatsApp conversation and exact `chat_id`. Direct chats expose a resolved contact in both `name` and `attendee_name` when available; groups retain their provider group `name` and return `attendee_name:null`. With `search` it filters case-insensitively on `name`, `subject`, `id`, `provider_id`, `attendee_provider_id`, `attendee_public_identifier`, and `attendee_name`. The attendee identifiers can carry a phone JID or `@lid`, and digit normalization makes bare or formatted identifiers match their stored form, such as `+49 151 67609512`, `004915167609512`, `4915167609512@s.whatsapp.net`, or the bare digits from `202726935924973@lid`. The provider CANNOT filter a chat list, so SignalDash scans and filters: read `search.exhaustive` before you conclude anything, `search.limit_reached` to know whether the matches were truncated by `limit`, and `search.searched_fields` for what was actually compared. `false` means "not among the `scanned_chats` scanned", never "does not exist" -- continue from the returned `cursor`. When `started_from_cursor` is true the scan began mid-list, so even `exhaustive` says nothing about the chats before that cursor. Search an exact phone number, lid, or known attendee name rather than guessing. Any other key, including `text` and `member_id`, is refused with `unsupported_parameter`. |
449
- | `wa_read_messages` | `chat_id` required; `limit` 1-100, default 30 | Verify a WhatsApp contact and recent history before summarizing, drafting, or sending. The response includes `current_watermark` for an exact compare-and-swap send. |
449
+ | `wa_read_messages` | `chat_id` required; `limit` 1-250, default 30; optional `cursor` from the previous page, unchanged, max 4000 characters | Read one bounded WhatsApp page. Start without cursor; follow issued `history_pagination.next_cursor` with paced calls and a finite page/message budget. Historical pages return `history_page:true`, `current_watermark:null`, and never refresh send-read proofs or reply/contact observations. Cursors are scoped to this user/account/chat, expire after 60 minutes or restart, and permit one active read at a time; an invalid cursor requires a fresh first page. Inspect `has_more`, `provider_exhausted`, and `cursor_advancing`; missing pagination is unknown, not absence, and repeated cursors require stopping. Stop on provider warnings, authentication errors or 403/429. Read the latest page again without cursor before sending. |
450
450
  | `wa_mark_read` | `chat_id` required | Explicitly clear one WhatsApp chat's unread state. Reading never clears unread automatically. |
451
451
  | `wa_get_attachment` | `chat_id`, `message_id`, `attachment_id` all required, max 500 characters each | Download one attachment of one message in a chat this account owns. Read the chat first: the exact `message_id` and `attachment_id` come from `wa_read_messages`. Returns the stored path on the SignalDash host, mimetype, byte size and sha256. |
452
452
  | `wa_transcribe_voice` | `chat_id`, `message_id`, `attachment_id` all required, max 500 characters each; `backend` optional, exactly `gemini` or `whisper` | Turn one WhatsApp voice note into text through SignalDash instead of fetching provider bytes yourself. Always read the returned `backend`: `gemini` is the accurate default, `whisper-small` is the weak local fallback and mangles German with English terms mixed in, and a fallback also carries `fallback_reason`. Non-audio attachments are refused with `415 not_audio`; an unknown backend with `400 unknown_backend`; a transcription that exceeds its time limit returns `504 transcription_timeout` with the stored audio path. |