Skip to content

feat(block): Add data enrichment block#4774

Merged
TheodoreSpeaks merged 5 commits into
stagingfrom
feat/enrichment-block
May 29, 2026
Merged

feat(block): Add data enrichment block#4774
TheodoreSpeaks merged 5 commits into
stagingfrom
feat/enrichment-block

Conversation

@TheodoreSpeaks
Copy link
Copy Markdown
Collaborator

Summary

  • Add a generic Data Enrichment workflow block (purple, generated from the enrichment registry) so workflows can run Work Email / Phone Number / Company Domain / Company Info
  • New internal endpoint POST /api/tools/enrichment/run (checkInternalAuth + contract) runs the same runEnrichment provider cascade; injects workspace's hosted/BYOK key via executeTool
  • Block exposes the winning provider's label on output.provider, and surfaces hosted-key cost on output.cost.total so the workflow logging session bills it
  • EnrichmentRunContext.tableId/rowId made optional (workflow path has no row)
  • Tool + block generated from the registry — new enrichments appear automatically

Type of Change

  • New feature

Testing

Tested manually; tsc clean, biome clean, bun run check:api-validation:strict passes, bun run lint clean

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)

@vercel
Copy link
Copy Markdown

vercel Bot commented May 28, 2026

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

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
docs Skipped Skipped May 29, 2026 1:58am

Request Review

@cursor
Copy link
Copy Markdown

cursor Bot commented May 28, 2026

PR Summary

Medium Risk
New internal tool route runs paid third-party enrichment cascades with workspace keys; auth is internal-only but misconfiguration or registry changes could affect billing and data lookups across workflows.

Overview
Adds a Data Enrichment workflow block and enrichment_run tool so workflows can run registry enrichments (work email, phone, company domain/info) using the same provider cascade as table enrichments.

The block UI, tool schema, and docs are generated from ALL_ENRICHMENTS, so new registry entries show up without hand-maintaining fields. It calls a new internal POST /api/tools/enrichment/run route (checkInternalAuth, Zod contract) that runs runEnrichment with workspaceId only—EnrichmentRunContext.tableId / rowId are now optional for this path.

runEnrichment now returns provider (winning provider label). Block/tool outputs include matched, provider, enrichment-specific fields, and cost.total on hosted-key runs for workflow billing. Shared mapFieldType maps enrichment column types to block/tool types. Docs page and API validation route count (+1) are updated.

Reviewed by Cursor Bugbot for commit 54fab27. Bugbot is set up for automated code reviews on this repo. Configure here.

@TheodoreSpeaks TheodoreSpeaks changed the title feat(enrichment): workflow Enrichment block + /api/tools/enrichment/run feat(block): Add data enrichment block May 28, 2026
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented May 28, 2026

Greptile Summary

This PR adds a Data Enrichment workflow block that exposes the existing enrichment registry (Work Email, Phone Number, Company Domain, Company Info) as a first-class block inside workflows, backed by a new internal endpoint POST /api/tools/enrichment/run that reuses the existing provider-cascade runner.

  • New EnrichmentBlock is generated dynamically from ALL_ENRICHMENTS, so new registry entries appear automatically; per-enrichment inputs are shown/hidden via condition on the operation dropdown.
  • EnrichmentRunContext.tableId/rowId are made optional so the same runner works for both the table per-row path and the workflow path (which only has workspaceId); the winning provider's label is surfaced in output.provider and hosted-key cost flows through output.cost.total for billing.

Confidence Score: 5/5

Safe to merge — the new endpoint is internal-auth gated, the contract correctly validates all inputs, and the registry-driven block generation is consistent with existing patterns.

The change is well-contained: a new internal route, a new block, and a thin tool config, all delegating to an already-tested enrichment runner. The only forward-looking concern is that the output-building loops in both the block and the tool don't guard against reserved IDs (matched, provider), which would silently corrupt output schemas if a future enrichment happened to use those names.

apps/sim/blocks/blocks/enrichment.ts and apps/sim/tools/enrichment/run.ts — both build output maps via loops that can unconditionally overwrite the statically defined matched/provider entries.

Important Files Changed

Filename Overview
apps/sim/app/api/tools/enrichment/run/route.ts New internal POST endpoint authenticated by checkInternalAuth; delegates to runEnrichment with the workspace's provider cascade. Logic is clean and consistent with the contract schema.
apps/sim/blocks/blocks/enrichment.ts Block generated from the enrichment registry; unconditional loop over outputProducers can overwrite the reserved matched/provider output definitions if a future enrichment uses those IDs.
apps/sim/tools/enrichment/run.ts Tool config for enrichment_run; …enrichmentOutputs spread last could overwrite static matched/provider output definitions if an enrichment ever uses those IDs; workspaceId is injected via _context and not a declared param.
apps/sim/enrichments/run.ts Adds provider field to EnrichmentRunOutcome; provider.label is surfaced on hit and null on miss — clean minimal change to an existing cascade runner.
apps/sim/lib/api/contracts/tools/enrichment.ts Zod contract for the run route; workspaceId validated with min(1), inputs defaulted to {}, response schema matches the route's return shape.

