@signaliz/sdk 1.0.5 → 1.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -21,17 +21,27 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
23
  Ai: () => Ai,
24
+ CAMPAIGN_BUILDER_OPERATING_PLAYBOOKS: () => CAMPAIGN_BUILDER_OPERATING_PLAYBOOKS,
25
+ CAMPAIGN_BUILDER_STRATEGY_TEMPLATES: () => CAMPAIGN_BUILDER_STRATEGY_TEMPLATES,
24
26
  CampaignBuilderAgent: () => CampaignBuilderAgent,
25
27
  Campaigns: () => Campaigns,
28
+ DEFAULT_CAMPAIGN_BUILDER_APPROVAL_TYPES: () => DEFAULT_CAMPAIGN_BUILDER_APPROVAL_TYPES,
29
+ DEFAULT_CAMPAIGN_BUILDER_BUILT_INS: () => DEFAULT_CAMPAIGN_BUILDER_BUILT_INS,
26
30
  DEFAULT_SIGNALIZ_CAMPAIGN_BUILDER_DEFAULTS: () => DEFAULT_SIGNALIZ_CAMPAIGN_BUILDER_DEFAULTS,
27
31
  GtmKernel: () => GtmKernel,
28
32
  Icps: () => Icps,
29
33
  Ops: () => Ops,
30
34
  Signaliz: () => Signaliz,
31
35
  SignalizError: () => SignalizError,
36
+ applyCampaignBuilderStrategyTemplate: () => applyCampaignBuilderStrategyTemplate,
32
37
  collectExecutionReferences: () => collectExecutionReferences,
33
38
  createCampaignBuilderAgentPlan: () => createCampaignBuilderAgentPlan,
39
+ createCampaignBuilderAgentRequestTemplate: () => createCampaignBuilderAgentRequestTemplate,
34
40
  createCampaignBuilderApproval: () => createCampaignBuilderApproval,
41
+ createCampaignBuilderToolRoute: () => createCampaignBuilderToolRoute,
42
+ getCampaignBuilderOperatingPlaybook: () => getCampaignBuilderOperatingPlaybook,
43
+ getCampaignBuilderOperatingPlaybooksForRequest: () => getCampaignBuilderOperatingPlaybooksForRequest,
44
+ getCampaignBuilderStrategyTemplate: () => getCampaignBuilderStrategyTemplate,
35
45
  getMissingCampaignBuilderApprovals: () => getMissingCampaignBuilderApprovals,
36
46
  normalizeExecutionReference: () => normalizeExecutionReference
37
47
  });
@@ -790,7 +800,7 @@ var Campaigns = class {
790
800
  async build(request, options) {
791
801
  return this.buildCampaign(request, options);
792
802
  }
793
- /** Scope an agency/client campaign into a markdown brief plus build_campaign dry-run args. */
803
+ /** Scope an agency/customer campaign into a markdown brief plus build_campaign dry-run args. */
794
804
  async scope(request) {
795
805
  return this.scopeCampaign(request);
796
806
  }
@@ -972,7 +982,11 @@ function mapStatus(data) {
972
982
  errors: diagnosticMessages(data.errors),
973
983
  artifactCount: data.artifact_count ?? 0,
974
984
  providerRoute: mapProviderRoute(data),
975
- nextAction: data.next_action ?? "",
985
+ triggerRunId: typeof data.trigger_run_id === "string" ? data.trigger_run_id : null,
986
+ staleRunningPhase: data.stale_running_phase === true,
987
+ phaseAgeSeconds: numberOrNull(data.phase_age_seconds),
988
+ diagnostics: recordOrNull(data.diagnostics) ?? {},
989
+ nextAction: formatNextAction(data.next_action),
976
990
  createdAt: data.created_at,
977
991
  updatedAt: data.updated_at,
978
992
  completedAt: data.completed_at
@@ -1012,6 +1026,19 @@ function diagnosticMessages(value) {
1012
1026
  return typeof record?.message === "string" ? record.message : null;
1013
1027
  }).filter((item) => typeof item === "string" && item.length > 0);
1014
1028
  }
1029
+ function formatNextAction(value) {
1030
+ if (!value) return "";
1031
+ if (typeof value === "string") return value;
1032
+ const record = recordOrNull(value);
1033
+ if (!record) return "";
1034
+ const tool = typeof record.tool === "string" ? record.tool : void 0;
1035
+ const type = typeof record.type === "string" ? record.type : void 0;
1036
+ const reason = typeof record.reason === "string" ? record.reason : void 0;
1037
+ const args = recordOrNull(record.arguments);
1038
+ const argText = args && Object.keys(args).length > 0 ? ` ${JSON.stringify(args)}` : "";
1039
+ const action = tool ? `${tool}${argText}` : type || "";
1040
+ return [action, reason].filter(Boolean).join(" \u2014 ");
1041
+ }
1015
1042
  function booleanOrNull(value) {
1016
1043
  return typeof value === "boolean" ? value : null;
1017
1044
  }
@@ -1052,7 +1079,7 @@ function mapArtifact(a) {
1052
1079
  function mapScope(data) {
1053
1080
  return {
1054
1081
  campaignScopeId: data.campaign_scope_id,
1055
- clientName: data.client_name,
1082
+ accountLabel: data.account_label,
1056
1083
  campaignName: data.campaign_name,
1057
1084
  approach: data.approach,
1058
1085
  approachLabel: data.approach_label,
@@ -1078,8 +1105,8 @@ function scopeArgs(request) {
1078
1105
  const args = {
1079
1106
  prompt: request.prompt
1080
1107
  };
1081
- if (request.clientName) args.client_name = request.clientName;
1082
- if (request.clientContext) args.client_context = request.clientContext;
1108
+ if (request.accountLabel) args.account_label = request.accountLabel;
1109
+ if (request.accountContext) args.account_context = request.accountContext;
1083
1110
  if (request.campaignGoal) args.campaign_goal = request.campaignGoal;
1084
1111
  if (request.targetCount) args.target_count = request.targetCount;
1085
1112
  if (request.destinations) args.destinations = request.destinations;
@@ -1207,22 +1234,565 @@ var DEFAULT_SIGNALIZ_CAMPAIGN_BUILDER_DEFAULTS = {
1207
1234
  approvalRequired: true
1208
1235
  }
1209
1236
  };
1237
+ var DEFAULT_CAMPAIGN_BUILDER_BUILT_INS = [
1238
+ "lead_generation",
1239
+ "email_finding",
1240
+ "email_verification",
1241
+ "signals"
1242
+ ];
1243
+ var DEFAULT_CAMPAIGN_BUILDER_APPROVAL_TYPES = [
1244
+ "memory_retrieval",
1245
+ "spend",
1246
+ "customer_tool",
1247
+ "external_write",
1248
+ "delivery",
1249
+ "launch"
1250
+ ];
1251
+ var CAMPAIGN_BUILDER_OPERATING_PLAYBOOKS = [
1252
+ {
1253
+ slug: "cache-first-large-list",
1254
+ label: "Cache-First Large List",
1255
+ whenToUse: [
1256
+ "The target count is high and reusable workspace lead or cache coverage may exist.",
1257
+ "The deliverable is a verified list or top-up rather than a deeply custom one-off workflow."
1258
+ ],
1259
+ sequence: [
1260
+ "Inventory reusable cache before paid sourcing.",
1261
+ "Report unique emails, role buckets, exclusions, and missing-field counts.",
1262
+ "Use fresh sourcing only for the approved gap.",
1263
+ "Write newly approved source metadata back to memory or cache after review."
1264
+ ],
1265
+ requiredFields: {
1266
+ inventory: ["matching_cached_rows", "unique_cached_emails", "persona_bucket_counts", "exclusions_applied", "missing_field_counts"],
1267
+ finalRows: ["first_name", "last_name", "company_name", "company_domain", "work_email", "email_status", "source_type"]
1268
+ },
1269
+ qualityGates: [
1270
+ "Deduplicate by normalized email before counting final rows.",
1271
+ "Separate cache reuse from fresh sourcing in the build receipt.",
1272
+ "Block export when required identity, company, or email fields are missing."
1273
+ ],
1274
+ activationBoundary: "Cache inventory is read-only. Fresh sourcing, cache writes, export, and sender loading require explicit approval.",
1275
+ memoryKeywords: ["cache inventory", "large list", "unique emails", "top-up sourcing", "source metadata"]
1276
+ },
1277
+ {
1278
+ slug: "net-new-suppressed-list",
1279
+ label: "Net-New Suppressed List",
1280
+ whenToUse: [
1281
+ "A prior campaign, seed list, or exclusion list must be suppressed.",
1282
+ "The operator needs both outreach-facing rows and provenance-rich QA evidence."
1283
+ ],
1284
+ sequence: [
1285
+ "Load suppression baselines before source selection.",
1286
+ "Apply email suppression as a hard gate and domain suppression as required by the brief.",
1287
+ "Keep provenance, source, and validation fields outside the outreach-facing export when needed.",
1288
+ "Run final overlap checks before any delivery action."
1289
+ ],
1290
+ requiredFields: {
1291
+ suppression: ["suppression_source", "prior_email_overlap", "prior_domain_match", "suppression_decision"],
1292
+ finalRows: ["first_name", "last_name", "company_name", "company_domain", "work_email", "email_status", "provenance_id"]
1293
+ },
1294
+ qualityGates: [
1295
+ "Prior email overlap must be zero for rows marked export ready.",
1296
+ "Prior-domain matches must be flagged or blocked according to the approved campaign promise.",
1297
+ "Do not describe rows as fully qualified when the approved path only proves net-new email status."
1298
+ ],
1299
+ activationBoundary: "Suppression review must pass before export, upload, CRM sync, sender load, or sequence launch.",
1300
+ memoryKeywords: ["suppression", "net-new", "prior email overlap", "domain review", "provenance-rich QA"]
1301
+ },
1302
+ {
1303
+ slug: "proof-first-vertical-gate",
1304
+ label: "Proof-First Vertical Gate",
1305
+ whenToUse: [
1306
+ "Wrong-account risk is high or the target category has close lookalike exclusions.",
1307
+ "Account proof is more important than raw lead volume."
1308
+ ],
1309
+ sequence: [
1310
+ "Define positive and negative proof fields before sourcing at scale.",
1311
+ "Qualify companies before contact discovery.",
1312
+ "Qualify contacts before email finding.",
1313
+ "Keep pass, review, and fail rows distinct through delivery review."
1314
+ ],
1315
+ requiredFields: {
1316
+ account: ["company_name", "company_domain", "source_url", "positive_proof", "negative_proof", "fit_score", "account_qualified"],
1317
+ contact: ["person_name", "person_title", "persona_match", "contact_fit_score", "contact_qualified"]
1318
+ },
1319
+ qualityGates: [
1320
+ "Do not spend on contact or email enrichment until the account passes the proof gate.",
1321
+ "Adjacent excluded categories must stay exclusions, not synonyms.",
1322
+ "Contact fit should meet the configured threshold before email finding or copy generation."
1323
+ ],
1324
+ activationBoundary: "Proof gates are required before contact spend, copy, export, or external writes.",
1325
+ memoryKeywords: ["proof gate", "vertical exclusion", "company before contact", "pass review fail", "fit threshold"]
1326
+ },
1327
+ {
1328
+ slug: "signal-led-copy-approval",
1329
+ label: "Signal-Led Copy With Approval",
1330
+ whenToUse: [
1331
+ "Outbound copy should be grounded in company signals, proof fields, or row context.",
1332
+ "Delivery destinations must remain locked after copy generation until review."
1333
+ ],
1334
+ sequence: [
1335
+ "Validate list quality before copy.",
1336
+ "Attach the strongest supported signal and source evidence.",
1337
+ "Generate copy only for fit-qualified and contactable rows.",
1338
+ "Hold every destination behind explicit approval."
1339
+ ],
1340
+ requiredFields: {
1341
+ evidence: ["strongest_signal", "signal_source_url", "why_now", "personalization_basis"],
1342
+ copy: ["subject_line", "opening_line", "email_copy", "copy_ready", "copy_blocker"]
1343
+ },
1344
+ qualityGates: [
1345
+ "Copy cannot invent unsupported pain, claims, numbers, or recent events.",
1346
+ "Weak evidence should route the row to review instead of send-ready copy.",
1347
+ "Destination fields must remain blocked until approval metadata is present."
1348
+ ],
1349
+ activationBoundary: "Copy readiness is not delivery approval. Export, sync, sender load, and launch require a separate human-approved gate.",
1350
+ memoryKeywords: ["company signals", "evidence-fed copy", "why now", "copy blocker", "approval gate"]
1351
+ },
1352
+ {
1353
+ slug: "domain-first-recovery",
1354
+ label: "Domain-First Recovery",
1355
+ whenToUse: [
1356
+ "Strict yield is low and broad people sourcing creates noisy, duplicated, or off-fit rows.",
1357
+ "The account universe should be recovered or expanded before more contact spend."
1358
+ ],
1359
+ sequence: [
1360
+ "Model attrition after an initial sample.",
1361
+ "Source or recover account domains in tight slices.",
1362
+ "Filter domains locally before contact discovery.",
1363
+ "Use accepted domains as the seed for person and email work."
1364
+ ],
1365
+ requiredFields: {
1366
+ domainReview: ["company_domain", "source_slice", "domain_fit_score", "domain_rejection_reason", "accepted_domain"],
1367
+ recovery: ["target_gap", "expected_yield", "accepted_domain_count", "contact_pull_limit"]
1368
+ },
1369
+ qualityGates: [
1370
+ "Do not repeat broad people-with-email sourcing after strict yield proves low.",
1371
+ "Rejected domains should stay suppressed unless the operator changes the ICP.",
1372
+ "Target count means final held rows, not raw sourced rows."
1373
+ ],
1374
+ activationBoundary: "Domain recovery informs sourcing. Contact enrichment, paid qualification, and export still require approved gates.",
1375
+ memoryKeywords: ["domain-first", "yield modeling", "attrition", "accepted domains", "gap fill"]
1376
+ },
1377
+ {
1378
+ slug: "table-workflow-handoff",
1379
+ label: "Table Workflow Handoff",
1380
+ whenToUse: [
1381
+ "The campaign needs connected source, account, people, enrichment, copy, and destination tables.",
1382
+ "A workspace or partner tool owns part of the workflow through MCP, webhook, API, or managed integration."
1383
+ ],
1384
+ sequence: [
1385
+ "Create source/account context before child people rows.",
1386
+ "Carry source context into enrichment, copy, and destination mapping.",
1387
+ "Expose request-ready, result, error, blocker, and export-ready fields for every action.",
1388
+ "Dry-run provider routes and destination writes before activation."
1389
+ ],
1390
+ requiredFields: {
1391
+ workflow: ["source_record_id", "company_context", "request_ready", "provider_status", "error", "export_ready", "export_blocker"],
1392
+ destination: ["destination_type", "destination_status", "approval_status", "approved_by", "approved_at"]
1393
+ },
1394
+ qualityGates: [
1395
+ "Every paid/API action needs visible request readiness and parsed output fields.",
1396
+ "Child people rows must preserve the account context that justified the search.",
1397
+ "Provider route activation must dry-run before any external write."
1398
+ ],
1399
+ activationBoundary: "MCP, webhook, managed integration, and destination routes remain dry-run until the reviewed route and campaign are approved.",
1400
+ memoryKeywords: ["table workflow", "request ready", "provider status", "export blocker", "BYO integration"]
1401
+ }
1402
+ ];
1403
+ var CAMPAIGN_BUILDER_STRATEGY_TEMPLATES = [
1404
+ {
1405
+ slug: "industrial-ot-resilience",
1406
+ label: "Industrial OT Resilience",
1407
+ aliases: ["industrial ot", "ot resilience", "industrial continuity", "industrial-ot-resilience"],
1408
+ defaultTargetCount: 3e3,
1409
+ campaignName: "Industrial OT Resilience Net-New",
1410
+ accountContext: [
1411
+ "Strategy template: Signaliz-only OT, industrial, manufacturing, embedded systems, field service, cyber resilience, and business continuity sourcing.",
1412
+ "Use prior approved campaign output as the email suppression baseline; final files must have zero prior-used email overlap.",
1413
+ "Keep external qualification providers disabled unless the operator explicitly changes the requirement."
1414
+ ].join(" "),
1415
+ icp: {
1416
+ personas: [
1417
+ "OT leader",
1418
+ "Industrial automation leader",
1419
+ "Engineering leader",
1420
+ "IT infrastructure leader",
1421
+ "Reliability or maintenance leader",
1422
+ "Operations leader"
1423
+ ],
1424
+ industries: [
1425
+ "Machinery",
1426
+ "Electrical and electronic manufacturing",
1427
+ "Mechanical or industrial engineering",
1428
+ "Industrial automation",
1429
+ "Semiconductors",
1430
+ "Medical devices",
1431
+ "Oil and energy",
1432
+ "Automotive"
1433
+ ],
1434
+ geographies: ["United States", "United Kingdom", "Canada", "Nordics", "Netherlands"],
1435
+ keywords: [
1436
+ "OT",
1437
+ "ICS",
1438
+ "SCADA",
1439
+ "control systems",
1440
+ "industrial automation",
1441
+ "manufacturing",
1442
+ "plant operations",
1443
+ "reliability",
1444
+ "maintenance",
1445
+ "PLC",
1446
+ "business continuity"
1447
+ ],
1448
+ exclusions: [
1449
+ "sales",
1450
+ "marketing",
1451
+ "recruiting",
1452
+ "HR",
1453
+ "finance",
1454
+ "legal",
1455
+ "customer success",
1456
+ "retail",
1457
+ "restaurants",
1458
+ "staffing",
1459
+ "real estate"
1460
+ ],
1461
+ requireVerifiedEmail: true
1462
+ },
1463
+ builtIns: ["lead_generation", "email_finding", "email_verification", "signals"],
1464
+ preferredProviders: ["signaliz_native"],
1465
+ memoryQueries: [{
1466
+ query: "industrial OT net-new prior email suppression verified manufacturing embedded systems field service cyber resilience business continuity",
1467
+ scopes: ["workspace", "operator_notes"],
1468
+ topK: 10,
1469
+ required: true,
1470
+ rationale: "Load OT sourcing, dedupe, cache metadata, and approval gates before planning net-new work."
1471
+ }],
1472
+ constraints: {
1473
+ deliverabilityNotes: [
1474
+ "Require verified email, valid syntax, first name, last name, company name, and normalized company domain.",
1475
+ "Keep export, upload, sync, send, and replacement actions blocked until explicit approval.",
1476
+ "Treat prior-domain matches as flagged review evidence unless strict domain suppression is explicitly requested."
1477
+ ]
1478
+ },
1479
+ signalizDefaults: {
1480
+ copy: {
1481
+ offerContext: "Do not invent product claims. Anchor messaging only in row-supported OT, industrial, cyber resilience, backup/recovery, or business-continuity context."
1482
+ }
1483
+ },
1484
+ agencyContext: {
1485
+ partnerEcosystem: ["signaliz", "instantly", "nango"]
1486
+ },
1487
+ operatingPlaybookSlugs: ["net-new-suppressed-list", "proof-first-vertical-gate", "signal-led-copy-approval"]
1488
+ },
1489
+ {
1490
+ slug: "non-medical-home-care",
1491
+ label: "Non-Medical Home Care Operations",
1492
+ aliases: ["home care", "non-medical home care", "home-care-operations", "non-medical-home-care"],
1493
+ defaultTargetCount: 3e3,
1494
+ campaignName: "Mature Home Care Agency Operators",
1495
+ accountContext: [
1496
+ "Strategy template: mature US non-medical home care agencies with scale signals, proof fields, strict home-care vs home-health separation, and approval-gated export.",
1497
+ "Use proof before paid enrichment or copy. Preserve pass vs review ICP status because healthcare language often blurs home care and home health."
1498
+ ].join(" "),
1499
+ icp: {
1500
+ personas: [
1501
+ "Owner",
1502
+ "CEO",
1503
+ "COO",
1504
+ "Administrator",
1505
+ "Operations Director",
1506
+ "Scheduler",
1507
+ "Care coordinator leader"
1508
+ ],
1509
+ industries: ["Non-medical home care", "Senior care", "Private duty care", "Home services"],
1510
+ companySizes: ["20+ employees", "600+ billable care hours/week", "1000+ billable care hours/week ideal"],
1511
+ geographies: ["United States"],
1512
+ keywords: [
1513
+ "non-medical home care",
1514
+ "private duty",
1515
+ "caregiver recruiting",
1516
+ "multi-location",
1517
+ "franchise",
1518
+ "scheduler",
1519
+ "billing",
1520
+ "payroll",
1521
+ "EVV",
1522
+ "WellSky",
1523
+ "AxisCare",
1524
+ "CareSmartz360"
1525
+ ],
1526
+ exclusions: [
1527
+ "home health",
1528
+ "skilled nursing",
1529
+ "hospice",
1530
+ "hospital",
1531
+ "clinic",
1532
+ "therapy practice",
1533
+ "very small owner-only shop"
1534
+ ],
1535
+ requireVerifiedEmail: true
1536
+ },
1537
+ builtIns: ["lead_generation", "local_leads", "email_finding", "email_verification", "signals"],
1538
+ preferredProviders: ["signaliz_native", "octave", "clay_webhook", "apify"],
1539
+ memoryQueries: [{
1540
+ query: "mature non-medical home care agencies billable hours franchise caregiver recruiting proof gate qualification export approval",
1541
+ scopes: ["workspace", "operator_notes"],
1542
+ topK: 10,
1543
+ required: true,
1544
+ rationale: "Load home-care ICP gates, source lanes, qualification thresholds, and home-care exclusion logic."
1545
+ }],
1546
+ constraints: {
1547
+ deliverabilityNotes: [
1548
+ "Company proof and strict ICP gate must pass before contact search, email finding, Signaliz signals, or export.",
1549
+ "Home health is an exclusion signal, not a synonym for home care."
1550
+ ]
1551
+ },
1552
+ signalizDefaults: {
1553
+ copy: {
1554
+ offerContext: "Use angles around after-hours shift recovery, billing/payroll exceptions, multi-location consistency, and caregiver retention only when supported by evidence."
1555
+ }
1556
+ },
1557
+ agencyContext: {
1558
+ partnerEcosystem: ["clay", "octave", "signaliz", "instantly", "nango"]
1559
+ },
1560
+ operatingPlaybookSlugs: ["proof-first-vertical-gate", "domain-first-recovery", "table-workflow-handoff"]
1561
+ },
1562
+ {
1563
+ slug: "agency-founder-led",
1564
+ label: "Founder-Led Agency Services",
1565
+ aliases: ["agency founder", "founder-led agency", "agency-founder-led"],
1566
+ defaultTargetCount: 3e3,
1567
+ campaignName: "Founder-Led Agency Executive Campaign",
1568
+ accountContext: [
1569
+ "Strategy template: agency founder, owner, CEO, and executive sourcing across marketing services, creative, web, PR, ecommerce, paid media, SEO, content, and specialist digital agencies.",
1570
+ "Use suppression files, company-domain pool review, people/email verification queues, and final approval gates before any delivery action."
1571
+ ].join(" "),
1572
+ icp: {
1573
+ personas: ["Founder", "Owner", "CEO", "Managing Partner", "President", "Agency Executive"],
1574
+ industries: [
1575
+ "Marketing services",
1576
+ "Advertising services",
1577
+ "Digital marketing agency",
1578
+ "Creative agency",
1579
+ "PR and communications",
1580
+ "Ecommerce agency",
1581
+ "Paid media agency",
1582
+ "SEO agency",
1583
+ "Content agency"
1584
+ ],
1585
+ companySizes: ["11-50", "25-150", "51-200"],
1586
+ geographies: ["United States"],
1587
+ keywords: [
1588
+ "agency founder",
1589
+ "performance marketing",
1590
+ "paid media",
1591
+ "SEO",
1592
+ "content",
1593
+ "creative",
1594
+ "web design",
1595
+ "brand agency",
1596
+ "PR communications",
1597
+ "Shopify",
1598
+ "Klaviyo"
1599
+ ],
1600
+ exclusions: ["enterprise holding company", "staffing", "recruiting", "software-only vendor", "freelancer-only profile"],
1601
+ requireVerifiedEmail: true
1602
+ },
1603
+ builtIns: ["lead_generation", "email_finding", "email_verification", "signals"],
1604
+ preferredProviders: ["signaliz_native", "octave"],
1605
+ memoryQueries: [{
1606
+ query: "agency founder owner CEO marketing services suppression domain pool email verification final approval gate",
1607
+ scopes: ["workspace", "operator_notes"],
1608
+ topK: 10,
1609
+ required: true,
1610
+ rationale: "Load agency-segment sourcing lanes, suppression rules, and verification workflow lessons."
1611
+ }],
1612
+ constraints: {
1613
+ deliverabilityNotes: [
1614
+ "Keep email and domain suppression visible in the plan.",
1615
+ "Do not export or send until the final verified file and suppression checks are approved."
1616
+ ]
1617
+ },
1618
+ agencyContext: {
1619
+ partnerEcosystem: ["signaliz", "octave", "instantly", "nango"]
1620
+ },
1621
+ operatingPlaybookSlugs: ["net-new-suppressed-list", "signal-led-copy-approval", "table-workflow-handoff"]
1622
+ },
1623
+ {
1624
+ slug: "cloud-infrastructure-displacement",
1625
+ label: "Cloud Infrastructure Displacement",
1626
+ aliases: ["cloud displacement", "private cloud displacement", "cloud infrastructure", "cloud-infrastructure-displacement"],
1627
+ defaultTargetCount: 3e3,
1628
+ campaignName: "Cloud Infrastructure Displacement Campaign",
1629
+ accountContext: [
1630
+ "Strategy template: managed infrastructure, private cloud, disaster recovery, colocation, and VMware/Broadcom displacement motions.",
1631
+ "The spend-efficient ladder is Signaliz company search, Octave company qualification, Signaliz people search, Octave person qualification, then Signaliz email finding and verification."
1632
+ ].join(" "),
1633
+ icp: {
1634
+ personas: [
1635
+ "CTO",
1636
+ "CIO",
1637
+ "CISO",
1638
+ "CFO tied to cloud spend",
1639
+ "VP Engineering",
1640
+ "VP Infrastructure",
1641
+ "VP Cloud",
1642
+ "Head of Platform",
1643
+ "Director IT",
1644
+ "Cloud Architect",
1645
+ "Infrastructure Architect"
1646
+ ],
1647
+ industries: [
1648
+ "SaaS",
1649
+ "Software",
1650
+ "Cybersecurity",
1651
+ "Fintech",
1652
+ "Healthcare technology",
1653
+ "Compliance and GRC",
1654
+ "DevOps",
1655
+ "Infrastructure",
1656
+ "Observability"
1657
+ ],
1658
+ companySizes: ["$10M-$500M revenue", "50-1500 employees"],
1659
+ geographies: ["United States"],
1660
+ keywords: [
1661
+ "VMware Broadcom",
1662
+ "VxRail",
1663
+ "cloud cost pressure",
1664
+ "private cloud",
1665
+ "Proxmox",
1666
+ "Hyper-V",
1667
+ "managed infrastructure",
1668
+ "DRaaS",
1669
+ "colocation",
1670
+ "uptime",
1671
+ "reliability"
1672
+ ],
1673
+ exclusions: [
1674
+ "MSP competitor",
1675
+ "hosting provider",
1676
+ "data center competitor",
1677
+ "staffing",
1678
+ "recruiting",
1679
+ "international-only",
1680
+ "procurement-only",
1681
+ "AI GPU-heavy infrastructure"
1682
+ ],
1683
+ requireVerifiedEmail: true
1684
+ },
1685
+ builtIns: ["lead_generation", "email_finding", "email_verification", "signals"],
1686
+ preferredProviders: ["signaliz_native", "octave"],
1687
+ memoryQueries: [{
1688
+ query: "cloud hosting infrastructure VMware Broadcom qualification verified email persona trigger SKU mapping",
1689
+ scopes: ["workspace", "operator_notes"],
1690
+ topK: 10,
1691
+ required: true,
1692
+ rationale: "Load cloud-infrastructure qualification order, persona clusters, trigger/SKU mapping, and verified-list QA rules."
1693
+ }],
1694
+ constraints: {
1695
+ deliverabilityNotes: [
1696
+ "Qualify accounts and people before email verification.",
1697
+ "If signal enrichment is deferred or unavailable, state it plainly instead of inventing evidence."
1698
+ ]
1699
+ },
1700
+ signalizDefaults: {
1701
+ copy: {
1702
+ offerContext: "Map pain to routes such as VMware/Broadcom exit, cloud cost reduction, infrastructure modernization, compliance gap, managed infrastructure, private cloud, Proxmox/Hyper-V, colocation, or DRaaS."
1703
+ }
1704
+ },
1705
+ agencyContext: {
1706
+ partnerEcosystem: ["signaliz", "octave", "instantly", "nango"]
1707
+ },
1708
+ operatingPlaybookSlugs: ["proof-first-vertical-gate", "domain-first-recovery", "signal-led-copy-approval"]
1709
+ }
1710
+ ];
1210
1711
  var CampaignBuilderAgent = class {
1211
1712
  constructor(client) {
1212
1713
  this.client = client;
1213
1714
  }
1214
1715
  async createPlan(request, options = {}) {
1716
+ const resolvedRequest = applyCampaignBuilderStrategyTemplate(request);
1215
1717
  const warnings = [];
1216
- const workspaceContext = request.workspaceContext ?? await this.getWorkspaceContext(warnings);
1217
- const scopeResult = options.scopeCampaign === false ? void 0 : await this.scopeCampaign(request, warnings);
1718
+ const workspaceContext = resolvedRequest.workspaceContext ?? await this.getWorkspaceContext(warnings);
1719
+ const scopeResult = options.scopeCampaign === false ? void 0 : await this.scopeCampaign(resolvedRequest, warnings);
1218
1720
  if (options.discoverCapabilities !== false) {
1219
- await this.discoverPlannedRoutes(request, warnings);
1721
+ await this.discoverPlannedRoutes(resolvedRequest, warnings);
1220
1722
  }
1221
- return createCampaignBuilderAgentPlan(request, {
1723
+ const plan = createCampaignBuilderAgentPlan(resolvedRequest, {
1222
1724
  workspaceContext,
1223
1725
  scopeBuildArgs: asRecord(scopeResult?.build_campaign_args ?? scopeResult?.buildCampaignArgs),
1224
1726
  warnings
1225
1727
  });
1728
+ if (options.includeStrategyMemoryStatus !== false) {
1729
+ await this.attachStrategyMemoryStatus(plan, warnings);
1730
+ }
1731
+ if (options.includeKernelPlan !== false) {
1732
+ await this.attachKernelCampaignBuildPlan(plan, warnings);
1733
+ }
1734
+ if (options.includeDeliveryRisk !== false) {
1735
+ await this.attachDeliveryRiskPreflight(plan, warnings);
1736
+ }
1737
+ return plan;
1738
+ }
1739
+ async commitPlan(plan, options = {}) {
1740
+ const writeMode = options.confirm === true && options.dryRun === false;
1741
+ if (writeMode && !options.approvedBy) {
1742
+ throw new Error("Campaign builder plan commit requires approvedBy before writing state");
1743
+ }
1744
+ const plannerStep = plan.mcpFlow.find((step) => step.id === "agency-campaign-build-plan");
1745
+ const plannerArgs = asRecord(plannerStep?.arguments);
1746
+ const commitArgs = compact({
1747
+ campaign_id: plan.buildRequest.gtmCampaignId,
1748
+ name: plan.campaignName,
1749
+ campaign_brief: plan.buildRequest.prompt || plan.goal,
1750
+ target_icp: plan.buildRequest.icp ? buildGtmTargetIcpContext(plan.buildRequest.icp) : void 0,
1751
+ lead_count: plan.targetCount,
1752
+ layers: plannerArgs.layers,
1753
+ preferred_providers: plannerArgs.preferred_providers,
1754
+ plan_snapshot: Object.keys(asRecord(plan.kernelPlan)).length > 0 ? plan.kernelPlan : buildFallbackPlanSnapshot(plan),
1755
+ send_config: plan.buildRequest.delivery ? {
1756
+ delivery: plan.buildRequest.delivery,
1757
+ approval_required: true
1758
+ } : void 0,
1759
+ brain_config: compact({
1760
+ campaign_builder_agent_v1: {
1761
+ plan_id: plan.planId,
1762
+ kernel_plan_attached: Object.keys(asRecord(plan.kernelPlan)).length > 0,
1763
+ approval_ids: plan.approvals.map((approval) => approval.id)
1764
+ },
1765
+ brain_defaults: plan.buildRequest.brainDefaults,
1766
+ brain_preflight: plan.buildRequest.brainPreflight,
1767
+ delivery_risk_preflight: plan.buildRequest.deliveryRisk,
1768
+ delivery_risk: plan.buildRequest.deliveryRisk
1769
+ }),
1770
+ metadata: {
1771
+ campaign_builder_agent_v1: {
1772
+ plan_id: plan.planId,
1773
+ source: "campaign-builder-agent",
1774
+ approval_required: plan.approvals.some((approval) => approval.blocking),
1775
+ approval_ids: plan.approvals.map((approval) => approval.id),
1776
+ estimated_credits: plan.estimatedCredits
1777
+ },
1778
+ brain_delivery_risk_preflight: plan.buildRequest.deliveryRisk,
1779
+ delivery_risk: plan.buildRequest.deliveryRisk
1780
+ },
1781
+ approval_required: plan.approvals.some((approval) => approval.blocking),
1782
+ actor_type: "agent",
1783
+ actor_id: options.approvedBy,
1784
+ rationale: options.rationale || "Committed a reviewed strategy-template campaign-builder plan before execution.",
1785
+ idempotency_key: options.idempotencyKey,
1786
+ dry_run: !writeMode,
1787
+ confirm: writeMode
1788
+ });
1789
+ const data = asRecord(await this.callMcp("gtm_campaign_build_plan_commit", commitArgs));
1790
+ const result = mapPlanCommitResult(data);
1791
+ if (result.wroteState && result.campaignId) {
1792
+ plan.buildRequest.gtmCampaignId = result.campaignId;
1793
+ refreshBuildStepArguments(plan);
1794
+ }
1795
+ return result;
1226
1796
  }
1227
1797
  async dryRunPlan(plan, options) {
1228
1798
  let args = buildCampaignArgs({
@@ -1257,6 +1827,15 @@ var CampaignBuilderAgent = class {
1257
1827
  if (missing.length > 0) {
1258
1828
  throw new Error(`Campaign builder approval is incomplete: ${missing.map((a) => a.label).join(", ")}`);
1259
1829
  }
1830
+ if (options?.commitBeforeLaunch && !plan.buildRequest.gtmCampaignId) {
1831
+ await this.commitPlan(plan, {
1832
+ confirm: true,
1833
+ dryRun: false,
1834
+ approvedBy: approval.approvedBy,
1835
+ idempotencyKey: options.idempotencyKey ? `${options.idempotencyKey}:plan-commit` : void 0,
1836
+ rationale: "Committed reviewed campaign-builder plan immediately before approved launch."
1837
+ });
1838
+ }
1260
1839
  let args = buildCampaignArgs({
1261
1840
  ...plan.buildRequest,
1262
1841
  dryRun: false,
@@ -1303,8 +1882,8 @@ var CampaignBuilderAgent = class {
1303
1882
  try {
1304
1883
  return await this.callMcp("scope_campaign", {
1305
1884
  prompt: request.goal,
1306
- client_name: request.clientName,
1307
- client_context: request.clientContext,
1885
+ account_label: campaignBuilderAccountLabel(request),
1886
+ account_context: campaignBuilderAccountContext(request),
1308
1887
  campaign_goal: request.goal,
1309
1888
  target_count: request.targetCount,
1310
1889
  approval_policy: request.approvalPolicy?.requireHumanApproval ? "human_required" : "standard"
@@ -1329,25 +1908,70 @@ var CampaignBuilderAgent = class {
1329
1908
  }
1330
1909
  }
1331
1910
  }
1911
+ async attachStrategyMemoryStatus(plan, warnings) {
1912
+ const statusStep = plan.mcpFlow.find((step) => step.id === "strategy-memory-status");
1913
+ if (!statusStep) return;
1914
+ try {
1915
+ const status = asRecord(await this.callMcp("gtm_campaign_strategy_memory_status", asRecord(statusStep.arguments)));
1916
+ plan.strategyMemoryStatus = status;
1917
+ const blockers = arrayOfStrings(status.blockers) ?? [];
1918
+ if (status.ready === false || blockers.length > 0) {
1919
+ warnings.push(`Strategy memory readiness is incomplete: ${blockers.join("; ") || "missing required strategy or workflow memory"}`);
1920
+ }
1921
+ } catch (error) {
1922
+ warnings.push(`Strategy memory readiness check failed: ${errorMessage(error)}`);
1923
+ }
1924
+ }
1925
+ async attachKernelCampaignBuildPlan(plan, warnings) {
1926
+ const plannerStep = plan.mcpFlow.find((step) => step.id === "agency-campaign-build-plan");
1927
+ if (!plannerStep) return;
1928
+ try {
1929
+ const kernelPlan = await this.callMcp("gtm_campaign_build_plan", asRecord(plannerStep.arguments));
1930
+ plan.kernelPlan = asRecord(kernelPlan);
1931
+ const brainDefaults = asRecord(plan.kernelPlan.brain_defaults ?? plan.kernelPlan.brainDefaults);
1932
+ if (Object.keys(brainDefaults).length > 0 && Object.keys(asRecord(plan.buildRequest.brainDefaults)).length === 0) {
1933
+ plan.buildRequest.brainDefaults = brainDefaults;
1934
+ refreshBuildStepArguments(plan);
1935
+ }
1936
+ } catch (error) {
1937
+ warnings.push(`GTM Kernel campaign build plan failed: ${errorMessage(error)}`);
1938
+ }
1939
+ }
1940
+ async attachDeliveryRiskPreflight(plan, warnings) {
1941
+ if (Object.keys(asRecord(plan.buildRequest.deliveryRisk)).length > 0) return;
1942
+ const riskStep = plan.mcpFlow.find((step) => step.tool === "gtm_brain_delivery_risk");
1943
+ if (!riskStep) return;
1944
+ try {
1945
+ const deliveryRisk = asRecord(await this.callMcp("gtm_brain_delivery_risk", asRecord(riskStep.arguments)));
1946
+ if (Object.keys(deliveryRisk).length > 0) {
1947
+ plan.buildRequest.deliveryRisk = deliveryRisk;
1948
+ refreshBuildStepArguments(plan);
1949
+ }
1950
+ } catch (error) {
1951
+ warnings.push(`GTM Brain delivery risk preflight failed: ${errorMessage(error)}`);
1952
+ }
1953
+ }
1332
1954
  async callMcp(tool, args) {
1333
1955
  return this.client.mcp("tools/call", { name: tool, arguments: compact(args) });
1334
1956
  }
1335
1957
  };
1336
1958
  function createCampaignBuilderAgentPlan(request, context = {}) {
1337
- const defaults = mergeDefaults(request.signalizDefaults);
1338
- const targetCount = request.targetCount ?? numberOrUndefined2(context.scopeBuildArgs?.target_count) ?? 100;
1339
- const campaignName = request.campaignName ?? stringValue(context.scopeBuildArgs?.name) ?? titleFromGoal(request.goal);
1340
- const workspaceContext = context.workspaceContext ?? request.workspaceContext ?? {};
1341
- const memory = normalizeMemory(request);
1342
- const routes = normalizeRoutes(request);
1343
- const estimatedCredits = estimateCredits(request, defaults, targetCount);
1344
- const buildRequest = createBuildRequest(request, defaults, targetCount, campaignName, context.scopeBuildArgs, routes, memory, context.scopeBrainPreflight);
1959
+ const resolvedRequest = applyCampaignBuilderStrategyTemplate(request);
1960
+ const defaults = mergeDefaults(resolvedRequest.signalizDefaults);
1961
+ const targetCount = resolvedRequest.targetCount ?? numberOrUndefined2(context.scopeBuildArgs?.target_count) ?? 100;
1962
+ const campaignName = resolvedRequest.campaignName ?? stringValue(context.scopeBuildArgs?.name) ?? titleFromGoal(resolvedRequest.goal);
1963
+ const workspaceContext = context.workspaceContext ?? resolvedRequest.workspaceContext ?? {};
1964
+ const memory = normalizeMemory(resolvedRequest);
1965
+ const routes = normalizeRoutes(resolvedRequest);
1966
+ const operatingPlaybooks = getCampaignBuilderOperatingPlaybooksForRequest(resolvedRequest);
1967
+ const estimatedCredits = estimateCredits(resolvedRequest, defaults, targetCount);
1968
+ const buildRequest = createBuildRequest(resolvedRequest, defaults, targetCount, campaignName, context.scopeBuildArgs, routes, memory, context.scopeBrainPreflight);
1345
1969
  const brainPreflight = asRecord(buildRequest.brainPreflight);
1346
- const approvals = deriveApprovals(request, routes, memory, estimatedCredits, defaults.delivery?.approvalRequired !== false);
1970
+ const approvals = deriveApprovals(resolvedRequest, routes, memory, estimatedCredits, defaults.delivery?.approvalRequired !== false);
1347
1971
  return {
1348
- planId: `cbp_${hashString(JSON.stringify({ goal: request.goal, campaignName, targetCount, routes }))}`,
1972
+ planId: `cbp_${hashString(JSON.stringify({ goal: resolvedRequest.goal, campaignName, targetCount, routes }))}`,
1349
1973
  campaignName,
1350
- goal: request.goal,
1974
+ goal: resolvedRequest.goal,
1351
1975
  targetCount,
1352
1976
  workspaceContext,
1353
1977
  memory,
@@ -1360,7 +1984,8 @@ function createCampaignBuilderAgentPlan(request, context = {}) {
1360
1984
  approvals,
1361
1985
  buildRequest,
1362
1986
  brainPreflight,
1363
- mcpFlow: createMcpFlow(request, buildRequest, routes, memory, approvals),
1987
+ operatingPlaybooks,
1988
+ mcpFlow: createMcpFlow(resolvedRequest, buildRequest, routes, memory, approvals),
1364
1989
  estimatedCredits,
1365
1990
  warnings: context.warnings ?? []
1366
1991
  };
@@ -1388,6 +2013,249 @@ function createCampaignBuilderApproval(plan, input) {
1388
2013
  approvedAt: (/* @__PURE__ */ new Date()).toISOString()
1389
2014
  };
1390
2015
  }
2016
+ function getCampaignBuilderStrategyTemplate(value) {
2017
+ const normalized = normalizeTemplateKey(value);
2018
+ if (!normalized) return void 0;
2019
+ return CAMPAIGN_BUILDER_STRATEGY_TEMPLATES.find(
2020
+ (template) => template.slug === normalized || template.aliases.some((alias) => normalizeTemplateKey(alias) === normalized)
2021
+ );
2022
+ }
2023
+ function getCampaignBuilderOperatingPlaybook(value) {
2024
+ const normalized = normalizeTemplateKey(value);
2025
+ if (!normalized) return void 0;
2026
+ return CAMPAIGN_BUILDER_OPERATING_PLAYBOOKS.find((playbook) => playbook.slug === normalized);
2027
+ }
2028
+ function getCampaignBuilderOperatingPlaybooksForRequest(request) {
2029
+ const template = getCampaignBuilderStrategyTemplate(request.strategyTemplate);
2030
+ const slugs = uniqueStrings([
2031
+ ...template?.operatingPlaybookSlugs ?? [],
2032
+ ...request.operatingPlaybooks ?? []
2033
+ ]);
2034
+ return slugs.map(getCampaignBuilderOperatingPlaybook).filter((playbook) => Boolean(playbook));
2035
+ }
2036
+ function applyCampaignBuilderStrategyTemplate(request) {
2037
+ const template = getCampaignBuilderStrategyTemplate(request.strategyTemplate);
2038
+ if (!template) return request;
2039
+ return {
2040
+ ...request,
2041
+ strategyTemplate: template.slug,
2042
+ campaignName: request.campaignName ?? template.campaignName,
2043
+ accountContext: mergeText(template.accountContext, campaignBuilderAccountContext(request)),
2044
+ targetCount: request.targetCount ?? template.defaultTargetCount,
2045
+ icp: mergeIcp(template.icp, request.icp),
2046
+ builtIns: request.builtIns ?? template.builtIns,
2047
+ operatingPlaybooks: uniqueStrings([
2048
+ ...template.operatingPlaybookSlugs,
2049
+ ...request.operatingPlaybooks ?? []
2050
+ ]),
2051
+ preferredProviders: uniqueStrings([
2052
+ ...template.preferredProviders,
2053
+ ...request.preferredProviders ?? []
2054
+ ]),
2055
+ memory: mergeMemoryPlan({
2056
+ enabled: true,
2057
+ useWorkspaceHistory: true,
2058
+ useNetworkPatterns: request.memory?.useNetworkPatterns,
2059
+ privacyMode: request.memory?.privacyMode,
2060
+ queries: template.memoryQueries
2061
+ }, request.memory),
2062
+ constraints: mergeConstraints(template.constraints, request.constraints),
2063
+ signalizDefaults: mergeSignalizDefaultOverrides(template.signalizDefaults, request.signalizDefaults),
2064
+ agencyContext: mergeAgencyContext(template.agencyContext, request.agencyContext)
2065
+ };
2066
+ }
2067
+ function createCampaignBuilderAgentRequestTemplate(input = {}) {
2068
+ const builtIns = new Set(input.builtIns ?? DEFAULT_CAMPAIGN_BUILDER_BUILT_INS);
2069
+ if (input.includeLocalLeads) builtIns.add("local_leads");
2070
+ const integrations = input.integrations ?? (input.includeCustomToolPlaceholder ? [createCampaignBuilderToolRoute({
2071
+ provider: "custom_mcp",
2072
+ layer: "enrichment",
2073
+ gtmLayers: ["company_enrichment"],
2074
+ toolName: "workspace_enrich",
2075
+ mcpServerName: "workspace-mcp",
2076
+ label: "Workspace enrichment MCP",
2077
+ mode: "if_available",
2078
+ approvalRequired: true
2079
+ })] : void 0);
2080
+ const preferredProviders = uniqueStrings([
2081
+ ...input.preferredProviders ?? [],
2082
+ ...input.includeNango === false ? [] : ["nango"]
2083
+ ]);
2084
+ const templated = applyCampaignBuilderStrategyTemplate({
2085
+ goal: input.goal || "Build a strategy-template campaign for mature operators in the target ICP.",
2086
+ strategyTemplate: input.strategyTemplate || "non-medical-home-care",
2087
+ campaignName: input.campaignName,
2088
+ accountLabel: input.accountLabel || "Workspace Campaign",
2089
+ accountContext: input.accountContext || "Use private workspace memory, current suppression rules, verified-email quality gates, and approval-gated provider routes.",
2090
+ targetCount: input.targetCount,
2091
+ icp: input.icp ?? {
2092
+ personas: ["Operations leader", "Founder", "Revenue leader"],
2093
+ industries: ["B2B services", "Vertical software", "Local operators"],
2094
+ geographies: ["United States"],
2095
+ keywords: ["growth", "operations", "customer acquisition"],
2096
+ requireVerifiedEmail: true
2097
+ },
2098
+ builtIns: [...builtIns],
2099
+ integrations,
2100
+ customerTools: input.customerTools,
2101
+ preferredProviders,
2102
+ constraints: input.constraints,
2103
+ workspaceContext: input.workspaceContext,
2104
+ brainDefaults: input.brainDefaults,
2105
+ deliveryRisk: input.deliveryRisk,
2106
+ gtmCampaignId: input.gtmCampaignId
2107
+ });
2108
+ return compact({
2109
+ ...templated,
2110
+ memory: mergeMemoryPlan({
2111
+ enabled: true,
2112
+ useWorkspaceHistory: true,
2113
+ useNetworkPatterns: false,
2114
+ privacyMode: "anonymized_patterns",
2115
+ queries: [{
2116
+ query: `${templated.strategyTemplate || "strategy-template"} campaign reply patterns, objections, qualification gates, and verified-email QA`,
2117
+ scopes: ["workspace", "operator_notes"],
2118
+ topK: 10,
2119
+ required: true,
2120
+ rationale: "Load approved private strategy and workflow patterns before campaign planning."
2121
+ }]
2122
+ }, input.memory),
2123
+ agencyContext: mergeAgencyContext({
2124
+ strategyModel: "strategy_template",
2125
+ includeStrategyPatterns: true,
2126
+ includeWorkflowPatterns: true,
2127
+ includeNangoCatalog: true,
2128
+ partnerEcosystem: input.includeNango === false ? ["signaliz"] : ["signaliz", "nango"]
2129
+ }, input.agencyContext),
2130
+ signalizDefaults: mergeSignalizDefaultOverrides({
2131
+ maxCredits: input.signalizDefaults?.maxCredits,
2132
+ delivery: {
2133
+ enabled: true,
2134
+ destinationType: input.signalizDefaults?.delivery?.destinationType ?? "json",
2135
+ approvalRequired: true
2136
+ }
2137
+ }, input.signalizDefaults),
2138
+ approvalPolicy: {
2139
+ requireHumanApproval: true,
2140
+ maxCreditsWithoutApproval: 0,
2141
+ requireApprovalFor: DEFAULT_CAMPAIGN_BUILDER_APPROVAL_TYPES,
2142
+ ...input.approvalPolicy
2143
+ }
2144
+ });
2145
+ }
2146
+ function createCampaignBuilderToolRoute(input) {
2147
+ return {
2148
+ provider: input.provider ?? "custom_mcp",
2149
+ layer: input.layer,
2150
+ toolName: input.toolName,
2151
+ mcpServerName: input.mcpServerName,
2152
+ label: input.label,
2153
+ mode: input.mode ?? "if_available",
2154
+ gtmLayer: input.gtmLayer,
2155
+ gtmLayers: input.gtmLayers,
2156
+ approvalRequired: input.approvalRequired ?? input.mode === "required",
2157
+ config: input.config,
2158
+ rationale: `${input.label ?? input.provider ?? "Custom tool"} is a user-provided campaign-builder route for ${input.layer}.`
2159
+ };
2160
+ }
2161
+ function normalizeTemplateKey(value) {
2162
+ return String(value || "").trim().toLowerCase().replace(/[_\s]+/g, "-");
2163
+ }
2164
+ function mergeText(base, override) {
2165
+ if (base && override && !base.includes(override)) return `${base}
2166
+ ${override}`;
2167
+ return override ?? base;
2168
+ }
2169
+ function mergeIcp(base, override) {
2170
+ if (!base) return override;
2171
+ if (!override) return base;
2172
+ return {
2173
+ ...base,
2174
+ ...override,
2175
+ personas: uniqueStrings([...base.personas ?? [], ...override.personas ?? []]),
2176
+ industries: uniqueStrings([...base.industries ?? [], ...override.industries ?? []]),
2177
+ companySizes: uniqueStrings([...base.companySizes ?? [], ...override.companySizes ?? []]),
2178
+ geographies: uniqueStrings([...base.geographies ?? [], ...override.geographies ?? []]),
2179
+ keywords: uniqueStrings([...base.keywords ?? [], ...override.keywords ?? []]),
2180
+ exclusions: uniqueStrings([...base.exclusions ?? [], ...override.exclusions ?? []]),
2181
+ requireVerifiedEmail: override.requireVerifiedEmail ?? base.requireVerifiedEmail
2182
+ };
2183
+ }
2184
+ function mergeMemoryPlan(base, override) {
2185
+ const queries = dedupeMemoryQueries([...base.queries ?? [], ...override?.queries ?? []]);
2186
+ return {
2187
+ ...base,
2188
+ ...override,
2189
+ queries: queries.length > 0 ? queries : void 0,
2190
+ enabled: override?.enabled ?? base.enabled,
2191
+ useWorkspaceHistory: override?.useWorkspaceHistory ?? base.useWorkspaceHistory,
2192
+ useNetworkPatterns: override?.useNetworkPatterns ?? base.useNetworkPatterns,
2193
+ privacyMode: override?.privacyMode ?? base.privacyMode
2194
+ };
2195
+ }
2196
+ function dedupeMemoryQueries(queries) {
2197
+ const seen = /* @__PURE__ */ new Set();
2198
+ return queries.filter((query) => {
2199
+ const key = query.query.trim().toLowerCase();
2200
+ if (!key || seen.has(key)) return false;
2201
+ seen.add(key);
2202
+ return true;
2203
+ });
2204
+ }
2205
+ function mergeConstraints(base, override) {
2206
+ if (!base) return override;
2207
+ if (!override) return base;
2208
+ return {
2209
+ ...base,
2210
+ ...override,
2211
+ geographies: uniqueStrings([...base.geographies ?? [], ...override.geographies ?? []]),
2212
+ exclusions: uniqueStrings([...base.exclusions ?? [], ...override.exclusions ?? []]),
2213
+ deliverabilityNotes: uniqueStrings([...base.deliverabilityNotes ?? [], ...override.deliverabilityNotes ?? []]),
2214
+ maxDailySends: override.maxDailySends ?? base.maxDailySends
2215
+ };
2216
+ }
2217
+ function mergeSignalizDefaultOverrides(base, override) {
2218
+ if (!base) return override;
2219
+ if (!override) return base;
2220
+ return {
2221
+ ...base,
2222
+ ...override,
2223
+ signals: { ...base.signals, ...override.signals },
2224
+ qualification: { ...base.qualification, ...override.qualification },
2225
+ copy: { ...base.copy, ...override.copy },
2226
+ delivery: { ...base.delivery, ...override.delivery }
2227
+ };
2228
+ }
2229
+ function mergeAgencyContext(base, override) {
2230
+ if (!base) return override;
2231
+ if (!override) return base;
2232
+ return {
2233
+ ...base,
2234
+ ...override,
2235
+ partnerEcosystem: uniqueStrings([...base.partnerEcosystem ?? [], ...override.partnerEcosystem ?? []]),
2236
+ strategyModel: override.strategyModel ?? base.strategyModel,
2237
+ includeStrategyPatterns: override.includeStrategyPatterns ?? base.includeStrategyPatterns,
2238
+ includeWorkflowPatterns: override.includeWorkflowPatterns ?? base.includeWorkflowPatterns,
2239
+ includeClayPatterns: override.includeClayPatterns ?? base.includeClayPatterns,
2240
+ includeNangoCatalog: override.includeNangoCatalog ?? base.includeNangoCatalog,
2241
+ revenueMotion: override.revenueMotion ?? base.revenueMotion
2242
+ };
2243
+ }
2244
+ function campaignBuilderStrategyModel(agencyContext) {
2245
+ return agencyContext?.strategyModel ?? "strategy_template";
2246
+ }
2247
+ function campaignBuilderStrategyPatternsEnabled(agencyContext) {
2248
+ return agencyContext?.includeStrategyPatterns ?? true;
2249
+ }
2250
+ function campaignBuilderWorkflowPatternsEnabled(agencyContext) {
2251
+ return agencyContext?.includeWorkflowPatterns ?? agencyContext?.includeClayPatterns ?? true;
2252
+ }
2253
+ function campaignBuilderAccountLabel(request) {
2254
+ return request.accountLabel;
2255
+ }
2256
+ function campaignBuilderAccountContext(request) {
2257
+ return request.accountContext;
2258
+ }
1391
2259
  function mergeDefaults(overrides) {
1392
2260
  return {
1393
2261
  ...DEFAULT_SIGNALIZ_CAMPAIGN_BUILDER_DEFAULTS,
@@ -1400,12 +2268,9 @@ function mergeDefaults(overrides) {
1400
2268
  }
1401
2269
  function normalizeMemory(request) {
1402
2270
  const configured = request.memory ?? {};
1403
- const queries = configured.queries && configured.queries.length > 0 ? configured.queries : [{
1404
- query: request.goal,
1405
- scopes: ["workspace", configured.useNetworkPatterns ? "network_patterns" : "operator_notes"],
1406
- topK: 8,
1407
- rationale: "Seed the campaign plan with prior ICP, angle, source, and reply-performance patterns."
1408
- }];
2271
+ const defaultQueries = defaultAgencyMemoryQueries(request, configured);
2272
+ const configuredQueries = configured.queries ?? [];
2273
+ const queries = configuredQueries.length > 0 ? request.strategyTemplate ? dedupeMemoryQueries([...configuredQueries, ...defaultQueries]) : configuredQueries : defaultQueries;
1409
2274
  return {
1410
2275
  enabled: configured.enabled !== false,
1411
2276
  queries,
@@ -1414,40 +2279,130 @@ function normalizeMemory(request) {
1414
2279
  privacyMode: configured.privacyMode ?? (configured.useNetworkPatterns ? "anonymized_patterns" : "workspace_only")
1415
2280
  };
1416
2281
  }
2282
+ function defaultAgencyMemoryQueries(request, configured) {
2283
+ const operatingPlaybookTerms = getCampaignBuilderOperatingPlaybooksForRequest(request).flatMap((playbook) => [playbook.label, ...playbook.memoryKeywords]).join(" ");
2284
+ const queries = [{
2285
+ query: request.goal,
2286
+ scopes: ["workspace", configured.useNetworkPatterns ? "network_patterns" : "operator_notes"],
2287
+ topK: 8,
2288
+ rationale: "Seed the campaign plan with prior ICP, angle, source, and reply-performance patterns."
2289
+ }];
2290
+ if (campaignBuilderStrategyModel(request.agencyContext) !== "custom" && campaignBuilderStrategyPatternsEnabled(request.agencyContext)) {
2291
+ queries.push({
2292
+ query: [
2293
+ "Private campaign strategy pattern library prior campaign casebook",
2294
+ campaignBuilderAccountLabel(request),
2295
+ operatingPlaybookTerms,
2296
+ request.goal
2297
+ ].filter(Boolean).join(" "),
2298
+ scopes: ["workspace", "operator_notes"],
2299
+ topK: 8,
2300
+ required: true,
2301
+ rationale: "Anchor the plan in private strategy learnings from prior industrial, healthcare, agency-services, infrastructure, recruiting, media, and integration builds."
2302
+ });
2303
+ }
2304
+ if (campaignBuilderWorkflowPatternsEnabled(request.agencyContext)) {
2305
+ queries.push({
2306
+ query: [
2307
+ "Workflow table architecture enrichment qualification copy export gates",
2308
+ request.goal
2309
+ ].filter(Boolean).join(" "),
2310
+ scopes: ["workspace", "operator_notes"],
2311
+ topK: 6,
2312
+ rationale: "Pull workflow patterns for source tables, enrichment order, qualification gates, and handoff controls."
2313
+ });
2314
+ }
2315
+ return queries;
2316
+ }
1417
2317
  function normalizeRoutes(request) {
1418
- const routes = [
1419
- {
1420
- id: "signaliz-source",
2318
+ const routes = builtInRoutesFor(request);
2319
+ routes.push(...routesFromCustomerTools(request.customerTools ?? []));
2320
+ routes.push(...request.integrations ?? []);
2321
+ return routes.map((route, index) => ({
2322
+ ...route,
2323
+ id: route.id ?? `${route.provider}-${route.layer}-${index + 1}`,
2324
+ mode: route.mode ?? "if_available"
2325
+ }));
2326
+ }
2327
+ function builtInRoutesFor(request) {
2328
+ const builtIns = new Set(normalizeBuiltIns(request));
2329
+ const routes = [];
2330
+ if (builtIns.has("lead_generation")) {
2331
+ routes.push({
2332
+ id: "signaliz-lead-generation",
1421
2333
  layer: "source",
2334
+ gtmLayers: ["find_company", "find_people", "lead_generation"],
1422
2335
  provider: "signaliz",
1423
2336
  mode: "required",
1424
2337
  toolName: "generate_leads",
1425
2338
  rationale: "Use Signaliz fresh workspace acquisition as the default source of truth."
1426
- },
1427
- {
1428
- id: "signaliz-verify",
1429
- layer: "qualification",
2339
+ });
2340
+ }
2341
+ if (builtIns.has("local_leads")) {
2342
+ routes.push({
2343
+ id: "signaliz-local-leads",
2344
+ layer: "source",
2345
+ gtmLayer: "local_leads",
2346
+ provider: "signaliz",
2347
+ mode: "if_available",
2348
+ toolName: "generate_local_leads",
2349
+ rationale: "Use Signaliz local-leads sourcing for geography-bound local business campaigns."
2350
+ });
2351
+ }
2352
+ if (builtIns.has("email_finding")) {
2353
+ routes.push({
2354
+ id: "signaliz-email-finding",
2355
+ layer: "enrichment",
2356
+ gtmLayer: "email_finding",
1430
2357
  provider: "signaliz",
1431
2358
  mode: "required",
1432
2359
  toolName: "find_and_verify_emails",
2360
+ rationale: "Find contact emails before verification and campaign handoff."
2361
+ });
2362
+ }
2363
+ if (builtIns.has("email_verification")) {
2364
+ routes.push({
2365
+ id: "signaliz-email-verification",
2366
+ layer: "qualification",
2367
+ gtmLayer: "email_verification",
2368
+ provider: "signaliz",
2369
+ mode: "required",
2370
+ toolName: "verify_emails",
1433
2371
  rationale: "Require verified contactability before sequence delivery."
1434
- },
1435
- {
2372
+ });
2373
+ }
2374
+ if (builtIns.has("signals")) {
2375
+ routes.push({
1436
2376
  id: "signaliz-signals",
1437
2377
  layer: "enrichment",
2378
+ gtmLayer: "company_enrichment",
1438
2379
  provider: "signaliz",
1439
2380
  mode: "if_available",
1440
2381
  toolName: "enrich_company_signals",
1441
2382
  rationale: "Attach current buying signals and evidence for qualification and copy."
1442
- }
1443
- ];
1444
- routes.push(...routesFromCustomerTools(request.customerTools ?? []));
1445
- routes.push(...request.integrations ?? []);
1446
- return routes.map((route, index) => ({
1447
- ...route,
1448
- id: route.id ?? `${route.provider}-${route.layer}-${index + 1}`,
1449
- mode: route.mode ?? "if_available"
1450
- }));
2383
+ });
2384
+ }
2385
+ return routes;
2386
+ }
2387
+ function normalizeBuiltIns(request) {
2388
+ const configured = request.builtIns !== void 0 ? request.builtIns : DEFAULT_CAMPAIGN_BUILDER_BUILT_INS;
2389
+ const builtIns = new Set(configured);
2390
+ if (request.builtIns === void 0 && looksLikeLocalLeadCampaign(request)) {
2391
+ builtIns.add("local_leads");
2392
+ }
2393
+ return [...builtIns].filter(isCampaignBuilderBuiltInTool);
2394
+ }
2395
+ function isCampaignBuilderBuiltInTool(value) {
2396
+ return ["lead_generation", "local_leads", "email_finding", "email_verification", "signals"].includes(String(value));
2397
+ }
2398
+ function looksLikeLocalLeadCampaign(request) {
2399
+ const text = [
2400
+ request.goal,
2401
+ campaignBuilderAccountContext(request),
2402
+ ...request.icp?.industries ?? [],
2403
+ ...request.icp?.keywords ?? []
2404
+ ].filter(Boolean).join(" ").toLowerCase();
2405
+ return /\b(local|google maps|near me|nearby|city|cities|location|locations|home services?|clinics?|restaurants?|contractors?)\b/.test(text);
1451
2406
  }
1452
2407
  function routesFromCustomerTools(tools) {
1453
2408
  return tools.flatMap(
@@ -1465,7 +2420,7 @@ function routesFromCustomerTools(tools) {
1465
2420
  ...tool.config,
1466
2421
  available_tools: tool.availableTools
1467
2422
  },
1468
- rationale: `${tool.label ?? tool.provider} is customer-provided for ${layer}.`
2423
+ rationale: `${tool.label ?? tool.provider} is operator-provided for ${layer}.`
1469
2424
  }))
1470
2425
  );
1471
2426
  }
@@ -1510,6 +2465,7 @@ function createBuildRequest(request, defaults, targetCount, campaignName, scopeB
1510
2465
  return buildRequest;
1511
2466
  }
1512
2467
  function createBrainPreflight(request, buildRequest, routes, memory) {
2468
+ const operatingPlaybooks = getCampaignBuilderOperatingPlaybooksForRequest(request);
1513
2469
  const layers = uniqueStrings([
1514
2470
  "icp",
1515
2471
  "email_finding",
@@ -1519,7 +2475,7 @@ function createBrainPreflight(request, buildRequest, routes, memory) {
1519
2475
  ["instantly", "smartlead", "heyreach"].some((provider) => routes.some((route) => route.provider === provider)) ? "sender" : void 0,
1520
2476
  memory.enabled ? "feedback" : void 0
1521
2477
  ]);
1522
- const providerChain = uniqueStrings(["signaliz", ...routes.map((route) => route.provider)]);
2478
+ const providerChain = uniqueStrings(["signaliz", ...request.preferredProviders ?? [], ...routes.map((route) => route.provider)]);
1523
2479
  const targetIcp = compact({
1524
2480
  personas: buildRequest.icp?.personas,
1525
2481
  industries: buildRequest.icp?.industries,
@@ -1560,6 +2516,13 @@ function createBrainPreflight(request, buildRequest, routes, memory) {
1560
2516
  required: true,
1561
2517
  policy: "Run read-only GTM Brain preflight before build_campaign so learned defaults, memory, and deliverability risk stay attached to the build.",
1562
2518
  layers,
2519
+ operating_playbooks: operatingPlaybooks.map((playbook) => ({
2520
+ slug: playbook.slug,
2521
+ label: playbook.label,
2522
+ quality_gates: playbook.qualityGates,
2523
+ required_fields: playbook.requiredFields,
2524
+ activation_boundary: playbook.activationBoundary
2525
+ })),
1563
2526
  target_icp: targetIcp,
1564
2527
  provider_chain: providerChain,
1565
2528
  lead_source: providerChain[0] ?? "signaliz",
@@ -1692,6 +2655,47 @@ function createMcpFlow(request, buildRequest, routes, memory, approvals) {
1692
2655
  approvalRequired: false
1693
2656
  }
1694
2657
  ];
2658
+ steps.push({
2659
+ id: "gtm-provider-catalog",
2660
+ phase: "plan",
2661
+ tool: "gtm_provider_catalog",
2662
+ arguments: {
2663
+ include_layer_catalog: true,
2664
+ include_planned: true
2665
+ },
2666
+ readOnly: true,
2667
+ approvalRequired: false
2668
+ });
2669
+ if (request.agencyContext?.includeNangoCatalog !== false) {
2670
+ steps.push({
2671
+ id: "nango-tool-catalog",
2672
+ phase: "plan",
2673
+ tool: "nango_mcp_tools_list",
2674
+ arguments: {
2675
+ format: "mcp"
2676
+ },
2677
+ readOnly: true,
2678
+ approvalRequired: false
2679
+ });
2680
+ }
2681
+ if (memory.enabled) {
2682
+ steps.push({
2683
+ id: "strategy-memory-status",
2684
+ phase: "memory",
2685
+ tool: "gtm_campaign_strategy_memory_status",
2686
+ arguments: buildGtmCampaignStrategyMemoryStatusArgs(request, buildRequest),
2687
+ readOnly: true,
2688
+ approvalRequired: false
2689
+ });
2690
+ }
2691
+ steps.push({
2692
+ id: "agency-campaign-build-plan",
2693
+ phase: "plan",
2694
+ tool: "gtm_campaign_build_plan",
2695
+ arguments: buildGtmCampaignBuildPlanArgs(request, buildRequest, routes, memory),
2696
+ readOnly: true,
2697
+ approvalRequired: memory.useNetworkPatterns === true
2698
+ });
1695
2699
  if (memory.enabled) {
1696
2700
  for (const [index, query] of memory.queries.entries()) {
1697
2701
  steps.push({
@@ -1705,6 +2709,25 @@ function createMcpFlow(request, buildRequest, routes, memory, approvals) {
1705
2709
  }
1706
2710
  }
1707
2711
  for (const route of routes) {
2712
+ if (shouldPrepareProviderRoute(route)) {
2713
+ steps.push({
2714
+ id: `prepare-${route.id}`,
2715
+ phase: "plan",
2716
+ tool: "gtm_provider_recipe_prepare",
2717
+ arguments: buildProviderRecipePrepareArgs(route, buildRequest),
2718
+ readOnly: true,
2719
+ approvalRequired: false
2720
+ });
2721
+ steps.push({
2722
+ id: `activate-${route.id}-dry-run`,
2723
+ phase: "plan",
2724
+ tool: "gtm_provider_route_activate",
2725
+ arguments: buildProviderRouteActivateArgs(route, buildRequest),
2726
+ readOnly: true,
2727
+ approvalRequired: false
2728
+ });
2729
+ }
2730
+ const routeApprovalRequired = route.approvalRequired === true || route.provider !== "signaliz" && route.approvalRequired !== false && route.mode === "required" || route.layer === "delivery" || route.layer === "feedback";
1708
2731
  steps.push({
1709
2732
  id: `route-${route.id}`,
1710
2733
  phase: route.layer,
@@ -1716,7 +2739,7 @@ function createMcpFlow(request, buildRequest, routes, memory, approvals) {
1716
2739
  config: route.config
1717
2740
  },
1718
2741
  readOnly: !["delivery", "feedback"].includes(route.layer),
1719
- approvalRequired: route.approvalRequired === true || route.layer === "delivery" || route.layer === "feedback"
2742
+ approvalRequired: routeApprovalRequired
1720
2743
  });
1721
2744
  }
1722
2745
  steps.push({
@@ -1725,8 +2748,8 @@ function createMcpFlow(request, buildRequest, routes, memory, approvals) {
1725
2748
  tool: "scope_campaign",
1726
2749
  arguments: {
1727
2750
  prompt: request.goal,
1728
- client_name: request.clientName,
1729
- client_context: request.clientContext,
2751
+ account_label: campaignBuilderAccountLabel(request),
2752
+ account_context: campaignBuilderAccountContext(request),
1730
2753
  target_count: request.targetCount
1731
2754
  },
1732
2755
  readOnly: true,
@@ -1788,9 +2811,199 @@ function createMcpFlow(request, buildRequest, routes, memory, approvals) {
1788
2811
  });
1789
2812
  return steps.map((step) => ({ ...step, arguments: compact(step.arguments) }));
1790
2813
  }
2814
+ function shouldPrepareProviderRoute(route) {
2815
+ return !["signaliz", "csv"].includes(route.provider);
2816
+ }
2817
+ function buildProviderRecipePrepareArgs(route, buildRequest) {
2818
+ const layerCapabilities = uniqueStrings(gtmLayersForRoute(route));
2819
+ const layer = layerCapabilities[0] ?? mapCampaignBuilderLayerToGtmLayer(route.layer) ?? "custom";
2820
+ const config = asRecord(route.config);
2821
+ return compact({
2822
+ provider_id: route.provider,
2823
+ provider_name: route.label,
2824
+ layer,
2825
+ layer_capabilities: layerCapabilities.length > 0 ? layerCapabilities : void 0,
2826
+ invocation_type: route.providerCapability?.invocationType ?? inferProviderInvocationType(route),
2827
+ auth_strategy: inferProviderAuthStrategy(route),
2828
+ workspace_mcp_server_id: stringValue(config.workspace_mcp_server_id ?? config.workspaceMcpServerId ?? route.mcpServerName),
2829
+ workspace_integration_id: stringValue(config.workspace_integration_id ?? config.workspaceIntegrationId),
2830
+ workspace_connection_id: stringValue(config.workspace_connection_id ?? config.workspaceConnectionId),
2831
+ endpoint_url: stringValue(config.endpoint_url ?? config.endpointUrl ?? config.webhook_url ?? config.webhookUrl),
2832
+ request_template: asOptionalRecord(config.request_template ?? config.requestTemplate),
2833
+ response_mapping: asOptionalRecord(config.response_mapping ?? config.responseMapping),
2834
+ input_schema: asOptionalRecord(config.input_schema ?? config.inputSchema ?? route.providerCapability?.exampleInputSchema),
2835
+ output_schema: asOptionalRecord(config.output_schema ?? config.outputSchema ?? route.providerCapability?.exampleOutputSchema),
2836
+ readiness: asOptionalRecord(config.readiness),
2837
+ metadata: compact({
2838
+ source: "campaign-builder-agent",
2839
+ route_id: route.id,
2840
+ campaign_name: buildRequest.name,
2841
+ tool_name: route.toolName,
2842
+ mcp_server_name: route.mcpServerName,
2843
+ dry_run_only: true
2844
+ }),
2845
+ context: compact({
2846
+ source: "campaign-builder-agent",
2847
+ route_id: route.id,
2848
+ gtm_campaign_id: buildRequest.gtmCampaignId
2849
+ }),
2850
+ use_signaliz_fallback: route.routingPolicy?.useSignalizFallback ?? true,
2851
+ priority: numberOrUndefined2(config.priority),
2852
+ status: stringValue(config.status) ?? "needs_setup"
2853
+ });
2854
+ }
2855
+ function buildProviderRouteActivateArgs(route, buildRequest) {
2856
+ const layerCapabilities = uniqueStrings(gtmLayersForRoute(route));
2857
+ const config = asRecord(route.config);
2858
+ return compact({
2859
+ provider_id: route.provider,
2860
+ provider_name: route.label,
2861
+ campaign_id: buildRequest.gtmCampaignId,
2862
+ layer: layerCapabilities[0] ?? mapCampaignBuilderLayerToGtmLayer(route.layer) ?? "custom",
2863
+ layers: layerCapabilities.length > 0 ? layerCapabilities : void 0,
2864
+ invocation_type: route.providerCapability?.invocationType ?? inferProviderInvocationType(route),
2865
+ auth_strategy: inferProviderAuthStrategy(route),
2866
+ workspace_mcp_server_id: stringValue(config.workspace_mcp_server_id ?? config.workspaceMcpServerId ?? route.mcpServerName),
2867
+ workspace_integration_id: stringValue(config.workspace_integration_id ?? config.workspaceIntegrationId),
2868
+ workspace_connection_id: stringValue(config.workspace_connection_id ?? config.workspaceConnectionId),
2869
+ endpoint_url: stringValue(config.endpoint_url ?? config.endpointUrl ?? config.webhook_url ?? config.webhookUrl),
2870
+ route_config: compact({
2871
+ ...asRecord(config.route_config ?? config.routeConfig),
2872
+ source: "campaign-builder-agent",
2873
+ route_id: route.id,
2874
+ tool_name: route.toolName,
2875
+ mcp_server_name: route.mcpServerName
2876
+ }),
2877
+ use_signaliz_fallback: route.routingPolicy?.useSignalizFallback ?? true,
2878
+ priority: numberOrUndefined2(config.priority),
2879
+ dry_run: true,
2880
+ confirm: false
2881
+ });
2882
+ }
2883
+ function inferProviderInvocationType(route) {
2884
+ if (route.provider === "airbyte") return "airbyte";
2885
+ if (route.provider === "nango") return "managed_integration";
2886
+ if (["custom_webhook", "webhook", "clay_webhook"].includes(route.provider)) return "webhook";
2887
+ if (["custom_api", "apollo", "ai_ark", "apify"].includes(route.provider)) return "api";
2888
+ if (route.mcpServerName || route.toolName || ["custom_mcp", "octave"].includes(route.provider)) return "mcp_tool";
2889
+ return "manual";
2890
+ }
2891
+ function inferProviderAuthStrategy(route) {
2892
+ const config = asRecord(route.config);
2893
+ const configured = stringValue(config.auth_strategy ?? config.authStrategy);
2894
+ if (configured) return configured;
2895
+ const invocationType = route.providerCapability?.invocationType ?? inferProviderInvocationType(route);
2896
+ if (invocationType === "webhook") return "webhook_secret";
2897
+ if (invocationType === "mcp_tool") return "mcp_auth";
2898
+ if (invocationType === "managed_integration") return "byo_runtime";
2899
+ if (invocationType === "api" || invocationType === "airbyte") return "integration_key";
2900
+ return void 0;
2901
+ }
2902
+ function refreshBuildStepArguments(plan) {
2903
+ for (const step of plan.mcpFlow) {
2904
+ if (step.id === "dry-run-build") {
2905
+ step.arguments = compact({
2906
+ ...buildCampaignArgs({ ...plan.buildRequest, dryRun: true, confirmSpend: false }),
2907
+ dry_run: true
2908
+ });
2909
+ }
2910
+ if (step.id === "approved-build") {
2911
+ step.arguments = compact({
2912
+ ...buildCampaignArgs({ ...plan.buildRequest, dryRun: false, confirmSpend: true }),
2913
+ required_approvals: plan.approvals.map((approval) => approval.id)
2914
+ });
2915
+ }
2916
+ }
2917
+ }
2918
+ function buildFallbackPlanSnapshot(plan) {
2919
+ const plannerStep = plan.mcpFlow.find((step) => step.id === "agency-campaign-build-plan");
2920
+ return compact({
2921
+ source_tool: "campaign-builder-agent",
2922
+ plan_id: plan.planId,
2923
+ query: asRecord(plannerStep?.arguments),
2924
+ campaign_name: plan.campaignName,
2925
+ goal: plan.goal,
2926
+ target_count: plan.targetCount,
2927
+ approvals: plan.approvals,
2928
+ brain_preflight: plan.brainPreflight,
2929
+ operating_playbooks: plan.operatingPlaybooks
2930
+ });
2931
+ }
2932
+ function mapPlanCommitResult(data) {
2933
+ const campaign = asRecord(data.campaign);
2934
+ const campaignBuild = asRecord(data.campaign_build ?? data.campaignBuild);
2935
+ const committedPlan = asRecord(data.committed_plan ?? data.committedPlan);
2936
+ const commitPlan = asRecord(data.commit_plan ?? data.commitPlan);
2937
+ const campaignArgs = asRecord(commitPlan.campaign_arguments ?? commitPlan.campaignArguments);
2938
+ return {
2939
+ dryRun: data.dry_run === true || data.dryRun === true,
2940
+ wroteState: data.wrote_state === true || data.wroteState === true,
2941
+ campaignId: stringValue(campaign.id ?? committedPlan.campaign_id ?? committedPlan.campaignId ?? commitPlan.campaign_id ?? commitPlan.campaignId ?? campaignArgs.id),
2942
+ campaignBuildId: stringValue(campaignBuild.id ?? committedPlan.campaign_build_id ?? committedPlan.campaignBuildId ?? campaignArgs.campaign_build_id ?? campaignArgs.campaignBuildId),
2943
+ raw: data
2944
+ };
2945
+ }
2946
+ function buildGtmCampaignBuildPlanArgs(request, buildRequest, routes, memory) {
2947
+ const agencyContext = request.agencyContext ?? {};
2948
+ const strategyModel = campaignBuilderStrategyModel(agencyContext);
2949
+ const partnerEcosystem = agencyContext.partnerEcosystem ?? (strategyModel === "custom" ? void 0 : ["clay", "instantly", "nango"]);
2950
+ const layers = uniqueStrings([
2951
+ "icp",
2952
+ buildRequest.icp?.requireVerifiedEmail !== false ? "email_finding" : void 0,
2953
+ buildRequest.icp?.requireVerifiedEmail !== false ? "email_verification" : void 0,
2954
+ ...routes.flatMap(gtmLayersForRoute),
2955
+ buildRequest.delivery?.destinationType === "webhook" ? "destination_export" : void 0,
2956
+ memory.enabled ? "feedback" : void 0
2957
+ ]);
2958
+ const preferredProviders = uniqueStrings([
2959
+ ...request.preferredProviders ?? [],
2960
+ ...routes.map((route) => route.provider).filter((provider) => provider !== "signaliz")
2961
+ ]);
2962
+ const operatingPlaybooks = getCampaignBuilderOperatingPlaybooksForRequest(request);
2963
+ return compact({
2964
+ campaign_id: buildRequest.gtmCampaignId,
2965
+ campaign_brief: buildRequest.prompt || request.goal,
2966
+ strategy_template: request.strategyTemplate,
2967
+ target_icp: buildRequest.icp ? buildGtmTargetIcpContext(buildRequest.icp) : void 0,
2968
+ lead_count: buildRequest.targetCount,
2969
+ layers: layers.length > 0 ? layers : void 0,
2970
+ preferred_providers: preferredProviders.length > 0 ? preferredProviders : void 0,
2971
+ strategy_model: strategyModel,
2972
+ include_strategy_patterns: campaignBuilderStrategyPatternsEnabled(agencyContext),
2973
+ include_workflow_patterns: campaignBuilderWorkflowPatternsEnabled(agencyContext),
2974
+ include_nango_catalog: agencyContext.includeNangoCatalog !== false,
2975
+ partner_ecosystem: partnerEcosystem,
2976
+ operating_playbooks: operatingPlaybooks.map((playbook) => ({
2977
+ slug: playbook.slug,
2978
+ label: playbook.label,
2979
+ quality_gates: playbook.qualityGates,
2980
+ activation_boundary: playbook.activationBoundary
2981
+ })),
2982
+ include_memory: memory.enabled,
2983
+ include_brain: true,
2984
+ include_provider_routes: true,
2985
+ include_failure_patterns: true,
2986
+ include_planned_providers: true,
2987
+ limit: 25
2988
+ });
2989
+ }
2990
+ function buildGtmCampaignStrategyMemoryStatusArgs(request, buildRequest) {
2991
+ return compact({
2992
+ query: request.goal,
2993
+ campaign_brief: buildRequest.prompt || request.goal,
2994
+ strategy_template: request.strategyTemplate,
2995
+ target_icp: buildRequest.icp ? buildGtmTargetIcpContext(buildRequest.icp) : void 0,
2996
+ memory_dimension_filters: request.strategyTemplate ? { strategy_template: request.strategyTemplate } : void 0,
2997
+ require_memory_dimension_match: false,
2998
+ include_samples: false,
2999
+ include_sources: true,
3000
+ days: 3650,
3001
+ limit: 25
3002
+ });
3003
+ }
1791
3004
  function buildGtmMemorySearchArgs(request, routes, query) {
1792
3005
  const layers = uniqueStrings(routes.flatMap(gtmLayersForRoute));
1793
- const providerChain = uniqueStrings(routes.map((route) => route.provider));
3006
+ const providerChain = uniqueStrings([...request.preferredProviders ?? [], ...routes.map((route) => route.provider)]);
1794
3007
  return compact({
1795
3008
  query: query.query,
1796
3009
  limit: query.topK,
@@ -1812,6 +3025,26 @@ function buildGtmTargetIcpContext(icp) {
1812
3025
  require_verified_email: icp.requireVerifiedEmail
1813
3026
  });
1814
3027
  }
3028
+ function mapCampaignBuilderLayerToGtmLayer(layer) {
3029
+ switch (layer) {
3030
+ case "source":
3031
+ return "lead_generation";
3032
+ case "enrichment":
3033
+ return "company_enrichment";
3034
+ case "qualification":
3035
+ return "qualification";
3036
+ case "copy":
3037
+ return "copy_enrichment";
3038
+ case "delivery":
3039
+ return "destination_export";
3040
+ case "feedback":
3041
+ return "feedback";
3042
+ case "approval":
3043
+ return "approval";
3044
+ default:
3045
+ return void 0;
3046
+ }
3047
+ }
1815
3048
  function buildCampaignArgs(request) {
1816
3049
  const args = {
1817
3050
  name: request.name,
@@ -1992,8 +3225,8 @@ function estimateCredits(request, defaults, targetCount) {
1992
3225
  }
1993
3226
  function buildDescription(request) {
1994
3227
  const parts = [
1995
- request.clientName ? `Client: ${request.clientName}` : void 0,
1996
- request.clientContext ? `Context: ${request.clientContext}` : void 0,
3228
+ campaignBuilderAccountLabel(request) ? `Account label: ${campaignBuilderAccountLabel(request)}` : void 0,
3229
+ campaignBuilderAccountContext(request) ? `Context: ${campaignBuilderAccountContext(request)}` : void 0,
1997
3230
  request.constraints?.deliverabilityNotes?.length ? `Deliverability: ${request.constraints.deliverabilityNotes.join("; ")}` : void 0,
1998
3231
  "Agent-built campaign plan layered on Signaliz kernel and existing MCP tools."
1999
3232
  ];
@@ -2016,6 +3249,10 @@ function compact(record) {
2016
3249
  function asRecord(value) {
2017
3250
  return value && typeof value === "object" && !Array.isArray(value) ? value : {};
2018
3251
  }
3252
+ function asOptionalRecord(value) {
3253
+ const record = asRecord(value);
3254
+ return Object.keys(record).length > 0 ? record : void 0;
3255
+ }
2019
3256
  function stringValue(value) {
2020
3257
  return typeof value === "string" && value.length > 0 ? value : void 0;
2021
3258
  }
@@ -3760,7 +4997,7 @@ var GtmKernel = class {
3760
4997
  campaigns: input.campaigns.map(campaignHistoryImportCampaignArgs)
3761
4998
  });
3762
4999
  }
3763
- /** Queue a Trigger-backed campaign history import for larger CMM/client backfills. */
5000
+ /** Queue a Trigger-backed campaign history import for larger private campaign backfills. */
3764
5001
  async importCampaignHistoryRun(input) {
3765
5002
  return this.callMcp("gtm_campaign_history_import_run", {
3766
5003
  source: input.source,
@@ -3891,6 +5128,25 @@ var GtmKernel = class {
3891
5128
  write_routine_outcomes: input.writeRoutineOutcomes
3892
5129
  });
3893
5130
  }
5131
+ /** Run a read-only Campaign Audit and persist workspace-scoped failure findings. */
5132
+ async runCampaignAudit(input) {
5133
+ return this.callMcp("gtm_campaign_audit_run", {
5134
+ provider: input.provider,
5135
+ provider_campaign_id: input.providerCampaignId,
5136
+ campaign_id: input.campaignId,
5137
+ campaign_name: input.campaignName,
5138
+ lookback_days: input.lookbackDays,
5139
+ limit_findings: input.limitFindings
5140
+ });
5141
+ }
5142
+ /** Read a persisted Campaign Audit by audit id or campaign id. */
5143
+ async getCampaignAudit(options) {
5144
+ return this.callMcp("gtm_campaign_audit_get", {
5145
+ audit_id: options.auditId,
5146
+ campaign_id: options.campaignId,
5147
+ limit_findings: options.limitFindings
5148
+ });
5149
+ }
3894
5150
  /** Normalize Instantly webhook/pull payloads and ingest row-level feedback through the GTM Kernel. */
3895
5151
  async syncInstantlyFeedback(input) {
3896
5152
  return this.callMcp("gtm_instantly_feedback_sync", {
@@ -4188,6 +5444,40 @@ var GtmKernel = class {
4188
5444
  include_layer_catalog: options.includeLayerCatalog
4189
5445
  });
4190
5446
  }
5447
+ /** List private-safe campaign strategy templates agents can merge into campaign build plans. */
5448
+ async campaignStrategyTemplates(options = {}) {
5449
+ return this.callMcp("gtm_campaign_strategy_templates", {
5450
+ strategy_template: options.strategyTemplate,
5451
+ query: options.query,
5452
+ include_details: options.includeDetails
5453
+ });
5454
+ }
5455
+ /** Build the read-only Memory, Brain, risk, and provider-route runbook needed before planning a campaign. */
5456
+ async campaignStartContext(input = {}) {
5457
+ return this.callMcp("gtm_campaign_start_context", {
5458
+ campaign_id: input.campaignId,
5459
+ campaign_build_id: input.campaignBuildId,
5460
+ campaign_brief: input.campaignBrief,
5461
+ strategy_template: input.strategyTemplate,
5462
+ target_icp: input.targetIcp,
5463
+ lead_count: input.leadCount,
5464
+ layers: input.layers,
5465
+ preferred_providers: input.preferredProviders,
5466
+ memory_dimension_filters: input.memoryDimensionFilters,
5467
+ require_memory_dimension_match: input.requireMemoryDimensionMatch,
5468
+ include_memory: input.includeMemory,
5469
+ include_brain: input.includeBrain,
5470
+ include_provider_routes: input.includeProviderRoutes,
5471
+ include_failure_patterns: input.includeFailurePatterns,
5472
+ include_delivery_risk: input.includeDeliveryRisk,
5473
+ include_global_brain: input.includeGlobalBrain,
5474
+ include_planned_providers: input.includePlannedProviders,
5475
+ days: input.days,
5476
+ min_confidence: input.minConfidence,
5477
+ min_sample_size: input.minSampleSize,
5478
+ limit: input.limit
5479
+ });
5480
+ }
4191
5481
  /** Inspect GTM integration activation cards for UI and agent routing without writing state. */
4192
5482
  async integrationsActivationStatus(options = {}) {
4193
5483
  return this.callMcp("gtm_integrations_activation_status", {
@@ -4203,10 +5493,16 @@ var GtmKernel = class {
4203
5493
  campaign_id: input.campaignId,
4204
5494
  campaign_build_id: input.campaignBuildId,
4205
5495
  campaign_brief: input.campaignBrief,
5496
+ strategy_template: input.strategyTemplate,
4206
5497
  target_icp: input.targetIcp,
4207
5498
  lead_count: input.leadCount,
4208
5499
  layers: input.layers,
4209
5500
  preferred_providers: input.preferredProviders,
5501
+ strategy_model: input.strategyModel,
5502
+ include_strategy_patterns: input.includeStrategyPatterns,
5503
+ include_workflow_patterns: input.includeWorkflowPatterns ?? input.includeClayPatterns,
5504
+ include_nango_catalog: input.includeNangoCatalog,
5505
+ partner_ecosystem: input.partnerEcosystem,
4210
5506
  memory_dimension_filters: input.memoryDimensionFilters,
4211
5507
  require_memory_dimension_match: input.requireMemoryDimensionMatch,
4212
5508
  include_memory: input.includeMemory,
@@ -4218,6 +5514,79 @@ var GtmKernel = class {
4218
5514
  limit: input.limit
4219
5515
  });
4220
5516
  }
5517
+ /** Emit reusable CampaignBuilderAgentRequest JSON from hosted MCP strategy-template defaults without spending credits. */
5518
+ async campaignAgentRequestTemplate(input = {}) {
5519
+ return this.callMcp("gtm_campaign_agent_request_template", {
5520
+ goal: input.goal,
5521
+ campaign_brief: input.campaignBrief,
5522
+ campaign_name: input.campaignName,
5523
+ account_label: input.accountLabel,
5524
+ account_context: input.accountContext,
5525
+ strategy_template: input.strategyTemplate,
5526
+ operating_playbooks: input.operatingPlaybooks,
5527
+ target_icp: input.targetIcp,
5528
+ target_count: input.targetCount,
5529
+ builtins: input.builtIns,
5530
+ include_local_leads: input.includeLocalLeads,
5531
+ include_byo_placeholder: input.includeByoPlaceholder,
5532
+ include_nango_catalog: input.includeNangoCatalog,
5533
+ preferred_providers: input.preferredProviders,
5534
+ privacy_mode: input.privacyMode,
5535
+ destination_type: input.destinationType
5536
+ });
5537
+ }
5538
+ /** Compose a one-call read-only strategy-template campaign-agent runbook across built-ins, Memory, Brain, Nango, and BYO routes. */
5539
+ async campaignAgentPlan(input = {}) {
5540
+ return this.callMcp("gtm_campaign_agent_plan", {
5541
+ goal: input.goal,
5542
+ campaign_brief: input.campaignBrief,
5543
+ campaign_name: input.campaignName,
5544
+ campaign_id: input.campaignId,
5545
+ campaign_build_id: input.campaignBuildId,
5546
+ strategy_template: input.strategyTemplate,
5547
+ operating_playbooks: input.operatingPlaybooks,
5548
+ account_context: input.accountContext,
5549
+ target_icp: input.targetIcp,
5550
+ target_count: input.targetCount,
5551
+ lead_count: input.leadCount,
5552
+ builtins: input.builtIns,
5553
+ use_local_leads: input.useLocalLeads,
5554
+ layers: input.layers,
5555
+ preferred_providers: input.preferredProviders,
5556
+ custom_tools: input.customTools,
5557
+ integrations: input.integrations,
5558
+ strategy_model: input.strategyModel,
5559
+ include_strategy_patterns: input.includeStrategyPatterns,
5560
+ include_workflow_patterns: input.includeWorkflowPatterns,
5561
+ include_nango_catalog: input.includeNangoCatalog,
5562
+ partner_ecosystem: input.partnerEcosystem,
5563
+ memory_dimension_filters: input.memoryDimensionFilters,
5564
+ require_memory_dimension_match: input.requireMemoryDimensionMatch,
5565
+ include_memory: input.includeMemory,
5566
+ include_brain: input.includeBrain,
5567
+ include_provider_routes: input.includeProviderRoutes,
5568
+ include_failure_patterns: input.includeFailurePatterns,
5569
+ include_delivery_risk: input.includeDeliveryRisk,
5570
+ include_planned_providers: input.includePlannedProviders,
5571
+ days: input.days,
5572
+ limit: input.limit
5573
+ });
5574
+ }
5575
+ /** Inspect private-safe strategy-template/workflow memory readiness before campaign planning. */
5576
+ async campaignStrategyMemoryStatus(input = {}) {
5577
+ return this.callMcp("gtm_campaign_strategy_memory_status", {
5578
+ strategy_template: input.strategyTemplate,
5579
+ query: input.query,
5580
+ campaign_brief: input.campaignBrief,
5581
+ target_icp: input.targetIcp,
5582
+ memory_dimension_filters: input.memoryDimensionFilters,
5583
+ require_memory_dimension_match: input.requireMemoryDimensionMatch,
5584
+ include_samples: input.includeSamples,
5585
+ include_sources: input.includeSources,
5586
+ days: input.days,
5587
+ limit: input.limit
5588
+ });
5589
+ }
4221
5590
  /** Persist a reviewed campaign build plan into a campaign object and audit log. Dry-run first by default. */
4222
5591
  async commitCampaignBuildPlan(input = {}) {
4223
5592
  return this.callMcp("gtm_campaign_build_plan_commit", {
@@ -4364,6 +5733,13 @@ var GtmKernel = class {
4364
5733
  vendor_id: input.vendorId,
4365
5734
  service_category: input.serviceCategory,
4366
5735
  connection_type: input.connectionType,
5736
+ integration_id: input.integrationId,
5737
+ provider_config_key: input.providerConfigKey,
5738
+ allowed_integrations: input.allowedIntegrations,
5739
+ surface: input.surface,
5740
+ source: input.source,
5741
+ user_email: input.userEmail,
5742
+ user_display_name: input.userDisplayName,
4367
5743
  status: input.status,
4368
5744
  metadata: input.metadata
4369
5745
  });
@@ -4420,6 +5796,20 @@ var GtmKernel = class {
4420
5796
  context: input.context
4421
5797
  });
4422
5798
  }
5799
+ /** Create a short-lived Nango Connect session so a user can authorize a vendor API. */
5800
+ async createNangoConnectSession(input) {
5801
+ return this.callMcp("nango_connect_session_create", {
5802
+ provider_id: input.providerId,
5803
+ integration_id: input.integrationId,
5804
+ provider_display_name: input.providerDisplayName,
5805
+ integration_display_name: input.integrationDisplayName,
5806
+ allowed_integrations: input.allowedIntegrations,
5807
+ surface: input.surface,
5808
+ source: input.source,
5809
+ user_email: input.userEmail,
5810
+ user_display_name: input.userDisplayName
5811
+ });
5812
+ }
4423
5813
  /** List Nango-backed action tools for a workspace connection without executing them. */
4424
5814
  async listNangoTools(options = {}) {
4425
5815
  return this.callMcp("nango_mcp_tools_list", {
@@ -4763,17 +6153,27 @@ var Signaliz = class {
4763
6153
  // Annotate the CommonJS export names for ESM import in node:
4764
6154
  0 && (module.exports = {
4765
6155
  Ai,
6156
+ CAMPAIGN_BUILDER_OPERATING_PLAYBOOKS,
6157
+ CAMPAIGN_BUILDER_STRATEGY_TEMPLATES,
4766
6158
  CampaignBuilderAgent,
4767
6159
  Campaigns,
6160
+ DEFAULT_CAMPAIGN_BUILDER_APPROVAL_TYPES,
6161
+ DEFAULT_CAMPAIGN_BUILDER_BUILT_INS,
4768
6162
  DEFAULT_SIGNALIZ_CAMPAIGN_BUILDER_DEFAULTS,
4769
6163
  GtmKernel,
4770
6164
  Icps,
4771
6165
  Ops,
4772
6166
  Signaliz,
4773
6167
  SignalizError,
6168
+ applyCampaignBuilderStrategyTemplate,
4774
6169
  collectExecutionReferences,
4775
6170
  createCampaignBuilderAgentPlan,
6171
+ createCampaignBuilderAgentRequestTemplate,
4776
6172
  createCampaignBuilderApproval,
6173
+ createCampaignBuilderToolRoute,
6174
+ getCampaignBuilderOperatingPlaybook,
6175
+ getCampaignBuilderOperatingPlaybooksForRequest,
6176
+ getCampaignBuilderStrategyTemplate,
4777
6177
  getMissingCampaignBuilderApprovals,
4778
6178
  normalizeExecutionReference
4779
6179
  });