mirror of
https://github.com/simstudioai/sim.git
synced 2026-09-24 15:45:35 +08:00
117fa66ec77d034ccdfc0806a77eaf19aff61eb8
5314
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
117fa66ec7 | fix(providers): sync xai defaultModel with grok-4.5 recommended flag (#5512) | ||
|
|
93481e4408 |
feat(providers): add xAI grok-4.5 model (#5511)
* feat(providers): add xAI grok-4.5 model * fix(providers): correct grok-4.5 release date to API-availability date |
||
|
|
9d34fbea1b |
refactor(utils): consolidate duplicated helpers onto @sim/utils (#5509)
* refactor(utils): consolidate duplicated helpers onto @sim/utils Replaces ~90 hand-rolled reimplementations of error-message extraction, postgres error-code checks, sleep, Math.random, retry/backoff, object filtering/omission, noop, string truncation, date/time formatting, email normalization, and plain-object type guards with the shared @sim/utils exports. Wires check:utils into CI (test-build.yml) so these patterns don't regress. * fix(test): mock @sim/utils/random instead of Math.random in schedule-execute tests The schedules/execute route previously used Math.random() for jitter delay; this consolidation PR switched it to randomInt() from @sim/utils/random, which is backed by crypto.getRandomValues() rather than Math.random(). The route.test.ts spies on Math.random() no longer had any effect, so jitter became real random delay instead of the deterministic 0ms the tests expect, causing intermittent 10s timeouts in CI. * fix(retry): preserve uncapped Retry-After comparison in tools/index.ts parseRetryAfter() caps its return value at 30s by default. tools/index.ts compares the parsed Retry-After against a caller-configured maxDelayMs to decide whether to skip a retry entirely -- capping before that comparison silently defeats the skip check whenever maxDelayMs is configured above 30s, since a Retry-After between 30s and maxDelayMs would incorrectly look "within limits" and get retried instead of skipped (caught by Cursor Bugbot). Added an optional maxMs param (default unchanged) so tools/index.ts can request the raw, uncapped value for its own comparison while backoffWithJitter still clamps the actual sleep duration to maxDelayMs. Added a regression test covering maxDelayMs > 30s. * fix(utils): fall back to Intl-resolved abbreviation for unmapped timezones getTimezoneAbbreviation only covered 9 hardcoded IANA zones and returned the raw IANA string for everything else, degrading schedule descriptions for zones like Europe/Berlin or America/Toronto (caught by Greptile). The deleted local implementation in schedules/utils.ts resolved any valid IANA timezone generically via Intl.DateTimeFormat's short timeZoneName. Restore that as a fallback so only genuinely invalid timezone strings return themselves unchanged. |
||
|
|
099f525d50 |
improvement(knowledge): open document tags from row context menu (#5510)
* improvement(knowledge): open document tags from row context menu The document row context menu had a Tags entry that only navigated to the document detail page, requiring another click through the breadcrumb dropdown to actually edit tags. It now opens the tag editor directly, and shows even when the document has no tags yet so a first tag can be added. * fix(knowledge): gate document tags menu item on edit permission Matches the existing disableRename/disableDelete/disableToggleEnabled pattern; the document detail breadcrumb already hides its Tags entry for non-editors the same way. * fix(knowledge): derive tags modal document data from live list cache The modal was fed a frozen document snapshot taken at right-click time. After a save, the mutation only invalidates the single-document and KB-detail queries (not the documents list query), so the modal's own sync effect rebuilt tags from the stale snapshot and could revert or drop the just-saved value. Track only the document id and look it up from the same documents array updateDocument() patches, so the modal always sees current data. |
||
|
|
cb6f99d518 |
fix(deps): upgrade better-auth 1.6.11 -> 1.6.13 (GHSA fix, Dependabot #166/#167) (#5508)
Patches a high-severity stored XSS in the oidc-provider and mcp plugins via javascript:/data: redirect_uri schemes. Also bumps @better-auth/sso and @better-auth/stripe to matching 1.6.13 peers. Patch-only release (1.6.11 -> 1.6.12 -> 1.6.13), no breaking changes in either changelog. |
||
|
|
8c61720d33 |
chore(tables): remove tables-fractional-ordering feature flag (#5503)
* chore(tables): remove tables-fractional-ordering feature flag * improvement(tables): drop dead position tracking from paste undo path * improvement(tables): drop dead position from create-row undo records |
||
|
|
4e6594dc54 |
feat(pii): add opt-in GLiNER NER engine (PII_ENGINE), device-agnostic (#5495)
* feat(pii): add opt-in GLiNER NER engine (PII_ENGINE), device-agnostic Swap the 4 NER entity types (PERSON/LOCATION/NRP/DATE_TIME) to a single multilingual GLiNER zero-shot model when PII_ENGINE=gliner; spaCy stays the default and all ~36 regex/checksum recognizers are identical on both engines. Device-agnostic via PII_DEVICE / cuda auto-detect — same code on Fargate CPU now and EC2-GPU later. - engines.py: side-effect-free builders; SharedModelGLiNERRecognizer loads ONE model shared across the 5 per-language instances and restricts labels to the entities it owns; small spaCy models keep tokenization/lemmas for the regex recognizers; fail-fast on the lean image - pii.Dockerfile: multi-stage — default target unchanged (lean spaCy); --target gliner is a superset (torch CPU + gliner + baked model) where both engines work; gliner-gpu scaffold for the GPU fleet - CI publishes the gliner variant (:staging-gliner/:latest-gliner, amd64) - Helm: pii.engine / pii.device values wired to PII_ENGINE/PII_DEVICE - scripts/bench_engines.py: throughput + NER-parity diff harness - tests: unit (mocked GLiNER) + in-image integration for both engines Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Up3F97mjCH9HCj1pX4J8VJ * refactor(pii): ship both engines in one image — engine is a pure env flip Collapse the gliner build target into the single pii image: spaCy lg models, torch (CPU), gliner, and the baked GLiNER weights all ship in it, so PII_ENGINE switches engines with no image swap and no tag matrix. CI reverts to the single pii build (no -gliner tags). The GPU variant becomes the same Dockerfile built with --build-arg TORCH_INDEX_URL=.../cu128. Image grows ~6.1GB -> ~9.6GB. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Up3F97mjCH9HCj1pX4J8VJ --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
4aba3dc5b4 |
improvement(landing): homepage redesign with live hero and real platform UI feature cards (#5408)
* improvement(landing): homepage redesign with live hero and real platform UI feature cards * improvement(landing): build-card workflow showcase, real Logs UI monitor window, proportional feature cards - Build card: replace the Mothership chat loop with a static left-to-right support-triage workflow showcase (two triggers converging on a triage agent, fanning out to Linear/Slack/Gmail/Tables) on the hero's solid --surface-3 stage, with the goo cycle loader phasing in the bottom-left corner; the chat animation component stays parked in build-callout/components for reuse - Monitor card: swap the floating logs panel for the REAL platform Logs page captured as a full window (new capture-logs-ui pipeline), framed and positioned identically to the Context card, over a new canyon backdrop - Feature cards scale like Cursor's: media stages are aspect-locked (3:2 desktop, 4:3 stacked) instead of fixed-height, and the UI-window callouts use percentage insets so the whole composition scales proportionally with the browser - Eyebrow chips relocate into the copy column above the title on stacked breakpoints instead of overlapping the full-width media - Extract the hero stage's block card for reuse; export the horizontal smoothstep edge helper; drop the unused formation-graph and logs-table-preview components Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(landing): use surface-hover token for voice input button Matches the token already used by its sibling composer buttons instead of a raw hex hover color. * fix(landing): restore SandboxWorkspacePermissionsProvider for the capture harness Staging removed the sandbox provider as unused when the academy pages were deleted (#5388), but the landing-preview capture route committed on this branch imports it - the branch failed to compile after rebasing. Restore the lightweight provider with its consumer documented. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(landing): satisfy HydrationState type in capture harness The mock hydration state set by the readme-tour-capture route was missing the required requestId/error fields added to HydrationState, breaking the production typecheck. * fix(landing): address Greptile/Cursor review findings - hero.tsx: object-top-left isn't a real Tailwind v3 utility, so the crop fell back to center; use object-left-top. - hero-workflow-stage.tsx: byId/builtIds were rebuilt on every render, including every drag pointermove frame; hoist the STAGE_BLOCKS lookup to module scope and memoize builtIds on builtCount. - hero-platform-loop.tsx: prefers-reduced-motion was only read once on mount, so toggling it mid-loop didn't stop the scheduled animation; listen for the media query's change event like BuildChatAnimation does. - landing-preview/page.tsx and readme-tour-capture/[workspaceId]/page.tsx: both are dev/preview-only scaffolds (one explicitly "local-only... delete before committing") that were reachable in production with no auth guard. 404 them outside of production instead of leaving them open. * fix(landing): reset fading when reduced motion cuts the loop short showFinished (added when wiring up the prefers-reduced-motion change listener) set the finished phase but left fading true if the preference flipped mid reset-fade, leaving HeroChatLoop stuck at opacity-0. * fix(landing): sync reduced-motion mid-reply in HeroChatLoop The word-reveal effect only checked prefers-reduced-motion once per showReply transition. If HeroPlatformLoop's showFinished set phase to 'reply' while it was already 'reply' (no re-render, no dependency change), the running stream interval kept ticking at normal speed instead of snapping to the full reply. Listen for the media query's change event, mirroring the fix already applied to HeroPlatformLoop and BuildChatAnimation. * fix(landing): sync reduced-motion mid-entrance in HeroStat HeroStat's staggered count-up entrance only checked prefers-reduced-motion once on mount, unlike the hero loops in this PR that now listen for the media query's change event. Toggling the preference mid-entrance left the scheduled timers/RAF running instead of snapping to the settled value. * fix(landing): stop double-seeding query cache in capture harness seed(queryClient) ran inside a useState lazy initializer, a render-phase side effect that Strict Mode invokes twice. Replace it with a ref guard so the store mutation runs exactly once, still synchronously before first paint. Flagged across three Greptile review rounds. * fix(landing): type the capture harness log filter seed as LogFilters qc.setQueryData(logKeys.list(...)) requires LogFilters, but the inline seed object had no annotation and timeRange inferred as string, which TypeScript widened past the TimeRange literal union. Failed prod build type-check. Also swap the stray `sandbox` prop back to `embedded` to match Workflow's actual prop name. --------- Co-authored-by: andresdjasso <andresdjasso@users.noreply.github.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com> Co-authored-by: waleed <walif6@gmail.com> |
||
|
|
12fb4a9db1 |
feat(db): auto-apply tracked script data migrations in db:migrate (#5497)
* feat(db): auto-apply tracked script data migrations in db:migrate * fix(db): reset session lock_timeout before script migrations, guard journal insert * improvement(db): re-verify advisory-lock session before script migrations |
||
|
|
41fdcdb5d3 | fix(knowledge): accept relative internal file URLs in document processor (#5499) | ||
|
|
aad254464b |
fix(copilot): don't surface custom blocks whose definition was deleted (#5498)
* fix(copilot): keep custom blocks out of the VFS static component cache so a deleted definition doesn't linger * fix(copilot): drop deleted-definition custom blocks from a workflow's state so the copilot can't see unrenderable blocks * fix(copilot): don't strip placed custom blocks when the definition load fails (null vs empty set) * refactor(copilot): drop unreachable static-cache custom-block filter The VFS static cache is only ever built by materialize(), which runs outside any custom-block overlay (the overlay is scoped to edit_workflow / get_blocks_metadata, neither of which materializes the VFS). So getAllBlocks() there always returns first-party blocks only and no custom block can be frozen into the cache. Removed the dead guard. |
||
|
|
858f7d2c2c |
fix(api-block): stop spoofing a browser fingerprint on outbound HTTP requests (#5496)
* fix(api-block): stop spoofing a browser fingerprint on outbound HTTP requests getDefaultHeaders() sent a Chrome User-Agent, a Referer pointing at Sim's own app, and mismatched Sec-Ch-Ua client hints on every API block request. Atlassian's Jira/Confluence Cloud REST API (and other browser-aware anti-CSRF/bot-defense layers) reject requests carrying a browser User-Agent with 403 "XSRF check failed", even with a valid Basic-auth header and X-Atlassian-Token: no-check set. Default headers now identify honestly as Sim, matching how other HTTP clients (curl, Postman, axios) behave. User-supplied headers still override any default. * fix(testing): sync shared tool-tester mock headers with new defaults createMockHeaders in the shared @sim/testing tool-tester builder still hardcoded the old Chrome UA / Referer / Sec-Ch-Ua fallback values. It was unreachable in current tests but would silently diverge from production getDefaultHeaders() for any future test hitting its fallback path. |
||
|
|
619e912256 |
fix(tables): canonicalize date cells, render times in effective timezone (#5465)
* fix(tables): canonicalize date cells, render times in effective timezone * improvement(tables): render date cells wall-clock-faithful via offset-preserved storage * fix(tables): address review — preserve midnight instants, validate calendar days, effective-zone Today |
||
|
|
60e3509811 |
fix(tables): server-authoritative run badge, tail SSE from latest, harden Stop-all (#5492)
* fix(tables): server-authoritative run badge, tail SSE from latest, harden Stop-all * fix(tables): return null dispatchId when Stop-all cancels a run during prep * improvement(tables): co-locate dispatcher imports, stamp throttle clock only on fetch start * fix(tables): table-wide hasRunning signal for Queueing label, fail fast on seq-read errors * fix(tables): clear hasRunning on table-wide stop, refetch rows when a run resolves without a dispatch * fix(tables): don't let dispatch-cancel cleanup mask the original prep failure * fix(tables): reconcile null-dispatch runs via invalidation, not stale snapshot restore * fix(tables): widen warm-cache remount check to either query cache |
||
|
|
56cd2cfa7c | feat(custom-block): audit-log publish, update, and unpublish events (#5493) | ||
|
|
61ceedc5b9 |
fix(notion): align integration with live API docs, add block retrieval coverage (#5491)
* fix(notion): align integration with live API docs, add block retrieval coverage
- wire up notion_update_page in the block (was registered but unreachable — no dropdown option or subBlocks)
- fix legacy NotionBlock outputs to cover all 17 operations, not just content/metadata
- trim ID params (pageId, databaseId, parentId) before use in request URLs across 8 tool files
- remove content required:true on create_page (Notion allows title-only pages)
- remove dead unused NotionReadDatabaseParams interface
- add notion_retrieve_block/_v2 tool for GET /v1/blocks/{id}, filling a gap in block CRUD coverage
* fix(notion): second validation pass — pagination gaps, phantom outputs, dead types, regen docs
- add missing startCursor/start_cursor pagination param to notion_query_database and notion_search
- fix notion_search missing from the shared pageSize/startCursor field's operation condition in NotionBlock
- fix NotionV2Block title/url/created_time/last_edited_time outputs rendering unconditionally for every operation instead of only the ones that return them
- remove 153 lines of dead unused output-shape constants from types.ts
- regenerate integration docs
* fix(notion): expose retrieve-block outputs in legacy block picker
type/block/archived only conditioned on notion_update_block/notion_delete_block,
and has_children was missing entirely — Retrieve Block's payload was invisible
in the legacy NotionBlock output picker (Greptile P1 on PR #5491).
* fix(notion): document type-specific content gap on retrieve_block output
block.properties (BLOCK_OUTPUT_PROPERTIES) only covers common block fields,
not the type-specific sub-object (paragraph.rich_text, image.file, etc.) —
that varies per block type and isn't enumerable. Documented in the
description per Greptile P2 on PR #5491; no functional change, block: data
already carries the full object at runtime.
|
||
|
|
ed1492bcbd |
fix(google-vault): validate against live API docs, add matter/hold/saved-query CRUD coverage (#5482)
* fix(google-vault): validate integration against live API docs, add matter/hold/saved-query CRUD coverage
- Fix critical bug: create_matters_export sent the deprecated Query.searchMethod field (deprecated 2019, support ended 2020) instead of method, silently breaking account/org-unit scoped exports
- Fix duplicate matterId subBlock id (two definitions collided across operations)
- Add matter lifecycle: update, close, reopen, delete, undelete
- Add matter collaborator management: add/remove permissions
- Add export delete
- Add hold update, delete, add/remove held accounts
- Add saved query create/list/delete
- Bump tool versions to 1.0.0 to match repo convention
- Fix docsLink to point at docs.sim.ai instead of the vendor site
- All new endpoints are covered by the existing ediscovery + devstorage.read_only OAuth scopes (no new scopes requested)
* fix(google-vault): pageToken should be user-or-llm visibility, not hidden
Greptile review: hidden is reserved for framework-injected tokens; pageToken
in list_saved_queries.ts should be user-or-llm so an agent/user can pass it,
matching the pattern used elsewhere for tool-supplied pagination cursors.
* fix(google-vault): fail loudly instead of silently clearing hold scope on update
Cursor Bugbot: PUT holds/{id} replaces the full resource — a name/query-only
update with no accountEmails/orgUnitId would silently drop the hold's
custodian coverage. Now throws a clear error directing callers to resend the
scope or use add_held_accounts/remove_held_accounts for incremental changes.
* fix(google-vault): reject unscoped exports/saved-queries for non-MAIL corpus
Independent audit (parallel doc-verification pass): create_matters_export
and create_saved_query resolved Query.method to undefined when corpus
wasn't MAIL and no accountEmails/orgUnitId was given, silently sending an
invalid request (method is a required Query field) instead of a clear
error. Now throws with an actionable message before the request is sent.
* fix(google-vault): document full-replace semantics on hold update query filters
Cursor Bugbot: update_matters_holds only sets query.mailQuery/groupsQuery/
driveQuery when terms/date/shared-drive fields are provided, but the PUT
replaces the whole hold — omitting a previously-set filter clears it, not
leaves it unchanged. Filters are legitimately optional (a hold may have
none), so this can't be hard-required like scope; instead the tool and
field descriptions now explicitly state the full-replace behavior and
direct callers to resupply current values via Vault List Holds first.
* fix(google-vault): isolate stale-value-prone subblocks per operation
Cursor Bugbot: consolidating shared subblocks across operations left two
cross-contamination risks since a stale value from one operation stays in
block state until overwritten:
- accountEmails/orgUnitId are checked emails-first with silent either/or
priority; sharing them across update_matters_holds and create_saved_query
meant a leftover value from a different operation could silently override
the intended scope. Gave both operations dedicated fields
(updateHoldAccountEmails/updateHoldOrgUnitId, savedQueryAccountEmails/
savedQueryOrgUnitId), remapped in tools.config.params.
- matterId presence alone switches google_vault_list_matters between
list-all and single-get. Sharing it with every other operation meant a
leftover matterId could silently turn "List Matters" into a single-matter
fetch. Gave list_matters its own optional listMatterId field.
create_matters_holds/create_matters_export keep sharing accountEmails/
orgUnitId as before this PR (pre-existing behavior, not introduced here).
* fix(google-vault): isolate list-optional-id fields from required-elsewhere counterparts
Cursor Bugbot: exportId/holdId/savedQueryId were shared between their
respective list operation (optional filter) and update/delete/held-account
operations (required). A stale ID left over from a delete/update on the
same block instance would silently narrow the corresponding list operation
to a single-resource get instead of listing the collection. Gave each list
operation its own dedicated optional field (listExportId, listHoldId,
listSavedQueryId), remapped in tools.config.params — same pattern already
used for listMatterId.
* fix(google-vault): defensively order mutually-exclusive scope spreads
Greptile: savedQueryAccountEmails/savedQueryOrgUnitId spread after their
updateHold* counterparts, so if both were ever truthy at once the wrong
one would silently win. In practice they're mutually exclusive (each only
populated while its own single 'operation' value is selected, so at most
one pair is ever truthy), but reordering costs nothing and removes any
doubt about precedence.
* docs: regenerate integration docs
Reruns scripts/generate-docs.ts against the current block/tool/trigger
registry. Picks up google_vault's new operations plus everything else that
had landed on staging without a docs regen (bigquery, google_calendar,
google_maps, onedrive, microsoft_teams, gitlab, github, discord, dropbox,
and others), plus icon and integrations.json updates.
|
||
|
|
0134a5b9a1 |
fix(onedrive): align tools with live Graph API docs, add missing endpoints (#5478)
* fix(onedrive): align tools with live Graph API docs, add missing endpoints
- wire up search/move/copy/create_share_link tools into block operation switch (were registered but unreachable, would throw 'Invalid OneDrive operation')
- fix tools.config.params to remap new canonical subBlock ids to correct tool param names
- add onedrive_get_item and onedrive_get_drive_info tools (item metadata, drive quota) — both within existing Files.Read/Files.ReadWrite scope
- add missing block inputs/outputs for new operations
- alphabetize onedrive registry entries
* fix(onedrive): escape single quotes in search query, document embed link type
- encodeURIComponent doesn't escape single quotes, breaking the OData
string literal for filenames containing an apostrophe
- clarify create_share_link's linkType description to include 'embed',
which the block UI already exposes as a valid option
* fix(onedrive): add real pagination continuation to search
- add pageToken param that follows the @odata.nextLink continuation
URL directly, so nextPageToken output is actually consumable
instead of a dead end
- wire pageToken through the block as an advanced-mode field on the
search operation
* fix(onedrive): prevent SSRF/token exfiltration via search pageToken
pageToken was used verbatim as the request URL with no host
validation, while the Authorization header is always attached —
a crafted pageToken pointing at an attacker-controlled host would
leak the OAuth access token. Pin the continuation URL to
graph.microsoft.com before using it.
* fix(onedrive): make search query optional for pageToken-only continuation requests
* fix(onedrive): fix folder-targeting wiring, OData escaping, and downloadUrl selection
- upload/create_folder/list all read params.folderSelector/manualFolderId, but
the block only ever sends folderId — folder targeting silently fell back to
drive root. Consolidate to a single folderId param matching what the block
sends (same pattern already used for destinationFolderId on move/copy)
- search's percent-encode-then-replace('%27') "escape" is undone by Graph's
standard URL-decode-before-parse, so an apostrophe in a query still breaks
the OData string literal; list's $filter had no escaping at all. Both now
double literal quotes (the correct OData V4 escape) via a shared
escapeODataStringLiteral helper before encoding
- get_item/list/search all omitted @microsoft.graph.downloadUrl from $select,
so webContentLink was always undefined on their outputs; added it
- list gains the same pageToken continuation support search already has, and
the block's Page Token field is now shown for both operations
* fix(onedrive): reuse shared assertGraphNextPageUrl for page-token validation
Hostname-only check let http://graph.microsoft.com/... continuation tokens
through, which would send the Bearer token over cleartext. Sibling Graph
integrations (sharepoint, microsoft_teams, microsoft_planner, microsoft_ad)
already share assertGraphNextPageUrl/getGraphNextPageUrl in
tools/sharepoint/utils.ts, which checks the full origin (scheme + host).
Reuse it in list/search instead of hand-rolling the check twice.
|
||
|
|
8fcce5100c |
fix(aws): align cloudwatch, cloudformation, athena, codepipeline with live API docs (#5483)
* fix(aws): align cloudwatch, cloudformation, athena, codepipeline with live API docs - cloudwatch: fix list_metrics pagination (wasn't draining pages past 500), add MaxRecords cap validation to describe_alarms; add describe_alarm_history, filter_log_events, put_log_group_retention - cloudformation: fix get_template missing TemplateStage param, fix invalid ModuleTag in block metadata; add full stack lifecycle tools (create/update/delete/cancel_update_stack, create/describe/execute_change_set, get_template_summary) - athena: fix missing .trim() on query/named-query ID fields; add delete_named_query, batch_get_query_execution, list_databases, list_table_metadata - codepipeline: fix missing rollbackMetadata field in list_pipeline_executions response; add get_pipeline, list_action_executions, disable/enable_stage_transition * fix(aws): require template on cloudformation change-sets, bump route-count baseline - cloudformation create_change_set now rejects requests missing both templateBody and usePreviousTemplate, matching update_stack (Cursor Bugbot finding) - bump check:api-validation route-count baseline 906->917 to reflect the 19 new fully contract-bound routes added in this PR (0 boundary violations) * fix(aws): address Greptile round-1 review findings - cloudwatch describe_alarm_history: always request both MetricAlarm and CompositeAlarm types, even when alarmName is provided (was silently returning empty history for composite alarms queried by name) - cloudformation: add validateAwsRegion refinement to region field on the 7 new write-path contracts (update/delete/cancel-update-stack, create/describe/execute-change-set, get-template-summary), matching the pattern already used elsewhere - cloudformation: destroy the AWS SDK client in a finally block on the same 7 new write routes, matching the pattern used by every other new route in this PR * fix(aws/cloudformation): add missing region validation and client cleanup to create-stack - Add validateAwsRegion refinement to create-stack contract (completes P2 fix from Greptile review) - Wrap AWS SDK call in try/finally with client.destroy() (completes P2 fix from Greptile review) - Aligns create-stack with the pattern used across all 7 other new CloudFormation routes Co-authored-by: Waleed <waleedlatif1@users.noreply.github.com> * fix(aws): final validation pass — bound missing limits, close consistency gaps - cloudformation create_stack: add missing validateAwsRegion refine and client.destroy() finally block, matching sibling write routes - cloudwatch get_metric_statistics: cap statistics array at AWS's 5-item limit - cloudwatch get_log_events: cap limit at AWS's 10,000-record max - athena batch_get_query_execution: surface engineExecutionTimeInMillis/queryPlanningTimeInMillis/queryQueueTimeInMillis, matching the sibling get_query_execution tool's Statistics mapping * fix(aws/athena): destroy AWS SDK client on the 4 new athena routes Cursor Bugbot finding: batch_get_query_execution, delete_named_query, list_databases, and list_table_metadata created an AthenaClient but never called client.destroy(), unlike every other new route in this PR. Wrapped each in try/finally to match. * fix(aws/athena): add validateAwsRegion refinement to the 4 new contracts Greptile finding: delete_named_query, batch_get_query_execution, list_databases, and list_table_metadata accepted any non-empty string for region, unlike every other new contract in this PR. --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Waleed <waleedlatif1@users.noreply.github.com> |
||
|
|
d32b9661d6 |
fix(microsoft-dataverse): align integration with live API docs, add table metadata tool (#5481)
* fix(microsoft-dataverse): align integration with live API docs, add table metadata tool - trim environment URL/entity/record IDs across all tools via shared getDataverseBaseUrl - encodeURIComponent OData $select/$filter/$orderby/$expand values in list_records/get_record - fix $top being silently ignored when Prefer: odata.maxpagesize is also sent - add microsoft_dataverse_get_entity_metadata tool for table/column lookup (covered by existing user_impersonation scope, no new scopes) * fix(microsoft-dataverse): clear stale select subBlock when mapping metadataSelect * fix(microsoft-dataverse): escape OData quotes in entity metadata key, surface JSON parse errors * fix(microsoft-dataverse): fix function alias params, add upload size guard, restore file output back-compat - execute_function: support @p1/@p2 parameter alias query-string bindings for values with reserved characters, per Dataverse Web API function docs - upload-file route: reject files over Dataverse's 128MB single-request upload ceiling with a clear error instead of an opaque API failure - download_file: add canonical `file` output (type: 'file') so downloaded bytes get persisted through Sim's execution file storage like every other file-download tool, while keeping the pre-existing fileContent/fileName/fileSize/mimeType fields for backwards compatibility with existing workflows * improvement(microsoft-dataverse): clarify fileColumn output description |
||
|
|
1a87f1a83c |
fix(microsoft-planner): align with live Graph API docs, add plan CRUD + categories (#5486)
* fix(microsoft-planner): align with live Graph API docs, add plan CRUD + categories
- fix update_task never returning updated task (missing Prefer: return=representation)
- fix wrong @odata.type on task assignments (missing leading #)
- fix update_plan/update_plan_details/update_bucket/update_task_details crashing
on 204 No Content responses to PATCH (Graph sometimes ignores Prefer header)
- add .trim() on path IDs across tools invoked outside the block
- add create_plan, update_plan, delete_plan, get_plan_details, update_plan_details
tools (If-Match/etag handled correctly on update/delete)
- add appliedCategories support on create_task/update_task
- all new tools verified against Graph API Permissions tables to require only
scopes we already request (Group.ReadWrite.All, Group.Read.All, Tasks.ReadWrite)
- regenerate integration docs
* fix(microsoft-planner): use Graph-specific error extractor consistently
7 tools were pinned to the generic 'nested-error-object' extractor
instead of MICROSOFT_GRAPH_ERRORS, losing Graph's inner-error detail
(e.g. ETag mismatch specifics) that sibling Microsoft integrations
(Excel, OneDrive, SharePoint) already surface correctly.
* fix(microsoft-planner): address Cursor/Greptile round-1 review findings
- fix empty priority/percentComplete string coercing to 0 (Number('')) at
the block layer, which Planner treats as urgent/0% instead of leaving unset
- support removing applied categories on update via a "-category3" prefix,
since Graph only clears a label when its key is explicitly set to false
- add missing MICROSOFT_GRAPH_ERRORS extractor to delete_plan/get_plan_details
* fix(microsoft-planner): don't return a stale etag on 204 update_task response
Graph's If-Match update changes the resource's etag even when it returns
204 No Content instead of the updated representation. Returning the
request's (now-stale) etag as if it were current would let a chained
update silently send a wrong If-Match and fail with 412. Return an empty
etag instead so update_task's own etag-required guard forces a re-fetch.
|
||
|
|
98dc1eea39 |
fix(google-maps): validate integration against live API docs, add Places Nearby Search (#5484)
* fix(google-maps): validate integration against live API docs, add Places Nearby Search - add google_maps_places_nearby tool (Places API New, searchNearby) for radius/type-based place discovery - add pageToken support to places_search (text search pagination) - add units param to speed_limits (Roads API KPH/MPH) - wire homeMobileCountryCode/homeMobileNetworkCode subblocks for geolocate - split radius subblock so places_nearby's required radius isn't hidden in advanced mode - add default value to rankPreference dropdown - add missing authMode: AuthMode.ApiKey on the block * fix(google-maps): mark elevation resolution optional per API docs Google's Elevation API omits resolution when it can't be determined, but our output schema declared it as a required number. Also fixes a stale comment calling Speed Limits "deprecated" when it's actually Asset Tracking-license restricted. * fix(google-maps): guard radius NaN parse, surface pageToken delay caveat - radius parsing in transformParams now guards NaN like every other numeric param in this block, so a non-numeric radius no longer silently sends "radius":null to the required Nearby Search field - pageToken description/placeholder now note the required delay before a token becomes valid, per Places Text Search API behavior |
||
|
|
82de72597f |
fix(google-calendar): align with live API docs, add calendar/ACL update+delete tools (#5485)
* fix(google-calendar): align with live API docs, add calendar/ACL update+delete tools - remove any types from V2 response typing in get/move/quick_add/instances - add google_calendar_update_calendar (PATCH calendars.patch) - add google_calendar_delete_calendar (DELETE calendars.delete) - add google_calendar_update_acl (PATCH acl.patch) - all new tools covered by existing calendar OAuth scope, no new scopes requested * fix(google-calendar): dedupe GoogleCalendarAclRole type in update_acl.ts export it from types.ts and import instead of redeclaring locally |
||
|
|
8174182e69 |
feat(bigquery): validate integration + add dataset/table lifecycle tools (#5480)
* feat(bigquery): validate integration against live API docs, add dataset/table lifecycle + query-result tools - Cross-checked existing query/list_datasets/list_tables/get_table/insert_rows tools against BigQuery REST v2 docs; no critical issues found - Added 6 new tools covered by the existing bigquery OAuth scope: create/delete dataset, create/delete table, list table data, get query results - Wired new operations into the block (subblocks, conditions, tools.config), registry, and barrel exports * fix(bigquery): address Greptile + Cursor Bugbot review findings - create_table: guard JSON.parse on the schema field with a clear error, trim tableReference IDs in the request body - create_dataset: trim datasetId in the request body - block: stop leaking a stale query "location" value into create_dataset when datasetLocation is empty; clarify pageToken output description covers list_table_data and get_query_results too * fix(bigquery): address second round of Cursor Bugbot findings - create_table: validate parsed schema is a non-empty array of field objects with a name, not just syntactically valid JSON - get_query_results: guard timeoutMs with Number.isFinite before appending to the query string, matching maxResults * fix(bigquery): final alignment pass from independent multi-agent validation - Add missing projectId block output (returned by get_table/create_table/create_dataset but was silently dropped from the block's output schema) - Switch query/rows/schema subBlocks from long-input to code, matching the JSON/SQL field convention used by every other DB integration (clickhouse, mongodb, postgresql, supabase) * fix(bigquery): stop leaking stale datasetId/tableId into create_dataset/create_table Same class of bug as the earlier location leak: params() spread hidden datasetId/tableId from ...rest unconditionally, so a stale value from a previously-selected operation could survive into create_dataset/create_table if the dedicated new-ID field was somehow empty. Gate datasetId/tableId (and location) to the operations that actually use them, via shared op-list constants also reused by the corresponding subblock conditions. |
||
|
|
f36461465b |
improvement(email): reply-to help@sim.ai for lifecycle and billing emails (#5487)
* improvement(email): reply-to help@sim.ai for lifecycle and billing emails - onboarding follow-up (5-day), payment-failed, and abandoned-checkout emails now reply-to the shared help inbox instead of a personal address - added getHelpEmailAddress() and reused it in the help route to remove the duplicated inline expression * fix(email): address Greptile review feedback - add a sendEmail assertion locking in the payment-failure email's replyTo - clarify getPersonalEmailFrom() JSDoc so it doesn't overstate replyTo's scope |
||
|
|
a48ecd2538 |
fix(posthog): validate integration against live API docs, add self-hosted support + CRUD coverage (#5476)
* fix(posthog): validate integration against live API docs, add self-hosted support + CRUD coverage
Fix missing response.ok checks across ~36 tools that silently treated
error bodies as success. Fix delete_feature_flag ignoring failure
responses, evaluate_flags targeting the undocumented /decide endpoint
without the required api_key body field, and batch_events reporting a
hardcoded events_processed count.
Add self-hosted host support (utils.ts) alongside the existing US/EU
region selector, and complete CRUD coverage with 5 new tools:
update_insight, update_cohort, update_experiment, delete_survey,
create_dashboard.
* fix(posthog): remove dead response.ok checks, fix real schema/endpoint bugs
The prior commit added if (!response.ok) branches inside transformResponse
across ~40 tool files. This is dead code — tools/index.ts already throws
on non-2xx (and error-payload) responses before transformResponse is ever
invoked, so transformResponse only ever receives already-successful
responses. Reverted to the idiomatic no-error-branch pattern used
elsewhere in the codebase (e.g. hunter/email_verifier.ts), and added a
posthog-errors errorExtractor so the framework's own error throw surfaces
PostHog's real {type, code, detail, attr} error shape instead of a
generic status message.
Verified against PostHog's live OpenAPI schema, fixed real bugs:
- delete_feature_flag: DELETE always returns 405 (hard delete not
allowed); switched to PATCH with deleted: true
- delete_person: no single-person DELETE endpoint exists; switched to
POST .../persons/bulk_delete/ with ids: [personId]
- create_annotation: insight_short_id is read-only on create; the
writable field is dashboard_id
- removed nonexistent fields (experiment variants, insight
filters/saved) not present in the current schema
- added missing trailing slashes on feature-flag/experiment URLs
* fix(posthog): reject unsafe self-hosted host values (SSRF)
The self-hosted host field accepted any string and only stripped
trailing slashes before prepending https://, so a workflow could point
it at loopback/private/link-local addresses (e.g. cloud instance-
metadata endpoints) and the executor would make a real server-side
request to it. Reuse the shared validateExternalUrl SSRF guard, same
pattern already used for Convex's custom deployment URL
(tools/convex/utils.ts); the tool executor separately re-validates with
DNS resolution and pins the resolved IP for the actual request.
Also drop an unused params arg in evaluate_flags' headers function.
* fix(posthog): fail loudly instead of silently dropping data on bad JSON params
Several tools caught JSON.parse failures on user-supplied filter/query/
parameters strings and silently substituted {} or null, which would
wipe the corresponding field on the PATCH/create request instead of
surfacing an error (Cursor Bugbot flagged this for update_cohort,
update_experiment, update_insight; the same pattern existed in their
create_* / update_feature_flag / evaluate_flags counterparts, fixed for
consistency). Now throws a descriptive error, matching the existing
convention in tools/notion/query_database.ts.
Also fixes batch_events: the request body silently sent an empty batch
on invalid JSON, and transformResponse always reported "captured
successfully" even when PostHog's response indicated failure
(data.status !== 1).
* fix(posthog): mark region required for update_experiment
posthog_update_experiment was the only experiment operation missing
from the region field's required-condition list; the other three
(create/get/list) already require it. Region is unconditionally
visible on this block (no condition key gates it), so this was a
required-ness inconsistency rather than a functional bug, but users
updating an EU experiment should still be prompted to select the
region explicitly rather than relying on the default.
* fix(posthog): fix cross-field value leakage and false-success reports
Merges update_insight's query subblock into the same insightQuery id
already used by create_insight (Cursor flagged: it previously reused
the 'query' subblock id shared by posthog_query's HogQL field and the
cohort query fields, so switching operations could carry a stale
HogQL/cohort-JSON value into an insight PATCH). Matches the existing
merged-condition pattern used elsewhere in this block instead of
duplicating the subblock id.
Also fixes two more false-success reports in the same class as the
batch_events/delete_feature_flag fixes: capture_event now checks the
ingest response's status field (same {"status": 1} contract as
/batch/) instead of unconditionally returning success, and
delete_person now reports failure when persons_deleted is 0 instead of
always success: true.
|
||
|
|
954fdd8595 |
fix(gmail): stop wrapping draft/send HTML body in per-paragraph <p> tags (#5479)
* fix(gmail): stop wrapping draft/send HTML body in per-paragraph <p> tags * fix(gmail): use <br> instead of CSS white-space for line breaks white-space: pre-wrap has inconsistent email-client support (including Gmail for non-Google accounts per caniemail.com); <br> is the client-agnostic standard for plain-text-to-HTML line breaks. |
||
|
|
03462b9289 |
fix(microsoft-teams): align tools with live Graph API docs, add missing endpoints (#5477)
* fix(microsoft-teams): align tools with live Graph API docs, add missing endpoints - fix list_channel_members/list_team_members falling back to userId when email is missing - add $top=50 pagination to read_channel for parity with read_chat - add list_teams, list_chats, list_channels, list_chat_members tools so agents can discover ids without the UI selectors - all new tools use only existing granted scopes (Team.ReadBasic.All, Chat.ReadBasic, Channel.ReadBasic.All) — no new OAuth scopes requested * fix(microsoft-teams): surface pagination truncation via hasMore flag - add hasMore output (derived from @odata.nextLink presence) to list_teams, list_chats, list_channels, list_chat_members so agents can detect truncated results instead of trusting the count field as a total - do NOT add $top to list_teams' joinedTeams request — Graph docs explicitly state this endpoint does not support OData query parameters, so it would silently no-op |
||
|
|
fe7d043f38 |
feat(custom-block): move management to enterprise settings; derive inputs live from deployed start (#5453)
* feat(custom-block): move management to enterprise settings; derive inputs live from deployed start * fix(custom-block): key custom-blocks query by workspaceId (react-query audit) * fix(custom-block): restore icon on discard instead of clearing the saved image * fix(custom-block): track create-flow dirty state and reset selections on discard * fix(custom-block): merge placeholders for id-less start fields; compare inputs by authored data only * improvement(custom-block): dedup input-mapping helper, reuse SettingsResourceRow + shared reserved-param set * fix(custom-block): keep disabled blocks resolvable so placed instances fail loudly instead of vanishing * fix(custom-block): derive fields for disabled blocks so edits keep placeholders; reseed edit form after async load * fix(custom-block): scope publish workspace picker to the current org |
||
|
|
c34a3bc64f |
fix(discord): align tools with live API docs, add missing endpoints (#5472)
* fix(discord): align tools with live API docs, add missing endpoints - fix ban_member deprecated delete_message_days -> delete_message_seconds - fix get_server phantom member_count/channels outputs, add with_counts support - fix create_thread missing type field causing silent private-thread default - fix delete_channel to return the deleted channel body - fix get_pinned_messages to use the current (non-deprecated) pins endpoint and drop an unused required serverId param - add .trim() on all URL-interpolated IDs and bot tokens across every tool - add discord_list_channels, discord_list_roles, discord_get_pinned_messages, discord_bulk_delete_messages - fix block subBlock required flags (userId, content, messageId) to match each operation's actual tool requirements - remove orphaned Discord OAuth scope descriptions (Discord uses bot tokens, not OAuth) * fix(discord): guard against whitespace-only messageId in create_thread Cursor Bugbot found that a whitespace-only messageId was treated as present (truthy), routing to the message-thread URL and trimming to an empty path segment instead of creating a standalone thread. * fix(discord): guard whitespace userId, add pins pagination - remove_reaction: whitespace-only userId no longer breaks the /@me fallback (Cursor Bugbot) - get_pinned_messages: add limit/before query params so pins beyond the first page (max 50) can be retrieved (Cursor Bugbot) - export DiscordMessage type and properly type pinned-message mapping * fix(discord): clamp shared limit subBlock to 1-50 for pinned messages The limit subBlock is shared between discord_get_messages (max 100) and discord_get_pinned_messages (max 50 per Discord's API), so a value carried over from the messages operation could exceed the pins endpoint's max and trigger a 400. Clamp at both the block dispatcher and the tool's request builder. * fix(discord): validate 2-100 message count before bulk delete Discord's bulk-delete endpoint requires 2-100 message IDs; forwarding an out-of-range count produced an opaque Discord API error instead of a clear preflight message. |
||
|
|
f3a65e164f |
fix(brightdata): align integration with live API docs, add markdown/mode/error-report support (#5470)
* fix(brightdata): align integration with live API docs, add markdown/mode/error-report support
- fix Discover numResults docs (max 20, not 1000) and contentFormat value ("md" not "markdown", which the API always rejected)
- add Discover mode param (standard/deep/fast/zeroRanking)
- add markdown output support to Web Unlocker scrape_url via data_format
- add include_errors support to scrape_dataset, matching sync_scrape
- add .trim() on datasetId in scrape_dataset/sync_scrape URLs
- add wandConfig on complex fields, tighten block output descriptions
* fix(brightdata): default mode field to empty so it's opt-in like other advanced params
Greptile flagged that mode shipped with a non-empty default ('standard'),
causing it to be sent on every Discover call unlike the sibling dataFormat
field which uses an empty/None default and only sends when the user opts in.
Aligns mode with that same pattern.
|
||
|
|
a5b8c7ecc4 |
feat(gitlab): add release and branch-compare tools, remove dead types (#5475)
* feat(gitlab): add release and branch-compare tools, remove dead types - Add gitlab_delete_branch, gitlab_compare_branches, gitlab_list_releases, gitlab_create_release tools + block wiring (fills gaps found during a full validate-integration pass against live GitLab API docs) - Remove 12 unexported, zero-consumer types left over from never-implemented tool ideas (labels, users, current-user, branch/notes listing) - Add filePath/branch block outputs that get_file/create_file/update_file already returned but weren't exposed - Broaden state/orderBy param descriptions to list all documented GitLab values * fix(gitlab): expose all tool-returned fields as block outputs - Add total, size, ref, blobId, lastCommitId, mergeRequestIid, changesCount, approvedBy, protected, id, status to the block outputs map — these fields are already returned by their respective tools but weren't declared as outputs - Add missing 'title' value to list_issues orderBy description * fix(gitlab): drop empty entries when splitting release milestones Trailing/extra commas in the milestones input (e.g. "v1, ,v2") would produce an empty string entry, which the GitLab API rejects. |
||
|
|
0132a04d90 |
fix(dropbox): align integration with Dropbox API docs, add revision/sharing tools (#5468)
* fix(dropbox): align integration with Dropbox API docs, add revision/sharing tools - fix search root-path bug: Dropbox requires "" not "/" for root, same fix already applied to list_folder - fix create_shared_link to return the existing link's metadata (url) when Dropbox reports shared_link_already_exists with matching settings, instead of just erroring - fix upload route autorename default (was true, Dropbox's documented default is false) - trim() all path/fromPath/toPath/rev params to guard against copy-pasted whitespace - mark nullable output fields (id, size, path_display, etc.) optional: true so folder/deleted items don't imply always-present file fields - widen path_display/path_lower types to optional, matching the real API - add dropbox_list_shared_links, dropbox_list_revisions, dropbox_restore tools + block wiring, filling gaps flagged during the audit (revision history/version recovery, and a companion to create_shared_link for looking up existing links) * style(dropbox): use ?? instead of || for boolean defaults in list_shared_links Consistency nit from Greptile review - matches the ?? pattern already used by every other transformResponse in this PR. * fix(dropbox): mark path_display/path_lower optional everywhere for consistency Greptile flagged that path_display was left required in list_folder.ts and list_revisions.ts despite being widened to optional in types.ts and most other output schemas in this PR. Fixed those two plus create_folder.ts, restore.ts, upload.ts, and list_shared_links.ts, which had the same gap. * fix(dropbox): list_shared_links path omission + list_revisions pagination Cursor Bugbot flagged two real gaps: - list_shared_links sent path: "" for root/all, but Dropbox only returns every link account-wide when path is omitted entirely; "" scopes to the root folder specifically. Now omits the field for root/empty/"/" input. - list_revisions exposed hasMore but no way to actually fetch more pages (Dropbox's before_rev cursor). Added a beforeRev param + advanced-mode block field. A third flagged issue (create_shared_link's error.shared_link_already_exists.metadata path) was verified against the official sharing.stone spec and confirmed correct as-is - replied on the PR thread with the citation, no change needed. * fix(dropbox): correct shared_link_already_exists JSON path The prior fix read data.error.shared_link_already_exists.metadata, which is wrong per Stone's own JSON serialization rules: a union member whose payload is a struct (SharedLinkMetadata) flattens that struct's fields alongside ".tag" rather than nesting under a wrapper key. The real shape is data.error.shared_link_already_exists directly (with an extra ".tag" field mixed in) - there is no nested .metadata key, so the existing-link fast path never fired before this fix. Also marks list_shared_links' expires output optional, matching every other optional field in this PR and the SharedLinkMetadata spec. * fix(dropbox): wire cursor pagination for List Shared Links in the block The dropbox_list_shared_links tool already accepted a cursor param, but the block never exposed it, so a workflow couldn't page past the first batch when hasMore was true. Adds an advanced-mode cursor subBlock + input entry, mirroring List Revisions' beforeRev field added in the same PR. |
||
|
|
a1e6744f30 |
fix(github): fix response bugs and add missing endpoint coverage (#5471)
* fix(github): fix response bugs and add missing endpoint coverage - Fix unauthenticated internal sub-fetch in pr.ts (list_pr_files) that 401'd on private repos and burned anon rate limits - Fix hardcoded/placeholder output fields in add_labels, delete_comment, delete_file - Handle 409 (sha mismatch) in merge_pr in addition to 405 - Loosen request_reviewers.reviewers to optional (team-only reviews) - Add items schema to get_commit parents array output - Add github_get_readme, github_create_pr_review, github_get_latest_release, github_list_tags (+ v2 variants) * fix(github): address review findings on pr.ts and delete_comment.ts - pr.ts: surface a real failure instead of silently returning success:true with an empty files array when the files sub-fetch fails; unify the sub-fetch Accept header with the rest of the file - delete_comment: success now tracks the actual deletion outcome instead of being hardcoded true * fix(github): guard new tools against non-2xx GitHub responses list_tags, get_readme, get_latest_release, and create_pr_review (v1 + v2) now check response.ok before parsing the payload as success data, returning success:false with a real error message instead of crashing on .map() or silently returning undefined fields when GitHub returns a 404/422/etc. |
||
|
|
9e3fc1fec3 |
feat(dub): expand link coverage and fix cross-operation param leakage (#5469)
* feat(dub): expand link coverage and fix cross-operation param leakage - add tenantId/folderId/trackConversion support and conversions output to link tools - add cursor pagination (startingAfter/endingBefore) to list_links, logo param to get_qr_code - add list_domains, list_tags, create_tag, list_folders tools - fix block param leakage where an unset field on one operation inherited a stale value left over from another operation * fix(dub): stop trackConversion from resetting existing links on update - only send trackConversion true or omit it, matching linkRewrite/linkArchived's partial-PATCH-safe pattern, so a routine update_link no longer silently disables conversion tracking on an existing link - include trackConversion in the cross-operation reset block so it can't leak a stale value into non-mutation operations either |
||
|
|
6d97b26dd8 |
feat(tinybird): validate integration against API, add job-status polling (#5474)
* feat(tinybird): validate integration against API, add job-status polling, scope block outputs - Validated all 6 existing tools against Tinybird's live REST API docs - Added tinybird_get_job tool to poll async import/delete jobs - Scoped block outputs with per-operation condition * fix(tinybird): align token-scope descriptions with Tinybird's plural scope names - events/query/query_pipe used singular DATASOURCE:/PIPE: scope names; Tinybird's Token API uses plural DATASOURCES:/PIPES: - append_datasource now notes DATASOURCES:APPEND also suffices, not just CREATE |
||
|
|
b70b21a68e |
fix(copilot): surface error cause chain in sim-to-go span status (#5473)
markSpanForError only recorded the top-level exception message, so a fetch() failure showed up as the generic "TypeError: fetch failed" with no indication of the real cause (ENOTFOUND, ECONNREFUSED, etc). Use describeError to walk the cause chain and set it as the span status message and an error.code attribute. |
||
|
|
e5b94326f7 | fix(granola): align get_note with real API spec (webUrl required, add speakerName) (#5467) | ||
|
|
3ddf254d4c | test(user-input): assert dismissed mention stays closed across repeated clicks (#5466) | ||
|
|
cad44b9996 |
fix(user-input): stop @mention/skill menu from reopening after dismiss (#5464)
* fix(user-input): stop @mention/skill menu from reopening after dismiss - Fixes a bug where the @mention (and /skill) autocomplete menu couldn't be dismissed: clicking away or pressing Escape closed it, but the very next click/selection change reopened it because the caret was still inside the unfinished @token - Adds a one-shot "dismissed" marker per token, set only on a real outside-click/Escape dismiss, cleared the instant the user types again - Shared fix in use-prompt-editor.ts covers every consumer: home chat input, scheduled-task modal, task-details modal * chore(user-input): drop redundant inline comments from the mention-dismiss fix Trims the inline // explanations added in the previous commit down to the two declaration-level doc comments that carry real information — matching the repo's no-inline-comments convention. * fix(user-input): clear slash dismissal marker on explicit toolbar trigger Cursor Bugbot review: insertSlashTrigger (the toolbar Slash button) called syncSlashState without clearing dismissedSlashStartRef, so a stale dismissal could suppress the skills menu on an explicit user action when the new token's start offset coincided with the previously dismissed one. An explicit trigger click must always open the menu, so it now clears the marker first like every other insertion path. |
||
|
|
b3175ae973 |
fix(rich-markdown-editor): strict, provenance-aware markdown paste (#5463)
* fix(rich-markdown-editor): strict, provenance-aware markdown paste
Pasting code-like text such as `5 * width * height` was italicized by StarterKit's lenient mark
paste rules. Own emphasis with the strict CommonMark parser instead:
- Disable StarterKit's mark paste rules (`enablePasteRules: false`); markdown paste is handled by
MarkdownPaste (marked) and rich paste by real HTML tags. Input rules (typing) are unaffected.
- Split the paste gate by provenance: structural markdown always parses (faithful GFM tables and
escaping), while inline-only marks parse for a plain-text paste but defer to a rich HTML sibling so
a copied table isn't flattened.
Emphasis (`*_ ** __ ~~ ``) renders; `5 * width`, `*args`, and `snake_case` stay literal — matching
Obsidian/Linear.
* test(rich-markdown-editor): assert code-like pastes are claimed but preserved byte-for-byte
The gate is intentionally lenient — a precise CommonMark-emphasis matcher would risk missing real
emphasis. Over-claiming is safe because the strict parser (marked) preserves non-markdown exactly;
assert the handler claims the paste and returns the input unchanged, not just that no mark is added.
* fix(rich-markdown-editor): keep paste literal inside inline code too
The paste handler skipped a fenced code block but not the inline code mark. Now that inline marks
gate the parse, pasting `*italic*` inside inline code would render rich instead of staying literal —
extend the code-context guard to editor.isActive('code').
|
||
|
|
b686111082 |
feat(textract): migrate to AWS SDK, add AnalyzeExpense and AnalyzeID (#5456)
* feat(textract): migrate to AWS SDK, add AnalyzeExpense and AnalyzeID - Replace hand-rolled AWS SigV4 signing with @aws-sdk/client-textract, matching sibling AWS integrations (secrets_manager, s3, sts) - Add Analyze Expense operation (invoice/receipt structured extraction) via AnalyzeExpense/StartExpenseAnalysis+GetExpenseAnalysis - Add Analyze Identity Document operation (AnalyzeID) with optional back-of-ID page - Add an operation selector to the textract_v2 block; defaults to the existing Analyze Document behavior for backward compatibility - Add tests for tool body/response mapping and route-level AWS response normalization * fix(textract): forward URL documents and fix ambiguous error status - textract_analyze_expense/textract_analyze_id now fall back to filePath/filePathBack when the document input is a URL string rather than an uploaded file object, so advanced "File reference" URL inputs actually reach the API (Cursor Bugbot) - mapTextractSdkError defaults to 500 (not 400) when the AWS SDK error has no HTTP status, since that implies a server-side/network failure rather than a bad request (Greptile) * fix(textract): stop stale processingMode from hiding ID document fields - Front-document fields (fileUpload/fileReference) are shared across all 3 operations; gate them with a values-aware condition so switching to Analyze Identity Document keeps them visible even if a stale processingMode='async' is left over from a previous operation - S3 URI field now also requires operation !== 'analyze_id', since that operation never supports S3 input * fix(textract): preserve first-page metadata across async pagination pollTextractJob's merge callbacks spread only the latest page, dropping any field (DocumentMetadata, model version) the first page had but a follow-up NextToken page omits. Merge accumulated first so later pages only override fields they actually return. * fix(textract): pass through the real upstream status for filePath fetch failures fetchDocumentBytes hardcoded 400 for any non-OK response from a document URL, masking transient 5xx failures from the document host as client errors and blocking tool-execution retries. Use the actual response status instead. * chore(textract): drop redundant inline comments |
||
|
|
017e8ca68f |
fix(ses): reject malformed startDate/endDate in list_suppressed_destinations (#5461)
startDate/endDate were passed through new Date(...) with no validity check, so a malformed non-empty string became an Invalid Date and was still forwarded to AWS, surfacing as a generic 500. The contract now rejects unparseable date strings with a clear 400. |
||
|
|
11be2a3167 |
fix(images): fix stale images (#5462)
* fix(images): fix stale images * Fix comment |
||
|
|
e9a922d346 |
fix(tables): enrichment sidebar column-id display + filter-scoped run menu (#5459)
* fix(tables): resolve column ids to display names in enrichment edit sidebar * feat(tables): scope group-header run menu to the active filter |
||
|
|
24ebba9acc | chore(credential-sets): cleanup feature (#5460) | ||
|
|
07a12249f5 |
feat(pii): env-driven uvicorn worker count (PII_WORKERS) (#5457)
* feat(pii): env-driven uvicorn worker count (PII_WORKERS)
Launch the Presidio service with --workers from the PII_WORKERS env var so one
image scales per task size (set PII_WORKERS = the task's vCPU count) without a
rebuild. `sh -c exec` expands the var while keeping uvicorn as PID 1 for clean
SIGTERM. Defaults to 1, so local/self-hosted is unchanged. Each worker loads the
spaCy models independently (~3.3GB measured), so task memory must be sized to
PII_WORKERS x ~3.3GB + overhead (set in infra alongside PII_WORKERS).
* harden(pii): quote PII_WORKERS expansion + raise healthcheck start-period for multi-worker
- Quote ${PII_WORKERS} so a malformed value fails uvicorn arg-parsing instead of
being shell-interpreted (verified: '1; echo X' rejected as non-integer, X not run)
- Bump HEALTHCHECK start-period 180s -> 300s: N workers load the spaCy models in
parallel, stretching cold start beyond the single-worker case
|
||
|
|
719179258c |
improvement(rich-markdown-editor): table column-resize cursor, exhaustive paste tests, editor docs (#5455)
* fix(rich-markdown-editor): show the col-resize cursor on table column borders prosemirror-tables toggles a `resize-cursor` class on the editor while the pointer is over a column boundary, but there was no rule to change the cursor — the blue resize handle showed with no cursor affordance. Add the scoped `col-resize` rule. * test(rich-markdown-editor): exhaustive markdown paste coverage Cover every rich construct (headings, marks, lists, task lists, blockquote, code block, image, thematic break, table), markdown parsed despite an HTML sibling, multi-block order, read-only rejection, and the defer/verbatim cases for non-markdown input. * docs(editor): add rich markdown editor page Document the inline rich markdown editor — formatting, structure, lists, tables, code blocks, images, the slash menu, and markdown fidelity — with a rendered overview screenshot. * test(rich-markdown-editor): scope paste tests to what MarkdownPaste actually gates Inline-only marks (single-asterisk italic, ~~, single-backtick code) are intentionally not detected by looksLikeMarkdown (single `*` would false-positive on e.g. `*args`); they route through the Markdown extension's own paste path, not MarkdownPaste. Move them from the rich-render cases to the defers-to-default cases so the suite tests the handler it names. |
||
|
|
03478cd574 |
fix(microsoft-excel): clean up dead code found during integration audit (#5454)
* fix(microsoft-excel): clean up dead code found during integration audit
- Remove unreachable 'update' operation subblocks (Google Sheets
copy-paste leftover — never a selectable dropdown option and not
handled by the tool selector or any registered tool)
- Fix microsoft_excel_table_add to trim spreadsheetId and OData-escape
tableName, matching every other tool in this file
- Drop phantom/dead type fields: Google-Sheets-only insertDataOption
and responseValueRenderOption (never used), never-populated
sheetId/sheetName/title/sheets metadata fields, unused rowIndex, and
the unconfigurable majorDimension param (hardcoded to 'ROWS' now
that it's inlined)
* fix(microsoft-excel): fix write output field mapping + OData escaping gaps
Found in an independent second-pass audit against the live Graph API
docs:
- microsoft_excel_write (v1) transformResponse read
updatedRange/updatedRows/updatedColumns/updatedCells from the Graph
response — none of these fields exist on the workbookRange resource
(the real fields are address/rowCount/columnCount), so these four
output fields were always undefined. Fixed to read the actual
fields, matching what the v2 write tool already does correctly.
- read.ts and write.ts (v1 and v2) built worksheets('name') OData
URLs with only encodeURIComponent, skipping escapeODataString — a
worksheet name containing an apostrophe would produce a malformed
request. Every other tool in this integration already escapes
correctly; read/write were the outliers.
- write.ts (v1) also wasn't trimming spreadsheetId before use,
inconsistent with every other tool here.
|
||
|
|
fb3f95d5dc |
feat(aws): expand SES/STS/Secrets Manager tool coverage, fix API alignment gaps (#5450)
* feat(aws): expand SES/STS/Secrets Manager tool coverage, fix API alignment gaps
- SES: add suppression list management, email identity CRUD, template
update, configuration set creation, custom verification email (10
new tools); fix silent httpsPolicy drop in create_configuration_set
and unvalidated suppression reason enum in list_suppressed_destinations
- STS: add AssumeRoleWithWebIdentity and AssumeRoleWithSAML (unsigned,
no static credentials required); extend assume_role with
policyArns/tags/transitiveTagKeys session params
- Secrets Manager: add describe_secret, tag_resource, untag_resource,
restore_secret, rotate_secret; fix list_secrets dropping
rotation/version metadata fields; normalize tool versions to 1.0.0
and alphabetize registry entries
All 31 tools verified param-by-param against live AWS API docs across
two independent audit passes.
* fix(aws): address review findings on SES config/identity and Secrets Manager rotation
- ses_create_configuration_set: validate suppressedReasons against
BOUNCE/COMPLAINT enum before calling AWS (was silently reaching AWS
as a generic 500 for bad values); tags now a proper Zod array schema
instead of a string with route-side JSON.parse
- ses_create_email_identity: dkimSigningAttributes and tags now proper
Zod object/array schemas instead of strings with route-side
JSON.parse, matching the pattern used elsewhere (e.g. sts_assume_role
tags, secrets_manager_tag_resource)
- secrets_manager_rotate_secret: reject automaticallyAfterDays and
scheduleExpression when both are supplied — AWS RotationRules
accepts only one
- sts createUnauthenticatedSTSClient: corrected a misleading comment
claiming these calls are fully unsigned; the SDK still falls through
its default credential provider chain
* fix(ses): correct json input types for tags/dkimSigningAttributes
The SES block declared the tags and dkimSigningAttributes block inputs
as 'string' instead of 'json', so the generic block executor never
parsed the JSON code-editor value before forwarding it — workflow runs
sent a raw JSON string where the contract now expects a structured
object/array, failing validation. Also corrected the corresponding
tool param TypeScript types, which were still typed as string | null.
* fix(ses): stop coercing switch string 'false' to true in create_configuration_set
Boolean('false') evaluates to true, so turning off the
reputationMetricsEnabled or sendingEnabled switch sent the opposite of
the user's choice to SES. Match the established === 'true' string
comparison pattern used elsewhere in the codebase.
* fix(sts): stop double-parsing assume_role session tags input
tags was declared as a 'json' block input, so the generic executor
JSON.parse'd it before the switch-case handler ran — but that handler
already converts the raw table-rows array (or a passthrough string)
into the JSON string the sts_assume_role contract expects. Declaring
it 'json' broke that conversion for non-string inputs. Reverted to
'string' so the handler's existing string/array disambiguation runs
on the untouched raw value.
* fix(sts): supply placeholder credentials to the unauthenticated client
createUnauthenticatedSTSClient omitted credentials entirely, so the
SDK's signing middleware fell through the default credential provider
chain and threw CredentialsProviderError before the request was sent
in any environment with no ambient AWS identity — even though
AssumeRoleWithWebIdentity/AssumeRoleWithSAML never check the
signature. Static placeholder credentials skip that resolution
without granting or requiring any real IAM identity.
|