feat(webhooks): scope event subscriptions to specific agents/workflows#216
Merged
Conversation
Adds optional agentIds and workflowIds filter arrays to AiWebhookSubscription so admins can limit a subscription to specific entities instead of receiving every event of a given type. Empty arrays preserve current behaviour (no constraint), so existing rows keep delivering as before. Filtering is dimension-specific: an agentIds filter only restricts events that carry an agent ID; a workflowIds filter only restricts workflow-typed events. A new EVENT_ENTITY_KEYS map is the single source of truth for which payload field carries each entity ID. Fails closed when the payload is missing the expected ID — prevents enrichment bugs from leaking events to scoped subscribers. Also enriches workflow_budget_exceeded with workflowId so engine call sites can target it via the workflow filter. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Pass `isTemplate=false` to the workflows list endpoint when loading options for the "Limit to workflows" multi-select. Templates aren't instantiated runtime entities, so they never appear in event payloads and scoping a sub to one is a no-op. The chip-label pre-fetch is intentionally left unfiltered so previously- saved IDs (or workflows later flipped to templates) still resolve to a name instead of showing a bare CUID. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds tests for the new code introduced in 5a3a3893: webhook-form (4 new tests): - Renders the Scope section with agent + workflow labels - Edit-mode prefetch resolves stored CUIDs to chip names via the admin agents/workflows endpoints (no `q` search query) - Empty-scope create form skips the prefetch entirely (no wasted request) - Workflow loader applies `isTemplate=false` so templates are filtered out server-side webhooks-table (3 new tests): - Scoped badge renders for a row with agentIds, tooltip shows counts - Scoped badge renders for a row with workflowIds - Scoped badge does NOT render when both arrays are empty (backward-compat rows stay un-decorated) Restores webhook-form.tsx to ≥80% on all four coverage metrics (was 70.6/77.6/73.8/68.2 before, now 91.9/86.7/85.7/89.2). webhooks-table.tsx branches improved 70.6 → 76.5; the residual gap is in pre-existing `it.todo` cases unrelated to entity scoping (lines 105, 125, 268, 303). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Contributor
Author
Code reviewNo issues found. Checked for bugs and CLAUDE.md compliance. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds optional agent and workflow filter arrays to
AiWebhookSubscriptionso admins can scope a subscription to specific entities instead of receiving every event of a given type. Empty arrays preserve current behaviour — existing rows continue delivering as before.Why
Operators running multiple agents/workflows had only one knob: subscribe to an event type and get it for every entity. That meant either flooding receivers, splitting one logical alert across N near-identical subscriptions, or filtering downstream. This PR closes the gap with two small filter columns and a centralised matching rule.
How it works
Filtering is dimension-specific: an
agentIdsfilter only restricts events that carry an agent ID; aworkflowIdsfilter only restricts workflow-typed events. Setting an agent filter does NOT silence unrelated workflow events. The map atlib/orchestration/webhooks/event-entity-keys.tsis the single source of truth for which payload field carries each entity ID; a coverage test asserts every wired event type is mapped.Fails closed when a mapped event's payload is missing the expected ID — a scoped sub with a non-empty filter on that dimension does NOT match. Prevents an upstream enrichment bug from leaking events to scoped subscribers.
What landed
String[] @default([])columns onAiWebhookSubscription+ additive migration (add_entity_scope_to_webhook_subscription).lib/orchestration/webhooks/dispatcher.tsrunsmatchesEntityScope(...)over the result offindManybefore scheduling deliveries.workflow_budget_exceedednow carriesworkflowIdfrom all four engine call sites, so workflow-typed subs can scope it.agentIds/workflowIdsflow throughcreateWebhookSchema/updateWebhookSchemaand the route handlers; 50-entry cap per dimension.MultiSelects (agents + workflows). Workflow picker filters templates server-side (isTemplate=false) since templates are never event subjects.<FieldHelp>copy explains the dimension-specific rule.Scopedbadge with count tooltip when either filter array is non-empty..context/orchestration/hooks.md; form + table updates in.context/admin/orchestration-webhooks.md.Tests
event-entity-keys.tsincluding a coverage assertion that every entry inWEBHOOK_EVENT_TYPEShas a deliberate map entry.isTemplate=false).workflow_budget_exceededcarriesworkflowIdend-to-end.All 4011 tests pass. Validate clean (0 errors).
webhook-form.tsxcoverage went from 70.6/77.6/73.8/68.2 → 91.9/86.7/85.7/89.2 (all ≥80%).Test plan
npm run db:migrate:dev— non-destructive additive migration applies.Backward compatibility
Fully backward compatible. Existing subscription rows default to empty arrays, which the matcher treats as "no constraint". The schema migration is purely additive. No API contract changes for existing fields.
Commits
🤖 Generated with Claude Code