v0.7.21: tools audits and extensions, appsheet integration, hitl fix by waleedlatif1 · Pull Request #5378 · simstudioai/sim · GitHub
Skip to content

v0.7.21: tools audits and extensions, appsheet integration, hitl fix#5378

Merged
waleedlatif1 merged 28 commits into
mainfrom
staging
Jul 2, 2026
Merged

v0.7.21: tools audits and extensions, appsheet integration, hitl fix#5378
waleedlatif1 merged 28 commits into
mainfrom
staging

Conversation

@waleedlatif1

@waleedlatif1 waleedlatif1 commented Jul 2, 2026

Copy link
Copy Markdown
Collaborator

waleedlatif1 and others added 25 commits July 1, 2026 22:50
…text (#5353)

* fix(mothership): stop inlining full execution traces for the logs context

Tagging a run via "Troubleshoot in Chat" (or any @-mention of a logs
context) resolved through processExecutionLogFromDb, which materialized
the ENTIRE execution trace (every block's input/output, nested tool-call
spans) and inlined it directly into the prompt. For any non-trivial run
this repeatedly blew the context window, forcing multiple compactions and
eventually auto-stopping the agent before it could investigate anything.

Every other context resolver in this file already avoids this by sending
a lightweight pointer instead of a full inline dump (workflow/blocks/
workflow_block contexts point into the VFS). Logs contexts have no VFS
materialization to point at, but the equivalent lightweight mechanism
already exists as a tool: query_logs supports incremental disclosure
(overview for timing/cost, full for a scoped block's input/output, or
pattern to grep the trace) and is already registered for the mothership
agent.

Now processExecutionLogFromDb sends a compact summary (id, workflow,
level, trigger, timing, cost) plus a note pointing the model at
query_logs with the executionId, instead of materializing and embedding
the trace. Also drops the now-unused executionData column from the
select projection, so resolving a logs context no longer fetches a
potentially large JSONB blob it never reads.

* improvement(mothership): send a bounded block overview instead of a bare tool pointer

Follow-up to the previous commit's fix (stop inlining full execution
traces). A pure text pointer telling the model to call query_logs made
the agent's very first useful action against a tagged run contingent on
it noticing and correctly acting on prose in a JSON blob it may only
skim — every sibling resolver in this file instead returns a
deterministic mechanism (a VFS path) the model reads on demand.

