Files
sim/apps/sim/tools/whatsapp/mark_read.ts
T
Waleed d878f15815 feat(integrations): extend Airtable, Google Docs, WhatsApp, and Excel tool depth (#5256)
* feat(airtable): add delete and upsert record tools

* feat(google-docs): add batchUpdate text, table, image, and style tools

* feat(whatsapp): add template, media, interactive, reaction, and mark-read tools

* feat(microsoft-excel): add clear, format, create-table, sort, and delete-worksheet tools

* fix(integrations): address review feedback

- google-docs: use camelCase fontSize field mask; normalize string booleans for bold/italic/underline and matchCase
- microsoft-excel: escape OData single quotes in worksheet/table keys; validate range for clear/format
- airtable: enforce batch limits (delete <=10 ids, upsert <=10 records and 1-3 merge fields) with clear errors

* fix(integrations): address round-2 review

- airtable: coerce upsert typecast as string-aware boolean (string "false" no longer truthy)
- microsoft-excel: format_range surfaces precise partial-state error when fill PATCH fails after font (no atomic font+fill endpoint in Graph)

* fix(whatsapp): treat 2xx mark-as-read as success unless body says success:false

* fix(integrations): build fix, doc accuracy, and comment cleanup

- google-docs: align manualDocumentId condition with the document selector so the documentId canonical group has matching conditions (fixes canonical-pair block test / build)
- microsoft-excel: describe fill/font color as hex code only (Graph does not reliably accept named colors)
- remove verbose explanatory inline comments from new tools (keep idiomatic section dividers)
- regenerate integration docs + integrations.json catalog from the block registry

* fix(integrations): harden delete-record id coercion and excel sort-column validation

- airtable: coerce recordIds entries via String() so numeric JSON values don't crash on .trim()
- microsoft-excel: drop the silent sortColumn default to 0 so invalid input surfaces the tool's clear validation error (both v1 and v2 blocks)

* fix(airtable): coerce upsert fieldsToMergeOn entries via String() to handle non-string values
2026-06-28 22:42:32 -07:00

77 lines
2.3 KiB
TypeScript

import type { ToolConfig } from '@/tools/types'
import type { WhatsAppMarkReadParams, WhatsAppMarkReadResponse } from '@/tools/whatsapp/types'
import { buildAuthHeaders, buildMessagesUrl, isRecord } from '@/tools/whatsapp/utils'
export const markReadTool: ToolConfig<WhatsAppMarkReadParams, WhatsAppMarkReadResponse> = {
id: 'whatsapp_mark_read',
name: 'WhatsApp Mark As Read',
description: 'Mark a received WhatsApp message as read so the sender sees blue checkmarks.',
version: '1.0.0',
params: {
messageId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'ID (wamid) of the incoming message to mark as read',
},
phoneNumberId: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'WhatsApp Business Phone Number ID (from Meta Business Suite)',
},
accessToken: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'WhatsApp Business API Access Token (from Meta Developer Portal)',
},
},
request: {
url: (params) => buildMessagesUrl(params.phoneNumberId),
method: 'POST',
headers: (params) => buildAuthHeaders(params.accessToken),
body: (params) => {
if (!params.messageId) {
throw new Error('Message ID is required but was not provided')
}
return {
messaging_product: 'whatsapp',
status: 'read',
message_id: params.messageId.trim(),
}
},
},
transformResponse: async (response: Response) => {
const responseText = await response.text()
const parsed = responseText ? (JSON.parse(responseText) as unknown) : {}
const data = isRecord(parsed) ? parsed : {}
const error = isRecord(data.error) ? data.error : undefined
if (!response.ok) {
const errorMessage =
(typeof error?.message === 'string' ? error.message : undefined) ||
(typeof error?.error_user_msg === 'string' ? error.error_user_msg : undefined) ||
`WhatsApp API error (${response.status})`
throw new Error(errorMessage)
}
return {
success: true,
output: {
success: data.success !== false,
},
}
},
outputs: {
success: {
type: 'boolean',
description: 'Whether the message was successfully marked as read',
},
},
}