Sequence Diagram

sequenceDiagram
    participant WF as Workflow Executor
    participant Tool as enrichment_run Tool
    participant Route as POST /api/tools/enrichment/run
    participant Runner as runEnrichment()
    participant P1 as Provider 1 (e.g. Hunter)
    participant P2 as Provider 2 (e.g. PDL)

    WF->>Tool: execute(enrichmentId, inputs, _context.workspaceId)
    Tool->>Route: "POST {enrichmentId, inputs, workspaceId}"
    Route->>Route: checkInternalAuth + Zod parse
    Route->>Route: getEnrichment(enrichmentId)
    Route->>Runner: "runEnrichment(enrichment, inputs, {workspaceId})"
    Runner->>P1: executeTool(toolId, params + _context)
    alt P1 returns result
        P1-->>Runner: success + output
        Runner-->>Route: "{result, cost, error:null, provider:"Hunter"}"
    else P1 misses or errors
        P1-->>Runner: no match or error
        Runner->>P2: executeTool(toolId, params + _context)
        P2-->>Runner: success + output
        Runner-->>Route: "{result, cost, error:null, provider:"People Data Labs"}"
    end
    Route-->>Tool: "{matched, result, cost, error, provider}"
    Tool-->>WF: "{success, output:{...result, matched, provider, cost?}}"
Loading

Reviews (2): Last reviewed commit: "chore: re-trigger CI" | Re-trigger Greptile

Comment thread apps/sim/app/api/tools/enrichment/run/route.ts Outdated
Comment thread apps/docs/content/docs/en/tools/enrichment.mdx
Comment thread apps/docs/content/docs/en/tools/enrichment.mdx
@TheodoreSpeaks
Copy link
Copy Markdown
Collaborator Author

Addressed in the latest commit:

  • P1 — silent missing workspaceId: workspaceId is now required in runEnrichmentBodySchema (z.string().min(1, 'workspaceId is required')), so parseRequest returns 400 if it's omitted. Route no longer falls through to an empty string.
  • P2 — docs color mismatch: BlockInfoCard color updated to #9333EA to match the block's bgColor.
  • P2 — incomplete output table: docs now list matched, provider, and every per-enrichment output (email, phone, domain, industry, employeeCount, foundedYear, description).

tsc + biome + check:api-validation:strict clean.

Add a generic Enrichment workflow block that runs a code-defined enrichment
(Work Email, Phone Number, Company Domain, Company Info, …) and returns its
outputs — usable in workflows, not just tables.

- New internal endpoint POST /api/tools/enrichment/run (checkInternalAuth +
  contract) runs the same runEnrichment provider cascade; injects the
  workspace's hosted/BYOK key via executeTool.
- New tool enrichment_run posts to it and surfaces hosted-key cost on the
  output so the workflow logging session bills it.
- New block blocks/blocks/enrichment.ts generated from the enrichment registry:
  operation dropdown = enrichments, per-enrichment conditional inputs, union of
  conditional outputs. New registry entries appear automatically.
- EnrichmentRunContext.tableId/rowId made optional (workflow path has no row).
- Register tool + block; bump api-validation route baseline; add EnrichmentIcon
  and generated docs page.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Comment thread scripts/check-api-validation-contracts.ts
Comment thread apps/sim/tools/enrichment/run.ts Outdated
# Conflicts:
#	scripts/check-api-validation-contracts.ts
@TheodoreSpeaks
Copy link
Copy Markdown
Collaborator Author

Addressed:

  • Low — duplicated type-mapping logic: factored a shared mapFieldType helper into enrichments/providers.ts (returns the narrow 'string' | 'number' | 'boolean' | 'json' union, assignable to both OutputType and ParamType). Tool and block both import it now; the two local implementations are gone.
  • Low — route baseline incremented by 2: the bot reviewed before I merged staging. After the merge, the audit is at exact match (total routes: 758 / baseline: 758), with no ratchet slack — check:api-validation:strict passes clean.

tsc + biome + audit clean.

Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 870203c. Configure here.

Comment thread apps/sim/tools/enrichment/run.ts
@TheodoreSpeaks
Copy link
Copy Markdown
Collaborator Author

Addressed in latest commit — reserved output keys (matched, provider) are now assigned after the per-enrichment outputs in both the tool and the block, so a future enrichment with a colliding output id can't silently shadow them. tsc + biome clean.

@TheodoreSpeaks TheodoreSpeaks merged commit 7f24ae1 into staging May 29, 2026
14 checks passed
@TheodoreSpeaks TheodoreSpeaks deleted the feat/enrichment-block branch May 29, 2026 02:19
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