@elevasis/sdk 1.17.0 → 1.19.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.
@@ -5560,6 +5560,29 @@ function estimateTokens(text) {
5560
5560
  const chars4 = content.length;
5561
5561
  return Math.ceil(chars4 / 3.5);
5562
5562
  }
5563
+ var UuidSchema = z.string().uuid();
5564
+ var NonEmptyStringSchema = z.string().trim().min(1).max(1e3);
5565
+ z.enum(["agent", "workflow"]);
5566
+ z.enum(["agent", "workflow", "scheduler", "api"]);
5567
+ z.string().trim().toLowerCase().min(1, "Credential name required").max(100, "Credential name too long (max 100 chars)").regex(
5568
+ /^[a-z0-9]+(-[a-z0-9]+)+$/,
5569
+ "Credential name must be lowercase letters, numbers, and hyphens in format: service-environment (e.g., gmail-prod, attio-dev)"
5570
+ );
5571
+ z.enum(["google-sheets", "google-calendar", "dropbox"]);
5572
+ z.string().min(10, "Authorization code too short").max(1e3, "Authorization code too long");
5573
+ z.string().min(10, "State parameter too short").max(2048, "State parameter too long");
5574
+ z.string().trim().transform((str) => str.replace(/[<>'"]/g, ""));
5575
+ z.string().email();
5576
+ z.string().url();
5577
+ z.object({
5578
+ limit: z.coerce.number().int().min(1).max(100).default(20),
5579
+ offset: z.coerce.number().int().min(0).default(0)
5580
+ });
5581
+ z.string().datetime();
5582
+ z.object({
5583
+ startDate: z.string().datetime(),
5584
+ endDate: z.string().datetime()
5585
+ });
5563
5586
 
5564
5587
  // ../core/src/platform/constants/limits.ts
5565
5588
  var MAX_SESSION_MEMORY_KEYS = 25;
@@ -6488,6 +6511,1301 @@ Fix the errors and generate a valid output.
6488
6511
  }
6489
6512
  }
6490
6513
  };
