Skip to content

fix(sendgrid): fix active field coercion, add pagination, tighten output typing#5368

Open
waleedlatif1 wants to merge 6 commits into
stagingfrom
worktree-sendgrid-validate
Open

fix(sendgrid): fix active field coercion, add pagination, tighten output typing#5368
waleedlatif1 wants to merge 6 commits into
stagingfrom
worktree-sendgrid-validate

Conversation

@waleedlatif1

Copy link
Copy Markdown
Collaborator

Summary

  • Fixed the active field on Create Template Version being sent to SendGrid as the string "true"/"false" instead of the required int 0/1 — this would fail on every default (non-advanced-mode) run
  • Added missing authMode: ApiKey on the SendGrid block
  • Added pageToken/nextPageToken pagination support to List Templates and List All Lists (SendGrid's page_token cursor, parsed from _metadata.next)
  • Fixed nullable output fields to consistently use ?? null / ?? [] with optional: true across get_contact, search_contacts, remove_contacts_from_list, create_template_version, add_contact, send_mail
  • Removed a dead data.templates fallback in list_templates (the API only ever returns result)
  • Removed unused UpdateContactParams/UpdateListParams/UpdateTemplateParams dead types; made CreateTemplateParams.generation optional to match actual tool behavior

Validated the full 16-tool integration against SendGrid's v3 API docs (Mail Send, Contacts, Lists, Transactional Templates/Versions) — all endpoints, params, and response shapes are aligned with current live API behavior. No fields were renamed or removed.

Type of Change

  • Bug fix
  • Improvement

Testing

Tested manually (tsc + biome clean on all touched files)

Checklist

  • Code follows project style guidelines
  • Self-reviewed my changes
  • Tests added/updated and passing
  • No new warnings introduced
  • I confirm that I have read and agree to the terms outlined in the Contributor License Agreement (CLA)

…put typing

- Fix active field for create_template_version being sent as the string
  "true"/"false" instead of the SendGrid-required int 0/1
- Add missing authMode: ApiKey on SendGridBlock
- Add pageToken/nextPageToken pagination support to list_templates and
  list_all_lists (SendGrid page_token cursor, parsed from _metadata.next)
- Fix nullable output fields to use ?? null / ?? [] with optional: true
  across get_contact, search_contacts, remove_contacts_from_list,
  create_template_version, add_contact, send_mail
- Remove dead data.templates fallback in list_templates (API only
  ever returns result)
- Remove unused UpdateContactParams/UpdateListParams/UpdateTemplateParams
  dead types; make CreateTemplateParams.generation optional to match
  actual tool behavior
@vercel

vercel Bot commented Jul 2, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
docs Skipped Skipped Jul 2, 2026 7:42am

Request Review

@cursor

cursor Bot commented Jul 2, 2026

Copy link
Copy Markdown

PR Summary

Low Risk
Scoped SendGrid integration fixes and typing; no auth or core platform changes beyond declaring ApiKey on the block.

Overview
Fixes SendGrid integration bugs and gaps so workflows match the v3 API and handle real response shapes.

Create Template Version now sends active as 0/1 via toActiveFlag (and the block maps the Yes/No dropdown to integers), fixing failures when the UI passed string "true"/"false". The SendGrid block declares authMode: ApiKey.

List All Lists and List Templates support cursor pagination: optional pageToken on requests, nextPageToken parsed from _metadata.next, plus advanced block fields and param wiring. List templates always sends page_size (default 20) and drops the unused data.templates fallback.

Across contact, mail, and template tools, nullable API fields use ?? null / ?? [] and tool outputs mark optional: true where appropriate. Shared types drop unused update param interfaces and align list/template result types with pagination and nullability.

Reviewed by Cursor Bugbot for commit 2ebda8b. Configure here.

Comment thread apps/sim/blocks/blocks/sendgrid.ts Outdated
Comment thread apps/sim/blocks/blocks/sendgrid.ts Outdated
…e coercion

- Gate listPageToken/templatePageToken remap on operation so a stale
  token from the other list operation can't override the intended one
- Fix active coercion to also treat a real boolean true (from a dynamic
  <Block.output> reference) as active, not just the dropdown string 'true'
@greptile-apps

greptile-apps Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes a critical SendGrid integration bug where the active field was sent as a string ("true"/"false") instead of the integer (1/0) the API requires, adds cursor-based pagination to list_templates and list_all_lists, and tightens nullable output typing across six tools.

  • active coercion: The block now converts any truthy/string/boolean representation to 0|1 before passing to the tool; the tool additionally wraps the final request build in toActiveFlag() — both paths are correct and the SendGridTemplateVersionRequest.active type is narrowed to number to match the API contract.
  • Pagination: Both list tools parse _metadata.next with new URL() (guarded by try/catch) to extract page_token, expose it as nextPageToken, and wire new pageToken input params through the block UI (advanced mode).
  • Type/nullable cleanup: jobId, htmlContent, plainContent, updatedAt, contactCount, messageId now use ?? null / ?? [] with optional: true in output metadata; three dead param interfaces are removed.

Confidence Score: 5/5

Safe to merge — all changes are additive or fix previously broken behavior with no regressions.

The active-coercion fix is correct for every input path (string dropdown, boolean wire, direct LLM call). Pagination parsing uses URL built-ins with a try/catch fallback. Nullable output changes consistently apply ?? null/?? [] with matching type declarations. No existing behavior was removed or regressed.

No files require special attention.

Important Files Changed

Filename Overview
apps/sim/blocks/blocks/sendgrid.ts Adds authMode, two pagination UI fields, and fixes active coercion — changes are correct and complete
apps/sim/tools/sendgrid/create_template_version.ts Replaces ad-hoc active coercion with toActiveFlag helper; handles all boolean/string/number falsy variants correctly; output nullability tightened
apps/sim/tools/sendgrid/list_templates.ts Adds pageToken param and nextPageToken output; parses cursor from _metadata.next with URL + try/catch; always sends page_size defaulting to 20
apps/sim/tools/sendgrid/list_all_lists.ts Adds pageToken param and nextPageToken output with the same safe URL-parsing pattern as list_templates
apps/sim/tools/sendgrid/types.ts Removes three dead interfaces, narrows SendGridTemplateVersionRequest.active to number-only, adds pageToken params and nextPageToken to result types
apps/sim/tools/sendgrid/get_contact.ts Nullable output fields now default to empty array / null; output declarations updated with optional: true
apps/sim/tools/sendgrid/search_contacts.ts contactCount nullable fallback and optional: true marker added
apps/sim/tools/sendgrid/add_contact.ts jobId, firstName, lastName marked optional; jobId gets ?? null fallback
apps/sim/tools/sendgrid/remove_contacts_from_list.ts jobId nullability fix and optional output marker
apps/sim/tools/sendgrid/send_mail.ts messageId output marked optional — correct since SendGrid does not return a message ID for all send paths

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant UI as Block UI
    participant Block as sendgrid.ts (transformInput)
    participant Tool as create_template_version.ts
    participant SG as SendGrid API

    UI->>Block: "active = 'true' (dropdown) OR true (wired boolean)"
    Block->>Block: "active === 'true' || active === true ? 1 : 0"
    Block->>Tool: "params.active = 1 | 0"
    Tool->>Tool: "toActiveFlag(params.active) to 0 | 1"
    Tool->>SG: "POST /v3/templates/{id}/versions { active: 1 }"
    SG-->>Tool: "201 { active: 1 }"
    Tool-->>Block: "{ active: true, htmlContent: null }"

    Note over UI,SG: Pagination flow
    UI->>Block: "templatePageToken = 'abc'"
    Block->>Tool: "pageToken = 'abc'"
    Tool->>SG: "GET /v3/templates?page_token=abc&page_size=20"
    SG-->>Tool: "{ result: [...], _metadata: { next: 'https://...?page_token=xyz' } }"
    Tool->>Tool: new URL(_metadata.next).searchParams.get('page_token')
    Tool-->>Block: "{ templates: [...], nextPageToken: 'xyz' }"
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant UI as Block UI
    participant Block as sendgrid.ts (transformInput)
    participant Tool as create_template_version.ts
    participant SG as SendGrid API

    UI->>Block: "active = 'true' (dropdown) OR true (wired boolean)"
    Block->>Block: "active === 'true' || active === true ? 1 : 0"
    Block->>Tool: "params.active = 1 | 0"
    Tool->>Tool: "toActiveFlag(params.active) to 0 | 1"
    Tool->>SG: "POST /v3/templates/{id}/versions { active: 1 }"
    SG-->>Tool: "201 { active: 1 }"
    Tool-->>Block: "{ active: true, htmlContent: null }"

    Note over UI,SG: Pagination flow
    UI->>Block: "templatePageToken = 'abc'"
    Block->>Tool: "pageToken = 'abc'"
    Tool->>SG: "GET /v3/templates?page_token=abc&page_size=20"
    SG-->>Tool: "{ result: [...], _metadata: { next: 'https://...?page_token=xyz' } }"
    Tool->>Tool: new URL(_metadata.next).searchParams.get('page_token')
    Tool-->>Block: "{ templates: [...], nextPageToken: 'xyz' }"
Loading

Reviews (6): Last reviewed commit: "fix(sendgrid): handle numeric 0 in toAct..." | Re-trigger Greptile

Comment thread apps/sim/blocks/blocks/sendgrid.ts
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile review

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cursor review

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 34d86a2. Configure here.

Per Greptile: the block-level active coercion only covered the UI
path. A direct sendgrid_create_template_version tool invocation with
a boolean active would still send a raw boolean to SendGrid. Coerce
to 0/1 in the tool's own request body so both paths are correct.
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

Fixed the tool-body active coercion Greptile flagged — create_template_version.ts now coerces params.active to 0/1 in its own request body (params.active ? 1 : 0) instead of relying on the block-level fix, so direct tool invocations with a boolean active are also correct. Tightened SendGridTemplateVersionRequest.active to number since it's always coerced now. Pushed in eb0ff54.

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile review

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cursor review

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit eb0ff54. Configure here.

SendGrid's GET /v3/templates requires page_size on every request
(no server-side default) — omitting it errors. Default to 20 to
match our own documented default when the caller doesn't set one.
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

Final independent validation pass (3 parallel subagents against live SendGrid docs) caught one more real gap: GET /v3/templates requires page_size on every request (no server-side default) — list_templates was only sending it when the caller explicitly set a value, so an unset call would fail. Now always sends page_size (defaulting to 20, matching the tool's documented default). Pushed in 29f06de.

Everything else across all 16 tools verified aligned with live SendGrid v3 docs, correct nullable output typing, and no backwards-incompatible field removals.

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile review

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cursor review

Comment thread apps/sim/tools/sendgrid/create_template_version.ts Outdated
Per Cursor Bugbot: params.active ? 1 : 0 treated any truthy string
(including "false") as active. Extracted a toActiveFlag helper that
only treats real false or the string 'false' as inactive, everything
else (including unset) defaults to active — matches the tool's
documented default.
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile review

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cursor review

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit c094e47. Configure here.

Per Greptile: the block coerces active to a number (0/1) before
calling the tool, but toActiveFlag only checked for false/'false',
so the block's inactive selection (0) fell through to the
"active" branch. Check against an explicit inactive-values set
covering the boolean, string, and numeric forms.
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

Confirmed and fixed — real bug: the block coerces active to a number (0/1) before calling the tool, but toActiveFlag only checked for false/'false', so the block's "inactive" selection (numeric 0) fell through to the active branch. Now checks against an explicit inactive-values set covering boolean, string, and numeric forms. Pushed in 2ebda8b.

Re: the nextPageToken block output missing optional: true" — checked the type, block-level OutputFieldDefinition (@sim/workflow-types/blocks) only accepts { type, description?, condition?, hiddenFromDisplay? }, no optional` field exists there (that's a tool-level-only construct). Not applicable, skipping.

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile review

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cursor review

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 2ebda8b. Configure here.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant