Skip to content

feat(input-format): upload files in file fields via the file uploader#5297

Merged
waleedlatif1 merged 9 commits into
stagingfrom
feat/file-input-dropzone
Jun 30, 2026
Merged

feat(input-format): upload files in file fields via the file uploader#5297
waleedlatif1 merged 9 commits into
stagingfrom
feat/file-input-dropzone

Conversation

@waleedlatif1

Copy link
Copy Markdown
Collaborator

Summary

  • The start-block input format's file field only offered a raw JSON editor expecting hand-written base64 objects. Production data confirms it's misused — of 766 blocks with a file field, only 13 had a value and nearly all were junk (local paths, raw text, leftover <base64> placeholders). It also never actually fed a run.
  • Reuse the existing FileUpload component for file-typed fields, with a toggle to fall back to the raw JSON editor for power users / legacy values.
  • Added an opt-in controlled mode (value / onValueChange) to FileUpload so it can be embedded where the value lives outside a subblock. Store-bound consumers (stt / vision / agent) are untouched.
  • File-field detection is normalized (file[] / files / file / image) so copilot/API-authored variants render correctly too.
  • Editor-attached files (already uploaded, run-ready) are wired into manual runs via the executor's files channel; chat/API runs still override.

Backwards compatibility

  • The inputFormat array shape is unchanged — file values are stored as a JSON string of run-ready file objects, so every existing reader stays compatible. No DB migration.
  • Legacy free-form values open in JSON mode, so nothing is lost; the uploader is the default only for empty/already-structured values.
  • Variables panel deliberately untouched (no file type there); a "Files" variable type is a separate follow-up since it needs executor variable-resolver work.

Type of Change

  • New feature

Testing

  • Added unit tests for the new pure helpers (isFileFieldType, parseInputFormatFiles); lib/workflows/input-format.test.ts passes (32 tests).
  • tsc clean for all changed files; tested manually.

Checklist

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

The file field in the start-block input format only offered a raw JSON
editor expecting hand-written base64 objects, which users routinely
filled with junk (local paths, raw text, leftover placeholders) and
which never actually fed a run.

Reuse the existing FileUpload component for file-typed fields:
- Add an opt-in controlled mode (value/onValueChange) to FileUpload so it
  can be embedded where the value lives outside a subblock; store-bound
  consumers (stt/vision/agent) are unchanged.
- Render the uploader for file fields, with a toggle to fall back to the
  raw JSON editor for power users / legacy values.
- Detect file fields by normalized type (file[]/files/file/image) so
  copilot/API-authored variants render correctly too.
- Wire editor-attached files (already uploaded, run-ready) into manual
  runs via the executor's files channel; chat/API runs still override.

Backwards compatible: the inputFormat array shape is unchanged (file
values are stored as a JSON string of run-ready file objects); legacy
free-form values open in JSON mode so nothing is lost.
@vercel

vercel Bot commented Jun 30, 2026

Copy link
Copy Markdown

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

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
docs Skipped Skipped Jun 30, 2026 10:56pm

Request Review

@cursor

cursor Bot commented Jun 30, 2026

Copy link
Copy Markdown

PR Summary

Medium Risk
Changes how manual-run workflow input is assembled and attaches real files to the start block files channel; mitigated by strict parsing, legacy JSON-only mode, and broad unit tests.

Overview
Start-block file[] fields can use the shared FileUpload UI (multi-file) instead of only a raw JSON editor, with an optional toggle back to JSON when the stored value is safe to round-trip.

FileUpload gains optional value / onValueChange controlled mode (store-backed subblocks unchanged); uploads/removes go through a shared commitValue path.

New input-format-files helpers map between run-ready InputFormatFile JSON and the uploader’s path-based shape, pick upload vs forced JSON when legacy/mixed content would be dropped, and serialize field values.

lib/workflows/input-format adds isFileFieldType (file[] only), strict parseInputFormatFiles, and collectInputFormatFiles aligned with executor file normalization.

Manual / run-from-block execution replaces inline input-format coercion with buildInputFormatInput, which skips file fields as named inputs and sets input.files from collected uploads (overriding a same-named scalar files field when attachments exist).

Unit tests cover the new parsers, adapters, and execution input helpers.

Reviewed by Cursor Bugbot for commit 47952a7. Configure here.

@greptile-apps

greptile-apps Bot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds uploader support for file fields in the start-block input format. The main changes are:

  • Controlled-mode support for the existing file uploader.
  • File-field parsing and serialization helpers for stored run-ready file values.
  • Uploader rendering for compatible file-typed input fields, with JSON fallback for legacy values.
  • Manual-run wiring that forwards collected file-field uploads through the executor file channel.
  • Tests for file-field detection, parsing, adapter behavior, and legacy fallback.

Confidence Score: 5/5

This looks safe to merge.

  • No blocking issues found in the changed code.

Important Files Changed

Filename Overview
apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/file-upload/file-upload.tsx Adds controlled value handling while keeping the existing store-backed uploader path unchanged.
apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/starter/input-format-files.ts Adds pure helpers to convert between stored input-format files and the uploader value shape.
apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/starter/input-format.tsx Renders uploader mode for compatible file fields and keeps JSON mode for legacy or mixed values.
apps/sim/app/workspace/[workspaceId]/w/[workflowId]/hooks/use-workflow-execution.ts Builds manual-run input from input-format fields and forwards collected file uploads through the files channel.
apps/sim/lib/workflows/input-format.ts Adds file-field detection plus run-ready file parsing and collection helpers.