6514
+ var ORGANIZATION_MODEL_ICON_TOKENS = [
6515
+ "nav.dashboard",
6516
+ "nav.calendar",
6517
+ "nav.sales",
6518
+ "nav.crm",
6519
+ "nav.lead-gen",
6520
+ "nav.projects",
6521
+ "nav.operations",
6522
+ "nav.monitoring",
6523
+ "nav.knowledge",
6524
+ "nav.settings",
6525
+ "nav.admin",
6526
+ "nav.archive",
6527
+ "knowledge.playbook",
6528
+ "knowledge.strategy",
6529
+ "knowledge.reference",
6530
+ "feature.dashboard",
6531
+ "feature.calendar",
6532
+ "feature.sales",
6533
+ "feature.crm",
6534
+ "feature.finance",
6535
+ "feature.lead-gen",
6536
+ "feature.platform",
6537
+ "feature.projects",
6538
+ "feature.operations",
6539
+ "feature.knowledge",
6540
+ "feature.monitoring",
6541
+ "feature.settings",
6542
+ "feature.admin",
6543
+ "feature.archive",
6544
+ "feature.seo",
6545
+ "resource.agent",
6546
+ "resource.workflow",
6547
+ "resource.integration",
6548
+ "resource.database",
6549
+ "resource.user",
6550
+ "resource.team",
6551
+ "integration.gmail",
6552
+ "integration.google-sheets",
6553
+ "integration.attio",
6554
+ "surface.dashboard",
6555
+ "surface.calendar",
6556
+ "surface.overview",
6557
+ "surface.command-view",
6558
+ "surface.command-queue",
6559
+ "surface.pipeline",
6560
+ "surface.lists",
6561
+ "surface.resources",
6562
+ "surface.settings",
6563
+ "status.success",
6564
+ "status.error",
6565
+ "status.warning",
6566
+ "status.info",
6567
+ "status.pending",
6568
+ "action.approve",
6569
+ "action.reject",
6570
+ "action.retry",
6571
+ "action.edit",
6572
+ "action.view",
6573
+ "action.launch",
6574
+ "action.message",
6575
+ "action.escalate",
6576
+ "action.promote",
6577
+ "action.submit",
6578
+ "action.email"
6579
+ ];
6580
+ var CustomIconTokenSchema = z.string().trim().max(80).regex(/^custom\.[a-z0-9]+(?:[-._][a-z0-9]+)*$/, "Custom icon tokens must start with custom.");
6581
+ var OrganizationModelBuiltinIconTokenSchema = z.enum(ORGANIZATION_MODEL_ICON_TOKENS);
6582
+ var OrganizationModelIconTokenSchema = z.union([
6583
+ OrganizationModelBuiltinIconTokenSchema,
6584
+ CustomIconTokenSchema
6585
+ ]);
6586
+
6587
+ // ../core/src/organization-model/domains/shared.ts
6588
+ var ModelIdSchema = z.string().trim().min(1).max(100).regex(/^[a-z0-9]+(?:[-._][a-z0-9]+)*$/, "IDs must be lowercase and use -, _, or . separators");
6589
+ var LabelSchema = z.string().trim().min(1).max(120);
6590
+ var DescriptionSchema = z.string().trim().min(1).max(2e3);
6591
+ var ColorTokenSchema = z.string().trim().min(1).max(50);
6592
+ var IconNameSchema = OrganizationModelIconTokenSchema;
6593
+ z.string().trim().startsWith("/").max(300);
6594
+ var ReferenceIdsSchema = z.array(ModelIdSchema).default([]);
6595
+ var DisplayMetadataSchema = z.object({
6596
+ label: LabelSchema,
6597
+ description: DescriptionSchema.optional(),
6598
+ color: ColorTokenSchema.optional(),
6599
+ icon: IconNameSchema.optional()
6600
+ });
6601
+ var TechStackEntrySchema = z.object({
6602
+ /** Name of the external platform (e.g. "HubSpot", "Stripe", "Notion"). */
6603
+ platform: z.string().trim().min(1).max(200),
6604
+ /** Free-form description of what this integration is used for. */
6605
+ purpose: z.string().trim().min(1).max(500),
6606
+ /**
6607
+ * Health of the credential backing this integration.
6608
+ * - configured: credential present and valid
6609
+ * - pending: not yet set up
6610
+ * - expired: credential existed but has lapsed
6611
+ * - missing: expected but not present
6612
+ */
6613
+ credentialStatus: z.enum(["configured", "pending", "expired", "missing"]),
6614
+ /**
6615
+ * Whether this integration is the primary system of record for its domain
6616
+ * (e.g. HubSpot is SoR for contacts). Defaults to false.
6617
+ */
6618
+ isSystemOfRecord: z.boolean().default(false)
6619
+ });
6620
+ DisplayMetadataSchema.extend({
6621
+ id: ModelIdSchema,
6622
+ resourceId: z.string().trim().min(1).max(255),
6623
+ resourceType: z.enum(["workflow", "agent", "trigger", "integration", "external", "human_checkpoint"]),
6624
+ featureIds: ReferenceIdsSchema,
6625
+ entityIds: ReferenceIdsSchema,
6626
+ surfaceIds: ReferenceIdsSchema,
6627
+ capabilityIds: ReferenceIdsSchema,
6628
+ /** Optional tech-stack metadata for external-SaaS integrations. */
6629
+ techStack: TechStackEntrySchema.optional()
6630
+ });
6631
+
6632
+ // ../core/src/organization-model/domains/sales.ts
6633
+ var SalesStageSemanticClassSchema = z.enum(["open", "active", "nurturing", "closed_won", "closed_lost"]);
6634
+ var SalesStageSchema = DisplayMetadataSchema.extend({
6635
+ id: ModelIdSchema,
6636
+ order: z.number().int().min(0),
6637
+ semanticClass: SalesStageSemanticClassSchema,
6638
+ surfaceIds: ReferenceIdsSchema,
6639
+ resourceIds: ReferenceIdsSchema
6640
+ });
6641
+ var SalesPipelineSchema = z.object({
6642
+ id: ModelIdSchema,
6643
+ label: z.string().trim().min(1).max(120),
6644
+ description: DescriptionSchema.optional(),
6645
+ entityId: ModelIdSchema,
6646
+ stages: z.array(SalesStageSchema).min(1)
6647
+ });
6648
+ z.object({
6649
+ entityId: ModelIdSchema,
6650
+ defaultPipelineId: ModelIdSchema,
6651
+ pipelines: z.array(SalesPipelineSchema).min(1)
6652
+ });
6653
+ var CRM_DISCOVERY_REPLIED_STATE = {
6654
+ stateKey: "discovery_replied",
6655
+ label: "Discovery Replied"
6656
+ };
6657
+ var CRM_DISCOVERY_LINK_SENT_STATE = {
6658
+ stateKey: "discovery_link_sent",
6659
+ label: "Discovery Link Sent"
6660
+ };
6661
+ var CRM_DISCOVERY_NUDGING_STATE = {
6662
+ stateKey: "discovery_nudging",
6663
+ label: "Discovery Nudging"
6664
+ };
6665
+ var CRM_DISCOVERY_BOOKING_CANCELLED_STATE = {
6666
+ stateKey: "discovery_booking_cancelled",
6667
+ label: "Discovery Booking Cancelled"
6668
+ };
6669
+ var CRM_REPLY_SENT_STATE = {
6670
+ stateKey: "reply_sent",
6671
+ label: "Reply Sent"
6672
+ };
6673
+ var CRM_FOLLOWUP_1_SENT_STATE = {
6674
+ stateKey: "followup_1_sent",
6675
+ label: "Follow-up 1 Sent"
6676
+ };
6677
+ var CRM_FOLLOWUP_2_SENT_STATE = {
6678
+ stateKey: "followup_2_sent",
6679
+ label: "Follow-up 2 Sent"
6680
+ };
6681
+ var CRM_FOLLOWUP_3_SENT_STATE = {
6682
+ stateKey: "followup_3_sent",
6683
+ label: "Follow-up 3 Sent"
6684
+ };
6685
+ var CRM_PIPELINE_DEFINITION = {
6686
+ pipelineKey: "crm",
6687
+ stages: [
6688
+ {
6689
+ stageKey: "interested",
6690
+ label: "Interested",
6691
+ color: "blue",
6692
+ states: [
6693
+ CRM_DISCOVERY_REPLIED_STATE,
6694
+ CRM_DISCOVERY_LINK_SENT_STATE,
6695
+ CRM_DISCOVERY_NUDGING_STATE,
6696
+ CRM_DISCOVERY_BOOKING_CANCELLED_STATE,
6697
+ CRM_REPLY_SENT_STATE,
6698
+ CRM_FOLLOWUP_1_SENT_STATE,
6699
+ CRM_FOLLOWUP_2_SENT_STATE,
6700
+ CRM_FOLLOWUP_3_SENT_STATE
6701
+ ]
6702
+ },
6703
+ { stageKey: "proposal", label: "Proposal", color: "yellow", states: [] },
6704
+ { stageKey: "closing", label: "Closing", color: "orange", states: [] },
6705
+ { stageKey: "closed_won", label: "Closed Won", color: "green", states: [] },
6706
+ { stageKey: "closed_lost", label: "Closed Lost", color: "red", states: [] },
6707
+ { stageKey: "nurturing", label: "Nurturing", color: "grape", states: [] }
6708
+ ]
6709
+ };
6710
+ var LEAD_GEN_STAGE_CATALOG = {
6711
+ // Prospecting — company population
6712
+ scraped: {
6713
+ key: "scraped",
6714
+ label: "Scraped",
6715
+ description: "Company was scraped from a source directory (Apify actor run).",
6716
+ order: 1,
6717
+ entity: "company"
6718
+ },
6719
+ populated: {
6720
+ key: "populated",
6721
+ label: "Companies found",
6722
+ description: "Companies have been found and added to the lead-gen list.",
6723
+ order: 2,
6724
+ entity: "company"
6725
+ },
6726
+ extracted: {
6727
+ key: "extracted",
6728
+ label: "Websites analyzed",
6729
+ description: "Company websites have been analyzed for business signals.",
6730
+ order: 3,
6731
+ entity: "company"
6732
+ },
6733
+ enriched: {
6734
+ key: "enriched",
6735
+ label: "Enriched",
6736
+ description: "Company or contact enriched with third-party data (e.g. Tomba, Anymailfinder).",
6737
+ order: 4,
6738
+ entity: "company"
6739
+ },
6740
+ "decision-makers-enriched": {
6741
+ key: "decision-makers-enriched",
6742
+ label: "Decision-makers found",
6743
+ description: "Decision-maker contacts discovered and attached to a qualified company.",
6744
+ order: 6,
6745
+ entity: "company"
6746
+ },
6747
+ // Prospecting — contact discovery
6748
+ discovered: {
6749
+ key: "discovered",
6750
+ label: "Decision-makers found",
6751
+ description: "Decision-maker contact details have been found.",
6752
+ order: 5,
6753
+ entity: "contact"
6754
+ },
6755
+ verified: {
6756
+ key: "verified",
6757
+ label: "Emails verified",
6758
+ description: "Contact email addresses have been checked for deliverability.",
6759
+ order: 7,
6760
+ entity: "contact"
6761
+ },
6762
+ // Qualification
6763
+ qualified: {
6764
+ key: "qualified",
6765
+ label: "Companies qualified",
6766
+ description: "Companies have been scored against the qualification criteria.",
6767
+ order: 8,
6768
+ entity: "company"
6769
+ },
6770
+ // Outreach
6771
+ personalized: {
6772
+ key: "personalized",
6773
+ label: "Personalized",
6774
+ description: "Outreach message personalized for the contact (Instantly personalization workflow).",
6775
+ order: 9,
6776
+ entity: "contact"
6777
+ },
6778
+ uploaded: {
6779
+ key: "uploaded",
6780
+ label: "Reviewed and exported",
6781
+ description: "Approved records have been reviewed and exported for handoff.",
6782
+ order: 10,
6783
+ entity: "contact"
6784
+ },
6785
+ interested: {
6786
+ key: "interested",
6787
+ label: "Interested",
6788
+ description: "Contact replied with a positive signal (Instantly reply-handler transition).",
6789
+ order: 11,
6790
+ entity: "contact"
6791
+ }
6792
+ };
6793
+
6794
+ // ../core/src/organization-model/domains/prospecting.ts
6795
+ var ProspectingLifecycleStageSchema = DisplayMetadataSchema.extend({
6796
+ id: ModelIdSchema,
6797
+ order: z.number().int().min(0)
6798
+ });
6799
+ var ProspectingBuildTemplateStepSchema = DisplayMetadataSchema.extend({
6800
+ id: ModelIdSchema,
6801
+ primaryEntity: z.enum(["company", "contact"]),
6802
+ outputs: z.array(z.enum(["company", "contact", "export"])).min(1),
6803
+ stageKey: ModelIdSchema,
6804
+ dependsOn: z.array(ModelIdSchema).optional(),
6805
+ dependencyMode: z.literal("per-record-eligibility"),
6806
+ capabilityKey: ModelIdSchema,
6807
+ defaultBatchSize: z.number().int().positive(),
6808
+ maxBatchSize: z.number().int().positive()
6809
+ }).refine((step) => step.defaultBatchSize <= step.maxBatchSize, {
6810
+ message: "defaultBatchSize must be less than or equal to maxBatchSize",
6811
+ path: ["defaultBatchSize"]
6812
+ });
6813
+ var ProspectingBuildTemplateSchema = DisplayMetadataSchema.extend({
6814
+ id: ModelIdSchema,
6815
+ steps: z.array(ProspectingBuildTemplateStepSchema).min(1)
6816
+ });
6817
+ z.object({
6818
+ id: ModelIdSchema,
6819
+ label: z.string(),
6820
+ description: z.string(),
6821
+ resourceId: ModelIdSchema
6822
+ });
6823
+ var CAPABILITY_REGISTRY = [
6824
+ {
6825
+ id: "lead-gen.company.source",
6826
+ label: "Source companies",
6827
+ description: "Import source companies from a list provider.",
6828
+ resourceId: "lgn-import-workflow"
6829
+ },
6830
+ {
6831
+ id: "lead-gen.company.apollo-import",
6832
+ label: "Import from Apollo",
6833
+ description: "Pull companies and seed contact data from an Apollo search or list.",
6834
+ resourceId: "lgn-01c-apollo-import-workflow"
6835
+ },
6836
+ {
6837
+ id: "lead-gen.contact.discover",
6838
+ label: "Discover contact emails",
6839
+ description: "Find email addresses for contacts at qualified companies.",
6840
+ resourceId: "lgn-04-email-discovery-workflow"
6841
+ },
6842
+ {
6843
+ id: "lead-gen.contact.verify-email",
6844
+ label: "Verify emails",
6845
+ description: "Check email deliverability before outreach.",
6846
+ resourceId: "lgn-05-email-verification-workflow"
6847
+ },
6848
+ {
6849
+ id: "lead-gen.company.website-extract",
6850
+ label: "Extract website signals",
6851
+ description: "Scrape and analyze company websites for qualification signals.",
6852
+ resourceId: "lgn-02-website-extract-workflow"
6853
+ },
6854
+ {
6855
+ id: "lead-gen.company.qualify",
6856
+ label: "Qualify companies",
6857
+ description: "Score and filter companies against the ICP rubric.",
6858
+ resourceId: "lgn-03-company-qualification-workflow"
6859
+ },
6860
+ {
6861
+ id: "lead-gen.company.dtc-subscription-qualify",
6862
+ label: "Qualify DTC subscription fit",
6863
+ description: "Classify subscription potential and consumable-product fit for DTC brands.",
6864
+ resourceId: "lgn-03b-dtc-subscription-score-workflow"
6865
+ },
6866
+ {
6867
+ id: "lead-gen.contact.apollo-decision-maker-enrich",
6868
+ label: "Enrich decision-makers",
6869
+ description: "Find and enrich qualified contacts at qualified companies via Apollo.",
6870
+ resourceId: "lgn-04b-apollo-decision-maker-enrich-workflow"
6871
+ },
6872
+ {
6873
+ id: "lead-gen.contact.personalize",
6874
+ label: "Personalize outreach",
6875
+ description: "Generate personalized opening lines for each contact.",
6876
+ resourceId: "ist-personalization-workflow"
6877
+ },
6878
+ {
6879
+ id: "lead-gen.review.outreach-ready",
6880
+ label: "Upload to outreach",
6881
+ description: "Upload approved contacts to the outreach sequence after QC review.",
6882
+ resourceId: "ist-upload-contacts-workflow"
6883
+ },
6884
+ {
6885
+ id: "lead-gen.export.list",
6886
+ label: "Export lead list",
6887
+ description: "Export approved leads as a downloadable lead list.",
6888
+ resourceId: "lgn-06-export-list-workflow"
6889
+ },
6890
+ {
6891
+ id: "lead-gen.company.cleanup",
6892
+ label: "Clean up companies",
6893
+ description: "Remove disqualified or duplicate companies from the list.",
6894
+ resourceId: "lgn-company-cleanup-workflow"
6895
+ }
6896
+ ];
6897
+ var PROSPECTING_STEPS = {
6898
+ localServices: {
6899
+ sourceCompanies: {
6900
+ id: "source-companies",
6901
+ label: "Companies found",
6902
+ primaryEntity: "company",
6903
+ outputs: ["company"],
6904
+ stageKey: "populated",
6905
+ dependencyMode: "per-record-eligibility",
6906
+ capabilityKey: "lead-gen.company.source",
6907
+ defaultBatchSize: 100,
6908
+ maxBatchSize: 250
6909
+ },
6910
+ analyzeWebsites: {
6911
+ id: "analyze-websites",
6912
+ label: "Websites analyzed",
6913
+ primaryEntity: "company",
6914
+ outputs: ["company"],
6915
+ stageKey: "extracted",
6916
+ dependsOn: ["source-companies"],
6917
+ dependencyMode: "per-record-eligibility",
6918
+ capabilityKey: "lead-gen.company.website-extract",
6919
+ defaultBatchSize: 50,
6920
+ maxBatchSize: 100
6921
+ },
6922
+ qualifyCompanies: {
6923
+ id: "qualify-companies",
6924
+ label: "Companies qualified",
6925
+ primaryEntity: "company",
6926
+ outputs: ["company"],
6927
+ stageKey: "qualified",
6928
+ dependsOn: ["analyze-websites"],
6929
+ dependencyMode: "per-record-eligibility",
6930
+ capabilityKey: "lead-gen.company.qualify",
6931
+ defaultBatchSize: 100,
6932
+ maxBatchSize: 250
6933
+ },
6934
+ findContacts: {
6935
+ id: "find-contacts",
6936
+ label: "Decision-makers found",
6937
+ primaryEntity: "contact",
6938
+ outputs: ["contact"],
6939
+ stageKey: "discovered",
6940
+ dependsOn: ["qualify-companies"],
6941
+ dependencyMode: "per-record-eligibility",
6942
+ capabilityKey: "lead-gen.contact.discover",
6943
+ defaultBatchSize: 50,
6944
+ maxBatchSize: 100
6945
+ },
6946
+ verifyEmails: {
6947
+ id: "verify-emails",
6948
+ label: "Emails verified",
6949
+ primaryEntity: "contact",
6950
+ outputs: ["contact"],
6951
+ stageKey: "verified",
6952
+ dependsOn: ["find-contacts"],
6953
+ dependencyMode: "per-record-eligibility",
6954
+ capabilityKey: "lead-gen.contact.verify-email",
6955
+ defaultBatchSize: 100,
6956
+ maxBatchSize: 500
6957
+ },
6958
+ personalize: {
6959
+ id: "personalize",
6960
+ label: "Personalize",
6961
+ primaryEntity: "contact",
6962
+ outputs: ["contact"],
6963
+ stageKey: "personalized",
6964
+ dependsOn: ["verify-emails"],
6965
+ dependencyMode: "per-record-eligibility",
6966
+ capabilityKey: "lead-gen.contact.personalize",
6967
+ defaultBatchSize: 25,
6968
+ maxBatchSize: 100
6969
+ },
6970
+ review: {
6971
+ id: "review",
6972
+ label: "Reviewed and exported",
6973
+ primaryEntity: "contact",
6974
+ outputs: ["export"],
6975
+ stageKey: "uploaded",
6976
+ dependsOn: ["personalize"],
6977
+ dependencyMode: "per-record-eligibility",
6978
+ capabilityKey: "lead-gen.review.outreach-ready",
6979
+ defaultBatchSize: 25,
6980
+ maxBatchSize: 100
6981
+ }
6982
+ },
6983
+ dtcApolloClickup: {
6984
+ importApolloSearch: {
6985
+ id: "import-apollo-search",
6986
+ label: "Companies found",
6987
+ description: "Pull companies and seed contact data from a predefined Apollo search or list.",
6988
+ primaryEntity: "company",
6989
+ outputs: ["company", "contact"],
6990
+ stageKey: "populated",
6991
+ dependencyMode: "per-record-eligibility",
6992
+ capabilityKey: "lead-gen.company.apollo-import",
6993
+ defaultBatchSize: 250,
6994
+ maxBatchSize: 1e3
6995
+ },
6996
+ analyzeWebsites: {
6997
+ id: "analyze-websites",
6998
+ label: "Websites analyzed",
6999
+ description: "Extract subscription, product, retention, and tech-stack signals from each brand website.",
7000
+ primaryEntity: "company",
7001
+ outputs: ["company"],
7002
+ stageKey: "extracted",
7003
+ dependsOn: ["import-apollo-search"],
7004
+ dependencyMode: "per-record-eligibility",
7005
+ capabilityKey: "lead-gen.company.website-extract",
7006
+ defaultBatchSize: 50,
7007
+ maxBatchSize: 100
7008
+ },
7009
+ scoreDtcFit: {
7010
+ id: "score-dtc-fit",
7011
+ label: "Companies qualified",
7012
+ description: "Classify subscription potential, consumable-product fit, retention maturity, and disqualifiers.",
7013
+ primaryEntity: "company",
7014
+ outputs: ["company"],
7015
+ stageKey: "qualified",
7016
+ dependsOn: ["analyze-websites"],
7017
+ dependencyMode: "per-record-eligibility",
7018
+ capabilityKey: "lead-gen.company.dtc-subscription-qualify",
7019
+ defaultBatchSize: 100,
7020
+ maxBatchSize: 250
7021
+ },
7022
+ enrichDecisionMakers: {
7023
+ id: "enrich-decision-makers",
7024
+ label: "Decision-makers found",
7025
+ description: "Use Apollo to find qualified contacts at qualified companies - founders, retention leads, lifecycle leads, and marketing owners.",
7026
+ primaryEntity: "company",
7027
+ outputs: ["contact"],
7028
+ stageKey: "decision-makers-enriched",
7029
+ dependsOn: ["score-dtc-fit"],
7030
+ dependencyMode: "per-record-eligibility",
7031
+ capabilityKey: "lead-gen.contact.apollo-decision-maker-enrich",
7032
+ defaultBatchSize: 100,
7033
+ maxBatchSize: 250
7034
+ },
7035
+ verifyEmails: {
7036
+ id: "verify-emails",
7037
+ label: "Emails verified",
7038
+ description: "Verify deliverability before the QC and handoff step.",
7039
+ primaryEntity: "contact",
7040
+ outputs: ["contact"],
7041
+ stageKey: "verified",
7042
+ dependsOn: ["enrich-decision-makers"],
7043
+ dependencyMode: "per-record-eligibility",
7044
+ capabilityKey: "lead-gen.contact.verify-email",
7045
+ defaultBatchSize: 250,
7046
+ maxBatchSize: 500
7047
+ },
7048
+ reviewAndExport: {
7049
+ id: "review-and-export",
7050
+ label: "Reviewed and exported",
7051
+ description: "Operator QC approves or rejects leads, then approved records are exported as a lead list.",
7052
+ primaryEntity: "company",
7053
+ outputs: ["export"],
7054
+ stageKey: "uploaded",
7055
+ dependsOn: ["verify-emails"],
7056
+ dependencyMode: "per-record-eligibility",
7057
+ capabilityKey: "lead-gen.export.list",
7058
+ defaultBatchSize: 100,
7059
+ maxBatchSize: 250
7060
+ }
7061
+ }
7062
+ };
7063
+ z.object({
7064
+ listEntityId: ModelIdSchema,
7065
+ companyEntityId: ModelIdSchema,
7066
+ contactEntityId: ModelIdSchema,
7067
+ description: DescriptionSchema.optional(),
7068
+ companyStages: z.array(ProspectingLifecycleStageSchema).min(1),
7069
+ contactStages: z.array(ProspectingLifecycleStageSchema).min(1),
7070
+ defaultBuildTemplateId: ModelIdSchema,
7071
+ buildTemplates: z.array(ProspectingBuildTemplateSchema).min(1)
7072
+ });
7073
+ function toProspectingLifecycleStage(stage) {
7074
+ return {
7075
+ id: stage.key,
7076
+ label: stage.label,
7077
+ order: stage.order
7078
+ };
7079
+ }
7080
+ function leadGenStagesForEntity(entity) {
7081
+ return Object.values(LEAD_GEN_STAGE_CATALOG).filter((stage) => stage.entity === entity).sort((a3, b2) => a3.order - b2.order).map(toProspectingLifecycleStage);
7082
+ }
7083
+ var DEFAULT_ORGANIZATION_MODEL_PROSPECTING = {
7084
+ companyStages: leadGenStagesForEntity("company"),
7085
+ contactStages: leadGenStagesForEntity("contact"),
7086
+ buildTemplates: [
7087
+ {
7088
+ id: "local-services",
7089
+ label: "Local Services Prospecting",
7090
+ description: "Curated local-services list build using company sourcing, website analysis, qualification, contact discovery, verification, personalization, and review.",
7091
+ steps: [
7092
+ PROSPECTING_STEPS.localServices.sourceCompanies,
7093
+ PROSPECTING_STEPS.localServices.analyzeWebsites,
7094
+ PROSPECTING_STEPS.localServices.qualifyCompanies,
7095
+ PROSPECTING_STEPS.localServices.findContacts,
7096
+ PROSPECTING_STEPS.localServices.verifyEmails,
7097
+ PROSPECTING_STEPS.localServices.personalize,
7098
+ PROSPECTING_STEPS.localServices.review
7099
+ ]
7100
+ },
7101
+ {
7102
+ id: "dtc-subscription-apollo-clickup",
7103
+ label: "DTC Subscription Apollo Export",
7104
+ description: "Prospecting pipeline for DTC subscription or subscription-ready brands where Apollo is the source and contact-enrichment layer, Elevasis handles company research and fit scoring, and approved leads export as an approved lead list.",
7105
+ steps: [
7106
+ PROSPECTING_STEPS.dtcApolloClickup.importApolloSearch,
7107
+ PROSPECTING_STEPS.dtcApolloClickup.analyzeWebsites,
7108
+ PROSPECTING_STEPS.dtcApolloClickup.scoreDtcFit,
7109
+ PROSPECTING_STEPS.dtcApolloClickup.enrichDecisionMakers,
7110
+ PROSPECTING_STEPS.dtcApolloClickup.verifyEmails,
7111
+ PROSPECTING_STEPS.dtcApolloClickup.reviewAndExport
7112
+ ]
7113
+ }
7114
+ ]
7115
+ };
7116
+
7117
+ // ../core/src/business/acquisition/build-templates.ts
7118
+ var PROSPECTING_BUILD_TEMPLATE_OPTIONS = DEFAULT_ORGANIZATION_MODEL_PROSPECTING.buildTemplates.map(
7119
+ ({ id, label, description }) => ({
7120
+ id,
7121
+ label,
7122
+ description
7123
+ })
7124
+ );
7125
+ function isProspectingBuildTemplateId(value) {
7126
+ return PROSPECTING_BUILD_TEMPLATE_OPTIONS.some((template) => template.id === value);
7127
+ }
7128
+ var ProcessingStageStatusSchema = z.enum(["success", "no_result", "skipped", "error"]);
7129
+ var LeadGenStageKeySchema = z.string().refine((value) => Object.prototype.hasOwnProperty.call(LEAD_GEN_STAGE_CATALOG, value), {
7130
+ message: "processing state key must match LEAD_GEN_STAGE_CATALOG"
7131
+ });
7132
+ var LeadGenCapabilityKeySchema = z.string().refine((value) => CAPABILITY_REGISTRY.some((c) => c.id === value), {
7133
+ message: "capabilityKey must match CAPABILITY_REGISTRY"
7134
+ });
7135
+ var crmStageKeys = CRM_PIPELINE_DEFINITION.stages.map((stage) => stage.stageKey);
7136
+ var crmStateKeys = CRM_PIPELINE_DEFINITION.stages.flatMap((stage) => stage.states.map((state) => state.stateKey));
7137
+ var CrmStageKeySchema = z.enum(crmStageKeys);
7138
+ var CrmStateKeySchema = z.enum(crmStateKeys);
7139
+ var ProcessingStateEntrySchema = z.object({
7140
+ status: ProcessingStageStatusSchema,
7141
+ data: z.unknown().optional()
7142
+ }).passthrough();
7143
+ var ProcessingStateSchema = z.record(LeadGenStageKeySchema, ProcessingStateEntrySchema);
7144
+ var CompanyProcessingStateSchema = ProcessingStateSchema;
7145
+ var ContactProcessingStateSchema = ProcessingStateSchema;
7146
+ var DealStageSchema = CrmStageKeySchema;
7147
+ var AcqDealTaskKindSchema = z.enum(["call", "email", "meeting", "other"]);
7148
+ z.object({
7149
+ dealId: UuidSchema
7150
+ });
7151
+ z.object({
7152
+ dealId: UuidSchema,
7153
+ taskId: UuidSchema
7154
+ });
7155
+ z.object({
7156
+ stage: DealStageSchema.optional(),
7157
+ search: z.string().optional(),
7158
+ limit: z.coerce.number().int().positive().default(50),
7159
+ offset: z.coerce.number().int().min(0).default(0)
7160
+ }).strict();
7161
+ z.object({
7162
+ search: z.string().trim().min(1).max(200).optional(),
7163
+ limit: z.coerce.number().int().min(1).max(25).default(10)
7164
+ }).strict();
7165
+ z.object({
7166
+ window: z.enum(["overdue", "today", "today_and_overdue", "upcoming"]).optional(),
7167
+ assigneeUserId: UuidSchema.optional()
7168
+ }).strict();
7169
+ z.object({
7170
+ body: z.string().trim().min(1).max(1e4)
7171
+ }).strict();
7172
+ z.object({
7173
+ title: z.string().trim().min(1).max(255),
7174
+ description: z.string().nullable().optional(),
7175
+ kind: AcqDealTaskKindSchema.optional(),
7176
+ dueAt: z.string().datetime().nullable().optional(),
7177
+ assigneeUserId: UuidSchema.nullable().optional()
7178
+ }).strict();
7179
+ z.object({
7180
+ pipelineKey: z.string().min(1),
7181
+ stageKey: z.string().min(1),
7182
+ stateKey: z.string().min(1).nullable().optional(),
7183
+ reason: z.string().optional(),
7184
+ expectedUpdatedAt: z.string().datetime().optional()
7185
+ }).strict();
7186
+ z.object({
7187
+ pipelineKey: z.literal(CRM_PIPELINE_DEFINITION.pipelineKey),
7188
+ stageKey: CrmStageKeySchema,
7189
+ stateKey: CrmStateKeySchema.nullable().optional(),
7190
+ reason: z.string().optional(),
7191
+ expectedUpdatedAt: z.string().datetime().optional()
7192
+ }).strict();
7193
+ z.object({
7194
+ stateKey: CrmStateKeySchema,
7195
+ reason: z.string().optional(),
7196
+ expectedUpdatedAt: z.string().datetime().optional()
7197
+ }).strict();
7198
+ z.object({
7199
+ dealId: UuidSchema,
7200
+ actionKey: NonEmptyStringSchema
7201
+ }).strict();
7202
+ z.object({
7203
+ payload: z.record(z.string(), z.unknown()).optional()
7204
+ }).strict();
7205
+ var DealContactSummarySchema = z.object({
7206
+ id: z.string(),
7207
+ first_name: z.string().nullable(),
7208
+ last_name: z.string().nullable(),
7209
+ email: z.string(),
7210
+ title: z.string().nullable(),
7211
+ headline: z.string().nullable(),
7212
+ linkedin_url: z.string().nullable(),
7213
+ processing_state: ProcessingStateSchema.nullable(),
7214
+ enrichment_data: z.record(z.string(), z.unknown()).nullable(),
7215
+ company: z.object({
7216
+ id: z.string(),
7217
+ name: z.string(),
7218
+ domain: z.string().nullable(),
7219
+ website: z.string().nullable(),
7220
+ linkedin_url: z.string().nullable(),
7221
+ segment: z.string().nullable(),
7222
+ category: z.string().nullable(),
7223
+ num_employees: z.number().nullable()
7224
+ }).nullable()
7225
+ });
7226
+ var DealPrioritySchema = z.object({
7227
+ bucketKey: z.enum(["needs_response", "follow_up_due", "waiting", "stale", "closed_low"]),
7228
+ rank: z.number().int(),
7229
+ label: z.string(),
7230
+ color: z.string(),
7231
+ reason: z.string(),
7232
+ latestActivityAt: z.string().nullable(),
7233
+ nextActionAt: z.string().nullable()
7234
+ });
7235
+ var DealListItemSchema = z.object({
7236
+ // acq_deals columns
7237
+ id: z.string(),
7238
+ organization_id: z.string(),
7239
+ contact_id: z.string().nullable(),
7240
+ contact_email: z.string(),
7241
+ pipeline_key: z.string(),
7242
+ stage_key: z.string().nullable(),
7243
+ state_key: z.string().nullable(),
7244
+ activity_log: z.unknown(),
7245
+ discovery_data: z.unknown().nullable(),
7246
+ discovery_submitted_at: z.string().nullable(),
7247
+ discovery_submitted_by: z.string().nullable(),
7248
+ proposal_data: z.unknown().nullable(),
7249
+ proposal_sent_at: z.string().nullable(),
7250
+ proposal_pdf_url: z.string().nullable(),
7251
+ signature_envelope_id: z.string().nullable(),
7252
+ source_list_id: z.string().nullable(),
7253
+ source_type: z.string().nullable(),
7254
+ initial_fee: z.number().nullable(),
7255
+ monthly_fee: z.number().nullable(),
7256
+ closed_lost_at: z.string().nullable(),
7257
+ closed_lost_reason: z.string().nullable(),
7258
+ created_at: z.string(),
7259
+ updated_at: z.string(),
7260
+ priority: DealPrioritySchema,
7261
+ ownership: z.enum(["us", "them"]).nullable(),
7262
+ nextAction: z.string().nullable(),
7263
+ // joined relation
7264
+ contact: DealContactSummarySchema.nullable()
7265
+ });
7266
+ z.object({
7267
+ data: z.array(DealListItemSchema),
7268
+ total: z.number().int(),
7269
+ limit: z.number().int(),
7270
+ offset: z.number().int()
7271
+ });
7272
+ var DealStageSummarySchema = z.object({
7273
+ stage: z.string(),
7274
+ count: z.number().int(),
7275
+ totalValue: z.number(),
7276
+ oldestUpdatedAt: z.string().nullable(),
7277
+ newestUpdatedAt: z.string().nullable()
7278
+ });
7279
+ var StaleDealSummarySchema = z.object({
7280
+ id: z.string(),
7281
+ contactEmail: z.string(),
7282
+ stageKey: z.string(),
7283
+ updatedAt: z.string(),
7284
+ daysStale: z.number().int()
7285
+ });
7286
+ z.object({
7287
+ totalDeals: z.number().int(),
7288
+ openDeals: z.number().int(),
7289
+ wonDeals: z.number().int(),
7290
+ lostDeals: z.number().int(),
7291
+ winRate: z.number(),
7292
+ avgDealSize: z.number(),
7293
+ totalPipelineValue: z.number(),
7294
+ stageSummary: z.array(DealStageSummarySchema),
7295
+ staleDeals: z.array(StaleDealSummarySchema)
7296
+ });
7297
+ var DealLookupItemSchema = z.object({
7298
+ id: z.string(),
7299
+ contactEmail: z.string(),
7300
+ stageKey: z.string().nullable(),
7301
+ updatedAt: z.string(),
7302
+ contactName: z.string().nullable(),
7303
+ companyName: z.string().nullable(),
7304
+ displayLabel: z.string()
7305
+ });
7306
+ z.array(DealLookupItemSchema);
7307
+ var ConversationMessageSchema = z.object({
7308
+ id: z.string(),
7309
+ direction: z.enum(["inbound", "outbound"]),
7310
+ fromEmail: z.string(),
7311
+ toEmail: z.string(),
7312
+ subject: z.string().nullable(),
7313
+ body: z.string(),
7314
+ sentAt: z.string().nullable()
7315
+ });
7316
+ var DealConversationSchema = z.object({
7317
+ messages: z.array(ConversationMessageSchema)
7318
+ });
7319
+ DealListItemSchema.extend({
7320
+ conversation: DealConversationSchema
7321
+ });
7322
+ var DealNoteResponseSchema = z.object({
7323
+ id: z.string(),
7324
+ dealId: z.string(),
7325
+ organizationId: z.string(),
7326
+ authorUserId: z.string().nullable(),
7327
+ body: z.string(),
7328
+ createdAt: z.string(),
7329
+ updatedAt: z.string()
7330
+ });
7331
+ z.array(DealNoteResponseSchema);
7332
+ var DealTaskResponseSchema = z.object({
7333
+ id: z.string(),
7334
+ organizationId: z.string(),
7335
+ dealId: z.string(),
7336
+ title: z.string(),
7337
+ description: z.string().nullable(),
7338
+ kind: AcqDealTaskKindSchema,
7339
+ dueAt: z.string().nullable(),
7340
+ assigneeUserId: z.string().nullable(),
7341
+ completedAt: z.string().nullable(),
7342
+ completedByUserId: z.string().nullable(),
7343
+ createdAt: z.string(),
7344
+ updatedAt: z.string(),
7345
+ createdByUserId: z.string().nullable()
7346
+ });
7347
+ z.array(DealTaskResponseSchema);
7348
+ var ListStatusSchema = z.enum(["draft", "enriching", "launched", "closing", "archived"]);
7349
+ var ScrapingConfigSchema = z.object({
7350
+ vertical: z.string().trim().max(255).optional(),
7351
+ geography: z.string().trim().max(500).optional(),
7352
+ size: z.string().trim().max(255).optional(),
7353
+ apifyInput: z.record(z.string(), z.unknown()).optional()
7354
+ });
7355
+ var IcpRubricSchema = z.object({
7356
+ qualificationRubricKey: z.string().trim().max(255).nullish(),
7357
+ targetDescription: z.string().optional(),
7358
+ minReviewCount: z.number().int().min(0).optional(),
7359
+ minRating: z.number().min(0).max(5).optional(),
7360
+ excludeFranchises: z.boolean().optional(),
7361
+ customRules: z.string().optional()
7362
+ });
7363
+ var PipelineStageSchema = z.object({
7364
+ key: z.string().refine((value) => Object.prototype.hasOwnProperty.call(LEAD_GEN_STAGE_CATALOG, value), {
7365
+ message: "pipeline stage key must match LEAD_GEN_STAGE_CATALOG"
7366
+ }),
7367
+ label: z.string().optional(),
7368
+ enabled: z.boolean().optional(),
7369
+ order: z.number().int().optional()
7370
+ });
7371
+ var PipelineConfigSchema = z.object({
7372
+ stages: z.array(PipelineStageSchema).optional()
7373
+ });
7374
+ var BuildPlanSnapshotStepSchema = z.object({
7375
+ id: z.string().trim().min(1).max(100),
7376
+ label: z.string().trim().min(1).max(120),
7377
+ description: z.string().trim().min(1).max(2e3).optional(),
7378
+ primaryEntity: z.enum(["company", "contact"]),
7379
+ outputs: z.array(z.enum(["company", "contact", "export"])).min(1),
7380
+ stageKey: LeadGenStageKeySchema,
7381
+ dependsOn: z.array(z.string().trim().min(1).max(100)).optional(),
7382
+ dependencyMode: z.literal("per-record-eligibility"),
7383
+ capabilityKey: LeadGenCapabilityKeySchema,
7384
+ defaultBatchSize: z.number().int().positive(),
7385
+ maxBatchSize: z.number().int().positive()
7386
+ }).refine((step) => step.defaultBatchSize <= step.maxBatchSize, {
7387
+ message: "defaultBatchSize must be less than or equal to maxBatchSize",
7388
+ path: ["defaultBatchSize"]
7389
+ });
7390
+ var BuildPlanSnapshotSchema = z.object({
7391
+ templateId: z.string().trim().min(1).max(100),
7392
+ templateLabel: z.string().trim().min(1).max(120),
7393
+ steps: z.array(BuildPlanSnapshotStepSchema).min(1)
7394
+ }).superRefine((snapshot, ctx) => {
7395
+ const stepIds = /* @__PURE__ */ new Set();
7396
+ snapshot.steps.forEach((step, index2) => {
7397
+ if (stepIds.has(step.id)) {
7398
+ ctx.addIssue({
7399
+ code: z.ZodIssueCode.custom,
7400
+ message: `duplicate build-plan step id "${step.id}"`,
7401
+ path: ["steps", index2, "id"]
7402
+ });
7403
+ }
7404
+ stepIds.add(step.id);
7405
+ });
7406
+ snapshot.steps.forEach((step, index2) => {
7407
+ for (const dependencyId of step.dependsOn ?? []) {
7408
+ if (!stepIds.has(dependencyId)) {
7409
+ ctx.addIssue({
7410
+ code: z.ZodIssueCode.custom,
7411
+ message: `dependsOn references unknown build-plan step "${dependencyId}"`,
7412
+ path: ["steps", index2, "dependsOn"]
7413
+ });
7414
+ }
7415
+ }
7416
+ });
7417
+ });
7418
+ var AcqListMetadataSchema = z.object({
7419
+ buildPlanSnapshot: BuildPlanSnapshotSchema.optional()
7420
+ }).catchall(z.unknown());
7421
+ var ProspectingBuildTemplateIdSchema = z.string().trim().min(1).max(100).refine(isProspectingBuildTemplateId, {
7422
+ message: "buildTemplateId must match a known prospecting build template"
7423
+ });
7424
+ var ListStageCountsSchema = z.object({
7425
+ // Attempted counts by canonical lead-gen stage. The detailed status
7426
+ // distribution lives on ListProgress; telemetry keeps the overview payload small.
7427
+ stageCounts: z.object({
7428
+ populated: z.number().int(),
7429
+ extracted: z.number().int(),
7430
+ qualified: z.number().int(),
7431
+ discovered: z.number().int(),
7432
+ verified: z.number().int(),
7433
+ personalized: z.number().int(),
7434
+ uploaded: z.number().int()
7435
+ }),
7436
+ deliverability: z.object({
7437
+ valid: z.number().int(),
7438
+ risky: z.number().int(),
7439
+ invalid: z.number().int(),
7440
+ unknown: z.number().int(),
7441
+ bounced: z.number().int()
7442
+ })
7443
+ });
7444
+ var ListTelemetrySchema = z.object({
7445
+ listId: UuidSchema,
7446
+ totalCompanies: z.number().int(),
7447
+ totalContacts: z.number().int(),
7448
+ stageCounts: ListStageCountsSchema.shape.stageCounts,
7449
+ deliverability: ListStageCountsSchema.shape.deliverability,
7450
+ activeWorkflows: z.array(z.string()).optional()
7451
+ });
7452
+ z.object({
7453
+ listId: UuidSchema
7454
+ });
7455
+ z.object({
7456
+ name: z.string().trim().min(1).max(255),
7457
+ description: z.string().trim().nullable().optional(),
7458
+ status: ListStatusSchema.optional(),
7459
+ buildTemplateId: ProspectingBuildTemplateIdSchema.optional(),
7460
+ scrapingConfig: ScrapingConfigSchema.optional(),
7461
+ icp: IcpRubricSchema.optional(),
7462
+ pipelineConfig: PipelineConfigSchema.optional()
7463
+ }).strict();
7464
+ z.object({
7465
+ name: z.string().trim().min(1).max(255).optional(),
7466
+ description: z.string().trim().nullable().optional(),
7467
+ batchIds: z.array(z.string()).optional(),
7468
+ buildTemplateId: ProspectingBuildTemplateIdSchema.optional(),
7469
+ confirmBuildTemplateChange: z.literal(true).optional()
7470
+ }).strict().refine(
7471
+ (data) => data.name !== void 0 || data.description !== void 0 || data.batchIds !== void 0 || data.buildTemplateId !== void 0,
7472
+ {
7473
+ message: "At least one field (name, description, batchIds, or buildTemplateId) must be provided"
7474
+ }
7475
+ ).refine((data) => data.buildTemplateId === void 0 || data.confirmBuildTemplateChange === true, {
7476
+ message: "confirmBuildTemplateChange must be true when changing buildTemplateId",
7477
+ path: ["confirmBuildTemplateChange"]
7478
+ });
7479
+ z.object({
7480
+ status: ListStatusSchema
7481
+ }).strict();
7482
+ z.object({
7483
+ scrapingConfig: ScrapingConfigSchema.partial().optional(),
7484
+ icp: IcpRubricSchema.partial().optional(),
7485
+ pipelineConfig: PipelineConfigSchema.partial().optional()
7486
+ }).strict().refine((data) => data.scrapingConfig !== void 0 || data.icp !== void 0 || data.pipelineConfig !== void 0, {
7487
+ message: "At least one of scrapingConfig, icp, or pipelineConfig must be provided"
7488
+ });
7489
+ z.object({
7490
+ companyIds: z.array(UuidSchema).min(1).max(1e3)
7491
+ }).strict();
7492
+ z.object({
7493
+ companyIds: z.array(UuidSchema).min(1).max(1e3)
7494
+ }).strict();
7495
+ z.object({
7496
+ contactIds: z.array(UuidSchema).min(1).max(1e3)
7497
+ }).strict();
7498
+ z.object({
7499
+ executionId: UuidSchema,
7500
+ configSnapshot: z.record(z.string(), z.unknown()).optional()
7501
+ }).strict();
7502
+ var AcqListResponseSchema = z.object({
7503
+ id: z.string(),
7504
+ organizationId: z.string(),
7505
+ name: z.string(),
7506
+ description: z.string().nullable(),
7507
+ batchIds: z.array(z.string()),
7508
+ instantlyCampaignId: z.string().nullable(),
7509
+ /** Lifecycle status (draft | enriching | launched | closing | archived). */
7510
+ status: ListStatusSchema,
7511
+ metadata: AcqListMetadataSchema,
7512
+ launchedAt: z.string().nullable(),
7513
+ completedAt: z.string().nullable(),
7514
+ createdAt: z.string(),
7515
+ /** Scraping criteria stored as jsonb on the row. */
7516
+ scrapingConfig: ScrapingConfigSchema,
7517
+ /** ICP / qualification rubric stored as jsonb on the row. */
7518
+ icp: IcpRubricSchema,
7519
+ /** Pipeline presentation contract stored as jsonb on the row. */
7520
+ pipelineConfig: PipelineConfigSchema
7521
+ });
7522
+ z.array(AcqListResponseSchema);
7523
+ z.array(ListTelemetrySchema);
7524
+ var ListStageProgressSchema = z.object({
7525
+ total: z.number().int().min(0),
7526
+ attempted: z.number().int().min(0),
7527
+ success: z.number().int().min(0),
7528
+ noResult: z.number().int().min(0),
7529
+ skipped: z.number().int().min(0),
7530
+ error: z.number().int().min(0),
7531
+ other: z.number().int().min(0),
7532
+ notAttempted: z.number().int().min(0)
7533
+ });
7534
+ z.object({
7535
+ totalMembers: z.number().int().min(0),
7536
+ totalCompanies: z.number().int().min(0),
7537
+ byCompanyStage: z.record(z.string(), ListStageProgressSchema),
7538
+ byContactStage: z.record(z.string(), ListStageProgressSchema)
7539
+ });
7540
+ var ListExecutionSummarySchema = z.object({
7541
+ executionId: z.string(),
7542
+ resourceId: z.string(),
7543
+ status: z.string(),
7544
+ createdAt: z.string(),
7545
+ completedAt: z.string().nullable(),
7546
+ durationMs: z.number().int().nullable(),
7547
+ input: z.unknown().nullable().optional()
7548
+ });
7549
+ z.array(ListExecutionSummarySchema);
7550
+ var QueryBooleanSchema = z.preprocess((value) => {
7551
+ if (value === "true" || value === "1" || value === true) return true;
7552
+ if (value === "false" || value === "0" || value === false) return false;
7553
+ return value;
7554
+ }, z.boolean());
7555
+ var AcqCompanyStatusSchema = z.enum(["active", "invalid"]);
7556
+ var AcqContactStatusSchema = z.enum(["active", "invalid"]);
7557
+ var AcqEmailValidSchema = z.enum(["VALID", "INVALID", "RISKY", "UNKNOWN"]);
7558
+ z.object({
7559
+ companyId: UuidSchema
7560
+ });
7561
+ z.object({
7562
+ contactId: UuidSchema
7563
+ });
7564
+ z.object({
7565
+ search: z.string().trim().min(1).max(200).optional(),
7566
+ listId: UuidSchema.optional(),
7567
+ domain: z.string().trim().min(1).max(255).optional(),
7568
+ website: z.string().trim().min(1).max(2048).optional(),
7569
+ segment: z.string().trim().min(1).max(255).optional(),
7570
+ category: z.string().trim().min(1).max(255).optional(),
7571
+ pipelineStatus: z.unknown().optional(),
7572
+ batchId: z.string().trim().min(1).max(255).optional(),
7573
+ status: AcqCompanyStatusSchema.optional(),
7574
+ includeAll: QueryBooleanSchema.optional(),
7575
+ limit: z.coerce.number().int().min(1).max(5e3).default(50),
7576
+ offset: z.coerce.number().int().min(0).default(0)
7577
+ }).strict();
7578
+ z.object({
7579
+ search: z.string().trim().min(1).max(200).optional(),
7580
+ listId: UuidSchema.optional(),
7581
+ openingLineIsNull: QueryBooleanSchema.optional(),
7582
+ batchId: z.string().trim().min(1).max(255).optional(),
7583
+ contactStatus: AcqContactStatusSchema.optional(),
7584
+ limit: z.coerce.number().int().min(1).max(5e3).default(5e3),
7585
+ offset: z.coerce.number().int().min(0).default(0)
7586
+ }).strict();
7587
+ z.object({
7588
+ name: z.string().trim().min(1).max(255),
7589
+ domain: z.string().trim().min(1).max(255).optional(),
7590
+ linkedinUrl: z.string().trim().url().optional(),
7591
+ website: z.string().trim().url().optional(),
7592
+ numEmployees: z.number().int().min(0).optional(),
7593
+ foundedYear: z.number().int().optional(),
7594
+ locationCity: z.string().trim().min(1).max(255).optional(),
7595
+ locationState: z.string().trim().min(1).max(255).optional(),
7596
+ category: z.string().trim().min(1).max(255).optional(),
7597
+ source: z.string().trim().min(1).max(255).optional(),
7598
+ batchId: z.string().trim().min(1).max(255).optional(),
7599
+ pipelineStatus: z.unknown().optional(),
7600
+ verticalResearch: z.string().trim().min(1).max(5e3).optional()
7601
+ }).strict();
7602
+ z.object({
7603
+ name: z.string().trim().min(1).max(255).optional(),
7604
+ domain: z.string().trim().min(1).max(255).optional(),
7605
+ linkedinUrl: z.string().trim().url().optional(),
7606
+ website: z.string().trim().url().optional(),
7607
+ numEmployees: z.number().int().min(0).optional(),
7608
+ foundedYear: z.number().int().optional(),
7609
+ locationCity: z.string().trim().min(1).max(255).optional(),
7610
+ locationState: z.string().trim().min(1).max(255).optional(),
7611
+ category: z.string().trim().min(1).max(255).optional(),
7612
+ segment: z.string().trim().min(1).max(255).optional(),
7613
+ processingState: CompanyProcessingStateSchema.optional(),
7614
+ pipelineStatus: z.unknown().optional(),
7615
+ enrichmentData: z.record(z.string(), z.unknown()).optional(),
7616
+ source: z.string().trim().min(1).max(255).optional(),
7617
+ batchId: z.string().trim().min(1).max(255).optional(),
7618
+ status: AcqCompanyStatusSchema.optional(),
7619
+ verticalResearch: z.string().trim().min(1).max(5e3).nullable().optional()
7620
+ }).strict().refine(
7621
+ (data) => data.name !== void 0 || data.domain !== void 0 || data.linkedinUrl !== void 0 || data.website !== void 0 || data.numEmployees !== void 0 || data.foundedYear !== void 0 || data.locationCity !== void 0 || data.locationState !== void 0 || data.category !== void 0 || data.segment !== void 0 || data.processingState !== void 0 || data.pipelineStatus !== void 0 || data.enrichmentData !== void 0 || data.source !== void 0 || data.batchId !== void 0 || data.status !== void 0 || data.verticalResearch !== void 0,
7622
+ {
7623
+ message: "At least one field must be provided"
7624
+ }
7625
+ );
7626
+ z.object({
7627
+ email: z.string().trim().email(),
7628
+ companyId: UuidSchema.optional(),
7629
+ firstName: z.string().trim().min(1).max(255).optional(),
7630
+ lastName: z.string().trim().min(1).max(255).optional(),
7631
+ linkedinUrl: z.string().trim().url().optional(),
7632
+ title: z.string().trim().min(1).max(255).optional(),
7633
+ source: z.string().trim().min(1).max(255).optional(),
7634
+ sourceId: z.string().trim().min(1).max(255).optional(),
7635
+ batchId: z.string().trim().min(1).max(255).optional(),
7636
+ pipelineStatus: z.unknown().optional()
7637
+ }).strict();
7638
+ z.object({
7639
+ companyId: UuidSchema.optional(),
7640
+ emailValid: AcqEmailValidSchema.optional(),
7641
+ firstName: z.string().trim().min(1).max(255).optional(),
7642
+ lastName: z.string().trim().min(1).max(255).optional(),
7643
+ linkedinUrl: z.string().trim().url().optional(),
7644
+ title: z.string().trim().min(1).max(255).optional(),
7645
+ headline: z.string().trim().min(1).max(5e3).optional(),
7646
+ filterReason: z.string().trim().min(1).max(5e3).optional(),
7647
+ openingLine: z.string().trim().min(1).max(5e3).optional(),
7648
+ processingState: ContactProcessingStateSchema.optional(),
7649
+ pipelineStatus: z.unknown().optional(),
7650
+ enrichmentData: z.record(z.string(), z.unknown()).optional(),
7651
+ status: AcqContactStatusSchema.optional()
7652
+ }).strict().refine(
7653
+ (data) => data.companyId !== void 0 || data.emailValid !== void 0 || data.firstName !== void 0 || data.lastName !== void 0 || data.linkedinUrl !== void 0 || data.title !== void 0 || data.headline !== void 0 || data.filterReason !== void 0 || data.openingLine !== void 0 || data.processingState !== void 0 || data.pipelineStatus !== void 0 || data.enrichmentData !== void 0 || data.status !== void 0,
7654
+ {
7655
+ message: "At least one field must be provided"
7656
+ }
7657
+ );
7658
+ var AcqCompanyResponseSchema = z.object({
7659
+ id: z.string(),
7660
+ organizationId: z.string(),
7661
+ name: z.string(),
7662
+ domain: z.string().nullable(),
7663
+ linkedinUrl: z.string().nullable(),
7664
+ website: z.string().nullable(),
7665
+ numEmployees: z.number().nullable(),
7666
+ foundedYear: z.number().nullable(),
7667
+ locationCity: z.string().nullable(),
7668
+ locationState: z.string().nullable(),
7669
+ category: z.string().nullable(),
7670
+ categoryPain: z.string().nullable(),
7671
+ segment: z.string().nullable(),
7672
+ processingState: CompanyProcessingStateSchema.nullable(),
7673
+ pipelineStatus: z.unknown().nullable().optional(),
7674
+ enrichmentData: z.record(z.string(), z.unknown()).nullable(),
7675
+ source: z.string().nullable(),
7676
+ batchId: z.string().nullable(),
7677
+ status: AcqCompanyStatusSchema,
7678
+ contactCount: z.number().int().min(0),
7679
+ verticalResearch: z.string().nullable(),
7680
+ createdAt: z.string(),
7681
+ updatedAt: z.string()
7682
+ });
7683
+ z.object({
7684
+ data: z.array(AcqCompanyResponseSchema),
7685
+ total: z.number().int(),
7686
+ limit: z.number().int(),
7687
+ offset: z.number().int()
7688
+ });
7689
+ z.object({
7690
+ segments: z.array(z.string()),
7691
+ categories: z.array(z.string()),
7692
+ statuses: z.array(AcqCompanyStatusSchema)
7693
+ });
7694
+ var AcqContactCompanySummarySchema = z.object({
7695
+ id: z.string(),
7696
+ name: z.string(),
7697
+ domain: z.string().nullable(),
7698
+ website: z.string().nullable(),
7699
+ linkedinUrl: z.string().nullable(),
7700
+ segment: z.string().nullable(),
7701
+ category: z.string().nullable(),
7702
+ status: AcqCompanyStatusSchema
7703
+ });
7704
+ var AcqContactResponseSchema = z.object({
7705
+ id: z.string(),
7706
+ organizationId: z.string(),
7707
+ companyId: z.string().nullable(),
7708
+ email: z.string(),
7709
+ emailValid: AcqEmailValidSchema.nullable(),
7710
+ firstName: z.string().nullable(),
7711
+ lastName: z.string().nullable(),
7712
+ linkedinUrl: z.string().nullable(),
7713
+ title: z.string().nullable(),
7714
+ headline: z.string().nullable(),
7715
+ filterReason: z.string().nullable(),
7716
+ openingLine: z.string().nullable(),
7717
+ source: z.string().nullable(),
7718
+ sourceId: z.string().nullable(),
7719
+ processingState: ContactProcessingStateSchema.nullable(),
7720
+ pipelineStatus: z.unknown().nullable().optional(),
7721
+ enrichmentData: z.record(z.string(), z.unknown()).nullable(),
7722
+ attioPersonId: z.string().nullable(),
7723
+ batchId: z.string().nullable(),
7724
+ status: AcqContactStatusSchema,
7725
+ company: AcqContactCompanySummarySchema.nullable().optional(),
7726
+ createdAt: z.string(),
7727
+ updatedAt: z.string()
7728
+ });
7729
+ z.object({
7730
+ data: z.array(AcqContactResponseSchema),
7731
+ total: z.number().int(),
7732
+ limit: z.number().int(),
7733
+ offset: z.number().int()
7734
+ });
7735
+ var AcqArtifactOwnerKindSchema = z.enum(["company", "contact", "deal", "list", "list_member"]);
7736
+ z.object({
7737
+ ownerKind: AcqArtifactOwnerKindSchema,
7738
+ ownerId: UuidSchema
7739
+ }).strict();
7740
+ z.object({
7741
+ ownerKind: AcqArtifactOwnerKindSchema,
7742
+ ownerId: UuidSchema,
7743
+ kind: z.string().trim().min(1).max(255),
7744
+ content: z.record(z.string(), z.unknown()),
7745
+ sourceExecutionId: UuidSchema.optional()
7746
+ }).strict();
7747
+ var AcqArtifactResponseSchema = z.object({
7748
+ id: z.string(),
7749
+ organizationId: z.string(),
7750
+ ownerKind: z.string(),
7751
+ ownerId: z.string(),
7752
+ kind: z.string(),
7753
+ content: z.record(z.string(), z.unknown()),
7754
+ sourceExecutionId: z.string().nullable(),
7755
+ createdBy: z.string().nullable(),
7756
+ createdAt: z.string(),
7757
+ version: z.number().int()
7758
+ });
7759
+ z.object({
7760
+ artifacts: z.array(AcqArtifactResponseSchema)
7761
+ });
7762
+ z.object({
7763
+ limit: z.coerce.number().int().min(1).max(500).default(50),
7764
+ offset: z.coerce.number().int().min(0).default(0)
7765
+ }).strict();
7766
+ z.object({
7767
+ memberId: UuidSchema
7768
+ });
7769
+ var AcqListMemberContactSummarySchema = z.object({
7770
+ id: z.string(),
7771
+ email: z.string(),
7772
+ firstName: z.string().nullable(),
7773
+ lastName: z.string().nullable(),
7774
+ title: z.string().nullable(),
7775
+ linkedinUrl: z.string().nullable(),
7776
+ companyId: z.string().nullable()
7777
+ });
7778
+ var AcqListMemberResponseSchema = z.object({
7779
+ id: z.string(),
7780
+ listId: z.string(),
7781
+ contactId: z.string(),
7782
+ pipelineKey: z.string(),
7783
+ stageKey: z.string(),
7784
+ stateKey: z.string(),
7785
+ activityLog: z.unknown(),
7786
+ addedAt: z.string(),
7787
+ addedBy: z.string().nullable(),
7788
+ sourceExecutionId: z.string().nullable(),
7789
+ contact: AcqListMemberContactSummarySchema.nullable()
7790
+ });
7791
+ z.object({
7792
+ members: z.array(AcqListMemberResponseSchema)
7793
+ });
7794
+ z.object({
7795
+ listCompanyId: UuidSchema
7796
+ });
7797
+ z.object({
7798
+ id: z.string(),
7799
+ listId: z.string(),
7800
+ companyId: z.string(),
7801
+ pipelineKey: z.string(),
7802
+ stageKey: z.string(),
7803
+ stateKey: z.string(),
7804
+ activityLog: z.unknown(),
7805
+ addedAt: z.string(),
7806
+ addedBy: z.string().nullable(),
7807
+ sourceExecutionId: z.string().nullable()
7808
+ });
6491
7809
  var RETRYABLE_CODES = /* @__PURE__ */ new Set([
6492
7810
  "rate_limit_exceeded",
6493
7811
  "network_error",
@@ -6821,7 +8139,9 @@ createAdapter("list", [
6821
8139
  "getConfig",
6822
8140
  "recordExecution",
6823
8141
  "updateCompanyStage",
6824
- "updateContactStage"
8142
+ "updateContactStage",
8143
+ "listPendingCompanyIds",
8144
+ "listPendingContactIds"
6825
8145
  ]);
6826
8146
 
6827
8147
  // src/worker/adapters/pdf.ts
@@ -6836,728 +8156,740 @@ createAdapter("execution", ["trigger", "triggerAsync"]);
6836
8156
  // src/worker/adapters/email.ts
6837
8157
  createAdapter("email", ["send"]);
6838
8158
 
6839
- // src/worker/index.ts
6840
- function captureConsole(executionId, logs) {
6841
- const origLog = console.log;
6842
- const origWarn = console.warn;
6843
- const origError = console.error;
6844
- const postLog = (level, message, logContext) => {
6845
- const timestamp = (/* @__PURE__ */ new Date()).toISOString();
6846
- const entry = { level, message, timestamp, context: logContext };
6847
- logs.push(entry);
6848
- parentPort?.postMessage({
6849
- type: "log",
6850
- entry: { level, message, timestamp, executionId, context: logContext }
6851
- });
6852
- };
6853
- const capture = (level, orig) => (...args) => {
6854
- postLog(level, args.map(String).join(" "));
6855
- orig(...args);
6856
- };
6857
- console.log = capture("info", origLog);
6858
- console.warn = capture("warn", origWarn);
6859
- console.error = capture("error", origError);
6860
- return {
6861
- restore: () => {
6862
- console.log = origLog;
6863
- console.warn = origWarn;
6864
- console.error = origError;
6865
- },
6866
- postLog
6867
- };
6868
- }
6869
- var LOG_STRING_TRUNCATE_LIMIT = 200;
6870
- function truncateForLogging(value) {
6871
- if (value === null || value === void 0) return value;
6872
- if (typeof value === "string") {
6873
- return value.length > LOG_STRING_TRUNCATE_LIMIT ? value.slice(0, LOG_STRING_TRUNCATE_LIMIT) + `\u2026 [${value.length} chars]` : value;
6874
- }
6875
- if (Array.isArray(value)) {
6876
- return value.map(truncateForLogging);
8159
+ // ../core/src/platform/registry/validation.ts
8160
+ var RegistryValidationError = class extends Error {
8161
+ constructor(orgName, resourceId, field, message) {
8162
+ super(message);
8163
+ this.orgName = orgName;
8164
+ this.resourceId = resourceId;
8165
+ this.field = field;
8166
+ this.name = "RegistryValidationError";
6877
8167
  }
6878
- if (typeof value === "object") {
6879
- const result = {};
6880
- for (const [k2, v2] of Object.entries(value)) {
6881
- result[k2] = truncateForLogging(v2);
8168
+ };
8169
+ function validateDeploymentSpec(orgName, resources) {
8170
+ const seenIds = /* @__PURE__ */ new Set();
8171
+ resources.workflows?.forEach((workflow) => {
8172
+ const id = workflow.config.resourceId;
8173
+ if (seenIds.has(id)) {
8174
+ throw new RegistryValidationError(
8175
+ orgName,
8176
+ id,
8177
+ null,
8178
+ `Duplicate resourceId "${id}" in organization "${orgName}". Workflows and agents must have unique IDs within an organization.`
8179
+ );
6882
8180
  }
6883
- return result;
6884
- }
6885
- return value;
6886
- }
6887
- function resolveNext(next, data) {
6888
- if (next === null) return null;
6889
- if (next.type === "linear") return next.target;
6890
- for (const route of next.routes) {
6891
- if (route.condition(data)) return route.target;
6892
- }
6893
- return next.default;
8181
+ seenIds.add(id);
8182
+ if ("modelConfig" in workflow && workflow.modelConfig) {
8183
+ validateResourceModelConfig(orgName, id, workflow.modelConfig);
8184
+ }
8185
+ if (workflow.interface) {
8186
+ validateExecutionInterface(orgName, id, workflow.interface, workflow.contract.inputSchema);
8187
+ }
8188
+ });
8189
+ resources.agents?.forEach((agent) => {
8190
+ const id = agent.config.resourceId;
8191
+ if (seenIds.has(id)) {
8192
+ throw new RegistryValidationError(
8193
+ orgName,
8194
+ id,
8195
+ null,
8196
+ `Duplicate resourceId "${id}" in organization "${orgName}". Workflows and agents must have unique IDs within an organization.`
8197
+ );
8198
+ }
8199
+ seenIds.add(id);
8200
+ validateResourceModelConfig(orgName, id, agent.modelConfig);
8201
+ if (agent.interface) {
8202
+ validateExecutionInterface(orgName, id, agent.interface, agent.contract.inputSchema);
8203
+ }
8204
+ });
6894
8205
  }
6895
- function safeZodToJsonSchema(schema) {
6896
- if (!schema || typeof schema !== "object" || !("parse" in schema)) return void 0;
8206
+ function validateResourceModelConfig(orgName, resourceId, modelConfig) {
6897
8207
  try {
6898
- const result = zodToJsonSchema(schema, { $refStrategy: "none", errorMessages: true });
6899
- if (result && typeof result === "object" && Object.keys(result).some((k2) => k2 !== "$schema")) {
6900
- return result;
8208
+ validateModelConfig(modelConfig);
8209
+ } catch (error) {
8210
+ if (error instanceof ModelConfigError) {
8211
+ throw new RegistryValidationError(
8212
+ orgName,
8213
+ resourceId,
8214
+ error.field,
8215
+ `Invalid model config in ${orgName}/${resourceId}: ${error.message} (field: ${error.field})`
8216
+ );
6901
8217
  }
6902
- } catch {
8218
+ throw error;
6903
8219
  }
6904
- return void 0;
6905
- }
6906
- function serializeNext(next) {
6907
- if (next === null) return null;
6908
- if (next.type === "linear") return { type: "linear", target: next.target };
6909
- return { type: "conditional", routes: next.routes.map((r2) => ({ target: r2.target })), default: next.default };
6910
8220
  }
6911
- async function executeWorkflow(workflow, input, context) {
6912
- const logs = [];
6913
- const { restore, postLog } = captureConsole(context.executionId, logs);
6914
- try {
6915
- let currentData = workflow.contract.inputSchema ? workflow.contract.inputSchema.parse(input) : input;
6916
- let stepId = workflow.entryPoint;
6917
- while (stepId !== null) {
6918
- const step = workflow.steps[stepId];
6919
- if (!step) {
6920
- throw new Error(`Step '${stepId}' not found in workflow '${workflow.config.resourceId}'`);
6921
- }
6922
- const stepStartTime = Date.now();
6923
- const stepInput = step.inputSchema.parse(currentData);
6924
- postLog("info", `Step '${step.name}' started`, {
6925
- type: "workflow",
6926
- contextType: "step-started",
6927
- stepId: step.id,
6928
- stepStatus: "started",
6929
- input: truncateForLogging(stepInput),
6930
- startTime: stepStartTime
6931
- });
6932
- try {
6933
- const rawOutput = await step.handler(stepInput, {
6934
- executionId: context.executionId,
6935
- organizationId: context.organizationId,
6936
- organizationName: context.organizationName,
6937
- resourceId: workflow.config.resourceId,
6938
- sessionId: context.sessionId,
6939
- sessionTurnNumber: context.sessionTurnNumber,
6940
- parentExecutionId: context.parentExecutionId,
6941
- executionDepth: context.executionDepth,
6942
- adapters: context.adapters,
6943
- store: /* @__PURE__ */ new Map(),
6944
- logger: {
6945
- debug: (msg) => console.log(`[debug] ${msg}`),
6946
- info: (msg) => console.log(`[info] ${msg}`),
6947
- warn: (msg) => console.warn(`[warn] ${msg}`),
6948
- error: (msg) => console.error(`[error] ${msg}`)
6949
- }
6950
- });
6951
- currentData = step.outputSchema.parse(rawOutput);
6952
- const stepEndTime = Date.now();
6953
- const nextStepId = resolveNext(step.next, currentData);
6954
- postLog("info", `Step '${step.name}' completed (${stepEndTime - stepStartTime}ms)`, {
6955
- type: "workflow",
6956
- contextType: "step-completed",
6957
- stepId: step.id,
6958
- stepStatus: "completed",
6959
- output: truncateForLogging(currentData),
6960
- duration: stepEndTime - stepStartTime,
6961
- isTerminal: nextStepId === null,
6962
- startTime: stepStartTime,
6963
- endTime: stepEndTime
6964
- });
6965
- if (step.next?.type === "conditional" && nextStepId !== null) {
6966
- postLog("info", `Routing from '${step.name}' to '${nextStepId}'`, {
6967
- type: "workflow",
6968
- contextType: "conditional-route",
6969
- stepId: step.id,
6970
- target: nextStepId
6971
- });
8221
+ function validateExecutionInterface(orgName, resourceId, executionInterface, inputSchema) {
8222
+ const form = executionInterface.form;
8223
+ const fieldMappings = form.fieldMappings ?? {};
8224
+ const schemaShape = extractZodShape(inputSchema);
8225
+ if (!schemaShape) {
8226
+ return;
8227
+ }
8228
+ const schemaFieldNames = Object.keys(schemaShape);
8229
+ const formToSchemaMap = /* @__PURE__ */ new Map();
8230
+ for (const field of form.fields) {
8231
+ const schemaKey = fieldMappings[field.name] ?? field.name;
8232
+ formToSchemaMap.set(field.name, schemaKey);
8233
+ }
8234
+ for (const schemaFieldName of schemaFieldNames) {
8235
+ const schemaField = schemaShape[schemaFieldName];
8236
+ const isRequired = !isZodOptional(schemaField);
8237
+ let hasFormField = false;
8238
+ for (const [formFieldName, mappedSchemaName] of Array.from(formToSchemaMap.entries())) {
8239
+ if (mappedSchemaName === schemaFieldName) {
8240
+ hasFormField = true;
8241
+ const formField = form.fields.find((f4) => f4.name === formFieldName);
8242
+ if (isRequired && !formField?.required) {
8243
+ throw new RegistryValidationError(
8244
+ orgName,
8245
+ resourceId,
8246
+ `interface.form.fields.${formFieldName}`,
8247
+ `ExecutionInterface field "${formFieldName}" should be required to match inputSchema field "${schemaFieldName}" in ${orgName}/${resourceId}`
8248
+ );
6972
8249
  }
6973
- stepId = nextStepId;
6974
- } catch (err) {
6975
- const stepEndTime = Date.now();
6976
- postLog("error", `Step '${step.name}' failed: ${String(err)}`, {
6977
- type: "workflow",
6978
- contextType: "step-failed",
6979
- stepId: step.id,
6980
- stepStatus: "failed",
6981
- error: String(err),
6982
- duration: stepEndTime - stepStartTime,
6983
- startTime: stepStartTime,
6984
- endTime: stepEndTime
6985
- });
6986
- throw err;
8250
+ break;
6987
8251
  }
6988
8252
  }
6989
- if (workflow.contract.outputSchema) {
6990
- currentData = workflow.contract.outputSchema.parse(currentData);
8253
+ if (isRequired && !hasFormField) {
8254
+ throw new RegistryValidationError(
8255
+ orgName,
8256
+ resourceId,
8257
+ "interface.form.fields",
8258
+ `ExecutionInterface missing required field "${schemaFieldName}" from inputSchema in ${orgName}/${resourceId}`
8259
+ );
8260
+ }
8261
+ }
8262
+ for (const [formFieldName, schemaFieldName] of Array.from(formToSchemaMap.entries())) {
8263
+ if (schemaFieldName.includes(".")) {
8264
+ const topLevelField = schemaFieldName.split(".")[0];
8265
+ throw new RegistryValidationError(
8266
+ orgName,
8267
+ resourceId,
8268
+ `interface.form.fields.${formFieldName}`,
8269
+ `ExecutionInterface field "${formFieldName}" uses nested notation. Flatten the inputSchema by moving nested fields to top-level (e.g., "${topLevelField}.x" \u2192 "x") in ${orgName}/${resourceId}`
8270
+ );
8271
+ }
8272
+ if (!schemaFieldNames.includes(schemaFieldName)) {
8273
+ throw new RegistryValidationError(
8274
+ orgName,
8275
+ resourceId,
8276
+ `interface.form.fields.${formFieldName}`,
8277
+ `ExecutionInterface field "${formFieldName}" maps to non-existent schema field "${schemaFieldName}" in ${orgName}/${resourceId}`
8278
+ );
6991
8279
  }
6992
- return { output: currentData, logs };
6993
- } finally {
6994
- restore();
6995
8280
  }
6996
8281
  }
6997
- function buildWorkerExecutionContext(params) {
6998
- const { executionId } = params;
6999
- const postLog = (level, message) => {
7000
- parentPort.postMessage({
7001
- type: "log",
7002
- entry: { level, message, timestamp: (/* @__PURE__ */ new Date()).toISOString(), executionId }
7003
- });
7004
- };
7005
- return {
7006
- executionId: params.executionId,
7007
- organizationId: params.organizationId,
7008
- organizationName: params.organizationName,
7009
- resourceId: params.resourceId,
7010
- sessionId: params.sessionId,
7011
- sessionTurnNumber: params.sessionTurnNumber,
7012
- parentExecutionId: params.parentExecutionId,
7013
- executionDepth: params.executionDepth,
7014
- signal: params.signal,
7015
- store: /* @__PURE__ */ new Map(),
7016
- logger: {
7017
- debug: (msg) => {
7018
- console.log(`[debug] ${msg}`);
7019
- postLog("info", msg);
7020
- },
7021
- info: (msg) => {
7022
- console.log(`[info] ${msg}`);
7023
- postLog("info", msg);
7024
- },
7025
- warn: (msg) => {
7026
- console.warn(`[warn] ${msg}`);
7027
- postLog("warn", msg);
7028
- },
7029
- error: (msg) => {
7030
- console.error(`[error] ${msg}`);
7031
- postLog("error", msg);
7032
- }
7033
- },
7034
- onMessageEvent: async (event) => {
7035
- parentPort.postMessage({ type: "message-event", executionId, event });
8282
+ function extractZodShape(schema) {
8283
+ if ("shape" in schema && typeof schema.shape === "object") {
8284
+ return schema.shape;
8285
+ }
8286
+ if ("_def" in schema) {
8287
+ const def = schema._def;
8288
+ if (def.innerType) {
8289
+ return extractZodShape(def.innerType);
7036
8290
  }
7037
- };
8291
+ if (def.schema) {
8292
+ return extractZodShape(def.schema);
8293
+ }
8294
+ }
8295
+ return null;
7038
8296
  }
7039
- function startWorker(org) {
7040
- const workflows = new Map((org.workflows ?? []).map((w2) => [w2.config.resourceId, w2]));
7041
- const agents = new Map((org.agents ?? []).map((a3) => [a3.config.resourceId, a3]));
7042
- let localAbortController = new AbortController();
7043
- console.log(`[SDK-WORKER] Worker started with ${workflows.size} workflow(s), ${agents.size} agent(s)`);
7044
- parentPort.on("message", async (msg) => {
7045
- if (msg.type === "manifest") {
7046
- parentPort.postMessage({
7047
- type: "manifest",
7048
- workflows: (org.workflows ?? []).map((w2) => ({
7049
- resourceId: w2.config.resourceId,
7050
- name: w2.config.name,
7051
- type: w2.config.type,
7052
- status: w2.config.status,
7053
- description: w2.config.description,
7054
- version: w2.config.version,
7055
- links: w2.config.links,
7056
- category: w2.config.category,
7057
- contract: {
7058
- inputSchema: safeZodToJsonSchema(w2.contract?.inputSchema),
7059
- outputSchema: safeZodToJsonSchema(w2.contract?.outputSchema)
7060
- },
7061
- steps: Object.values(w2.steps).map((step) => ({
7062
- id: step.id,
7063
- name: step.name,
7064
- description: step.description,
7065
- inputSchema: safeZodToJsonSchema(step.inputSchema),
7066
- outputSchema: safeZodToJsonSchema(step.outputSchema),
7067
- next: serializeNext(step.next)
7068
- })),
7069
- entryPoint: w2.entryPoint
7070
- })),
7071
- agents: (org.agents ?? []).map((a3) => ({
7072
- resourceId: a3.config.resourceId,
7073
- name: a3.config.name,
7074
- type: a3.config.type,
7075
- status: a3.config.status,
7076
- description: a3.config.description,
7077
- version: a3.config.version,
7078
- links: a3.config.links,
7079
- category: a3.config.category,
7080
- contract: {
7081
- inputSchema: safeZodToJsonSchema(a3.contract?.inputSchema),
7082
- outputSchema: safeZodToJsonSchema(a3.contract?.outputSchema)
7083
- }
7084
- })),
7085
- triggers: org.triggers ?? [],
7086
- integrations: org.integrations ?? [],
7087
- humanCheckpoints: org.humanCheckpoints ?? [],
7088
- relationships: org.relationships ?? void 0
7089
- });
7090
- return;
7091
- }
7092
- if (msg.type === "tool-result") {
7093
- handleToolResult(msg);
7094
- return;
7095
- }
7096
- if (msg.type === "credential-result") {
7097
- handleCredentialResult(msg);
7098
- return;
7099
- }
7100
- if (msg.type === "abort") {
7101
- console.log("[SDK-WORKER] Abort requested by parent");
7102
- localAbortController.abort();
7103
- return;
7104
- }
7105
- if (msg.type === "execute") {
7106
- const {
7107
- resourceId,
7108
- executionId,
7109
- input,
7110
- organizationId,
7111
- organizationName,
7112
- sessionId,
7113
- sessionTurnNumber,
7114
- parentExecutionId,
7115
- executionDepth
7116
- } = msg;
7117
- console.log(`[SDK-WORKER] Execute request: resourceId=${resourceId}, executionId=${executionId}`);
7118
- localAbortController = new AbortController();
7119
- const workflow = workflows.get(resourceId);
7120
- if (workflow) {
7121
- const startTime = Date.now();
7122
- try {
7123
- console.log(`[SDK-WORKER] Running workflow '${resourceId}' (${Object.keys(workflow.steps).length} steps)`);
7124
- const { output, logs } = await executeWorkflow(workflow, input, {
7125
- executionId,
7126
- organizationId: organizationId ?? "",
7127
- organizationName: organizationName ?? "",
7128
- sessionId,
7129
- sessionTurnNumber,
7130
- parentExecutionId,
7131
- executionDepth: executionDepth ?? 0
7132
- });
7133
- const durationMs = Date.now() - startTime;
7134
- console.log(`[SDK-WORKER] Workflow '${resourceId}' completed (${durationMs}ms)`);
7135
- parentPort.postMessage({ type: "result", status: "completed", output, logs, metrics: { durationMs } });
7136
- } catch (err) {
7137
- const durationMs = Date.now() - startTime;
7138
- console.error(`[SDK-WORKER] Workflow '${resourceId}' failed (${durationMs}ms): ${String(err)}`);
7139
- parentPort.postMessage({
7140
- type: "result",
7141
- status: "failed",
7142
- error: String(err),
7143
- logs: [],
7144
- metrics: { durationMs }
7145
- });
7146
- }
7147
- return;
7148
- }
7149
- const agentDef = agents.get(resourceId);
7150
- if (agentDef) {
7151
- const logs = [];
7152
- const { restore } = captureConsole(executionId, logs);
7153
- const startTime = Date.now();
7154
- try {
7155
- console.log(`[SDK-WORKER] Running agent '${resourceId}' (${agentDef.tools.length} tools)`);
7156
- const adapterFactory = createPostMessageAdapterFactory();
7157
- const agentInstance = new Agent(agentDef, adapterFactory);
7158
- const context = buildWorkerExecutionContext({
7159
- executionId,
7160
- organizationId: organizationId ?? "",
7161
- organizationName: organizationName ?? "",
7162
- resourceId,
7163
- sessionId,
7164
- sessionTurnNumber,
7165
- parentExecutionId,
7166
- executionDepth: executionDepth ?? 0,
7167
- signal: localAbortController.signal
7168
- });
7169
- const output = await agentInstance.execute(input, context);
7170
- const durationMs = Date.now() - startTime;
7171
- console.log(`[SDK-WORKER] Agent '${resourceId}' completed (${durationMs}ms)`);
7172
- parentPort.postMessage({ type: "result", status: "completed", output, logs, metrics: { durationMs } });
7173
- } catch (err) {
7174
- const durationMs = Date.now() - startTime;
7175
- const errorMessage = err?.message ?? String(err);
7176
- err?.code ?? "unknown";
7177
- const errorName = err?.name ?? err?.constructor?.name ?? "Error";
7178
- console.error(`[SDK-WORKER] Agent '${resourceId}' failed (${durationMs}ms): [${errorName}] ${errorMessage}`);
7179
- parentPort.postMessage({
7180
- type: "result",
7181
- status: "failed",
7182
- error: `${errorName}: ${errorMessage}`,
7183
- logs,
7184
- metrics: { durationMs }
7185
- });
7186
- } finally {
7187
- restore();
7188
- }
7189
- return;
7190
- }
7191
- console.error(`[SDK-WORKER] Resource not found: ${resourceId}`);
7192
- parentPort.postMessage({
7193
- type: "result",
7194
- status: "failed",
7195
- error: `Resource not found: ${resourceId}`,
7196
- logs: []
7197
- });
7198
- }
7199
- });
7200
- }
7201
- if (workerData != null && workerData.kind === "static") {
7202
- const { modulePath } = workerData;
7203
- void (async () => {
7204
- const mod = await import(modulePath);
7205
- startWorker(mod.default);
7206
- })();
8297
+ function isZodOptional(schema) {
8298
+ return schema.isOptional();
7207
8299
  }
7208
-
7209
- // src/test-utils/workflow.ts
7210
- function extractStepEvents(logs) {
7211
- return logs.flatMap((log) => {
7212
- const context = log.context;
7213
- if (!context || context.type !== "workflow" || typeof context.contextType !== "string") {
7214
- return [];
7215
- }
7216
- return [
7217
- {
7218
- type: context.contextType,
7219
- stepId: typeof context.stepId === "string" ? context.stepId : void 0,
7220
- stepStatus: typeof context.stepStatus === "string" ? context.stepStatus : void 0,
7221
- input: context.input,
7222
- output: context.output,
7223
- error: context.error,
7224
- duration: typeof context.duration === "number" ? context.duration : void 0,
7225
- target: typeof context.target === "string" ? context.target : void 0,
7226
- raw: context
7227
- }
7228
- ];
7229
- });
8300
+ function validateRelationships(orgName, resources) {
8301
+ if (!resources.relationships && !resources.triggers && !resources.externalResources && !resources.humanCheckpoints)
8302
+ return;
8303
+ const validAgentIds = new Set(resources.agents?.map((a3) => a3.config.resourceId) ?? []);
8304
+ const validWorkflowIds = new Set(resources.workflows?.map((w2) => w2.config.resourceId) ?? []);
8305
+ const validIntegrationIds = new Set(resources.integrations?.map((i) => i.resourceId) ?? []);
8306
+ const validTriggerIds = new Set(resources.triggers?.map((t) => t.resourceId) ?? []);
8307
+ const allInternalIds = /* @__PURE__ */ new Set([
8308
+ ...Array.from(validAgentIds),
8309
+ ...Array.from(validWorkflowIds),
8310
+ ...Array.from(validTriggerIds),
8311
+ ...Array.from(validIntegrationIds)
8312
+ ]);
8313
+ validateTriggers(orgName, resources.triggers ?? []);
8314
+ validateResourceRelationships(
8315
+ orgName,
8316
+ resources.relationships ?? {},
8317
+ validAgentIds,
8318
+ validWorkflowIds,
8319
+ validIntegrationIds,
8320
+ validTriggerIds
8321
+ );
8322
+ validateExternalResources(
8323
+ orgName,
8324
+ resources.externalResources ?? [],
8325
+ allInternalIds,
8326
+ validAgentIds,
8327
+ validWorkflowIds,
8328
+ validIntegrationIds
8329
+ );
8330
+ validateHumanCheckpoints(orgName, resources.humanCheckpoints ?? [], allInternalIds, validAgentIds, validWorkflowIds);
7230
8331
  }
7231
- async function runWorkflow(definition, input, options = {}) {
7232
- const context = options.context ?? {};
7233
- const { output, logs } = await executeWorkflow(definition, input, {
7234
- executionId: context.executionId ?? `test-${Date.now()}`,
7235
- organizationId: context.organizationId ?? "test-org",
7236
- organizationName: context.organizationName ?? "Test Organization",
7237
- sessionId: context.sessionId,
7238
- sessionTurnNumber: context.sessionTurnNumber,
7239
- parentExecutionId: context.parentExecutionId,
7240
- executionDepth: context.executionDepth ?? 0,
7241
- adapters: options.adapters
7242
- });
7243
- return {
7244
- output,
7245
- logs,
7246
- stepEvents: extractStepEvents(logs)
7247
- };
8332
+ function validateTriggers(_orgName, _triggers, _validAgentIds, _validWorkflowIds) {
7248
8333
  }
7249
-
7250
- // ../core/src/platform/registry/validation.ts
7251
- var RegistryValidationError = class extends Error {
7252
- constructor(orgName, resourceId, field, message) {
7253
- super(message);
7254
- this.orgName = orgName;
7255
- this.resourceId = resourceId;
7256
- this.field = field;
7257
- this.name = "RegistryValidationError";
7258
- }
7259
- };
7260
- function validateDeploymentSpec(orgName, resources) {
7261
- const seenIds = /* @__PURE__ */ new Set();
7262
- resources.workflows?.forEach((workflow) => {
7263
- const id = workflow.config.resourceId;
7264
- if (seenIds.has(id)) {
8334
+ function validateResourceRelationships(orgName, relationships, validAgentIds, validWorkflowIds, validIntegrationIds, validTriggerIds) {
8335
+ for (const [resourceId, declaration] of Object.entries(relationships)) {
8336
+ const resourceExists = validAgentIds.has(resourceId) || validWorkflowIds.has(resourceId) || validTriggerIds.has(resourceId);
8337
+ if (!resourceExists) {
7265
8338
  throw new RegistryValidationError(
7266
8339
  orgName,
7267
- id,
8340
+ resourceId,
7268
8341
  null,
7269
- `Duplicate resourceId "${id}" in organization "${orgName}". Workflows and agents must have unique IDs within an organization.`
8342
+ `[${orgName}] Relationship declared for non-existent resource: ${resourceId}`
7270
8343
  );
7271
8344
  }
7272
- seenIds.add(id);
7273
- if ("modelConfig" in workflow && workflow.modelConfig) {
7274
- validateResourceModelConfig(orgName, id, workflow.modelConfig);
7275
- }
7276
- if (workflow.interface) {
7277
- validateExecutionInterface(orgName, id, workflow.interface, workflow.contract.inputSchema);
7278
- }
7279
- });
7280
- resources.agents?.forEach((agent) => {
7281
- const id = agent.config.resourceId;
7282
- if (seenIds.has(id)) {
8345
+ declaration.triggers?.agents?.forEach((agentId) => {
8346
+ if (!validAgentIds.has(agentId)) {
8347
+ throw new RegistryValidationError(
8348
+ orgName,
8349
+ resourceId,
8350
+ "triggers.agents",
8351
+ `[${orgName}] Resource '${resourceId}' triggers non-existent agent: ${agentId}`
8352
+ );
8353
+ }
8354
+ });
8355
+ declaration.triggers?.workflows?.forEach((workflowId) => {
8356
+ if (!validWorkflowIds.has(workflowId)) {
8357
+ throw new RegistryValidationError(
8358
+ orgName,
8359
+ resourceId,
8360
+ "triggers.workflows",
8361
+ `[${orgName}] Resource '${resourceId}' triggers non-existent workflow: ${workflowId}`
8362
+ );
8363
+ }
8364
+ });
8365
+ declaration.uses?.integrations?.forEach((integrationId) => {
8366
+ if (!validIntegrationIds.has(integrationId)) {
8367
+ throw new RegistryValidationError(
8368
+ orgName,
8369
+ resourceId,
8370
+ "uses.integrations",
8371
+ `[${orgName}] Resource '${resourceId}' uses non-existent integration: ${integrationId}`
8372
+ );
8373
+ }
8374
+ });
8375
+ }
8376
+ }
8377
+ function validateExternalResources(orgName, externalResources, allInternalIds, validAgentIds, validWorkflowIds, validIntegrationIds) {
8378
+ externalResources.forEach((external) => {
8379
+ if (allInternalIds.has(external.resourceId)) {
7283
8380
  throw new RegistryValidationError(
7284
8381
  orgName,
7285
- id,
8382
+ external.resourceId,
7286
8383
  null,
7287
- `Duplicate resourceId "${id}" in organization "${orgName}". Workflows and agents must have unique IDs within an organization.`
8384
+ `[${orgName}] External resource ID '${external.resourceId}' conflicts with internal resource ID`
7288
8385
  );
7289
8386
  }
7290
- seenIds.add(id);
7291
- validateResourceModelConfig(orgName, id, agent.modelConfig);
7292
- if (agent.interface) {
7293
- validateExecutionInterface(orgName, id, agent.interface, agent.contract.inputSchema);
7294
- }
8387
+ external.triggers?.agents?.forEach((agentId) => {
8388
+ if (!validAgentIds.has(agentId)) {
8389
+ throw new RegistryValidationError(
8390
+ orgName,
8391
+ external.resourceId,
8392
+ "triggers.agents",
8393
+ `[${orgName}] External resource '${external.resourceId}' triggers non-existent agent: ${agentId}`
8394
+ );
8395
+ }
8396
+ });
8397
+ external.triggers?.workflows?.forEach((workflowId) => {
8398
+ if (!validWorkflowIds.has(workflowId)) {
8399
+ throw new RegistryValidationError(
8400
+ orgName,
8401
+ external.resourceId,
8402
+ "triggers.workflows",
8403
+ `[${orgName}] External resource '${external.resourceId}' triggers non-existent workflow: ${workflowId}`
8404
+ );
8405
+ }
8406
+ });
8407
+ external.uses?.integrations?.forEach((integrationId) => {
8408
+ if (!validIntegrationIds.has(integrationId)) {
8409
+ throw new RegistryValidationError(
8410
+ orgName,
8411
+ external.resourceId,
8412
+ "uses.integrations",
8413
+ `[${orgName}] External resource '${external.resourceId}' uses non-existent integration: ${integrationId}`
8414
+ );
8415
+ }
8416
+ });
7295
8417
  });
7296
8418
  }
7297
- function validateResourceModelConfig(orgName, resourceId, modelConfig) {
7298
- try {
7299
- validateModelConfig(modelConfig);
7300
- } catch (error) {
7301
- if (error instanceof ModelConfigError) {
8419
+ function validateHumanCheckpoints(orgName, humanCheckpoints, allInternalIds, validAgentIds, validWorkflowIds) {
8420
+ humanCheckpoints.forEach((humanCheckpoint) => {
8421
+ if (allInternalIds.has(humanCheckpoint.resourceId)) {
7302
8422
  throw new RegistryValidationError(
7303
8423
  orgName,
7304
- resourceId,
7305
- error.field,
7306
- `Invalid model config in ${orgName}/${resourceId}: ${error.message} (field: ${error.field})`
8424
+ humanCheckpoint.resourceId,
8425
+ null,
8426
+ `[${orgName}] Human checkpoint ID '${humanCheckpoint.resourceId}' conflicts with internal resource ID`
7307
8427
  );
7308
8428
  }
7309
- throw error;
8429
+ humanCheckpoint.requestedBy?.agents?.forEach((agentId) => {
8430
+ if (!validAgentIds.has(agentId)) {
8431
+ throw new RegistryValidationError(
8432
+ orgName,
8433
+ humanCheckpoint.resourceId,
8434
+ "requestedBy.agents",
8435
+ `[${orgName}] Human checkpoint '${humanCheckpoint.resourceId}' requestedBy non-existent agent: ${agentId}`
8436
+ );
8437
+ }
8438
+ });
8439
+ humanCheckpoint.requestedBy?.workflows?.forEach((workflowId) => {
8440
+ if (!validWorkflowIds.has(workflowId)) {
8441
+ throw new RegistryValidationError(
8442
+ orgName,
8443
+ humanCheckpoint.resourceId,
8444
+ "requestedBy.workflows",
8445
+ `[${orgName}] Human checkpoint '${humanCheckpoint.resourceId}' requestedBy non-existent workflow: ${workflowId}`
8446
+ );
8447
+ }
8448
+ });
8449
+ humanCheckpoint.routesTo?.agents?.forEach((agentId) => {
8450
+ if (!validAgentIds.has(agentId)) {
8451
+ throw new RegistryValidationError(
8452
+ orgName,
8453
+ humanCheckpoint.resourceId,
8454
+ "routesTo.agents",
8455
+ `[${orgName}] Human checkpoint '${humanCheckpoint.resourceId}' routesTo non-existent agent: ${agentId}`
8456
+ );
8457
+ }
8458
+ });
8459
+ humanCheckpoint.routesTo?.workflows?.forEach((workflowId) => {
8460
+ if (!validWorkflowIds.has(workflowId)) {
8461
+ throw new RegistryValidationError(
8462
+ orgName,
8463
+ humanCheckpoint.resourceId,
8464
+ "routesTo.workflows",
8465
+ `[${orgName}] Human checkpoint '${humanCheckpoint.resourceId}' routesTo non-existent workflow: ${workflowId}`
8466
+ );
8467
+ }
8468
+ });
8469
+ });
8470
+ }
8471
+ var listBuilderStageKeys = Object.keys(LEAD_GEN_STAGE_CATALOG);
8472
+ var ListBuilderStageKeySchema = z.enum(listBuilderStageKeys);
8473
+
8474
+ // src/worker/list-builder-workflow.ts
8475
+ var ListBuilderResultSchema = z.object({
8476
+ entity: z.enum(["company", "contact"]),
8477
+ id: z.string().min(1),
8478
+ status: ProcessingStageStatusSchema,
8479
+ stageKey: ListBuilderStageKeySchema.optional(),
8480
+ data: z.unknown().optional()
8481
+ });
8482
+ z.array(ListBuilderResultSchema);
8483
+
8484
+ // src/worker/index.ts
8485
+ function captureConsole(executionId, logs) {
8486
+ const origLog = console.log;
8487
+ const origWarn = console.warn;
8488
+ const origError = console.error;
8489
+ const postLog = (level, message, logContext) => {
8490
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString();
8491
+ const entry = { level, message, timestamp, context: logContext };
8492
+ logs.push(entry);
8493
+ parentPort?.postMessage({
8494
+ type: "log",
8495
+ entry: { level, message, timestamp, executionId, context: logContext }
8496
+ });
8497
+ };
8498
+ const capture = (level, orig) => (...args) => {
8499
+ postLog(level, args.map(String).join(" "));
8500
+ orig(...args);
8501
+ };
8502
+ console.log = capture("info", origLog);
8503
+ console.warn = capture("warn", origWarn);
8504
+ console.error = capture("error", origError);
8505
+ return {
8506
+ restore: () => {
8507
+ console.log = origLog;
8508
+ console.warn = origWarn;
8509
+ console.error = origError;
8510
+ },
8511
+ postLog
8512
+ };
8513
+ }
8514
+ var LOG_STRING_TRUNCATE_LIMIT = 200;
8515
+ function truncateForLogging(value) {
8516
+ if (value === null || value === void 0) return value;
8517
+ if (typeof value === "string") {
8518
+ return value.length > LOG_STRING_TRUNCATE_LIMIT ? value.slice(0, LOG_STRING_TRUNCATE_LIMIT) + `\u2026 [${value.length} chars]` : value;
7310
8519
  }
8520
+ if (Array.isArray(value)) {
8521
+ return value.map(truncateForLogging);
8522
+ }
8523
+ if (typeof value === "object") {
8524
+ const result = {};
8525
+ for (const [k2, v2] of Object.entries(value)) {
8526
+ result[k2] = truncateForLogging(v2);
8527
+ }
8528
+ return result;
8529
+ }
8530
+ return value;
7311
8531
  }
7312
- function validateExecutionInterface(orgName, resourceId, executionInterface, inputSchema) {
7313
- const form = executionInterface.form;
7314
- const fieldMappings = form.fieldMappings ?? {};
7315
- const schemaShape = extractZodShape(inputSchema);
7316
- if (!schemaShape) {
7317
- return;
8532
+ function resolveNext(next, data) {
8533
+ if (next === null) return null;
8534
+ if (next.type === "linear") return next.target;
8535
+ for (const route of next.routes) {
8536
+ if (route.condition(data)) return route.target;
7318
8537
  }
7319
- const schemaFieldNames = Object.keys(schemaShape);
7320
- const formToSchemaMap = /* @__PURE__ */ new Map();
7321
- for (const field of form.fields) {
7322
- const schemaKey = fieldMappings[field.name] ?? field.name;
7323
- formToSchemaMap.set(field.name, schemaKey);
8538
+ return next.default;
8539
+ }
8540
+ function safeZodToJsonSchema(schema) {
8541
+ if (!schema || typeof schema !== "object" || !("parse" in schema)) return void 0;
8542
+ try {
8543
+ const result = zodToJsonSchema(schema, { $refStrategy: "none", errorMessages: true });
8544
+ if (result && typeof result === "object" && Object.keys(result).some((k2) => k2 !== "$schema")) {
8545
+ return result;
8546
+ }
8547
+ } catch {
7324
8548
  }
7325
- for (const schemaFieldName of schemaFieldNames) {
7326
- const schemaField = schemaShape[schemaFieldName];
7327
- const isRequired = !isZodOptional(schemaField);
7328
- let hasFormField = false;
7329
- for (const [formFieldName, mappedSchemaName] of Array.from(formToSchemaMap.entries())) {
7330
- if (mappedSchemaName === schemaFieldName) {
7331
- hasFormField = true;
7332
- const formField = form.fields.find((f4) => f4.name === formFieldName);
7333
- if (isRequired && !formField?.required) {
7334
- throw new RegistryValidationError(
7335
- orgName,
7336
- resourceId,
7337
- `interface.form.fields.${formFieldName}`,
7338
- `ExecutionInterface field "${formFieldName}" should be required to match inputSchema field "${schemaFieldName}" in ${orgName}/${resourceId}`
7339
- );
8549
+ return void 0;
8550
+ }
8551
+ function serializeNext(next) {
8552
+ if (next === null) return null;
8553
+ if (next.type === "linear") return { type: "linear", target: next.target };
8554
+ return { type: "conditional", routes: next.routes.map((r2) => ({ target: r2.target })), default: next.default };
8555
+ }
8556
+ async function executeWorkflow(workflow, input, context) {
8557
+ const logs = [];
8558
+ const { restore, postLog } = captureConsole(context.executionId, logs);
8559
+ try {
8560
+ let currentData = workflow.contract.inputSchema ? workflow.contract.inputSchema.parse(input) : input;
8561
+ let stepId = workflow.entryPoint;
8562
+ while (stepId !== null) {
8563
+ const step = workflow.steps[stepId];
8564
+ if (!step) {
8565
+ throw new Error(`Step '${stepId}' not found in workflow '${workflow.config.resourceId}'`);
8566
+ }
8567
+ const stepStartTime = Date.now();
8568
+ const stepInput = step.inputSchema.parse(currentData);
8569
+ postLog("info", `Step '${step.name}' started`, {
8570
+ type: "workflow",
8571
+ contextType: "step-started",
8572
+ stepId: step.id,
8573
+ stepStatus: "started",
8574
+ input: truncateForLogging(stepInput),
8575
+ startTime: stepStartTime
8576
+ });
8577
+ try {
8578
+ const rawOutput = await step.handler(stepInput, {
8579
+ executionId: context.executionId,
8580
+ organizationId: context.organizationId,
8581
+ organizationName: context.organizationName,
8582
+ resourceId: workflow.config.resourceId,
8583
+ sessionId: context.sessionId,
8584
+ sessionTurnNumber: context.sessionTurnNumber,
8585
+ parentExecutionId: context.parentExecutionId,
8586
+ executionDepth: context.executionDepth,
8587
+ adapters: context.adapters,
8588
+ store: /* @__PURE__ */ new Map(),
8589
+ logger: {
8590
+ debug: (msg) => console.log(`[debug] ${msg}`),
8591
+ info: (msg) => console.log(`[info] ${msg}`),
8592
+ warn: (msg) => console.warn(`[warn] ${msg}`),
8593
+ error: (msg) => console.error(`[error] ${msg}`)
8594
+ }
8595
+ });
8596
+ currentData = step.outputSchema.parse(rawOutput);
8597
+ const stepEndTime = Date.now();
8598
+ const nextStepId = resolveNext(step.next, currentData);
8599
+ postLog("info", `Step '${step.name}' completed (${stepEndTime - stepStartTime}ms)`, {
8600
+ type: "workflow",
8601
+ contextType: "step-completed",
8602
+ stepId: step.id,
8603
+ stepStatus: "completed",
8604
+ output: truncateForLogging(currentData),
8605
+ duration: stepEndTime - stepStartTime,
8606
+ isTerminal: nextStepId === null,
8607
+ startTime: stepStartTime,
8608
+ endTime: stepEndTime
8609
+ });
8610
+ if (step.next?.type === "conditional" && nextStepId !== null) {
8611
+ postLog("info", `Routing from '${step.name}' to '${nextStepId}'`, {
8612
+ type: "workflow",
8613
+ contextType: "conditional-route",
8614
+ stepId: step.id,
8615
+ target: nextStepId
8616
+ });
7340
8617
  }
7341
- break;
8618
+ stepId = nextStepId;
8619
+ } catch (err) {
8620
+ const stepEndTime = Date.now();
8621
+ postLog("error", `Step '${step.name}' failed: ${String(err)}`, {
8622
+ type: "workflow",
8623
+ contextType: "step-failed",
8624
+ stepId: step.id,
8625
+ stepStatus: "failed",
8626
+ error: String(err),
8627
+ duration: stepEndTime - stepStartTime,
8628
+ startTime: stepStartTime,
8629
+ endTime: stepEndTime
8630
+ });
8631
+ throw err;
7342
8632
  }
7343
8633
  }
7344
- if (isRequired && !hasFormField) {
7345
- throw new RegistryValidationError(
7346
- orgName,
7347
- resourceId,
7348
- "interface.form.fields",
7349
- `ExecutionInterface missing required field "${schemaFieldName}" from inputSchema in ${orgName}/${resourceId}`
7350
- );
8634
+ if (workflow.contract.outputSchema) {
8635
+ currentData = workflow.contract.outputSchema.parse(currentData);
7351
8636
  }
8637
+ return { output: currentData, logs };
8638
+ } finally {
8639
+ restore();
7352
8640
  }
7353
- for (const [formFieldName, schemaFieldName] of Array.from(formToSchemaMap.entries())) {
7354
- if (schemaFieldName.includes(".")) {
7355
- const topLevelField = schemaFieldName.split(".")[0];
7356
- throw new RegistryValidationError(
7357
- orgName,
7358
- resourceId,
7359
- `interface.form.fields.${formFieldName}`,
7360
- `ExecutionInterface field "${formFieldName}" uses nested notation. Flatten the inputSchema by moving nested fields to top-level (e.g., "${topLevelField}.x" \u2192 "x") in ${orgName}/${resourceId}`
7361
- );
7362
- }
7363
- if (!schemaFieldNames.includes(schemaFieldName)) {
7364
- throw new RegistryValidationError(
7365
- orgName,
7366
- resourceId,
7367
- `interface.form.fields.${formFieldName}`,
7368
- `ExecutionInterface field "${formFieldName}" maps to non-existent schema field "${schemaFieldName}" in ${orgName}/${resourceId}`
7369
- );
8641
+ }
8642
+ function buildWorkerExecutionContext(params) {
8643
+ const { executionId } = params;
8644
+ const postLog = (level, message) => {
8645
+ parentPort.postMessage({
8646
+ type: "log",
8647
+ entry: { level, message, timestamp: (/* @__PURE__ */ new Date()).toISOString(), executionId }
8648
+ });
8649
+ };
8650
+ return {
8651
+ executionId: params.executionId,
8652
+ organizationId: params.organizationId,
8653
+ organizationName: params.organizationName,
8654
+ resourceId: params.resourceId,
8655
+ sessionId: params.sessionId,
8656
+ sessionTurnNumber: params.sessionTurnNumber,
8657
+ parentExecutionId: params.parentExecutionId,
8658
+ executionDepth: params.executionDepth,
8659
+ signal: params.signal,
8660
+ store: /* @__PURE__ */ new Map(),
8661
+ logger: {
8662
+ debug: (msg) => {
8663
+ console.log(`[debug] ${msg}`);
8664
+ postLog("info", msg);
8665
+ },
8666
+ info: (msg) => {
8667
+ console.log(`[info] ${msg}`);
8668
+ postLog("info", msg);
8669
+ },
8670
+ warn: (msg) => {
8671
+ console.warn(`[warn] ${msg}`);
8672
+ postLog("warn", msg);
8673
+ },
8674
+ error: (msg) => {
8675
+ console.error(`[error] ${msg}`);
8676
+ postLog("error", msg);
8677
+ }
8678
+ },
8679
+ onMessageEvent: async (event) => {
8680
+ parentPort.postMessage({ type: "message-event", executionId, event });
7370
8681
  }
7371
- }
8682
+ };
7372
8683
  }
7373
- function extractZodShape(schema) {
7374
- if ("shape" in schema && typeof schema.shape === "object") {
7375
- return schema.shape;
7376
- }
7377
- if ("_def" in schema) {
7378
- const def = schema._def;
7379
- if (def.innerType) {
7380
- return extractZodShape(def.innerType);
8684
+ function startWorker(org) {
8685
+ const workflows = new Map((org.workflows ?? []).map((w2) => [w2.config.resourceId, w2]));
8686
+ const agents = new Map((org.agents ?? []).map((a3) => [a3.config.resourceId, a3]));
8687
+ let localAbortController = new AbortController();
8688
+ console.log(`[SDK-WORKER] Worker started with ${workflows.size} workflow(s), ${agents.size} agent(s)`);
8689
+ parentPort.on("message", async (msg) => {
8690
+ if (msg.type === "manifest") {
8691
+ parentPort.postMessage({
8692
+ type: "manifest",
8693
+ workflows: (org.workflows ?? []).map((w2) => ({
8694
+ resourceId: w2.config.resourceId,
8695
+ name: w2.config.name,
8696
+ type: w2.config.type,
8697
+ status: w2.config.status,
8698
+ description: w2.config.description,
8699
+ version: w2.config.version,
8700
+ links: w2.config.links,
8701
+ category: w2.config.category,
8702
+ contract: {
8703
+ inputSchema: safeZodToJsonSchema(w2.contract?.inputSchema),
8704
+ outputSchema: safeZodToJsonSchema(w2.contract?.outputSchema)
8705
+ },
8706
+ steps: Object.values(w2.steps).map((step) => ({
8707
+ id: step.id,
8708
+ name: step.name,
8709
+ description: step.description,
8710
+ inputSchema: safeZodToJsonSchema(step.inputSchema),
8711
+ outputSchema: safeZodToJsonSchema(step.outputSchema),
8712
+ next: serializeNext(step.next)
8713
+ })),
8714
+ entryPoint: w2.entryPoint
8715
+ })),
8716
+ agents: (org.agents ?? []).map((a3) => ({
8717
+ resourceId: a3.config.resourceId,
8718
+ name: a3.config.name,
8719
+ type: a3.config.type,
8720
+ status: a3.config.status,
8721
+ description: a3.config.description,
8722
+ version: a3.config.version,
8723
+ links: a3.config.links,
8724
+ category: a3.config.category,
8725
+ contract: {
8726
+ inputSchema: safeZodToJsonSchema(a3.contract?.inputSchema),
8727
+ outputSchema: safeZodToJsonSchema(a3.contract?.outputSchema)
8728
+ }
8729
+ })),
8730
+ triggers: org.triggers ?? [],
8731
+ integrations: org.integrations ?? [],
8732
+ humanCheckpoints: org.humanCheckpoints ?? [],
8733
+ relationships: org.relationships ?? void 0
8734
+ });
8735
+ return;
7381
8736
  }
7382
- if (def.schema) {
7383
- return extractZodShape(def.schema);
8737
+ if (msg.type === "tool-result") {
8738
+ handleToolResult(msg);
8739
+ return;
7384
8740
  }
7385
- }
7386
- return null;
7387
- }
7388
- function isZodOptional(schema) {
7389
- return schema.isOptional();
7390
- }
7391
- function validateRelationships(orgName, resources) {
7392
- if (!resources.relationships && !resources.triggers && !resources.externalResources && !resources.humanCheckpoints)
7393
- return;
7394
- const validAgentIds = new Set(resources.agents?.map((a3) => a3.config.resourceId) ?? []);
7395
- const validWorkflowIds = new Set(resources.workflows?.map((w2) => w2.config.resourceId) ?? []);
7396
- const validIntegrationIds = new Set(resources.integrations?.map((i) => i.resourceId) ?? []);
7397
- const validTriggerIds = new Set(resources.triggers?.map((t) => t.resourceId) ?? []);
7398
- const allInternalIds = /* @__PURE__ */ new Set([
7399
- ...Array.from(validAgentIds),
7400
- ...Array.from(validWorkflowIds),
7401
- ...Array.from(validTriggerIds),
7402
- ...Array.from(validIntegrationIds)
7403
- ]);
7404
- validateTriggers(orgName, resources.triggers ?? []);
7405
- validateResourceRelationships(
7406
- orgName,
7407
- resources.relationships ?? {},
7408
- validAgentIds,
7409
- validWorkflowIds,
7410
- validIntegrationIds,
7411
- validTriggerIds
7412
- );
7413
- validateExternalResources(
7414
- orgName,
7415
- resources.externalResources ?? [],
7416
- allInternalIds,
7417
- validAgentIds,
7418
- validWorkflowIds,
7419
- validIntegrationIds
7420
- );
7421
- validateHumanCheckpoints(orgName, resources.humanCheckpoints ?? [], allInternalIds, validAgentIds, validWorkflowIds);
7422
- }
7423
- function validateTriggers(_orgName, _triggers, _validAgentIds, _validWorkflowIds) {
7424
- }
7425
- function validateResourceRelationships(orgName, relationships, validAgentIds, validWorkflowIds, validIntegrationIds, validTriggerIds) {
7426
- for (const [resourceId, declaration] of Object.entries(relationships)) {
7427
- const resourceExists = validAgentIds.has(resourceId) || validWorkflowIds.has(resourceId) || validTriggerIds.has(resourceId);
7428
- if (!resourceExists) {
7429
- throw new RegistryValidationError(
7430
- orgName,
7431
- resourceId,
7432
- null,
7433
- `[${orgName}] Relationship declared for non-existent resource: ${resourceId}`
7434
- );
8741
+ if (msg.type === "credential-result") {
8742
+ handleCredentialResult(msg);
8743
+ return;
8744
+ }
8745
+ if (msg.type === "abort") {
8746
+ console.log("[SDK-WORKER] Abort requested by parent");
8747
+ localAbortController.abort();
8748
+ return;
7435
8749
  }
7436
- declaration.triggers?.agents?.forEach((agentId) => {
7437
- if (!validAgentIds.has(agentId)) {
7438
- throw new RegistryValidationError(
7439
- orgName,
7440
- resourceId,
7441
- "triggers.agents",
7442
- `[${orgName}] Resource '${resourceId}' triggers non-existent agent: ${agentId}`
7443
- );
7444
- }
7445
- });
7446
- declaration.triggers?.workflows?.forEach((workflowId) => {
7447
- if (!validWorkflowIds.has(workflowId)) {
7448
- throw new RegistryValidationError(
7449
- orgName,
7450
- resourceId,
7451
- "triggers.workflows",
7452
- `[${orgName}] Resource '${resourceId}' triggers non-existent workflow: ${workflowId}`
7453
- );
8750
+ if (msg.type === "execute") {
8751
+ const {
8752
+ resourceId,
8753
+ executionId,
8754
+ input,
8755
+ organizationId,
8756
+ organizationName,
8757
+ sessionId,
8758
+ sessionTurnNumber,
8759
+ parentExecutionId,
8760
+ executionDepth
8761
+ } = msg;
8762
+ console.log(`[SDK-WORKER] Execute request: resourceId=${resourceId}, executionId=${executionId}`);
8763
+ localAbortController = new AbortController();
8764
+ const workflow = workflows.get(resourceId);
8765
+ if (workflow) {
8766
+ const startTime = Date.now();
8767
+ try {
8768
+ console.log(`[SDK-WORKER] Running workflow '${resourceId}' (${Object.keys(workflow.steps).length} steps)`);
8769
+ const { output, logs } = await executeWorkflow(workflow, input, {
8770
+ executionId,
8771
+ organizationId: organizationId ?? "",
8772
+ organizationName: organizationName ?? "",
8773
+ sessionId,
8774
+ sessionTurnNumber,
8775
+ parentExecutionId,
8776
+ executionDepth: executionDepth ?? 0
8777
+ });
8778
+ const durationMs = Date.now() - startTime;
8779
+ console.log(`[SDK-WORKER] Workflow '${resourceId}' completed (${durationMs}ms)`);
8780
+ parentPort.postMessage({ type: "result", status: "completed", output, logs, metrics: { durationMs } });
8781
+ } catch (err) {
8782
+ const durationMs = Date.now() - startTime;
8783
+ console.error(`[SDK-WORKER] Workflow '${resourceId}' failed (${durationMs}ms): ${String(err)}`);
8784
+ parentPort.postMessage({
8785
+ type: "result",
8786
+ status: "failed",
8787
+ error: String(err),
8788
+ logs: [],
8789
+ metrics: { durationMs }
8790
+ });
8791
+ }
8792
+ return;
7454
8793
  }
7455
- });
7456
- declaration.uses?.integrations?.forEach((integrationId) => {
7457
- if (!validIntegrationIds.has(integrationId)) {
7458
- throw new RegistryValidationError(
7459
- orgName,
7460
- resourceId,
7461
- "uses.integrations",
7462
- `[${orgName}] Resource '${resourceId}' uses non-existent integration: ${integrationId}`
7463
- );
8794
+ const agentDef = agents.get(resourceId);
8795
+ if (agentDef) {
8796
+ const logs = [];
8797
+ const { restore } = captureConsole(executionId, logs);
8798
+ const startTime = Date.now();
8799
+ try {
8800
+ console.log(`[SDK-WORKER] Running agent '${resourceId}' (${agentDef.tools.length} tools)`);
8801
+ const adapterFactory = createPostMessageAdapterFactory();
8802
+ const agentInstance = new Agent(agentDef, adapterFactory);
8803
+ const context = buildWorkerExecutionContext({
8804
+ executionId,
8805
+ organizationId: organizationId ?? "",
8806
+ organizationName: organizationName ?? "",
8807
+ resourceId,
8808
+ sessionId,
8809
+ sessionTurnNumber,
8810
+ parentExecutionId,
8811
+ executionDepth: executionDepth ?? 0,
8812
+ signal: localAbortController.signal
8813
+ });
8814
+ const output = await agentInstance.execute(input, context);
8815
+ const durationMs = Date.now() - startTime;
8816
+ console.log(`[SDK-WORKER] Agent '${resourceId}' completed (${durationMs}ms)`);
8817
+ parentPort.postMessage({ type: "result", status: "completed", output, logs, metrics: { durationMs } });
8818
+ } catch (err) {
8819
+ const durationMs = Date.now() - startTime;
8820
+ const errorMessage = err?.message ?? String(err);
8821
+ err?.code ?? "unknown";
8822
+ const errorName = err?.name ?? err?.constructor?.name ?? "Error";
8823
+ console.error(`[SDK-WORKER] Agent '${resourceId}' failed (${durationMs}ms): [${errorName}] ${errorMessage}`);
8824
+ parentPort.postMessage({
8825
+ type: "result",
8826
+ status: "failed",
8827
+ error: `${errorName}: ${errorMessage}`,
8828
+ logs,
8829
+ metrics: { durationMs }
8830
+ });
8831
+ } finally {
8832
+ restore();
8833
+ }
8834
+ return;
7464
8835
  }
7465
- });
7466
- }
7467
- }
7468
- function validateExternalResources(orgName, externalResources, allInternalIds, validAgentIds, validWorkflowIds, validIntegrationIds) {
7469
- externalResources.forEach((external) => {
7470
- if (allInternalIds.has(external.resourceId)) {
7471
- throw new RegistryValidationError(
7472
- orgName,
7473
- external.resourceId,
7474
- null,
7475
- `[${orgName}] External resource ID '${external.resourceId}' conflicts with internal resource ID`
7476
- );
8836
+ console.error(`[SDK-WORKER] Resource not found: ${resourceId}`);
8837
+ parentPort.postMessage({
8838
+ type: "result",
8839
+ status: "failed",
8840
+ error: `Resource not found: ${resourceId}`,
8841
+ logs: []
8842
+ });
7477
8843
  }
7478
- external.triggers?.agents?.forEach((agentId) => {
7479
- if (!validAgentIds.has(agentId)) {
7480
- throw new RegistryValidationError(
7481
- orgName,
7482
- external.resourceId,
7483
- "triggers.agents",
7484
- `[${orgName}] External resource '${external.resourceId}' triggers non-existent agent: ${agentId}`
7485
- );
7486
- }
7487
- });
7488
- external.triggers?.workflows?.forEach((workflowId) => {
7489
- if (!validWorkflowIds.has(workflowId)) {
7490
- throw new RegistryValidationError(
7491
- orgName,
7492
- external.resourceId,
7493
- "triggers.workflows",
7494
- `[${orgName}] External resource '${external.resourceId}' triggers non-existent workflow: ${workflowId}`
7495
- );
7496
- }
7497
- });
7498
- external.uses?.integrations?.forEach((integrationId) => {
7499
- if (!validIntegrationIds.has(integrationId)) {
7500
- throw new RegistryValidationError(
7501
- orgName,
7502
- external.resourceId,
7503
- "uses.integrations",
7504
- `[${orgName}] External resource '${external.resourceId}' uses non-existent integration: ${integrationId}`
7505
- );
7506
- }
7507
- });
7508
8844
  });
7509
8845
  }
7510
- function validateHumanCheckpoints(orgName, humanCheckpoints, allInternalIds, validAgentIds, validWorkflowIds) {
7511
- humanCheckpoints.forEach((humanCheckpoint) => {
7512
- if (allInternalIds.has(humanCheckpoint.resourceId)) {
7513
- throw new RegistryValidationError(
7514
- orgName,
7515
- humanCheckpoint.resourceId,
7516
- null,
7517
- `[${orgName}] Human checkpoint ID '${humanCheckpoint.resourceId}' conflicts with internal resource ID`
7518
- );
8846
+ if (workerData != null && workerData.kind === "static") {
8847
+ const { modulePath } = workerData;
8848
+ void (async () => {
8849
+ const mod = await import(modulePath);
8850
+ startWorker(mod.default);
8851
+ })();
8852
+ }
8853
+
8854
+ // src/test-utils/workflow.ts
8855
+ function extractStepEvents(logs) {
8856
+ return logs.flatMap((log) => {
8857
+ const context = log.context;
8858
+ if (!context || context.type !== "workflow" || typeof context.contextType !== "string") {
8859
+ return [];
7519
8860
  }
7520
- humanCheckpoint.requestedBy?.agents?.forEach((agentId) => {
7521
- if (!validAgentIds.has(agentId)) {
7522
- throw new RegistryValidationError(
7523
- orgName,
7524
- humanCheckpoint.resourceId,
7525
- "requestedBy.agents",
7526
- `[${orgName}] Human checkpoint '${humanCheckpoint.resourceId}' requestedBy non-existent agent: ${agentId}`
7527
- );
7528
- }
7529
- });
7530
- humanCheckpoint.requestedBy?.workflows?.forEach((workflowId) => {
7531
- if (!validWorkflowIds.has(workflowId)) {
7532
- throw new RegistryValidationError(
7533
- orgName,
7534
- humanCheckpoint.resourceId,
7535
- "requestedBy.workflows",
7536
- `[${orgName}] Human checkpoint '${humanCheckpoint.resourceId}' requestedBy non-existent workflow: ${workflowId}`
7537
- );
7538
- }
7539
- });
7540
- humanCheckpoint.routesTo?.agents?.forEach((agentId) => {
7541
- if (!validAgentIds.has(agentId)) {
7542
- throw new RegistryValidationError(
7543
- orgName,
7544
- humanCheckpoint.resourceId,
7545
- "routesTo.agents",
7546
- `[${orgName}] Human checkpoint '${humanCheckpoint.resourceId}' routesTo non-existent agent: ${agentId}`
7547
- );
7548
- }
7549
- });
7550
- humanCheckpoint.routesTo?.workflows?.forEach((workflowId) => {
7551
- if (!validWorkflowIds.has(workflowId)) {
7552
- throw new RegistryValidationError(
7553
- orgName,
7554
- humanCheckpoint.resourceId,
7555
- "routesTo.workflows",
7556
- `[${orgName}] Human checkpoint '${humanCheckpoint.resourceId}' routesTo non-existent workflow: ${workflowId}`
7557
- );
8861
+ return [
8862
+ {
8863
+ type: context.contextType,
8864
+ stepId: typeof context.stepId === "string" ? context.stepId : void 0,
8865
+ stepStatus: typeof context.stepStatus === "string" ? context.stepStatus : void 0,
8866
+ input: context.input,
8867
+ output: context.output,
8868
+ error: context.error,
8869
+ duration: typeof context.duration === "number" ? context.duration : void 0,
8870
+ target: typeof context.target === "string" ? context.target : void 0,
8871
+ raw: context
7558
8872
  }
7559
- });
8873
+ ];
8874
+ });
8875
+ }
8876
+ async function runWorkflow(definition, input, options = {}) {
8877
+ const context = options.context ?? {};
8878
+ const { output, logs } = await executeWorkflow(definition, input, {
8879
+ executionId: context.executionId ?? `test-${Date.now()}`,
8880
+ organizationId: context.organizationId ?? "test-org",
8881
+ organizationName: context.organizationName ?? "Test Organization",
8882
+ sessionId: context.sessionId,
8883
+ sessionTurnNumber: context.sessionTurnNumber,
8884
+ parentExecutionId: context.parentExecutionId,
8885
+ executionDepth: context.executionDepth ?? 0,
8886
+ adapters: options.adapters
7560
8887
  });
8888
+ return {
8889
+ output,
8890
+ logs,
8891
+ stepEvents: extractStepEvents(logs)
8892
+ };
7561
8893
  }
7562
8894
 
7563
8895
  // src/test-utils/registry.ts
@@ -24328,7 +25660,14 @@ var mockCrm = (overrides) => createMockAdapter(
24328
25660
  overrides
24329
25661
  );
24330
25662
  var mockList = (overrides) => createMockAdapter(
24331
- ["getConfig", "recordExecution", "updateCompanyStage", "updateContactStage"],
25663
+ [
25664
+ "getConfig",
25665
+ "recordExecution",
25666
+ "updateCompanyStage",
25667
+ "updateContactStage",
25668
+ "listPendingCompanyIds",
25669
+ "listPendingContactIds"
25670
+ ],
24332
25671
  overrides
24333
25672
  );
24334
25673
  var mockPdf = (overrides) => createMockAdapter(["render", "renderToBuffer"], overrides);