sea-dev 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/tasks/README.md +89 -0
- package/.cursor/rules/commits.mdc +31 -0
- package/.cursor/rules/general.mdc +84 -0
- package/.github/workflows/ci-cd.yml +141 -0
- package/CLAUDE.md +337 -0
- package/README.md +129 -0
- package/apps/api/.prettierignore +6 -0
- package/apps/api/.prettierrc.js +3 -0
- package/apps/api/dotenvx-safe.sh +11 -0
- package/apps/api/eslint.config.mjs +3 -0
- package/apps/api/package.json +58 -0
- package/apps/api/src/clients/posthog.ts +25 -0
- package/apps/api/src/dal/submission.ts +59 -0
- package/apps/api/src/errors.ts +55 -0
- package/apps/api/src/index.ts +21 -0
- package/apps/api/src/lib/channel.ts +28 -0
- package/apps/api/src/lib/config.ts +9 -0
- package/apps/api/src/lib/fmt.test.ts +9 -0
- package/apps/api/src/lib/fmt.ts +62 -0
- package/apps/api/src/lib/invariant.ts +23 -0
- package/apps/api/src/middleware/auth.ts +66 -0
- package/apps/api/src/routes/index.ts +20 -0
- package/apps/api/src/routes/v2/chat/handlers.ts +693 -0
- package/apps/api/src/routes/v2/chat/index.ts +257 -0
- package/apps/api/src/routes/v2/chat/schemas.ts +43 -0
- package/apps/api/src/routes/v2/deals/handlers.ts +64 -0
- package/apps/api/src/routes/v2/deals/index.ts +88 -0
- package/apps/api/src/routes/v2/deals/schemas.ts +38 -0
- package/apps/api/src/routes/v2/forms/handlers.ts +415 -0
- package/apps/api/src/routes/v2/forms/index.ts +382 -0
- package/apps/api/src/routes/v2/forms/schemas.ts +243 -0
- package/apps/api/src/routes/v2/index.ts +19 -0
- package/apps/api/src/routes/v2/pipelines/handlers.ts +261 -0
- package/apps/api/src/routes/v2/pipelines/index.ts +224 -0
- package/apps/api/src/routes/v2/pipelines/schemas.ts +173 -0
- package/apps/api/src/routes/v2/submissions/handlers.ts +555 -0
- package/apps/api/src/routes/v2/submissions/index.ts +366 -0
- package/apps/api/src/routes/v2/submissions/schemas.ts +233 -0
- package/apps/api/src/routes/v2/workflows/handlers.ts +81 -0
- package/apps/api/src/routes/v2/workflows/index.ts +88 -0
- package/apps/api/src/routes/v2/workflows/schemas.ts +40 -0
- package/apps/api/src/server.ts +146 -0
- package/apps/api/src/static/favicon.ico +0 -0
- package/apps/api/src/types/api.ts +14 -0
- package/apps/api/src/types/result.ts +3 -0
- package/apps/api/tsconfig.json +22 -0
- package/apps/api/vite.config.ts +28 -0
- package/apps/api/vitest.config.ts +14 -0
- package/apps/conversion-worker/Dockerfile +59 -0
- package/apps/conversion-worker/package.json +31 -0
- package/apps/conversion-worker/src/lib/config.ts +7 -0
- package/apps/conversion-worker/src/main.ts +22 -0
- package/apps/conversion-worker/src/workflows/convert-pptx.ts +116 -0
- package/apps/conversion-worker/tsconfig.json +27 -0
- package/apps/conversion-worker/vite.config.ts +33 -0
- package/apps/main/.prettierignore +6 -0
- package/apps/main/.prettierrc.js +3 -0
- package/apps/main/CLAUDE.md +245 -0
- package/apps/main/Procfile +1 -0
- package/apps/main/README.md +193 -0
- package/apps/main/db-tests.jsonl +116 -0
- package/apps/main/dotenvx-safe.sh +11 -0
- package/apps/main/drizzle/meta/_journal.json +1 -0
- package/apps/main/drizzle.config.ts +25 -0
- package/apps/main/eslint.config.mjs +3 -0
- package/apps/main/generate-routes.mjs +5 -0
- package/apps/main/package.json +131 -0
- package/apps/main/playwright.config.ts +23 -0
- package/apps/main/postcss.config.ts +5 -0
- package/apps/main/public/bg-dark.svg +10 -0
- package/apps/main/public/bg.svg +10 -0
- package/apps/main/public/favicon.ico +0 -0
- package/apps/main/run.sh +146 -0
- package/apps/main/scripts/browser.ts +14 -0
- package/apps/main/scripts/db-test-cov.ts +277 -0
- package/apps/main/scripts/login.ts +78 -0
- package/apps/main/scripts/repl.ts +61 -0
- package/apps/main/src/_foo.ts +31 -0
- package/apps/main/src/_tests/db.test.ts +19 -0
- package/apps/main/src/_tests/mock-db.ts +60 -0
- package/apps/main/src/client.tsx +13 -0
- package/apps/main/src/clients/loops.ts +13 -0
- package/apps/main/src/clients/polar.ts +12 -0
- package/apps/main/src/clients/posthog.ts +12 -0
- package/apps/main/src/components/chat/chat-context.tsx +99 -0
- package/apps/main/src/components/chat/chat-messages.tsx +184 -0
- package/apps/main/src/components/chat/chat-status.tsx +140 -0
- package/apps/main/src/components/chat/chat.tsx +458 -0
- package/apps/main/src/components/chat/citation-modal.tsx +54 -0
- package/apps/main/src/components/cta.tsx +21 -0
- package/apps/main/src/components/data-display/derived.tsx +40 -0
- package/apps/main/src/components/data-display/group-single.tsx +57 -0
- package/apps/main/src/components/data-display/group-table.tsx +165 -0
- package/apps/main/src/components/data-display/group-wrapper.tsx +54 -0
- package/apps/main/src/components/data-display/item.tsx +678 -0
- package/apps/main/src/components/error.tsx +45 -0
- package/apps/main/src/components/forms/error.tsx +22 -0
- package/apps/main/src/components/grid.tsx +7 -0
- package/apps/main/src/components/header/container.tsx +73 -0
- package/apps/main/src/components/header/header-bar.tsx +102 -0
- package/apps/main/src/components/modals/copy-display.tsx +37 -0
- package/apps/main/src/components/modals/copy-form.tsx +152 -0
- package/apps/main/src/components/modals/duplicate-workflow.tsx +89 -0
- package/apps/main/src/components/modals/field-correction.tsx +323 -0
- package/apps/main/src/components/modals/form-viewer.tsx +126 -0
- package/apps/main/src/components/modals/modals.tsx +44 -0
- package/apps/main/src/components/modals/new-deal.tsx +78 -0
- package/apps/main/src/components/modals/new-form.tsx +133 -0
- package/apps/main/src/components/modals/new-pipeline.tsx +70 -0
- package/apps/main/src/components/modals/new-submission.tsx +321 -0
- package/apps/main/src/components/modals/new-workflow.tsx +342 -0
- package/apps/main/src/components/modals/transformation-sources-modal.tsx +157 -0
- package/apps/main/src/components/modals/view-report.tsx +193 -0
- package/apps/main/src/components/not-found.tsx +14 -0
- package/apps/main/src/components/search/search-bar.tsx +178 -0
- package/apps/main/src/components/sheet-selector.tsx +135 -0
- package/apps/main/src/components/side-panel/doc-list.tsx +480 -0
- package/apps/main/src/components/sidebar/admin-sidebar.tsx +75 -0
- package/apps/main/src/components/sidebar/app-sidebar.tsx +417 -0
- package/apps/main/src/components/sidebar/model-select.tsx +134 -0
- package/apps/main/src/components/sidebar/settings-sidebar.tsx +132 -0
- package/apps/main/src/components/sidebar/sidebar-right.tsx +22 -0
- package/apps/main/src/components/sidebar/stop-impersonate.tsx +21 -0
- package/apps/main/src/components/svg/loading.tsx +33 -0
- package/apps/main/src/components/theme-selector.tsx +43 -0
- package/apps/main/src/components/unsaved-badge.tsx +19 -0
- package/apps/main/src/components/upload/file-upload.tsx +354 -0
- package/apps/main/src/fns/submission-groups.ts +28 -0
- package/apps/main/src/fns/submission-items.ts +11 -0
- package/apps/main/src/global-middleware.ts +16 -0
- package/apps/main/src/hooks/use-update-state.ts +18 -0
- package/apps/main/src/lib/auth-client.ts +16 -0
- package/apps/main/src/lib/auth.test.ts +359 -0
- package/apps/main/src/lib/auth.ts +144 -0
- package/apps/main/src/lib/billing.ts +23 -0
- package/apps/main/src/lib/config-iso.ts +76 -0
- package/apps/main/src/lib/config.ts +61 -0
- package/apps/main/src/lib/excel.ts +16 -0
- package/apps/main/src/lib/feedback-cache.ts +70 -0
- package/apps/main/src/lib/logger.ts +44 -0
- package/apps/main/src/lib/models.ts +22 -0
- package/apps/main/src/lib/not-found.ts +17 -0
- package/apps/main/src/lib/pdf.ts +16 -0
- package/apps/main/src/lib/tabularize.ts +54 -0
- package/apps/main/src/lib/utils.ts +10 -0
- package/apps/main/src/lib/zfd.ts +217 -0
- package/apps/main/src/middleware.ts +55 -0
- package/apps/main/src/routeTree.gen.ts +1255 -0
- package/apps/main/src/router.tsx +24 -0
- package/apps/main/src/routes/__root.tsx +92 -0
- package/apps/main/src/routes/_authed/_app/(dashboard)/index.tsx +227 -0
- package/apps/main/src/routes/_authed/_app/agents/$agentId/config.tsx +224 -0
- package/apps/main/src/routes/_authed/_app/agents/$agentId/index.tsx +206 -0
- package/apps/main/src/routes/_authed/_app/agents/-components/agent-actions-menu.tsx +94 -0
- package/apps/main/src/routes/_authed/_app/agents/-components/agent-artifacts.tsx +153 -0
- package/apps/main/src/routes/_authed/_app/agents/-components/agent-chat.tsx +220 -0
- package/apps/main/src/routes/_authed/_app/agents/-components/agent-history-menu.tsx +81 -0
- package/apps/main/src/routes/_authed/_app/agents/-components/agent-model-select.tsx +84 -0
- package/apps/main/src/routes/_authed/_app/agents/-components/agent-relevant-items.tsx +226 -0
- package/apps/main/src/routes/_authed/_app/agents/-components/agent-upload-button.tsx +298 -0
- package/apps/main/src/routes/_authed/_app/agents/-components/context-modal.tsx +187 -0
- package/apps/main/src/routes/_authed/_app/agents/-fns.ts +560 -0
- package/apps/main/src/routes/_authed/_app/agents/index.tsx +65 -0
- package/apps/main/src/routes/_authed/_app/deals/$dealId/$subId/-components/citation-tree.tsx +268 -0
- package/apps/main/src/routes/_authed/_app/deals/$dealId/$subId.tsx +655 -0
- package/apps/main/src/routes/_authed/_app/deals/$dealId/-components/doc-loading.tsx +37 -0
- package/apps/main/src/routes/_authed/_app/deals/$dealId/-components/share-link.tsx +42 -0
- package/apps/main/src/routes/_authed/_app/deals/$dealId/-components/submission-card.tsx +89 -0
- package/apps/main/src/routes/_authed/_app/deals/$dealId/-components/submission-filter.tsx +193 -0
- package/apps/main/src/routes/_authed/_app/deals/$dealId/-components/submissions.tsx +36 -0
- package/apps/main/src/routes/_authed/_app/deals/$dealId/-components/summary.tsx +82 -0
- package/apps/main/src/routes/_authed/_app/deals/$dealId/-components/upload-doc.tsx +120 -0
- package/apps/main/src/routes/_authed/_app/deals/$dealId/-fns.ts +653 -0
- package/apps/main/src/routes/_authed/_app/deals/$dealId/index.tsx +259 -0
- package/apps/main/src/routes/_authed/_app/deals/$dealId/route.tsx +29 -0
- package/apps/main/src/routes/_authed/_app/deals/index.tsx +104 -0
- package/apps/main/src/routes/_authed/_app/feedback/index.tsx +639 -0
- package/apps/main/src/routes/_authed/_app/feedback/insights.tsx +250 -0
- package/apps/main/src/routes/_authed/_app/pipelines/$pipelineId/$runId/-components/blockers-panel.tsx +260 -0
- package/apps/main/src/routes/_authed/_app/pipelines/$pipelineId/$runId/-components/manual-input-panel.tsx +301 -0
- package/apps/main/src/routes/_authed/_app/pipelines/$pipelineId/$runId/-components/submission-selector-modal.tsx +143 -0
- package/apps/main/src/routes/_authed/_app/pipelines/$pipelineId/$runId/-components/upload-doc.tsx +120 -0
- package/apps/main/src/routes/_authed/_app/pipelines/$pipelineId/$runId/index.tsx +1485 -0
- package/apps/main/src/routes/_authed/_app/pipelines/$pipelineId/-components/dag-view.tsx +296 -0
- package/apps/main/src/routes/_authed/_app/pipelines/$pipelineId/-components/step-config-modal.tsx +634 -0
- package/apps/main/src/routes/_authed/_app/pipelines/$pipelineId/index.tsx +911 -0
- package/apps/main/src/routes/_authed/_app/pipelines/-fns.ts +510 -0
- package/apps/main/src/routes/_authed/_app/pipelines/index.tsx +103 -0
- package/apps/main/src/routes/_authed/_app/reports/$reportId.tsx +397 -0
- package/apps/main/src/routes/_authed/_app/reports/-fns.ts +11 -0
- package/apps/main/src/routes/_authed/_app/reports/index.tsx +22 -0
- package/apps/main/src/routes/_authed/_app/route.tsx +48 -0
- package/apps/main/src/routes/_authed/_app/submissions/-columns.tsx +161 -0
- package/apps/main/src/routes/_authed/_app/submissions/-fns.ts +128 -0
- package/apps/main/src/routes/_authed/_app/submissions/index.tsx +190 -0
- package/apps/main/src/routes/_authed/_app/workflows/$wfSlug/$formId.tsx +542 -0
- package/apps/main/src/routes/_authed/_app/workflows/$wfSlug/-components/derived.tsx +154 -0
- package/apps/main/src/routes/_authed/_app/workflows/$wfSlug/-components/field.tsx +369 -0
- package/apps/main/src/routes/_authed/_app/workflows/$wfSlug/-components/group.tsx +475 -0
- package/apps/main/src/routes/_authed/_app/workflows/$wfSlug/index.tsx +263 -0
- package/apps/main/src/routes/_authed/_app/workflows/$wfSlug/route.tsx +33 -0
- package/apps/main/src/routes/_authed/_app/workflows/-components/form-card.tsx +315 -0
- package/apps/main/src/routes/_authed/_app/workflows/index.tsx +86 -0
- package/apps/main/src/routes/_authed/admin/index.tsx +12 -0
- package/apps/main/src/routes/_authed/admin/route.tsx +42 -0
- package/apps/main/src/routes/_authed/admin/users/-columns.tsx +124 -0
- package/apps/main/src/routes/_authed/admin/users/-fns.ts +30 -0
- package/apps/main/src/routes/_authed/admin/users/index.tsx +29 -0
- package/apps/main/src/routes/_authed/catchNotFound.tsx +114 -0
- package/apps/main/src/routes/_authed/redirects/forms.$id.tsx +29 -0
- package/apps/main/src/routes/_authed/redirects/submissions.$id.tsx +27 -0
- package/apps/main/src/routes/_authed/redirects/workflows.$id.tsx +27 -0
- package/apps/main/src/routes/_authed/route.tsx +51 -0
- package/apps/main/src/routes/_authed/settings/-components/new-api-key.tsx +85 -0
- package/apps/main/src/routes/_authed/settings/-components/new-invite.tsx +100 -0
- package/apps/main/src/routes/_authed/settings/analytics.tsx +1710 -0
- package/apps/main/src/routes/_authed/settings/billing/-components/price-table.tsx +129 -0
- package/apps/main/src/routes/_authed/settings/billing/-fns.ts +76 -0
- package/apps/main/src/routes/_authed/settings/billing/index.tsx +119 -0
- package/apps/main/src/routes/_authed/settings/embed.tsx +337 -0
- package/apps/main/src/routes/_authed/settings/index.tsx +12 -0
- package/apps/main/src/routes/_authed/settings/keys.tsx +157 -0
- package/apps/main/src/routes/_authed/settings/members.tsx +276 -0
- package/apps/main/src/routes/_authed/settings/route.tsx +22 -0
- package/apps/main/src/routes/_authed/settings/user.tsx +87 -0
- package/apps/main/src/routes/_authed/settings/workspace.tsx +206 -0
- package/apps/main/src/routes/_public/-components/sign-in-up.tsx +96 -0
- package/apps/main/src/routes/_public/embedded.tsx +57 -0
- package/apps/main/src/routes/_public/invite.$inviteId.tsx +143 -0
- package/apps/main/src/routes/_public/no-access.tsx +38 -0
- package/apps/main/src/routes/_public/no-invite.tsx +39 -0
- package/apps/main/src/routes/_public/otp.tsx +103 -0
- package/apps/main/src/routes/_public/route.tsx +15 -0
- package/apps/main/src/routes/_public/sign-in.tsx +111 -0
- package/apps/main/src/routes/_public/sign-up.tsx +114 -0
- package/apps/main/src/routes/api/auth/$.ts +11 -0
- package/apps/main/src/routes/api/billing/paid.ts +42 -0
- package/apps/main/src/routes/api/billing/webhooks.ts +70 -0
- package/apps/main/src/routes/api/chat/agent.ts +40 -0
- package/apps/main/src/routes/api/chat/key.ts +42 -0
- package/apps/main/src/routes/api/chat/member.ts +35 -0
- package/apps/main/src/routes/api/test/index.ts +19 -0
- package/apps/main/src/server.tsx +6 -0
- package/apps/main/src/styles/app.css +23 -0
- package/apps/main/src/vite-env.d.ts +7 -0
- package/apps/main/test.http +6 -0
- package/apps/main/tsconfig.json +17 -0
- package/apps/main/vite.config.ts +24 -0
- package/apps/main/vitest.config.js +17 -0
- package/apps/mcp/README.md +171 -0
- package/apps/mcp/eslint.config.mjs +3 -0
- package/apps/mcp/package.json +37 -0
- package/apps/mcp/src/index.ts +414 -0
- package/apps/mcp/tsconfig.json +19 -0
- package/apps/mcp/vite.config.ts +22 -0
- package/apps/posthog-proxy/index.html +9 -0
- package/apps/workers/.prettierignore +7 -0
- package/apps/workers/.prettierrc.js +3 -0
- package/apps/workers/dotenvx-safe.sh +11 -0
- package/apps/workers/eslint.config.mjs +3 -0
- package/apps/workers/package.json +65 -0
- package/apps/workers/src/lib/config.ts +7 -0
- package/apps/workers/src/lib/messages.ts +0 -0
- package/apps/workers/src/lib/posthog.ts +25 -0
- package/apps/workers/src/main.ts +58 -0
- package/apps/workers/src/workflows/extraction.ts +866 -0
- package/apps/workers/src/workflows/index.ts +3 -0
- package/apps/workers/src/workflows/pipeline-dag.ts +210 -0
- package/apps/workers/src/workflows/pipeline-steps.ts +1393 -0
- package/apps/workers/tsconfig.json +16 -0
- package/apps/workers/vite.config.ts +35 -0
- package/docs/CHANGELOG.md +84 -0
- package/docs/agent-templates-and-runs.md +859 -0
- package/docs/aws-migration-plan.md +267 -0
- package/docs/impl-p0-form-builder-improvements.md +683 -0
- package/docs/on-prem-deployment-spec.docx +0 -0
- package/docs/on-prem-deployment-spec.md +378 -0
- package/docs/prd-form-builder-strategy.md +1120 -0
- package/docs/widget-ng-apf-packaging-spec.md +43 -0
- package/infra/k8s/charts/seadotdev/Chart.yaml +6 -0
- package/infra/k8s/charts/seadotdev/templates/_helpers.tpl +27 -0
- package/infra/k8s/charts/seadotdev/templates/api-v2.yaml +105 -0
- package/infra/k8s/charts/seadotdev/templates/external-secrets.yaml +83 -0
- package/infra/k8s/charts/seadotdev/templates/ingress.yaml +54 -0
- package/infra/k8s/charts/seadotdev/templates/main-app.yaml +104 -0
- package/infra/k8s/charts/seadotdev/templates/workers.yaml +182 -0
- package/infra/k8s/charts/seadotdev/values.yaml +143 -0
- package/infra/terraform/main.tf +399 -0
- package/libs/ai/.prettierignore +2 -0
- package/libs/ai/.prettierrc.js +5 -0
- package/libs/ai/README.md +139 -0
- package/libs/ai/eslint.config.mjs +3 -0
- package/libs/ai/package.json +42 -0
- package/libs/ai/src/index.ts +5 -0
- package/libs/ai/src/models.ts +19 -0
- package/libs/ai/src/rag/index.ts +1 -0
- package/libs/ai/src/rag/rag.test.ts +99 -0
- package/libs/ai/src/rag/rag.ts +510 -0
- package/libs/ai/tsconfig.json +21 -0
- package/libs/ai/vite.config.ts +38 -0
- package/libs/cache/.prettierignore +2 -0
- package/libs/cache/eslint.config.mjs +3 -0
- package/libs/cache/package.json +35 -0
- package/libs/cache/src/feedback.ts +77 -0
- package/libs/cache/src/index.ts +2 -0
- package/libs/cache/tsconfig.json +19 -0
- package/libs/cache/vite.config.ts +36 -0
- package/libs/clients/.prettierignore +6 -0
- package/libs/clients/eslint.config.mjs +3 -0
- package/libs/clients/package.json +59 -0
- package/libs/clients/src/azure.ts +249 -0
- package/libs/clients/src/gcp.ts +220 -0
- package/libs/clients/src/hatchet.ts +86 -0
- package/libs/clients/src/index.ts +8 -0
- package/libs/clients/src/loops.ts +86 -0
- package/libs/clients/src/polar.ts +77 -0
- package/libs/clients/src/posthog.ts +55 -0
- package/libs/clients/tsconfig.json +19 -0
- package/libs/clients/vite.config.ts +35 -0
- package/libs/config/.prettierignore +6 -0
- package/libs/config/.prettierrc.js +12 -0
- package/libs/config/eslint.config.mjs +3 -0
- package/libs/config/package.json +50 -0
- package/libs/config/src/azure.ts +54 -0
- package/libs/config/src/db.ts +18 -0
- package/libs/config/src/gcp.ts +53 -0
- package/libs/config/src/google.ts +17 -0
- package/libs/config/src/hatchet.ts +20 -0
- package/libs/config/src/index.ts +108 -0
- package/libs/config/src/llm.ts +17 -0
- package/libs/config/src/polar.ts +24 -0
- package/libs/config/src/util.ts +8 -0
- package/libs/config/src/vercel.ts +26 -0
- package/libs/config/tsconfig.json +19 -0
- package/libs/config/vite.config.ts +34 -0
- package/libs/core/.prettierignore +2 -0
- package/libs/core/eslint.config.mjs +3 -0
- package/libs/core/package.json +59 -0
- package/libs/core/src/chat/derived.ts +97 -0
- package/libs/core/src/chat/feedback.ts +293 -0
- package/libs/core/src/chat/index.ts +6 -0
- package/libs/core/src/chat/model.ts +92 -0
- package/libs/core/src/chat/prepare-tools.ts +286 -0
- package/libs/core/src/chat/prompts.ts +623 -0
- package/libs/core/src/chat/stream.ts +311 -0
- package/libs/core/src/chat/summarize.ts +168 -0
- package/libs/core/src/chat/tools/agent.ts +403 -0
- package/libs/core/src/chat/tools/chart-agent.ts +526 -0
- package/libs/core/src/chat/tools/chart-helpers/sandbox.ts +47 -0
- package/libs/core/src/chat/tools/chart.ts +86 -0
- package/libs/core/src/chat/tools/credit-agent.ts +1383 -0
- package/libs/core/src/chat/tools/credit.ts +1435 -0
- package/libs/core/src/chat/tools/deep-dive-agent.ts +100 -0
- package/libs/core/src/chat/tools/deep-dive.ts +141 -0
- package/libs/core/src/chat/tools/form.ts +449 -0
- package/libs/core/src/chat/tools/helpers.ts +91 -0
- package/libs/core/src/chat/tools/index.ts +42 -0
- package/libs/core/src/chat/tools/pipeline-artifact.ts +76 -0
- package/libs/core/src/chat/tools/report.ts +40 -0
- package/libs/core/src/chat/tools/search.ts +390 -0
- package/libs/core/src/chat/tools/submission.ts +227 -0
- package/libs/core/src/chat/tools/workflow.ts +684 -0
- package/libs/core/src/chat/types.ts +3 -0
- package/libs/core/src/data-extraction/classification/azure.ts +168 -0
- package/libs/core/src/data-extraction/classification/index.ts +1 -0
- package/libs/core/src/data-extraction/dal.ts +246 -0
- package/libs/core/src/data-extraction/form-structure-extractor.ts +294 -0
- package/libs/core/src/data-extraction/index.ts +4 -0
- package/libs/core/src/data-extraction/layout/azure.ts +730 -0
- package/libs/core/src/data-extraction/layout/excel.ts +180 -0
- package/libs/core/src/data-extraction/layout/gcp.ts +1071 -0
- package/libs/core/src/data-extraction/layout/index.ts +266 -0
- package/libs/core/src/data-extraction/layout/plaintext.ts +45 -0
- package/libs/core/src/data-extraction/models.ts +38 -0
- package/libs/core/src/data-extraction/pdf-utils.ts +96 -0
- package/libs/core/src/data-extraction/structuring/bank-statement.ts +1182 -0
- package/libs/core/src/data-extraction/structuring/custom.ts +495 -0
- package/libs/core/src/data-extraction/structuring/index.ts +290 -0
- package/libs/core/src/data-extraction/structuring/prompts.ts +69 -0
- package/libs/core/src/data-extraction/type-guards.ts +110 -0
- package/libs/core/src/data-extraction/types.ts +84 -0
- package/libs/core/src/data-extraction/utils.ts +31 -0
- package/libs/core/src/data-extraction/validation/bank-statement.ts +127 -0
- package/libs/core/src/deals.ts +17 -0
- package/libs/core/src/documents.ts +152 -0
- package/libs/core/src/index.ts +5 -0
- package/libs/core/src/pipelines/display.ts +678 -0
- package/libs/core/src/pipelines/execute.ts +2342 -0
- package/libs/core/src/pipelines/index.ts +4 -0
- package/libs/core/src/pipelines/list.ts +12 -0
- package/libs/core/src/pipelines/runs.ts +53 -0
- package/libs/core/tsconfig.json +20 -0
- package/libs/core/vite.config.ts +56 -0
- package/libs/dal/.prettierignore +6 -0
- package/libs/dal/.prettierrc.js +12 -0
- package/libs/dal/eslint.config.mjs +3 -0
- package/libs/dal/package.json +57 -0
- package/libs/dal/src/_tests/db.test.ts +19 -0
- package/libs/dal/src/_tests/mock-db.ts +60 -0
- package/libs/dal/src/api-key.test.ts +397 -0
- package/libs/dal/src/api-key.ts +110 -0
- package/libs/dal/src/billing.ts +23 -0
- package/libs/dal/src/conversation.test.ts +655 -0
- package/libs/dal/src/conversation.ts +532 -0
- package/libs/dal/src/deal.test.ts +45 -0
- package/libs/dal/src/deal.ts +87 -0
- package/libs/dal/src/defaults-consumer-lending-uk.ts +33 -0
- package/libs/dal/src/defaults-consumer-lending-us.ts +33 -0
- package/libs/dal/src/defaults-private-credit.ts +57 -0
- package/libs/dal/src/defaults-private-equity.ts +51 -0
- package/libs/dal/src/defaults-smb-lending-us.ts +1569 -0
- package/libs/dal/src/defaults-sme-lending-uk-express.ts +1527 -0
- package/libs/dal/src/defaults-sme-lending-uk.ts +1669 -0
- package/libs/dal/src/defaults-types.ts +23 -0
- package/libs/dal/src/defaults.ts +550 -0
- package/libs/dal/src/document.test.ts +70 -0
- package/libs/dal/src/document.ts +192 -0
- package/libs/dal/src/feedback.ts +255 -0
- package/libs/dal/src/form.test.ts +637 -0
- package/libs/dal/src/form.ts +1165 -0
- package/libs/dal/src/index.ts +20 -0
- package/libs/dal/src/invitation.test.ts +746 -0
- package/libs/dal/src/invitation.ts +207 -0
- package/libs/dal/src/member.test.ts +185 -0
- package/libs/dal/src/member.ts +80 -0
- package/libs/dal/src/organization.ts +116 -0
- package/libs/dal/src/permission.ts +25 -0
- package/libs/dal/src/pipeline.test.ts +388 -0
- package/libs/dal/src/pipeline.ts +4222 -0
- package/libs/dal/src/report.ts +199 -0
- package/libs/dal/src/result.ts +16 -0
- package/libs/dal/src/search.ts +172 -0
- package/libs/dal/src/session.test.ts +110 -0
- package/libs/dal/src/session.ts +31 -0
- package/libs/dal/src/submission.test.ts +1304 -0
- package/libs/dal/src/submission.ts +1396 -0
- package/libs/dal/src/tool.ts +159 -0
- package/libs/dal/src/user.ts +16 -0
- package/libs/dal/src/workflow.test.ts +89 -0
- package/libs/dal/src/workflow.ts +262 -0
- package/libs/dal/tsconfig.build.json +4 -0
- package/libs/dal/tsconfig.json +22 -0
- package/libs/dal/vite.config.ts +34 -0
- package/libs/db/.prettierignore +6 -0
- package/libs/db/.prettierrc.js +12 -0
- package/libs/db/eslint.config.mjs +3 -0
- package/libs/db/package.json +52 -0
- package/libs/db/src/index.ts +24 -0
- package/libs/db/src/relations.ts +549 -0
- package/libs/db/src/schema.ts +2 -0
- package/libs/db/src/schemas/api.ts +35 -0
- package/libs/db/src/schemas/conversations.ts +175 -0
- package/libs/db/src/schemas/core.ts +359 -0
- package/libs/db/src/schemas/documents.ts +181 -0
- package/libs/db/src/schemas/feedback.ts +40 -0
- package/libs/db/src/schemas/index.ts +26 -0
- package/libs/db/src/schemas/organisations.ts +97 -0
- package/libs/db/src/schemas/pipelines.ts +440 -0
- package/libs/db/src/schemas/users.ts +95 -0
- package/libs/db/src/types.ts +190 -0
- package/libs/db/src/utils.ts +14 -0
- package/libs/db/tsconfig.json +19 -0
- package/libs/db/vite.config.ts +31 -0
- package/libs/lint/.prettierignore +6 -0
- package/libs/lint/eslint.config.mjs +61 -0
- package/libs/lint/package.json +29 -0
- package/libs/lint/prettier.config.js +12 -0
- package/libs/schemas/.prettierignore +6 -0
- package/libs/schemas/.prettierrc.js +12 -0
- package/libs/schemas/README.md +15 -0
- package/libs/schemas/eslint.config.mjs +3 -0
- package/libs/schemas/package.json +67 -0
- package/libs/schemas/src/core/chat.ts +67 -0
- package/libs/schemas/src/core/core-result.ts +15 -0
- package/libs/schemas/src/core/data-extraction.ts +184 -0
- package/libs/schemas/src/core/layout.ts +478 -0
- package/libs/schemas/src/core/pipeline.ts +128 -0
- package/libs/schemas/src/core/submission.ts +97 -0
- package/libs/schemas/src/db/account.ts +57 -0
- package/libs/schemas/src/db/apiKey.ts +57 -0
- package/libs/schemas/src/db/context.ts +33 -0
- package/libs/schemas/src/db/conversation.ts +65 -0
- package/libs/schemas/src/db/deal.ts +42 -0
- package/libs/schemas/src/db/document.ts +103 -0
- package/libs/schemas/src/db/documentCitation.ts +58 -0
- package/libs/schemas/src/db/documentExtraction.ts +69 -0
- package/libs/schemas/src/db/fieldCorrection.ts +85 -0
- package/libs/schemas/src/db/form.ts +45 -0
- package/libs/schemas/src/db/formField.ts +59 -0
- package/libs/schemas/src/db/formGroup.ts +42 -0
- package/libs/schemas/src/db/impersonation.ts +39 -0
- package/libs/schemas/src/db/index.ts +25 -0
- package/libs/schemas/src/db/invitation.ts +42 -0
- package/libs/schemas/src/db/member.ts +36 -0
- package/libs/schemas/src/db/message.ts +58 -0
- package/libs/schemas/src/db/organization.ts +62 -0
- package/libs/schemas/src/db/session.ts +48 -0
- package/libs/schemas/src/db/submission.ts +54 -0
- package/libs/schemas/src/db/submissionGroup.ts +36 -0
- package/libs/schemas/src/db/submissionItem.ts +33 -0
- package/libs/schemas/src/db/submissionItemVersion.ts +70 -0
- package/libs/schemas/src/db/user.ts +51 -0
- package/libs/schemas/src/db/utils.ts +3 -0
- package/libs/schemas/src/db/verification.ts +36 -0
- package/libs/schemas/src/db/workflow.ts +42 -0
- package/libs/schemas/src/index.ts +10 -0
- package/libs/schemas/tsconfig.json +21 -0
- package/libs/schemas/vite.config.ts +38 -0
- package/libs/ui/.prettierignore +6 -0
- package/libs/ui/.prettierrc.js +12 -0
- package/libs/ui/components.json +24 -0
- package/libs/ui/eslint.config.mjs +3 -0
- package/libs/ui/package.json +142 -0
- package/libs/ui/src/components/chart-viz/chart.tsx +255 -0
- package/libs/ui/src/components/chart-viz/converters.ts +474 -0
- package/libs/ui/src/components/chart-viz/dashboard.tsx +146 -0
- package/libs/ui/src/components/chart-viz/index.ts +37 -0
- package/libs/ui/src/components/chart-viz/markdown.tsx +344 -0
- package/libs/ui/src/components/chart-viz/table.tsx +446 -0
- package/libs/ui/src/components/chart-viz/theme-context.tsx +70 -0
- package/libs/ui/src/components/chart-viz/themes/dark.ts +98 -0
- package/libs/ui/src/components/chart-viz/themes/index.ts +69 -0
- package/libs/ui/src/components/chart-viz/themes/light.ts +98 -0
- package/libs/ui/src/components/chart-viz/themes/tailwind.ts +326 -0
- package/libs/ui/src/components/chart-viz/themes/types.ts +99 -0
- package/libs/ui/src/components/chart-viz/tool-display.tsx +150 -0
- package/libs/ui/src/components/chart-viz/types.ts +95 -0
- package/libs/ui/src/components/doc-viewers/excel/index.tsx +431 -0
- package/libs/ui/src/components/doc-viewers/excel/themes.ts +160 -0
- package/libs/ui/src/components/doc-viewers/image/index.tsx +410 -0
- package/libs/ui/src/components/doc-viewers/pdf/index.tsx +258 -0
- package/libs/ui/src/components/doc-viewers/pdf/virtualized-pdf.tsx +556 -0
- package/libs/ui/src/components/misc/rel-date.tsx +52 -0
- package/libs/ui/src/components/misc/styled-link.tsx +2 -0
- package/libs/ui/src/components/table/data-table.tsx +546 -0
- package/libs/ui/src/components/table/report-table.tsx +305 -0
- package/libs/ui/src/components/table/sortable-column.tsx +34 -0
- package/libs/ui/src/components/ui/accordion.tsx +62 -0
- package/libs/ui/src/components/ui/alert-dialog.tsx +142 -0
- package/libs/ui/src/components/ui/alert.tsx +62 -0
- package/libs/ui/src/components/ui/artifact.tsx +118 -0
- package/libs/ui/src/components/ui/attachments.tsx +388 -0
- package/libs/ui/src/components/ui/avatar.tsx +39 -0
- package/libs/ui/src/components/ui/badge.tsx +43 -0
- package/libs/ui/src/components/ui/breadcrumb.tsx +102 -0
- package/libs/ui/src/components/ui/button-group.tsx +78 -0
- package/libs/ui/src/components/ui/button.tsx +79 -0
- package/libs/ui/src/components/ui/card.tsx +32 -0
- package/libs/ui/src/components/ui/carousel.tsx +228 -0
- package/libs/ui/src/components/ui/chain-of-thought.tsx +198 -0
- package/libs/ui/src/components/ui/checkbox.tsx +27 -0
- package/libs/ui/src/components/ui/citation.tsx +34 -0
- package/libs/ui/src/components/ui/code-block.tsx +500 -0
- package/libs/ui/src/components/ui/collapsible.tsx +19 -0
- package/libs/ui/src/components/ui/command.tsx +161 -0
- package/libs/ui/src/components/ui/conversation.tsx +90 -0
- package/libs/ui/src/components/ui/dialog.tsx +142 -0
- package/libs/ui/src/components/ui/dropdown-menu.tsx +246 -0
- package/libs/ui/src/components/ui/highlight.tsx +3 -0
- package/libs/ui/src/components/ui/hover-card.tsx +36 -0
- package/libs/ui/src/components/ui/inline-citation.tsx +251 -0
- package/libs/ui/src/components/ui/input-group.tsx +156 -0
- package/libs/ui/src/components/ui/input-otp.tsx +78 -0
- package/libs/ui/src/components/ui/input.tsx +21 -0
- package/libs/ui/src/components/ui/label.tsx +19 -0
- package/libs/ui/src/components/ui/model-selector.tsx +174 -0
- package/libs/ui/src/components/ui/multisidebar.tsx +750 -0
- package/libs/ui/src/components/ui/popover.tsx +43 -0
- package/libs/ui/src/components/ui/progress.tsx +28 -0
- package/libs/ui/src/components/ui/reasoning.tsx +178 -0
- package/libs/ui/src/components/ui/resizable.tsx +49 -0
- package/libs/ui/src/components/ui/scroll-area.tsx +54 -0
- package/libs/ui/src/components/ui/select.tsx +171 -0
- package/libs/ui/src/components/ui/separator.tsx +26 -0
- package/libs/ui/src/components/ui/sheet.tsx +128 -0
- package/libs/ui/src/components/ui/shimmer.tsx +53 -0
- package/libs/ui/src/components/ui/skeleton.tsx +13 -0
- package/libs/ui/src/components/ui/sonner.tsx +23 -0
- package/libs/ui/src/components/ui/switch.tsx +26 -0
- package/libs/ui/src/components/ui/table.tsx +96 -0
- package/libs/ui/src/components/ui/tabs.tsx +52 -0
- package/libs/ui/src/components/ui/textarea.tsx +41 -0
- package/libs/ui/src/components/ui/tool.tsx +209 -0
- package/libs/ui/src/components/ui/tooltip.tsx +58 -0
- package/libs/ui/src/components/ui/typography.tsx +113 -0
- package/libs/ui/src/fonts/manrope-v15-latin-300.woff2 +0 -0
- package/libs/ui/src/fonts/manrope-v15-latin-400.woff2 +0 -0
- package/libs/ui/src/fonts/manrope-v15-latin-500.woff2 +0 -0
- package/libs/ui/src/fonts/manrope-v15-latin-600.woff2 +0 -0
- package/libs/ui/src/hooks/use-mobile.ts +19 -0
- package/libs/ui/src/lib/utils.ts +6 -0
- package/libs/ui/src/styles/fonts.css +35 -0
- package/libs/ui/src/styles/style.css +218 -0
- package/libs/ui/tsconfig.json +21 -0
- package/libs/ui/vite.config.ts +80 -0
- package/libs/ui-lit/README.md +245 -0
- package/libs/ui-lit/TESTING_GUIDE.md +296 -0
- package/libs/ui-lit/eslint.config.mjs +3 -0
- package/libs/ui-lit/package.json +41 -0
- package/libs/ui-lit/scripts/build-css.js +43 -0
- package/libs/ui-lit/src/components/sea-alert.ts +132 -0
- package/libs/ui-lit/src/components/sea-button.ts +95 -0
- package/libs/ui-lit/src/components/sea-card.ts +113 -0
- package/libs/ui-lit/src/components/sea-input.ts +184 -0
- package/libs/ui-lit/src/components/sea-spinner.ts +65 -0
- package/libs/ui-lit/src/index.ts +15 -0
- package/libs/ui-lit/src/lib/utils.ts +6 -0
- package/libs/ui-lit/src/styles/tailwind.css +76 -0
- package/libs/ui-lit/src/theme.css +66 -0
- package/libs/ui-lit/src/theme.ts +79 -0
- package/libs/ui-lit/src/vite-env.d.ts +6 -0
- package/libs/ui-lit/tailwind.config.ts +50 -0
- package/libs/ui-lit/test.html +289 -0
- package/libs/ui-lit/tsconfig.json +23 -0
- package/libs/ui-lit/vite.config.ts +31 -0
- package/libs/ui-lit/vite.css.config.ts +20 -0
- package/libs/util/.prettierignore +6 -0
- package/libs/util/.prettierrc.js +12 -0
- package/libs/util/eslint.config.mjs +3 -0
- package/libs/util/package.json +45 -0
- package/libs/util/src/billing.ts +10 -0
- package/libs/util/src/data-transform.ts +19 -0
- package/libs/util/src/encryption.ts +45 -0
- package/libs/util/src/fmt.test.ts +9 -0
- package/libs/util/src/fmt.ts +71 -0
- package/libs/util/src/fuzzy.ts +47 -0
- package/libs/util/src/id.ts +24 -0
- package/libs/util/src/invariant.ts +31 -0
- package/libs/util/src/sub-name.ts +7 -0
- package/libs/util/tsconfig.json +19 -0
- package/libs/util/vite.config.ts +34 -0
- package/package.json +28 -0
- package/packages/widget/.prettierignore +6 -0
- package/packages/widget/.prettierrc.js +12 -0
- package/packages/widget/README.md +95 -0
- package/packages/widget/eslint.config.mjs +11 -0
- package/packages/widget/openapi-ts.config.ts +8 -0
- package/packages/widget/package.json +89 -0
- package/packages/widget/postcss.config.mjs +10 -0
- package/packages/widget/src/clients/api/client/client.ts +187 -0
- package/packages/widget/src/clients/api/client/index.ts +22 -0
- package/packages/widget/src/clients/api/client/types.ts +192 -0
- package/packages/widget/src/clients/api/client/utils.ts +394 -0
- package/packages/widget/src/clients/api/client.gen.ts +18 -0
- package/packages/widget/src/clients/api/core/auth.ts +39 -0
- package/packages/widget/src/clients/api/core/bodySerializer.ts +74 -0
- package/packages/widget/src/clients/api/core/params.ts +132 -0
- package/packages/widget/src/clients/api/core/pathSerializer.ts +169 -0
- package/packages/widget/src/clients/api/core/types.ts +80 -0
- package/packages/widget/src/clients/api/index.ts +3 -0
- package/packages/widget/src/clients/api/sdk.gen.ts +805 -0
- package/packages/widget/src/clients/api/types.gen.ts +2085 -0
- package/packages/widget/src/components/container.tsx +42 -0
- package/packages/widget/src/components/data-display.tsx +384 -0
- package/packages/widget/src/components/data-viewer.tsx +311 -0
- package/packages/widget/src/components/doc-list.tsx +102 -0
- package/packages/widget/src/components/field-correction-modal.tsx +265 -0
- package/packages/widget/src/components/header.tsx +71 -0
- package/packages/widget/src/components/new-submission.tsx +290 -0
- package/packages/widget/src/components/sidebar-right.tsx +19 -0
- package/packages/widget/src/components/submission-card.tsx +66 -0
- package/packages/widget/src/components/submission-page.tsx +75 -0
- package/packages/widget/src/components/upload-doc.tsx +241 -0
- package/packages/widget/src/components/widget.tsx +101 -0
- package/packages/widget/src/index.tsx +167 -0
- package/packages/widget/src/lib/config.ts +2 -0
- package/packages/widget/src/lib/util.ts +40 -0
- package/packages/widget/src/styles/index.css +5 -0
- package/packages/widget/src/styles/tw-properties.css +337 -0
- package/packages/widget/src/vite-env.d.ts +3 -0
- package/packages/widget/tsconfig.app.json +35 -0
- package/packages/widget/tsconfig.json +4 -0
- package/packages/widget/tsconfig.node.json +24 -0
- package/packages/widget/vite.config.ts +116 -0
- package/packages/widget-lit/BOTTLENECKS.md +250 -0
- package/packages/widget-lit/IMPLEMENTATION_SUMMARY.md +295 -0
- package/packages/widget-lit/README.md +232 -0
- package/packages/widget-lit/eslint.config.mjs +3 -0
- package/packages/widget-lit/package.json +52 -0
- package/packages/widget-lit/src/api-client.ts +230 -0
- package/packages/widget-lit/src/api-client.ts.backup +218 -0
- package/packages/widget-lit/src/components/sea-chat.ts +382 -0
- package/packages/widget-lit/src/components/sea-submission-viewer.ts +267 -0
- package/packages/widget-lit/src/components/sea-widget.ts +317 -0
- package/packages/widget-lit/src/index.ts +48 -0
- package/packages/widget-lit/src/react.ts +58 -0
- package/packages/widget-lit/src/style.css +47 -0
- package/packages/widget-lit/tsconfig.json +24 -0
- package/packages/widget-lit/vite.config.ts +29 -0
- package/packages/widget-ng/DEVELOPMENT.md +74 -0
- package/packages/widget-ng/README.md +657 -0
- package/packages/widget-ng/dev.sh +14 -0
- package/packages/widget-ng/eslint.config.mjs +24 -0
- package/packages/widget-ng/ng-package.json +9 -0
- package/packages/widget-ng/package.json +85 -0
- package/packages/widget-ng/src/index.ts +45 -0
- package/packages/widget-ng/src/lib/components/sea-chat.component.ts +737 -0
- package/packages/widget-ng/src/lib/components/sea-data-viewer.component.ts +2240 -0
- package/packages/widget-ng/src/lib/components/sea-deal-form-modal.component.ts +702 -0
- package/packages/widget-ng/src/lib/components/sea-document-list.component.ts +350 -0
- package/packages/widget-ng/src/lib/components/sea-feedback-modal.component.ts +461 -0
- package/packages/widget-ng/src/lib/components/sea-file-upload.component.ts +655 -0
- package/packages/widget-ng/src/lib/components/sea-model-selection-modal.component.ts +367 -0
- package/packages/widget-ng/src/lib/components/sea-new-submission-modal.component.ts +414 -0
- package/packages/widget-ng/src/lib/components/sea-pdf-viewer.component.ts +869 -0
- package/packages/widget-ng/src/lib/components/sea-submission-card.component.ts +251 -0
- package/packages/widget-ng/src/lib/components/sea-widget.component.ts +684 -0
- package/packages/widget-ng/src/lib/models/submission.model.ts +170 -0
- package/packages/widget-ng/src/lib/pipes/markdown.pipe.ts +57 -0
- package/packages/widget-ng/src/lib/services/api-client.service.ts +715 -0
- package/packages/widget-ng/src/lib/services/chat.service.ts +330 -0
- package/packages/widget-ng/src/lib/services/config.service.ts +107 -0
- package/packages/widget-ng/src/web-component.ts +56 -0
- package/packages/widget-ng/tsconfig.json +25 -0
- package/packages/widget-ng/tsconfig.lib.json +9 -0
- package/packages/widget-ng/vite.config.elements.ts +26 -0
- package/packages/widget-ng/vitest.config.ts +19 -0
- package/packages/widget-ng/vitest.setup.ts +13 -0
- package/pnpm-workspace.yaml +18 -0
- package/render.yaml +136 -0
- package/scripts/README.md +57 -0
- package/scripts/package.json +22 -0
- package/scripts/python/.python-version +1 -0
- package/scripts/python/README.md +3 -0
- package/scripts/python/export-org-data.py +693 -0
- package/scripts/python/pyproject.toml +29 -0
- package/scripts/python/requirements-dev.lock +36 -0
- package/scripts/python/requirements.lock +36 -0
- package/scripts/python/src/gen.py +297 -0
- package/scripts/python/test.py +34 -0
- package/scripts/src/fix-storage-provider-mismatch.ts +239 -0
- package/scripts/src/sync-render-yaml.ts +290 -0
- package/scripts/src/test-chat-stream.ts +300 -0
- package/scripts/src/test-reconciliation.ts +230 -0
- package/scripts/tsconfig.json +15 -0
- package/tests/angular-test-app/.vscode/extensions.json +4 -0
- package/tests/angular-test-app/.vscode/launch.json +13 -0
- package/tests/angular-test-app/.vscode/tasks.json +24 -0
- package/tests/angular-test-app/README.md +59 -0
- package/tests/angular-test-app/angular.json +111 -0
- package/tests/angular-test-app/clean-start.sh +14 -0
- package/tests/angular-test-app/package.json +36 -0
- package/tests/angular-test-app/public/favicon.ico +0 -0
- package/tests/angular-test-app/src/app/app.component.ts +220 -0
- package/tests/angular-test-app/src/app/app.config.ts +5 -0
- package/tests/angular-test-app/src/env.d.ts +13 -0
- package/tests/angular-test-app/src/index.html +13 -0
- package/tests/angular-test-app/src/main.ts +6 -0
- package/tests/angular-test-app/src/styles.css +8 -0
- package/tests/angular-test-app/tsconfig.app.json +15 -0
- package/tests/angular-test-app/tsconfig.json +27 -0
- package/tests/crm-viewer-app/API_INTEGRATION_SUMMARY.md +295 -0
- package/tests/crm-viewer-app/CURRENT_ASSETS_FIELDS.md +148 -0
- package/tests/crm-viewer-app/FIELD_ID_MAPPING.md +206 -0
- package/tests/crm-viewer-app/INTEGRATION_GUIDE.md +309 -0
- package/tests/crm-viewer-app/README.md +174 -0
- package/tests/crm-viewer-app/REAL_API_INTEGRATION.md +240 -0
- package/tests/crm-viewer-app/UPDATED_IMPLEMENTATION.md +279 -0
- package/tests/crm-viewer-app/angular.json +114 -0
- package/tests/crm-viewer-app/package.json +35 -0
- package/tests/crm-viewer-app/src/app/app.component.ts +534 -0
- package/tests/crm-viewer-app/src/app/citation.service.ts +316 -0
- package/tests/crm-viewer-app/src/env.d.ts +16 -0
- package/tests/crm-viewer-app/src/index.html +19 -0
- package/tests/crm-viewer-app/src/main.ts +7 -0
- package/tests/crm-viewer-app/src/styles.css +409 -0
- package/tests/crm-viewer-app/src/template.html +2678 -0
- package/tests/crm-viewer-app/tsconfig.app.json +15 -0
- package/tests/crm-viewer-app/tsconfig.json +27 -0
- package/tests/e2e/package.json +17 -0
- package/tests/e2e/playwright.config.ts +75 -0
- package/tests/e2e/tests/api/health.spec.ts +10 -0
- package/tests/e2e/tests/app/example.spec.ts +10 -0
- package/tests/widget-test-app/.prettierignore +6 -0
- package/tests/widget-test-app/README.md +48 -0
- package/tests/widget-test-app/index.html +12 -0
- package/tests/widget-test-app/package.json +24 -0
- package/tests/widget-test-app/src/App.css +192 -0
- package/tests/widget-test-app/src/App.tsx +80 -0
- package/tests/widget-test-app/src/main.tsx +9 -0
- package/tests/widget-test-app/src/vite-env.d.ts +4 -0
- package/tests/widget-test-app/tsconfig.json +25 -0
- package/tests/widget-test-app/tsconfig.node.json +11 -0
- package/tests/widget-test-app/vite.config.ts +14 -0
|
@@ -0,0 +1,1393 @@
|
|
|
1
|
+
import { getWorkerConfig } from "@/lib/config";
|
|
2
|
+
import { createLanguageModel } from "@sea/ai/models";
|
|
3
|
+
import { HatchetClientMgr } from "@sea/clients/hatchet";
|
|
4
|
+
import { createPipelineArtifact } from "@sea/core";
|
|
5
|
+
import { addAdditionalPropertiesToJsonSchema } from "@sea/core/data-extraction/structuring/custom";
|
|
6
|
+
import { getForm } from "@sea/dal/form";
|
|
7
|
+
import {
|
|
8
|
+
createPipelineRunStep,
|
|
9
|
+
getGroupForStepRun,
|
|
10
|
+
getParentStepRuns,
|
|
11
|
+
getParentStepRunsWithDependencies,
|
|
12
|
+
getPipelineStepById,
|
|
13
|
+
getStepDocuments,
|
|
14
|
+
getStepIntegrationConfig,
|
|
15
|
+
getSubmissionGroups,
|
|
16
|
+
logRequestCall,
|
|
17
|
+
resolveStepBlockersOnCompletion,
|
|
18
|
+
storePipelineOutputData,
|
|
19
|
+
updatePipelineRunStepStatus,
|
|
20
|
+
} from "@sea/dal/pipeline";
|
|
21
|
+
import type { DenormGroup, DenormSubmission, DenormTable } from "@sea/dal/submission";
|
|
22
|
+
import {
|
|
23
|
+
createSubmissionWithConversation,
|
|
24
|
+
getDenormSubmission,
|
|
25
|
+
getDenormSubmissions,
|
|
26
|
+
syncSubmissionToForm,
|
|
27
|
+
} from "@sea/dal/submission";
|
|
28
|
+
import { db, PIPELINE_RUN_STEP_STATUS, schema } from "@sea/db";
|
|
29
|
+
import type { FormGroupHydrated, FormWithGroups, Member } from "@sea/db/types";
|
|
30
|
+
import { invariant } from "@sea/util/invariant";
|
|
31
|
+
import type { LanguageModel } from "ai";
|
|
32
|
+
import { jsonSchema, Output, stepCountIs, ToolLoopAgent, zodSchema, type JSONSchema7 } from "ai";
|
|
33
|
+
import { and, eq, inArray } from "drizzle-orm";
|
|
34
|
+
import pLimit from "p-limit";
|
|
35
|
+
import * as z from "zod/v4";
|
|
36
|
+
import { extractDataUnified } from "./extraction";
|
|
37
|
+
|
|
38
|
+
const config = getWorkerConfig();
|
|
39
|
+
const hatchet = new HatchetClientMgr(config.hatchet).getHatchet();
|
|
40
|
+
|
|
41
|
+
// ============================================================================
|
|
42
|
+
// Input/Output Types
|
|
43
|
+
// ============================================================================
|
|
44
|
+
|
|
45
|
+
// Use type instead of interface to allow index signature
|
|
46
|
+
export type StepExecutionInput = {
|
|
47
|
+
memberId: string;
|
|
48
|
+
runId: string;
|
|
49
|
+
runStepId: string;
|
|
50
|
+
stepId: string;
|
|
51
|
+
[key: string]: string; // Index signature for JsonObject compatibility
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
export type StepExecutionOutput = {
|
|
55
|
+
status: string;
|
|
56
|
+
outputSubmissionId?: string;
|
|
57
|
+
error?: string;
|
|
58
|
+
[key: string]: string | undefined; // Index signature for JsonObject compatibility
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
// ============================================================================
|
|
62
|
+
// Template Step Workflow - Spawns Multiple Instances
|
|
63
|
+
// ============================================================================
|
|
64
|
+
|
|
65
|
+
export type TemplateStepInput = StepExecutionInput & {
|
|
66
|
+
stepRole: "extraction" | "integration" | "analysis" | "manual";
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
export const templateStepWorkflow = hatchet.workflow<TemplateStepInput>({
|
|
70
|
+
name: "template-step",
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
// ============================================================================
|
|
74
|
+
// Helper Functions
|
|
75
|
+
// ============================================================================
|
|
76
|
+
|
|
77
|
+
function serializeGroup(group: DenormGroup): string {
|
|
78
|
+
const htmlParts: string[] = [];
|
|
79
|
+
htmlParts.push(`<h2>${group.name}</h2>`);
|
|
80
|
+
htmlParts.push("<dl>");
|
|
81
|
+
|
|
82
|
+
for (const item of group.items) {
|
|
83
|
+
htmlParts.push(`<dt>${item.name}</dt>`);
|
|
84
|
+
htmlParts.push(`<dd id="${item.id}">${String(item.value ?? "")}</dd>`);
|
|
85
|
+
}
|
|
86
|
+
for (const derived of group.derived) {
|
|
87
|
+
htmlParts.push(`<dt>${derived.name} (derived)</dt>`);
|
|
88
|
+
htmlParts.push(`<dd id="${derived.id}">${String(derived.value ?? "")}</dd>`);
|
|
89
|
+
}
|
|
90
|
+
htmlParts.push("</dl>");
|
|
91
|
+
|
|
92
|
+
return htmlParts.join("\n");
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function serializeTable(table: DenormTable): string {
|
|
96
|
+
const htmlParts: string[] = [];
|
|
97
|
+
|
|
98
|
+
htmlParts.push(`<h2>${table.name}</h2>`);
|
|
99
|
+
htmlParts.push("<table>");
|
|
100
|
+
|
|
101
|
+
// Table header
|
|
102
|
+
htmlParts.push("<thead><tr>");
|
|
103
|
+
for (const col of table.columns) {
|
|
104
|
+
htmlParts.push(`<th>${col}</th>`);
|
|
105
|
+
}
|
|
106
|
+
htmlParts.push("</tr></thead>");
|
|
107
|
+
|
|
108
|
+
// Table body
|
|
109
|
+
htmlParts.push("<tbody>");
|
|
110
|
+
for (const row of table.rows) {
|
|
111
|
+
htmlParts.push("<tr>");
|
|
112
|
+
|
|
113
|
+
// Regular items
|
|
114
|
+
for (const item of row.items) {
|
|
115
|
+
htmlParts.push(`<td id="${item.id}">${String(item.value ?? "")}</td>`);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Derived items
|
|
119
|
+
for (const derived of row.derived) {
|
|
120
|
+
htmlParts.push(`<td id="${derived.id}">${String(derived.value ?? "")}</td>`);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
htmlParts.push("</tr>");
|
|
124
|
+
}
|
|
125
|
+
htmlParts.push("</tbody>");
|
|
126
|
+
htmlParts.push("</table>");
|
|
127
|
+
|
|
128
|
+
return htmlParts.join("\n");
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Serialize submission to HTML for LLM consumption
|
|
133
|
+
*/
|
|
134
|
+
function serializeSubmission(submission: DenormSubmission): string {
|
|
135
|
+
const htmlParts: string[] = [];
|
|
136
|
+
|
|
137
|
+
// Add submission header
|
|
138
|
+
htmlParts.push(`<section>`);
|
|
139
|
+
htmlParts.push(`<h1>${submission.formName}</h1>`);
|
|
140
|
+
if (submission.name) {
|
|
141
|
+
htmlParts.push(`<p><strong>Submission:</strong> ${submission.name}</p>`);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Serialize single groups (definition lists)
|
|
145
|
+
for (const group of submission.groups) {
|
|
146
|
+
htmlParts.push(serializeGroup(group));
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Serialize tables (multi groups)
|
|
150
|
+
for (const table of submission.tables) {
|
|
151
|
+
htmlParts.push(serializeTable(table));
|
|
152
|
+
}
|
|
153
|
+
htmlParts.push("</section>");
|
|
154
|
+
|
|
155
|
+
return htmlParts.join("\n");
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Build extraction schema for a group with reasoning field for pipeline analysis
|
|
160
|
+
*/
|
|
161
|
+
function buildAnalysisSchemaFromGroup(
|
|
162
|
+
group: FormGroupHydrated,
|
|
163
|
+
): z.ZodObject<Record<string, z.ZodType>> {
|
|
164
|
+
const groupFields: Record<string, z.ZodType> = {};
|
|
165
|
+
|
|
166
|
+
for (const field of group.fields) {
|
|
167
|
+
switch (field.type) {
|
|
168
|
+
case "string":
|
|
169
|
+
case "string-long":
|
|
170
|
+
groupFields[field.name] = z
|
|
171
|
+
.object({
|
|
172
|
+
value: z.string(),
|
|
173
|
+
refId: z.string(),
|
|
174
|
+
reasoning: z
|
|
175
|
+
.string()
|
|
176
|
+
.describe("Explanation of how this value was derived from the input data"),
|
|
177
|
+
})
|
|
178
|
+
.nullable()
|
|
179
|
+
.describe(field.hint);
|
|
180
|
+
break;
|
|
181
|
+
case "number":
|
|
182
|
+
case "money":
|
|
183
|
+
groupFields[field.name] = z
|
|
184
|
+
.object({
|
|
185
|
+
value: z.number(),
|
|
186
|
+
refId: z.string(),
|
|
187
|
+
reasoning: z
|
|
188
|
+
.string()
|
|
189
|
+
.describe("Explanation of how this value was derived from the input data"),
|
|
190
|
+
})
|
|
191
|
+
.nullable()
|
|
192
|
+
.describe(field.hint);
|
|
193
|
+
break;
|
|
194
|
+
case "boolean":
|
|
195
|
+
groupFields[field.name] = z
|
|
196
|
+
.object({
|
|
197
|
+
value: z.boolean(),
|
|
198
|
+
refId: z.string(),
|
|
199
|
+
reasoning: z
|
|
200
|
+
.string()
|
|
201
|
+
.describe("Explanation of how this value was derived from the input data"),
|
|
202
|
+
})
|
|
203
|
+
.nullable()
|
|
204
|
+
.describe(field.hint);
|
|
205
|
+
break;
|
|
206
|
+
case "date":
|
|
207
|
+
groupFields[field.name] = z
|
|
208
|
+
.object({
|
|
209
|
+
value: z.iso.date(),
|
|
210
|
+
refId: z.string(),
|
|
211
|
+
reasoning: z
|
|
212
|
+
.string()
|
|
213
|
+
.describe("Explanation of how this value was derived from the input data"),
|
|
214
|
+
})
|
|
215
|
+
.nullable()
|
|
216
|
+
.describe(field.hint);
|
|
217
|
+
break;
|
|
218
|
+
case "email":
|
|
219
|
+
groupFields[field.name] = z
|
|
220
|
+
.object({
|
|
221
|
+
value: z.email(),
|
|
222
|
+
refId: z.string(),
|
|
223
|
+
reasoning: z
|
|
224
|
+
.string()
|
|
225
|
+
.describe("Explanation of how this value was derived from the input data"),
|
|
226
|
+
})
|
|
227
|
+
.nullable()
|
|
228
|
+
.describe(field.hint);
|
|
229
|
+
break;
|
|
230
|
+
case "url":
|
|
231
|
+
groupFields[field.name] = z
|
|
232
|
+
.object({
|
|
233
|
+
value: z.string().describe("Valid URL"),
|
|
234
|
+
refId: z.string(),
|
|
235
|
+
reasoning: z
|
|
236
|
+
.string()
|
|
237
|
+
.describe("Explanation of how this value was derived from the input data"),
|
|
238
|
+
})
|
|
239
|
+
.nullable()
|
|
240
|
+
.describe(field.hint);
|
|
241
|
+
break;
|
|
242
|
+
case "enum":
|
|
243
|
+
if (field.options && field.options.length > 0) {
|
|
244
|
+
groupFields[field.name] = z
|
|
245
|
+
.object({
|
|
246
|
+
value: z.enum(field.options as [string, ...string[]]),
|
|
247
|
+
refId: z.string(),
|
|
248
|
+
reasoning: z
|
|
249
|
+
.string()
|
|
250
|
+
.describe("Explanation of how this value was derived from the input data"),
|
|
251
|
+
})
|
|
252
|
+
.nullable()
|
|
253
|
+
.describe(`${field.hint}. Must be one of: ${field.options.join(", ")}`);
|
|
254
|
+
} else {
|
|
255
|
+
groupFields[field.name] = z
|
|
256
|
+
.object({
|
|
257
|
+
value: z.string(),
|
|
258
|
+
refId: z.string(),
|
|
259
|
+
reasoning: z
|
|
260
|
+
.string()
|
|
261
|
+
.describe("Explanation of how this value was derived from the input data"),
|
|
262
|
+
})
|
|
263
|
+
.nullable()
|
|
264
|
+
.describe(field.hint);
|
|
265
|
+
}
|
|
266
|
+
break;
|
|
267
|
+
default:
|
|
268
|
+
groupFields[field.name] = z
|
|
269
|
+
.object({
|
|
270
|
+
value: z.unknown(),
|
|
271
|
+
refId: z.string(),
|
|
272
|
+
reasoning: z
|
|
273
|
+
.string()
|
|
274
|
+
.describe("Explanation of how this value was derived from the input data"),
|
|
275
|
+
})
|
|
276
|
+
.nullable()
|
|
277
|
+
.describe(field.hint);
|
|
278
|
+
break;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
return group.multi
|
|
283
|
+
? z.object({
|
|
284
|
+
[group.name]: z.array(z.object(groupFields)),
|
|
285
|
+
})
|
|
286
|
+
: z.object({
|
|
287
|
+
[group.name]: z.object(groupFields),
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* Build response schema from output form groups for pipeline analysis
|
|
293
|
+
*/
|
|
294
|
+
function buildStepResponseSchema(outputFormGroups: FormGroupHydrated[]) {
|
|
295
|
+
const extractionSchema = outputFormGroups.reduce((acc, group) => {
|
|
296
|
+
const groupSchema = buildAnalysisSchemaFromGroup(group);
|
|
297
|
+
return z.object({
|
|
298
|
+
...acc.shape,
|
|
299
|
+
...groupSchema.shape,
|
|
300
|
+
});
|
|
301
|
+
}, z.object({}));
|
|
302
|
+
|
|
303
|
+
return z.object({
|
|
304
|
+
reasoning: z.string().nullable(),
|
|
305
|
+
data: extractionSchema.nullable(),
|
|
306
|
+
});
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* Build HTTP request from integration config template
|
|
311
|
+
*/
|
|
312
|
+
async function buildHttpRequest({
|
|
313
|
+
config: reqConfig,
|
|
314
|
+
parentData,
|
|
315
|
+
}: {
|
|
316
|
+
config: {
|
|
317
|
+
method: "GET" | "POST" | "PUT" | "DELETE";
|
|
318
|
+
urlTemplate: string;
|
|
319
|
+
headers: Record<string, string>;
|
|
320
|
+
bodyTemplate?: string;
|
|
321
|
+
};
|
|
322
|
+
parentData: DenormSubmission[];
|
|
323
|
+
}): Promise<{
|
|
324
|
+
method: string;
|
|
325
|
+
url: string;
|
|
326
|
+
headers: Record<string, string>;
|
|
327
|
+
body?: string;
|
|
328
|
+
}> {
|
|
329
|
+
// Build variable map from parent submissions
|
|
330
|
+
const variables = new Map<string, string>();
|
|
331
|
+
|
|
332
|
+
for (const submission of parentData) {
|
|
333
|
+
// Add form-level variables
|
|
334
|
+
variables.set(`form.name`, submission.formName);
|
|
335
|
+
|
|
336
|
+
// Add field-level variables from groups
|
|
337
|
+
for (const group of submission.groups) {
|
|
338
|
+
for (const item of group.items) {
|
|
339
|
+
const key = `${group.name}.${item.name}`;
|
|
340
|
+
const value = String(item.value ?? "");
|
|
341
|
+
variables.set(key, value);
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
for (const derived of group.derived) {
|
|
345
|
+
const key = `${group.name}.${derived.name}`;
|
|
346
|
+
const value = String(derived.value ?? "");
|
|
347
|
+
variables.set(key, value);
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
// Add table row variables (use first row)
|
|
352
|
+
for (const table of submission.tables) {
|
|
353
|
+
const firstRow = table.rows[0];
|
|
354
|
+
if (firstRow) {
|
|
355
|
+
for (const item of firstRow.items) {
|
|
356
|
+
const key = `${table.name}.${item.name}`;
|
|
357
|
+
const value = String(item.value ?? "");
|
|
358
|
+
variables.set(key, value);
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
// Substitute variables in templates
|
|
365
|
+
const substituteVariables = (template: string): string => {
|
|
366
|
+
return template.replace(/\{\{([^}]+)\}\}/g, (match, varName) => {
|
|
367
|
+
const trimmedName = varName.trim();
|
|
368
|
+
const value = variables.get(trimmedName);
|
|
369
|
+
|
|
370
|
+
if (value !== undefined) {
|
|
371
|
+
return encodeURIComponent(value);
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
console.warn(`[buildHttpRequest] Variable not found: ${trimmedName}`);
|
|
375
|
+
return match;
|
|
376
|
+
});
|
|
377
|
+
};
|
|
378
|
+
|
|
379
|
+
const url = substituteVariables(reqConfig.urlTemplate);
|
|
380
|
+
|
|
381
|
+
const headers: Record<string, string> = {};
|
|
382
|
+
for (const [key, value] of Object.entries(reqConfig.headers)) {
|
|
383
|
+
headers[key] = substituteVariables(value);
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
const body = reqConfig.bodyTemplate ? substituteVariables(reqConfig.bodyTemplate) : undefined;
|
|
387
|
+
|
|
388
|
+
return {
|
|
389
|
+
method: reqConfig.method,
|
|
390
|
+
url,
|
|
391
|
+
headers,
|
|
392
|
+
body,
|
|
393
|
+
};
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
// ============================================================================
|
|
397
|
+
// LLM Analysis Helper
|
|
398
|
+
// ============================================================================
|
|
399
|
+
|
|
400
|
+
async function runAnalysisWithLLM({
|
|
401
|
+
member,
|
|
402
|
+
runId,
|
|
403
|
+
runStepId,
|
|
404
|
+
step,
|
|
405
|
+
inputSubmissions,
|
|
406
|
+
outputForm,
|
|
407
|
+
spawningGroup,
|
|
408
|
+
model,
|
|
409
|
+
}: {
|
|
410
|
+
member: Member;
|
|
411
|
+
runId: string;
|
|
412
|
+
runStepId: string;
|
|
413
|
+
step: {
|
|
414
|
+
id: string;
|
|
415
|
+
description: string;
|
|
416
|
+
prompt: string;
|
|
417
|
+
toolsAllowed: string[] | null;
|
|
418
|
+
};
|
|
419
|
+
inputSubmissions: DenormSubmission[];
|
|
420
|
+
outputForm: FormWithGroups;
|
|
421
|
+
spawningGroup?: DenormGroup | null;
|
|
422
|
+
model: LanguageModel;
|
|
423
|
+
}) {
|
|
424
|
+
try {
|
|
425
|
+
// Build output schema
|
|
426
|
+
const workflowStepResponseSchema = buildStepResponseSchema(outputForm.groups);
|
|
427
|
+
const strictSchema = zodSchema(workflowStepResponseSchema);
|
|
428
|
+
addAdditionalPropertiesToJsonSchema(strictSchema.jsonSchema as JSONSchema7);
|
|
429
|
+
|
|
430
|
+
// Build instructions
|
|
431
|
+
const instructionsParts = [
|
|
432
|
+
`
|
|
433
|
+
<role>You are a precise data transformation specialist executing one step in a data workflow.</role>
|
|
434
|
+
|
|
435
|
+
<task>
|
|
436
|
+
- Your broad task is ${step.description}.
|
|
437
|
+
- The user will specify the exact instructions on how to perform the data transformations for this step in the <step_instructions> section.
|
|
438
|
+
</task>
|
|
439
|
+
|
|
440
|
+
<input_format>
|
|
441
|
+
- HTML-formatted submission data with multiple sections
|
|
442
|
+
- Each field has an id attribute for reference (e.g., id="field-123")
|
|
443
|
+
- Sections may include definition lists (<dl>) and tables (<table>)
|
|
444
|
+
- Multiple input submissions may be provided
|
|
445
|
+
</input_format>
|
|
446
|
+
|
|
447
|
+
<transformation_rules>
|
|
448
|
+
1. <completeness>Extract ALL fields defined in the output schema</completeness>
|
|
449
|
+
2. <output_format>For each primitive field (string, number, boolean), output:
|
|
450
|
+
"fieldName": { "value": <transformed_value>, "refId": "<element_id>", "reasoning": "<explanation>" }</output_format>
|
|
451
|
+
3. <multiple_references>When a value is derived from multiple input elements, list all element IDs separated by commas in the refId field</multiple_references>
|
|
452
|
+
4. <reasoning_requirement>
|
|
453
|
+
- The reasoning field MUST explain HOW the value was derived from the input data.
|
|
454
|
+
- When referring to specific elements from input data, refer to them by the corresponding header trace under which they reside
|
|
455
|
+
</reasoning_requirement>
|
|
456
|
+
5. <reasoning_examples>
|
|
457
|
+
- "Calculated by summing TransactionAmount fields from rows 1-5"
|
|
458
|
+
- "Extracted from BankName field in section 'Bank Statement'"
|
|
459
|
+
- "Average of Balance values across all input data"
|
|
460
|
+
- "Converted from USD to GBP using exchange rate in row 3"</reasoning_examples>
|
|
461
|
+
6. <source_fidelity>ONLY use values present in or reasonably inferred from the input data - NO external knowledge</source_fidelity>
|
|
462
|
+
7. <reference_requirement>EVERY extracted value MUST include a refId pointing to the source element(s) and a reasoning explaining the transformation</reference_requirement>
|
|
463
|
+
</transformation_rules>
|
|
464
|
+
|
|
465
|
+
<output_requirements>
|
|
466
|
+
- Return a JSON object conforming to the provided schema
|
|
467
|
+
- Validate output matches schema structure exactly
|
|
468
|
+
- All required fields must be present
|
|
469
|
+
- All values must include refId and reasoning
|
|
470
|
+
</output_requirements>`,
|
|
471
|
+
];
|
|
472
|
+
|
|
473
|
+
instructionsParts.push("<step_instructions>", step.prompt, "</step_instructions>");
|
|
474
|
+
const instructions = instructionsParts.join("\n");
|
|
475
|
+
|
|
476
|
+
// Build messages
|
|
477
|
+
const serializedInput = inputSubmissions.map((sub) => serializeSubmission(sub));
|
|
478
|
+
const messages = [
|
|
479
|
+
{
|
|
480
|
+
role: "user" as const,
|
|
481
|
+
content: `===== INPUT DATA =====\n${serializedInput}`,
|
|
482
|
+
},
|
|
483
|
+
];
|
|
484
|
+
if (spawningGroup) {
|
|
485
|
+
messages.push({
|
|
486
|
+
role: "user" as const,
|
|
487
|
+
content: ["<main_input>", serializeGroup(spawningGroup), "</main_input>"].join("\n"),
|
|
488
|
+
});
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
// Load pipeline-specific tools
|
|
492
|
+
const tools = {
|
|
493
|
+
createArtifact: createPipelineArtifact({
|
|
494
|
+
member,
|
|
495
|
+
runId,
|
|
496
|
+
runStepId,
|
|
497
|
+
}),
|
|
498
|
+
};
|
|
499
|
+
|
|
500
|
+
// Create agent with structured output
|
|
501
|
+
const agent = new ToolLoopAgent({
|
|
502
|
+
model,
|
|
503
|
+
instructions,
|
|
504
|
+
tools,
|
|
505
|
+
stopWhen: stepCountIs(10),
|
|
506
|
+
output: Output.object({
|
|
507
|
+
schema: jsonSchema(strictSchema.jsonSchema),
|
|
508
|
+
}),
|
|
509
|
+
});
|
|
510
|
+
|
|
511
|
+
const result = await agent.generate({ messages });
|
|
512
|
+
const parsedOutput = workflowStepResponseSchema.parse(result.output);
|
|
513
|
+
|
|
514
|
+
return {
|
|
515
|
+
status: PIPELINE_RUN_STEP_STATUS.COMPLETED,
|
|
516
|
+
data: parsedOutput.data,
|
|
517
|
+
};
|
|
518
|
+
} catch (error) {
|
|
519
|
+
return {
|
|
520
|
+
status: PIPELINE_RUN_STEP_STATUS.FAILED,
|
|
521
|
+
data: null,
|
|
522
|
+
error: error instanceof Error ? error.message : "Analysis failed",
|
|
523
|
+
};
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
// ============================================================================
|
|
528
|
+
// Extraction Step Task
|
|
529
|
+
// ============================================================================
|
|
530
|
+
|
|
531
|
+
export const executeExtractionStepTask = hatchet.task<StepExecutionInput, StepExecutionOutput>({
|
|
532
|
+
name: "execute-extraction-step",
|
|
533
|
+
timeout: "30m", // Extraction can take a while
|
|
534
|
+
fn: async (input) => {
|
|
535
|
+
console.log("[executeExtractionStepTask] Starting...");
|
|
536
|
+
const { memberId, runStepId, stepId } = input;
|
|
537
|
+
|
|
538
|
+
try {
|
|
539
|
+
// Get member
|
|
540
|
+
const member = await db.query.member.findFirst({
|
|
541
|
+
where: eq(schema.member.id, memberId),
|
|
542
|
+
});
|
|
543
|
+
invariant(member, "Member not found");
|
|
544
|
+
|
|
545
|
+
// Get run step
|
|
546
|
+
const runStep = await db.query.pipelineRunStep.findFirst({
|
|
547
|
+
where: eq(schema.pipelineRunStep.id, runStepId),
|
|
548
|
+
});
|
|
549
|
+
invariant(runStep, "Run step not found");
|
|
550
|
+
|
|
551
|
+
// Get step definition
|
|
552
|
+
const stepResult = await getPipelineStepById({ member, stepId });
|
|
553
|
+
if (!stepResult.ok) {
|
|
554
|
+
throw new Error(`Step ${stepId} not found`);
|
|
555
|
+
}
|
|
556
|
+
const step = stepResult.data;
|
|
557
|
+
|
|
558
|
+
await updatePipelineRunStepStatus({
|
|
559
|
+
member,
|
|
560
|
+
runStepId,
|
|
561
|
+
status: PIPELINE_RUN_STEP_STATUS.RUNNING,
|
|
562
|
+
});
|
|
563
|
+
|
|
564
|
+
// Get documents linked to this step run
|
|
565
|
+
const documentsResult = await getStepDocuments({
|
|
566
|
+
member,
|
|
567
|
+
runStepId,
|
|
568
|
+
});
|
|
569
|
+
|
|
570
|
+
if (!documentsResult.ok) {
|
|
571
|
+
throw new Error("Failed to load step documents");
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
if (documentsResult.data.length === 0) {
|
|
575
|
+
throw new Error("No documents linked to extraction step");
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
// Validate we have output forms
|
|
579
|
+
if (step.outputForms.length === 0) {
|
|
580
|
+
throw new Error("Extraction step missing output form");
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
// Get pipeline run to access dealId
|
|
584
|
+
const pipelineRun = await db.query.pipelineRun.findFirst({
|
|
585
|
+
where: eq(schema.pipelineRun.id, runStep.runId),
|
|
586
|
+
});
|
|
587
|
+
if (!pipelineRun) {
|
|
588
|
+
throw new Error("Pipeline run not found");
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
// Process each output form
|
|
592
|
+
const outputSubmissionIds: string[] = [];
|
|
593
|
+
|
|
594
|
+
// Fetch all form names upfront
|
|
595
|
+
const formIds = step.outputForms.map((f) => f.formId);
|
|
596
|
+
const forms = await db.query.form.findMany({
|
|
597
|
+
where: (fields, { inArray }) => inArray(fields.id, formIds),
|
|
598
|
+
});
|
|
599
|
+
const formIdToName = new Map(forms.map((f) => [f.id, f.name]));
|
|
600
|
+
|
|
601
|
+
for (const [formIndex, outputFormConfig] of step.outputForms.entries()) {
|
|
602
|
+
const outputFormId = outputFormConfig.formId;
|
|
603
|
+
const formName = formIdToName.get(outputFormId);
|
|
604
|
+
|
|
605
|
+
console.log(
|
|
606
|
+
`[executeExtractionStepTask] Processing output form ${formIndex + 1}/${step.outputForms.length}: ${outputFormId} (${formName})`,
|
|
607
|
+
);
|
|
608
|
+
|
|
609
|
+
// Build submission name
|
|
610
|
+
let submissionName: string;
|
|
611
|
+
if (runStep.spawnType === "instance") {
|
|
612
|
+
if (step.outputForms.length > 1) {
|
|
613
|
+
submissionName = `${step.name} - Instance ${runStep.stepRunIndex! + 1} - ${formName ?? `Form ${formIndex + 1}`}`;
|
|
614
|
+
} else {
|
|
615
|
+
submissionName = `${step.name} - Instance ${runStep.stepRunIndex! + 1}`;
|
|
616
|
+
}
|
|
617
|
+
} else {
|
|
618
|
+
if (step.outputForms.length > 1) {
|
|
619
|
+
submissionName = `${step.name} - ${formName ?? `Form ${formIndex + 1}`}`;
|
|
620
|
+
} else {
|
|
621
|
+
submissionName = `${step.name} output`;
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
// Create output submission for extracted data
|
|
626
|
+
const outputSubmission = await createSubmissionWithConversation({
|
|
627
|
+
member,
|
|
628
|
+
data: {
|
|
629
|
+
formId: outputFormId,
|
|
630
|
+
dealId: pipelineRun.dealId,
|
|
631
|
+
name: submissionName,
|
|
632
|
+
status: "draft",
|
|
633
|
+
type: "extraction",
|
|
634
|
+
},
|
|
635
|
+
});
|
|
636
|
+
|
|
637
|
+
await syncSubmissionToForm({
|
|
638
|
+
member,
|
|
639
|
+
submissionId: outputSubmission.id,
|
|
640
|
+
});
|
|
641
|
+
|
|
642
|
+
// For each document, create documentExtraction and trigger extraction workflow directly
|
|
643
|
+
const extractionPromises = documentsResult.data.map(async (document) => {
|
|
644
|
+
// Create documentExtraction record
|
|
645
|
+
const [documentExtraction] = await db
|
|
646
|
+
.insert(schema.documentExtraction)
|
|
647
|
+
.values({
|
|
648
|
+
documentId: document.id,
|
|
649
|
+
submissionId: outputSubmission.id,
|
|
650
|
+
status: "pending",
|
|
651
|
+
extractionModel: "smart",
|
|
652
|
+
extractionTrigger: "api",
|
|
653
|
+
})
|
|
654
|
+
.returning({ id: schema.documentExtraction.id });
|
|
655
|
+
|
|
656
|
+
invariant(
|
|
657
|
+
documentExtraction,
|
|
658
|
+
`Failed to create documentExtraction for document ${document.id}`,
|
|
659
|
+
);
|
|
660
|
+
|
|
661
|
+
console.log(
|
|
662
|
+
`[executeExtractionStepTask] Calling extraction workflow for form ${formIndex + 1}, document: ${document.name} (extractionId: ${documentExtraction.id})`,
|
|
663
|
+
);
|
|
664
|
+
|
|
665
|
+
// Call extraction workflow directly (no event, no polling!)
|
|
666
|
+
await extractDataUnified.run({
|
|
667
|
+
documentExtractionId: documentExtraction.id,
|
|
668
|
+
options: {
|
|
669
|
+
extractionModel: "general",
|
|
670
|
+
reasoningEffort: "medium",
|
|
671
|
+
},
|
|
672
|
+
userPrompt: step.prompt || undefined,
|
|
673
|
+
});
|
|
674
|
+
|
|
675
|
+
console.log(
|
|
676
|
+
`[executeExtractionStepTask] Extraction completed for form ${formIndex + 1}, document: ${document.name}`,
|
|
677
|
+
);
|
|
678
|
+
|
|
679
|
+
return documentExtraction.id;
|
|
680
|
+
});
|
|
681
|
+
|
|
682
|
+
// Wait for all extractions to complete for this form
|
|
683
|
+
await Promise.all(extractionPromises);
|
|
684
|
+
|
|
685
|
+
// Link output submission to run step
|
|
686
|
+
await db.insert(schema.pipelineRunStepOutputSubmission).values({
|
|
687
|
+
runStepId,
|
|
688
|
+
submissionId: outputSubmission.id,
|
|
689
|
+
});
|
|
690
|
+
|
|
691
|
+
outputSubmissionIds.push(outputSubmission.id);
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
// Mark step as completed
|
|
695
|
+
await updatePipelineRunStepStatus({
|
|
696
|
+
member,
|
|
697
|
+
runStepId,
|
|
698
|
+
status: PIPELINE_RUN_STEP_STATUS.COMPLETED,
|
|
699
|
+
});
|
|
700
|
+
|
|
701
|
+
// Resolve blockers now that extraction is complete
|
|
702
|
+
await resolveStepBlockersOnCompletion({
|
|
703
|
+
member,
|
|
704
|
+
runStepId,
|
|
705
|
+
});
|
|
706
|
+
|
|
707
|
+
console.log(
|
|
708
|
+
`[executeExtractionStepTask] Completed extraction step with ${documentsResult.data.length} document(s) across ${step.outputForms.length} form(s), output submissions: ${outputSubmissionIds.join(", ")}`,
|
|
709
|
+
);
|
|
710
|
+
|
|
711
|
+
return {
|
|
712
|
+
status: PIPELINE_RUN_STEP_STATUS.COMPLETED,
|
|
713
|
+
outputSubmissionId: outputSubmissionIds[0], // Keep first for backwards compatibility
|
|
714
|
+
};
|
|
715
|
+
} catch (error) {
|
|
716
|
+
console.error("[executeExtractionStepTask] Error:", error);
|
|
717
|
+
await updatePipelineRunStepStatus({
|
|
718
|
+
member: { id: memberId } as Member,
|
|
719
|
+
runStepId,
|
|
720
|
+
status: PIPELINE_RUN_STEP_STATUS.FAILED,
|
|
721
|
+
error: error instanceof Error ? error.message : "Unknown error",
|
|
722
|
+
});
|
|
723
|
+
|
|
724
|
+
return {
|
|
725
|
+
status: PIPELINE_RUN_STEP_STATUS.FAILED,
|
|
726
|
+
error: error instanceof Error ? error.message : "Extraction step failed",
|
|
727
|
+
};
|
|
728
|
+
}
|
|
729
|
+
},
|
|
730
|
+
});
|
|
731
|
+
|
|
732
|
+
// ============================================================================
|
|
733
|
+
// Integration Step Task
|
|
734
|
+
// ============================================================================
|
|
735
|
+
|
|
736
|
+
export const executeIntegrationStepTask = hatchet.task<StepExecutionInput, StepExecutionOutput>({
|
|
737
|
+
name: "execute-integration-step",
|
|
738
|
+
timeout: "10m",
|
|
739
|
+
fn: async (input) => {
|
|
740
|
+
const { memberId, runStepId, stepId } = input;
|
|
741
|
+
|
|
742
|
+
try {
|
|
743
|
+
const member = await db.query.member.findFirst({
|
|
744
|
+
where: eq(schema.member.id, memberId),
|
|
745
|
+
});
|
|
746
|
+
invariant(member, "Member not found");
|
|
747
|
+
|
|
748
|
+
const runStep = await db.query.pipelineRunStep.findFirst({
|
|
749
|
+
where: eq(schema.pipelineRunStep.id, runStepId),
|
|
750
|
+
});
|
|
751
|
+
invariant(runStep, "Run step not found");
|
|
752
|
+
|
|
753
|
+
const stepResult = await getPipelineStepById({ member, stepId });
|
|
754
|
+
if (!stepResult.ok) {
|
|
755
|
+
throw new Error(`Step ${stepId} not found`);
|
|
756
|
+
}
|
|
757
|
+
const step = stepResult.data;
|
|
758
|
+
|
|
759
|
+
await updatePipelineRunStepStatus({
|
|
760
|
+
member,
|
|
761
|
+
runStepId,
|
|
762
|
+
status: PIPELINE_RUN_STEP_STATUS.RUNNING,
|
|
763
|
+
});
|
|
764
|
+
|
|
765
|
+
// Get integration config
|
|
766
|
+
const integrationConfigResult = await getStepIntegrationConfig({
|
|
767
|
+
member,
|
|
768
|
+
stepId,
|
|
769
|
+
});
|
|
770
|
+
|
|
771
|
+
if (!integrationConfigResult.ok || !integrationConfigResult.data) {
|
|
772
|
+
throw new Error("Integration step missing config");
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
const integrationConfig = integrationConfigResult.data;
|
|
776
|
+
|
|
777
|
+
// Get parent step outputs
|
|
778
|
+
const parentStepRunsResult = await getParentStepRuns({
|
|
779
|
+
member,
|
|
780
|
+
runStepId,
|
|
781
|
+
});
|
|
782
|
+
|
|
783
|
+
if (!parentStepRunsResult.ok) {
|
|
784
|
+
throw new Error("Failed to load parent step outputs");
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
const parentStepRuns = parentStepRunsResult.data;
|
|
788
|
+
|
|
789
|
+
// Load output submissions for each parent step run
|
|
790
|
+
const parentSubmissions = await Promise.all(
|
|
791
|
+
parentStepRuns.map(async (p) => {
|
|
792
|
+
const outputMapping = await db.query.pipelineRunStepOutputSubmission.findFirst({
|
|
793
|
+
where: eq(schema.pipelineRunStepOutputSubmission.runStepId, p.id),
|
|
794
|
+
});
|
|
795
|
+
if (!outputMapping) return null;
|
|
796
|
+
return getDenormSubmission({
|
|
797
|
+
member,
|
|
798
|
+
submissionId: outputMapping.submissionId,
|
|
799
|
+
withCitations: true,
|
|
800
|
+
withTransformations: true,
|
|
801
|
+
});
|
|
802
|
+
}),
|
|
803
|
+
);
|
|
804
|
+
|
|
805
|
+
const validParentSubmissions = parentSubmissions.filter(
|
|
806
|
+
(s): s is NonNullable<typeof s> => s !== null,
|
|
807
|
+
);
|
|
808
|
+
|
|
809
|
+
// Build request from template
|
|
810
|
+
const request = await buildHttpRequest({
|
|
811
|
+
config: {
|
|
812
|
+
method: integrationConfig.method as "GET" | "POST" | "PUT" | "DELETE",
|
|
813
|
+
urlTemplate: integrationConfig.urlTemplate,
|
|
814
|
+
headers: integrationConfig.headers,
|
|
815
|
+
bodyTemplate: integrationConfig.bodyTemplate ?? undefined,
|
|
816
|
+
},
|
|
817
|
+
parentData: validParentSubmissions,
|
|
818
|
+
});
|
|
819
|
+
|
|
820
|
+
// Make API call
|
|
821
|
+
const startTime = Date.now();
|
|
822
|
+
let statusCode: number | undefined;
|
|
823
|
+
let responseBody: unknown;
|
|
824
|
+
let error: string | undefined;
|
|
825
|
+
|
|
826
|
+
try {
|
|
827
|
+
const response = await fetch(request.url, {
|
|
828
|
+
method: request.method,
|
|
829
|
+
headers: request.headers,
|
|
830
|
+
body: request.body,
|
|
831
|
+
});
|
|
832
|
+
|
|
833
|
+
statusCode = response.status;
|
|
834
|
+
responseBody = await response.json();
|
|
835
|
+
} catch (err) {
|
|
836
|
+
error = err instanceof Error ? err.message : "Request failed";
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
const durationMs = Date.now() - startTime;
|
|
840
|
+
|
|
841
|
+
// Log request call
|
|
842
|
+
await logRequestCall({
|
|
843
|
+
member,
|
|
844
|
+
runStepId,
|
|
845
|
+
method: request.method,
|
|
846
|
+
url: request.url,
|
|
847
|
+
requestHeaders: request.headers,
|
|
848
|
+
requestBody: request.body,
|
|
849
|
+
statusCode,
|
|
850
|
+
responseBody,
|
|
851
|
+
durationMs,
|
|
852
|
+
error,
|
|
853
|
+
});
|
|
854
|
+
|
|
855
|
+
if (error || !statusCode || statusCode >= 400) {
|
|
856
|
+
throw new Error(error || `HTTP ${statusCode}`);
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
await updatePipelineRunStepStatus({
|
|
860
|
+
member,
|
|
861
|
+
runStepId,
|
|
862
|
+
status: PIPELINE_RUN_STEP_STATUS.COMPLETED,
|
|
863
|
+
});
|
|
864
|
+
|
|
865
|
+
// Resolve blockers now that integration is complete
|
|
866
|
+
await resolveStepBlockersOnCompletion({
|
|
867
|
+
member,
|
|
868
|
+
runStepId,
|
|
869
|
+
});
|
|
870
|
+
|
|
871
|
+
return {
|
|
872
|
+
status: PIPELINE_RUN_STEP_STATUS.COMPLETED,
|
|
873
|
+
};
|
|
874
|
+
} catch (error) {
|
|
875
|
+
await updatePipelineRunStepStatus({
|
|
876
|
+
member: { id: memberId } as Member,
|
|
877
|
+
runStepId,
|
|
878
|
+
status: PIPELINE_RUN_STEP_STATUS.FAILED,
|
|
879
|
+
error: error instanceof Error ? error.message : "Integration step failed",
|
|
880
|
+
});
|
|
881
|
+
|
|
882
|
+
return {
|
|
883
|
+
status: PIPELINE_RUN_STEP_STATUS.FAILED,
|
|
884
|
+
error: error instanceof Error ? error.message : "Integration step failed",
|
|
885
|
+
};
|
|
886
|
+
}
|
|
887
|
+
},
|
|
888
|
+
});
|
|
889
|
+
|
|
890
|
+
// ============================================================================
|
|
891
|
+
// Analysis Step Task
|
|
892
|
+
// ============================================================================
|
|
893
|
+
|
|
894
|
+
export const executeAnalysisStepTask = hatchet.task<StepExecutionInput, StepExecutionOutput>({
|
|
895
|
+
name: "execute-analysis-step",
|
|
896
|
+
timeout: "20m", // Analysis with LLM can take time
|
|
897
|
+
fn: async (input) => {
|
|
898
|
+
const { memberId, runStepId } = input;
|
|
899
|
+
|
|
900
|
+
try {
|
|
901
|
+
const member = await db.query.member.findFirst({
|
|
902
|
+
where: eq(schema.member.id, memberId),
|
|
903
|
+
});
|
|
904
|
+
invariant(member, "Member not found");
|
|
905
|
+
|
|
906
|
+
const runStep = await db.query.pipelineRunStep.findFirst({
|
|
907
|
+
with: { step: { with: { outputForms: true } }, run: true },
|
|
908
|
+
where: eq(schema.pipelineRunStep.id, runStepId),
|
|
909
|
+
});
|
|
910
|
+
invariant(runStep, "Run step not found");
|
|
911
|
+
|
|
912
|
+
await updatePipelineRunStepStatus({
|
|
913
|
+
member,
|
|
914
|
+
runStepId,
|
|
915
|
+
status: PIPELINE_RUN_STEP_STATUS.RUNNING,
|
|
916
|
+
});
|
|
917
|
+
|
|
918
|
+
// Get parent step runs with dependency configurations
|
|
919
|
+
const parentStepRunsResult = await getParentStepRunsWithDependencies({
|
|
920
|
+
member,
|
|
921
|
+
runStepId,
|
|
922
|
+
});
|
|
923
|
+
|
|
924
|
+
if (!parentStepRunsResult.ok) {
|
|
925
|
+
throw new Error("Failed to load parent step runs");
|
|
926
|
+
}
|
|
927
|
+
const parentStepRuns = parentStepRunsResult.data;
|
|
928
|
+
|
|
929
|
+
// Load output submissions for each parent step run
|
|
930
|
+
const parentSubmissionIds = (
|
|
931
|
+
await db
|
|
932
|
+
.select()
|
|
933
|
+
.from(schema.pipelineRunStepOutputSubmission)
|
|
934
|
+
.where(
|
|
935
|
+
inArray(
|
|
936
|
+
schema.pipelineRunStepOutputSubmission.runStepId,
|
|
937
|
+
parentStepRuns.map((p) => p.id),
|
|
938
|
+
),
|
|
939
|
+
)
|
|
940
|
+
).map((row) => row.submissionId);
|
|
941
|
+
const parentSubmissions = await getDenormSubmissions({
|
|
942
|
+
member,
|
|
943
|
+
submissionIds: parentSubmissionIds,
|
|
944
|
+
withCitations: true,
|
|
945
|
+
withTransformations: true,
|
|
946
|
+
});
|
|
947
|
+
|
|
948
|
+
// Check if this is a multi step - if so filter input submissions accordingly
|
|
949
|
+
const multiGroupResult = await getGroupForStepRun({
|
|
950
|
+
member,
|
|
951
|
+
runStepId,
|
|
952
|
+
});
|
|
953
|
+
const spawningGroup = multiGroupResult.ok ? multiGroupResult.data : null;
|
|
954
|
+
const inputSubmissions = parentSubmissions.filter(({ tables }) => {
|
|
955
|
+
const hasSpawningGroupTable = tables.some(
|
|
956
|
+
({ formGroupId }) => formGroupId === spawningGroup?.formGroupId,
|
|
957
|
+
);
|
|
958
|
+
return !hasSpawningGroupTable;
|
|
959
|
+
});
|
|
960
|
+
|
|
961
|
+
// Create model instance
|
|
962
|
+
const model = createLanguageModel({
|
|
963
|
+
gatewayApiKey: config.vercel.aiGatewayApiKey,
|
|
964
|
+
modelId: "openai/gpt-5.2",
|
|
965
|
+
});
|
|
966
|
+
|
|
967
|
+
// Create output submission for each output form
|
|
968
|
+
for (const { formId } of runStep.step.outputForms) {
|
|
969
|
+
const outputSubmission = await createSubmissionWithConversation({
|
|
970
|
+
member,
|
|
971
|
+
data: {
|
|
972
|
+
formId,
|
|
973
|
+
dealId: runStep.run.dealId,
|
|
974
|
+
name:
|
|
975
|
+
runStep.spawnType === "instance"
|
|
976
|
+
? `${runStep.step.name} - Instance ${runStep.stepRunIndex! + 1}`
|
|
977
|
+
: `${runStep.step.name} output`,
|
|
978
|
+
status: "draft",
|
|
979
|
+
type: "transformation",
|
|
980
|
+
},
|
|
981
|
+
});
|
|
982
|
+
await syncSubmissionToForm({
|
|
983
|
+
member,
|
|
984
|
+
submissionId: outputSubmission.id,
|
|
985
|
+
});
|
|
986
|
+
|
|
987
|
+
// Run LLM-based analysis
|
|
988
|
+
const outputForm = await getForm({ member, formId });
|
|
989
|
+
const analysisResult = await runAnalysisWithLLM({
|
|
990
|
+
member,
|
|
991
|
+
runId: runStep.runId,
|
|
992
|
+
runStepId,
|
|
993
|
+
step: runStep.step,
|
|
994
|
+
inputSubmissions,
|
|
995
|
+
outputForm,
|
|
996
|
+
spawningGroup,
|
|
997
|
+
model,
|
|
998
|
+
});
|
|
999
|
+
|
|
1000
|
+
// Store output
|
|
1001
|
+
if (analysisResult.data) {
|
|
1002
|
+
const storeResult = await storePipelineOutputData({
|
|
1003
|
+
member,
|
|
1004
|
+
outputSubmissionId: outputSubmission.id,
|
|
1005
|
+
outputData: analysisResult.data as Record<
|
|
1006
|
+
string,
|
|
1007
|
+
| Record<string, { value: string | number | null; refId: string } | null>
|
|
1008
|
+
| Record<string, { value: string | number | null; refId: string } | null>[]
|
|
1009
|
+
| null
|
|
1010
|
+
>,
|
|
1011
|
+
});
|
|
1012
|
+
|
|
1013
|
+
if (!storeResult.ok) {
|
|
1014
|
+
throw new Error("Failed to store pipeline output data");
|
|
1015
|
+
}
|
|
1016
|
+
}
|
|
1017
|
+
|
|
1018
|
+
// Link output submission to run step
|
|
1019
|
+
await db.insert(schema.pipelineRunStepOutputSubmission).values({
|
|
1020
|
+
runStepId,
|
|
1021
|
+
submissionId: outputSubmission.id,
|
|
1022
|
+
});
|
|
1023
|
+
|
|
1024
|
+
await updatePipelineRunStepStatus({
|
|
1025
|
+
member,
|
|
1026
|
+
runStepId,
|
|
1027
|
+
status: analysisResult.status,
|
|
1028
|
+
error: analysisResult.error,
|
|
1029
|
+
});
|
|
1030
|
+
|
|
1031
|
+
if (analysisResult.status === "failed") {
|
|
1032
|
+
throw new Error(analysisResult.error || "Analysis step failed");
|
|
1033
|
+
}
|
|
1034
|
+
}
|
|
1035
|
+
|
|
1036
|
+
return {
|
|
1037
|
+
status: PIPELINE_RUN_STEP_STATUS.COMPLETED,
|
|
1038
|
+
};
|
|
1039
|
+
} catch (error) {
|
|
1040
|
+
await updatePipelineRunStepStatus({
|
|
1041
|
+
member: { id: memberId } as Member,
|
|
1042
|
+
runStepId,
|
|
1043
|
+
status: PIPELINE_RUN_STEP_STATUS.FAILED,
|
|
1044
|
+
error: error instanceof Error ? error.message : "Analysis step failed",
|
|
1045
|
+
});
|
|
1046
|
+
|
|
1047
|
+
return {
|
|
1048
|
+
status: PIPELINE_RUN_STEP_STATUS.FAILED,
|
|
1049
|
+
error: error instanceof Error ? error.message : "Analysis step failed",
|
|
1050
|
+
};
|
|
1051
|
+
}
|
|
1052
|
+
},
|
|
1053
|
+
});
|
|
1054
|
+
|
|
1055
|
+
// ============================================================================
|
|
1056
|
+
// Manual Step Task
|
|
1057
|
+
// ============================================================================
|
|
1058
|
+
|
|
1059
|
+
export const executeManualStepTask = hatchet.task<StepExecutionInput, StepExecutionOutput>({
|
|
1060
|
+
name: "execute-manual-step",
|
|
1061
|
+
timeout: "5m",
|
|
1062
|
+
fn: async (input) => {
|
|
1063
|
+
const { memberId, runStepId, stepId } = input;
|
|
1064
|
+
|
|
1065
|
+
try {
|
|
1066
|
+
const member = await db.query.member.findFirst({
|
|
1067
|
+
where: eq(schema.member.id, memberId),
|
|
1068
|
+
});
|
|
1069
|
+
invariant(member, "Member not found");
|
|
1070
|
+
const runStep = await db.query.pipelineRunStep.findFirst({
|
|
1071
|
+
where: eq(schema.pipelineRunStep.id, runStepId),
|
|
1072
|
+
});
|
|
1073
|
+
invariant(runStep, "Run step not found");
|
|
1074
|
+
|
|
1075
|
+
const stepResult = await getPipelineStepById({ member, stepId });
|
|
1076
|
+
if (!stepResult.ok) {
|
|
1077
|
+
throw new Error(`Step ${stepId} not found`);
|
|
1078
|
+
}
|
|
1079
|
+
const step = stepResult.data;
|
|
1080
|
+
await updatePipelineRunStepStatus({
|
|
1081
|
+
member,
|
|
1082
|
+
runStepId,
|
|
1083
|
+
status: PIPELINE_RUN_STEP_STATUS.RUNNING,
|
|
1084
|
+
});
|
|
1085
|
+
|
|
1086
|
+
// Check if manual output submission has been provided
|
|
1087
|
+
const outputMapping = await db.query.pipelineRunStepOutputSubmission.findFirst({
|
|
1088
|
+
where: eq(schema.pipelineRunStepOutputSubmission.runStepId, runStepId),
|
|
1089
|
+
});
|
|
1090
|
+
|
|
1091
|
+
if (!outputMapping) {
|
|
1092
|
+
// No output submission yet - create a blocker and mark as blocked
|
|
1093
|
+
console.log(
|
|
1094
|
+
`[executeManualStepTask] Step ${step.name} blocked - waiting for manual output submission`,
|
|
1095
|
+
);
|
|
1096
|
+
|
|
1097
|
+
// Check if blocker already exists
|
|
1098
|
+
const existingBlocker = await db.query.pipelineRunStepBlocker.findFirst({
|
|
1099
|
+
where: and(
|
|
1100
|
+
eq(schema.pipelineRunStepBlocker.runStepId, runStepId),
|
|
1101
|
+
eq(schema.pipelineRunStepBlocker.blockerType, "missing_manual_input"),
|
|
1102
|
+
eq(schema.pipelineRunStepBlocker.resolved, false),
|
|
1103
|
+
),
|
|
1104
|
+
});
|
|
1105
|
+
|
|
1106
|
+
if (!existingBlocker) {
|
|
1107
|
+
await db.insert(schema.pipelineRunStepBlocker).values({
|
|
1108
|
+
runStepId,
|
|
1109
|
+
blockerType: "missing_manual_input",
|
|
1110
|
+
blockerDetails: {
|
|
1111
|
+
type: "missing_manual_input",
|
|
1112
|
+
stepName: step.name,
|
|
1113
|
+
stepDescription: step.description,
|
|
1114
|
+
},
|
|
1115
|
+
resolved: false,
|
|
1116
|
+
});
|
|
1117
|
+
}
|
|
1118
|
+
|
|
1119
|
+
await updatePipelineRunStepStatus({
|
|
1120
|
+
member,
|
|
1121
|
+
runStepId,
|
|
1122
|
+
status: PIPELINE_RUN_STEP_STATUS.BLOCKED,
|
|
1123
|
+
});
|
|
1124
|
+
|
|
1125
|
+
return {
|
|
1126
|
+
status: PIPELINE_RUN_STEP_STATUS.BLOCKED,
|
|
1127
|
+
};
|
|
1128
|
+
}
|
|
1129
|
+
|
|
1130
|
+
// Output submission exists - all dependencies satisfied, mark as completed
|
|
1131
|
+
const result = await updatePipelineRunStepStatus({
|
|
1132
|
+
member,
|
|
1133
|
+
runStepId,
|
|
1134
|
+
status: PIPELINE_RUN_STEP_STATUS.COMPLETED,
|
|
1135
|
+
});
|
|
1136
|
+
|
|
1137
|
+
if (!result.ok) {
|
|
1138
|
+
throw new Error("Failed to update pipeline run step status");
|
|
1139
|
+
}
|
|
1140
|
+
|
|
1141
|
+
console.log(
|
|
1142
|
+
`[executeManualStepTask] Step ${step.name} completed - manual output submission provided`,
|
|
1143
|
+
);
|
|
1144
|
+
|
|
1145
|
+
return {
|
|
1146
|
+
status: PIPELINE_RUN_STEP_STATUS.COMPLETED,
|
|
1147
|
+
};
|
|
1148
|
+
} catch (error) {
|
|
1149
|
+
await updatePipelineRunStepStatus({
|
|
1150
|
+
member: { id: memberId } as Member,
|
|
1151
|
+
runStepId,
|
|
1152
|
+
status: PIPELINE_RUN_STEP_STATUS.FAILED,
|
|
1153
|
+
error: error instanceof Error ? error.message : "Manual step failed",
|
|
1154
|
+
});
|
|
1155
|
+
|
|
1156
|
+
return {
|
|
1157
|
+
status: PIPELINE_RUN_STEP_STATUS.FAILED,
|
|
1158
|
+
error: error instanceof Error ? error.message : "Manual step failed",
|
|
1159
|
+
};
|
|
1160
|
+
}
|
|
1161
|
+
},
|
|
1162
|
+
});
|
|
1163
|
+
|
|
1164
|
+
// ============================================================================
|
|
1165
|
+
// Template Step Task - Dynamic Instance Spawning
|
|
1166
|
+
// ============================================================================
|
|
1167
|
+
export const executeTemplateStepTask = hatchet.task<StepExecutionInput, StepExecutionOutput>({
|
|
1168
|
+
name: "execute-template-step",
|
|
1169
|
+
timeout: "60m", // Templates can spawn many children
|
|
1170
|
+
fn: async (input) => {
|
|
1171
|
+
console.log("[executeTemplateStepTask] Starting template execution...");
|
|
1172
|
+
const { memberId, runStepId, stepId, stepRole } = input;
|
|
1173
|
+
|
|
1174
|
+
try {
|
|
1175
|
+
// Get member
|
|
1176
|
+
const member = await db.query.member.findFirst({
|
|
1177
|
+
where: eq(schema.member.id, memberId),
|
|
1178
|
+
});
|
|
1179
|
+
invariant(member, "Member not found");
|
|
1180
|
+
|
|
1181
|
+
// Get template run step
|
|
1182
|
+
const runStep = await db.query.pipelineRunStep.findFirst({
|
|
1183
|
+
where: eq(schema.pipelineRunStep.id, runStepId),
|
|
1184
|
+
});
|
|
1185
|
+
invariant(runStep, "Template run step not found");
|
|
1186
|
+
invariant(runStep.spawnType === "template", "Run step must be template type");
|
|
1187
|
+
|
|
1188
|
+
// Get step definition
|
|
1189
|
+
const stepResult = await getPipelineStepById({ member, stepId });
|
|
1190
|
+
if (!stepResult.ok) {
|
|
1191
|
+
throw new Error(`Step ${stepId} not found`);
|
|
1192
|
+
}
|
|
1193
|
+
const step = stepResult.data;
|
|
1194
|
+
|
|
1195
|
+
await updatePipelineRunStepStatus({
|
|
1196
|
+
member,
|
|
1197
|
+
runStepId,
|
|
1198
|
+
status: PIPELINE_RUN_STEP_STATUS.RUNNING,
|
|
1199
|
+
});
|
|
1200
|
+
|
|
1201
|
+
// Get parent step runs with dependency config
|
|
1202
|
+
const parentStepRunsResult = await getParentStepRunsWithDependencies({
|
|
1203
|
+
member,
|
|
1204
|
+
runStepId,
|
|
1205
|
+
});
|
|
1206
|
+
|
|
1207
|
+
if (!parentStepRunsResult.ok) {
|
|
1208
|
+
throw new Error("Failed to load parent step runs");
|
|
1209
|
+
}
|
|
1210
|
+
const parentStepRuns = parentStepRunsResult.data;
|
|
1211
|
+
|
|
1212
|
+
// Find dependencies with multiFormGroupId (the spawning trigger)
|
|
1213
|
+
const multiDeps = parentStepRuns.filter((p) => p.multiFormGroupId !== null);
|
|
1214
|
+
if (!multiDeps?.length) return { status: PIPELINE_RUN_STEP_STATUS.COMPLETED };
|
|
1215
|
+
if (multiDeps.length > 1)
|
|
1216
|
+
throw new Error("Multiple multi-group parents found, not supported");
|
|
1217
|
+
|
|
1218
|
+
// Get the unique
|
|
1219
|
+
const multiDep = multiDeps[0];
|
|
1220
|
+
invariant(multiDep, "Multi dependency not found");
|
|
1221
|
+
|
|
1222
|
+
// Get parent's output submission
|
|
1223
|
+
const parentOutputMapping = await db.query.pipelineRunStepOutputSubmission.findFirst({
|
|
1224
|
+
where: eq(schema.pipelineRunStepOutputSubmission.runStepId, multiDep.id),
|
|
1225
|
+
});
|
|
1226
|
+
if (!parentOutputMapping) {
|
|
1227
|
+
throw new Error("Parent step has no output submission");
|
|
1228
|
+
}
|
|
1229
|
+
|
|
1230
|
+
// Get submission groups to spawn instances
|
|
1231
|
+
const groupsResult = await getSubmissionGroups({
|
|
1232
|
+
member,
|
|
1233
|
+
submissionId: parentOutputMapping.submissionId,
|
|
1234
|
+
formGroupId: multiDep.multiFormGroupId!,
|
|
1235
|
+
});
|
|
1236
|
+
if (!groupsResult.ok) {
|
|
1237
|
+
throw new Error("Failed to load submission groups");
|
|
1238
|
+
}
|
|
1239
|
+
|
|
1240
|
+
const groups = groupsResult.data;
|
|
1241
|
+
console.log(
|
|
1242
|
+
`[executeTemplateStepTask] Found ${groups.length} group(s) to spawn for step ${step.name}`,
|
|
1243
|
+
);
|
|
1244
|
+
|
|
1245
|
+
if (groups.length === 0) {
|
|
1246
|
+
console.log("[executeTemplateStepTask] No groups to process, marking template as complete");
|
|
1247
|
+
await updatePipelineRunStepStatus({
|
|
1248
|
+
member,
|
|
1249
|
+
runStepId,
|
|
1250
|
+
status: PIPELINE_RUN_STEP_STATUS.COMPLETED,
|
|
1251
|
+
});
|
|
1252
|
+
return { status: PIPELINE_RUN_STEP_STATUS.COMPLETED };
|
|
1253
|
+
}
|
|
1254
|
+
|
|
1255
|
+
// Create instance runSteps for each group
|
|
1256
|
+
const instanceRunSteps = [];
|
|
1257
|
+
|
|
1258
|
+
for (let i = 0; i < groups.length; i++) {
|
|
1259
|
+
const group = groups[i];
|
|
1260
|
+
invariant(group, `Group at index ${i} is undefined`);
|
|
1261
|
+
|
|
1262
|
+
console.log(
|
|
1263
|
+
`[executeTemplateStepTask] Creating instance ${i + 1}/${groups.length} for group ${group.id}`,
|
|
1264
|
+
);
|
|
1265
|
+
|
|
1266
|
+
const instanceResult = await createPipelineRunStep({
|
|
1267
|
+
member,
|
|
1268
|
+
runId: runStep.runId,
|
|
1269
|
+
stepId,
|
|
1270
|
+
spawnType: "instance",
|
|
1271
|
+
submissionGroupId: group.id,
|
|
1272
|
+
stepRunIndex: i,
|
|
1273
|
+
});
|
|
1274
|
+
|
|
1275
|
+
if (!instanceResult.ok) {
|
|
1276
|
+
throw new Error(`Failed to create instance runStep for group ${group.id}`);
|
|
1277
|
+
}
|
|
1278
|
+
|
|
1279
|
+
instanceRunSteps.push(instanceResult.data);
|
|
1280
|
+
}
|
|
1281
|
+
|
|
1282
|
+
console.log(
|
|
1283
|
+
`[executeTemplateStepTask] Created ${instanceRunSteps.length} instance runStep(s), spawning workflows...`,
|
|
1284
|
+
);
|
|
1285
|
+
|
|
1286
|
+
// Spawn child workflows with concurrency limit (max 10 parallel)
|
|
1287
|
+
const limit = pLimit(10);
|
|
1288
|
+
const childPromises = instanceRunSteps.map((instanceRunStep) =>
|
|
1289
|
+
limit(async () => {
|
|
1290
|
+
const instanceInput: StepExecutionInput = {
|
|
1291
|
+
memberId,
|
|
1292
|
+
runId: runStep.runId,
|
|
1293
|
+
runStepId: instanceRunStep.id,
|
|
1294
|
+
stepId,
|
|
1295
|
+
};
|
|
1296
|
+
|
|
1297
|
+
console.log(
|
|
1298
|
+
`[executeTemplateStepTask] Spawning instance workflow: ${stepRole}-step (runStepId: ${instanceRunStep.id})`,
|
|
1299
|
+
);
|
|
1300
|
+
|
|
1301
|
+
// Execute based on step role
|
|
1302
|
+
switch (stepRole) {
|
|
1303
|
+
case "extraction": {
|
|
1304
|
+
const result = await executeExtractionStepTask.run(instanceInput);
|
|
1305
|
+
return result;
|
|
1306
|
+
}
|
|
1307
|
+
case "integration": {
|
|
1308
|
+
const result = await executeIntegrationStepTask.run(instanceInput);
|
|
1309
|
+
return result;
|
|
1310
|
+
}
|
|
1311
|
+
case "analysis": {
|
|
1312
|
+
const result = await executeAnalysisStepTask.run(instanceInput);
|
|
1313
|
+
return result;
|
|
1314
|
+
}
|
|
1315
|
+
case "manual": {
|
|
1316
|
+
const result = await executeManualStepTask.run(instanceInput);
|
|
1317
|
+
return result;
|
|
1318
|
+
}
|
|
1319
|
+
default:
|
|
1320
|
+
throw new Error(`Unknown step role: ${stepRole}`);
|
|
1321
|
+
}
|
|
1322
|
+
}),
|
|
1323
|
+
);
|
|
1324
|
+
|
|
1325
|
+
// Wait for all instances to complete (durable wait)
|
|
1326
|
+
console.log(
|
|
1327
|
+
`[executeTemplateStepTask] Waiting for ${childPromises.length} instance(s) to complete with max 10 concurrent executions...`,
|
|
1328
|
+
);
|
|
1329
|
+
const instanceResults = await Promise.all(childPromises);
|
|
1330
|
+
|
|
1331
|
+
// Check instance results
|
|
1332
|
+
const failedInstances = instanceResults.filter(
|
|
1333
|
+
(r) => r && r.status === PIPELINE_RUN_STEP_STATUS.FAILED,
|
|
1334
|
+
);
|
|
1335
|
+
const completedInstances = instanceResults.filter(
|
|
1336
|
+
(r) => r && r.status === PIPELINE_RUN_STEP_STATUS.COMPLETED,
|
|
1337
|
+
);
|
|
1338
|
+
|
|
1339
|
+
console.log(
|
|
1340
|
+
`[executeTemplateStepTask] Instance results: ${completedInstances.length} completed, ${failedInstances.length} failed`,
|
|
1341
|
+
);
|
|
1342
|
+
|
|
1343
|
+
// Resolve child step blockers now that template is complete
|
|
1344
|
+
await resolveStepBlockersOnCompletion({
|
|
1345
|
+
member,
|
|
1346
|
+
runStepId,
|
|
1347
|
+
});
|
|
1348
|
+
|
|
1349
|
+
// Mark template as complete if all instances succeeded
|
|
1350
|
+
if (failedInstances.length === 0) {
|
|
1351
|
+
await updatePipelineRunStepStatus({
|
|
1352
|
+
member,
|
|
1353
|
+
runStepId,
|
|
1354
|
+
status: PIPELINE_RUN_STEP_STATUS.COMPLETED,
|
|
1355
|
+
});
|
|
1356
|
+
|
|
1357
|
+
console.log(
|
|
1358
|
+
`[executeTemplateStepTask] Template step completed successfully with ${instanceResults.length} instance(s)`,
|
|
1359
|
+
);
|
|
1360
|
+
|
|
1361
|
+
return {
|
|
1362
|
+
status: PIPELINE_RUN_STEP_STATUS.COMPLETED,
|
|
1363
|
+
};
|
|
1364
|
+
} else {
|
|
1365
|
+
// Some instances failed
|
|
1366
|
+
await updatePipelineRunStepStatus({
|
|
1367
|
+
member,
|
|
1368
|
+
runStepId,
|
|
1369
|
+
status: PIPELINE_RUN_STEP_STATUS.FAILED,
|
|
1370
|
+
error: `${failedInstances.length} instance(s) failed`,
|
|
1371
|
+
});
|
|
1372
|
+
|
|
1373
|
+
return {
|
|
1374
|
+
status: PIPELINE_RUN_STEP_STATUS.FAILED,
|
|
1375
|
+
error: `${failedInstances.length} of ${instanceResults.length} instance(s) failed`,
|
|
1376
|
+
};
|
|
1377
|
+
}
|
|
1378
|
+
} catch (error) {
|
|
1379
|
+
console.error("[executeTemplateStepTask] Error:", error);
|
|
1380
|
+
await updatePipelineRunStepStatus({
|
|
1381
|
+
member: { id: memberId } as Member,
|
|
1382
|
+
runStepId,
|
|
1383
|
+
status: PIPELINE_RUN_STEP_STATUS.FAILED,
|
|
1384
|
+
error: error instanceof Error ? error.message : "Template step failed",
|
|
1385
|
+
});
|
|
1386
|
+
|
|
1387
|
+
return {
|
|
1388
|
+
status: PIPELINE_RUN_STEP_STATUS.FAILED,
|
|
1389
|
+
error: error instanceof Error ? error.message : "Template step failed",
|
|
1390
|
+
};
|
|
1391
|
+
}
|
|
1392
|
+
},
|
|
1393
|
+
});
|