Skip to content

Commit 46703e3

Browse files
authored
fix: six pre-existing integration defects surfaced by the docs audit (#7195)
* fix(docs): pin the generator's sort locale to en-US localeCompare with no locale argument uses the runtime default, which varies with LANG and the ICU build. Against the real 254 catalog names, tr-TR reorders 141 positions, et-EE 45, cs-CZ 2 and lt-LT diverges at index 40 — so a contributor on any of those regenerates a different integrations.json and fails CI with no obvious cause. Pins en-US at all four sort sites. The committed artifacts are unchanged: regenerating before and after leaves the tree byte-identical. Adds a guard test asserting the committed catalog matches an explicit en-US ordering, plus one that fails if an unpinned localeCompare returns. * fix(vanta): remove the MIME Type field whose value was always discarded The block rendered an advanced MIME Type input and forwarded it as the tool's mimeType, but the upload path never reads it: file-input.ts sets `resolved.contentType || userFile.type || input.mimeType || …`, and every return path of downloadServableFileFromStorage yields a non-empty content type — a literal, getMimeTypeFromExtension's GENERIC_MIME_TYPE fallback, or resolveServableDocBytes' constants and getContentType fallback. The placeholder claimed it was 'used when the file has no type of its own', which never happens. Removes the subBlock, its mapper write and its inputs entry, and marks the tool param hidden so it is no longer advertised to the model on a path where it cannot take effect. The param itself stays, because the base64 branch still reads it. Letting a typed value win instead was rejected: for a compiled artifact the storage-resolved type is the only one matching the bytes actually sent, so an override would break the case the resolver exists to fix. * fix(github): resolve the PR head SHA for file comments github_comment sent commit_id as undefined for every file comment: the param was hidden with no subBlock and no mapper write, so GitHub — which marks commit_id required on POST /pulls/{n}/comments — answered 422 on a path the commentType dropdown exposes. When commitId is absent the tool now fetches the pull request first and uses head.sha, mirroring how Jira resolves cloudId from domain. Also removes the position param, which GitHub marks deprecated ("Use line instead"); line is already a real subBlock. * fix(google-drive): expose the page token so pagination is reachable list, search, list_comments, list_permissions and list_revisions each declared a hidden pageToken and forwarded it to Google, but the block had no subBlock of that name and never has — so every list was capped at one page and the nextPageToken output had nowhere to go. Adds a per-operation Page Token field mirroring the block's existing per-operation pageSize fields, collapses them onto the canonical pageToken in the params mapper, and flips the tool param to user-only so it is documented and settable. * fix(confluence): stop documenting a cloudId users cannot supply All 46 Confluence tools marked cloudId 'user-only', publishing it on 46 doc rows, but the block has no cloudId subBlock so no user could ever fill it. createConfluenceClient already resolves the cloud id from the domain through the shared Atlassian resolver, exactly as Jira does, and Jira marks the same param hidden. Marks cloudId hidden to match. domain stays user-only and settable — it is now the only user-provided param on every Confluence tool. * fix(docs): teach the source scanner about regex literals blankStringsAndComments was a single regex with no concept of a regex literal, so two shapes silently truncated a block's subBlock list: /don't/ the apostrophe opened a phantom string that swallowed the following entries /[}]/ the brace in the character class closed the enclosing object Both returned a short list with no warning — a confident wrong answer, which for the hidden-param filter means silently deleting a user-settable row. No block file uses a regex literal today, so this was latent. Replaces the regex with a linear scanner that distinguishes a regex literal from a division by the previous significant character, blanks regex bodies whole (their last character is arbitrary source, same reason comments are blanked whole), and tracks ${} nesting so a backtick inside a template expression cannot end the template early. The scanner now returns null when it ends inside an unterminated construct. All three call sites treat that as UNKNOWN rather than guessing, so the filter switches off instead of stripping. Generated artifacts are byte-identical and the warning count is unchanged. * fix(github): gate the commit lookup on path, coerce line, name the failing field Three corrections to the file-comment fix, from a validation sweep. needsCommitLookup did not check `path`, and ran before the `path` branch in request.url. A file comment with an empty File Path — reachable, since path is not required on the block — went GET /pulls/{n} then POST /comments with path undefined, a 422. On staging it posted to /pulls/{n}/reviews, which GitHub documents as creating a pending review and where commit_id is optional. The lookup is now gated on path, so only a request headed for /comments triggers it. The block has no tools.config.params, so `line` reached the tool as the string the short-input produced while GitHub types it as an integer — file comments would still have 422'd, one API call later. Coerced in request.body, which runs at execution; anything non-finite is omitted rather than sent as NaN. readGitHubErrorMessage returned only the top-level message, so a 422 read "Validation Failed" with no indication of which field was rejected. The errors[] detail is now appended. Responses without errors[] are unchanged. * test(github): cover the comment routing cases the gate changed Adds the file_comment-without-a-path case (which the commit lookup now skips), the untouched-block default where commentType is unset, a pr_comment carrying a path, and the line coercion on both the direct and resolved-commit paths. * fix(google-drive): let an agent feed the page token back in A page token is an opaque continuation value produced by a previous tool response, not an account-specific id the user has to supply, so 'user-only' hid it from agent blocks: they saw nextPageToken in the result and could not send it back, silently reporting page one as the whole answer. Every other pagination token in the tool set is 'user-or-llm'. Also covers the case the mapper guard actually defends — a per-operation page token surviving an operation switch, which reaches inputs because shouldSerializeSubBlock skips condition evaluation for advanced fields. * docs(generator): name the load-bearing newline rule and report an unscannable source - Record why '\\n' is in REGEX_ALLOWED_AFTER: formatters emit a binary '/' at end-of-line, so every line-leading '/' in blocks/*.ts is a real regex, including the ones in table.ts and table_v2.ts. Removing it silently mis-scans those two. - Split a scanner failure out of the spread-only 'ids: null' case. Both scans come back empty for the same reason when blankStringsAndComments bails, so the mapper's renames were dropped with no warning; it now reports a parseError and warns. The spread case is unchanged, and its TSDoc no longer claims a cause that was false. - Route every catalog sort through an exported compareCatalogNames so the ordering test exercises the generator's comparator instead of re-deriving it, and match localeCompare arguments whole so localeCompare() and a variable locale are caught. - Note that downloadServableFileFromStorage guarantees a non-empty content type, so the Vanta mimeType fallback chain reads as deliberately defensive. Artifacts regenerate byte-identically and the generator warning set is unchanged. * fix(vanta): declare the removed uploadMimeType subblock as dropped check-block-registry fails a PR that deletes a subblock id without a migration entry, because a deployed workflow can still hold a value under that id. The serializer already discards an orphan silently, but the repo's contract is that the removal is declared rather than inferred. Uses the _removed_ form, scoped to upload_document_file: the value has no replacement field to move to. * fix(github): run the two-phase PR comment on the secure transport The file-comment flow posted its comment from `transformResponse` with a bare global `fetch`, so that request carried no abort signal, no response ceiling and no DNS/SSRF validation — cancelling a workflow still left the comment posted. `transformResponse` cannot receive the signal; `directExecution` can. Both tools now run the lookup and the POST through a new `secureGitHubRequest`, mirroring `secureBitbucketRead`, with the signal forwarded to each. Routing, line coercion and the `errors[]` detail are unchanged, and a failed response still throws an error carrying `status`/`statusText`/`data` as the transport does. Request bodies and the comment payload are explicitly typed instead of `Record<string, any>`. * fix(vanta): keep mimeType an ordinary upload parameter `mimeType` was marked hidden, but `visibility: 'hidden'` is reserved for system-injected params such as OAuth tokens. It also left the base64 upload path with no way to set a content type, since `fileContent` is hidden too. * fix(generator): lex regex-in-keyword-position and template interpolation The scanner chose regex-vs-division from the previous significant character, so a regex in operand position (`return /x/`, `typeof /x/`, `case /x/`, ...) lexed as a division off the keyword's last letter and its body stayed in the structural view; `azure_devops.ts` is inert today only because the braces in its `return /^\d{4}-\d{2}-\d{2}$/` happen to balance. The `${}` depth counter was also not string-aware, so a brace inside a quoted expression miscounted, the closing backtick was lost and the block was reported unreadable — which silently stops filtering resolver-derived hidden params. Both scans now run on one set of lexer primitives: `${}` expressions are lexed with the same string, comment, regex and template handling as top-level code. Regenerated docs, tool metadata and the integration catalog are byte-identical and the generator's warning count is unchanged. * fix(github): stop forwarding the GitHub token across a redirect origin secureGitHubRequest passed no redirectPolicy, and the transport only strips credential headers when one is present, so an api.github.com redirect to another origin carried the workspace's Authorization: Bearer header to the new host. Adopts the standard policy already used by the internal Google Drive client. stripAuthOnRedirect stays off: GitHub redirects same-origin for legitimate reasons (a renamed repository answers 301), and dropping auth there would turn a working call into a 401. * fix(github): reject a fractional comment line instead of truncating it toLineNumber ran Math.trunc, so line 3.9 posted the review comment on line 3 — a silent change to what the caller asked for, on a field where landing on the wrong line of the diff is invisible until someone reads the comment. A non-integer now fails with a message naming the field, matching how a missing head commit SHA fails on this path. Blank and unparseable input is still omitted: line is optional and nothing usable was supplied. * fix(github): select the comment endpoint by comment type, not by path The endpoint was chosen by the presence of path, while the body was chosen by commentType, so a pr_comment naming a file posted a review body to POST /pulls/{n}/comments. GitHub documents body, commit_id and path as required there, so that request can only ever 422 — it has been broken since before this PR. The endpoint now follows the comment type: only a file comment carrying a path uses /comments, everything else stays on /reviews. The test that codified the broken routing is corrected, and the full type/path matrix is pinned. * test(confluence): drop the cloudId visibility invariant test Removed at request. The visibility change itself is unaffected; it loses only the guard that would have caught a future edit reverting one of the 46 files. * fix(github): send an explicit User-Agent and stop downgrading a redirected comment POST `secureGitHubRequest` powers the GitHub comment tool's `directExecution` path, which bypasses the declarative transport. Two behaviors the transport provided did not survive the move. User-Agent: the transport sets `User-Agent: Sim` on every request it formats (`request-transport.ts`), and `secureFetchWithPinnedIP` adds none of its own — it builds the request with raw `node:https` and passes headers through verbatim. Production runs on Bun, whose `node:http` shim injects `user-agent: Bun/x.y.z`, so GitHub does not reject these calls today; the defect is that Sim's deliberate attribution is silently replaced by a runtime version string, and that the tool depends on an undocumented runtime behavior that does not hold under Node, where GitHub answers 403 "Request forbidden by administrative rules". Set in the helper rather than in the tool's header map so every future caller inherits it; a caller-supplied value still wins. Redirect method: the policy was `mode: 'standard'`, under which `resolveRedirectHop` rewrites a 301/302'd POST to a bodyless GET regardless of origin. GitHub answers 301 within api.github.com for a renamed repository, so commenting on a PR there would GET `/pulls/{n}/comments`, receive a JSON array, fail the payload shape check, and report success with no comment created. `legacy` keeps the method and body across that hop. Cross-origin credential stripping is unaffected — the guarded follower strips Authorization, Proxy-Authorization and Cookie whenever `sendCredentialsOnCrossOriginRedirect` is false, in either mode. * fix(vanta): drop the dead whenOperation from the removed-subblock entry migrateBlockSubblockIds handles a _removed_ target before it consults whenOperation, so the scope was never applied. Mine was the only _removed_ entry in the file carrying one. Unconditional deletion is also what this case wants. Subblock values are keyed by id and are not cleared when the operation changes, so a user who filled the MIME field and then switched the block to another operation has the value stored under that operation; a scoped delete would strand it permanently. The field no longer exists for any operation, so it should go regardless of the stored operation. * fix(docs-gen): close a regex-vs-division gap and make three guards testable `REGEX_ALLOWED_AFTER` was missing `'/'`, so a regex directly after a division operator lexed as a second division: in `x / y / /[}]/` the character class was left in the structural view and its `}` closed the enclosing object early, truncating the block's subBlock ids with no warning. Add `'/'`, and guard the `'+'`/`'-'` entries with a `++`/`--` lookbehind so a postfix update still reads as a value and `i++ / 2` stays a division rather than a phantom regex that runs to end-of-input and reports the block unreadable. The `.`/`#` property guard and the `'\n'` entry both survived their mutants. `counts.in / 2, m: preturn / 2` is self-cancelling — the mis-lexed regex closes on the second slash and blanks nothing structural — so the fixtures now leave an odd number of slashes on the line. The `'\n'` entry had no coverage at all: its fixture is now the wrapped `.match(` newline `/re/` shape that `blocks/table.ts` and `blocks/table_v2.ts` produce, which is what that entry (not the preceding `(`, which the newline overwrites) actually decides. Its comment claimed a count of line-leading regexes that drifts with the sources; restate it without one. Drop the two locale tests that could not fail. CI runs under an `en-US` default, where an unpinned `localeCompare` returns exactly what the pinned one does, so no behavioural comparison discriminates; and asserting the committed `integrations.json` against the comparator that produced it agrees by construction. The source grep for a literal locale argument is the real guard. Generated output is byte-identical and the extraction differential over `apps/sim/blocks/blocks/` is empty.
1 parent 88a9671 commit 46703e3

70 files changed

Lines changed: 1785 additions & 191 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

apps/docs/content/docs/en/integrations/confluence.mdx

Lines changed: 0 additions & 46 deletions
Large diffs are not rendered by default.

apps/docs/content/docs/en/integrations/google_drive.mdx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ List files and folders in Google Drive with complete metadata
4646
| `folderId` | string | No | The ID of the folder to list files from \(internal use\) |
4747
| `query` | string | No | Search term to filter files by name \(e.g. "budget" finds files with "budget" in the name\). Do NOT use Google Drive query syntax here - just provide a plain search term. |
4848
| `pageSize` | number | No | The maximum number of files to return \(default: 100\) |
49+
| `pageToken` | string | No | The page token to use for pagination |
4950

5051
#### Output
5152

@@ -484,6 +485,7 @@ Search for files in Google Drive using advanced query syntax (e.g., fullText con
484485
| --------- | ---- | -------- | ----------- |
485486
| `query` | string | Yes | Google Drive query string using advanced search syntax \(e.g., "fullText contains 'budget'", "mimeType = 'application/pdf'", "modifiedTime &gt; '2024-01-01'"\) |
486487
| `pageSize` | number | No | Maximum number of files to return \(default: 100\) |
488+
| `pageToken` | string | No | Token for fetching the next page of results |
487489

488490
#### Output
489491

@@ -671,6 +673,7 @@ List all permissions (who has access) for a file in Google Drive
671673
| Parameter | Type | Required | Description |
672674
| --------- | ---- | -------- | ----------- |
673675
| `fileId` | string | Yes | The ID of the file to list permissions for |
676+
| `pageToken` | string | No | The page token to use for pagination |
674677

675678
#### Output
676679

@@ -720,6 +723,7 @@ List the revision history of a file in Google Drive
720723
| --------- | ---- | -------- | ----------- |
721724
| `fileId` | string | Yes | The ID of the file to list revisions for |
722725
| `pageSize` | number | No | Maximum number of revisions to return \(1-1000, default 200\) |
726+
| `pageToken` | string | No | The page token to use for pagination |
723727

724728
#### Output
725729

@@ -779,6 +783,7 @@ List comments on a file in Google Drive
779783
| `includeDeleted` | boolean | No | Whether to include deleted comments \(their content is stripped\) |
780784
| `pageSize` | number | No | Maximum number of comments to return \(1-100, default 20\) |
781785
| `startModifiedTime` | string | No | Only return comments modified after this RFC 3339 timestamp |
786+
| `pageToken` | string | No | The page token to use for pagination |
782787

783788
#### Output
784789

apps/docs/content/docs/en/integrations/vanta.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -331,7 +331,7 @@ Upload an evidence file to a Vanta document. Requires credentials with the vanta
331331
| `documentId` | string | Yes | Unique ID of the document to attach the file to |
332332
| `file` | file | No | The evidence file to upload |
333333
| `fileName` | string | No | Optional file name override |
334-
| `mimeType` | string | No | MIME type of the file \(e.g., application/pdf\). Used only for base64 uploads; ignored for a file from the File input, whose content type is always resolved from storage. |
334+
| `mimeType` | string | No | MIME type of the file \(e.g., application/pdf\). Applies only to the base64 upload path; a file from the File input always sends the content type resolved from storage. |
335335
| `description` | string | No | Description of the uploaded evidence \(e.g., "Q3 access review evidence"\) |
336336
| `effectiveAtDate` | string | No | ISO 8601 date indicating when the document is effective from |
337337

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
/**
2+
* @vitest-environment node
3+
*/
4+
import { describe, expect, it, vi } from 'vitest'
5+
6+
vi.mock('@/triggers', () => ({
7+
getTrigger: () => ({ subBlocks: [] }),
8+
}))
9+
10+
import { GoogleDriveBlock } from '@/blocks/blocks/google_drive'
11+
import { listTool } from '@/tools/google_drive/list'
12+
import { listCommentsTool } from '@/tools/google_drive/list_comments'
13+
import { listPermissionsTool } from '@/tools/google_drive/list_permissions'
14+
import { listRevisionsTool } from '@/tools/google_drive/list_revisions'
15+
import { searchTool } from '@/tools/google_drive/search'
16+
17+
const paginationCases = [
18+
{ operation: 'list', subBlockId: 'pageToken', tool: listTool },
19+
{ operation: 'search', subBlockId: 'searchPageToken', tool: searchTool },
20+
{ operation: 'list_permissions', subBlockId: 'permissionsPageToken', tool: listPermissionsTool },
21+
{ operation: 'list_revisions', subBlockId: 'revisionsPageToken', tool: listRevisionsTool },
22+
{ operation: 'list_comments', subBlockId: 'commentsPageToken', tool: listCommentsTool },
23+
] as const
24+
25+
describe('GoogleDriveBlock pagination', () => {
26+
const buildParams = GoogleDriveBlock.tools.config.params!
27+
28+
describe.each(paginationCases)('$operation', ({ operation, subBlockId, tool }) => {
29+
it('exposes a page token field scoped to the operation', () => {
30+
expect(GoogleDriveBlock.subBlocks.find(({ id }) => id === subBlockId)).toMatchObject({
31+
type: 'short-input',
32+
mode: 'advanced',
33+
condition: { field: 'operation', value: operation },
34+
})
35+
})
36+
37+
/**
38+
* `pageToken` is the canonical tool param, so the `list` case would forward
39+
* through `...rest` even without the mapper. The per-operation ids are the
40+
* ones the mapper has to translate, and none of them may survive as-is.
41+
*/
42+
it('forwards the page token to the tool under its own id', () => {
43+
const params = buildParams({ operation, [subBlockId]: 'token-abc' }, undefined as never)
44+
45+
expect(params).toMatchObject({ pageToken: 'token-abc' })
46+
if (subBlockId !== 'pageToken') expect(params[subBlockId]).toBeUndefined()
47+
})
48+
49+
it('lets an agent feed a nextPageToken back in', () => {
50+
expect(tool.params.pageToken?.visibility).toBe('user-or-llm')
51+
})
52+
})
53+
54+
it('does not leak a page token into operations that do not paginate', () => {
55+
expect(
56+
buildParams({ operation: 'get_file', pageToken: 'token-abc' }, undefined as never).pageToken
57+
).toBeUndefined()
58+
})
59+
60+
/**
61+
* `shouldSerializeSubBlock` short-circuits for `advanced` fields in basic display
62+
* mode without evaluating `condition`, so a page token typed under one operation
63+
* genuinely reaches `inputs` after the user switches to another. The mapper must
64+
* pick the token belonging to the operation being run and drop the rest.
65+
*/
66+
describe.each(paginationCases.filter(({ subBlockId }) => subBlockId !== 'pageToken'))(
67+
'$subBlockId left over from a previous operation',
68+
({ subBlockId }) => {
69+
it.each(['upload', 'get_file', 'list'])('is dropped under %s', (operation) => {
70+
const params = buildParams({ operation, [subBlockId]: 'stale' }, undefined as never)
71+
72+
expect(params.pageToken).toBeUndefined()
73+
expect(params[subBlockId]).toBeUndefined()
74+
})
75+
}
76+
)
77+
78+
it('prefers the operation-owned token when a stale sibling is also present', () => {
79+
const params = buildParams(
80+
{
81+
operation: 'search',
82+
searchPageToken: 'search-token',
83+
commentsPageToken: 'stale',
84+
pageToken: 'stale-canonical',
85+
},
86+
undefined as never
87+
)
88+
89+
expect(params.pageToken).toBe('search-token')
90+
expect(params.commentsPageToken).toBeUndefined()
91+
expect(params.searchPageToken).toBeUndefined()
92+
})
93+
94+
it('declares pageToken as a block input', () => {
95+
expect(GoogleDriveBlock.inputs.pageToken).toBeDefined()
96+
})
97+
})

apps/sim/blocks/blocks/google_drive.ts

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -463,6 +463,14 @@ Return ONLY the query string - no explanations, no quotes around the whole thing
463463
placeholder: 'Number of results (default: 100, max: 100)',
464464
condition: { field: 'operation', value: 'list' },
465465
},
466+
{
467+
id: 'pageToken',
468+
title: 'Page Token',
469+
type: 'short-input',
470+
placeholder: 'Token from a previous nextPageToken',
471+
mode: 'advanced',
472+
condition: { field: 'operation', value: 'list' },
473+
},
466474
// Download File Fields - File Selector (basic mode)
467475
{
468476
id: 'downloadFileSelector',
@@ -905,6 +913,14 @@ Return ONLY the message text - no subject line, no greetings/signatures, no extr
905913
condition: { field: 'operation', value: 'list_permissions' },
906914
required: true,
907915
},
916+
{
917+
id: 'permissionsPageToken',
918+
title: 'Page Token',
919+
type: 'short-input',
920+
placeholder: 'Token from a previous nextPageToken',
921+
mode: 'advanced',
922+
condition: { field: 'operation', value: 'list_permissions' },
923+
},
908924
// Get File Content Fields
909925
{
910926
id: 'getContentFileSelector',
@@ -1073,6 +1089,14 @@ Return ONLY the query string - no explanations, no quotes around the whole thing
10731089
mode: 'advanced',
10741090
condition: { field: 'operation', value: 'search' },
10751091
},
1092+
{
1093+
id: 'searchPageToken',
1094+
title: 'Page Token',
1095+
type: 'short-input',
1096+
placeholder: 'Token from a previous nextPageToken',
1097+
mode: 'advanced',
1098+
condition: { field: 'operation', value: 'search' },
1099+
},
10761100
// Untrash File Fields
10771101
{
10781102
id: 'untrashFileSelector',
@@ -1191,6 +1215,14 @@ Return ONLY the query string - no explanations, no quotes around the whole thing
11911215
mode: 'advanced',
11921216
condition: { field: 'operation', value: 'list_revisions' },
11931217
},
1218+
{
1219+
id: 'revisionsPageToken',
1220+
title: 'Page Token',
1221+
type: 'short-input',
1222+
placeholder: 'Token from a previous nextPageToken',
1223+
mode: 'advanced',
1224+
condition: { field: 'operation', value: 'list_revisions' },
1225+
},
11941226
{
11951227
id: 'getRevisionFileSelector',
11961228
title: 'Select File',
@@ -1255,6 +1287,14 @@ Return ONLY the query string - no explanations, no quotes around the whole thing
12551287
mode: 'advanced',
12561288
condition: { field: 'operation', value: 'list_comments' },
12571289
},
1290+
{
1291+
id: 'commentsPageToken',
1292+
title: 'Page Token',
1293+
type: 'short-input',
1294+
placeholder: 'Token from a previous nextPageToken',
1295+
mode: 'advanced',
1296+
condition: { field: 'operation', value: 'list_comments' },
1297+
},
12581298
{
12591299
id: 'includeDeleted',
12601300
title: 'Include Deleted Comments',
@@ -1473,6 +1513,11 @@ Return ONLY the comment text - no explanations, no quotes, no extra formatting.`
14731513
searchPageSize,
14741514
revisionsPageSize,
14751515
commentsPageSize,
1516+
pageToken,
1517+
searchPageToken,
1518+
permissionsPageToken,
1519+
revisionsPageToken,
1520+
commentsPageToken,
14761521
getContentExportMimeType,
14771522
exportMimeType,
14781523
...rest
@@ -1586,6 +1631,13 @@ Return ONLY the comment text - no explanations, no quotes, no extra formatting.`
15861631
else if (params.operation === 'list_revisions') effectivePageSize = revisionsPageSize
15871632
else if (params.operation === 'list_comments') effectivePageSize = commentsPageSize
15881633

1634+
let effectivePageToken: string | undefined = pageToken
1635+
if (params.operation === 'search') effectivePageToken = searchPageToken
1636+
else if (params.operation === 'list_permissions') effectivePageToken = permissionsPageToken
1637+
else if (params.operation === 'list_revisions') effectivePageToken = revisionsPageToken
1638+
else if (params.operation === 'list_comments') effectivePageToken = commentsPageToken
1639+
else if (params.operation !== 'list') effectivePageToken = undefined
1640+
15891641
const effectiveQuery = params.operation === 'search' ? searchQuery : query
15901642
const effectiveMimeType =
15911643
params.operation === 'get_content'
@@ -1603,6 +1655,7 @@ Return ONLY the comment text - no explanations, no quotes, no extra formatting.`
16031655
pageSize: effectivePageSize
16041656
? Number.parseInt(effectivePageSize as string, 10)
16051657
: undefined,
1658+
pageToken: effectivePageToken?.trim() || undefined,
16061659
query: effectiveQuery,
16071660
mimeType: effectiveMimeType === 'auto' ? undefined : effectiveMimeType,
16081661
type: shareType, // Map shareType to type for share tool
@@ -1660,6 +1713,7 @@ Return ONLY the comment text - no explanations, no quotes, no extra formatting.`
16601713
// List operation inputs
16611714
query: { type: 'string', description: 'Search query' },
16621715
pageSize: { type: 'number', description: 'Results per page' },
1716+
pageToken: { type: 'string', description: 'Pagination token from a previous nextPageToken' },
16631717
// Copy operation inputs
16641718
newName: { type: 'string', description: 'New name for copied file' },
16651719
// Update operation inputs

apps/sim/blocks/blocks/vanta.ts

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -286,14 +286,6 @@ export const VantaBlock: BlockConfig<ToolResponse> = {
286286
condition: { field: 'operation', value: 'upload_document_file' },
287287
mode: 'advanced',
288288
},
289-
{
290-
id: 'uploadMimeType',
291-
title: 'MIME Type',
292-
type: 'short-input',
293-
placeholder: 'e.g., application/pdf (used when the file has no type of its own)',
294-
condition: { field: 'operation', value: 'upload_document_file' },
295-
mode: 'advanced',
296-
},
297289
{
298290
id: 'uploadDescription',
299291
title: 'Description',
@@ -930,7 +922,6 @@ export const VantaBlock: BlockConfig<ToolResponse> = {
930922
const normalizedFile = normalizeFileInput(rest.file, { single: true })
931923
if (normalizedFile) result.file = normalizedFile
932924
result.fileName = optionalString(rest.uploadFileName)
933-
result.mimeType = optionalString(rest.uploadMimeType)
934925
result.description = optionalString(rest.uploadDescription)
935926
result.effectiveAtDate = optionalString(rest.effectiveAtDate)
936927
break
@@ -993,10 +984,6 @@ export const VantaBlock: BlockConfig<ToolResponse> = {
993984
uploadedFileId: { type: 'string', description: 'Uploaded file ID' },
994985
file: { type: 'json', description: 'Evidence file to upload' },
995986
uploadFileName: { type: 'string', description: 'Optional file name override' },
996-
uploadMimeType: {
997-
type: 'string',
998-
description: 'MIME type override used when the uploaded content has no type of its own',
999-
},
1000987
uploadDescription: { type: 'string', description: 'Description of the uploaded evidence' },
1001988
effectiveAtDate: { type: 'string', description: 'Effective date of the document (ISO 8601)' },
1002989
frameworkMatchesAny: { type: 'string', description: 'Comma-separated framework ID filters' },

apps/sim/lib/internal/vanta/file-input.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,11 @@ export async function resolveVantaUploadFile(
7070
signal: context.signal,
7171
})
7272
context.signal?.throwIfAborted()
73+
/**
74+
* Every return path of `downloadServableFileFromStorage` yields a non-empty content
75+
* type, so `resolved.contentType` always wins. The remaining operands are defensive
76+
* fallbacks kept in place in case that guarantee is ever relaxed.
77+
*/
7378
return {
7479
buffer: resolved.buffer,
7580
fileName: input.fileName || userFile.name,

apps/sim/lib/workflows/migrations/subblock-migrations.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,13 @@ export const SUBBLOCK_ID_MIGRATIONS: Record<string, readonly SubblockIdMigration
292292
* dropped outright.
293293
*/
294294
sap_concur: [{ from: 'forwardId', to: '_removed_forwardId' }],
295+
/**
296+
* `uploadMimeType` was an advanced MIME Type input on Upload Document File whose
297+
* value the upload path never read: the content type is resolved from storage and
298+
* that resolution is never empty, so the field's value lost the `||` chain every
299+
* time. Dropped rather than renamed — there is no field for the value to move to.
300+
*/
301+
vanta: [{ from: 'uploadMimeType', to: '_removed_uploadMimeType' }],
295302
}
296303

297304
/** Reads the value out of a stored subblock entry, tolerating a bare value. */

apps/sim/tools/confluence/add_label.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ export const confluenceAddLabelTool: InternalToolConfig<
6868
cloudId: {
6969
type: 'string',
7070
required: false,
71-
visibility: 'user-only',
71+
visibility: 'hidden',
7272
description:
7373
'Confluence Cloud ID for the instance. If not provided, it will be fetched using the domain.',
7474
},

apps/sim/tools/confluence/create_blogpost.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ export const confluenceCreateBlogPostTool: InternalToolConfig<
8484
cloudId: {
8585
type: 'string',
8686
required: false,
87-
visibility: 'user-only',
87+
visibility: 'hidden',
8888
description:
8989
'Confluence Cloud ID for the instance. If not provided, it will be fetched using the domain.',
9090
},

0 commit comments

Comments
 (0)