feat(platform): Support input nodes alongside trigger nodes - #11220
feat(platform): Support input nodes alongside trigger nodes#11220Pwuts wants to merge 30 commits into
Conversation
✅ Deploy Preview for auto-gpt-docs-dev canceled.
|
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
WalkthroughTriggered preset inputs are split into regular graph inputs and per-node trigger masks across setup, reconfiguration, execution, validation tooling, UI, and a migration for stored presets. ChangesWebhook preset input split
Estimated code review effort🎯 5 (Critical) | ⏱️ ~90 minutes Suggested labels
Suggested reviewers
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
Here's the code health analysis summary for commits Analysis Summary
|
✅ Deploy Preview for auto-gpt-docs canceled.
|
|
Thank you for submitting this PR to support input nodes alongside trigger nodes! Your changes look well-structured, including:
However, before this PR can be merged, please:
Once you've completed the checklist, this PR should be ready for another review. The code changes themselves look good and align well with the stated purpose of supporting input blocks alongside trigger nodes. |
|
This pull request has conflicts with the base branch, please resolve those so we can evaluate the pull request. |
|
Conflicts have been resolved! 🎉 A maintainer will review the pull request shortly. |
|
Thanks for working on this feature to support input nodes alongside trigger nodes! The changes look good and are well-structured, but there are a couple of things to address before we can merge this PR:
Once these issues are addressed, your PR should be ready for review again. |
|
This pull request has conflicts with the base branch, please resolve those so we can evaluate the pull request. |
This comment was marked as low quality.
This comment was marked as low quality.
1 similar comment
This comment was marked as low quality.
This comment was marked as low quality.
…t-input-blocks-alongside-trigger-blocks # Conflicts: # autogpt_platform/backend/backend/api/features/library/routes/presets.py # autogpt_platform/frontend/src/app/(platform)/build/components/legacy-builder/BlocksControl.tsx
|
Conflicts have been resolved! 🎉 A maintainer will review the pull request shortly. |
🔍 PR Overlap DetectionThis check compares your PR against all other open PRs targeting the same branch to detect potential merge conflicts early. 🟢 Low Risk — File Overlap OnlyThese PRs touch the same files but different sections (click to expand)
Summary: 0 conflict(s), 0 medium risk, 5 low risk (out of 5 PRs with file overlap) Auto-generated on push. Ignores: |
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## dev #11220 +/- ##
==========================================
+ Coverage 81.48% 81.51% +0.03%
==========================================
Files 3553 3555 +2
Lines 265706 266086 +380
Branches 24618 24634 +16
==========================================
+ Hits 216514 216904 +390
+ Misses 43830 43786 -44
- Partials 5362 5396 +34
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
… mask
When a triggered preset stores both regular graph inputs and the trigger
config, the trigger config is nested under a per-node key. The webhook
execution path was passing the full `preset.inputs` to
`is_triggered_by_event_type`, so the event filter (e.g. GitHub event
selection) couldn't be found and event-filtered triggers raised
"Event filter is not configured on trigger".
Extract the node's input mask before the event-type check and check it
against the unwrapped trigger config instead.
Also generalize the storage key `_trigger_params_{node_id}` ->
`_node_input_mask_{node_id}` to match the executor's `nodes_input_masks`
concept (route, copilot tools, RPC, and the data migration all updated).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…t-input-blocks-alongside-trigger-blocks
Conflicts resolved across the preset-trigger input-mask work and dev's
expert-scoping changes:
- triggers.py / db.py / router.py / manage_presets.py: keep both sides —
the `_node_input_mask_{node_id}` wrap/extract plus dev's expert tenancy
resolution and `WebhookPresetMigrationResult` return shape.
- triggers_test.py: both sides added different tests at the same point;
kept the union. Adapted this branch's two tests to dev's 5-tuple
`_patches()` signature (now yields `p_expert`), and fixed
`test_invalid_inputs_rejected_before_webhook_setup`, which auto-merged
outside the conflict region while still unpacking the old 4-tuple.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L5qijS3Tm9QxQzt2kARtLp
|
Conflicts have been resolved! 🎉 A maintainer will review the pull request shortly. |
…contract
Post-merge fallout from combining the `_node_input_mask_{node_id}` input
shape with dev's expert-scoping work; all three are test-only.
- webhook_ingress_test.py: `_make_expert_preset` built a preset with flat
`inputs={}`, so the new mask guard skipped the run and
`add_graph_execution` was never awaited. Nest an (empty) trigger mask.
- triggers_test.py: dev's three expert update tests passed the trigger
config flat; it now nests under the per-node mask key, so they failed
with "Missing trigger configuration" before reaching the tenancy logic
they actually assert on.
- webhook_preset_trigger_test.py: `_preset()` left `expert_id` as an
auto-created MagicMock attribute, which is truthy, so dev's new private
expert branch swallowed the run before the event-type check. Set it to
None explicitly.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L5qijS3Tm9QxQzt2kARtLp
Editing an existing trigger rendered empty fields and silently discarded the
edits: `SelectedTriggerView` read `preset.inputs` raw, but a triggered preset
nests its trigger config under `_node_input_mask_{node_id}` alongside the
regular graph inputs. Lookups by flat field name therefore missed, the graph
inputs were never shown at all, and saving wrote the edits back at the top
level where `update_triggered_preset` doesn't look — so the webhook
re-registered with the stale config.
- Split `getAgentInputFields` into the graph's input schema and a new
`getTriggerConfigFields` for the trigger block's config. The old
`trigger_setup_info?.config_schema ?? input_schema` fallback dates from when
a triggered preset stored *only* the trigger config; a triggered agent now
has both, so falling back from one to the other is wrong everywhere it was
used (run, schedule and template views included).
- Add `splitPresetInputs`/`mergePresetInputs`, mirroring the backend's
`node_input_mask_key()`. The trigger node id isn't exposed to the client, so
the mask key is located by prefix and preserved on save rather than rebuilt.
- Render trigger config and graph inputs as separate sections, matching the
setup modal.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YCuti3c1zp3RxejkiJrVGb
|
/review |
…inputs Addresses the review findings on the per-node input mask contract: - The SQL data migration's trigger-block allowlist is fixed at authoring time, so it can never cover a block added later. Add the two it already missed (AllQuiet, Stripe) and make the boot backfill `migrate_flat_triggered_preset_inputs()` authoritative — it derives the set from `get_webhook_block_ids()` and picks up detached presets that SQL cannot tell apart from run templates. - `migrate_legacy_triggered_graphs()` created presets with flat inputs after `migrate deploy` had already run; it now writes the mask key. - Bump the preset version and re-key its mask in one transaction, so a half-applied migration can't strand a preset outside the retry filter. - Validate updated inputs in `update_triggered_preset` the way setup does. - Give the copilot `update_preset` tool a separate `trigger_config`, so graph inputs stop being injected into the trigger config. - Refuse (rather than silently drop) a trigger edit on a preset with no mask key, and stop rendering an empty inputs card for historical runs. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…t-input-blocks-alongside-trigger-blocks
Bound the boot backfill with the same `asyncio.wait_for` its guarded neighbour uses: on a converged database it is one selective query, but the first boot after the data migration walks whatever that migration could not reach, and an unbounded backfill in the startup path delays the port before the API serves traffic. Each preset commits on its own, so a timeout defers the remainder to the next boot. Also count failures, so a systematic one reports a total rather than only per-preset lines. Tests, each proven to fail against the mutation it exists to catch: the mask-less discriminator on all four cohorts, the backfill's steady-state cost and its wrapping of a preset the SQL migration missed, the update path's input validation and its mask/graph-input split, the copilot tool's routing of `inputs` and `trigger_config`, the refused save on a preset with no mask key, and the read-only inputs panel no longer rendering an empty card. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
🤖 Review backlog closed: 8 fixed, 0 declined, 0 escalatedAll eight open threads from the 2026-09-02 review were verified against the code before being acted on, and all eight turned out to be real at this head. Fixes are in 140e63f (code) and 43b3725 (tests), on top of a
The blocker's own suggestion is the part worth reading. Deriving the id set from block type is right in spirit but unavailable in SQL — What the findings got wrong: nothing material. The one correction is to the fix proposed on VerificationSix mutations were run, one per new guard, and each was caught by the test that covers it: the mask-less discriminator forced true (3 tests fail), the query's mask-absence filter removed (1), the update path's validation swallowed (1), the copilot routing reverted to merging Suites: 1647 Migration: all 196 migrations applied to a throwaway A pyright error in |
|
🤖 Follow-up evidence on the two migration threads: the boot backfill was exercised against a real Postgres, not only against mocked Prisma models. Seeded on the local database: a graph with a GitHub Issues trigger node, and a preset with That covers the parts unit tests could not: the Still unmeasured: first-boot timing against a production-scale cohort. That is what the |
`tool_schema_test.py::test_total_schema_char_budget` was already failing on
this branch at 61,313 chars against a 61,000 limit — the PR's own
`constant_inputs` and my `trigger_config` are new tool surface, and both
tools' descriptions had grown wordy. Restoring just those two files to their
dev versions makes the test pass, so the overage is this PR's.
Trimmed 303 chars of restatement from both tools first, keeping the
prohibitions the model actually needs ("never by editing the trigger node",
"not the trigger config"), then bumped the budget 61,000 -> 62,000 for the
two genuinely new parameters, in the same documented form as the five bumps
before it: what it buys, the measured total, the headroom.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Four comments ran to four and five lines where two or three carry the same constraint. No behaviour change. Also record, above `_CHAR_BUDGET` where a resolver will actually see it, that a merge conflict on that constant resolves to the higher value: #14424 and #14455 are bumping the same line concurrently, and each branch's CI only measures its own delta against dev, so taking the incoming side lowers a ceiling that has to cover every in-flight PR at once. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This PR lets a triggered preset carry regular graph inputs alongside its trigger config, so a graph can have both a webhook-trigger node and input nodes instead of being forced to choose one.
Why
Previously a graph could have either a webhook-trigger node or input nodes, but not both: the builder blocked combining them, and a triggered preset stored only the trigger config as its
inputs. That meant you couldn't configure regular graph inputs on a webhook-triggered agent.How
inputsnow hold the regular graph inputs plus the trigger node's config nested under a per-node key_node_input_mask_{node_id}. The name matches the executor's existingnodes_input_masksconcept.TriggeredPresetSetupRequestgains aconstant_inputsfield (regular graph input values).setup_triggered_presetwraps the trigger config under the per-node key and storesconstant_inputsalongside it._execute_webhook_preset_triggerseparates the two again: regular inputs are passed as graphinputs, while the trigger config + webhook payload become the trigger node'snodes_input_masksentry. The event-type filter is checked against the unwrapped trigger config.update_triggered_presetextracts the trigger config from the same per-node key when re-registering the webhook.api/features/library/triggers.py) reused by the/presetsroutes, the copilot preset tools, and a DatabaseManager RPC endpoint, so all paths produce/consume the same input shape.migrate_preset_trigger_params) converts the bulk of existing triggered presets at deploy time. Its trigger-block list is fixed when the migration is written and an applied migration cannot re-run, so the authoritative conversion ismigrate_flat_triggered_preset_inputs(), which runs on each REST boot and derives the block set fromget_webhook_block_ids(). It also reaches presets whose webhook was detached, which SQL cannot distinguish from a run-template preset — it compares the preset's input names against the trigger block's config schema. On a converged database it is one selective query and no per-preset work; on the first boot after the migration it is bounded byasyncio.wait_for(..., timeout=30), and since each preset commits on its own, a timeout defers the remainder to the next boot rather than delaying the port.Changes 🏗️
constant_inputstoTriggeredPresetSetupRequest; wrap the trigger config under_node_input_mask_{node_id}and store regular inputs alongside itupdate_triggered_presetthe way setup does, give the copilotupdate_presettool a separatetrigger_configso graph inputs stop landing inside the trigger config, and stop the UI reporting success on a trigger edit it silently droppedconstant_inputs,trigger_config), after trimming 303 chars of restatement from both tools' descriptions. Without this the PR is over budget: restoringsetup_agent_webhook_trigger.pyandmanage_presets.pyto theirdevversions makestest_total_schema_char_budgetpass, so the overage is this PR'sVerified
Executed here: the new
migrate_flat_triggered_preset_inputs()discriminator across all four preset cohorts, the backfill's steady-state cost and its wrapping of a preset the SQL migration missed,update_triggered_preset's input validation and its mask/graph-input split, the copilot tool's routing ofinputsvstrigger_config, the refused save on a mask-less preset, and the read-only inputs panel. Every one of those was run against a mutation of the guard it covers and failed, so none of them passes vacuously. Suite runs: 1647test_block.py, 233 integrations + webhooks, 118 library, 68 triggers + copilot presets, 3architecture_test.py, 14 frontend vitest, andtsc --noEmitclean. The full 196-migration directory applied to a throwawaypgvector/pgvector:pg16andmigrate diffagainstschema.prismashowed only the pre-existingorganizationId/trigram drift thatdevalready has; this migration contains no DDL.The backfill was also run against a real Postgres, not only mocks: seeding a detached (
webhookId = NULL) preset with flatrepo/eventsrows on a graph carrying a GitHub Issues trigger node — the exact cohort the SQL migration skips — the boot backfill selected it, replaced both rows with one_node_input_mask_{prefix}row holding the same values, and a second run left it untouched.Not executed: the two manual end-to-end items below, and the backfill at production scale — the timing of a large first-boot cohort is bounded by the timeout rather than measured.
Checklist 📋
For code changes:
setup_triggered_presetwraps regular inputs + trigger config under_node_input_mask_{node_id}update_triggered_presetextracts trigger config from the per-node key; rejects reconfigure when the key is missinginputs, trigger config (+payload) as the node mask, and checks the event filter against the unwrapped configFor configuration changes:
.env.defaultis updated or already compatible with my changesdocker-compose.ymlis updated or already compatible with my changes20251016151116_migrate_preset_trigger_params(converts existing triggered presets; no schema change)