Reviews (9): Last reviewed commit: "fix(input-format): uploaded files always..." | Re-trigger Greptile

Comment thread apps/sim/lib/workflows/input-format.ts Outdated
…r, harden types

Follow-up cleanup from /simplify + /cleanup review:
- Extract pure file adapters into input-format-files.ts (filesToControlValue,
  controlValueToFiles, serializeInputFormatFiles, defaultFileFieldMode) so they
  are unit-tested without a DOM; add tests.
- Derive InputFormatFile from the canonical executor UserFile so the editor and
  runtime file shapes can't drift.
- Consolidate the two manual run-input builders into one buildInputFormatInput
  helper so manual run and run-from-block handle files identically.
- Narrow file-field detection to the canonical file[] (matches the field-type
  dropdown and the existing execution/webhook file paths) so no pre-existing
  non-file[] field changes behavior.
- defaultFileFieldMode parses once; the file value is only parsed in upload mode.
- Add lib/component unit tests (45 passing).
…files input

Addresses review (Greptile P1s):
- parseInputFormatFiles now requires the full run-ready shape (id/name/url +
  finite size + type), so a partial file can't open in uploader mode or reach
  workflowInput.files only to be rejected by normalizeStartFile (which would
  silently drop every file).
- buildInputFormatInput no longer overwrites a user field literally named
  'files' with the upload channel; that reserved-name collision is left for the
  executor to surface.
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile review

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cursor review

Comment thread apps/sim/lib/workflows/input-format.ts
…N mode

Addresses review round 2 (Greptile P1 + Cursor):
- parseInputFormatFiles now requires a non-empty key (the uploader always sets
  one); an external/signed URL with no recoverable key no longer opens uploader
  mode or reaches workflowInput.files only to be rejected.
- defaultFileFieldMode uses the uploader only when EVERY entry is run-ready;
  a mixed array with any legacy/partial entry stays in JSON mode so the uploader
  can't drop the entries it can't represent on the next save.
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile review

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cursor review

Comment thread apps/sim/lib/workflows/input-format.ts Outdated
…ss values

Addresses review round 3 (Greptile P1 + Cursor):
- parseInputFormatFiles accepts a key-less file when its url is an internal
  /api/files/serve/... url (the executor recovers the key from it, same as
  normalizeStartFile); only a missing key with a non-internal url is rejected.
- The file field offers the uploader only when it can represent the stored
  value losslessly (empty or all run-ready); for mixed/legacy values it forces
  JSON mode and hides the toggle, so a sticky 'upload' preference can no longer
  drop entries the uploader cannot show on save.
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile review

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cursor review

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

✅ Bugbot reviewed your changes and found no new issues!

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

Reviewed by Cursor Bugbot for commit a028114. Configure here.

Comment thread apps/sim/lib/workflows/input-format.ts
…rmatFiles

Addresses review round 4 (Greptile): normalizeStartFile rejects falsy
id/name/url/type and file normalization is all-or-nothing, so an empty-string
field (e.g. hand-edited value with an empty id + internal url) would open in
uploader mode and drop every file from the run. Require non-empty strings to
match the executor.
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile review

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cursor review

Comment thread apps/sim/lib/workflows/input-format.ts Outdated

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

✅ Bugbot reviewed your changes and found no new issues!

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

Reviewed by Cursor Bugbot for commit f2718e9. Configure here.

…rnalFileUrl

Addresses review round 5 (Greptile): isInternalFileUrl only checks the URL
prefix, but the executor parses+decodes the key. A malformed internal URL (no
extractable key) passed the prefix check, got collected into workflowInput.files,
then normalizeStartFile rejected it and dropped the whole files array. Now mirror
the executor exactly — attempt parseInternalFileUrl and require a real key.
Tests use a realistic recoverable internal URL.
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile review

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cursor review

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

✅ Bugbot reviewed your changes and found no new issues!

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

Reviewed by Cursor Bugbot for commit 519917a. Configure here.

Addresses review round 6 (Greptile): files is NOT in the executor's reserved
input-format names (EXECUTION_CONTROL_OUTPUT_FIELD_NAMES), so the previous guard
silently dropped uploaded file[] values whenever a plain field named files
coexisted. files is the start block's canonical file channel (the chat trigger
names its own file field files), so uploaded files now always populate it and
take precedence — dropping real attachments is the worse outcome, and making
files a reserved-name error isn't viable since it's the legitimate file-field
name.
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile review

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cursor review

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

✅ Bugbot reviewed your changes and found no new issues!

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

Reviewed by Cursor Bugbot for commit 47952a7. Configure here.

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile review

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cursor review

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

✅ Bugbot reviewed your changes and found no new issues!

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

Reviewed by Cursor Bugbot for commit 47952a7. Configure here.

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile review

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cursor review

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

✅ Bugbot reviewed your changes and found no new issues!

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

Reviewed by Cursor Bugbot for commit 47952a7. Configure here.

@waleedlatif1 waleedlatif1 merged commit c17c003 into staging Jun 30, 2026
15 checks passed
@waleedlatif1 waleedlatif1 deleted the feat/file-input-dropzone branch June 30, 2026 23:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant