@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.
@@ -751,7 +751,7 @@ var Campaigns = class {
751
751
  async build(request, options) {
752
752
  return this.buildCampaign(request, options);
753
753
  }
754
- /** Scope an agency/client campaign into a markdown brief plus build_campaign dry-run args. */
754
+ /** Scope an agency/customer campaign into a markdown brief plus build_campaign dry-run args. */
755
755
  async scope(request) {
756
756
  return this.scopeCampaign(request);
757
757
  }
@@ -933,7 +933,11 @@ function mapStatus(data) {
933
933
  errors: diagnosticMessages(data.errors),
934
934
  artifactCount: data.artifact_count ?? 0,
935
935
  providerRoute: mapProviderRoute(data),
936
- nextAction: data.next_action ?? "",
936
+ triggerRunId: typeof data.trigger_run_id === "string" ? data.trigger_run_id : null,
937
+ staleRunningPhase: data.stale_running_phase === true,
938
+ phaseAgeSeconds: numberOrNull(data.phase_age_seconds),
939
+ diagnostics: recordOrNull(data.diagnostics) ?? {},
940
+ nextAction: formatNextAction(data.next_action),
937
941
  createdAt: data.created_at,
938
942
  updatedAt: data.updated_at,
939
943
  completedAt: data.completed_at
@@ -973,6 +977,19 @@ function diagnosticMessages(value) {
973
977
  return typeof record?.message === "string" ? record.message : null;
974
978
  }).filter((item) => typeof item === "string" && item.length > 0);
975
979
  }
980
+ function formatNextAction(value) {
981
+ if (!value) return "";
982
+ if (typeof value === "string") return value;
983
+ const record = recordOrNull(value);
984
+ if (!record) return "";
985
+ const tool = typeof record.tool === "string" ? record.tool : void 0;
986
+ const type = typeof record.type === "string" ? record.type : void 0;
987
+ const reason = typeof record.reason === "string" ? record.reason : void 0;
988
+ const args = recordOrNull(record.arguments);
989
+ const argText = args && Object.keys(args).length > 0 ? ` ${JSON.stringify(args)}` : "";
990
+ const action = tool ? `${tool}${argText}` : type || "";
991
+ return [action, reason].filter(Boolean).join(" \u2014 ");
992
+ }
976
993
  function booleanOrNull(value) {
977
994
  return typeof value === "boolean" ? value : null;
978
995
  }