There's no VFS materialization for individual execution logs, but the
same deterministic signal is available cheaply: toOverview() (the exact
projection query_logs's own "overview" view already returns) walks the
raw trace spans and produces a compact tree — block name/type/status/
timing/cost, no input or output — without touching large-value refs at
all. The summary now includes that tree, so the model can see which
block failed on the first turn, and the note narrows to what still
requires a tool call: a block's actual input/output/error, or a grep.

materializeExecutionData is still called, but it's a no-op for the
common inline case (it only unwraps a top-level object-storage pointer
for runs whose whole trace was offloaded as one blob) and was needed to
reach traceSpans at all for those heavier runs — exactly the runs most
worth an overview.

A serialized-size cap (mirroring query-logs.ts's own truncation
fallback, scaled down since this lands in the prompt unconditionally)
drops the overview if a pathological span count pushes it over budget,
falling back to the note alone.

Extends the tests: the happy path now asserts the overview tree is
present and that no raw input/output payload leaks into the serialized
summary, plus a new test for the size-cap fallback.
…cs (#5362)

- add wandConfig AI-autofill to expense/spend-limit filter subBlocks
- surface is_ppro_enabled on get/list transfer tools
- surface start_date/end_date/authorization_settings on list_spend_limits to match get_spend_limit
Tool-level get_transfer/list_transfers already returned is_ppro_enabled
(confirmed present on Brex's live Transfer schema), but the block's
outputs map didn't declare it, so it was unreachable from the workflow
UI. Adds it alongside the other transfer output fields.
…et-template tools (#5358)

* fix(loops): align integration with live API docs, add suppression + get-template tools

- fix list_transactional_emails endpoint URL (was /transactional, now /transactional-emails)
- fix response fields to match actual API schema (createdAt/updatedAt, not the never-existent lastUpdated)
- add loops_check_contact_suppression, loops_remove_contact_suppression, loops_get_transactional_email tools
- wire new tools into block operations, outputs, and registries
- alphabetize tools/registry.ts loops entries

* fix(loops): expose contactId output, fix stale tool description

- add missing contactId block output for check_contact_suppression (Greptile P1)
- fix list_transactional_emails description to mention createdAt (Greptile P2)

* fix(loops): restore lastUpdated as backwards-compat alias on list_transactional_emails

Final validation pass found that /api/v1/transactional (the endpoint this tool
used before this PR) is a real, functional, deprecated Loops endpoint whose
schema genuinely returns lastUpdated - it was not a broken/invented field.
Migrating to /api/v1/transactional-emails is still correct (current endpoint,
better error semantics), but dropping lastUpdated would break any existing
workflow reading it from this block's output. Keep it as a deprecated alias
of updatedAt alongside the new createdAt/updatedAt fields.

* fix(loops): update id output description to cover get_transactional_email
…5367)

* fix(ahrefs): align tool coverage and outputs with the Ahrefs API v3

- 5 of 8 tools were missing the required `select` param (API v3 rejects
  list-endpoint requests without it) and 3 sent a `date` param the
  endpoint doesn't accept
- all list endpoints sent an `offset` param that doesn't exist on any
  Ahrefs v3 site-explorer endpoint (only `limit` is supported)
- domain_rating and backlinks_stats read response fields at the wrong
  nesting level and always returned zeros; several other tools mapped
  output fields to column names the API doesn't return (position, url,
  traffic, backlinks, dofollow_backlinks, http_code) instead of the
  real ones (best_position, best_position_url, sum_traffic,
  links_to_target, dofollow_links, http_code_target)
- keyword_overview used the wrong endpoint param entirely (`keyword`
  instead of `keywords`) so it always returned empty
- added ahrefs_metrics (site-explorer/metrics) and
  ahrefs_organic_competitors (site-explorer/organic-competitors) tools
- fixed docsLink to point at docs.sim.ai instead of ahrefs.com

* fix(ahrefs): default metrics country to us like every other tool

Greptile and Cursor Bugbot both flagged that ahrefs_metrics omitted
the country when unset, unlike every other country-accepting Ahrefs
tool, which silently returns global data instead of US data on
direct tool calls.

* fix(ahrefs): default history to all_time on backlinks and referring domains

Cursor Bugbot flagged that history was only sent when explicitly set,
even though the block UI defaults it to all_time — same class of gap
as the metrics.ts country fix, applied for direct tool-call consistency.

* feat(ahrefs): expose search intent flags on keyword overview

Adds the real intents field (informational, navigational, commercial,
transactional, branded, local) from keywords-explorer/overview, which
was verified valid against the live API docs but not yet surfaced.
…s tool; icon/color tweaks (#5356)

* fix(algolia): fix serialization-time param mutation, add geo/facet search, task status tool

- move all tools.config coercion/remapping out of tool() into a proper params() function so dynamic block references aren't destroyed before variable resolution
- wire facets and getRankingInfo into the search tool so those documented outputs are actually reachable
- add geo-search (aroundLatLng/aroundRadius/insideBoundingBox/insidePolygon) to search and browse_records, matching delete_by_filter
- fix aroundRadius param type (string, not number, since it accepts "all")
- sync batch_operations description with the real action set (delete, clear)
- consolidate list_indices pagination into the shared page/hitsPerPage fields instead of duplicate listPage/listHitsPerPage
- add algolia_get_task_status tool so workflows can poll a taskID instead of guessing when a write is applied
- trim indexName/objectID/destination before building request URLs
- add ranking-tuning and index-snapshot skills to AlgoliaBlockMeta

fix(dropcontact): swap icon to the official wordmark's teal swirl mark, bgColor to match

chore(grafana): bgColor to white to match brand tile convention

* fix(algolia): register subblock-id migration for listPage/listHitsPerPage

CI's subblock-id stability check correctly flagged that consolidating
list_indices pagination into the shared page/hitsPerPage fields would
silently drop values from already-deployed workflows. Add the rename
mapping so existing saved state migrates instead of being lost.

* fix(algolia): remove fabricated pendingTask field from get_task_status

Algolia's Get Task Status response (additionalProperties: false) only
returns `status` (published | notPublished) — pendingTask belongs to
the List Indices response, not this endpoint. Drop it from the tool's
output, response type, and block outputs rather than inventing data.

* fix(algolia): coerce getRankingInfo/createIfNotExists/forwardToReplicas from real booleans, not just strings

A wired <Block.output> boolean (e.g. true) failed the `=== 'true'`
string-only checks and silently flipped to the wrong value. Add a
toBool helper that accepts both the dropdown's string values and a
genuine boolean passed in via a dynamic reference.

fix(dropcontact): render icon with currentColor instead of hardcoded fill

The new teal swirl mark's fill (#0ABA9F) matched the block's bgColor
exactly, making the icon invisible on its own tile. Use currentColor
and set iconColor so the shared tile-contrast logic (getTileIconColorClass)
renders it white-on-teal like the rest of the brand icon system.

* fix(algolia): trim indexName in request bodies, not just URL paths

Greptile caught that search.ts's body-level indexName (sent inside the
multi-query POST body, not URL-encoded) wasn't trimmed like every other
tool's URL-path indexName. Fixed there and in get_records.ts's per-request
indexName default/override, which had the same gap.

* fix(algolia): route list_indices and get_task_status GETs to the -dsn read host

Verified against Algolia's official JS client source
(getDefaultHosts + transporter isRead = useReadTransporter || method === 'GET'):
every GET request routes to the read (-dsn) host, matching the other 14
tools in this integration (get_record, get_settings, etc). Both tools
were incorrectly hitting the write host.

* chore(algolia): regenerate docs to drop stale pendingTask entry

The get_task_status pendingTask output was removed from code in
d102129 (fabricated field, not in Algolia's real API response) but
docs weren't regenerated at the time, leaving a stale entry. Also
syncs the Dropcontact icon's currentColor fill into the docs mirror.

* fix(algolia): correct batch_operations body requirement wording

Verified against Algolia's actual batchWriteParams schema (specs/common/schemas/Batch.yml):
body is a required property on every batch request item, including
index-level delete/clear actions — it isn't omittable. The tool's
param description previously said to omit it; corrected to say use an
empty object instead.
…tch (#5354)

* feat(similarweb): add page views tool, fix paid referrals field mismatch

- Add similarweb_page_views tool (Total Page Views, Desktop & Mobile)
- Fix paidReferrals in website overview: API Lite response key is
  literally "paid _referrals" (space before underscore), not caught
  by the existing fallback chain, so it always resolved to null
- Move startDate/endDate/mainDomainOnly to advanced mode

* fix(similarweb): accept both page_views key spellings in page views response

Cursor Bugbot and Greptile both flagged the response field as page_views by
convention, but SimilarWeb's own docs example response uses pages_views for
this specific endpoint. Accept both spellings defensively so the tool works
regardless of which is actually returned.
#5366)

* fix(tailscale): align tool coverage and outputs with the Tailscale API

- fix list_users profilePicUrl field name (API returns lowercase, was always null)
- add nodeId, keyExpiryDisabled, expires to device outputs
- quote the If-Match header value on ACL updates per API spec
- add set_acl, expire_device_key, suspend_user, delete_user tools
- add wandConfig to dnsServers/searchPaths block fields
- expand BlockMeta skills/templates for ACL and key-expiry workflows

* fix(tailscale): remove phantom magicDNS field from list_dns_nameservers

The GET /tailnet/{tailnet}/dns/nameservers response only returns
{dns: string[]} per the API spec — magicDNS is not part of this
endpoint's response and was always silently false.

* fix(tailscale): extend ToolResponse in expire_device_key response type

Matches the pattern used by the other new tools in this PR
(delete_user, suspend_user).

* fix(tailscale): list_auth_keys now returns all tailnet keys

GET /tailnet/{tailnet}/keys silently scopes to the caller's own
keys unless all=true is passed, contradicting the tool's stated
purpose of listing all auth keys in the tailnet.
…nloads (#5365)

* fix(onepassword): validate integration against API docs, add file downloads

- add onepassword_get_item_file tool + route for downloading item file
  attachments (SDK items.files.read / Connect files/{id}/content), backed
  by newly-exposed item.files metadata on get/create/replace/update item
- fix update_item JSON Patch applying array indices instead of 1Password's
  documented field-ID addressing (/fields/{fieldId}/...), which silently
  dropped field edits in Service Account mode
- fix Service Account mode's list-vaults/list-items filter to honor SCIM
  `eq` exact-match semantics instead of always substring-matching
- expand the create-item category dropdown from 9 to 19 real, creatable
  1Password categories (was missing SOFTWARE_LICENSE, EMAIL_ACCOUNT,
  MEMBERSHIP, PASSPORT, REWARD_PROGRAM, DRIVER_LICENSE, BANK_ACCOUNT,
  MEDICAL_RECORD, OUTDOOR_LICENSE, WIRELESS_ROUTER, SOCIAL_SECURITY_NUMBER)
- replace the block's single opaque `response: json` output with typed,
  per-operation output fields matching repo convention
- remove incorrect password-masking on the Vault ID field (not a secret)
- re-export tool types from the onepassword barrel

* fix(onepassword): honor SCIM attribute name in filter matcher

matchesFilter always compared against name/title regardless of the
attribute named in the eq expression, so `id eq "..."` incorrectly
matched against the display name instead of the id.

* fix(onepassword): close output-parity and doc-string gaps from final audit

- restore a deprecated no-op 'response' output so pre-existing saved
  workflows referencing it fail soft (empty) instead of hard-erroring
  now that per-operation outputs replace it
- add missing block outputs (urls, favorite, version, state,
  lastEditedBy) for get/create/replace/update item so all real
  FULL_ITEM fields are discoverable as <Block.field> references
- hide Connect Server credential fields for Resolve Secret (Service
  Account only) instead of leaving them selectable and silently ignored
- correct two doc-string enum lists that advertised values the API
  doesn't return (vault type TRANSFER, item state DELETED)

* fix(onepassword): fix silent data loss in update_item (Service Account mode)

update_item applied user JSON Patch ops (documented/typed against the
Connect-shaped vocabulary get_item returns: label/type/section.id)
directly onto the raw SDK item, whose vocabulary differs (title/
fieldType/sectionId, and SDK category enum strings vs Connect's
SCREAMING_SNAKE_CASE). Most patches beyond /title, /tags/-, and
/fields/{id}/value silently no-opped or could corrupt the item while
still reporting success.

Extracted the Connect->SDK item conversion already used by replace_item
into a shared connectItemToSdkItem helper. update_item now normalizes
the fetched item to Connect shape, applies patches to that, then
converts back before calling items.put() -- matching create/replace's
existing translation pattern.

Found via an adversarial final-verification pass that traced concrete
patch operations by hand against the SDK's actual field vocabulary.

* fix(onepassword): preserve field metadata and empty-title fallback

connectItemToSdkItem rebuilt every field as a bare object, dropping
SDK-only metadata (e.g. password-generation details) that a raw
patch/replace previously left untouched. Now merges onto the existing
SDK field by id before applying the translated properties, and only
starts fields bare when they're genuinely new.

Also restored the || (not ??) fallback on title to match replace_item's
prior behavior of treating an explicitly empty title as "not provided".
…ics (#5355)

* fix(amplitude): validate integration against API docs, add funnels/retention

- Fix Identify/Group Identify sending JSON instead of the form-urlencoded body Amplitude requires
- Fix Send Event using snake_case product_id/revenue_type instead of Amplitude's camelCase productId/revenueType
- Fix Get Revenue parsing a response shape that never matched the real Revenue LTV API
- Add EU data residency support across all tools
- Add missing filters/formula/segment params to Event Segmentation, groupBy/segment to Active Users and Revenue
- Add first_used/last_used to User Activity output, non_active/flow_hidden to List Events output
- Add real-time/hourly interval options to Event Segmentation
- Add Funnels and Retention tools for conversion and retention analysis
- Harden JSON-shape validation across funnels/segmentation/retention (fail loudly on malformed or partial input instead of silently degrading)
- Expose every tool output field (user_profile, send_event, user_search) on the block so nothing is unreachable downstream
- Update brand colors to current Amplitude guide

* fix(amplitude): validate retention brackets, require formula param, add segmentation 2nd group-by

- Retention now validates retentionBrackets as a JSON array and requires it when retentionMode is "bracket", matching the block UI's requirement
- Event Segmentation now throws if metric is "formula" but no formula is provided, matching the block UI's requirement
- Event Segmentation now supports a documented second group-by property via groupBy2/g2
- Corrected Get Active Users' group-by copy — Amplitude's docs don't document a second-property syntax for /api/2/users the way they do for segmentation's g2, so the field no longer overpromises "max two"
* fix(vercel): align integration with live Vercel REST API docs

- add missing teamId/slug scoping to 29 tools (deployments, checks, projects, env vars)
- add DNS SRV/HTTPS record support (nested srv/https objects) to create/update_dns_record
- add decrypt/gitBranch filters to get_env_vars, autoUpdate to rerequest_check
- add redirect param to create_alias, comment to create_dns_record
- add missing customNameservers/userId/teamId/transferStartedAt fields to list_domains output
- wire pagination filters (limit/since/until/search/app) into block subBlocks for list_deployments, list_teams, list_team_members, list_dns_records, list_project_domains
- wire previously-unexposed tool params into block UI: withGitRepoInfo, gitSource, forceNew, externalId, rerequestable, output, direction, follow
- fix duplicate projectId subBlock id collision between list_deployments and other project-scoped operations
- fix teamId scope field incorrectly hidden for check operations

* fix(vercel): address review findings on DNS/deployment param handling

- fix withGitRepoInfo 'No' dropdown sending withGitRepoInfo=false instead of omitting the param
- remove redundant duplicate 'Forward' option from eventsDirection dropdown
- fix mxPriority being silently dropped in update_dns_record when record type is left unset

* fix(vercel): fix pagination token type mismatch and clarify DNS update UX

- fix list_projects nextFrom being stored as a number despite string typing, which threw TypeError on .trim() when chained into a follow-up list_projects call
- clarify that the DNS update Value field has no effect on existing SRV/HTTPS records unless Record Type is explicitly reselected

* fix(vercel): fix zero-value SRV/HTTPS/MX numeric fields being dropped

- SRV weight/port/priority, HTTPS priority, and MX priority use truthy checks that silently drop legitimate 0 values; switch to explicit empty/null checks
- add missing MX Priority field to create_dns_record block UI (tool already required it for MX records but there was no way to set it)

* fix(vercel): fix stale cross-operation field leaks in block params

- fix list_deployments/create_deployment/update_check/list_team_members/update_dns_record/update_env_var conditionally spreading into keys that collide with unrelated operations' non-destructured literal subBlock fields (projectId, deploymentId, target, name, search)
- a stale value left over from switching operations in the UI would silently leak into the wrong tool call since the conditional spread only overrides when the current operation's own field has a value
- fix now always assigns these keys directly so they deterministically override any stale base value

* feat(vercel): close remaining input/output completeness gaps

- add missing slug (team-slug) param to 13 domain/DNS/alias tools that were skipped in an earlier fix pass, matching the pattern used everywhere else in this integration
- add rootDirectory, nodeVersion, devCommand params to create_project/update_project (verified against Vercel's live OpenAPI spec — high-value fields for monorepo support and runtime pinning)
- surface rootDirectory/nodeVersion in get_project/list_projects outputs, since the API already returns them
- wire all new fields into the block UI as advanced fields

* fix(vercel): fix remaining No->false truthy-string dropdown bugs

- checkRerequestable, checkAutoUpdate, envVarsDecrypt dropdowns used id: 'false' for their No option (a truthy non-empty string), causing the conditional spread to always fire and explicitly send false instead of omitting the param
- swept the whole file for this pattern; checkBlocking correctly keeps 'false' since it's a required field that's always sent directly, not conditionally

* fix(vercel): fix silent project-rename leak in update_project

- update_project had no dedicated rename field and just returned base directly, so a stale value from create_deployment's unrelated 'name' subBlock (Project Name for the deployment) could silently flow through and rename a project on update
- add a dedicated 'New Project Name' field for update_project, wired with a direct override so it always takes precedence over any stale leaked value
* v0.6.29: login improvements, posthog telemetry (#4026)

* feat(posthog): Add tracking on mothership abort (#4023)

Co-authored-by: Theodore Li <theo@sim.ai>

* fix(login): fix captcha headers for manual login  (#4025)

* fix(signup): fix turnstile key loading

* fix(login): fix captcha header passing

* Catch user already exists, remove login form captcha

* feat(langsmith): add run update, get run, and feedback tools

- add langsmith_update_run (PATCH /runs/{id}) to complete the create-then-patch tracing lifecycle
- add langsmith_get_run (GET /runs/{id}) to read a run back
- add langsmith_create_feedback (POST /feedback) to attach scores/corrections to runs
- wire all three into the LangSmith block, reusing shared subBlocks across operations
- fix feedback-capture template to use real feedback API instead of faking it via tagged runs
- switch manual Object.fromEntries filtering to filterUndefined per repo convention

* fix(langsmith): reject non-numeric feedback score instead of silently sending null

Number() on an invalid score string produces NaN, which serializes to
JSON null and would still be sent to LangSmith. Throw instead, matching
the existing parseJsonValue error pattern.

* fix(langsmith): harden error handling and validation on new run tools

- update_run, get_run, create_feedback now check response.ok before
  parsing/returning, matching the cloudwatch/zoom convention instead of
  silently returning success on a 4xx/404
- block outputs schema now exposes inputs/outputs for Get Run
- update_run requires at least one field to patch, matching the
  batch-ingest guard for post/patch

* fix(langsmith): align get_run/update_run outputs and narrow feedback score type

- get_run now also outputs runId (alias of id) so workflows can read
  the run identifier consistently across all operations on the block
- update_run now parses and surfaces the response message instead of
  discarding the body entirely, matching create_run's pattern
- narrow LangsmithCreateFeedbackParams.score to number — the tool
  param is declared as JSON-schema 'number' and the block's parseScore
  never produces a boolean, so the wider type was dead and misleading

* fix(langsmith): reject empty-string patch fields and empty PATCH bodies

- block mapper now normalizes blank name/end_time/status/error inputs
  to undefined instead of forwarding empty strings, which would clear
  those fields on the LangSmith run
- update_run tool now throws if the filtered PATCH body is empty,
  guarding direct/programmatic tool calls that bypass the block's own
  "at least one field" check

* fix(langsmith): normalize empty-string patch fields at the tool layer too

Direct/agent tool calls bypass the block's own emptyToUndefined guard,
so update_run now normalizes blank name/end_time/status/error itself
before filtering, matching the block-level fix.

---------

Co-authored-by: Theodore Li <theodoreqili@gmail.com>
Co-authored-by: Siddharth Ganesan <33737564+Sg312@users.noreply.github.com>
Co-authored-by: Vikhyath Mondreti <vikhyathvikku@gmail.com>
Co-authored-by: Theodore Li <theo@sim.ai>
…e encoding, add missing endpoints (#5371)

* fix(supabase): remove non-functional SQL introspection path, harden storage URL encoding, add missing storage endpoints

- introspect.ts no longer attempts raw SQL via a nonexistent PostgREST
  RPC endpoint (always failed); now uses the OpenAPI-spec path directly
  with honest heuristic/best-effort documentation for PK/FK/index fields
- storage tools now trim + URL-encode bucket/path segments before
  building request URLs (download, list, get_public_url,
  create_signed_url, delete_bucket, delete, and the upload API route)
- storage_create_signed_url guards against a missing signedURL field
  in the response instead of silently building a broken URL
- add supabase_storage_create_signed_upload_url, supabase_storage_update_bucket,
  and supabase_storage_empty_bucket tools + block wiring
- change insert/upsert `data` param type from 'array' to 'json' to match
  actual accepted shapes (array or single object)
- bump tool versions to semver (1.0 -> 1.0.0)
- rewrite a BlockMeta template that implied unsupported Supabase Auth
  Admin user-provisioning

(cherry picked from commit 52b655a)

* fix(supabase): address review feedback on update-bucket, signed upload url, and introspect

- storage_update_bucket now fetches the bucket's current config first
  and only overrides isPublic/fileSizeLimit/allowedMimeTypes when the
  caller explicitly provides them, instead of silently forcing
  public: false on every update (the Storage API's PUT is a full
  replace, not a patch)
- storage_create_signed_upload_url and storage_empty_bucket now check
  response.ok before surfacing an error, so a non-2xx response reports
  Supabase's actual error instead of a misleading parse-side message
- introspect.ts drops the spurious ?select=* query param from the
  OpenAPI spec request (meaningless on the root spec endpoint)

(cherry picked from commit 557e407)

* fix(supabase): tri-state bucket visibility on update, empty-string param coercion, introspect schema header

- introspect.ts now sends Accept-Profile when a schema param is given,
  matching the convention used by the other DB tools, so schema-scoped
  introspection actually reads from that schema's spec
- storage_update_bucket.ts treats an empty-string param the same as
  "not provided" (e.g. an untouched file size limit input no longer
  coerces to 0)
- the shared "Public Bucket" dropdown always sent an explicit true/false
  for storage_update_bucket (its default masked "not touched"), which
  could still flip a public bucket private; added a dedicated
  "Keep Current / True / False" control for the update operation so
  omitting a choice genuinely omits the isPublic override

(cherry picked from commit c80567b)

* fix(supabase): check response.ok before parsing storage_create_signed_url

Matches the pattern already applied to the new signed-upload-url tool
this session — a non-2xx response now surfaces Supabase's actual error
message instead of the generic "did not return a signed URL path" one.

(cherry picked from commit 9f40427)

* fix(supabase): correct download param semantics, echoed path field, and schema hint mismatch

Found by a second, per-tool parallel validation pass against live Supabase/PostgREST docs and source:

- storage_get_public_url.ts and storage_create_signed_url.ts sent
  download=true literally, which Supabase's Storage API treats as a
  filename override (renaming the downloaded file to "true") rather
  than a boolean flag; forcing a download while keeping the original
  filename requires an empty download= value
- storage_create_signed_url.ts also sent download in the POST body,
  which the sign endpoint ignores entirely — forcing download only
  works as a query param on the returned URL
- storage_create_signed_upload_url.ts read a `path` field from the API
  response that doesn't exist there; it now echoes the caller-supplied
  path, matching the official storage-js client
- introspect.ts's nullable heuristic didn't disclose that a NOT NULL
  column with a default is misreported as nullable (PostgREST omits it
  from the OpenAPI required list in that case); documented alongside
  the other already-disclosed heuristics, and removed a tautological
  schema-filter check left over from an earlier revision
- insert.ts/upsert.ts's `data` param reverted from 'json' back to
  'array': the 'json' type mapped to an LLM-facing JSON-schema type of
  'object', which contradicted the param's own description ("array of
  objects or a single object")
…wnload tools (#5369)

* feat(sharepoint): validate against Graph API and add delete/update/download tools

- Fix bugs found validating existing tools against live Graph docs: malformed
  nested $expand syntax in get_list, reversed site-resolution precedence in
  create_list, unsanitized field fallback in add_list_items, missing URL
  encoding in read_page, and an incorrect root/serverRelativeUrl field shape
- Fix V1 block gaps vs V2: upload_file required flag, missing required on
  pageName/listDisplayName, wrong site-picker mimeType, dead subBlock refs
- Add 8 new tools within already-granted scopes for CRUD completion:
  delete_list_item, get_list_item, delete_page, update_page, publish_page,
  download_file, delete_file, get_drive_item
- Add opt-in stripAuthOnRedirect option to secureFetchWithPinnedIP so the
  SharePoint file-download route doesn't resend the bearer token to the
  preauthenticated redirect target (default off, no behavior change elsewhere)
- Dedupe read-only list-item field sanitization into a shared utils helper

* fix(sharepoint): encode siteId consistently and fix create_page precedence

- URL-encode siteId/groupId everywhere it's interpolated into a Graph
  request path (Graph site IDs like "host,guid,guid" contain commas that
  must be encoded) - addresses Cursor Bugbot findings on update_page,
  delete_page, publish_page, and applies the same fix consistently across
  every other sharepoint tool for consistency
- Fix create_page's site-resolution precedence (was siteSelector before
  siteId, inconsistent with every sibling tool)

* fix(sharepoint): escape HTML in page content and stop fallback from throwing

- create_page/update_page only escaped quotes when building innerHtml;
  add a shared escapeHtml() helper that also escapes &, <, > so page
  content with angle brackets/ampersands doesn't corrupt the canvas layout
- add_list_items' fields fallback (sanitized re-derivation when Graph's
  response omits fields) could throw on a malformed fallback input after
  the item was already created successfully; catch and fall back to
  undefined instead of failing an already-successful response

* fix(sharepoint): scope columnDefinitions->pageContent mapping to create_list

Both V1 and V2 tools.config.params mapped columnDefinitions onto pageContent
whenever columnDefinitions was truthy, with no operation check. Stale
list-column JSON left in block state after switching to create_page/
update_page would silently replace the user's intended page text. Gate
the mapping on operation === create_list (V1) / sharepoint_create_list (V2).

* fix(sharepoint): cap download-file content fetch at MAX_FILE_SIZE

Greptile flagged the content fetch as unbounded - a large file would
buffer entirely in memory before base64-encoding into the JSON response.
Pass maxResponseBytes: MAX_FILE_SIZE (100MB, same constant used by the
upload path) to secureFetchWithPinnedIP so oversized files reject early
with a clear PayloadSizeLimitError instead of exhausting memory.

* fix(sharepoint): close V1 block input/output gaps and encode upload URLs

Final validation pass (4 parallel audit agents against live Graph docs)
surfaced remaining gaps:

- apps/sim/app/api/tools/sharepoint/upload/route.ts: siteId/driveId were
  not encodeURIComponent-ed in the Graph upload URL, unlike every other
  sharepoint route/tool - same encoding-gap class fixed everywhere else
- read_page.ts: transformResponse recomputed siteId with a raw `||` in
  3 spots instead of the optionalTrim(...) || optionalTrim(...) || 'root'
  precedence used by request.url and every sibling tool
- SharepointBlock (V1, legacy/hidden-from-toolbar but still executable
  for existing saved workflows): listItemFields and listItemId were
  missing `required` for update_list despite the tool requiring them;
  maxPages/groupId/includeColumns/includeItems/nextPageUrl subBlocks
  were entirely absent, making those tool params unreachable from the
  UI; block-level outputs were missing site/pages/content/totalPages/
  nextPageUrl/lists/skippedFiles/skippedCount/errors even though the
  underlying tools return them - V2 already covered all of these
Fixes GHSA-fgmj-fm8m-jvvx / CVE-2026-45249 — Lines series tooltip
rendering could execute raw HTML from series.data[i].name when no
custom tooltip.formatter is set.
…n, and security tools (#5364)

* feat(clerk): expand Clerk integration with org, membership, moderation, and security tools

- fix 4 validate-integration warnings: missing .trim() on org/session IDs, incomplete session-status dropdown, missing list_users/list_organizations filter subBlocks
- add organization update/delete tools
- add organization membership CRUD (list, add, update role, remove)
- add organization invitation create/list
- add user ban/unban/lock/unlock and OAuth access token retrieval
- add allowlist/blocklist identifier management
- add JWT template list/get
- add actor token create/revoke (impersonation)
- add matching webhook triggers for session ended/removed/revoked, organization updated/deleted, and membership updated/deleted
- wire all 23 new tools into the block, tool registry, and trigger registry

* fix(clerk): I/O completeness fixes from final validation pass

- remove dead limit/offset params from list_blocklist_identifiers (Clerk API accepts zero params on this endpoint, verified across 6 spec versions)
- expose publicMetadata on OAuth access token output (was silently dropped)
- expose inviter email/first/last name (public_inviter_data) on organization invitation create/list outputs
- add missing orderBy param to list_organization_invitations
…ead-field bugs (#5360)

* feat(wordpress): add category/tag CRUD tools, fix delete-status and dead-field bugs

- Add wordpress_{get,update,delete}_category and _tag tools for full taxonomy parity
- Fix `deleted: data.deleted || true` always evaluating true across all 6 delete tools (posts/pages/media/comments/categories/tags)
- Remove dead `force` param from delete_media (endpoint always force-deletes; param had zero effect)
- Remove unwired `hideEmpty` block input
- Normalize search_content perPage/page visibility to user-or-llm for consistency

* fix(wordpress): use ?? instead of || for zero-valued numeric fields in delete_category/tag

count and parent can legitimately be 0 (empty term, top-level category); || was
dropping those values, same antipattern already fixed for `deleted` in this PR.
Flagged independently by Greptile and Cursor Bugbot.

* fix(wordpress): use ?? for zero-valued numeric fields across all delete tools

Same || antipattern already fixed for category/tag delete tools was still
present in delete_post/page/comment/media for id, author, featured_media,
menu_order, parent, post — all legitimately 0 in common cases (no featured
image, top-level page/comment). Found by a final independent validation pass.

* fix(wordpress): don't drop categoryParent=0 (root-level category) in block param mapping

Truthy check on params.categoryParent treated a resolved numeric 0 (root-level,
no parent) as unset. Flagged by Cursor Bugbot on create_category/update_category.

* fix(wordpress): don't clear category/tag description on update when field left blank

description used !== undefined (numeric-field convention) instead of a truthy
check (string-field convention used everywhere else in this codebase, e.g.
update_post/update_page excerpt), so an untouched empty description field
silently wiped existing text on every update. Flagged by Cursor Bugbot.

* fix(wordpress): fix search type/subtype mislabeling, complete I/O exposure gaps

- search_content.ts: type param was mislabeled with subtype's vocabulary
  (post/page/attachment); real WP type enum is post/term/post-format. Rewired
  the block's Content Type dropdown to map to subtype (which is what
  post/page/attachment actually filter), not type.
- Widened subBlock conditions so params already read by tools.config.params
  are actually reachable in the UI: commentPostId for list_comments,
  categories/tags for list_posts, parent for list_pages.
- Added missing subBlocks for tool params with no UI path: comment
  parent/authorName/authorEmail/authorUrl (create_comment), media description
  (upload_media), author filter (list_posts).
- Extended the ?? / !== undefined fix (already applied to categoryParent) to
  the same class of param across the block: featuredMedia, page parent,
  menuOrder, and the new commentParent/listAuthor mappings.
- Fixed featuredMedia/parent truthy-check inconsistency in create_post,
  update_post, create_page, update_page, create_category, create_comment
  body builders to match the !== undefined convention used elsewhere.

Found by an independent final validation pass across 3 parallel agents.

* fix(wordpress): keep searchType subBlock id to preserve saved-workflow compat

The type/subtype fix should only change which API param the field feeds
(subtype, not type) — renaming the subBlock id to searchSubtype broke
already-saved workflows with a search content-type filter set, since the
block would stop reading the old searchType key. Reverted the id rename,
kept the underlying subtype mapping fix. Flagged by Cursor Bugbot.

* fix(wordpress): remove invalid Attachment search subtype, fix listAuthor input type

- Search Content's "Content Type" dropdown offered Attachment, which maps to
  subtype=attachment. WP core's WP_REST_Post_Search_Handler explicitly
  excludes attachment from valid subtypes (media isn't searchable via
  /search) — selecting it guaranteed a 400 rest_invalid_param. Removed the
  option; only Post/Page (the only valid subtypes) remain.
- listAuthor was declared type: 'string' in the inputs catalog despite being
  Number()-coerced before use, inconsistent with every other ID-like field
  (postId, pageId, categoryId, commentParent, etc. are all 'number').

Found by an independent final pre-merge validation pass, requested before
merge to be certain of full API alignment.
* feat(trello): expand tool coverage and fix API gaps

- add delete card, remove label/member, update list, add/update checklist item, list members, and search tools
- add filter support to list lists/cards, since/before paging to get actions, member assignment on card creation
- promote move-to-list field out of advanced mode

* fix(trello): address review feedback on checklist item tooling

- idChecklist can be absent on Trello checkItem responses, so stop treating it as required
- validate state/name is provided before building the update-checklist-item request URL
- reject Update Checklist Item at the block level when neither State nor New Item Name is set
- add missing idOrganization field to search's board output schema
…ion/wandConfig consistency (#5361)

* improvement(gong): tighten pagination optionality and add wandConfig to ID list fields

- mark cursor output optional:true on aggregate_activity, interaction_stats, list_flows for consistency with list_calls
- add wandConfig to comma-separated ID fields (callIds, primaryUserIds, userIds, scorecardIds, reviewedUserIds) matching repo convention for CSV inputs

* fix(gong): request context data for get_extensive_calls

contentSelector.context/contextTiming were never set on the /v2/calls/extensive
request, so the documented context (CRM/external-system links) output was
silently always empty even though the field is declared in the tool's outputs.

* feat(gong): add data privacy erase and Engage flow prospect tools

- gong_purge_email_address / gong_purge_phone_number: POST /v2/data-privacy/erase-data-for-*,
  the write-half pairing with the existing lookup_email/lookup_phone read tools
- gong_assign_flow_prospects: POST /v2/flows/prospects/assign, enrolls CRM prospects into an
  Engage flow
- gong_get_prospect_flows: POST /v2/flows/prospects, looks up which flows a prospect is in

Field names verified against an OpenAPI-generator-produced client (cedricziel/gong-rs) whose
serde rename attributes mirror Gong's published spec, since Gong's interactive Swagger docs
require an authenticated session and can't be fetched directly.

* fix(gong): require human-entered target for data-erase tools

emailAddress/phoneNumber on the purge tools were user-or-llm, letting an
agent autonomously pick the erasure target for an irreversible operation
with no human confirmation. Match the user-only visibility already used
for credentials.
…84 (#5375)

The pinned totalRoutes/zodRoutes baseline (883) went stale after a
legitimate new Zod-contract-compliant route merged without the
required ratchet bump, breaking check:api-validation:strict on
staging HEAD itself. Actual count is 884 total / 884 zod / 0 non-zod
routes — a pure headcount update, no policy violation.
…ilters (#5359)

* feat(fathom): add list meeting types tool and missing list-meetings filters

- Add fathom_list_meeting_types tool (GET /meeting_types)
- Add missing list-meetings params: includeHighlights, meetingType,
  calendarInviteesDomains, calendarInviteesDomainsType
- Add missing meeting response fields: meeting_type, meeting_url,
  shared_with, highlights
- Wire new operation and filters into the Fathom block

* fix(fathom): expose meeting_url/highlights in outputs, stop force-sending domain type default

- Add meeting_url and highlights to list_meetings outputs schema so
  they're addressable from downstream blocks (Greptile P1)
- Drop the forced 'all' default on calendarInviteesDomainsType so the
  filter is only sent when a user explicitly picks a value (Greptile P2)

* fix(fathom): never send calendar_invitees_domains_type=all to the API

Match the existing Fathom connector's guard (meetingType !== 'all') so
the request omits the param entirely when the value is the API's own
default, regardless of what the dropdown shows selected in the UI.

* fix(fathom): fully expose list_meetings meeting fields in outputs schema

transformResponse already returned meeting_title, scheduled/recording
times, recorded_by, calendar_invitees, default_summary, transcript,
action_items, and crm_matches, but outputs.meetings.items.properties
only documented a curated subset, leaving these fields unaddressable
from downstream workflow blocks. Complete the schema to match the
full Meeting object Fathom's API returns.

* fix(fathom): mark recording_id optional in list_meetings outputs

transformResponse maps recording_id as meeting.recording_id ?? null
and the response type already types it number | null; the outputs
schema now reflects that nullability.

* fix(fathom): mark calendar_invitees email optional in list_meetings outputs

Fathom's docs mark Invitee.email as nullable; the outputs schema now
reflects that instead of declaring it as always-present.
#5372)

* feat(hex): expand API coverage, fix ID trimming, add cursor pagination

- Add hex_update_collection, hex_create_group, hex_update_group,
  hex_delete_group, hex_deactivate_user tools + block wiring
- Add missing run_project fields (viewId, notifications) and
  get_project_runs runTriggerFilter
- Add after/before cursor pagination to list_projects, list_groups,
  list_data_connections, list_collections
- Add .trim() on all interpolated ID path params to guard against
  copy-paste whitespace

* fix(hex): guard JSON.parse on user-supplied array/object params

Wrap JSON.parse calls for memberUserIds, addUserIds, removeUserIds,
inputParams, and notifications in try/catch so malformed input throws
a clear error instead of an opaque parse exception.

* fix(hex): forward empty collection description on update

update_collection's params() mapping only copied collectionDescription
when truthy, so clearing it to an empty string in the UI never reached
the API. Untouched fields resolve to null (not undefined), so use a
loose null check to distinguish "cleared" from "never touched" without
sending description: null on every unrelated update.

* fix(hex): close remaining API coverage gaps found via raw OpenAPI spec

Pulled Hex's actual OpenAPI spec (static.hex.site/openapi.json) as
ground truth for a final verification pass:

- list_users was missing after/before cursor pagination and the
  userIds filter, which the spec confirms it supports (an earlier
  doc-summary pass had incorrectly flagged this as unverifiable)
- list_users response also exposes lastLoginDate per user, not
  previously surfaced
- list_projects was missing includeComponents, includeTrashed,
  creatorEmail, ownerEmail, collectionId, categories, sortBy, and
  sortDirection filters that the spec confirms are real query params

* fix(hex): trim remaining user-suppliable IDs for consistency

Trim collectionId (list_projects filter), viewId (run_project body),
and group member UUIDs (create_group/update_group) to match the
.trim() convention already applied to path-segment IDs elsewhere.

* fix(hex): validate parsed JSON is actually an array before iterating

categories, memberUserIds, addUserIds, and removeUserIds could parse
as valid JSON that isn't an array (e.g. an object), which would throw
an opaque "not iterable"/"map is not a function" error deeper in the
call. Validate Array.isArray after parsing and fail with a clear
message instead.

* fix(hex): validate array element types, send explicit ALL trigger filter

- notifications now gets the same Array.isArray guard already applied
  to categories/memberUserIds/addUserIds/removeUserIds
- member/category array elements are now validated as strings before
  .trim()/append, instead of crashing on non-string entries
- runTriggerFilter "All" option now sends the documented ALL enum
  value explicitly instead of relying on omission
…put typing (#5368)

* fix(sendgrid): fix active field coercion, add pagination, tighten output 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

* fix(sendgrid): address Cursor Bugbot findings on pagination and active 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'

* fix(sendgrid): coerce active to int at the tool layer too

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.

* fix(sendgrid): always send page_size on list_templates

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.

* fix(sendgrid): explicit false/'false' check for active flag

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.

* fix(sendgrid): handle numeric 0 in toActiveFlag

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.

* fix(sendgrid): nest add_contact custom fields under custom_fields

Pre-existing bug (predates this PR): custom fields were merged onto
the contact object as top-level sibling keys via safeAssign/Object.assign,
but SendGrid's PUT /v3/marketing/contacts requires them nested under a
custom_fields object. SendGrid silently drops unrecognized top-level
keys, so the documented customFields param never actually reached
SendGrid. Caught during a final adversarial re-verification pass
before merge.

* fix(sendgrid): document consistent page_size requirement for list_templates pagination

Per Cursor Bugbot: list_templates always defaults page_size to 20
when unset (required by SendGrid), so a follow-up pageToken-only
call after a first call with a larger pageSize would silently
shrink to 20 and desync page boundaries. This is inherent to a
stateless tool call (SendGrid requires page_size on every request,
and the tool has no way to remember the prior call's value), so
clarify via param description and UI placeholder that callers must
repeat the same pageSize across paginated calls.

* chore(api-validation): bump stale route-count ratchet baseline 883->884

Unrelated to the SendGrid work in this branch. staging's own HEAD
already has 884 compliant Zod-backed API routes (0 non-Zod), but this
ratchet baseline was never bumped when that route landed, so any PR
rebasing onto current staging fails check:api-validation:strict with
"route count increased from 883 to 884". All routes remain fully
Zod-backed; this is a mechanical counter update, not a policy change.

* fix(sendgrid): dedupe active coercion between block and tool

Per Cursor Bugbot: the block's pre-coercion only recognized the
dropdown string 'true' or boolean true as active, so a dynamic
reference producing numeric 1 or string '1' fell through to 0 and
silently created an inactive template version. Exported the tool's
toActiveFlag and reused it in the block instead of duplicating the
inactive-value logic, so both layers can no longer drift out of sync.
…potency (#5377)

- verifyAuth now rejects with 401 when no token is configured instead of
  silently allowing unauthenticated requests through
- formatInput falls back to the legacy formId providerConfig key (pre-#3141
  rename to triggerFormId) so old deployments keep working
- add extractIdempotencyId keyed on formId:responseId to dedupe retried
  Apps Script deliveries
* feat(google-appsheet): add Google AppSheet integration

- 4 tools (find/add/edit/delete rows) against the AppSheet Action API
- API key auth via Application Access Key (no OAuth/scopes needed)
- Block with operation dropdown, region selector, and Selector expression support
- Generated docs

* improvement(google-appsheet): harden response parsing, add wand config and skills

- Guard against empty/non-JSON AppSheet response bodies (Delete may return no body)
- Add wandConfig to the Selector field for AI-assisted expression generation
- Add 3 skills grounded in attested AppSheet/Zapier automation patterns
- Tighten json output descriptions to describe inner shape

* fix(google-appsheet): validate region against allow-list, encode appId, validate rows shape

- Reject unrecognized region values instead of interpolating them into the
  request host (a caller could otherwise redirect the Application Access
  Key to an arbitrary domain)
- URL-encode appId, not just tableName, in the Action endpoint path
- Reject non-array Rows input in tools.config.params instead of forwarding
  a single object to the AppSheet Action API
- Drop the mismatched json-object generationType on the rows wand config
  (that enricher appends "must start with { and end with }", which
  conflicts with the JSON-array shape the field expects)
- Add utils.test.ts covering region validation and response-body parsing

* docs(google-appsheet): add manual intro/getting-started section

Match the MANUAL-CONTENT convention used by other integration docs
(Airtable, Ahrefs, Google PageSpeed) — an overview of the service, what
the Sim integration lets agents do, and how to get an Application
Access Key.

* docs: sync generated integration docs with current source

Regenerate docs for integrations whose tools/blocks changed upstream
without a matching docs regen (ahrefs, algolia, amplitude, brex, clerk,
gong, hex, langsmith, loops, onepassword, sendgrid, sharepoint,
similarweb, supabase, tailscale, trello, vercel, wordpress), plus the
integrations.json catalog.
@waleedlatif1 waleedlatif1 requested a review from a team as a code owner July 2, 2026 19:00
@greptile-apps

greptile-apps Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

@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 10:11pm

Request Review

@cursor

cursor Bot commented Jul 2, 2026

Copy link
Copy Markdown

* improvement(forking): fork time ux

* add storage quota

* address comments

* merge latest staging

* address comments
@waleedlatif1 waleedlatif1 changed the title v0.7.21: tools audits and extensions, appsheet integration v0.7.21: tools audits and extensions, appsheet integration, hitl fix Jul 2, 2026
…sume page (#5381)

* fix(resume): fix click-blocking footer overlay + hardening on HITL resume page

- SupportFooter rendered position:absolute with no space reserved for it
  in InterfacesShell/AuthShell/file-share auth gate, silently overlapping
  and eating clicks on whatever content ended up in its ~50px footprint
  (on the resume page, the Resume Execution button itself)
- Applied the same fix to /invite and /f/[token], which shared the
  identical absolute-positioning pattern
- handleResume no longer fails silently on validation errors or
  unexpected exceptions
- getPauseContextDetail no longer duplicates a pause point's full
  response payload in the same API response
- Oversized HITL display-data values are now truncated in the resume
  page preview instead of rendering unbounded

* fix(resume): use consistent string for truncation-notice length

The object-branch truncation notice sliced from the prettified
JSON.stringify(value, null, 2) but reported the total against the
compact JSON.stringify(value).length, which could show a nonsensical
"5,000 of 4,800 characters shown" when the compact form is shorter
than the prettified slice. Derive both from the same string.

* fix(resume): show em dash for empty-string display data values

renderStructuredValuePreview only treated null/undefined as empty; an
empty string fell through to the plain-text branch and rendered as a
bordered, padded, contentless pill that reads as a stray UI element
(e.g. an unstyled toggle) in the Display Data table.
@waleedlatif1 waleedlatif1 merged commit 4fcfe76 into main Jul 2, 2026
37 checks passed
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.

2 participants