@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.
@@ -782,7 +782,7 @@ var Campaigns = class {
782
782
  async build(request, options) {
783
783
  return this.buildCampaign(request, options);
784
784
  }
785
- /** Scope an agency/client campaign into a markdown brief plus build_campaign dry-run args. */
785
+ /** Scope an agency/customer campaign into a markdown brief plus build_campaign dry-run args. */
786
786
  async scope(request) {
787
787
  return this.scopeCampaign(request);
788
788
  }
@@ -964,7 +964,11 @@ function mapStatus(data) {
964
964
  errors: diagnosticMessages(data.errors),
965
965
  artifactCount: data.artifact_count ?? 0,
966
966
  providerRoute: mapProviderRoute(data),
967
- nextAction: data.next_action ?? "",
967
+ triggerRunId: typeof data.trigger_run_id === "string" ? data.trigger_run_id : null,
968
+ staleRunningPhase: data.stale_running_phase === true,
969
+ phaseAgeSeconds: numberOrNull(data.phase_age_seconds),
970
+ diagnostics: recordOrNull(data.diagnostics) ?? {},
971
+ nextAction: formatNextAction(data.next_action),
968
972
  createdAt: data.created_at,
969
973
  updatedAt: data.updated_at,
970
974
  completedAt: data.completed_at
@@ -1004,6 +1008,19 @@ function diagnosticMessages(value) {
1004
1008
  return typeof record?.message === "string" ? record.message : null;
1005
1009
  }).filter((item) => typeof item === "string" && item.length > 0);
1006
1010
  }
1011
+ function formatNextAction(value) {
1012
+ if (!value) return "";
1013
+ if (typeof value === "string") return value;
1014
+ const record = recordOrNull(value);
1015
+ if (!record) return "";
1016
+ const tool = typeof record.tool === "string" ? record.tool : void 0;
1017
+ const type = typeof record.type === "string" ? record.type : void 0;
1018
+ const reason = typeof record.reason === "string" ? record.reason : void 0;
1019
+ const args = recordOrNull(record.arguments);
1020
+ const argText = args && Object.keys(args).length > 0 ? ` ${JSON.stringify(args)}` : "";
1021
+ const action = tool ? `${tool}${argText}` : type || "";
1022
+ return [action, reason].filter(Boolean).join(" \u2014 ");
1023
+ }
1007
1024
  function booleanOrNull(value) {
1008
1025
  return typeof value === "boolean" ? value : null;
1009
1026
  }