@@ -1013,7 +1030,7 @@ function mapArtifact(a) {
1013
1030
  function mapScope(data) {
1014
1031
  return {
1015
1032
  campaignScopeId: data.campaign_scope_id,
1016
- clientName: data.client_name,
1033
+ accountLabel: data.account_label,
1017
1034
  campaignName: data.campaign_name,
1018
1035
  approach: data.approach,
1019
1036
  approachLabel: data.approach_label,
@@ -1039,8 +1056,8 @@ function scopeArgs(request) {
1039
1056
  const args = {
1040
1057
  prompt: request.prompt
1041
1058
  };
1042
- if (request.clientName) args.client_name = request.clientName;
1043
- if (request.clientContext) args.client_context = request.clientContext;
1059
+ if (request.accountLabel) args.account_label = request.accountLabel;
1060
+ if (request.accountContext) args.account_context = request.accountContext;
1044
1061
  if (request.campaignGoal) args.campaign_goal = request.campaignGoal;
1045
1062
  if (request.targetCount) args.target_count = request.targetCount;
1046
1063
  if (request.destinations) args.destinations = request.destinations;
@@ -1168,22 +1185,565 @@ var DEFAULT_SIGNALIZ_CAMPAIGN_BUILDER_DEFAULTS = {
1168
1185
  approvalRequired: true
1169
1186
  }
1170
1187
  };
1188
+ var DEFAULT_CAMPAIGN_BUILDER_BUILT_INS = [
1189
+ "lead_generation",
1190
+ "email_finding",
1191
+ "email_verification",
1192
+ "signals"
1193
+ ];
1194
+ var DEFAULT_CAMPAIGN_BUILDER_APPROVAL_TYPES = [
1195
+ "memory_retrieval",
1196
+ "spend",
1197
+ "customer_tool",
1198
+ "external_write",
1199
+ "delivery",
1200
+ "launch"
1201
+ ];
1202
+ var CAMPAIGN_BUILDER_OPERATING_PLAYBOOKS = [
1203
+ {
1204
+ slug: "cache-first-large-list",
1205
+ label: "Cache-First Large List",
1206
+ whenToUse: [
1207
+ "The target count is high and reusable workspace lead or cache coverage may exist.",
1208
+ "The deliverable is a verified list or top-up rather than a deeply custom one-off workflow."
1209
+ ],
1210
+ sequence: [
1211
+ "Inventory reusable cache before paid sourcing.",
1212
+ "Report unique emails, role buckets, exclusions, and missing-field counts.",
1213
+ "Use fresh sourcing only for the approved gap.",
1214
+ "Write newly approved source metadata back to memory or cache after review."
1215
+ ],
1216
+ requiredFields: {
1217
+ inventory: ["matching_cached_rows", "unique_cached_emails", "persona_bucket_counts", "exclusions_applied", "missing_field_counts"],
1218
+ finalRows: ["first_name", "last_name", "company_name", "company_domain", "work_email", "email_status", "source_type"]
1219
+ },
1220
+ qualityGates: [
1221
+ "Deduplicate by normalized email before counting final rows.",
1222
+ "Separate cache reuse from fresh sourcing in the build receipt.",
1223
+ "Block export when required identity, company, or email fields are missing."
1224
+ ],
1225
+ activationBoundary: "Cache inventory is read-only. Fresh sourcing, cache writes, export, and sender loading require explicit approval.",
1226
+ memoryKeywords: ["cache inventory", "large list", "unique emails", "top-up sourcing", "source metadata"]
1227
+ },
1228
+ {
1229
+ slug: "net-new-suppressed-list",
1230
+ label: "Net-New Suppressed List",
1231
+ whenToUse: [
1232
+ "A prior campaign, seed list, or exclusion list must be suppressed.",
1233
+ "The operator needs both outreach-facing rows and provenance-rich QA evidence."
1234
+ ],
1235
+ sequence: [
1236
+ "Load suppression baselines before source selection.",
1237
+ "Apply email suppression as a hard gate and domain suppression as required by the brief.",
1238
+ "Keep provenance, source, and validation fields outside the outreach-facing export when needed.",
1239
+ "Run final overlap checks before any delivery action."
1240
+ ],
1241
+ requiredFields: {
1242
+ suppression: ["suppression_source", "prior_email_overlap", "prior_domain_match", "suppression_decision"],
1243
+ finalRows: ["first_name", "last_name", "company_name", "company_domain", "work_email", "email_status", "provenance_id"]
1244
+ },
1245
+ qualityGates: [
1246
+ "Prior email overlap must be zero for rows marked export ready.",
1247
+ "Prior-domain matches must be flagged or blocked according to the approved campaign promise.",
1248
+ "Do not describe rows as fully qualified when the approved path only proves net-new email status."
1249
+ ],
1250
+ activationBoundary: "Suppression review must pass before export, upload, CRM sync, sender load, or sequence launch.",
1251
+ memoryKeywords: ["suppression", "net-new", "prior email overlap", "domain review", "provenance-rich QA"]
1252
+ },
1253
+ {
1254
+ slug: "proof-first-vertical-gate",
1255
+ label: "Proof-First Vertical Gate",
1256
+ whenToUse: [
1257
+ "Wrong-account risk is high or the target category has close lookalike exclusions.",
1258
+ "Account proof is more important than raw lead volume."
1259
+ ],
1260
+ sequence: [
1261
+ "Define positive and negative proof fields before sourcing at scale.",
1262
+ "Qualify companies before contact discovery.",
1263
+ "Qualify contacts before email finding.",
1264
+ "Keep pass, review, and fail rows distinct through delivery review."
1265
+ ],
1266
+ requiredFields: {
1267
+ account: ["company_name", "company_domain", "source_url", "positive_proof", "negative_proof", "fit_score", "account_qualified"],
1268
+ contact: ["person_name", "person_title", "persona_match", "contact_fit_score", "contact_qualified"]
1269
+ },
1270
+ qualityGates: [
1271
+ "Do not spend on contact or email enrichment until the account passes the proof gate.",
1272
+ "Adjacent excluded categories must stay exclusions, not synonyms.",
1273
+ "Contact fit should meet the configured threshold before email finding or copy generation."
1274
+ ],
1275
+ activationBoundary: "Proof gates are required before contact spend, copy, export, or external writes.",
1276
+ memoryKeywords: ["proof gate", "vertical exclusion", "company before contact", "pass review fail", "fit threshold"]
1277
+ },
1278
+ {
1279
+ slug: "signal-led-copy-approval",
1280
+ label: "Signal-Led Copy With Approval",
1281
+ whenToUse: [
1282
+ "Outbound copy should be grounded in company signals, proof fields, or row context.",
1283
+ "Delivery destinations must remain locked after copy generation until review."
1284
+ ],
1285
+ sequence: [
1286
+ "Validate list quality before copy.",
1287
+ "Attach the strongest supported signal and source evidence.",
1288
+ "Generate copy only for fit-qualified and contactable rows.",
1289
+ "Hold every destination behind explicit approval."
1290
+ ],
1291
+ requiredFields: {
1292
+ evidence: ["strongest_signal", "signal_source_url", "why_now", "personalization_basis"],
1293
+ copy: ["subject_line", "opening_line", "email_copy", "copy_ready", "copy_blocker"]
1294
+ },
1295
+ qualityGates: [
1296
+ "Copy cannot invent unsupported pain, claims, numbers, or recent events.",
1297
+ "Weak evidence should route the row to review instead of send-ready copy.",
1298
+ "Destination fields must remain blocked until approval metadata is present."
1299
+ ],
1300
+ activationBoundary: "Copy readiness is not delivery approval. Export, sync, sender load, and launch require a separate human-approved gate.",
1301
+ memoryKeywords: ["company signals", "evidence-fed copy", "why now", "copy blocker", "approval gate"]
1302
+ },
1303
+ {
1304
+ slug: "domain-first-recovery",
1305
+ label: "Domain-First Recovery",
1306
+ whenToUse: [
1307
+ "Strict yield is low and broad people sourcing creates noisy, duplicated, or off-fit rows.",
1308
+ "The account universe should be recovered or expanded before more contact spend."
1309
+ ],
1310
+ sequence: [
1311
+ "Model attrition after an initial sample.",
1312
+ "Source or recover account domains in tight slices.",
1313
+ "Filter domains locally before contact discovery.",
1314
+ "Use accepted domains as the seed for person and email work."
1315
+ ],
1316
+ requiredFields: {
1317
+ domainReview: ["company_domain", "source_slice", "domain_fit_score", "domain_rejection_reason", "accepted_domain"],
1318
+ recovery: ["target_gap", "expected_yield", "accepted_domain_count", "contact_pull_limit"]
1319
+ },
1320
+ qualityGates: [
1321
+ "Do not repeat broad people-with-email sourcing after strict yield proves low.",
1322
+ "Rejected domains should stay suppressed unless the operator changes the ICP.",
1323
+ "Target count means final held rows, not raw sourced rows."
1324
+ ],
1325
+ activationBoundary: "Domain recovery informs sourcing. Contact enrichment, paid qualification, and export still require approved gates.",
1326
+ memoryKeywords: ["domain-first", "yield modeling", "attrition", "accepted domains", "gap fill"]
1327
+ },
1328
+ {
1329
+ slug: "table-workflow-handoff",
1330
+ label: "Table Workflow Handoff",
1331
+ whenToUse: [
1332
+ "The campaign needs connected source, account, people, enrichment, copy, and destination tables.",
1333
+ "A workspace or partner tool owns part of the workflow through MCP, webhook, API, or managed integration."
1334
+ ],
1335
+ sequence: [
1336
+ "Create source/account context before child people rows.",
1337
+ "Carry source context into enrichment, copy, and destination mapping.",
1338
+ "Expose request-ready, result, error, blocker, and export-ready fields for every action.",
1339
+ "Dry-run provider routes and destination writes before activation."
1340
+ ],
1341
+ requiredFields: {
1342
+ workflow: ["source_record_id", "company_context", "request_ready", "provider_status", "error", "export_ready", "export_blocker"],
1343
+ destination: ["destination_type", "destination_status", "approval_status", "approved_by", "approved_at"]
1344
+ },
1345
+ qualityGates: [
1346
+ "Every paid/API action needs visible request readiness and parsed output fields.",
1347
+ "Child people rows must preserve the account context that justified the search.",
1348
+ "Provider route activation must dry-run before any external write."
1349
+ ],
1350
+ activationBoundary: "MCP, webhook, managed integration, and destination routes remain dry-run until the reviewed route and campaign are approved.",
1351
+ memoryKeywords: ["table workflow", "request ready", "provider status", "export blocker", "BYO integration"]
1352
+ }
1353
+ ];
1354
+ var CAMPAIGN_BUILDER_STRATEGY_TEMPLATES = [
1355
+ {
1356
+ slug: "industrial-ot-resilience",
1357
+ label: "Industrial OT Resilience",
1358
+ aliases: ["industrial ot", "ot resilience", "industrial continuity", "industrial-ot-resilience"],
1359
+ defaultTargetCount: 3e3,
1360
+ campaignName: "Industrial OT Resilience Net-New",
1361
+ accountContext: [
1362
+ "Strategy template: Signaliz-only OT, industrial, manufacturing, embedded systems, field service, cyber resilience, and business continuity sourcing.",
1363
+ "Use prior approved campaign output as the email suppression baseline; final files must have zero prior-used email overlap.",
1364
+ "Keep external qualification providers disabled unless the operator explicitly changes the requirement."
1365
+ ].join(" "),
1366
+ icp: {
1367
+ personas: [
1368
+ "OT leader",
1369
+ "Industrial automation leader",
1370
+ "Engineering leader",
1371
+ "IT infrastructure leader",
1372
+ "Reliability or maintenance leader",
1373
+ "Operations leader"
1374
+ ],
1375
+ industries: [
1376
+ "Machinery",
1377
+ "Electrical and electronic manufacturing",
1378
+ "Mechanical or industrial engineering",
1379
+ "Industrial automation",
1380
+ "Semiconductors",
1381
+ "Medical devices",
1382
+ "Oil and energy",
1383
+ "Automotive"
1384
+ ],
1385
+ geographies: ["United States", "United Kingdom", "Canada", "Nordics", "Netherlands"],
1386
+ keywords: [
1387
+ "OT",
1388
+ "ICS",
1389
+ "SCADA",
1390
+ "control systems",
1391
+ "industrial automation",
1392
+ "manufacturing",
1393
+ "plant operations",
1394
+ "reliability",
1395
+ "maintenance",
1396
+ "PLC",
1397
+ "business continuity"
1398
+ ],
1399
+ exclusions: [
1400
+ "sales",
1401
+ "marketing",
1402
+ "recruiting",
1403
+ "HR",
1404
+ "finance",
1405
+ "legal",
1406
+ "customer success",
1407
+ "retail",
1408
+ "restaurants",
1409
+ "staffing",
1410
+ "real estate"
1411
+ ],
1412
+ requireVerifiedEmail: true
1413
+ },
1414
+ builtIns: ["lead_generation", "email_finding", "email_verification", "signals"],
1415
+ preferredProviders: ["signaliz_native"],
1416
+ memoryQueries: [{
1417
+ query: "industrial OT net-new prior email suppression verified manufacturing embedded systems field service cyber resilience business continuity",
1418
+ scopes: ["workspace", "operator_notes"],
1419
+ topK: 10,
1420
+ required: true,
1421
+ rationale: "Load OT sourcing, dedupe, cache metadata, and approval gates before planning net-new work."
1422
+ }],
1423
+ constraints: {
1424
+ deliverabilityNotes: [
1425
+ "Require verified email, valid syntax, first name, last name, company name, and normalized company domain.",
1426
+ "Keep export, upload, sync, send, and replacement actions blocked until explicit approval.",
1427
+ "Treat prior-domain matches as flagged review evidence unless strict domain suppression is explicitly requested."
1428
+ ]
1429
+ },
1430
+ signalizDefaults: {
1431
+ copy: {
1432
+ offerContext: "Do not invent product claims. Anchor messaging only in row-supported OT, industrial, cyber resilience, backup/recovery, or business-continuity context."
1433
+ }
1434
+ },
1435
+ agencyContext: {
1436
+ partnerEcosystem: ["signaliz", "instantly", "nango"]
1437
+ },
1438
+ operatingPlaybookSlugs: ["net-new-suppressed-list", "proof-first-vertical-gate", "signal-led-copy-approval"]
1439
+ },
1440
+ {
1441
+ slug: "non-medical-home-care",
1442
+ label: "Non-Medical Home Care Operations",
1443
+ aliases: ["home care", "non-medical home care", "home-care-operations", "non-medical-home-care"],
1444
+ defaultTargetCount: 3e3,
1445
+ campaignName: "Mature Home Care Agency Operators",
1446
+ accountContext: [
1447
+ "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.",
1448
+ "Use proof before paid enrichment or copy. Preserve pass vs review ICP status because healthcare language often blurs home care and home health."
1449
+ ].join(" "),
1450
+ icp: {
1451
+ personas: [
1452
+ "Owner",
1453
+ "CEO",
1454
+ "COO",
1455
+ "Administrator",
1456
+ "Operations Director",
1457
+ "Scheduler",
1458
+ "Care coordinator leader"
1459
+ ],
1460
+ industries: ["Non-medical home care", "Senior care", "Private duty care", "Home services"],
1461
+ companySizes: ["20+ employees", "600+ billable care hours/week", "1000+ billable care hours/week ideal"],
1462
+ geographies: ["United States"],
1463
+ keywords: [
1464
+ "non-medical home care",
1465
+ "private duty",
1466
+ "caregiver recruiting",
1467
+ "multi-location",
1468
+ "franchise",
1469
+ "scheduler",
1470
+ "billing",
1471
+ "payroll",
1472
+ "EVV",
1473
+ "WellSky",
1474
+ "AxisCare",
1475
+ "CareSmartz360"
1476
+ ],
1477
+ exclusions: [
1478
+ "home health",
1479
+ "skilled nursing",
1480
+ "hospice",
1481
+ "hospital",
1482
+ "clinic",
1483
+ "therapy practice",
1484
+ "very small owner-only shop"
1485
+ ],
1486
+ requireVerifiedEmail: true
1487
+ },
1488
+ builtIns: ["lead_generation", "local_leads", "email_finding", "email_verification", "signals"],
1489
+ preferredProviders: ["signaliz_native", "octave", "clay_webhook", "apify"],
1490
+ memoryQueries: [{
1491
+ query: "mature non-medical home care agencies billable hours franchise caregiver recruiting proof gate qualification export approval",
1492
+ scopes: ["workspace", "operator_notes"],
1493
+ topK: 10,
1494
+ required: true,
1495
+ rationale: "Load home-care ICP gates, source lanes, qualification thresholds, and home-care exclusion logic."
1496
+ }],
1497
+ constraints: {
1498
+ deliverabilityNotes: [
1499
+ "Company proof and strict ICP gate must pass before contact search, email finding, Signaliz signals, or export.",
1500
+ "Home health is an exclusion signal, not a synonym for home care."
1501
+ ]
1502
+ },
1503
+ signalizDefaults: {
1504
+ copy: {
1505
+ offerContext: "Use angles around after-hours shift recovery, billing/payroll exceptions, multi-location consistency, and caregiver retention only when supported by evidence."
1506
+ }
1507
+ },
1508
+ agencyContext: {
1509
+ partnerEcosystem: ["clay", "octave", "signaliz", "instantly", "nango"]
1510
+ },
1511
+ operatingPlaybookSlugs: ["proof-first-vertical-gate", "domain-first-recovery", "table-workflow-handoff"]
1512
+ },
1513
+ {
1514
+ slug: "agency-founder-led",
1515
+ label: "Founder-Led Agency Services",
1516
+ aliases: ["agency founder", "founder-led agency", "agency-founder-led"],
1517
+ defaultTargetCount: 3e3,
1518
+ campaignName: "Founder-Led Agency Executive Campaign",
1519
+ accountContext: [
1520
+ "Strategy template: agency founder, owner, CEO, and executive sourcing across marketing services, creative, web, PR, ecommerce, paid media, SEO, content, and specialist digital agencies.",
1521
+ "Use suppression files, company-domain pool review, people/email verification queues, and final approval gates before any delivery action."
1522
+ ].join(" "),
1523
+ icp: {
1524
+ personas: ["Founder", "Owner", "CEO", "Managing Partner", "President", "Agency Executive"],
1525
+ industries: [
1526
+ "Marketing services",
1527
+ "Advertising services",
1528
+ "Digital marketing agency",
1529
+ "Creative agency",
1530
+ "PR and communications",
1531
+ "Ecommerce agency",
1532
+ "Paid media agency",
1533
+ "SEO agency",
1534
+ "Content agency"
1535
+ ],
1536
+ companySizes: ["11-50", "25-150", "51-200"],
1537
+ geographies: ["United States"],
1538
+ keywords: [
1539
+ "agency founder",
1540
+ "performance marketing",
1541
+ "paid media",
1542
+ "SEO",
1543
+ "content",
1544
+ "creative",
1545
+ "web design",
1546
+ "brand agency",
1547
+ "PR communications",
1548
+ "Shopify",
1549
+ "Klaviyo"
1550
+ ],
1551
+ exclusions: ["enterprise holding company", "staffing", "recruiting", "software-only vendor", "freelancer-only profile"],
1552
+ requireVerifiedEmail: true
1553
+ },
1554
+ builtIns: ["lead_generation", "email_finding", "email_verification", "signals"],
1555
+ preferredProviders: ["signaliz_native", "octave"],
1556
+ memoryQueries: [{
1557
+ query: "agency founder owner CEO marketing services suppression domain pool email verification final approval gate",
1558
+ scopes: ["workspace", "operator_notes"],
1559
+ topK: 10,
1560
+ required: true,
1561
+ rationale: "Load agency-segment sourcing lanes, suppression rules, and verification workflow lessons."
1562
+ }],
1563
+ constraints: {
1564
+ deliverabilityNotes: [
1565
+ "Keep email and domain suppression visible in the plan.",
1566
+ "Do not export or send until the final verified file and suppression checks are approved."
1567
+ ]
1568
+ },
1569
+ agencyContext: {
1570
+ partnerEcosystem: ["signaliz", "octave", "instantly", "nango"]
1571
+ },
1572
+ operatingPlaybookSlugs: ["net-new-suppressed-list", "signal-led-copy-approval", "table-workflow-handoff"]
1573
+ },
1574
+ {
1575
+ slug: "cloud-infrastructure-displacement",
1576
+ label: "Cloud Infrastructure Displacement",
1577
+ aliases: ["cloud displacement", "private cloud displacement", "cloud infrastructure", "cloud-infrastructure-displacement"],
1578
+ defaultTargetCount: 3e3,
1579
+ campaignName: "Cloud Infrastructure Displacement Campaign",
1580
+ accountContext: [
1581
+ "Strategy template: managed infrastructure, private cloud, disaster recovery, colocation, and VMware/Broadcom displacement motions.",
1582
+ "The spend-efficient ladder is Signaliz company search, Octave company qualification, Signaliz people search, Octave person qualification, then Signaliz email finding and verification."
1583
+ ].join(" "),
1584
+ icp: {
1585
+ personas: [
1586
+ "CTO",
1587
+ "CIO",
1588
+ "CISO",
1589
+ "CFO tied to cloud spend",
1590
+ "VP Engineering",
1591
+ "VP Infrastructure",
1592
+ "VP Cloud",
1593
+ "Head of Platform",
1594
+ "Director IT",
1595
+ "Cloud Architect",
1596
+ "Infrastructure Architect"
1597
+ ],
1598
+ industries: [
1599
+ "SaaS",
1600
+ "Software",
1601
+ "Cybersecurity",
1602
+ "Fintech",
1603
+ "Healthcare technology",
1604
+ "Compliance and GRC",
1605
+ "DevOps",
1606
+ "Infrastructure",
1607
+ "Observability"
1608
+ ],
1609
+ companySizes: ["$10M-$500M revenue", "50-1500 employees"],
1610
+ geographies: ["United States"],
1611
+ keywords: [
1612
+ "VMware Broadcom",
1613
+ "VxRail",
1614
+ "cloud cost pressure",
1615
+ "private cloud",
1616
+ "Proxmox",
1617
+ "Hyper-V",
1618
+ "managed infrastructure",
1619
+ "DRaaS",
1620
+ "colocation",
1621
+ "uptime",
1622
+ "reliability"
1623
+ ],
1624
+ exclusions: [
1625
+ "MSP competitor",
1626
+ "hosting provider",
1627
+ "data center competitor",
1628
+ "staffing",
1629
+ "recruiting",
1630
+ "international-only",
1631
+ "procurement-only",
1632
+ "AI GPU-heavy infrastructure"
1633
+ ],
1634
+ requireVerifiedEmail: true
1635
+ },
1636
+ builtIns: ["lead_generation", "email_finding", "email_verification", "signals"],
1637
+ preferredProviders: ["signaliz_native", "octave"],
1638
+ memoryQueries: [{
1639
+ query: "cloud hosting infrastructure VMware Broadcom qualification verified email persona trigger SKU mapping",
1640
+ scopes: ["workspace", "operator_notes"],
1641
+ topK: 10,
1642
+ required: true,
1643
+ rationale: "Load cloud-infrastructure qualification order, persona clusters, trigger/SKU mapping, and verified-list QA rules."
1644
+ }],
1645
+ constraints: {
1646
+ deliverabilityNotes: [
1647
+ "Qualify accounts and people before email verification.",
1648
+ "If signal enrichment is deferred or unavailable, state it plainly instead of inventing evidence."
1649
+ ]
1650
+ },
1651
+ signalizDefaults: {
1652
+ copy: {
1653
+ 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."
1654
+ }
1655
+ },
1656
+ agencyContext: {
1657
+ partnerEcosystem: ["signaliz", "octave", "instantly", "nango"]
1658
+ },
1659
+ operatingPlaybookSlugs: ["proof-first-vertical-gate", "domain-first-recovery", "signal-led-copy-approval"]
1660
+ }
1661
+ ];
1171
1662
  var CampaignBuilderAgent = class {
1172
1663
  constructor(client) {
1173
1664
  this.client = client;
1174
1665
  }
1175
1666
  async createPlan(request, options = {}) {
1667
+ const resolvedRequest = applyCampaignBuilderStrategyTemplate(request);
1176
1668
  const warnings = [];
1177
- const workspaceContext = request.workspaceContext ?? await this.getWorkspaceContext(warnings);
1178
- const scopeResult = options.scopeCampaign === false ? void 0 : await this.scopeCampaign(request, warnings);
1669
+ const workspaceContext = resolvedRequest.workspaceContext ?? await this.getWorkspaceContext(warnings);
1670
+ const scopeResult = options.scopeCampaign === false ? void 0 : await this.scopeCampaign(resolvedRequest, warnings);
1179
1671
  if (options.discoverCapabilities !== false) {
1180
- await this.discoverPlannedRoutes(request, warnings);
1672
+ await this.discoverPlannedRoutes(resolvedRequest, warnings);
1181
1673
  }
1182
- return createCampaignBuilderAgentPlan(request, {
1674
+ const plan = createCampaignBuilderAgentPlan(resolvedRequest, {
1183
1675
  workspaceContext,
1184
1676
  scopeBuildArgs: asRecord(scopeResult?.build_campaign_args ?? scopeResult?.buildCampaignArgs),
1185
1677
  warnings
1186
1678
  });
1679
+ if (options.includeStrategyMemoryStatus !== false) {
1680
+ await this.attachStrategyMemoryStatus(plan, warnings);
1681
+ }
1682
+ if (options.includeKernelPlan !== false) {
1683
+ await this.attachKernelCampaignBuildPlan(plan, warnings);
1684
+ }
1685
+ if (options.includeDeliveryRisk !== false) {
1686
+ await this.attachDeliveryRiskPreflight(plan, warnings);
1687
+ }
1688
+ return plan;
1689
+ }
1690
+ async commitPlan(plan, options = {}) {
1691
+ const writeMode = options.confirm === true && options.dryRun === false;
1692
+ if (writeMode && !options.approvedBy) {
1693
+ throw new Error("Campaign builder plan commit requires approvedBy before writing state");
1694
+ }
1695
+ const plannerStep = plan.mcpFlow.find((step) => step.id === "agency-campaign-build-plan");
1696
+ const plannerArgs = asRecord(plannerStep?.arguments);
1697
+ const commitArgs = compact({
1698
+ campaign_id: plan.buildRequest.gtmCampaignId,
1699
+ name: plan.campaignName,
1700
+ campaign_brief: plan.buildRequest.prompt || plan.goal,
1701
+ target_icp: plan.buildRequest.icp ? buildGtmTargetIcpContext(plan.buildRequest.icp) : void 0,
1702
+ lead_count: plan.targetCount,
1703
+ layers: plannerArgs.layers,
1704
+ preferred_providers: plannerArgs.preferred_providers,
1705
+ plan_snapshot: Object.keys(asRecord(plan.kernelPlan)).length > 0 ? plan.kernelPlan : buildFallbackPlanSnapshot(plan),
1706
+ send_config: plan.buildRequest.delivery ? {
1707
+ delivery: plan.buildRequest.delivery,
1708
+ approval_required: true
1709
+ } : void 0,
1710
+ brain_config: compact({
1711
+ campaign_builder_agent_v1: {
1712
+ plan_id: plan.planId,
1713
+ kernel_plan_attached: Object.keys(asRecord(plan.kernelPlan)).length > 0,
1714
+ approval_ids: plan.approvals.map((approval) => approval.id)
1715
+ },
1716
+ brain_defaults: plan.buildRequest.brainDefaults,
1717
+ brain_preflight: plan.buildRequest.brainPreflight,
1718
+ delivery_risk_preflight: plan.buildRequest.deliveryRisk,
1719
+ delivery_risk: plan.buildRequest.deliveryRisk
1720
+ }),
1721
+ metadata: {
1722
+ campaign_builder_agent_v1: {
1723
+ plan_id: plan.planId,
1724
+ source: "campaign-builder-agent",
1725
+ approval_required: plan.approvals.some((approval) => approval.blocking),
1726
+ approval_ids: plan.approvals.map((approval) => approval.id),
1727
+ estimated_credits: plan.estimatedCredits
1728
+ },
1729
+ brain_delivery_risk_preflight: plan.buildRequest.deliveryRisk,
1730
+ delivery_risk: plan.buildRequest.deliveryRisk
1731
+ },
1732
+ approval_required: plan.approvals.some((approval) => approval.blocking),
1733
+ actor_type: "agent",
1734
+ actor_id: options.approvedBy,
1735
+ rationale: options.rationale || "Committed a reviewed strategy-template campaign-builder plan before execution.",
1736
+ idempotency_key: options.idempotencyKey,
1737
+ dry_run: !writeMode,
1738
+ confirm: writeMode
1739
+ });
1740
+ const data = asRecord(await this.callMcp("gtm_campaign_build_plan_commit", commitArgs));
1741
+ const result = mapPlanCommitResult(data);
1742
+ if (result.wroteState && result.campaignId) {
1743
+ plan.buildRequest.gtmCampaignId = result.campaignId;
1744
+ refreshBuildStepArguments(plan);
1745
+ }
1746
+ return result;
1187
1747
  }
1188
1748
  async dryRunPlan(plan, options) {
1189
1749
  let args = buildCampaignArgs({
@@ -1218,6 +1778,15 @@ var CampaignBuilderAgent = class {
1218
1778
  if (missing.length > 0) {
1219
1779
  throw new Error(`Campaign builder approval is incomplete: ${missing.map((a) => a.label).join(", ")}`);
1220
1780
  }
1781
+ if (options?.commitBeforeLaunch && !plan.buildRequest.gtmCampaignId) {
1782
+ await this.commitPlan(plan, {
1783
+ confirm: true,
1784
+ dryRun: false,
1785
+ approvedBy: approval.approvedBy,
1786
+ idempotencyKey: options.idempotencyKey ? `${options.idempotencyKey}:plan-commit` : void 0,
1787
+ rationale: "Committed reviewed campaign-builder plan immediately before approved launch."
1788
+ });
1789
+ }
1221
1790
  let args = buildCampaignArgs({
1222
1791
  ...plan.buildRequest,
1223
1792
  dryRun: false,
@@ -1264,8 +1833,8 @@ var CampaignBuilderAgent = class {
1264
1833
  try {
1265
1834
  return await this.callMcp("scope_campaign", {
1266
1835
  prompt: request.goal,
1267
- client_name: request.clientName,
1268
- client_context: request.clientContext,
1836
+ account_label: campaignBuilderAccountLabel(request),
1837
+ account_context: campaignBuilderAccountContext(request),
1269
1838
  campaign_goal: request.goal,
1270
1839
  target_count: request.targetCount,
1271
1840
  approval_policy: request.approvalPolicy?.requireHumanApproval ? "human_required" : "standard"
@@ -1290,25 +1859,70 @@ var CampaignBuilderAgent = class {
1290
1859
  }
1291
1860
  }
1292
1861
  }
1862
+ async attachStrategyMemoryStatus(plan, warnings) {
1863
+ const statusStep = plan.mcpFlow.find((step) => step.id === "strategy-memory-status");
1864
+ if (!statusStep) return;
1865
+ try {
1866
+ const status = asRecord(await this.callMcp("gtm_campaign_strategy_memory_status", asRecord(statusStep.arguments)));
1867
+ plan.strategyMemoryStatus = status;
1868
+ const blockers = arrayOfStrings(status.blockers) ?? [];
1869
+ if (status.ready === false || blockers.length > 0) {
1870
+ warnings.push(`Strategy memory readiness is incomplete: ${blockers.join("; ") || "missing required strategy or workflow memory"}`);
1871
+ }
1872
+ } catch (error) {
1873
+ warnings.push(`Strategy memory readiness check failed: ${errorMessage(error)}`);
1874
+ }
1875
+ }
1876
+ async attachKernelCampaignBuildPlan(plan, warnings) {
1877
+ const plannerStep = plan.mcpFlow.find((step) => step.id === "agency-campaign-build-plan");
1878
+ if (!plannerStep) return;
1879
+ try {
1880
+ const kernelPlan = await this.callMcp("gtm_campaign_build_plan", asRecord(plannerStep.arguments));
1881
+ plan.kernelPlan = asRecord(kernelPlan);
1882
+ const brainDefaults = asRecord(plan.kernelPlan.brain_defaults ?? plan.kernelPlan.brainDefaults);
1883
+ if (Object.keys(brainDefaults).length > 0 && Object.keys(asRecord(plan.buildRequest.brainDefaults)).length === 0) {
1884
+ plan.buildRequest.brainDefaults = brainDefaults;
1885
+ refreshBuildStepArguments(plan);
1886
+ }
1887
+ } catch (error) {
1888
+ warnings.push(`GTM Kernel campaign build plan failed: ${errorMessage(error)}`);
1889
+ }
1890
+ }
1891
+ async attachDeliveryRiskPreflight(plan, warnings) {
1892
+ if (Object.keys(asRecord(plan.buildRequest.deliveryRisk)).length > 0) return;
1893
+ const riskStep = plan.mcpFlow.find((step) => step.tool === "gtm_brain_delivery_risk");
1894
+ if (!riskStep) return;
1895
+ try {
1896
+ const deliveryRisk = asRecord(await this.callMcp("gtm_brain_delivery_risk", asRecord(riskStep.arguments)));
1897
+ if (Object.keys(deliveryRisk).length > 0) {
1898
+ plan.buildRequest.deliveryRisk = deliveryRisk;
1899
+ refreshBuildStepArguments(plan);
1900
+ }
1901
+ } catch (error) {
1902
+ warnings.push(`GTM Brain delivery risk preflight failed: ${errorMessage(error)}`);
1903
+ }
1904
+ }
1293
1905
  async callMcp(tool, args) {
1294
1906
  return this.client.mcp("tools/call", { name: tool, arguments: compact(args) });
1295
1907
  }
1296
1908
  };
1297
1909
  function createCampaignBuilderAgentPlan(request, context = {}) {
1298
- const defaults = mergeDefaults(request.signalizDefaults);
1299
- const targetCount = request.targetCount ?? numberOrUndefined2(context.scopeBuildArgs?.target_count) ?? 100;
1300
- const campaignName = request.campaignName ?? stringValue(context.scopeBuildArgs?.name) ?? titleFromGoal(request.goal);
1301
- const workspaceContext = context.workspaceContext ?? request.workspaceContext ?? {};
1302
- const memory = normalizeMemory(request);
1303
- const routes = normalizeRoutes(request);
1304
- const estimatedCredits = estimateCredits(request, defaults, targetCount);
1305
- const buildRequest = createBuildRequest(request, defaults, targetCount, campaignName, context.scopeBuildArgs, routes, memory, context.scopeBrainPreflight);
1910
+ const resolvedRequest = applyCampaignBuilderStrategyTemplate(request);
1911
+ const defaults = mergeDefaults(resolvedRequest.signalizDefaults);
1912
+ const targetCount = resolvedRequest.targetCount ?? numberOrUndefined2(context.scopeBuildArgs?.target_count) ?? 100;
1913
+ const campaignName = resolvedRequest.campaignName ?? stringValue(context.scopeBuildArgs?.name) ?? titleFromGoal(resolvedRequest.goal);
1914
+ const workspaceContext = context.workspaceContext ?? resolvedRequest.workspaceContext ?? {};
1915
+ const memory = normalizeMemory(resolvedRequest);
1916
+ const routes = normalizeRoutes(resolvedRequest);
1917
+ const operatingPlaybooks = getCampaignBuilderOperatingPlaybooksForRequest(resolvedRequest);
1918
+ const estimatedCredits = estimateCredits(resolvedRequest, defaults, targetCount);
1919
+ const buildRequest = createBuildRequest(resolvedRequest, defaults, targetCount, campaignName, context.scopeBuildArgs, routes, memory, context.scopeBrainPreflight);
1306
1920
  const brainPreflight = asRecord(buildRequest.brainPreflight);
1307
- const approvals = deriveApprovals(request, routes, memory, estimatedCredits, defaults.delivery?.approvalRequired !== false);
1921
+ const approvals = deriveApprovals(resolvedRequest, routes, memory, estimatedCredits, defaults.delivery?.approvalRequired !== false);
1308
1922
  return {
1309
- planId: `cbp_${hashString(JSON.stringify({ goal: request.goal, campaignName, targetCount, routes }))}`,
1923
+ planId: `cbp_${hashString(JSON.stringify({ goal: resolvedRequest.goal, campaignName, targetCount, routes }))}`,
1310
1924
  campaignName,
1311
- goal: request.goal,
1925
+ goal: resolvedRequest.goal,
1312
1926
  targetCount,
1313
1927
  workspaceContext,
1314
1928
  memory,
@@ -1321,7 +1935,8 @@ function createCampaignBuilderAgentPlan(request, context = {}) {
1321
1935
  approvals,
1322
1936
  buildRequest,
1323
1937
  brainPreflight,
1324
- mcpFlow: createMcpFlow(request, buildRequest, routes, memory, approvals),
1938
+ operatingPlaybooks,
1939
+ mcpFlow: createMcpFlow(resolvedRequest, buildRequest, routes, memory, approvals),
1325
1940
  estimatedCredits,
1326
1941
  warnings: context.warnings ?? []
1327
1942
  };
@@ -1349,6 +1964,249 @@ function createCampaignBuilderApproval(plan, input) {
1349
1964
  approvedAt: (/* @__PURE__ */ new Date()).toISOString()
1350
1965
  };
1351
1966
  }
1967
+ function getCampaignBuilderStrategyTemplate(value) {
1968
+ const normalized = normalizeTemplateKey(value);
1969
+ if (!normalized) return void 0;
1970
+ return CAMPAIGN_BUILDER_STRATEGY_TEMPLATES.find(
1971
+ (template) => template.slug === normalized || template.aliases.some((alias) => normalizeTemplateKey(alias) === normalized)
1972
+ );
1973
+ }
1974
+ function getCampaignBuilderOperatingPlaybook(value) {
1975
+ const normalized = normalizeTemplateKey(value);
1976
+ if (!normalized) return void 0;
1977
+ return CAMPAIGN_BUILDER_OPERATING_PLAYBOOKS.find((playbook) => playbook.slug === normalized);
1978
+ }
1979
+ function getCampaignBuilderOperatingPlaybooksForRequest(request) {
1980
+ const template = getCampaignBuilderStrategyTemplate(request.strategyTemplate);
1981
+ const slugs = uniqueStrings([
1982
+ ...template?.operatingPlaybookSlugs ?? [],
1983
+ ...request.operatingPlaybooks ?? []
1984
+ ]);
1985
+ return slugs.map(getCampaignBuilderOperatingPlaybook).filter((playbook) => Boolean(playbook));
1986
+ }
1987
+ function applyCampaignBuilderStrategyTemplate(request) {
1988
+ const template = getCampaignBuilderStrategyTemplate(request.strategyTemplate);
1989
+ if (!template) return request;
1990
+ return {
1991
+ ...request,
1992
+ strategyTemplate: template.slug,
1993
+ campaignName: request.campaignName ?? template.campaignName,
1994
+ accountContext: mergeText(template.accountContext, campaignBuilderAccountContext(request)),
1995
+ targetCount: request.targetCount ?? template.defaultTargetCount,
1996
+ icp: mergeIcp(template.icp, request.icp),
1997
+ builtIns: request.builtIns ?? template.builtIns,
1998
+ operatingPlaybooks: uniqueStrings([
1999
+ ...template.operatingPlaybookSlugs,
2000
+ ...request.operatingPlaybooks ?? []
2001
+ ]),
2002
+ preferredProviders: uniqueStrings([
2003
+ ...template.preferredProviders,
2004
+ ...request.preferredProviders ?? []
2005
+ ]),
2006
+ memory: mergeMemoryPlan({
2007
+ enabled: true,
2008
+ useWorkspaceHistory: true,
2009
+ useNetworkPatterns: request.memory?.useNetworkPatterns,
2010
+ privacyMode: request.memory?.privacyMode,
2011
+ queries: template.memoryQueries
2012
+ }, request.memory),
2013
+ constraints: mergeConstraints(template.constraints, request.constraints),
2014
+ signalizDefaults: mergeSignalizDefaultOverrides(template.signalizDefaults, request.signalizDefaults),
2015
+ agencyContext: mergeAgencyContext(template.agencyContext, request.agencyContext)
2016
+ };
2017
+ }
2018
+ function createCampaignBuilderAgentRequestTemplate(input = {}) {
2019
+ const builtIns = new Set(input.builtIns ?? DEFAULT_CAMPAIGN_BUILDER_BUILT_INS);
2020
+ if (input.includeLocalLeads) builtIns.add("local_leads");
2021
+ const integrations = input.integrations ?? (input.includeCustomToolPlaceholder ? [createCampaignBuilderToolRoute({
2022
+ provider: "custom_mcp",
2023
+ layer: "enrichment",
2024
+ gtmLayers: ["company_enrichment"],
2025
+ toolName: "workspace_enrich",
2026
+ mcpServerName: "workspace-mcp",
2027
+ label: "Workspace enrichment MCP",
2028
+ mode: "if_available",
2029
+ approvalRequired: true
2030
+ })] : void 0);
2031
+ const preferredProviders = uniqueStrings([
2032
+ ...input.preferredProviders ?? [],
2033
+ ...input.includeNango === false ? [] : ["nango"]
2034
+ ]);
2035
+ const templated = applyCampaignBuilderStrategyTemplate({
2036
+ goal: input.goal || "Build a strategy-template campaign for mature operators in the target ICP.",
2037
+ strategyTemplate: input.strategyTemplate || "non-medical-home-care",
2038
+ campaignName: input.campaignName,
2039
+ accountLabel: input.accountLabel || "Workspace Campaign",
2040
+ accountContext: input.accountContext || "Use private workspace memory, current suppression rules, verified-email quality gates, and approval-gated provider routes.",
2041
+ targetCount: input.targetCount,
2042
+ icp: input.icp ?? {
2043
+ personas: ["Operations leader", "Founder", "Revenue leader"],
2044
+ industries: ["B2B services", "Vertical software", "Local operators"],
2045
+ geographies: ["United States"],
2046
+ keywords: ["growth", "operations", "customer acquisition"],
2047
+ requireVerifiedEmail: true
2048
+ },
2049
+ builtIns: [...builtIns],
2050
+ integrations,
2051
+ customerTools: input.customerTools,
2052
+ preferredProviders,
2053
+ constraints: input.constraints,
2054
+ workspaceContext: input.workspaceContext,
2055
+ brainDefaults: input.brainDefaults,
2056
+ deliveryRisk: input.deliveryRisk,
2057
+ gtmCampaignId: input.gtmCampaignId
2058
+ });
2059
+ return compact({
2060
+ ...templated,
2061
+ memory: mergeMemoryPlan({
2062
+ enabled: true,
2063
+ useWorkspaceHistory: true,
2064
+ useNetworkPatterns: false,
2065
+ privacyMode: "anonymized_patterns",
2066
+ queries: [{
2067
+ query: `${templated.strategyTemplate || "strategy-template"} campaign reply patterns, objections, qualification gates, and verified-email QA`,
2068
+ scopes: ["workspace", "operator_notes"],
2069
+ topK: 10,
2070
+ required: true,
2071
+ rationale: "Load approved private strategy and workflow patterns before campaign planning."
2072
+ }]
2073
+ }, input.memory),
2074
+ agencyContext: mergeAgencyContext({
2075
+ strategyModel: "strategy_template",
2076
+ includeStrategyPatterns: true,
2077
+ includeWorkflowPatterns: true,
2078
+ includeNangoCatalog: true,
2079
+ partnerEcosystem: input.includeNango === false ? ["signaliz"] : ["signaliz", "nango"]
2080
+ }, input.agencyContext),
2081
+ signalizDefaults: mergeSignalizDefaultOverrides({
2082
+ maxCredits: input.signalizDefaults?.maxCredits,
2083
+ delivery: {
2084
+ enabled: true,
2085
+ destinationType: input.signalizDefaults?.delivery?.destinationType ?? "json",
2086
+ approvalRequired: true
2087
+ }
2088
+ }, input.signalizDefaults),
2089
+ approvalPolicy: {
2090
+ requireHumanApproval: true,
2091
+ maxCreditsWithoutApproval: 0,
2092
+ requireApprovalFor: DEFAULT_CAMPAIGN_BUILDER_APPROVAL_TYPES,
2093
+ ...input.approvalPolicy
2094
+ }
2095
+ });
2096
+ }
2097
+ function createCampaignBuilderToolRoute(input) {
2098
+ return {
2099
+ provider: input.provider ?? "custom_mcp",
2100
+ layer: input.layer,
2101
+ toolName: input.toolName,
2102
+ mcpServerName: input.mcpServerName,
2103
+ label: input.label,
2104
+ mode: input.mode ?? "if_available",
2105
+ gtmLayer: input.gtmLayer,
2106
+ gtmLayers: input.gtmLayers,
2107
+ approvalRequired: input.approvalRequired ?? input.mode === "required",
2108
+ config: input.config,
2109
+ rationale: `${input.label ?? input.provider ?? "Custom tool"} is a user-provided campaign-builder route for ${input.layer}.`
2110
+ };
2111
+ }
2112
+ function normalizeTemplateKey(value) {
2113
+ return String(value || "").trim().toLowerCase().replace(/[_\s]+/g, "-");
2114
+ }
2115
+ function mergeText(base, override) {
2116
+ if (base && override && !base.includes(override)) return `${base}
2117
+ ${override}`;
2118
+ return override ?? base;
2119
+ }
2120
+ function mergeIcp(base, override) {
2121
+ if (!base) return override;
2122
+ if (!override) return base;
2123
+ return {
2124
+ ...base,
2125
+ ...override,
2126
+ personas: uniqueStrings([...base.personas ?? [], ...override.personas ?? []]),
2127
+ industries: uniqueStrings([...base.industries ?? [], ...override.industries ?? []]),
2128
+ companySizes: uniqueStrings([...base.companySizes ?? [], ...override.companySizes ?? []]),
2129
+ geographies: uniqueStrings([...base.geographies ?? [], ...override.geographies ?? []]),
2130
+ keywords: uniqueStrings([...base.keywords ?? [], ...override.keywords ?? []]),
2131
+ exclusions: uniqueStrings([...base.exclusions ?? [], ...override.exclusions ?? []]),
2132
+ requireVerifiedEmail: override.requireVerifiedEmail ?? base.requireVerifiedEmail
2133
+ };
2134
+ }
2135
+ function mergeMemoryPlan(base, override) {
2136
+ const queries = dedupeMemoryQueries([...base.queries ?? [], ...override?.queries ?? []]);
2137
+ return {
2138
+ ...base,
2139
+ ...override,
2140
+ queries: queries.length > 0 ? queries : void 0,
2141
+ enabled: override?.enabled ?? base.enabled,
2142
+ useWorkspaceHistory: override?.useWorkspaceHistory ?? base.useWorkspaceHistory,
2143
+ useNetworkPatterns: override?.useNetworkPatterns ?? base.useNetworkPatterns,
2144
+ privacyMode: override?.privacyMode ?? base.privacyMode
2145
+ };
2146
+ }
2147
+ function dedupeMemoryQueries(queries) {
2148
+ const seen = /* @__PURE__ */ new Set();
2149
+ return queries.filter((query) => {
2150
+ const key = query.query.trim().toLowerCase();
2151
+ if (!key || seen.has(key)) return false;
2152
+ seen.add(key);
2153
+ return true;
2154
+ });
2155
+ }
2156
+ function mergeConstraints(base, override) {
2157
+ if (!base) return override;
2158
+ if (!override) return base;
2159
+ return {
2160
+ ...base,
2161
+ ...override,
2162
+ geographies: uniqueStrings([...base.geographies ?? [], ...override.geographies ?? []]),
2163
+ exclusions: uniqueStrings([...base.exclusions ?? [], ...override.exclusions ?? []]),
2164
+ deliverabilityNotes: uniqueStrings([...base.deliverabilityNotes ?? [], ...override.deliverabilityNotes ?? []]),
2165
+ maxDailySends: override.maxDailySends ?? base.maxDailySends
2166
+ };
2167
+ }
2168
+ function mergeSignalizDefaultOverrides(base, override) {
2169
+ if (!base) return override;
2170
+ if (!override) return base;
2171
+ return {
2172
+ ...base,
2173
+ ...override,
2174
+ signals: { ...base.signals, ...override.signals },
2175
+ qualification: { ...base.qualification, ...override.qualification },
2176
+ copy: { ...base.copy, ...override.copy },
2177
+ delivery: { ...base.delivery, ...override.delivery }
2178
+ };
2179
+ }
2180
+ function mergeAgencyContext(base, override) {
2181
+ if (!base) return override;
2182
+ if (!override) return base;
2183
+ return {
2184
+ ...base,
2185
+ ...override,
2186
+ partnerEcosystem: uniqueStrings([...base.partnerEcosystem ?? [], ...override.partnerEcosystem ?? []]),
2187
+ strategyModel: override.strategyModel ?? base.strategyModel,
2188
+ includeStrategyPatterns: override.includeStrategyPatterns ?? base.includeStrategyPatterns,
2189
+ includeWorkflowPatterns: override.includeWorkflowPatterns ?? base.includeWorkflowPatterns,
2190
+ includeClayPatterns: override.includeClayPatterns ?? base.includeClayPatterns,
2191
+ includeNangoCatalog: override.includeNangoCatalog ?? base.includeNangoCatalog,
2192
+ revenueMotion: override.revenueMotion ?? base.revenueMotion
2193
+ };
2194
+ }
2195
+ function campaignBuilderStrategyModel(agencyContext) {
2196
+ return agencyContext?.strategyModel ?? "strategy_template";
2197
+ }
2198
+ function campaignBuilderStrategyPatternsEnabled(agencyContext) {
2199
+ return agencyContext?.includeStrategyPatterns ?? true;
2200
+ }
2201
+ function campaignBuilderWorkflowPatternsEnabled(agencyContext) {
2202
+ return agencyContext?.includeWorkflowPatterns ?? agencyContext?.includeClayPatterns ?? true;
2203
+ }
2204
+ function campaignBuilderAccountLabel(request) {
2205
+ return request.accountLabel;
2206
+ }
2207
+ function campaignBuilderAccountContext(request) {
2208
+ return request.accountContext;
2209
+ }
1352
2210
  function mergeDefaults(overrides) {
1353
2211
  return {
1354
2212
  ...DEFAULT_SIGNALIZ_CAMPAIGN_BUILDER_DEFAULTS,
@@ -1361,12 +2219,9 @@ function mergeDefaults(overrides) {
1361
2219
  }
1362
2220
  function normalizeMemory(request) {
1363
2221
  const configured = request.memory ?? {};
1364
- const queries = configured.queries && configured.queries.length > 0 ? configured.queries : [{
1365
- query: request.goal,
1366
- scopes: ["workspace", configured.useNetworkPatterns ? "network_patterns" : "operator_notes"],
1367
- topK: 8,
1368
- rationale: "Seed the campaign plan with prior ICP, angle, source, and reply-performance patterns."
1369
- }];
2222
+ const defaultQueries = defaultAgencyMemoryQueries(request, configured);
2223
+ const configuredQueries = configured.queries ?? [];
2224
+ const queries = configuredQueries.length > 0 ? request.strategyTemplate ? dedupeMemoryQueries([...configuredQueries, ...defaultQueries]) : configuredQueries : defaultQueries;
1370
2225
  return {
1371
2226
  enabled: configured.enabled !== false,
1372
2227
  queries,
@@ -1375,40 +2230,130 @@ function normalizeMemory(request) {
1375
2230
  privacyMode: configured.privacyMode ?? (configured.useNetworkPatterns ? "anonymized_patterns" : "workspace_only")
1376
2231
  };
1377
2232
  }
2233
+ function defaultAgencyMemoryQueries(request, configured) {
2234
+ const operatingPlaybookTerms = getCampaignBuilderOperatingPlaybooksForRequest(request).flatMap((playbook) => [playbook.label, ...playbook.memoryKeywords]).join(" ");
2235
+ const queries = [{
2236
+ query: request.goal,
2237
+ scopes: ["workspace", configured.useNetworkPatterns ? "network_patterns" : "operator_notes"],
2238
+ topK: 8,
2239
+ rationale: "Seed the campaign plan with prior ICP, angle, source, and reply-performance patterns."
2240
+ }];
2241
+ if (campaignBuilderStrategyModel(request.agencyContext) !== "custom" && campaignBuilderStrategyPatternsEnabled(request.agencyContext)) {
2242
+ queries.push({
2243
+ query: [
2244
+ "Private campaign strategy pattern library prior campaign casebook",
2245
+ campaignBuilderAccountLabel(request),
2246
+ operatingPlaybookTerms,
2247
+ request.goal
2248
+ ].filter(Boolean).join(" "),
2249
+ scopes: ["workspace", "operator_notes"],
2250
+ topK: 8,
2251
+ required: true,
2252
+ rationale: "Anchor the plan in private strategy learnings from prior industrial, healthcare, agency-services, infrastructure, recruiting, media, and integration builds."
2253
+ });
2254
+ }
2255
+ if (campaignBuilderWorkflowPatternsEnabled(request.agencyContext)) {
2256
+ queries.push({
2257
+ query: [
2258
+ "Workflow table architecture enrichment qualification copy export gates",
2259
+ request.goal
2260
+ ].filter(Boolean).join(" "),
2261
+ scopes: ["workspace", "operator_notes"],
2262
+ topK: 6,
2263
+ rationale: "Pull workflow patterns for source tables, enrichment order, qualification gates, and handoff controls."
2264
+ });
2265
+ }
2266
+ return queries;
2267
+ }
1378
2268
  function normalizeRoutes(request) {
1379
- const routes = [
1380
- {
1381
- id: "signaliz-source",
2269
+ const routes = builtInRoutesFor(request);
2270
+ routes.push(...routesFromCustomerTools(request.customerTools ?? []));
2271
+ routes.push(...request.integrations ?? []);
2272
+ return routes.map((route, index) => ({
2273
+ ...route,
2274
+ id: route.id ?? `${route.provider}-${route.layer}-${index + 1}`,
2275
+ mode: route.mode ?? "if_available"
2276
+ }));
2277
+ }
2278
+ function builtInRoutesFor(request) {
2279
+ const builtIns = new Set(normalizeBuiltIns(request));
2280
+ const routes = [];
2281
+ if (builtIns.has("lead_generation")) {
2282
+ routes.push({
2283
+ id: "signaliz-lead-generation",
1382
2284
  layer: "source",
2285
+ gtmLayers: ["find_company", "find_people", "lead_generation"],
1383
2286
  provider: "signaliz",
1384
2287
  mode: "required",
1385
2288
  toolName: "generate_leads",
1386
2289
  rationale: "Use Signaliz fresh workspace acquisition as the default source of truth."
1387
- },
1388
- {
1389
- id: "signaliz-verify",
1390
- layer: "qualification",
2290
+ });
2291
+ }
2292
+ if (builtIns.has("local_leads")) {
2293
+ routes.push({
2294
+ id: "signaliz-local-leads",
2295
+ layer: "source",
2296
+ gtmLayer: "local_leads",
2297
+ provider: "signaliz",
2298
+ mode: "if_available",
2299
+ toolName: "generate_local_leads",
2300
+ rationale: "Use Signaliz local-leads sourcing for geography-bound local business campaigns."
2301
+ });
2302
+ }
2303
+ if (builtIns.has("email_finding")) {
2304
+ routes.push({
2305
+ id: "signaliz-email-finding",
2306
+ layer: "enrichment",
2307
+ gtmLayer: "email_finding",
1391
2308
  provider: "signaliz",
1392
2309
  mode: "required",
1393
2310
  toolName: "find_and_verify_emails",
2311
+ rationale: "Find contact emails before verification and campaign handoff."
2312
+ });
2313
+ }
2314
+ if (builtIns.has("email_verification")) {
2315
+ routes.push({
2316
+ id: "signaliz-email-verification",
2317
+ layer: "qualification",
2318
+ gtmLayer: "email_verification",
2319
+ provider: "signaliz",
2320
+ mode: "required",
2321
+ toolName: "verify_emails",
1394
2322
  rationale: "Require verified contactability before sequence delivery."
1395
- },
1396
- {
2323
+ });
2324
+ }
2325
+ if (builtIns.has("signals")) {
2326
+ routes.push({
1397
2327
  id: "signaliz-signals",
1398
2328
  layer: "enrichment",
2329
+ gtmLayer: "company_enrichment",
1399
2330
  provider: "signaliz",
1400
2331
  mode: "if_available",
1401
2332
  toolName: "enrich_company_signals",
1402
2333
  rationale: "Attach current buying signals and evidence for qualification and copy."
1403
- }
1404
- ];
1405
- routes.push(...routesFromCustomerTools(request.customerTools ?? []));
1406
- routes.push(...request.integrations ?? []);
1407
- return routes.map((route, index) => ({
1408
- ...route,
1409
- id: route.id ?? `${route.provider}-${route.layer}-${index + 1}`,
1410
- mode: route.mode ?? "if_available"
1411
- }));
2334
+ });
2335
+ }
2336
+ return routes;
2337
+ }
2338
+ function normalizeBuiltIns(request) {
2339
+ const configured = request.builtIns !== void 0 ? request.builtIns : DEFAULT_CAMPAIGN_BUILDER_BUILT_INS;
2340
+ const builtIns = new Set(configured);
2341
+ if (request.builtIns === void 0 && looksLikeLocalLeadCampaign(request)) {
2342
+ builtIns.add("local_leads");
2343
+ }
2344
+ return [...builtIns].filter(isCampaignBuilderBuiltInTool);
2345
+ }
2346
+ function isCampaignBuilderBuiltInTool(value) {
2347
+ return ["lead_generation", "local_leads", "email_finding", "email_verification", "signals"].includes(String(value));
2348
+ }
2349
+ function looksLikeLocalLeadCampaign(request) {
2350
+ const text = [
2351
+ request.goal,
2352
+ campaignBuilderAccountContext(request),
2353
+ ...request.icp?.industries ?? [],
2354
+ ...request.icp?.keywords ?? []
2355
+ ].filter(Boolean).join(" ").toLowerCase();
2356
+ return /\b(local|google maps|near me|nearby|city|cities|location|locations|home services?|clinics?|restaurants?|contractors?)\b/.test(text);
1412
2357
  }
1413
2358
  function routesFromCustomerTools(tools) {
1414
2359
  return tools.flatMap(
@@ -1426,7 +2371,7 @@ function routesFromCustomerTools(tools) {
1426
2371
  ...tool.config,
1427
2372
  available_tools: tool.availableTools
1428
2373
  },
1429
- rationale: `${tool.label ?? tool.provider} is customer-provided for ${layer}.`
2374
+ rationale: `${tool.label ?? tool.provider} is operator-provided for ${layer}.`
1430
2375
  }))
1431
2376
  );
1432
2377
  }
@@ -1471,6 +2416,7 @@ function createBuildRequest(request, defaults, targetCount, campaignName, scopeB
1471
2416
  return buildRequest;
1472
2417
  }
1473
2418
  function createBrainPreflight(request, buildRequest, routes, memory) {
2419
+ const operatingPlaybooks = getCampaignBuilderOperatingPlaybooksForRequest(request);
1474
2420
  const layers = uniqueStrings([
1475
2421
  "icp",
1476
2422
  "email_finding",
@@ -1480,7 +2426,7 @@ function createBrainPreflight(request, buildRequest, routes, memory) {
1480
2426
  ["instantly", "smartlead", "heyreach"].some((provider) => routes.some((route) => route.provider === provider)) ? "sender" : void 0,
1481
2427
  memory.enabled ? "feedback" : void 0
1482
2428
  ]);
1483
- const providerChain = uniqueStrings(["signaliz", ...routes.map((route) => route.provider)]);
2429
+ const providerChain = uniqueStrings(["signaliz", ...request.preferredProviders ?? [], ...routes.map((route) => route.provider)]);
1484
2430
  const targetIcp = compact({
1485
2431
  personas: buildRequest.icp?.personas,
1486
2432
  industries: buildRequest.icp?.industries,
@@ -1521,6 +2467,13 @@ function createBrainPreflight(request, buildRequest, routes, memory) {
1521
2467
  required: true,
1522
2468
  policy: "Run read-only GTM Brain preflight before build_campaign so learned defaults, memory, and deliverability risk stay attached to the build.",
1523
2469
  layers,
2470
+ operating_playbooks: operatingPlaybooks.map((playbook) => ({
2471
+ slug: playbook.slug,
2472
+ label: playbook.label,
2473
+ quality_gates: playbook.qualityGates,
2474
+ required_fields: playbook.requiredFields,
2475
+ activation_boundary: playbook.activationBoundary
2476
+ })),
1524
2477
  target_icp: targetIcp,
1525
2478
  provider_chain: providerChain,
1526
2479
  lead_source: providerChain[0] ?? "signaliz",
@@ -1653,6 +2606,47 @@ function createMcpFlow(request, buildRequest, routes, memory, approvals) {
1653
2606
  approvalRequired: false
1654
2607
  }
1655
2608
  ];
2609
+ steps.push({
2610
+ id: "gtm-provider-catalog",
2611
+ phase: "plan",
2612
+ tool: "gtm_provider_catalog",
2613
+ arguments: {
2614
+ include_layer_catalog: true,
2615
+ include_planned: true
2616
+ },
2617
+ readOnly: true,
2618
+ approvalRequired: false
2619
+ });
2620
+ if (request.agencyContext?.includeNangoCatalog !== false) {
2621
+ steps.push({
2622
+ id: "nango-tool-catalog",
2623
+ phase: "plan",
2624
+ tool: "nango_mcp_tools_list",
2625
+ arguments: {
2626
+ format: "mcp"
2627
+ },
2628
+ readOnly: true,
2629
+ approvalRequired: false
2630
+ });
2631
+ }
2632
+ if (memory.enabled) {
2633
+ steps.push({
2634
+ id: "strategy-memory-status",
2635
+ phase: "memory",
2636
+ tool: "gtm_campaign_strategy_memory_status",
2637
+ arguments: buildGtmCampaignStrategyMemoryStatusArgs(request, buildRequest),
2638
+ readOnly: true,
2639
+ approvalRequired: false
2640
+ });
2641
+ }
2642
+ steps.push({
2643
+ id: "agency-campaign-build-plan",
2644
+ phase: "plan",
2645
+ tool: "gtm_campaign_build_plan",
2646
+ arguments: buildGtmCampaignBuildPlanArgs(request, buildRequest, routes, memory),
2647
+ readOnly: true,
2648
+ approvalRequired: memory.useNetworkPatterns === true
2649
+ });
1656
2650
  if (memory.enabled) {
1657
2651
  for (const [index, query] of memory.queries.entries()) {
1658
2652
  steps.push({
@@ -1666,6 +2660,25 @@ function createMcpFlow(request, buildRequest, routes, memory, approvals) {
1666
2660
  }
1667
2661
  }
1668
2662
  for (const route of routes) {
2663
+ if (shouldPrepareProviderRoute(route)) {
2664
+ steps.push({
2665
+ id: `prepare-${route.id}`,
2666
+ phase: "plan",
2667
+ tool: "gtm_provider_recipe_prepare",
2668
+ arguments: buildProviderRecipePrepareArgs(route, buildRequest),
2669
+ readOnly: true,
2670
+ approvalRequired: false
2671
+ });
2672
+ steps.push({
2673
+ id: `activate-${route.id}-dry-run`,
2674
+ phase: "plan",
2675
+ tool: "gtm_provider_route_activate",
2676
+ arguments: buildProviderRouteActivateArgs(route, buildRequest),
2677
+ readOnly: true,
2678
+ approvalRequired: false
2679
+ });
2680
+ }
2681
+ const routeApprovalRequired = route.approvalRequired === true || route.provider !== "signaliz" && route.approvalRequired !== false && route.mode === "required" || route.layer === "delivery" || route.layer === "feedback";
1669
2682
  steps.push({
1670
2683
  id: `route-${route.id}`,
1671
2684
  phase: route.layer,
@@ -1677,7 +2690,7 @@ function createMcpFlow(request, buildRequest, routes, memory, approvals) {
1677
2690
  config: route.config
1678
2691
  },
1679
2692
  readOnly: !["delivery", "feedback"].includes(route.layer),
1680
- approvalRequired: route.approvalRequired === true || route.layer === "delivery" || route.layer === "feedback"
2693
+ approvalRequired: routeApprovalRequired
1681
2694
  });
1682
2695
  }
1683
2696
  steps.push({
@@ -1686,8 +2699,8 @@ function createMcpFlow(request, buildRequest, routes, memory, approvals) {
1686
2699
  tool: "scope_campaign",
1687
2700
  arguments: {
1688
2701
  prompt: request.goal,
1689
- client_name: request.clientName,
1690
- client_context: request.clientContext,
2702
+ account_label: campaignBuilderAccountLabel(request),
2703
+ account_context: campaignBuilderAccountContext(request),
1691
2704
  target_count: request.targetCount
1692
2705
  },
1693
2706
  readOnly: true,
@@ -1749,9 +2762,199 @@ function createMcpFlow(request, buildRequest, routes, memory, approvals) {
1749
2762
  });
1750
2763
  return steps.map((step) => ({ ...step, arguments: compact(step.arguments) }));
1751
2764
  }
2765
+ function shouldPrepareProviderRoute(route) {
2766
+ return !["signaliz", "csv"].includes(route.provider);
2767
+ }
2768
+ function buildProviderRecipePrepareArgs(route, buildRequest) {
2769
+ const layerCapabilities = uniqueStrings(gtmLayersForRoute(route));
2770
+ const layer = layerCapabilities[0] ?? mapCampaignBuilderLayerToGtmLayer(route.layer) ?? "custom";
2771
+ const config = asRecord(route.config);
2772
+ return compact({
2773
+ provider_id: route.provider,
2774
+ provider_name: route.label,
2775
+ layer,
2776
+ layer_capabilities: layerCapabilities.length > 0 ? layerCapabilities : void 0,
2777
+ invocation_type: route.providerCapability?.invocationType ?? inferProviderInvocationType(route),
2778
+ auth_strategy: inferProviderAuthStrategy(route),
2779
+ workspace_mcp_server_id: stringValue(config.workspace_mcp_server_id ?? config.workspaceMcpServerId ?? route.mcpServerName),
2780
+ workspace_integration_id: stringValue(config.workspace_integration_id ?? config.workspaceIntegrationId),
2781
+ workspace_connection_id: stringValue(config.workspace_connection_id ?? config.workspaceConnectionId),
2782
+ endpoint_url: stringValue(config.endpoint_url ?? config.endpointUrl ?? config.webhook_url ?? config.webhookUrl),
2783
+ request_template: asOptionalRecord(config.request_template ?? config.requestTemplate),
2784
+ response_mapping: asOptionalRecord(config.response_mapping ?? config.responseMapping),
2785
+ input_schema: asOptionalRecord(config.input_schema ?? config.inputSchema ?? route.providerCapability?.exampleInputSchema),
2786
+ output_schema: asOptionalRecord(config.output_schema ?? config.outputSchema ?? route.providerCapability?.exampleOutputSchema),
2787
+ readiness: asOptionalRecord(config.readiness),
2788
+ metadata: compact({
2789
+ source: "campaign-builder-agent",
2790
+ route_id: route.id,
2791
+ campaign_name: buildRequest.name,
2792
+ tool_name: route.toolName,
2793
+ mcp_server_name: route.mcpServerName,
2794
+ dry_run_only: true
2795
+ }),
2796
+ context: compact({
2797
+ source: "campaign-builder-agent",
2798
+ route_id: route.id,
2799
+ gtm_campaign_id: buildRequest.gtmCampaignId
2800
+ }),
2801
+ use_signaliz_fallback: route.routingPolicy?.useSignalizFallback ?? true,
2802
+ priority: numberOrUndefined2(config.priority),
2803
+ status: stringValue(config.status) ?? "needs_setup"
2804
+ });
2805
+ }
2806
+ function buildProviderRouteActivateArgs(route, buildRequest) {
2807
+ const layerCapabilities = uniqueStrings(gtmLayersForRoute(route));
2808
+ const config = asRecord(route.config);
2809
+ return compact({
2810
+ provider_id: route.provider,
2811
+ provider_name: route.label,
2812
+ campaign_id: buildRequest.gtmCampaignId,
2813
+ layer: layerCapabilities[0] ?? mapCampaignBuilderLayerToGtmLayer(route.layer) ?? "custom",
2814
+ layers: layerCapabilities.length > 0 ? layerCapabilities : void 0,
2815
+ invocation_type: route.providerCapability?.invocationType ?? inferProviderInvocationType(route),
2816
+ auth_strategy: inferProviderAuthStrategy(route),
2817
+ workspace_mcp_server_id: stringValue(config.workspace_mcp_server_id ?? config.workspaceMcpServerId ?? route.mcpServerName),
2818
+ workspace_integration_id: stringValue(config.workspace_integration_id ?? config.workspaceIntegrationId),
2819
+ workspace_connection_id: stringValue(config.workspace_connection_id ?? config.workspaceConnectionId),
2820
+ endpoint_url: stringValue(config.endpoint_url ?? config.endpointUrl ?? config.webhook_url ?? config.webhookUrl),
2821
+ route_config: compact({
2822
+ ...asRecord(config.route_config ?? config.routeConfig),
2823
+ source: "campaign-builder-agent",
2824
+ route_id: route.id,
2825
+ tool_name: route.toolName,
2826
+ mcp_server_name: route.mcpServerName
2827
+ }),
2828
+ use_signaliz_fallback: route.routingPolicy?.useSignalizFallback ?? true,
2829
+ priority: numberOrUndefined2(config.priority),
2830
+ dry_run: true,
2831
+ confirm: false
2832
+ });
2833
+ }
2834
+ function inferProviderInvocationType(route) {
2835
+ if (route.provider === "airbyte") return "airbyte";
2836
+ if (route.provider === "nango") return "managed_integration";
2837
+ if (["custom_webhook", "webhook", "clay_webhook"].includes(route.provider)) return "webhook";
2838
+ if (["custom_api", "apollo", "ai_ark", "apify"].includes(route.provider)) return "api";
2839
+ if (route.mcpServerName || route.toolName || ["custom_mcp", "octave"].includes(route.provider)) return "mcp_tool";
2840
+ return "manual";
2841
+ }
2842
+ function inferProviderAuthStrategy(route) {
2843
+ const config = asRecord(route.config);
2844
+ const configured = stringValue(config.auth_strategy ?? config.authStrategy);
2845
+ if (configured) return configured;
2846
+ const invocationType = route.providerCapability?.invocationType ?? inferProviderInvocationType(route);
2847
+ if (invocationType === "webhook") return "webhook_secret";
2848
+ if (invocationType === "mcp_tool") return "mcp_auth";
2849
+ if (invocationType === "managed_integration") return "byo_runtime";
2850
+ if (invocationType === "api" || invocationType === "airbyte") return "integration_key";
2851
+ return void 0;
2852
+ }
2853
+ function refreshBuildStepArguments(plan) {
2854
+ for (const step of plan.mcpFlow) {
2855
+ if (step.id === "dry-run-build") {
2856
+ step.arguments = compact({
2857
+ ...buildCampaignArgs({ ...plan.buildRequest, dryRun: true, confirmSpend: false }),
2858
+ dry_run: true
2859
+ });
2860
+ }
2861
+ if (step.id === "approved-build") {
2862
+ step.arguments = compact({
2863
+ ...buildCampaignArgs({ ...plan.buildRequest, dryRun: false, confirmSpend: true }),
2864
+ required_approvals: plan.approvals.map((approval) => approval.id)
2865
+ });
2866
+ }
2867
+ }
2868
+ }
2869
+ function buildFallbackPlanSnapshot(plan) {
2870
+ const plannerStep = plan.mcpFlow.find((step) => step.id === "agency-campaign-build-plan");
2871
+ return compact({
2872
+ source_tool: "campaign-builder-agent",
2873
+ plan_id: plan.planId,
2874
+ query: asRecord(plannerStep?.arguments),
2875
+ campaign_name: plan.campaignName,
2876
+ goal: plan.goal,
2877
+ target_count: plan.targetCount,
2878
+ approvals: plan.approvals,
2879
+ brain_preflight: plan.brainPreflight,
2880
+ operating_playbooks: plan.operatingPlaybooks
2881
+ });
2882
+ }
2883
+ function mapPlanCommitResult(data) {
2884
+ const campaign = asRecord(data.campaign);
2885
+ const campaignBuild = asRecord(data.campaign_build ?? data.campaignBuild);
2886
+ const committedPlan = asRecord(data.committed_plan ?? data.committedPlan);
2887
+ const commitPlan = asRecord(data.commit_plan ?? data.commitPlan);
2888
+ const campaignArgs = asRecord(commitPlan.campaign_arguments ?? commitPlan.campaignArguments);
2889
+ return {
2890
+ dryRun: data.dry_run === true || data.dryRun === true,
2891
+ wroteState: data.wrote_state === true || data.wroteState === true,
2892
+ campaignId: stringValue(campaign.id ?? committedPlan.campaign_id ?? committedPlan.campaignId ?? commitPlan.campaign_id ?? commitPlan.campaignId ?? campaignArgs.id),
2893
+ campaignBuildId: stringValue(campaignBuild.id ?? committedPlan.campaign_build_id ?? committedPlan.campaignBuildId ?? campaignArgs.campaign_build_id ?? campaignArgs.campaignBuildId),
2894
+ raw: data
2895
+ };
2896
+ }
2897
+ function buildGtmCampaignBuildPlanArgs(request, buildRequest, routes, memory) {
2898
+ const agencyContext = request.agencyContext ?? {};
2899
+ const strategyModel = campaignBuilderStrategyModel(agencyContext);
2900
+ const partnerEcosystem = agencyContext.partnerEcosystem ?? (strategyModel === "custom" ? void 0 : ["clay", "instantly", "nango"]);
2901
+ const layers = uniqueStrings([
2902
+ "icp",
2903
+ buildRequest.icp?.requireVerifiedEmail !== false ? "email_finding" : void 0,
2904
+ buildRequest.icp?.requireVerifiedEmail !== false ? "email_verification" : void 0,
2905
+ ...routes.flatMap(gtmLayersForRoute),
2906
+ buildRequest.delivery?.destinationType === "webhook" ? "destination_export" : void 0,
2907
+ memory.enabled ? "feedback" : void 0
2908
+ ]);
2909
+ const preferredProviders = uniqueStrings([
2910
+ ...request.preferredProviders ?? [],
2911
+ ...routes.map((route) => route.provider).filter((provider) => provider !== "signaliz")
2912
+ ]);
2913
+ const operatingPlaybooks = getCampaignBuilderOperatingPlaybooksForRequest(request);
2914
+ return compact({
2915
+ campaign_id: buildRequest.gtmCampaignId,
2916
+ campaign_brief: buildRequest.prompt || request.goal,
2917
+ strategy_template: request.strategyTemplate,
2918
+ target_icp: buildRequest.icp ? buildGtmTargetIcpContext(buildRequest.icp) : void 0,
2919
+ lead_count: buildRequest.targetCount,
2920
+ layers: layers.length > 0 ? layers : void 0,
2921
+ preferred_providers: preferredProviders.length > 0 ? preferredProviders : void 0,
2922
+ strategy_model: strategyModel,
2923
+ include_strategy_patterns: campaignBuilderStrategyPatternsEnabled(agencyContext),
2924
+ include_workflow_patterns: campaignBuilderWorkflowPatternsEnabled(agencyContext),
2925
+ include_nango_catalog: agencyContext.includeNangoCatalog !== false,
2926
+ partner_ecosystem: partnerEcosystem,
2927
+ operating_playbooks: operatingPlaybooks.map((playbook) => ({
2928
+ slug: playbook.slug,
2929
+ label: playbook.label,
2930
+ quality_gates: playbook.qualityGates,
2931
+ activation_boundary: playbook.activationBoundary
2932
+ })),
2933
+ include_memory: memory.enabled,
2934
+ include_brain: true,
2935
+ include_provider_routes: true,
2936
+ include_failure_patterns: true,
2937
+ include_planned_providers: true,
2938
+ limit: 25
2939
+ });
2940
+ }
2941
+ function buildGtmCampaignStrategyMemoryStatusArgs(request, buildRequest) {
2942
+ return compact({
2943
+ query: request.goal,
2944
+ campaign_brief: buildRequest.prompt || request.goal,
2945
+ strategy_template: request.strategyTemplate,
2946
+ target_icp: buildRequest.icp ? buildGtmTargetIcpContext(buildRequest.icp) : void 0,
2947
+ memory_dimension_filters: request.strategyTemplate ? { strategy_template: request.strategyTemplate } : void 0,
2948
+ require_memory_dimension_match: false,
2949
+ include_samples: false,
2950
+ include_sources: true,
2951
+ days: 3650,
2952
+ limit: 25
2953
+ });
2954
+ }
1752
2955
  function buildGtmMemorySearchArgs(request, routes, query) {
1753
2956
  const layers = uniqueStrings(routes.flatMap(gtmLayersForRoute));
1754
- const providerChain = uniqueStrings(routes.map((route) => route.provider));
2957
+ const providerChain = uniqueStrings([...request.preferredProviders ?? [], ...routes.map((route) => route.provider)]);
1755
2958
  return compact({
1756
2959
  query: query.query,
1757
2960
  limit: query.topK,
@@ -1773,6 +2976,26 @@ function buildGtmTargetIcpContext(icp) {
1773
2976
  require_verified_email: icp.requireVerifiedEmail
1774
2977
  });
1775
2978
  }
2979
+ function mapCampaignBuilderLayerToGtmLayer(layer) {
2980
+ switch (layer) {
2981
+ case "source":
2982
+ return "lead_generation";
2983
+ case "enrichment":
2984
+ return "company_enrichment";
2985
+ case "qualification":
2986
+ return "qualification";
2987
+ case "copy":
2988
+ return "copy_enrichment";
2989
+ case "delivery":
2990
+ return "destination_export";
2991
+ case "feedback":
2992
+ return "feedback";
2993
+ case "approval":
2994
+ return "approval";
2995
+ default:
2996
+ return void 0;
2997
+ }
2998
+ }
1776
2999
  function buildCampaignArgs(request) {
1777
3000
  const args = {
1778
3001
  name: request.name,
@@ -1953,8 +3176,8 @@ function estimateCredits(request, defaults, targetCount) {
1953
3176
  }
1954
3177
  function buildDescription(request) {
1955
3178
  const parts = [
1956
- request.clientName ? `Client: ${request.clientName}` : void 0,
1957
- request.clientContext ? `Context: ${request.clientContext}` : void 0,
3179
+ campaignBuilderAccountLabel(request) ? `Account label: ${campaignBuilderAccountLabel(request)}` : void 0,
3180
+ campaignBuilderAccountContext(request) ? `Context: ${campaignBuilderAccountContext(request)}` : void 0,
1958
3181
  request.constraints?.deliverabilityNotes?.length ? `Deliverability: ${request.constraints.deliverabilityNotes.join("; ")}` : void 0,
1959
3182
  "Agent-built campaign plan layered on Signaliz kernel and existing MCP tools."
1960
3183
  ];
@@ -1977,6 +3200,10 @@ function compact(record) {
1977
3200
  function asRecord(value) {
1978
3201
  return value && typeof value === "object" && !Array.isArray(value) ? value : {};
1979
3202
  }
3203
+ function asOptionalRecord(value) {
3204
+ const record = asRecord(value);
3205
+ return Object.keys(record).length > 0 ? record : void 0;
3206
+ }
1980
3207
  function stringValue(value) {
1981
3208
  return typeof value === "string" && value.length > 0 ? value : void 0;
1982
3209
  }
@@ -3721,7 +4948,7 @@ var GtmKernel = class {
3721
4948
  campaigns: input.campaigns.map(campaignHistoryImportCampaignArgs)
3722
4949
  });
3723
4950
  }
3724
- /** Queue a Trigger-backed campaign history import for larger CMM/client backfills. */
4951
+ /** Queue a Trigger-backed campaign history import for larger private campaign backfills. */
3725
4952
  async importCampaignHistoryRun(input) {
3726
4953
  return this.callMcp("gtm_campaign_history_import_run", {
3727
4954
  source: input.source,
@@ -3852,6 +5079,25 @@ var GtmKernel = class {
3852
5079
  write_routine_outcomes: input.writeRoutineOutcomes
3853
5080
  });
3854
5081
  }
5082
+ /** Run a read-only Campaign Audit and persist workspace-scoped failure findings. */
5083
+ async runCampaignAudit(input) {
5084
+ return this.callMcp("gtm_campaign_audit_run", {
5085
+ provider: input.provider,
5086
+ provider_campaign_id: input.providerCampaignId,
5087
+ campaign_id: input.campaignId,
5088
+ campaign_name: input.campaignName,
5089
+ lookback_days: input.lookbackDays,
5090
+ limit_findings: input.limitFindings
5091
+ });
5092
+ }
5093
+ /** Read a persisted Campaign Audit by audit id or campaign id. */
5094
+ async getCampaignAudit(options) {
5095
+ return this.callMcp("gtm_campaign_audit_get", {
5096
+ audit_id: options.auditId,
5097
+ campaign_id: options.campaignId,
5098
+ limit_findings: options.limitFindings
5099
+ });
5100
+ }
3855
5101
  /** Normalize Instantly webhook/pull payloads and ingest row-level feedback through the GTM Kernel. */
3856
5102
  async syncInstantlyFeedback(input) {
3857
5103
  return this.callMcp("gtm_instantly_feedback_sync", {
@@ -4149,6 +5395,40 @@ var GtmKernel = class {
4149
5395
  include_layer_catalog: options.includeLayerCatalog
4150
5396
  });
4151
5397
  }
5398
+ /** List private-safe campaign strategy templates agents can merge into campaign build plans. */
5399
+ async campaignStrategyTemplates(options = {}) {
5400
+ return this.callMcp("gtm_campaign_strategy_templates", {
5401
+ strategy_template: options.strategyTemplate,
5402
+ query: options.query,
5403
+ include_details: options.includeDetails
5404
+ });
5405
+ }
5406
+ /** Build the read-only Memory, Brain, risk, and provider-route runbook needed before planning a campaign. */
5407
+ async campaignStartContext(input = {}) {
5408
+ return this.callMcp("gtm_campaign_start_context", {
5409
+ campaign_id: input.campaignId,
5410
+ campaign_build_id: input.campaignBuildId,
5411
+ campaign_brief: input.campaignBrief,
5412
+ strategy_template: input.strategyTemplate,
5413
+ target_icp: input.targetIcp,
5414
+ lead_count: input.leadCount,
5415
+ layers: input.layers,
5416
+ preferred_providers: input.preferredProviders,
5417
+ memory_dimension_filters: input.memoryDimensionFilters,
5418
+ require_memory_dimension_match: input.requireMemoryDimensionMatch,
5419
+ include_memory: input.includeMemory,
5420
+ include_brain: input.includeBrain,
5421
+ include_provider_routes: input.includeProviderRoutes,
5422
+ include_failure_patterns: input.includeFailurePatterns,
5423
+ include_delivery_risk: input.includeDeliveryRisk,
5424
+ include_global_brain: input.includeGlobalBrain,
5425
+ include_planned_providers: input.includePlannedProviders,
5426
+ days: input.days,
5427
+ min_confidence: input.minConfidence,
5428
+ min_sample_size: input.minSampleSize,
5429
+ limit: input.limit
5430
+ });
5431
+ }
4152
5432
  /** Inspect GTM integration activation cards for UI and agent routing without writing state. */
4153
5433
  async integrationsActivationStatus(options = {}) {
4154
5434
  return this.callMcp("gtm_integrations_activation_status", {
@@ -4164,10 +5444,16 @@ var GtmKernel = class {
4164
5444
  campaign_id: input.campaignId,
4165
5445
  campaign_build_id: input.campaignBuildId,
4166
5446
  campaign_brief: input.campaignBrief,
5447
+ strategy_template: input.strategyTemplate,
4167
5448
  target_icp: input.targetIcp,
4168
5449
  lead_count: input.leadCount,
4169
5450
  layers: input.layers,
4170
5451
  preferred_providers: input.preferredProviders,
5452
+ strategy_model: input.strategyModel,
5453
+ include_strategy_patterns: input.includeStrategyPatterns,
5454
+ include_workflow_patterns: input.includeWorkflowPatterns ?? input.includeClayPatterns,
5455
+ include_nango_catalog: input.includeNangoCatalog,
5456
+ partner_ecosystem: input.partnerEcosystem,
4171
5457
  memory_dimension_filters: input.memoryDimensionFilters,
4172
5458
  require_memory_dimension_match: input.requireMemoryDimensionMatch,
4173
5459
  include_memory: input.includeMemory,
@@ -4179,6 +5465,79 @@ var GtmKernel = class {
4179
5465
  limit: input.limit
4180
5466
  });
4181
5467
  }
5468
+ /** Emit reusable CampaignBuilderAgentRequest JSON from hosted MCP strategy-template defaults without spending credits. */
5469
+ async campaignAgentRequestTemplate(input = {}) {
5470
+ return this.callMcp("gtm_campaign_agent_request_template", {
5471
+ goal: input.goal,
5472
+ campaign_brief: input.campaignBrief,
5473
+ campaign_name: input.campaignName,
5474
+ account_label: input.accountLabel,
5475
+ account_context: input.accountContext,
5476
+ strategy_template: input.strategyTemplate,
5477
+ operating_playbooks: input.operatingPlaybooks,
5478
+ target_icp: input.targetIcp,
5479
+ target_count: input.targetCount,
5480
+ builtins: input.builtIns,
5481
+ include_local_leads: input.includeLocalLeads,
5482
+ include_byo_placeholder: input.includeByoPlaceholder,
5483
+ include_nango_catalog: input.includeNangoCatalog,
5484
+ preferred_providers: input.preferredProviders,
5485
+ privacy_mode: input.privacyMode,
5486
+ destination_type: input.destinationType
5487
+ });
5488
+ }
5489
+ /** Compose a one-call read-only strategy-template campaign-agent runbook across built-ins, Memory, Brain, Nango, and BYO routes. */
5490
+ async campaignAgentPlan(input = {}) {
5491
+ return this.callMcp("gtm_campaign_agent_plan", {
5492
+ goal: input.goal,
5493
+ campaign_brief: input.campaignBrief,
5494
+ campaign_name: input.campaignName,
5495
+ campaign_id: input.campaignId,
5496
+ campaign_build_id: input.campaignBuildId,
5497
+ strategy_template: input.strategyTemplate,
5498
+ operating_playbooks: input.operatingPlaybooks,
5499
+ account_context: input.accountContext,
5500
+ target_icp: input.targetIcp,
5501
+ target_count: input.targetCount,
5502
+ lead_count: input.leadCount,
5503
+ builtins: input.builtIns,
5504
+ use_local_leads: input.useLocalLeads,
5505
+ layers: input.layers,
5506
+ preferred_providers: input.preferredProviders,
5507
+ custom_tools: input.customTools,
5508
+ integrations: input.integrations,
5509
+ strategy_model: input.strategyModel,
5510
+ include_strategy_patterns: input.includeStrategyPatterns,
5511
+ include_workflow_patterns: input.includeWorkflowPatterns,
5512
+ include_nango_catalog: input.includeNangoCatalog,
5513
+ partner_ecosystem: input.partnerEcosystem,
5514
+ memory_dimension_filters: input.memoryDimensionFilters,
5515
+ require_memory_dimension_match: input.requireMemoryDimensionMatch,
5516
+ include_memory: input.includeMemory,
5517
+ include_brain: input.includeBrain,
5518
+ include_provider_routes: input.includeProviderRoutes,
5519
+ include_failure_patterns: input.includeFailurePatterns,
5520
+ include_delivery_risk: input.includeDeliveryRisk,
5521
+ include_planned_providers: input.includePlannedProviders,
5522
+ days: input.days,
5523
+ limit: input.limit
5524
+ });
5525
+ }
5526
+ /** Inspect private-safe strategy-template/workflow memory readiness before campaign planning. */
5527
+ async campaignStrategyMemoryStatus(input = {}) {
5528
+ return this.callMcp("gtm_campaign_strategy_memory_status", {
5529
+ strategy_template: input.strategyTemplate,
5530
+ query: input.query,
5531
+ campaign_brief: input.campaignBrief,
5532
+ target_icp: input.targetIcp,
5533
+ memory_dimension_filters: input.memoryDimensionFilters,
5534
+ require_memory_dimension_match: input.requireMemoryDimensionMatch,
5535
+ include_samples: input.includeSamples,
5536
+ include_sources: input.includeSources,
5537
+ days: input.days,
5538
+ limit: input.limit
5539
+ });
5540
+ }
4182
5541
  /** Persist a reviewed campaign build plan into a campaign object and audit log. Dry-run first by default. */
4183
5542
  async commitCampaignBuildPlan(input = {}) {
4184
5543
  return this.callMcp("gtm_campaign_build_plan_commit", {
@@ -4325,6 +5684,13 @@ var GtmKernel = class {
4325
5684
  vendor_id: input.vendorId,
4326
5685
  service_category: input.serviceCategory,
4327
5686
  connection_type: input.connectionType,
5687
+ integration_id: input.integrationId,
5688
+ provider_config_key: input.providerConfigKey,
5689
+ allowed_integrations: input.allowedIntegrations,
5690
+ surface: input.surface,
5691
+ source: input.source,
5692
+ user_email: input.userEmail,
5693
+ user_display_name: input.userDisplayName,
4328
5694
  status: input.status,
4329
5695
  metadata: input.metadata
4330
5696
  });
@@ -4381,6 +5747,20 @@ var GtmKernel = class {
4381
5747
  context: input.context
4382
5748
  });
4383
5749
  }
5750
+ /** Create a short-lived Nango Connect session so a user can authorize a vendor API. */
5751
+ async createNangoConnectSession(input) {
5752
+ return this.callMcp("nango_connect_session_create", {
5753
+ provider_id: input.providerId,
5754
+ integration_id: input.integrationId,
5755
+ provider_display_name: input.providerDisplayName,
5756
+ integration_display_name: input.integrationDisplayName,
5757
+ allowed_integrations: input.allowedIntegrations,
5758
+ surface: input.surface,
5759
+ source: input.source,
5760
+ user_email: input.userEmail,
5761
+ user_display_name: input.userDisplayName
5762
+ });
5763
+ }
4384
5764
  /** List Nango-backed action tools for a workspace connection without executing them. */
4385
5765
  async listNangoTools(options = {}) {
4386
5766
  return this.callMcp("nango_mcp_tools_list", {
@@ -4726,10 +6106,20 @@ export {
4726
6106
  SignalizError,
4727
6107
  Campaigns,
4728
6108
  DEFAULT_SIGNALIZ_CAMPAIGN_BUILDER_DEFAULTS,
6109
+ DEFAULT_CAMPAIGN_BUILDER_BUILT_INS,
6110
+ DEFAULT_CAMPAIGN_BUILDER_APPROVAL_TYPES,
6111
+ CAMPAIGN_BUILDER_OPERATING_PLAYBOOKS,
6112
+ CAMPAIGN_BUILDER_STRATEGY_TEMPLATES,
4729
6113
  CampaignBuilderAgent,
4730
6114
  createCampaignBuilderAgentPlan,
4731
6115
  getMissingCampaignBuilderApprovals,
4732
6116
  createCampaignBuilderApproval,
6117
+ getCampaignBuilderStrategyTemplate,
6118
+ getCampaignBuilderOperatingPlaybook,
6119
+ getCampaignBuilderOperatingPlaybooksForRequest,
6120
+ applyCampaignBuilderStrategyTemplate,
6121
+ createCampaignBuilderAgentRequestTemplate,
6122
+ createCampaignBuilderToolRoute,
4733
6123
  Icps,
4734
6124
  normalizeExecutionReference,
4735
6125
  collectExecutionReferences,