@@ -1044,7 +1061,7 @@ function mapArtifact(a) {
1044
1061
  function mapScope(data) {
1045
1062
  return {
1046
1063
  campaignScopeId: data.campaign_scope_id,
1047
- clientName: data.client_name,
1064
+ accountLabel: data.account_label,
1048
1065
  campaignName: data.campaign_name,
1049
1066
  approach: data.approach,
1050
1067
  approachLabel: data.approach_label,
@@ -1070,8 +1087,8 @@ function scopeArgs(request) {
1070
1087
  const args = {
1071
1088
  prompt: request.prompt
1072
1089
  };
1073
- if (request.clientName) args.client_name = request.clientName;
1074
- if (request.clientContext) args.client_context = request.clientContext;
1090
+ if (request.accountLabel) args.account_label = request.accountLabel;
1091
+ if (request.accountContext) args.account_context = request.accountContext;
1075
1092
  if (request.campaignGoal) args.campaign_goal = request.campaignGoal;
1076
1093
  if (request.targetCount) args.target_count = request.targetCount;
1077
1094
  if (request.destinations) args.destinations = request.destinations;
@@ -1199,22 +1216,557 @@ var DEFAULT_SIGNALIZ_CAMPAIGN_BUILDER_DEFAULTS = {
1199
1216
  approvalRequired: true
1200
1217
  }
1201
1218
  };
1219
+ var DEFAULT_CAMPAIGN_BUILDER_BUILT_INS = [
1220
+ "lead_generation",
1221
+ "email_finding",
1222
+ "email_verification",
1223
+ "signals"
1224
+ ];
1225
+ var CAMPAIGN_BUILDER_OPERATING_PLAYBOOKS = [
1226
+ {
1227
+ slug: "cache-first-large-list",
1228
+ label: "Cache-First Large List",
1229
+ whenToUse: [
1230
+ "The target count is high and reusable workspace lead or cache coverage may exist.",
1231
+ "The deliverable is a verified list or top-up rather than a deeply custom one-off workflow."
1232
+ ],
1233
+ sequence: [
1234
+ "Inventory reusable cache before paid sourcing.",
1235
+ "Report unique emails, role buckets, exclusions, and missing-field counts.",
1236
+ "Use fresh sourcing only for the approved gap.",
1237
+ "Write newly approved source metadata back to memory or cache after review."
1238
+ ],
1239
+ requiredFields: {
1240
+ inventory: ["matching_cached_rows", "unique_cached_emails", "persona_bucket_counts", "exclusions_applied", "missing_field_counts"],
1241
+ finalRows: ["first_name", "last_name", "company_name", "company_domain", "work_email", "email_status", "source_type"]
1242
+ },
1243
+ qualityGates: [
1244
+ "Deduplicate by normalized email before counting final rows.",
1245
+ "Separate cache reuse from fresh sourcing in the build receipt.",
1246
+ "Block export when required identity, company, or email fields are missing."
1247
+ ],
1248
+ activationBoundary: "Cache inventory is read-only. Fresh sourcing, cache writes, export, and sender loading require explicit approval.",
1249
+ memoryKeywords: ["cache inventory", "large list", "unique emails", "top-up sourcing", "source metadata"]
1250
+ },
1251
+ {
1252
+ slug: "net-new-suppressed-list",
1253
+ label: "Net-New Suppressed List",
1254
+ whenToUse: [
1255
+ "A prior campaign, seed list, or exclusion list must be suppressed.",
1256
+ "The operator needs both outreach-facing rows and provenance-rich QA evidence."
1257
+ ],
1258
+ sequence: [
1259
+ "Load suppression baselines before source selection.",
1260
+ "Apply email suppression as a hard gate and domain suppression as required by the brief.",
1261
+ "Keep provenance, source, and validation fields outside the outreach-facing export when needed.",
1262
+ "Run final overlap checks before any delivery action."
1263
+ ],
1264
+ requiredFields: {
1265
+ suppression: ["suppression_source", "prior_email_overlap", "prior_domain_match", "suppression_decision"],
1266
+ finalRows: ["first_name", "last_name", "company_name", "company_domain", "work_email", "email_status", "provenance_id"]
1267
+ },
1268
+ qualityGates: [
1269
+ "Prior email overlap must be zero for rows marked export ready.",
1270
+ "Prior-domain matches must be flagged or blocked according to the approved campaign promise.",
1271
+ "Do not describe rows as fully qualified when the approved path only proves net-new email status."
1272
+ ],
1273
+ activationBoundary: "Suppression review must pass before export, upload, CRM sync, sender load, or sequence launch.",
1274
+ memoryKeywords: ["suppression", "net-new", "prior email overlap", "domain review", "provenance-rich QA"]
1275
+ },
1276
+ {
1277
+ slug: "proof-first-vertical-gate",
1278
+ label: "Proof-First Vertical Gate",
1279
+ whenToUse: [
1280
+ "Wrong-account risk is high or the target category has close lookalike exclusions.",
1281
+ "Account proof is more important than raw lead volume."
1282
+ ],
1283
+ sequence: [
1284
+ "Define positive and negative proof fields before sourcing at scale.",
1285
+ "Qualify companies before contact discovery.",
1286
+ "Qualify contacts before email finding.",
1287
+ "Keep pass, review, and fail rows distinct through delivery review."
1288
+ ],
1289
+ requiredFields: {
1290
+ account: ["company_name", "company_domain", "source_url", "positive_proof", "negative_proof", "fit_score", "account_qualified"],
1291
+ contact: ["person_name", "person_title", "persona_match", "contact_fit_score", "contact_qualified"]
1292
+ },
1293
+ qualityGates: [
1294
+ "Do not spend on contact or email enrichment until the account passes the proof gate.",
1295
+ "Adjacent excluded categories must stay exclusions, not synonyms.",
1296
+ "Contact fit should meet the configured threshold before email finding or copy generation."
1297
+ ],
1298
+ activationBoundary: "Proof gates are required before contact spend, copy, export, or external writes.",
1299
+ memoryKeywords: ["proof gate", "vertical exclusion", "company before contact", "pass review fail", "fit threshold"]
1300
+ },
1301
+ {
1302
+ slug: "signal-led-copy-approval",
1303
+ label: "Signal-Led Copy With Approval",
1304
+ whenToUse: [
1305
+ "Outbound copy should be grounded in company signals, proof fields, or row context.",
1306
+ "Delivery destinations must remain locked after copy generation until review."
1307
+ ],
1308
+ sequence: [
1309
+ "Validate list quality before copy.",
1310
+ "Attach the strongest supported signal and source evidence.",
1311
+ "Generate copy only for fit-qualified and contactable rows.",
1312
+ "Hold every destination behind explicit approval."
1313
+ ],
1314
+ requiredFields: {
1315
+ evidence: ["strongest_signal", "signal_source_url", "why_now", "personalization_basis"],
1316
+ copy: ["subject_line", "opening_line", "email_copy", "copy_ready", "copy_blocker"]
1317
+ },
1318
+ qualityGates: [
1319
+ "Copy cannot invent unsupported pain, claims, numbers, or recent events.",
1320
+ "Weak evidence should route the row to review instead of send-ready copy.",
1321
+ "Destination fields must remain blocked until approval metadata is present."
1322
+ ],
1323
+ activationBoundary: "Copy readiness is not delivery approval. Export, sync, sender load, and launch require a separate human-approved gate.",
1324
+ memoryKeywords: ["company signals", "evidence-fed copy", "why now", "copy blocker", "approval gate"]
1325
+ },
1326
+ {
1327
+ slug: "domain-first-recovery",
1328
+ label: "Domain-First Recovery",
1329
+ whenToUse: [
1330
+ "Strict yield is low and broad people sourcing creates noisy, duplicated, or off-fit rows.",
1331
+ "The account universe should be recovered or expanded before more contact spend."
1332
+ ],
1333
+ sequence: [
1334
+ "Model attrition after an initial sample.",
1335
+ "Source or recover account domains in tight slices.",
1336
+ "Filter domains locally before contact discovery.",
1337
+ "Use accepted domains as the seed for person and email work."
1338
+ ],
1339
+ requiredFields: {
1340
+ domainReview: ["company_domain", "source_slice", "domain_fit_score", "domain_rejection_reason", "accepted_domain"],
1341
+ recovery: ["target_gap", "expected_yield", "accepted_domain_count", "contact_pull_limit"]
1342
+ },
1343
+ qualityGates: [
1344
+ "Do not repeat broad people-with-email sourcing after strict yield proves low.",
1345
+ "Rejected domains should stay suppressed unless the operator changes the ICP.",
1346
+ "Target count means final held rows, not raw sourced rows."
1347
+ ],
1348
+ activationBoundary: "Domain recovery informs sourcing. Contact enrichment, paid qualification, and export still require approved gates.",
1349
+ memoryKeywords: ["domain-first", "yield modeling", "attrition", "accepted domains", "gap fill"]
1350
+ },
1351
+ {
1352
+ slug: "table-workflow-handoff",
1353
+ label: "Table Workflow Handoff",
1354
+ whenToUse: [
1355
+ "The campaign needs connected source, account, people, enrichment, copy, and destination tables.",
1356
+ "A workspace or partner tool owns part of the workflow through MCP, webhook, API, or managed integration."
1357
+ ],
1358
+ sequence: [
1359
+ "Create source/account context before child people rows.",
1360
+ "Carry source context into enrichment, copy, and destination mapping.",
1361
+ "Expose request-ready, result, error, blocker, and export-ready fields for every action.",
1362
+ "Dry-run provider routes and destination writes before activation."
1363
+ ],
1364
+ requiredFields: {
1365
+ workflow: ["source_record_id", "company_context", "request_ready", "provider_status", "error", "export_ready", "export_blocker"],
1366
+ destination: ["destination_type", "destination_status", "approval_status", "approved_by", "approved_at"]
1367
+ },
1368
+ qualityGates: [
1369
+ "Every paid/API action needs visible request readiness and parsed output fields.",
1370
+ "Child people rows must preserve the account context that justified the search.",
1371
+ "Provider route activation must dry-run before any external write."
1372
+ ],
1373
+ activationBoundary: "MCP, webhook, managed integration, and destination routes remain dry-run until the reviewed route and campaign are approved.",
1374
+ memoryKeywords: ["table workflow", "request ready", "provider status", "export blocker", "BYO integration"]
1375
+ }
1376
+ ];
1377
+ var CAMPAIGN_BUILDER_STRATEGY_TEMPLATES = [
1378
+ {
1379
+ slug: "industrial-ot-resilience",
1380
+ label: "Industrial OT Resilience",
1381
+ aliases: ["industrial ot", "ot resilience", "industrial continuity", "industrial-ot-resilience"],
1382
+ defaultTargetCount: 3e3,
1383
+ campaignName: "Industrial OT Resilience Net-New",
1384
+ accountContext: [
1385
+ "Strategy template: Signaliz-only OT, industrial, manufacturing, embedded systems, field service, cyber resilience, and business continuity sourcing.",
1386
+ "Use prior approved campaign output as the email suppression baseline; final files must have zero prior-used email overlap.",
1387
+ "Keep external qualification providers disabled unless the operator explicitly changes the requirement."
1388
+ ].join(" "),
1389
+ icp: {
1390
+ personas: [
1391
+ "OT leader",
1392
+ "Industrial automation leader",
1393
+ "Engineering leader",
1394
+ "IT infrastructure leader",
1395
+ "Reliability or maintenance leader",
1396
+ "Operations leader"
1397
+ ],
1398
+ industries: [
1399
+ "Machinery",
1400
+ "Electrical and electronic manufacturing",
1401
+ "Mechanical or industrial engineering",
1402
+ "Industrial automation",
1403
+ "Semiconductors",
1404
+ "Medical devices",
1405
+ "Oil and energy",
1406
+ "Automotive"
1407
+ ],
1408
+ geographies: ["United States", "United Kingdom", "Canada", "Nordics", "Netherlands"],
1409
+ keywords: [
1410
+ "OT",
1411
+ "ICS",
1412
+ "SCADA",
1413
+ "control systems",
1414
+ "industrial automation",
1415
+ "manufacturing",
1416
+ "plant operations",
1417
+ "reliability",
1418
+ "maintenance",
1419
+ "PLC",
1420
+ "business continuity"
1421
+ ],
1422
+ exclusions: [
1423
+ "sales",
1424
+ "marketing",
1425
+ "recruiting",
1426
+ "HR",
1427
+ "finance",
1428
+ "legal",
1429
+ "customer success",
1430
+ "retail",
1431
+ "restaurants",
1432
+ "staffing",
1433
+ "real estate"
1434
+ ],
1435
+ requireVerifiedEmail: true
1436
+ },
1437
+ builtIns: ["lead_generation", "email_finding", "email_verification", "signals"],
1438
+ preferredProviders: ["signaliz_native"],
1439
+ memoryQueries: [{
1440
+ query: "industrial OT net-new prior email suppression verified manufacturing embedded systems field service cyber resilience business continuity",
1441
+ scopes: ["workspace", "operator_notes"],
1442
+ topK: 10,
1443
+ required: true,
1444
+ rationale: "Load OT sourcing, dedupe, cache metadata, and approval gates before planning net-new work."
1445
+ }],
1446
+ constraints: {
1447
+ deliverabilityNotes: [
1448
+ "Require verified email, valid syntax, first name, last name, company name, and normalized company domain.",
1449
+ "Keep export, upload, sync, send, and replacement actions blocked until explicit approval.",
1450
+ "Treat prior-domain matches as flagged review evidence unless strict domain suppression is explicitly requested."
1451
+ ]
1452
+ },
1453
+ signalizDefaults: {
1454
+ copy: {
1455
+ offerContext: "Do not invent product claims. Anchor messaging only in row-supported OT, industrial, cyber resilience, backup/recovery, or business-continuity context."
1456
+ }
1457
+ },
1458
+ agencyContext: {
1459
+ partnerEcosystem: ["signaliz", "instantly", "nango"]
1460
+ },
1461
+ operatingPlaybookSlugs: ["net-new-suppressed-list", "proof-first-vertical-gate", "signal-led-copy-approval"]
1462
+ },
1463
+ {
1464
+ slug: "non-medical-home-care",
1465
+ label: "Non-Medical Home Care Operations",
1466
+ aliases: ["home care", "non-medical home care", "home-care-operations", "non-medical-home-care"],
1467
+ defaultTargetCount: 3e3,
1468
+ campaignName: "Mature Home Care Agency Operators",
1469
+ accountContext: [
1470
+ "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.",
1471
+ "Use proof before paid enrichment or copy. Preserve pass vs review ICP status because healthcare language often blurs home care and home health."
1472
+ ].join(" "),
1473
+ icp: {
1474
+ personas: [
1475
+ "Owner",
1476
+ "CEO",
1477
+ "COO",
1478
+ "Administrator",
1479
+ "Operations Director",
1480
+ "Scheduler",
1481
+ "Care coordinator leader"
1482
+ ],
1483
+ industries: ["Non-medical home care", "Senior care", "Private duty care", "Home services"],
1484
+ companySizes: ["20+ employees", "600+ billable care hours/week", "1000+ billable care hours/week ideal"],
1485
+ geographies: ["United States"],
1486
+ keywords: [
1487
+ "non-medical home care",
1488
+ "private duty",
1489
+ "caregiver recruiting",
1490
+ "multi-location",
1491
+ "franchise",
1492
+ "scheduler",
1493
+ "billing",
1494
+ "payroll",
1495
+ "EVV",
1496
+ "WellSky",
1497
+ "AxisCare",
1498
+ "CareSmartz360"
1499
+ ],
1500
+ exclusions: [
1501
+ "home health",
1502
+ "skilled nursing",
1503
+ "hospice",
1504
+ "hospital",
1505
+ "clinic",
1506
+ "therapy practice",
1507
+ "very small owner-only shop"
1508
+ ],
1509
+ requireVerifiedEmail: true
1510
+ },
1511
+ builtIns: ["lead_generation", "local_leads", "email_finding", "email_verification", "signals"],
1512
+ preferredProviders: ["signaliz_native", "octave", "clay_webhook", "apify"],
1513
+ memoryQueries: [{
1514
+ query: "mature non-medical home care agencies billable hours franchise caregiver recruiting proof gate qualification export approval",
1515
+ scopes: ["workspace", "operator_notes"],
1516
+ topK: 10,
1517
+ required: true,
1518
+ rationale: "Load home-care ICP gates, source lanes, qualification thresholds, and home-care exclusion logic."
1519
+ }],
1520
+ constraints: {
1521
+ deliverabilityNotes: [
1522
+ "Company proof and strict ICP gate must pass before contact search, email finding, Signaliz signals, or export.",
1523
+ "Home health is an exclusion signal, not a synonym for home care."
1524
+ ]
1525
+ },
1526
+ signalizDefaults: {
1527
+ copy: {
1528
+ offerContext: "Use angles around after-hours shift recovery, billing/payroll exceptions, multi-location consistency, and caregiver retention only when supported by evidence."
1529
+ }
1530
+ },
1531
+ agencyContext: {
1532
+ partnerEcosystem: ["clay", "octave", "signaliz", "instantly", "nango"]
1533
+ },
1534
+ operatingPlaybookSlugs: ["proof-first-vertical-gate", "domain-first-recovery", "table-workflow-handoff"]
1535
+ },
1536
+ {
1537
+ slug: "agency-founder-led",
1538
+ label: "Founder-Led Agency Services",
1539
+ aliases: ["agency founder", "founder-led agency", "agency-founder-led"],
1540
+ defaultTargetCount: 3e3,
1541
+ campaignName: "Founder-Led Agency Executive Campaign",
1542
+ accountContext: [
1543
+ "Strategy template: agency founder, owner, CEO, and executive sourcing across marketing services, creative, web, PR, ecommerce, paid media, SEO, content, and specialist digital agencies.",
1544
+ "Use suppression files, company-domain pool review, people/email verification queues, and final approval gates before any delivery action."
1545
+ ].join(" "),
1546
+ icp: {
1547
+ personas: ["Founder", "Owner", "CEO", "Managing Partner", "President", "Agency Executive"],
1548
+ industries: [
1549
+ "Marketing services",
1550
+ "Advertising services",
1551
+ "Digital marketing agency",
1552
+ "Creative agency",
1553
+ "PR and communications",
1554
+ "Ecommerce agency",
1555
+ "Paid media agency",
1556
+ "SEO agency",
1557
+ "Content agency"
1558
+ ],
1559
+ companySizes: ["11-50", "25-150", "51-200"],
1560
+ geographies: ["United States"],
1561
+ keywords: [
1562
+ "agency founder",
1563
+ "performance marketing",
1564
+ "paid media",
1565
+ "SEO",
1566
+ "content",
1567
+ "creative",
1568
+ "web design",
1569
+ "brand agency",
1570
+ "PR communications",
1571
+ "Shopify",
1572
+ "Klaviyo"
1573
+ ],
1574
+ exclusions: ["enterprise holding company", "staffing", "recruiting", "software-only vendor", "freelancer-only profile"],
1575
+ requireVerifiedEmail: true
1576
+ },
1577
+ builtIns: ["lead_generation", "email_finding", "email_verification", "signals"],
1578
+ preferredProviders: ["signaliz_native", "octave"],
1579
+ memoryQueries: [{
1580
+ query: "agency founder owner CEO marketing services suppression domain pool email verification final approval gate",
1581
+ scopes: ["workspace", "operator_notes"],
1582
+ topK: 10,
1583
+ required: true,
1584
+ rationale: "Load agency-segment sourcing lanes, suppression rules, and verification workflow lessons."
1585
+ }],
1586
+ constraints: {
1587
+ deliverabilityNotes: [
1588
+ "Keep email and domain suppression visible in the plan.",
1589
+ "Do not export or send until the final verified file and suppression checks are approved."
1590
+ ]
1591
+ },
1592
+ agencyContext: {
1593
+ partnerEcosystem: ["signaliz", "octave", "instantly", "nango"]
1594
+ },
1595
+ operatingPlaybookSlugs: ["net-new-suppressed-list", "signal-led-copy-approval", "table-workflow-handoff"]
1596
+ },
1597
+ {
1598
+ slug: "cloud-infrastructure-displacement",
1599
+ label: "Cloud Infrastructure Displacement",
1600
+ aliases: ["cloud displacement", "private cloud displacement", "cloud infrastructure", "cloud-infrastructure-displacement"],
1601
+ defaultTargetCount: 3e3,
1602
+ campaignName: "Cloud Infrastructure Displacement Campaign",
1603
+ accountContext: [
1604
+ "Strategy template: managed infrastructure, private cloud, disaster recovery, colocation, and VMware/Broadcom displacement motions.",
1605
+ "The spend-efficient ladder is Signaliz company search, Octave company qualification, Signaliz people search, Octave person qualification, then Signaliz email finding and verification."
1606
+ ].join(" "),
1607
+ icp: {
1608
+ personas: [
1609
+ "CTO",
1610
+ "CIO",
1611
+ "CISO",
1612
+ "CFO tied to cloud spend",
1613
+ "VP Engineering",
1614
+ "VP Infrastructure",
1615
+ "VP Cloud",
1616
+ "Head of Platform",
1617
+ "Director IT",
1618
+ "Cloud Architect",
1619
+ "Infrastructure Architect"
1620
+ ],
1621
+ industries: [
1622
+ "SaaS",
1623
+ "Software",
1624
+ "Cybersecurity",
1625
+ "Fintech",
1626
+ "Healthcare technology",
1627
+ "Compliance and GRC",
1628
+ "DevOps",
1629
+ "Infrastructure",
1630
+ "Observability"
1631
+ ],
1632
+ companySizes: ["$10M-$500M revenue", "50-1500 employees"],
1633
+ geographies: ["United States"],
1634
+ keywords: [
1635
+ "VMware Broadcom",
1636
+ "VxRail",
1637
+ "cloud cost pressure",
1638
+ "private cloud",
1639
+ "Proxmox",
1640
+ "Hyper-V",
1641
+ "managed infrastructure",
1642
+ "DRaaS",
1643
+ "colocation",
1644
+ "uptime",
1645
+ "reliability"
1646
+ ],
1647
+ exclusions: [
1648
+ "MSP competitor",
1649
+ "hosting provider",
1650
+ "data center competitor",
1651
+ "staffing",
1652
+ "recruiting",
1653
+ "international-only",
1654
+ "procurement-only",
1655
+ "AI GPU-heavy infrastructure"
1656
+ ],
1657
+ requireVerifiedEmail: true
1658
+ },
1659
+ builtIns: ["lead_generation", "email_finding", "email_verification", "signals"],
1660
+ preferredProviders: ["signaliz_native", "octave"],
1661
+ memoryQueries: [{
1662
+ query: "cloud hosting infrastructure VMware Broadcom qualification verified email persona trigger SKU mapping",
1663
+ scopes: ["workspace", "operator_notes"],
1664
+ topK: 10,
1665
+ required: true,
1666
+ rationale: "Load cloud-infrastructure qualification order, persona clusters, trigger/SKU mapping, and verified-list QA rules."
1667
+ }],
1668
+ constraints: {
1669
+ deliverabilityNotes: [
1670
+ "Qualify accounts and people before email verification.",
1671
+ "If signal enrichment is deferred or unavailable, state it plainly instead of inventing evidence."
1672
+ ]
1673
+ },
1674
+ signalizDefaults: {
1675
+ copy: {
1676
+ 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."
1677
+ }
1678
+ },
1679
+ agencyContext: {
1680
+ partnerEcosystem: ["signaliz", "octave", "instantly", "nango"]
1681
+ },
1682
+ operatingPlaybookSlugs: ["proof-first-vertical-gate", "domain-first-recovery", "signal-led-copy-approval"]
1683
+ }
1684
+ ];
1202
1685
  var CampaignBuilderAgent = class {
1203
1686
  constructor(client) {
1204
1687
  this.client = client;
1205
1688
  }
1206
1689
  async createPlan(request, options = {}) {
1690
+ const resolvedRequest = applyCampaignBuilderStrategyTemplate(request);
1207
1691
  const warnings = [];
1208
- const workspaceContext = request.workspaceContext ?? await this.getWorkspaceContext(warnings);
1209
- const scopeResult = options.scopeCampaign === false ? void 0 : await this.scopeCampaign(request, warnings);
1692
+ const workspaceContext = resolvedRequest.workspaceContext ?? await this.getWorkspaceContext(warnings);
1693
+ const scopeResult = options.scopeCampaign === false ? void 0 : await this.scopeCampaign(resolvedRequest, warnings);
1210
1694
  if (options.discoverCapabilities !== false) {
1211
- await this.discoverPlannedRoutes(request, warnings);
1695
+ await this.discoverPlannedRoutes(resolvedRequest, warnings);
1212
1696
  }
1213
- return createCampaignBuilderAgentPlan(request, {
1697
+ const plan = createCampaignBuilderAgentPlan(resolvedRequest, {
1214
1698
  workspaceContext,
1215
1699
  scopeBuildArgs: asRecord(scopeResult?.build_campaign_args ?? scopeResult?.buildCampaignArgs),
1216
1700
  warnings
1217
1701
  });
1702
+ if (options.includeStrategyMemoryStatus !== false) {
1703
+ await this.attachStrategyMemoryStatus(plan, warnings);
1704
+ }
1705
+ if (options.includeKernelPlan !== false) {
1706
+ await this.attachKernelCampaignBuildPlan(plan, warnings);
1707
+ }
1708
+ if (options.includeDeliveryRisk !== false) {
1709
+ await this.attachDeliveryRiskPreflight(plan, warnings);
1710
+ }
1711
+ return plan;
1712
+ }
1713
+ async commitPlan(plan, options = {}) {
1714
+ const writeMode = options.confirm === true && options.dryRun === false;
1715
+ if (writeMode && !options.approvedBy) {
1716
+ throw new Error("Campaign builder plan commit requires approvedBy before writing state");
1717
+ }
1718
+ const plannerStep = plan.mcpFlow.find((step) => step.id === "agency-campaign-build-plan");
1719
+ const plannerArgs = asRecord(plannerStep?.arguments);
1720
+ const commitArgs = compact({
1721
+ campaign_id: plan.buildRequest.gtmCampaignId,
1722
+ name: plan.campaignName,
1723
+ campaign_brief: plan.buildRequest.prompt || plan.goal,
1724
+ target_icp: plan.buildRequest.icp ? buildGtmTargetIcpContext(plan.buildRequest.icp) : void 0,
1725
+ lead_count: plan.targetCount,
1726
+ layers: plannerArgs.layers,
1727
+ preferred_providers: plannerArgs.preferred_providers,
1728
+ plan_snapshot: Object.keys(asRecord(plan.kernelPlan)).length > 0 ? plan.kernelPlan : buildFallbackPlanSnapshot(plan),
1729
+ send_config: plan.buildRequest.delivery ? {
1730
+ delivery: plan.buildRequest.delivery,
1731
+ approval_required: true
1732
+ } : void 0,
1733
+ brain_config: compact({
1734
+ campaign_builder_agent_v1: {
1735
+ plan_id: plan.planId,
1736
+ kernel_plan_attached: Object.keys(asRecord(plan.kernelPlan)).length > 0,
1737
+ approval_ids: plan.approvals.map((approval) => approval.id)
1738
+ },
1739
+ brain_defaults: plan.buildRequest.brainDefaults,
1740
+ brain_preflight: plan.buildRequest.brainPreflight,
1741
+ delivery_risk_preflight: plan.buildRequest.deliveryRisk,
1742
+ delivery_risk: plan.buildRequest.deliveryRisk
1743
+ }),
1744
+ metadata: {
1745
+ campaign_builder_agent_v1: {
1746
+ plan_id: plan.planId,
1747
+ source: "campaign-builder-agent",
1748
+ approval_required: plan.approvals.some((approval) => approval.blocking),
1749
+ approval_ids: plan.approvals.map((approval) => approval.id),
1750
+ estimated_credits: plan.estimatedCredits
1751
+ },
1752
+ brain_delivery_risk_preflight: plan.buildRequest.deliveryRisk,
1753
+ delivery_risk: plan.buildRequest.deliveryRisk
1754
+ },
1755
+ approval_required: plan.approvals.some((approval) => approval.blocking),
1756
+ actor_type: "agent",
1757
+ actor_id: options.approvedBy,
1758
+ rationale: options.rationale || "Committed a reviewed strategy-template campaign-builder plan before execution.",
1759
+ idempotency_key: options.idempotencyKey,
1760
+ dry_run: !writeMode,
1761
+ confirm: writeMode
1762
+ });
1763
+ const data = asRecord(await this.callMcp("gtm_campaign_build_plan_commit", commitArgs));
1764
+ const result = mapPlanCommitResult(data);
1765
+ if (result.wroteState && result.campaignId) {
1766
+ plan.buildRequest.gtmCampaignId = result.campaignId;
1767
+ refreshBuildStepArguments(plan);
1768
+ }
1769
+ return result;
1218
1770
  }
1219
1771
  async dryRunPlan(plan, options) {
1220
1772
  let args = buildCampaignArgs({
@@ -1249,6 +1801,15 @@ var CampaignBuilderAgent = class {
1249
1801
  if (missing.length > 0) {
1250
1802
  throw new Error(`Campaign builder approval is incomplete: ${missing.map((a) => a.label).join(", ")}`);
1251
1803
  }
1804
+ if (options?.commitBeforeLaunch && !plan.buildRequest.gtmCampaignId) {
1805
+ await this.commitPlan(plan, {
1806
+ confirm: true,
1807
+ dryRun: false,
1808
+ approvedBy: approval.approvedBy,
1809
+ idempotencyKey: options.idempotencyKey ? `${options.idempotencyKey}:plan-commit` : void 0,
1810
+ rationale: "Committed reviewed campaign-builder plan immediately before approved launch."
1811
+ });
1812
+ }
1252
1813
  let args = buildCampaignArgs({
1253
1814
  ...plan.buildRequest,
1254
1815
  dryRun: false,
@@ -1295,8 +1856,8 @@ var CampaignBuilderAgent = class {
1295
1856
  try {
1296
1857
  return await this.callMcp("scope_campaign", {
1297
1858
  prompt: request.goal,
1298
- client_name: request.clientName,
1299
- client_context: request.clientContext,
1859
+ account_label: campaignBuilderAccountLabel(request),
1860
+ account_context: campaignBuilderAccountContext(request),
1300
1861
  campaign_goal: request.goal,
1301
1862
  target_count: request.targetCount,
1302
1863
  approval_policy: request.approvalPolicy?.requireHumanApproval ? "human_required" : "standard"
@@ -1321,25 +1882,70 @@ var CampaignBuilderAgent = class {
1321
1882
  }
1322
1883
  }
1323
1884
  }
1885
+ async attachStrategyMemoryStatus(plan, warnings) {
1886
+ const statusStep = plan.mcpFlow.find((step) => step.id === "strategy-memory-status");
1887
+ if (!statusStep) return;
1888
+ try {
1889
+ const status = asRecord(await this.callMcp("gtm_campaign_strategy_memory_status", asRecord(statusStep.arguments)));
1890
+ plan.strategyMemoryStatus = status;
1891
+ const blockers = arrayOfStrings(status.blockers) ?? [];
1892
+ if (status.ready === false || blockers.length > 0) {
1893
+ warnings.push(`Strategy memory readiness is incomplete: ${blockers.join("; ") || "missing required strategy or workflow memory"}`);
1894
+ }
1895
+ } catch (error) {
1896
+ warnings.push(`Strategy memory readiness check failed: ${errorMessage(error)}`);
1897
+ }
1898
+ }
1899
+ async attachKernelCampaignBuildPlan(plan, warnings) {
1900
+ const plannerStep = plan.mcpFlow.find((step) => step.id === "agency-campaign-build-plan");
1901
+ if (!plannerStep) return;
1902
+ try {
1903
+ const kernelPlan = await this.callMcp("gtm_campaign_build_plan", asRecord(plannerStep.arguments));
1904
+ plan.kernelPlan = asRecord(kernelPlan);
1905
+ const brainDefaults = asRecord(plan.kernelPlan.brain_defaults ?? plan.kernelPlan.brainDefaults);
1906
+ if (Object.keys(brainDefaults).length > 0 && Object.keys(asRecord(plan.buildRequest.brainDefaults)).length === 0) {
1907
+ plan.buildRequest.brainDefaults = brainDefaults;
1908
+ refreshBuildStepArguments(plan);
1909
+ }
1910
+ } catch (error) {
1911
+ warnings.push(`GTM Kernel campaign build plan failed: ${errorMessage(error)}`);
1912
+ }
1913
+ }
1914
+ async attachDeliveryRiskPreflight(plan, warnings) {
1915
+ if (Object.keys(asRecord(plan.buildRequest.deliveryRisk)).length > 0) return;
1916
+ const riskStep = plan.mcpFlow.find((step) => step.tool === "gtm_brain_delivery_risk");
1917
+ if (!riskStep) return;
1918
+ try {
1919
+ const deliveryRisk = asRecord(await this.callMcp("gtm_brain_delivery_risk", asRecord(riskStep.arguments)));
1920
+ if (Object.keys(deliveryRisk).length > 0) {
1921
+ plan.buildRequest.deliveryRisk = deliveryRisk;
1922
+ refreshBuildStepArguments(plan);
1923
+ }
1924
+ } catch (error) {
1925
+ warnings.push(`GTM Brain delivery risk preflight failed: ${errorMessage(error)}`);
1926
+ }
1927
+ }
1324
1928
  async callMcp(tool, args) {
1325
1929
  return this.client.mcp("tools/call", { name: tool, arguments: compact(args) });
1326
1930
  }
1327
1931
  };
1328
1932
  function createCampaignBuilderAgentPlan(request, context = {}) {
1329
- const defaults = mergeDefaults(request.signalizDefaults);
1330
- const targetCount = request.targetCount ?? numberOrUndefined2(context.scopeBuildArgs?.target_count) ?? 100;
1331
- const campaignName = request.campaignName ?? stringValue(context.scopeBuildArgs?.name) ?? titleFromGoal(request.goal);
1332
- const workspaceContext = context.workspaceContext ?? request.workspaceContext ?? {};
1333
- const memory = normalizeMemory(request);
1334
- const routes = normalizeRoutes(request);
1335
- const estimatedCredits = estimateCredits(request, defaults, targetCount);
1336
- const buildRequest = createBuildRequest(request, defaults, targetCount, campaignName, context.scopeBuildArgs, routes, memory, context.scopeBrainPreflight);
1933
+ const resolvedRequest = applyCampaignBuilderStrategyTemplate(request);
1934
+ const defaults = mergeDefaults(resolvedRequest.signalizDefaults);
1935
+ const targetCount = resolvedRequest.targetCount ?? numberOrUndefined2(context.scopeBuildArgs?.target_count) ?? 100;
1936
+ const campaignName = resolvedRequest.campaignName ?? stringValue(context.scopeBuildArgs?.name) ?? titleFromGoal(resolvedRequest.goal);
1937
+ const workspaceContext = context.workspaceContext ?? resolvedRequest.workspaceContext ?? {};
1938
+ const memory = normalizeMemory(resolvedRequest);
1939
+ const routes = normalizeRoutes(resolvedRequest);
1940
+ const operatingPlaybooks = getCampaignBuilderOperatingPlaybooksForRequest(resolvedRequest);
1941
+ const estimatedCredits = estimateCredits(resolvedRequest, defaults, targetCount);
1942
+ const buildRequest = createBuildRequest(resolvedRequest, defaults, targetCount, campaignName, context.scopeBuildArgs, routes, memory, context.scopeBrainPreflight);
1337
1943
  const brainPreflight = asRecord(buildRequest.brainPreflight);
1338
- const approvals = deriveApprovals(request, routes, memory, estimatedCredits, defaults.delivery?.approvalRequired !== false);
1944
+ const approvals = deriveApprovals(resolvedRequest, routes, memory, estimatedCredits, defaults.delivery?.approvalRequired !== false);
1339
1945
  return {
1340
- planId: `cbp_${hashString(JSON.stringify({ goal: request.goal, campaignName, targetCount, routes }))}`,
1946
+ planId: `cbp_${hashString(JSON.stringify({ goal: resolvedRequest.goal, campaignName, targetCount, routes }))}`,
1341
1947
  campaignName,
1342
- goal: request.goal,
1948
+ goal: resolvedRequest.goal,
1343
1949
  targetCount,
1344
1950
  workspaceContext,
1345
1951
  memory,
@@ -1352,7 +1958,8 @@ function createCampaignBuilderAgentPlan(request, context = {}) {
1352
1958
  approvals,
1353
1959
  buildRequest,
1354
1960
  brainPreflight,
1355
- mcpFlow: createMcpFlow(request, buildRequest, routes, memory, approvals),
1961
+ operatingPlaybooks,
1962
+ mcpFlow: createMcpFlow(resolvedRequest, buildRequest, routes, memory, approvals),
1356
1963
  estimatedCredits,
1357
1964
  warnings: context.warnings ?? []
1358
1965
  };
@@ -1373,6 +1980,155 @@ function getMissingCampaignBuilderApprovals(plan, approval) {
1373
1980
  return false;
1374
1981
  });
1375
1982
  }
1983
+ function getCampaignBuilderStrategyTemplate(value) {
1984
+ const normalized = normalizeTemplateKey(value);
1985
+ if (!normalized) return void 0;
1986
+ return CAMPAIGN_BUILDER_STRATEGY_TEMPLATES.find(
1987
+ (template) => template.slug === normalized || template.aliases.some((alias) => normalizeTemplateKey(alias) === normalized)
1988
+ );
1989
+ }
1990
+ function getCampaignBuilderOperatingPlaybook(value) {
1991
+ const normalized = normalizeTemplateKey(value);
1992
+ if (!normalized) return void 0;
1993
+ return CAMPAIGN_BUILDER_OPERATING_PLAYBOOKS.find((playbook) => playbook.slug === normalized);
1994
+ }
1995
+ function getCampaignBuilderOperatingPlaybooksForRequest(request) {
1996
+ const template = getCampaignBuilderStrategyTemplate(request.strategyTemplate);
1997
+ const slugs = uniqueStrings([
1998
+ ...template?.operatingPlaybookSlugs ?? [],
1999
+ ...request.operatingPlaybooks ?? []
2000
+ ]);
2001
+ return slugs.map(getCampaignBuilderOperatingPlaybook).filter((playbook) => Boolean(playbook));
2002
+ }
2003
+ function applyCampaignBuilderStrategyTemplate(request) {
2004
+ const template = getCampaignBuilderStrategyTemplate(request.strategyTemplate);
2005
+ if (!template) return request;
2006
+ return {
2007
+ ...request,
2008
+ strategyTemplate: template.slug,
2009
+ campaignName: request.campaignName ?? template.campaignName,
2010
+ accountContext: mergeText(template.accountContext, campaignBuilderAccountContext(request)),
2011
+ targetCount: request.targetCount ?? template.defaultTargetCount,
2012
+ icp: mergeIcp(template.icp, request.icp),
2013
+ builtIns: request.builtIns ?? template.builtIns,
2014
+ operatingPlaybooks: uniqueStrings([
2015
+ ...template.operatingPlaybookSlugs,
2016
+ ...request.operatingPlaybooks ?? []
2017
+ ]),
2018
+ preferredProviders: uniqueStrings([
2019
+ ...template.preferredProviders,
2020
+ ...request.preferredProviders ?? []
2021
+ ]),
2022
+ memory: mergeMemoryPlan({
2023
+ enabled: true,
2024
+ useWorkspaceHistory: true,
2025
+ useNetworkPatterns: request.memory?.useNetworkPatterns,
2026
+ privacyMode: request.memory?.privacyMode,
2027
+ queries: template.memoryQueries
2028
+ }, request.memory),
2029
+ constraints: mergeConstraints(template.constraints, request.constraints),
2030
+ signalizDefaults: mergeSignalizDefaultOverrides(template.signalizDefaults, request.signalizDefaults),
2031
+ agencyContext: mergeAgencyContext(template.agencyContext, request.agencyContext)
2032
+ };
2033
+ }
2034
+ function normalizeTemplateKey(value) {
2035
+ return String(value || "").trim().toLowerCase().replace(/[_\s]+/g, "-");
2036
+ }
2037
+ function mergeText(base, override) {
2038
+ if (base && override && !base.includes(override)) return `${base}
2039
+ ${override}`;
2040
+ return override ?? base;
2041
+ }
2042
+ function mergeIcp(base, override) {
2043
+ if (!base) return override;
2044
+ if (!override) return base;
2045
+ return {
2046
+ ...base,
2047
+ ...override,
2048
+ personas: uniqueStrings([...base.personas ?? [], ...override.personas ?? []]),
2049
+ industries: uniqueStrings([...base.industries ?? [], ...override.industries ?? []]),
2050
+ companySizes: uniqueStrings([...base.companySizes ?? [], ...override.companySizes ?? []]),
2051
+ geographies: uniqueStrings([...base.geographies ?? [], ...override.geographies ?? []]),
2052
+ keywords: uniqueStrings([...base.keywords ?? [], ...override.keywords ?? []]),
2053
+ exclusions: uniqueStrings([...base.exclusions ?? [], ...override.exclusions ?? []]),
2054
+ requireVerifiedEmail: override.requireVerifiedEmail ?? base.requireVerifiedEmail
2055
+ };
2056
+ }
2057
+ function mergeMemoryPlan(base, override) {
2058
+ const queries = dedupeMemoryQueries([...base.queries ?? [], ...override?.queries ?? []]);
2059
+ return {
2060
+ ...base,
2061
+ ...override,
2062
+ queries: queries.length > 0 ? queries : void 0,
2063
+ enabled: override?.enabled ?? base.enabled,
2064
+ useWorkspaceHistory: override?.useWorkspaceHistory ?? base.useWorkspaceHistory,
2065
+ useNetworkPatterns: override?.useNetworkPatterns ?? base.useNetworkPatterns,
2066
+ privacyMode: override?.privacyMode ?? base.privacyMode
2067
+ };
2068
+ }
2069
+ function dedupeMemoryQueries(queries) {
2070
+ const seen = /* @__PURE__ */ new Set();
2071
+ return queries.filter((query) => {
2072
+ const key = query.query.trim().toLowerCase();
2073
+ if (!key || seen.has(key)) return false;
2074
+ seen.add(key);
2075
+ return true;
2076
+ });
2077
+ }
2078
+ function mergeConstraints(base, override) {
2079
+ if (!base) return override;
2080
+ if (!override) return base;
2081
+ return {
2082
+ ...base,
2083
+ ...override,
2084
+ geographies: uniqueStrings([...base.geographies ?? [], ...override.geographies ?? []]),
2085
+ exclusions: uniqueStrings([...base.exclusions ?? [], ...override.exclusions ?? []]),
2086
+ deliverabilityNotes: uniqueStrings([...base.deliverabilityNotes ?? [], ...override.deliverabilityNotes ?? []]),
2087
+ maxDailySends: override.maxDailySends ?? base.maxDailySends
2088
+ };
2089
+ }
2090
+ function mergeSignalizDefaultOverrides(base, override) {
2091
+ if (!base) return override;
2092
+ if (!override) return base;
2093
+ return {
2094
+ ...base,
2095
+ ...override,
2096
+ signals: { ...base.signals, ...override.signals },
2097
+ qualification: { ...base.qualification, ...override.qualification },
2098
+ copy: { ...base.copy, ...override.copy },
2099
+ delivery: { ...base.delivery, ...override.delivery }
2100
+ };
2101
+ }
2102
+ function mergeAgencyContext(base, override) {
2103
+ if (!base) return override;
2104
+ if (!override) return base;
2105
+ return {
2106
+ ...base,
2107
+ ...override,
2108
+ partnerEcosystem: uniqueStrings([...base.partnerEcosystem ?? [], ...override.partnerEcosystem ?? []]),
2109
+ strategyModel: override.strategyModel ?? base.strategyModel,
2110
+ includeStrategyPatterns: override.includeStrategyPatterns ?? base.includeStrategyPatterns,
2111
+ includeWorkflowPatterns: override.includeWorkflowPatterns ?? base.includeWorkflowPatterns,
2112
+ includeClayPatterns: override.includeClayPatterns ?? base.includeClayPatterns,
2113
+ includeNangoCatalog: override.includeNangoCatalog ?? base.includeNangoCatalog,
2114
+ revenueMotion: override.revenueMotion ?? base.revenueMotion
2115
+ };
2116
+ }
2117
+ function campaignBuilderStrategyModel(agencyContext) {
2118
+ return agencyContext?.strategyModel ?? "strategy_template";
2119
+ }
2120
+ function campaignBuilderStrategyPatternsEnabled(agencyContext) {
2121
+ return agencyContext?.includeStrategyPatterns ?? true;
2122
+ }
2123
+ function campaignBuilderWorkflowPatternsEnabled(agencyContext) {
2124
+ return agencyContext?.includeWorkflowPatterns ?? agencyContext?.includeClayPatterns ?? true;
2125
+ }
2126
+ function campaignBuilderAccountLabel(request) {
2127
+ return request.accountLabel;
2128
+ }
2129
+ function campaignBuilderAccountContext(request) {
2130
+ return request.accountContext;
2131
+ }
1376
2132
  function mergeDefaults(overrides) {
1377
2133
  return {
1378
2134
  ...DEFAULT_SIGNALIZ_CAMPAIGN_BUILDER_DEFAULTS,
@@ -1385,12 +2141,9 @@ function mergeDefaults(overrides) {
1385
2141
  }
1386
2142
  function normalizeMemory(request) {
1387
2143
  const configured = request.memory ?? {};
1388
- const queries = configured.queries && configured.queries.length > 0 ? configured.queries : [{
1389
- query: request.goal,
1390
- scopes: ["workspace", configured.useNetworkPatterns ? "network_patterns" : "operator_notes"],
1391
- topK: 8,
1392
- rationale: "Seed the campaign plan with prior ICP, angle, source, and reply-performance patterns."
1393
- }];
2144
+ const defaultQueries = defaultAgencyMemoryQueries(request, configured);
2145
+ const configuredQueries = configured.queries ?? [];
2146
+ const queries = configuredQueries.length > 0 ? request.strategyTemplate ? dedupeMemoryQueries([...configuredQueries, ...defaultQueries]) : configuredQueries : defaultQueries;
1394
2147
  return {
1395
2148
  enabled: configured.enabled !== false,
1396
2149
  queries,
@@ -1399,40 +2152,130 @@ function normalizeMemory(request) {
1399
2152
  privacyMode: configured.privacyMode ?? (configured.useNetworkPatterns ? "anonymized_patterns" : "workspace_only")
1400
2153
  };
1401
2154
  }
2155
+ function defaultAgencyMemoryQueries(request, configured) {
2156
+ const operatingPlaybookTerms = getCampaignBuilderOperatingPlaybooksForRequest(request).flatMap((playbook) => [playbook.label, ...playbook.memoryKeywords]).join(" ");
2157
+ const queries = [{
2158
+ query: request.goal,
2159
+ scopes: ["workspace", configured.useNetworkPatterns ? "network_patterns" : "operator_notes"],
2160
+ topK: 8,
2161
+ rationale: "Seed the campaign plan with prior ICP, angle, source, and reply-performance patterns."
2162
+ }];
2163
+ if (campaignBuilderStrategyModel(request.agencyContext) !== "custom" && campaignBuilderStrategyPatternsEnabled(request.agencyContext)) {
2164
+ queries.push({
2165
+ query: [
2166
+ "Private campaign strategy pattern library prior campaign casebook",
2167
+ campaignBuilderAccountLabel(request),
2168
+ operatingPlaybookTerms,
2169
+ request.goal
2170
+ ].filter(Boolean).join(" "),
2171
+ scopes: ["workspace", "operator_notes"],
2172
+ topK: 8,
2173
+ required: true,
2174
+ rationale: "Anchor the plan in private strategy learnings from prior industrial, healthcare, agency-services, infrastructure, recruiting, media, and integration builds."
2175
+ });
2176
+ }
2177
+ if (campaignBuilderWorkflowPatternsEnabled(request.agencyContext)) {
2178
+ queries.push({
2179
+ query: [
2180
+ "Workflow table architecture enrichment qualification copy export gates",
2181
+ request.goal
2182
+ ].filter(Boolean).join(" "),
2183
+ scopes: ["workspace", "operator_notes"],
2184
+ topK: 6,
2185
+ rationale: "Pull workflow patterns for source tables, enrichment order, qualification gates, and handoff controls."
2186
+ });
2187
+ }
2188
+ return queries;
2189
+ }
1402
2190
  function normalizeRoutes(request) {
1403
- const routes = [
1404
- {
1405
- id: "signaliz-source",
2191
+ const routes = builtInRoutesFor(request);
2192
+ routes.push(...routesFromCustomerTools(request.customerTools ?? []));
2193
+ routes.push(...request.integrations ?? []);
2194
+ return routes.map((route, index) => ({
2195
+ ...route,
2196
+ id: route.id ?? `${route.provider}-${route.layer}-${index + 1}`,
2197
+ mode: route.mode ?? "if_available"
2198
+ }));
2199
+ }
2200
+ function builtInRoutesFor(request) {
2201
+ const builtIns = new Set(normalizeBuiltIns(request));
2202
+ const routes = [];
2203
+ if (builtIns.has("lead_generation")) {
2204
+ routes.push({
2205
+ id: "signaliz-lead-generation",
1406
2206
  layer: "source",
2207
+ gtmLayers: ["find_company", "find_people", "lead_generation"],
1407
2208
  provider: "signaliz",
1408
2209
  mode: "required",
1409
2210
  toolName: "generate_leads",
1410
2211
  rationale: "Use Signaliz fresh workspace acquisition as the default source of truth."
1411
- },
1412
- {
1413
- id: "signaliz-verify",
1414
- layer: "qualification",
2212
+ });
2213
+ }
2214
+ if (builtIns.has("local_leads")) {
2215
+ routes.push({
2216
+ id: "signaliz-local-leads",
2217
+ layer: "source",
2218
+ gtmLayer: "local_leads",
2219
+ provider: "signaliz",
2220
+ mode: "if_available",
2221
+ toolName: "generate_local_leads",
2222
+ rationale: "Use Signaliz local-leads sourcing for geography-bound local business campaigns."
2223
+ });
2224
+ }
2225
+ if (builtIns.has("email_finding")) {
2226
+ routes.push({
2227
+ id: "signaliz-email-finding",
2228
+ layer: "enrichment",
2229
+ gtmLayer: "email_finding",
1415
2230
  provider: "signaliz",
1416
2231
  mode: "required",
1417
2232
  toolName: "find_and_verify_emails",
2233
+ rationale: "Find contact emails before verification and campaign handoff."
2234
+ });
2235
+ }
2236
+ if (builtIns.has("email_verification")) {
2237
+ routes.push({
2238
+ id: "signaliz-email-verification",
2239
+ layer: "qualification",
2240
+ gtmLayer: "email_verification",
2241
+ provider: "signaliz",
2242
+ mode: "required",
2243
+ toolName: "verify_emails",
1418
2244
  rationale: "Require verified contactability before sequence delivery."
1419
- },
1420
- {
2245
+ });
2246
+ }
2247
+ if (builtIns.has("signals")) {
2248
+ routes.push({
1421
2249
  id: "signaliz-signals",
1422
2250
  layer: "enrichment",
2251
+ gtmLayer: "company_enrichment",
1423
2252
  provider: "signaliz",
1424
2253
  mode: "if_available",
1425
2254
  toolName: "enrich_company_signals",
1426
2255
  rationale: "Attach current buying signals and evidence for qualification and copy."
1427
- }
1428
- ];
1429
- routes.push(...routesFromCustomerTools(request.customerTools ?? []));
1430
- routes.push(...request.integrations ?? []);
1431
- return routes.map((route, index) => ({
1432
- ...route,
1433
- id: route.id ?? `${route.provider}-${route.layer}-${index + 1}`,
1434
- mode: route.mode ?? "if_available"
1435
- }));
2256
+ });
2257
+ }
2258
+ return routes;
2259
+ }
2260
+ function normalizeBuiltIns(request) {
2261
+ const configured = request.builtIns !== void 0 ? request.builtIns : DEFAULT_CAMPAIGN_BUILDER_BUILT_INS;
2262
+ const builtIns = new Set(configured);
2263
+ if (request.builtIns === void 0 && looksLikeLocalLeadCampaign(request)) {
2264
+ builtIns.add("local_leads");
2265
+ }
2266
+ return [...builtIns].filter(isCampaignBuilderBuiltInTool);
2267
+ }
2268
+ function isCampaignBuilderBuiltInTool(value) {
2269
+ return ["lead_generation", "local_leads", "email_finding", "email_verification", "signals"].includes(String(value));
2270
+ }
2271
+ function looksLikeLocalLeadCampaign(request) {
2272
+ const text = [
2273
+ request.goal,
2274
+ campaignBuilderAccountContext(request),
2275
+ ...request.icp?.industries ?? [],
2276
+ ...request.icp?.keywords ?? []
2277
+ ].filter(Boolean).join(" ").toLowerCase();
2278
+ return /\b(local|google maps|near me|nearby|city|cities|location|locations|home services?|clinics?|restaurants?|contractors?)\b/.test(text);
1436
2279
  }
1437
2280
  function routesFromCustomerTools(tools) {
1438
2281
  return tools.flatMap(
@@ -1450,7 +2293,7 @@ function routesFromCustomerTools(tools) {
1450
2293
  ...tool.config,
1451
2294
  available_tools: tool.availableTools
1452
2295
  },
1453
- rationale: `${tool.label ?? tool.provider} is customer-provided for ${layer}.`
2296
+ rationale: `${tool.label ?? tool.provider} is operator-provided for ${layer}.`
1454
2297
  }))
1455
2298
  );
1456
2299
  }
@@ -1495,6 +2338,7 @@ function createBuildRequest(request, defaults, targetCount, campaignName, scopeB
1495
2338
  return buildRequest;
1496
2339
  }
1497
2340
  function createBrainPreflight(request, buildRequest, routes, memory) {
2341
+ const operatingPlaybooks = getCampaignBuilderOperatingPlaybooksForRequest(request);
1498
2342
  const layers = uniqueStrings([
1499
2343
  "icp",
1500
2344
  "email_finding",
@@ -1504,7 +2348,7 @@ function createBrainPreflight(request, buildRequest, routes, memory) {
1504
2348
  ["instantly", "smartlead", "heyreach"].some((provider) => routes.some((route) => route.provider === provider)) ? "sender" : void 0,
1505
2349
  memory.enabled ? "feedback" : void 0
1506
2350
  ]);
1507
- const providerChain = uniqueStrings(["signaliz", ...routes.map((route) => route.provider)]);
2351
+ const providerChain = uniqueStrings(["signaliz", ...request.preferredProviders ?? [], ...routes.map((route) => route.provider)]);
1508
2352
  const targetIcp = compact({
1509
2353
  personas: buildRequest.icp?.personas,
1510
2354
  industries: buildRequest.icp?.industries,
@@ -1545,6 +2389,13 @@ function createBrainPreflight(request, buildRequest, routes, memory) {
1545
2389
  required: true,
1546
2390
  policy: "Run read-only GTM Brain preflight before build_campaign so learned defaults, memory, and deliverability risk stay attached to the build.",
1547
2391
  layers,
2392
+ operating_playbooks: operatingPlaybooks.map((playbook) => ({
2393
+ slug: playbook.slug,
2394
+ label: playbook.label,
2395
+ quality_gates: playbook.qualityGates,
2396
+ required_fields: playbook.requiredFields,
2397
+ activation_boundary: playbook.activationBoundary
2398
+ })),
1548
2399
  target_icp: targetIcp,
1549
2400
  provider_chain: providerChain,
1550
2401
  lead_source: providerChain[0] ?? "signaliz",
@@ -1677,6 +2528,47 @@ function createMcpFlow(request, buildRequest, routes, memory, approvals) {
1677
2528
  approvalRequired: false
1678
2529
  }
1679
2530
  ];
2531
+ steps.push({
2532
+ id: "gtm-provider-catalog",
2533
+ phase: "plan",
2534
+ tool: "gtm_provider_catalog",
2535
+ arguments: {
2536
+ include_layer_catalog: true,
2537
+ include_planned: true
2538
+ },
2539
+ readOnly: true,
2540
+ approvalRequired: false
2541
+ });
2542
+ if (request.agencyContext?.includeNangoCatalog !== false) {
2543
+ steps.push({
2544
+ id: "nango-tool-catalog",
2545
+ phase: "plan",
2546
+ tool: "nango_mcp_tools_list",
2547
+ arguments: {
2548
+ format: "mcp"
2549
+ },
2550
+ readOnly: true,
2551
+ approvalRequired: false
2552
+ });
2553
+ }
2554
+ if (memory.enabled) {
2555
+ steps.push({
2556
+ id: "strategy-memory-status",
2557
+ phase: "memory",
2558
+ tool: "gtm_campaign_strategy_memory_status",
2559
+ arguments: buildGtmCampaignStrategyMemoryStatusArgs(request, buildRequest),
2560
+ readOnly: true,
2561
+ approvalRequired: false
2562
+ });
2563
+ }
2564
+ steps.push({
2565
+ id: "agency-campaign-build-plan",
2566
+ phase: "plan",
2567
+ tool: "gtm_campaign_build_plan",
2568
+ arguments: buildGtmCampaignBuildPlanArgs(request, buildRequest, routes, memory),
2569
+ readOnly: true,
2570
+ approvalRequired: memory.useNetworkPatterns === true
2571
+ });
1680
2572
  if (memory.enabled) {
1681
2573
  for (const [index, query] of memory.queries.entries()) {
1682
2574
  steps.push({
@@ -1690,6 +2582,25 @@ function createMcpFlow(request, buildRequest, routes, memory, approvals) {
1690
2582
  }
1691
2583
  }
1692
2584
  for (const route of routes) {
2585
+ if (shouldPrepareProviderRoute(route)) {
2586
+ steps.push({
2587
+ id: `prepare-${route.id}`,
2588
+ phase: "plan",
2589
+ tool: "gtm_provider_recipe_prepare",
2590
+ arguments: buildProviderRecipePrepareArgs(route, buildRequest),
2591
+ readOnly: true,
2592
+ approvalRequired: false
2593
+ });
2594
+ steps.push({
2595
+ id: `activate-${route.id}-dry-run`,
2596
+ phase: "plan",
2597
+ tool: "gtm_provider_route_activate",
2598
+ arguments: buildProviderRouteActivateArgs(route, buildRequest),
2599
+ readOnly: true,
2600
+ approvalRequired: false
2601
+ });
2602
+ }
2603
+ const routeApprovalRequired = route.approvalRequired === true || route.provider !== "signaliz" && route.approvalRequired !== false && route.mode === "required" || route.layer === "delivery" || route.layer === "feedback";
1693
2604
  steps.push({
1694
2605
  id: `route-${route.id}`,
1695
2606
  phase: route.layer,
@@ -1701,7 +2612,7 @@ function createMcpFlow(request, buildRequest, routes, memory, approvals) {
1701
2612
  config: route.config
1702
2613
  },
1703
2614
  readOnly: !["delivery", "feedback"].includes(route.layer),
1704
- approvalRequired: route.approvalRequired === true || route.layer === "delivery" || route.layer === "feedback"
2615
+ approvalRequired: routeApprovalRequired
1705
2616
  });
1706
2617
  }
1707
2618
  steps.push({
@@ -1710,8 +2621,8 @@ function createMcpFlow(request, buildRequest, routes, memory, approvals) {
1710
2621
  tool: "scope_campaign",
1711
2622
  arguments: {
1712
2623
  prompt: request.goal,
1713
- client_name: request.clientName,
1714
- client_context: request.clientContext,
2624
+ account_label: campaignBuilderAccountLabel(request),
2625
+ account_context: campaignBuilderAccountContext(request),
1715
2626
  target_count: request.targetCount
1716
2627
  },
1717
2628
  readOnly: true,
@@ -1773,9 +2684,199 @@ function createMcpFlow(request, buildRequest, routes, memory, approvals) {
1773
2684
  });
1774
2685
  return steps.map((step) => ({ ...step, arguments: compact(step.arguments) }));
1775
2686
  }
2687
+ function shouldPrepareProviderRoute(route) {
2688
+ return !["signaliz", "csv"].includes(route.provider);
2689
+ }
2690
+ function buildProviderRecipePrepareArgs(route, buildRequest) {
2691
+ const layerCapabilities = uniqueStrings(gtmLayersForRoute(route));
2692
+ const layer = layerCapabilities[0] ?? mapCampaignBuilderLayerToGtmLayer(route.layer) ?? "custom";
2693
+ const config = asRecord(route.config);
2694
+ return compact({
2695
+ provider_id: route.provider,
2696
+ provider_name: route.label,
2697
+ layer,
2698
+ layer_capabilities: layerCapabilities.length > 0 ? layerCapabilities : void 0,
2699
+ invocation_type: route.providerCapability?.invocationType ?? inferProviderInvocationType(route),
2700
+ auth_strategy: inferProviderAuthStrategy(route),
2701
+ workspace_mcp_server_id: stringValue(config.workspace_mcp_server_id ?? config.workspaceMcpServerId ?? route.mcpServerName),
2702
+ workspace_integration_id: stringValue(config.workspace_integration_id ?? config.workspaceIntegrationId),
2703
+ workspace_connection_id: stringValue(config.workspace_connection_id ?? config.workspaceConnectionId),
2704
+ endpoint_url: stringValue(config.endpoint_url ?? config.endpointUrl ?? config.webhook_url ?? config.webhookUrl),
2705
+ request_template: asOptionalRecord(config.request_template ?? config.requestTemplate),
2706
+ response_mapping: asOptionalRecord(config.response_mapping ?? config.responseMapping),
2707
+ input_schema: asOptionalRecord(config.input_schema ?? config.inputSchema ?? route.providerCapability?.exampleInputSchema),
2708
+ output_schema: asOptionalRecord(config.output_schema ?? config.outputSchema ?? route.providerCapability?.exampleOutputSchema),
2709
+ readiness: asOptionalRecord(config.readiness),
2710
+ metadata: compact({
2711
+ source: "campaign-builder-agent",
2712
+ route_id: route.id,
2713
+ campaign_name: buildRequest.name,
2714
+ tool_name: route.toolName,
2715
+ mcp_server_name: route.mcpServerName,
2716
+ dry_run_only: true
2717
+ }),
2718
+ context: compact({
2719
+ source: "campaign-builder-agent",
2720
+ route_id: route.id,
2721
+ gtm_campaign_id: buildRequest.gtmCampaignId
2722
+ }),
2723
+ use_signaliz_fallback: route.routingPolicy?.useSignalizFallback ?? true,
2724
+ priority: numberOrUndefined2(config.priority),
2725
+ status: stringValue(config.status) ?? "needs_setup"
2726
+ });
2727
+ }
2728
+ function buildProviderRouteActivateArgs(route, buildRequest) {
2729
+ const layerCapabilities = uniqueStrings(gtmLayersForRoute(route));
2730
+ const config = asRecord(route.config);
2731
+ return compact({
2732
+ provider_id: route.provider,
2733
+ provider_name: route.label,
2734
+ campaign_id: buildRequest.gtmCampaignId,
2735
+ layer: layerCapabilities[0] ?? mapCampaignBuilderLayerToGtmLayer(route.layer) ?? "custom",
2736
+ layers: layerCapabilities.length > 0 ? layerCapabilities : void 0,
2737
+ invocation_type: route.providerCapability?.invocationType ?? inferProviderInvocationType(route),
2738
+ auth_strategy: inferProviderAuthStrategy(route),
2739
+ workspace_mcp_server_id: stringValue(config.workspace_mcp_server_id ?? config.workspaceMcpServerId ?? route.mcpServerName),
2740
+ workspace_integration_id: stringValue(config.workspace_integration_id ?? config.workspaceIntegrationId),
2741
+ workspace_connection_id: stringValue(config.workspace_connection_id ?? config.workspaceConnectionId),
2742
+ endpoint_url: stringValue(config.endpoint_url ?? config.endpointUrl ?? config.webhook_url ?? config.webhookUrl),
2743
+ route_config: compact({
2744
+ ...asRecord(config.route_config ?? config.routeConfig),
2745
+ source: "campaign-builder-agent",
2746
+ route_id: route.id,
2747
+ tool_name: route.toolName,
2748
+ mcp_server_name: route.mcpServerName
2749
+ }),
2750
+ use_signaliz_fallback: route.routingPolicy?.useSignalizFallback ?? true,
2751
+ priority: numberOrUndefined2(config.priority),
2752
+ dry_run: true,
2753
+ confirm: false
2754
+ });
2755
+ }
2756
+ function inferProviderInvocationType(route) {
2757
+ if (route.provider === "airbyte") return "airbyte";
2758
+ if (route.provider === "nango") return "managed_integration";
2759
+ if (["custom_webhook", "webhook", "clay_webhook"].includes(route.provider)) return "webhook";
2760
+ if (["custom_api", "apollo", "ai_ark", "apify"].includes(route.provider)) return "api";
2761
+ if (route.mcpServerName || route.toolName || ["custom_mcp", "octave"].includes(route.provider)) return "mcp_tool";
2762
+ return "manual";
2763
+ }
2764
+ function inferProviderAuthStrategy(route) {
2765
+ const config = asRecord(route.config);
2766
+ const configured = stringValue(config.auth_strategy ?? config.authStrategy);
2767
+ if (configured) return configured;
2768
+ const invocationType = route.providerCapability?.invocationType ?? inferProviderInvocationType(route);
2769
+ if (invocationType === "webhook") return "webhook_secret";
2770
+ if (invocationType === "mcp_tool") return "mcp_auth";
2771
+ if (invocationType === "managed_integration") return "byo_runtime";
2772
+ if (invocationType === "api" || invocationType === "airbyte") return "integration_key";
2773
+ return void 0;
2774
+ }
2775
+ function refreshBuildStepArguments(plan) {
2776
+ for (const step of plan.mcpFlow) {
2777
+ if (step.id === "dry-run-build") {
2778
+ step.arguments = compact({
2779
+ ...buildCampaignArgs({ ...plan.buildRequest, dryRun: true, confirmSpend: false }),
2780
+ dry_run: true
2781
+ });
2782
+ }
2783
+ if (step.id === "approved-build") {
2784
+ step.arguments = compact({
2785
+ ...buildCampaignArgs({ ...plan.buildRequest, dryRun: false, confirmSpend: true }),
2786
+ required_approvals: plan.approvals.map((approval) => approval.id)
2787
+ });
2788
+ }
2789
+ }
2790
+ }
2791
+ function buildFallbackPlanSnapshot(plan) {
2792
+ const plannerStep = plan.mcpFlow.find((step) => step.id === "agency-campaign-build-plan");
2793
+ return compact({
2794
+ source_tool: "campaign-builder-agent",
2795
+ plan_id: plan.planId,
2796
+ query: asRecord(plannerStep?.arguments),
2797
+ campaign_name: plan.campaignName,
2798
+ goal: plan.goal,
2799
+ target_count: plan.targetCount,
2800
+ approvals: plan.approvals,
2801
+ brain_preflight: plan.brainPreflight,
2802
+ operating_playbooks: plan.operatingPlaybooks
2803
+ });
2804
+ }
2805
+ function mapPlanCommitResult(data) {
2806
+ const campaign = asRecord(data.campaign);
2807
+ const campaignBuild = asRecord(data.campaign_build ?? data.campaignBuild);
2808
+ const committedPlan = asRecord(data.committed_plan ?? data.committedPlan);
2809
+ const commitPlan = asRecord(data.commit_plan ?? data.commitPlan);
2810
+ const campaignArgs = asRecord(commitPlan.campaign_arguments ?? commitPlan.campaignArguments);
2811
+ return {
2812
+ dryRun: data.dry_run === true || data.dryRun === true,
2813
+ wroteState: data.wrote_state === true || data.wroteState === true,
2814
+ campaignId: stringValue(campaign.id ?? committedPlan.campaign_id ?? committedPlan.campaignId ?? commitPlan.campaign_id ?? commitPlan.campaignId ?? campaignArgs.id),
2815
+ campaignBuildId: stringValue(campaignBuild.id ?? committedPlan.campaign_build_id ?? committedPlan.campaignBuildId ?? campaignArgs.campaign_build_id ?? campaignArgs.campaignBuildId),
2816
+ raw: data
2817
+ };
2818
+ }
2819
+ function buildGtmCampaignBuildPlanArgs(request, buildRequest, routes, memory) {
2820
+ const agencyContext = request.agencyContext ?? {};
2821
+ const strategyModel = campaignBuilderStrategyModel(agencyContext);
2822
+ const partnerEcosystem = agencyContext.partnerEcosystem ?? (strategyModel === "custom" ? void 0 : ["clay", "instantly", "nango"]);
2823
+ const layers = uniqueStrings([
2824
+ "icp",
2825
+ buildRequest.icp?.requireVerifiedEmail !== false ? "email_finding" : void 0,
2826
+ buildRequest.icp?.requireVerifiedEmail !== false ? "email_verification" : void 0,
2827
+ ...routes.flatMap(gtmLayersForRoute),
2828
+ buildRequest.delivery?.destinationType === "webhook" ? "destination_export" : void 0,
2829
+ memory.enabled ? "feedback" : void 0
2830
+ ]);
2831
+ const preferredProviders = uniqueStrings([
2832
+ ...request.preferredProviders ?? [],
2833
+ ...routes.map((route) => route.provider).filter((provider) => provider !== "signaliz")
2834
+ ]);
2835
+ const operatingPlaybooks = getCampaignBuilderOperatingPlaybooksForRequest(request);
2836
+ return compact({
2837
+ campaign_id: buildRequest.gtmCampaignId,
2838
+ campaign_brief: buildRequest.prompt || request.goal,
2839
+ strategy_template: request.strategyTemplate,
2840
+ target_icp: buildRequest.icp ? buildGtmTargetIcpContext(buildRequest.icp) : void 0,
2841
+ lead_count: buildRequest.targetCount,
2842
+ layers: layers.length > 0 ? layers : void 0,
2843
+ preferred_providers: preferredProviders.length > 0 ? preferredProviders : void 0,
2844
+ strategy_model: strategyModel,
2845
+ include_strategy_patterns: campaignBuilderStrategyPatternsEnabled(agencyContext),
2846
+ include_workflow_patterns: campaignBuilderWorkflowPatternsEnabled(agencyContext),
2847
+ include_nango_catalog: agencyContext.includeNangoCatalog !== false,
2848
+ partner_ecosystem: partnerEcosystem,
2849
+ operating_playbooks: operatingPlaybooks.map((playbook) => ({
2850
+ slug: playbook.slug,
2851
+ label: playbook.label,
2852
+ quality_gates: playbook.qualityGates,
2853
+ activation_boundary: playbook.activationBoundary
2854
+ })),
2855
+ include_memory: memory.enabled,
2856
+ include_brain: true,
2857
+ include_provider_routes: true,
2858
+ include_failure_patterns: true,
2859
+ include_planned_providers: true,
2860
+ limit: 25
2861
+ });
2862
+ }
2863
+ function buildGtmCampaignStrategyMemoryStatusArgs(request, buildRequest) {
2864
+ return compact({
2865
+ query: request.goal,
2866
+ campaign_brief: buildRequest.prompt || request.goal,
2867
+ strategy_template: request.strategyTemplate,
2868
+ target_icp: buildRequest.icp ? buildGtmTargetIcpContext(buildRequest.icp) : void 0,
2869
+ memory_dimension_filters: request.strategyTemplate ? { strategy_template: request.strategyTemplate } : void 0,
2870
+ require_memory_dimension_match: false,
2871
+ include_samples: false,
2872
+ include_sources: true,
2873
+ days: 3650,
2874
+ limit: 25
2875
+ });
2876
+ }
1776
2877
  function buildGtmMemorySearchArgs(request, routes, query) {
1777
2878
  const layers = uniqueStrings(routes.flatMap(gtmLayersForRoute));
1778
- const providerChain = uniqueStrings(routes.map((route) => route.provider));
2879
+ const providerChain = uniqueStrings([...request.preferredProviders ?? [], ...routes.map((route) => route.provider)]);
1779
2880
  return compact({
1780
2881
  query: query.query,
1781
2882
  limit: query.topK,
@@ -1797,6 +2898,26 @@ function buildGtmTargetIcpContext(icp) {
1797
2898
  require_verified_email: icp.requireVerifiedEmail
1798
2899
  });
1799
2900
  }
2901
+ function mapCampaignBuilderLayerToGtmLayer(layer) {
2902
+ switch (layer) {
2903
+ case "source":
2904
+ return "lead_generation";
2905
+ case "enrichment":
2906
+ return "company_enrichment";
2907
+ case "qualification":
2908
+ return "qualification";
2909
+ case "copy":
2910
+ return "copy_enrichment";
2911
+ case "delivery":
2912
+ return "destination_export";
2913
+ case "feedback":
2914
+ return "feedback";
2915
+ case "approval":
2916
+ return "approval";
2917
+ default:
2918
+ return void 0;
2919
+ }
2920
+ }
1800
2921
  function buildCampaignArgs(request) {
1801
2922
  const args = {
1802
2923
  name: request.name,
@@ -1977,8 +3098,8 @@ function estimateCredits(request, defaults, targetCount) {
1977
3098
  }
1978
3099
  function buildDescription(request) {
1979
3100
  const parts = [
1980
- request.clientName ? `Client: ${request.clientName}` : void 0,
1981
- request.clientContext ? `Context: ${request.clientContext}` : void 0,
3101
+ campaignBuilderAccountLabel(request) ? `Account label: ${campaignBuilderAccountLabel(request)}` : void 0,
3102
+ campaignBuilderAccountContext(request) ? `Context: ${campaignBuilderAccountContext(request)}` : void 0,
1982
3103
  request.constraints?.deliverabilityNotes?.length ? `Deliverability: ${request.constraints.deliverabilityNotes.join("; ")}` : void 0,
1983
3104
  "Agent-built campaign plan layered on Signaliz kernel and existing MCP tools."
1984
3105
  ];
@@ -2001,6 +3122,10 @@ function compact(record) {
2001
3122
  function asRecord(value) {
2002
3123
  return value && typeof value === "object" && !Array.isArray(value) ? value : {};
2003
3124
  }
3125
+ function asOptionalRecord(value) {
3126
+ const record = asRecord(value);
3127
+ return Object.keys(record).length > 0 ? record : void 0;
3128
+ }
2004
3129
  function stringValue(value) {
2005
3130
  return typeof value === "string" && value.length > 0 ? value : void 0;
2006
3131
  }
@@ -3745,7 +4870,7 @@ var GtmKernel = class {
3745
4870
  campaigns: input.campaigns.map(campaignHistoryImportCampaignArgs)
3746
4871
  });
3747
4872
  }
3748
- /** Queue a Trigger-backed campaign history import for larger CMM/client backfills. */
4873
+ /** Queue a Trigger-backed campaign history import for larger private campaign backfills. */
3749
4874
  async importCampaignHistoryRun(input) {
3750
4875
  return this.callMcp("gtm_campaign_history_import_run", {
3751
4876
  source: input.source,
@@ -3876,6 +5001,25 @@ var GtmKernel = class {
3876
5001
  write_routine_outcomes: input.writeRoutineOutcomes
3877
5002
  });
3878
5003
  }
5004
+ /** Run a read-only Campaign Audit and persist workspace-scoped failure findings. */
5005
+ async runCampaignAudit(input) {
5006
+ return this.callMcp("gtm_campaign_audit_run", {
5007
+ provider: input.provider,
5008
+ provider_campaign_id: input.providerCampaignId,
5009
+ campaign_id: input.campaignId,
5010
+ campaign_name: input.campaignName,
5011
+ lookback_days: input.lookbackDays,
5012
+ limit_findings: input.limitFindings
5013
+ });
5014
+ }
5015
+ /** Read a persisted Campaign Audit by audit id or campaign id. */
5016
+ async getCampaignAudit(options) {
5017
+ return this.callMcp("gtm_campaign_audit_get", {
5018
+ audit_id: options.auditId,
5019
+ campaign_id: options.campaignId,
5020
+ limit_findings: options.limitFindings
5021
+ });
5022
+ }
3879
5023
  /** Normalize Instantly webhook/pull payloads and ingest row-level feedback through the GTM Kernel. */
3880
5024
  async syncInstantlyFeedback(input) {
3881
5025
  return this.callMcp("gtm_instantly_feedback_sync", {
@@ -4173,6 +5317,40 @@ var GtmKernel = class {
4173
5317
  include_layer_catalog: options.includeLayerCatalog
4174
5318
  });
4175
5319
  }
5320
+ /** List private-safe campaign strategy templates agents can merge into campaign build plans. */
5321
+ async campaignStrategyTemplates(options = {}) {
5322
+ return this.callMcp("gtm_campaign_strategy_templates", {
5323
+ strategy_template: options.strategyTemplate,
5324
+ query: options.query,
5325
+ include_details: options.includeDetails
5326
+ });
5327
+ }
5328
+ /** Build the read-only Memory, Brain, risk, and provider-route runbook needed before planning a campaign. */
5329
+ async campaignStartContext(input = {}) {
5330
+ return this.callMcp("gtm_campaign_start_context", {
5331
+ campaign_id: input.campaignId,
5332
+ campaign_build_id: input.campaignBuildId,
5333
+ campaign_brief: input.campaignBrief,
5334
+ strategy_template: input.strategyTemplate,
5335
+ target_icp: input.targetIcp,
5336
+ lead_count: input.leadCount,
5337
+ layers: input.layers,
5338
+ preferred_providers: input.preferredProviders,
5339
+ memory_dimension_filters: input.memoryDimensionFilters,
5340
+ require_memory_dimension_match: input.requireMemoryDimensionMatch,
5341
+ include_memory: input.includeMemory,
5342
+ include_brain: input.includeBrain,
5343
+ include_provider_routes: input.includeProviderRoutes,
5344
+ include_failure_patterns: input.includeFailurePatterns,
5345
+ include_delivery_risk: input.includeDeliveryRisk,
5346
+ include_global_brain: input.includeGlobalBrain,
5347
+ include_planned_providers: input.includePlannedProviders,
5348
+ days: input.days,
5349
+ min_confidence: input.minConfidence,
5350
+ min_sample_size: input.minSampleSize,
5351
+ limit: input.limit
5352
+ });
5353
+ }
4176
5354
  /** Inspect GTM integration activation cards for UI and agent routing without writing state. */
4177
5355
  async integrationsActivationStatus(options = {}) {
4178
5356
  return this.callMcp("gtm_integrations_activation_status", {
@@ -4188,21 +5366,100 @@ var GtmKernel = class {
4188
5366
  campaign_id: input.campaignId,
4189
5367
  campaign_build_id: input.campaignBuildId,
4190
5368
  campaign_brief: input.campaignBrief,
5369
+ strategy_template: input.strategyTemplate,
5370
+ target_icp: input.targetIcp,
5371
+ lead_count: input.leadCount,
5372
+ layers: input.layers,
5373
+ preferred_providers: input.preferredProviders,
5374
+ strategy_model: input.strategyModel,
5375
+ include_strategy_patterns: input.includeStrategyPatterns,
5376
+ include_workflow_patterns: input.includeWorkflowPatterns ?? input.includeClayPatterns,
5377
+ include_nango_catalog: input.includeNangoCatalog,
5378
+ partner_ecosystem: input.partnerEcosystem,
5379
+ memory_dimension_filters: input.memoryDimensionFilters,
5380
+ require_memory_dimension_match: input.requireMemoryDimensionMatch,
5381
+ include_memory: input.includeMemory,
5382
+ include_brain: input.includeBrain,
5383
+ include_provider_routes: input.includeProviderRoutes,
5384
+ include_failure_patterns: input.includeFailurePatterns,
5385
+ include_planned_providers: input.includePlannedProviders,
5386
+ days: input.days,
5387
+ limit: input.limit
5388
+ });
5389
+ }
5390
+ /** Emit reusable CampaignBuilderAgentRequest JSON from hosted MCP strategy-template defaults without spending credits. */
5391
+ async campaignAgentRequestTemplate(input = {}) {
5392
+ return this.callMcp("gtm_campaign_agent_request_template", {
5393
+ goal: input.goal,
5394
+ campaign_brief: input.campaignBrief,
5395
+ campaign_name: input.campaignName,
5396
+ account_label: input.accountLabel,
5397
+ account_context: input.accountContext,
5398
+ strategy_template: input.strategyTemplate,
5399
+ operating_playbooks: input.operatingPlaybooks,
4191
5400
  target_icp: input.targetIcp,
5401
+ target_count: input.targetCount,
5402
+ builtins: input.builtIns,
5403
+ include_local_leads: input.includeLocalLeads,
5404
+ include_byo_placeholder: input.includeByoPlaceholder,
5405
+ include_nango_catalog: input.includeNangoCatalog,
5406
+ preferred_providers: input.preferredProviders,
5407
+ privacy_mode: input.privacyMode,
5408
+ destination_type: input.destinationType
5409
+ });
5410
+ }
5411
+ /** Compose a one-call read-only strategy-template campaign-agent runbook across built-ins, Memory, Brain, Nango, and BYO routes. */
5412
+ async campaignAgentPlan(input = {}) {
5413
+ return this.callMcp("gtm_campaign_agent_plan", {
5414
+ goal: input.goal,
5415
+ campaign_brief: input.campaignBrief,
5416
+ campaign_name: input.campaignName,
5417
+ campaign_id: input.campaignId,
5418
+ campaign_build_id: input.campaignBuildId,
5419
+ strategy_template: input.strategyTemplate,
5420
+ operating_playbooks: input.operatingPlaybooks,
5421
+ account_context: input.accountContext,
5422
+ target_icp: input.targetIcp,
5423
+ target_count: input.targetCount,
4192
5424
  lead_count: input.leadCount,
5425
+ builtins: input.builtIns,
5426
+ use_local_leads: input.useLocalLeads,
4193
5427
  layers: input.layers,
4194
5428
  preferred_providers: input.preferredProviders,
5429
+ custom_tools: input.customTools,
5430
+ integrations: input.integrations,
5431
+ strategy_model: input.strategyModel,
5432
+ include_strategy_patterns: input.includeStrategyPatterns,
5433
+ include_workflow_patterns: input.includeWorkflowPatterns,
5434
+ include_nango_catalog: input.includeNangoCatalog,
5435
+ partner_ecosystem: input.partnerEcosystem,
4195
5436
  memory_dimension_filters: input.memoryDimensionFilters,
4196
5437
  require_memory_dimension_match: input.requireMemoryDimensionMatch,
4197
5438
  include_memory: input.includeMemory,
4198
5439
  include_brain: input.includeBrain,
4199
5440
  include_provider_routes: input.includeProviderRoutes,
4200
5441
  include_failure_patterns: input.includeFailurePatterns,
5442
+ include_delivery_risk: input.includeDeliveryRisk,
4201
5443
  include_planned_providers: input.includePlannedProviders,
4202
5444
  days: input.days,
4203
5445
  limit: input.limit
4204
5446
  });
4205
5447
  }
5448
+ /** Inspect private-safe strategy-template/workflow memory readiness before campaign planning. */
5449
+ async campaignStrategyMemoryStatus(input = {}) {
5450
+ return this.callMcp("gtm_campaign_strategy_memory_status", {
5451
+ strategy_template: input.strategyTemplate,
5452
+ query: input.query,
5453
+ campaign_brief: input.campaignBrief,
5454
+ target_icp: input.targetIcp,
5455
+ memory_dimension_filters: input.memoryDimensionFilters,
5456
+ require_memory_dimension_match: input.requireMemoryDimensionMatch,
5457
+ include_samples: input.includeSamples,
5458
+ include_sources: input.includeSources,
5459
+ days: input.days,
5460
+ limit: input.limit
5461
+ });
5462
+ }
4206
5463
  /** Persist a reviewed campaign build plan into a campaign object and audit log. Dry-run first by default. */
4207
5464
  async commitCampaignBuildPlan(input = {}) {
4208
5465
  return this.callMcp("gtm_campaign_build_plan_commit", {
@@ -4349,6 +5606,13 @@ var GtmKernel = class {
4349
5606
  vendor_id: input.vendorId,
4350
5607
  service_category: input.serviceCategory,
4351
5608
  connection_type: input.connectionType,
5609
+ integration_id: input.integrationId,
5610
+ provider_config_key: input.providerConfigKey,
5611
+ allowed_integrations: input.allowedIntegrations,
5612
+ surface: input.surface,
5613
+ source: input.source,
5614
+ user_email: input.userEmail,
5615
+ user_display_name: input.userDisplayName,
4352
5616
  status: input.status,
4353
5617
  metadata: input.metadata
4354
5618
  });
@@ -4405,6 +5669,20 @@ var GtmKernel = class {
4405
5669
  context: input.context
4406
5670
  });
4407
5671
  }
5672
+ /** Create a short-lived Nango Connect session so a user can authorize a vendor API. */
5673
+ async createNangoConnectSession(input) {
5674
+ return this.callMcp("nango_connect_session_create", {
5675
+ provider_id: input.providerId,
5676
+ integration_id: input.integrationId,
5677
+ provider_display_name: input.providerDisplayName,
5678
+ integration_display_name: input.integrationDisplayName,
5679
+ allowed_integrations: input.allowedIntegrations,
5680
+ surface: input.surface,
5681
+ source: input.source,
5682
+ user_email: input.userEmail,
5683
+ user_display_name: input.userDisplayName
5684
+ });
5685
+ }
4408
5686
  /** List Nango-backed action tools for a workspace connection without executing them. */
4409
5687
  async listNangoTools(options = {}) {
4410
5688
  return this.callMcp("nango_mcp_tools_list", {