@signaliz/sdk 1.0.5 → 1.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +100 -8
- package/dist/{chunk-GF2T2X3W.mjs → chunk-BHL5NHVO.mjs} +1446 -56
- package/dist/cli.js +2403 -63
- package/dist/cli.mjs +962 -9
- package/dist/index.d.mts +262 -10
- package/dist/index.d.ts +262 -10
- package/dist/index.js +1456 -56
- package/dist/index.mjs +21 -1
- package/dist/mcp-config.js +1334 -56
- package/dist/mcp-config.mjs +1 -1
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
"use strict";
|
|
3
3
|
|
|
4
|
+
// src/cli.ts
|
|
5
|
+
var import_node_fs = require("fs");
|
|
6
|
+
|
|
4
7
|
// src/errors.ts
|
|
5
8
|
var SignalizError = class extends Error {
|
|
6
9
|
constructor(data) {
|
|
@@ -754,7 +757,7 @@ var Campaigns = class {
|
|
|
754
757
|
async build(request, options) {
|
|
755
758
|
return this.buildCampaign(request, options);
|
|
756
759
|
}
|
|
757
|
-
/** Scope an agency/
|
|
760
|
+
/** Scope an agency/customer campaign into a markdown brief plus build_campaign dry-run args. */
|
|
758
761
|
async scope(request) {
|
|
759
762
|
return this.scopeCampaign(request);
|
|
760
763
|
}
|
|
@@ -936,7 +939,11 @@ function mapStatus(data) {
|
|
|
936
939
|
errors: diagnosticMessages(data.errors),
|
|
937
940
|
artifactCount: data.artifact_count ?? 0,
|
|
938
941
|
providerRoute: mapProviderRoute(data),
|
|
939
|
-
|
|
942
|
+
triggerRunId: typeof data.trigger_run_id === "string" ? data.trigger_run_id : null,
|
|
943
|
+
staleRunningPhase: data.stale_running_phase === true,
|
|
944
|
+
phaseAgeSeconds: numberOrNull(data.phase_age_seconds),
|
|
945
|
+
diagnostics: recordOrNull(data.diagnostics) ?? {},
|
|
946
|
+
nextAction: formatNextAction(data.next_action),
|
|
940
947
|
createdAt: data.created_at,
|
|
941
948
|
updatedAt: data.updated_at,
|
|
942
949
|
completedAt: data.completed_at
|
|
@@ -976,6 +983,19 @@ function diagnosticMessages(value) {
|
|
|
976
983
|
return typeof record?.message === "string" ? record.message : null;
|
|
977
984
|
}).filter((item) => typeof item === "string" && item.length > 0);
|
|
978
985
|
}
|
|
986
|
+
function formatNextAction(value) {
|
|
987
|
+
if (!value) return "";
|
|
988
|
+
if (typeof value === "string") return value;
|
|
989
|
+
const record = recordOrNull(value);
|
|
990
|
+
if (!record) return "";
|
|
991
|
+
const tool = typeof record.tool === "string" ? record.tool : void 0;
|
|
992
|
+
const type = typeof record.type === "string" ? record.type : void 0;
|
|
993
|
+
const reason = typeof record.reason === "string" ? record.reason : void 0;
|
|
994
|
+
const args = recordOrNull(record.arguments);
|
|
995
|
+
const argText = args && Object.keys(args).length > 0 ? ` ${JSON.stringify(args)}` : "";
|
|
996
|
+
const action = tool ? `${tool}${argText}` : type || "";
|
|
997
|
+
return [action, reason].filter(Boolean).join(" \u2014 ");
|
|
998
|
+
}
|
|
979
999
|
function booleanOrNull(value) {
|
|
980
1000
|
return typeof value === "boolean" ? value : null;
|
|
981
1001
|
}
|
|
@@ -1016,7 +1036,7 @@ function mapArtifact(a) {
|
|
|
1016
1036
|
function mapScope(data) {
|
|
1017
1037
|
return {
|
|
1018
1038
|
campaignScopeId: data.campaign_scope_id,
|
|
1019
|
-
|
|
1039
|
+
accountLabel: data.account_label,
|
|
1020
1040
|
campaignName: data.campaign_name,
|
|
1021
1041
|
approach: data.approach,
|
|
1022
1042
|
approachLabel: data.approach_label,
|
|
@@ -1042,8 +1062,8 @@ function scopeArgs(request) {
|
|
|
1042
1062
|
const args = {
|
|
1043
1063
|
prompt: request.prompt
|
|
1044
1064
|
};
|
|
1045
|
-
if (request.
|
|
1046
|
-
if (request.
|
|
1065
|
+
if (request.accountLabel) args.account_label = request.accountLabel;
|
|
1066
|
+
if (request.accountContext) args.account_context = request.accountContext;
|
|
1047
1067
|
if (request.campaignGoal) args.campaign_goal = request.campaignGoal;
|
|
1048
1068
|
if (request.targetCount) args.target_count = request.targetCount;
|
|
1049
1069
|
if (request.destinations) args.destinations = request.destinations;
|
|
@@ -1171,22 +1191,565 @@ var DEFAULT_SIGNALIZ_CAMPAIGN_BUILDER_DEFAULTS = {
|
|
|
1171
1191
|
approvalRequired: true
|
|
1172
1192
|
}
|
|
1173
1193
|
};
|
|
1194
|
+
var DEFAULT_CAMPAIGN_BUILDER_BUILT_INS = [
|
|
1195
|
+
"lead_generation",
|
|
1196
|
+
"email_finding",
|
|
1197
|
+
"email_verification",
|
|
1198
|
+
"signals"
|
|
1199
|
+
];
|
|
1200
|
+
var DEFAULT_CAMPAIGN_BUILDER_APPROVAL_TYPES = [
|
|
1201
|
+
"memory_retrieval",
|
|
1202
|
+
"spend",
|
|
1203
|
+
"customer_tool",
|
|
1204
|
+
"external_write",
|
|
1205
|
+
"delivery",
|
|
1206
|
+
"launch"
|
|
1207
|
+
];
|
|
1208
|
+
var CAMPAIGN_BUILDER_OPERATING_PLAYBOOKS = [
|
|
1209
|
+
{
|
|
1210
|
+
slug: "cache-first-large-list",
|
|
1211
|
+
label: "Cache-First Large List",
|
|
1212
|
+
whenToUse: [
|
|
1213
|
+
"The target count is high and reusable workspace lead or cache coverage may exist.",
|
|
1214
|
+
"The deliverable is a verified list or top-up rather than a deeply custom one-off workflow."
|
|
1215
|
+
],
|
|
1216
|
+
sequence: [
|
|
1217
|
+
"Inventory reusable cache before paid sourcing.",
|
|
1218
|
+
"Report unique emails, role buckets, exclusions, and missing-field counts.",
|
|
1219
|
+
"Use fresh sourcing only for the approved gap.",
|
|
1220
|
+
"Write newly approved source metadata back to memory or cache after review."
|
|
1221
|
+
],
|
|
1222
|
+
requiredFields: {
|
|
1223
|
+
inventory: ["matching_cached_rows", "unique_cached_emails", "persona_bucket_counts", "exclusions_applied", "missing_field_counts"],
|
|
1224
|
+
finalRows: ["first_name", "last_name", "company_name", "company_domain", "work_email", "email_status", "source_type"]
|
|
1225
|
+
},
|
|
1226
|
+
qualityGates: [
|
|
1227
|
+
"Deduplicate by normalized email before counting final rows.",
|
|
1228
|
+
"Separate cache reuse from fresh sourcing in the build receipt.",
|
|
1229
|
+
"Block export when required identity, company, or email fields are missing."
|
|
1230
|
+
],
|
|
1231
|
+
activationBoundary: "Cache inventory is read-only. Fresh sourcing, cache writes, export, and sender loading require explicit approval.",
|
|
1232
|
+
memoryKeywords: ["cache inventory", "large list", "unique emails", "top-up sourcing", "source metadata"]
|
|
1233
|
+
},
|
|
1234
|
+
{
|
|
1235
|
+
slug: "net-new-suppressed-list",
|
|
1236
|
+
label: "Net-New Suppressed List",
|
|
1237
|
+
whenToUse: [
|
|
1238
|
+
"A prior campaign, seed list, or exclusion list must be suppressed.",
|
|
1239
|
+
"The operator needs both outreach-facing rows and provenance-rich QA evidence."
|
|
1240
|
+
],
|
|
1241
|
+
sequence: [
|
|
1242
|
+
"Load suppression baselines before source selection.",
|
|
1243
|
+
"Apply email suppression as a hard gate and domain suppression as required by the brief.",
|
|
1244
|
+
"Keep provenance, source, and validation fields outside the outreach-facing export when needed.",
|
|
1245
|
+
"Run final overlap checks before any delivery action."
|
|
1246
|
+
],
|
|
1247
|
+
requiredFields: {
|
|
1248
|
+
suppression: ["suppression_source", "prior_email_overlap", "prior_domain_match", "suppression_decision"],
|
|
1249
|
+
finalRows: ["first_name", "last_name", "company_name", "company_domain", "work_email", "email_status", "provenance_id"]
|
|
1250
|
+
},
|
|
1251
|
+
qualityGates: [
|
|
1252
|
+
"Prior email overlap must be zero for rows marked export ready.",
|
|
1253
|
+
"Prior-domain matches must be flagged or blocked according to the approved campaign promise.",
|
|
1254
|
+
"Do not describe rows as fully qualified when the approved path only proves net-new email status."
|
|
1255
|
+
],
|
|
1256
|
+
activationBoundary: "Suppression review must pass before export, upload, CRM sync, sender load, or sequence launch.",
|
|
1257
|
+
memoryKeywords: ["suppression", "net-new", "prior email overlap", "domain review", "provenance-rich QA"]
|
|
1258
|
+
},
|
|
1259
|
+
{
|
|
1260
|
+
slug: "proof-first-vertical-gate",
|
|
1261
|
+
label: "Proof-First Vertical Gate",
|
|
1262
|
+
whenToUse: [
|
|
1263
|
+
"Wrong-account risk is high or the target category has close lookalike exclusions.",
|
|
1264
|
+
"Account proof is more important than raw lead volume."
|
|
1265
|
+
],
|
|
1266
|
+
sequence: [
|
|
1267
|
+
"Define positive and negative proof fields before sourcing at scale.",
|
|
1268
|
+
"Qualify companies before contact discovery.",
|
|
1269
|
+
"Qualify contacts before email finding.",
|
|
1270
|
+
"Keep pass, review, and fail rows distinct through delivery review."
|
|
1271
|
+
],
|
|
1272
|
+
requiredFields: {
|
|
1273
|
+
account: ["company_name", "company_domain", "source_url", "positive_proof", "negative_proof", "fit_score", "account_qualified"],
|
|
1274
|
+
contact: ["person_name", "person_title", "persona_match", "contact_fit_score", "contact_qualified"]
|
|
1275
|
+
},
|
|
1276
|
+
qualityGates: [
|
|
1277
|
+
"Do not spend on contact or email enrichment until the account passes the proof gate.",
|
|
1278
|
+
"Adjacent excluded categories must stay exclusions, not synonyms.",
|
|
1279
|
+
"Contact fit should meet the configured threshold before email finding or copy generation."
|
|
1280
|
+
],
|
|
1281
|
+
activationBoundary: "Proof gates are required before contact spend, copy, export, or external writes.",
|
|
1282
|
+
memoryKeywords: ["proof gate", "vertical exclusion", "company before contact", "pass review fail", "fit threshold"]
|
|
1283
|
+
},
|
|
1284
|
+
{
|
|
1285
|
+
slug: "signal-led-copy-approval",
|
|
1286
|
+
label: "Signal-Led Copy With Approval",
|
|
1287
|
+
whenToUse: [
|
|
1288
|
+
"Outbound copy should be grounded in company signals, proof fields, or row context.",
|
|
1289
|
+
"Delivery destinations must remain locked after copy generation until review."
|
|
1290
|
+
],
|
|
1291
|
+
sequence: [
|
|
1292
|
+
"Validate list quality before copy.",
|
|
1293
|
+
"Attach the strongest supported signal and source evidence.",
|
|
1294
|
+
"Generate copy only for fit-qualified and contactable rows.",
|
|
1295
|
+
"Hold every destination behind explicit approval."
|
|
1296
|
+
],
|
|
1297
|
+
requiredFields: {
|
|
1298
|
+
evidence: ["strongest_signal", "signal_source_url", "why_now", "personalization_basis"],
|
|
1299
|
+
copy: ["subject_line", "opening_line", "email_copy", "copy_ready", "copy_blocker"]
|
|
1300
|
+
},
|
|
1301
|
+
qualityGates: [
|
|
1302
|
+
"Copy cannot invent unsupported pain, claims, numbers, or recent events.",
|
|
1303
|
+
"Weak evidence should route the row to review instead of send-ready copy.",
|
|
1304
|
+
"Destination fields must remain blocked until approval metadata is present."
|
|
1305
|
+
],
|
|
1306
|
+
activationBoundary: "Copy readiness is not delivery approval. Export, sync, sender load, and launch require a separate human-approved gate.",
|
|
1307
|
+
memoryKeywords: ["company signals", "evidence-fed copy", "why now", "copy blocker", "approval gate"]
|
|
1308
|
+
},
|
|
1309
|
+
{
|
|
1310
|
+
slug: "domain-first-recovery",
|
|
1311
|
+
label: "Domain-First Recovery",
|
|
1312
|
+
whenToUse: [
|
|
1313
|
+
"Strict yield is low and broad people sourcing creates noisy, duplicated, or off-fit rows.",
|
|
1314
|
+
"The account universe should be recovered or expanded before more contact spend."
|
|
1315
|
+
],
|
|
1316
|
+
sequence: [
|
|
1317
|
+
"Model attrition after an initial sample.",
|
|
1318
|
+
"Source or recover account domains in tight slices.",
|
|
1319
|
+
"Filter domains locally before contact discovery.",
|
|
1320
|
+
"Use accepted domains as the seed for person and email work."
|
|
1321
|
+
],
|
|
1322
|
+
requiredFields: {
|
|
1323
|
+
domainReview: ["company_domain", "source_slice", "domain_fit_score", "domain_rejection_reason", "accepted_domain"],
|
|
1324
|
+
recovery: ["target_gap", "expected_yield", "accepted_domain_count", "contact_pull_limit"]
|
|
1325
|
+
},
|
|
1326
|
+
qualityGates: [
|
|
1327
|
+
"Do not repeat broad people-with-email sourcing after strict yield proves low.",
|
|
1328
|
+
"Rejected domains should stay suppressed unless the operator changes the ICP.",
|
|
1329
|
+
"Target count means final held rows, not raw sourced rows."
|
|
1330
|
+
],
|
|
1331
|
+
activationBoundary: "Domain recovery informs sourcing. Contact enrichment, paid qualification, and export still require approved gates.",
|
|
1332
|
+
memoryKeywords: ["domain-first", "yield modeling", "attrition", "accepted domains", "gap fill"]
|
|
1333
|
+
},
|
|
1334
|
+
{
|
|
1335
|
+
slug: "table-workflow-handoff",
|
|
1336
|
+
label: "Table Workflow Handoff",
|
|
1337
|
+
whenToUse: [
|
|
1338
|
+
"The campaign needs connected source, account, people, enrichment, copy, and destination tables.",
|
|
1339
|
+
"A workspace or partner tool owns part of the workflow through MCP, webhook, API, or managed integration."
|
|
1340
|
+
],
|
|
1341
|
+
sequence: [
|
|
1342
|
+
"Create source/account context before child people rows.",
|
|
1343
|
+
"Carry source context into enrichment, copy, and destination mapping.",
|
|
1344
|
+
"Expose request-ready, result, error, blocker, and export-ready fields for every action.",
|
|
1345
|
+
"Dry-run provider routes and destination writes before activation."
|
|
1346
|
+
],
|
|
1347
|
+
requiredFields: {
|
|
1348
|
+
workflow: ["source_record_id", "company_context", "request_ready", "provider_status", "error", "export_ready", "export_blocker"],
|
|
1349
|
+
destination: ["destination_type", "destination_status", "approval_status", "approved_by", "approved_at"]
|
|
1350
|
+
},
|
|
1351
|
+
qualityGates: [
|
|
1352
|
+
"Every paid/API action needs visible request readiness and parsed output fields.",
|
|
1353
|
+
"Child people rows must preserve the account context that justified the search.",
|
|
1354
|
+
"Provider route activation must dry-run before any external write."
|
|
1355
|
+
],
|
|
1356
|
+
activationBoundary: "MCP, webhook, managed integration, and destination routes remain dry-run until the reviewed route and campaign are approved.",
|
|
1357
|
+
memoryKeywords: ["table workflow", "request ready", "provider status", "export blocker", "BYO integration"]
|
|
1358
|
+
}
|
|
1359
|
+
];
|
|
1360
|
+
var CAMPAIGN_BUILDER_STRATEGY_TEMPLATES = [
|
|
1361
|
+
{
|
|
1362
|
+
slug: "industrial-ot-resilience",
|
|
1363
|
+
label: "Industrial OT Resilience",
|
|
1364
|
+
aliases: ["industrial ot", "ot resilience", "industrial continuity", "industrial-ot-resilience"],
|
|
1365
|
+
defaultTargetCount: 3e3,
|
|
1366
|
+
campaignName: "Industrial OT Resilience Net-New",
|
|
1367
|
+
accountContext: [
|
|
1368
|
+
"Strategy template: Signaliz-only OT, industrial, manufacturing, embedded systems, field service, cyber resilience, and business continuity sourcing.",
|
|
1369
|
+
"Use prior approved campaign output as the email suppression baseline; final files must have zero prior-used email overlap.",
|
|
1370
|
+
"Keep external qualification providers disabled unless the operator explicitly changes the requirement."
|
|
1371
|
+
].join(" "),
|
|
1372
|
+
icp: {
|
|
1373
|
+
personas: [
|
|
1374
|
+
"OT leader",
|
|
1375
|
+
"Industrial automation leader",
|
|
1376
|
+
"Engineering leader",
|
|
1377
|
+
"IT infrastructure leader",
|
|
1378
|
+
"Reliability or maintenance leader",
|
|
1379
|
+
"Operations leader"
|
|
1380
|
+
],
|
|
1381
|
+
industries: [
|
|
1382
|
+
"Machinery",
|
|
1383
|
+
"Electrical and electronic manufacturing",
|
|
1384
|
+
"Mechanical or industrial engineering",
|
|
1385
|
+
"Industrial automation",
|
|
1386
|
+
"Semiconductors",
|
|
1387
|
+
"Medical devices",
|
|
1388
|
+
"Oil and energy",
|
|
1389
|
+
"Automotive"
|
|
1390
|
+
],
|
|
1391
|
+
geographies: ["United States", "United Kingdom", "Canada", "Nordics", "Netherlands"],
|
|
1392
|
+
keywords: [
|
|
1393
|
+
"OT",
|
|
1394
|
+
"ICS",
|
|
1395
|
+
"SCADA",
|
|
1396
|
+
"control systems",
|
|
1397
|
+
"industrial automation",
|
|
1398
|
+
"manufacturing",
|
|
1399
|
+
"plant operations",
|
|
1400
|
+
"reliability",
|
|
1401
|
+
"maintenance",
|
|
1402
|
+
"PLC",
|
|
1403
|
+
"business continuity"
|
|
1404
|
+
],
|
|
1405
|
+
exclusions: [
|
|
1406
|
+
"sales",
|
|
1407
|
+
"marketing",
|
|
1408
|
+
"recruiting",
|
|
1409
|
+
"HR",
|
|
1410
|
+
"finance",
|
|
1411
|
+
"legal",
|
|
1412
|
+
"customer success",
|
|
1413
|
+
"retail",
|
|
1414
|
+
"restaurants",
|
|
1415
|
+
"staffing",
|
|
1416
|
+
"real estate"
|
|
1417
|
+
],
|
|
1418
|
+
requireVerifiedEmail: true
|
|
1419
|
+
},
|
|
1420
|
+
builtIns: ["lead_generation", "email_finding", "email_verification", "signals"],
|
|
1421
|
+
preferredProviders: ["signaliz_native"],
|
|
1422
|
+
memoryQueries: [{
|
|
1423
|
+
query: "industrial OT net-new prior email suppression verified manufacturing embedded systems field service cyber resilience business continuity",
|
|
1424
|
+
scopes: ["workspace", "operator_notes"],
|
|
1425
|
+
topK: 10,
|
|
1426
|
+
required: true,
|
|
1427
|
+
rationale: "Load OT sourcing, dedupe, cache metadata, and approval gates before planning net-new work."
|
|
1428
|
+
}],
|
|
1429
|
+
constraints: {
|
|
1430
|
+
deliverabilityNotes: [
|
|
1431
|
+
"Require verified email, valid syntax, first name, last name, company name, and normalized company domain.",
|
|
1432
|
+
"Keep export, upload, sync, send, and replacement actions blocked until explicit approval.",
|
|
1433
|
+
"Treat prior-domain matches as flagged review evidence unless strict domain suppression is explicitly requested."
|
|
1434
|
+
]
|
|
1435
|
+
},
|
|
1436
|
+
signalizDefaults: {
|
|
1437
|
+
copy: {
|
|
1438
|
+
offerContext: "Do not invent product claims. Anchor messaging only in row-supported OT, industrial, cyber resilience, backup/recovery, or business-continuity context."
|
|
1439
|
+
}
|
|
1440
|
+
},
|
|
1441
|
+
agencyContext: {
|
|
1442
|
+
partnerEcosystem: ["signaliz", "instantly", "nango"]
|
|
1443
|
+
},
|
|
1444
|
+
operatingPlaybookSlugs: ["net-new-suppressed-list", "proof-first-vertical-gate", "signal-led-copy-approval"]
|
|
1445
|
+
},
|
|
1446
|
+
{
|
|
1447
|
+
slug: "non-medical-home-care",
|
|
1448
|
+
label: "Non-Medical Home Care Operations",
|
|
1449
|
+
aliases: ["home care", "non-medical home care", "home-care-operations", "non-medical-home-care"],
|
|
1450
|
+
defaultTargetCount: 3e3,
|
|
1451
|
+
campaignName: "Mature Home Care Agency Operators",
|
|
1452
|
+
accountContext: [
|
|
1453
|
+
"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.",
|
|
1454
|
+
"Use proof before paid enrichment or copy. Preserve pass vs review ICP status because healthcare language often blurs home care and home health."
|
|
1455
|
+
].join(" "),
|
|
1456
|
+
icp: {
|
|
1457
|
+
personas: [
|
|
1458
|
+
"Owner",
|
|
1459
|
+
"CEO",
|
|
1460
|
+
"COO",
|
|
1461
|
+
"Administrator",
|
|
1462
|
+
"Operations Director",
|
|
1463
|
+
"Scheduler",
|
|
1464
|
+
"Care coordinator leader"
|
|
1465
|
+
],
|
|
1466
|
+
industries: ["Non-medical home care", "Senior care", "Private duty care", "Home services"],
|
|
1467
|
+
companySizes: ["20+ employees", "600+ billable care hours/week", "1000+ billable care hours/week ideal"],
|
|
1468
|
+
geographies: ["United States"],
|
|
1469
|
+
keywords: [
|
|
1470
|
+
"non-medical home care",
|
|
1471
|
+
"private duty",
|
|
1472
|
+
"caregiver recruiting",
|
|
1473
|
+
"multi-location",
|
|
1474
|
+
"franchise",
|
|
1475
|
+
"scheduler",
|
|
1476
|
+
"billing",
|
|
1477
|
+
"payroll",
|
|
1478
|
+
"EVV",
|
|
1479
|
+
"WellSky",
|
|
1480
|
+
"AxisCare",
|
|
1481
|
+
"CareSmartz360"
|
|
1482
|
+
],
|
|
1483
|
+
exclusions: [
|
|
1484
|
+
"home health",
|
|
1485
|
+
"skilled nursing",
|
|
1486
|
+
"hospice",
|
|
1487
|
+
"hospital",
|
|
1488
|
+
"clinic",
|
|
1489
|
+
"therapy practice",
|
|
1490
|
+
"very small owner-only shop"
|
|
1491
|
+
],
|
|
1492
|
+
requireVerifiedEmail: true
|
|
1493
|
+
},
|
|
1494
|
+
builtIns: ["lead_generation", "local_leads", "email_finding", "email_verification", "signals"],
|
|
1495
|
+
preferredProviders: ["signaliz_native", "octave", "clay_webhook", "apify"],
|
|
1496
|
+
memoryQueries: [{
|
|
1497
|
+
query: "mature non-medical home care agencies billable hours franchise caregiver recruiting proof gate qualification export approval",
|
|
1498
|
+
scopes: ["workspace", "operator_notes"],
|
|
1499
|
+
topK: 10,
|
|
1500
|
+
required: true,
|
|
1501
|
+
rationale: "Load home-care ICP gates, source lanes, qualification thresholds, and home-care exclusion logic."
|
|
1502
|
+
}],
|
|
1503
|
+
constraints: {
|
|
1504
|
+
deliverabilityNotes: [
|
|
1505
|
+
"Company proof and strict ICP gate must pass before contact search, email finding, Signaliz signals, or export.",
|
|
1506
|
+
"Home health is an exclusion signal, not a synonym for home care."
|
|
1507
|
+
]
|
|
1508
|
+
},
|
|
1509
|
+
signalizDefaults: {
|
|
1510
|
+
copy: {
|
|
1511
|
+
offerContext: "Use angles around after-hours shift recovery, billing/payroll exceptions, multi-location consistency, and caregiver retention only when supported by evidence."
|
|
1512
|
+
}
|
|
1513
|
+
},
|
|
1514
|
+
agencyContext: {
|
|
1515
|
+
partnerEcosystem: ["clay", "octave", "signaliz", "instantly", "nango"]
|
|
1516
|
+
},
|
|
1517
|
+
operatingPlaybookSlugs: ["proof-first-vertical-gate", "domain-first-recovery", "table-workflow-handoff"]
|
|
1518
|
+
},
|
|
1519
|
+
{
|
|
1520
|
+
slug: "agency-founder-led",
|
|
1521
|
+
label: "Founder-Led Agency Services",
|
|
1522
|
+
aliases: ["agency founder", "founder-led agency", "agency-founder-led"],
|
|
1523
|
+
defaultTargetCount: 3e3,
|
|
1524
|
+
campaignName: "Founder-Led Agency Executive Campaign",
|
|
1525
|
+
accountContext: [
|
|
1526
|
+
"Strategy template: agency founder, owner, CEO, and executive sourcing across marketing services, creative, web, PR, ecommerce, paid media, SEO, content, and specialist digital agencies.",
|
|
1527
|
+
"Use suppression files, company-domain pool review, people/email verification queues, and final approval gates before any delivery action."
|
|
1528
|
+
].join(" "),
|
|
1529
|
+
icp: {
|
|
1530
|
+
personas: ["Founder", "Owner", "CEO", "Managing Partner", "President", "Agency Executive"],
|
|
1531
|
+
industries: [
|
|
1532
|
+
"Marketing services",
|
|
1533
|
+
"Advertising services",
|
|
1534
|
+
"Digital marketing agency",
|
|
1535
|
+
"Creative agency",
|
|
1536
|
+
"PR and communications",
|
|
1537
|
+
"Ecommerce agency",
|
|
1538
|
+
"Paid media agency",
|
|
1539
|
+
"SEO agency",
|
|
1540
|
+
"Content agency"
|
|
1541
|
+
],
|
|
1542
|
+
companySizes: ["11-50", "25-150", "51-200"],
|
|
1543
|
+
geographies: ["United States"],
|
|
1544
|
+
keywords: [
|
|
1545
|
+
"agency founder",
|
|
1546
|
+
"performance marketing",
|
|
1547
|
+
"paid media",
|
|
1548
|
+
"SEO",
|
|
1549
|
+
"content",
|
|
1550
|
+
"creative",
|
|
1551
|
+
"web design",
|
|
1552
|
+
"brand agency",
|
|
1553
|
+
"PR communications",
|
|
1554
|
+
"Shopify",
|
|
1555
|
+
"Klaviyo"
|
|
1556
|
+
],
|
|
1557
|
+
exclusions: ["enterprise holding company", "staffing", "recruiting", "software-only vendor", "freelancer-only profile"],
|
|
1558
|
+
requireVerifiedEmail: true
|
|
1559
|
+
},
|
|
1560
|
+
builtIns: ["lead_generation", "email_finding", "email_verification", "signals"],
|
|
1561
|
+
preferredProviders: ["signaliz_native", "octave"],
|
|
1562
|
+
memoryQueries: [{
|
|
1563
|
+
query: "agency founder owner CEO marketing services suppression domain pool email verification final approval gate",
|
|
1564
|
+
scopes: ["workspace", "operator_notes"],
|
|
1565
|
+
topK: 10,
|
|
1566
|
+
required: true,
|
|
1567
|
+
rationale: "Load agency-segment sourcing lanes, suppression rules, and verification workflow lessons."
|
|
1568
|
+
}],
|
|
1569
|
+
constraints: {
|
|
1570
|
+
deliverabilityNotes: [
|
|
1571
|
+
"Keep email and domain suppression visible in the plan.",
|
|
1572
|
+
"Do not export or send until the final verified file and suppression checks are approved."
|
|
1573
|
+
]
|
|
1574
|
+
},
|
|
1575
|
+
agencyContext: {
|
|
1576
|
+
partnerEcosystem: ["signaliz", "octave", "instantly", "nango"]
|
|
1577
|
+
},
|
|
1578
|
+
operatingPlaybookSlugs: ["net-new-suppressed-list", "signal-led-copy-approval", "table-workflow-handoff"]
|
|
1579
|
+
},
|
|
1580
|
+
{
|
|
1581
|
+
slug: "cloud-infrastructure-displacement",
|
|
1582
|
+
label: "Cloud Infrastructure Displacement",
|
|
1583
|
+
aliases: ["cloud displacement", "private cloud displacement", "cloud infrastructure", "cloud-infrastructure-displacement"],
|
|
1584
|
+
defaultTargetCount: 3e3,
|
|
1585
|
+
campaignName: "Cloud Infrastructure Displacement Campaign",
|
|
1586
|
+
accountContext: [
|
|
1587
|
+
"Strategy template: managed infrastructure, private cloud, disaster recovery, colocation, and VMware/Broadcom displacement motions.",
|
|
1588
|
+
"The spend-efficient ladder is Signaliz company search, Octave company qualification, Signaliz people search, Octave person qualification, then Signaliz email finding and verification."
|
|
1589
|
+
].join(" "),
|
|
1590
|
+
icp: {
|
|
1591
|
+
personas: [
|
|
1592
|
+
"CTO",
|
|
1593
|
+
"CIO",
|
|
1594
|
+
"CISO",
|
|
1595
|
+
"CFO tied to cloud spend",
|
|
1596
|
+
"VP Engineering",
|
|
1597
|
+
"VP Infrastructure",
|
|
1598
|
+
"VP Cloud",
|
|
1599
|
+
"Head of Platform",
|
|
1600
|
+
"Director IT",
|
|
1601
|
+
"Cloud Architect",
|
|
1602
|
+
"Infrastructure Architect"
|
|
1603
|
+
],
|
|
1604
|
+
industries: [
|
|
1605
|
+
"SaaS",
|
|
1606
|
+
"Software",
|
|
1607
|
+
"Cybersecurity",
|
|
1608
|
+
"Fintech",
|
|
1609
|
+
"Healthcare technology",
|
|
1610
|
+
"Compliance and GRC",
|
|
1611
|
+
"DevOps",
|
|
1612
|
+
"Infrastructure",
|
|
1613
|
+
"Observability"
|
|
1614
|
+
],
|
|
1615
|
+
companySizes: ["$10M-$500M revenue", "50-1500 employees"],
|
|
1616
|
+
geographies: ["United States"],
|
|
1617
|
+
keywords: [
|
|
1618
|
+
"VMware Broadcom",
|
|
1619
|
+
"VxRail",
|
|
1620
|
+
"cloud cost pressure",
|
|
1621
|
+
"private cloud",
|
|
1622
|
+
"Proxmox",
|
|
1623
|
+
"Hyper-V",
|
|
1624
|
+
"managed infrastructure",
|
|
1625
|
+
"DRaaS",
|
|
1626
|
+
"colocation",
|
|
1627
|
+
"uptime",
|
|
1628
|
+
"reliability"
|
|
1629
|
+
],
|
|
1630
|
+
exclusions: [
|
|
1631
|
+
"MSP competitor",
|
|
1632
|
+
"hosting provider",
|
|
1633
|
+
"data center competitor",
|
|
1634
|
+
"staffing",
|
|
1635
|
+
"recruiting",
|
|
1636
|
+
"international-only",
|
|
1637
|
+
"procurement-only",
|
|
1638
|
+
"AI GPU-heavy infrastructure"
|
|
1639
|
+
],
|
|
1640
|
+
requireVerifiedEmail: true
|
|
1641
|
+
},
|
|
1642
|
+
builtIns: ["lead_generation", "email_finding", "email_verification", "signals"],
|
|
1643
|
+
preferredProviders: ["signaliz_native", "octave"],
|
|
1644
|
+
memoryQueries: [{
|
|
1645
|
+
query: "cloud hosting infrastructure VMware Broadcom qualification verified email persona trigger SKU mapping",
|
|
1646
|
+
scopes: ["workspace", "operator_notes"],
|
|
1647
|
+
topK: 10,
|
|
1648
|
+
required: true,
|
|
1649
|
+
rationale: "Load cloud-infrastructure qualification order, persona clusters, trigger/SKU mapping, and verified-list QA rules."
|
|
1650
|
+
}],
|
|
1651
|
+
constraints: {
|
|
1652
|
+
deliverabilityNotes: [
|
|
1653
|
+
"Qualify accounts and people before email verification.",
|
|
1654
|
+
"If signal enrichment is deferred or unavailable, state it plainly instead of inventing evidence."
|
|
1655
|
+
]
|
|
1656
|
+
},
|
|
1657
|
+
signalizDefaults: {
|
|
1658
|
+
copy: {
|
|
1659
|
+
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."
|
|
1660
|
+
}
|
|
1661
|
+
},
|
|
1662
|
+
agencyContext: {
|
|
1663
|
+
partnerEcosystem: ["signaliz", "octave", "instantly", "nango"]
|
|
1664
|
+
},
|
|
1665
|
+
operatingPlaybookSlugs: ["proof-first-vertical-gate", "domain-first-recovery", "signal-led-copy-approval"]
|
|
1666
|
+
}
|
|
1667
|
+
];
|
|
1174
1668
|
var CampaignBuilderAgent = class {
|
|
1175
1669
|
constructor(client) {
|
|
1176
1670
|
this.client = client;
|
|
1177
1671
|
}
|
|
1178
1672
|
async createPlan(request, options = {}) {
|
|
1673
|
+
const resolvedRequest = applyCampaignBuilderStrategyTemplate(request);
|
|
1179
1674
|
const warnings = [];
|
|
1180
|
-
const workspaceContext =
|
|
1181
|
-
const scopeResult = options.scopeCampaign === false ? void 0 : await this.scopeCampaign(
|
|
1675
|
+
const workspaceContext = resolvedRequest.workspaceContext ?? await this.getWorkspaceContext(warnings);
|
|
1676
|
+
const scopeResult = options.scopeCampaign === false ? void 0 : await this.scopeCampaign(resolvedRequest, warnings);
|
|
1182
1677
|
if (options.discoverCapabilities !== false) {
|
|
1183
|
-
await this.discoverPlannedRoutes(
|
|
1678
|
+
await this.discoverPlannedRoutes(resolvedRequest, warnings);
|
|
1184
1679
|
}
|
|
1185
|
-
|
|
1680
|
+
const plan = createCampaignBuilderAgentPlan(resolvedRequest, {
|
|
1186
1681
|
workspaceContext,
|
|
1187
1682
|
scopeBuildArgs: asRecord(scopeResult?.build_campaign_args ?? scopeResult?.buildCampaignArgs),
|
|
1188
1683
|
warnings
|
|
1189
1684
|
});
|
|
1685
|
+
if (options.includeStrategyMemoryStatus !== false) {
|
|
1686
|
+
await this.attachStrategyMemoryStatus(plan, warnings);
|
|
1687
|
+
}
|
|
1688
|
+
if (options.includeKernelPlan !== false) {
|
|
1689
|
+
await this.attachKernelCampaignBuildPlan(plan, warnings);
|
|
1690
|
+
}
|
|
1691
|
+
if (options.includeDeliveryRisk !== false) {
|
|
1692
|
+
await this.attachDeliveryRiskPreflight(plan, warnings);
|
|
1693
|
+
}
|
|
1694
|
+
return plan;
|
|
1695
|
+
}
|
|
1696
|
+
async commitPlan(plan, options = {}) {
|
|
1697
|
+
const writeMode = options.confirm === true && options.dryRun === false;
|
|
1698
|
+
if (writeMode && !options.approvedBy) {
|
|
1699
|
+
throw new Error("Campaign builder plan commit requires approvedBy before writing state");
|
|
1700
|
+
}
|
|
1701
|
+
const plannerStep = plan.mcpFlow.find((step) => step.id === "agency-campaign-build-plan");
|
|
1702
|
+
const plannerArgs = asRecord(plannerStep?.arguments);
|
|
1703
|
+
const commitArgs = compact({
|
|
1704
|
+
campaign_id: plan.buildRequest.gtmCampaignId,
|
|
1705
|
+
name: plan.campaignName,
|
|
1706
|
+
campaign_brief: plan.buildRequest.prompt || plan.goal,
|
|
1707
|
+
target_icp: plan.buildRequest.icp ? buildGtmTargetIcpContext(plan.buildRequest.icp) : void 0,
|
|
1708
|
+
lead_count: plan.targetCount,
|
|
1709
|
+
layers: plannerArgs.layers,
|
|
1710
|
+
preferred_providers: plannerArgs.preferred_providers,
|
|
1711
|
+
plan_snapshot: Object.keys(asRecord(plan.kernelPlan)).length > 0 ? plan.kernelPlan : buildFallbackPlanSnapshot(plan),
|
|
1712
|
+
send_config: plan.buildRequest.delivery ? {
|
|
1713
|
+
delivery: plan.buildRequest.delivery,
|
|
1714
|
+
approval_required: true
|
|
1715
|
+
} : void 0,
|
|
1716
|
+
brain_config: compact({
|
|
1717
|
+
campaign_builder_agent_v1: {
|
|
1718
|
+
plan_id: plan.planId,
|
|
1719
|
+
kernel_plan_attached: Object.keys(asRecord(plan.kernelPlan)).length > 0,
|
|
1720
|
+
approval_ids: plan.approvals.map((approval) => approval.id)
|
|
1721
|
+
},
|
|
1722
|
+
brain_defaults: plan.buildRequest.brainDefaults,
|
|
1723
|
+
brain_preflight: plan.buildRequest.brainPreflight,
|
|
1724
|
+
delivery_risk_preflight: plan.buildRequest.deliveryRisk,
|
|
1725
|
+
delivery_risk: plan.buildRequest.deliveryRisk
|
|
1726
|
+
}),
|
|
1727
|
+
metadata: {
|
|
1728
|
+
campaign_builder_agent_v1: {
|
|
1729
|
+
plan_id: plan.planId,
|
|
1730
|
+
source: "campaign-builder-agent",
|
|
1731
|
+
approval_required: plan.approvals.some((approval) => approval.blocking),
|
|
1732
|
+
approval_ids: plan.approvals.map((approval) => approval.id),
|
|
1733
|
+
estimated_credits: plan.estimatedCredits
|
|
1734
|
+
},
|
|
1735
|
+
brain_delivery_risk_preflight: plan.buildRequest.deliveryRisk,
|
|
1736
|
+
delivery_risk: plan.buildRequest.deliveryRisk
|
|
1737
|
+
},
|
|
1738
|
+
approval_required: plan.approvals.some((approval) => approval.blocking),
|
|
1739
|
+
actor_type: "agent",
|
|
1740
|
+
actor_id: options.approvedBy,
|
|
1741
|
+
rationale: options.rationale || "Committed a reviewed strategy-template campaign-builder plan before execution.",
|
|
1742
|
+
idempotency_key: options.idempotencyKey,
|
|
1743
|
+
dry_run: !writeMode,
|
|
1744
|
+
confirm: writeMode
|
|
1745
|
+
});
|
|
1746
|
+
const data = asRecord(await this.callMcp("gtm_campaign_build_plan_commit", commitArgs));
|
|
1747
|
+
const result = mapPlanCommitResult(data);
|
|
1748
|
+
if (result.wroteState && result.campaignId) {
|
|
1749
|
+
plan.buildRequest.gtmCampaignId = result.campaignId;
|
|
1750
|
+
refreshBuildStepArguments(plan);
|
|
1751
|
+
}
|
|
1752
|
+
return result;
|
|
1190
1753
|
}
|
|
1191
1754
|
async dryRunPlan(plan, options) {
|
|
1192
1755
|
let args = buildCampaignArgs({
|
|
@@ -1221,6 +1784,15 @@ var CampaignBuilderAgent = class {
|
|
|
1221
1784
|
if (missing.length > 0) {
|
|
1222
1785
|
throw new Error(`Campaign builder approval is incomplete: ${missing.map((a) => a.label).join(", ")}`);
|
|
1223
1786
|
}
|
|
1787
|
+
if (options?.commitBeforeLaunch && !plan.buildRequest.gtmCampaignId) {
|
|
1788
|
+
await this.commitPlan(plan, {
|
|
1789
|
+
confirm: true,
|
|
1790
|
+
dryRun: false,
|
|
1791
|
+
approvedBy: approval.approvedBy,
|
|
1792
|
+
idempotencyKey: options.idempotencyKey ? `${options.idempotencyKey}:plan-commit` : void 0,
|
|
1793
|
+
rationale: "Committed reviewed campaign-builder plan immediately before approved launch."
|
|
1794
|
+
});
|
|
1795
|
+
}
|
|
1224
1796
|
let args = buildCampaignArgs({
|
|
1225
1797
|
...plan.buildRequest,
|
|
1226
1798
|
dryRun: false,
|
|
@@ -1267,8 +1839,8 @@ var CampaignBuilderAgent = class {
|
|
|
1267
1839
|
try {
|
|
1268
1840
|
return await this.callMcp("scope_campaign", {
|
|
1269
1841
|
prompt: request.goal,
|
|
1270
|
-
|
|
1271
|
-
|
|
1842
|
+
account_label: campaignBuilderAccountLabel(request),
|
|
1843
|
+
account_context: campaignBuilderAccountContext(request),
|
|
1272
1844
|
campaign_goal: request.goal,
|
|
1273
1845
|
target_count: request.targetCount,
|
|
1274
1846
|
approval_policy: request.approvalPolicy?.requireHumanApproval ? "human_required" : "standard"
|
|
@@ -1293,25 +1865,70 @@ var CampaignBuilderAgent = class {
|
|
|
1293
1865
|
}
|
|
1294
1866
|
}
|
|
1295
1867
|
}
|
|
1868
|
+
async attachStrategyMemoryStatus(plan, warnings) {
|
|
1869
|
+
const statusStep = plan.mcpFlow.find((step) => step.id === "strategy-memory-status");
|
|
1870
|
+
if (!statusStep) return;
|
|
1871
|
+
try {
|
|
1872
|
+
const status = asRecord(await this.callMcp("gtm_campaign_strategy_memory_status", asRecord(statusStep.arguments)));
|
|
1873
|
+
plan.strategyMemoryStatus = status;
|
|
1874
|
+
const blockers = arrayOfStrings(status.blockers) ?? [];
|
|
1875
|
+
if (status.ready === false || blockers.length > 0) {
|
|
1876
|
+
warnings.push(`Strategy memory readiness is incomplete: ${blockers.join("; ") || "missing required strategy or workflow memory"}`);
|
|
1877
|
+
}
|
|
1878
|
+
} catch (error) {
|
|
1879
|
+
warnings.push(`Strategy memory readiness check failed: ${errorMessage(error)}`);
|
|
1880
|
+
}
|
|
1881
|
+
}
|
|
1882
|
+
async attachKernelCampaignBuildPlan(plan, warnings) {
|
|
1883
|
+
const plannerStep = plan.mcpFlow.find((step) => step.id === "agency-campaign-build-plan");
|
|
1884
|
+
if (!plannerStep) return;
|
|
1885
|
+
try {
|
|
1886
|
+
const kernelPlan = await this.callMcp("gtm_campaign_build_plan", asRecord(plannerStep.arguments));
|
|
1887
|
+
plan.kernelPlan = asRecord(kernelPlan);
|
|
1888
|
+
const brainDefaults = asRecord(plan.kernelPlan.brain_defaults ?? plan.kernelPlan.brainDefaults);
|
|
1889
|
+
if (Object.keys(brainDefaults).length > 0 && Object.keys(asRecord(plan.buildRequest.brainDefaults)).length === 0) {
|
|
1890
|
+
plan.buildRequest.brainDefaults = brainDefaults;
|
|
1891
|
+
refreshBuildStepArguments(plan);
|
|
1892
|
+
}
|
|
1893
|
+
} catch (error) {
|
|
1894
|
+
warnings.push(`GTM Kernel campaign build plan failed: ${errorMessage(error)}`);
|
|
1895
|
+
}
|
|
1896
|
+
}
|
|
1897
|
+
async attachDeliveryRiskPreflight(plan, warnings) {
|
|
1898
|
+
if (Object.keys(asRecord(plan.buildRequest.deliveryRisk)).length > 0) return;
|
|
1899
|
+
const riskStep = plan.mcpFlow.find((step) => step.tool === "gtm_brain_delivery_risk");
|
|
1900
|
+
if (!riskStep) return;
|
|
1901
|
+
try {
|
|
1902
|
+
const deliveryRisk = asRecord(await this.callMcp("gtm_brain_delivery_risk", asRecord(riskStep.arguments)));
|
|
1903
|
+
if (Object.keys(deliveryRisk).length > 0) {
|
|
1904
|
+
plan.buildRequest.deliveryRisk = deliveryRisk;
|
|
1905
|
+
refreshBuildStepArguments(plan);
|
|
1906
|
+
}
|
|
1907
|
+
} catch (error) {
|
|
1908
|
+
warnings.push(`GTM Brain delivery risk preflight failed: ${errorMessage(error)}`);
|
|
1909
|
+
}
|
|
1910
|
+
}
|
|
1296
1911
|
async callMcp(tool, args) {
|
|
1297
1912
|
return this.client.mcp("tools/call", { name: tool, arguments: compact(args) });
|
|
1298
1913
|
}
|
|
1299
1914
|
};
|
|
1300
1915
|
function createCampaignBuilderAgentPlan(request, context = {}) {
|
|
1301
|
-
const
|
|
1302
|
-
const
|
|
1303
|
-
const
|
|
1304
|
-
const
|
|
1305
|
-
const
|
|
1306
|
-
const
|
|
1307
|
-
const
|
|
1308
|
-
const
|
|
1916
|
+
const resolvedRequest = applyCampaignBuilderStrategyTemplate(request);
|
|
1917
|
+
const defaults = mergeDefaults(resolvedRequest.signalizDefaults);
|
|
1918
|
+
const targetCount = resolvedRequest.targetCount ?? numberOrUndefined2(context.scopeBuildArgs?.target_count) ?? 100;
|
|
1919
|
+
const campaignName = resolvedRequest.campaignName ?? stringValue(context.scopeBuildArgs?.name) ?? titleFromGoal(resolvedRequest.goal);
|
|
1920
|
+
const workspaceContext = context.workspaceContext ?? resolvedRequest.workspaceContext ?? {};
|
|
1921
|
+
const memory = normalizeMemory(resolvedRequest);
|
|
1922
|
+
const routes = normalizeRoutes(resolvedRequest);
|
|
1923
|
+
const operatingPlaybooks = getCampaignBuilderOperatingPlaybooksForRequest(resolvedRequest);
|
|
1924
|
+
const estimatedCredits = estimateCredits(resolvedRequest, defaults, targetCount);
|
|
1925
|
+
const buildRequest = createBuildRequest(resolvedRequest, defaults, targetCount, campaignName, context.scopeBuildArgs, routes, memory, context.scopeBrainPreflight);
|
|
1309
1926
|
const brainPreflight = asRecord(buildRequest.brainPreflight);
|
|
1310
|
-
const approvals = deriveApprovals(
|
|
1927
|
+
const approvals = deriveApprovals(resolvedRequest, routes, memory, estimatedCredits, defaults.delivery?.approvalRequired !== false);
|
|
1311
1928
|
return {
|
|
1312
|
-
planId: `cbp_${hashString(JSON.stringify({ goal:
|
|
1929
|
+
planId: `cbp_${hashString(JSON.stringify({ goal: resolvedRequest.goal, campaignName, targetCount, routes }))}`,
|
|
1313
1930
|
campaignName,
|
|
1314
|
-
goal:
|
|
1931
|
+
goal: resolvedRequest.goal,
|
|
1315
1932
|
targetCount,
|
|
1316
1933
|
workspaceContext,
|
|
1317
1934
|
memory,
|
|
@@ -1324,7 +1941,8 @@ function createCampaignBuilderAgentPlan(request, context = {}) {
|
|
|
1324
1941
|
approvals,
|
|
1325
1942
|
buildRequest,
|
|
1326
1943
|
brainPreflight,
|
|
1327
|
-
|
|
1944
|
+
operatingPlaybooks,
|
|
1945
|
+
mcpFlow: createMcpFlow(resolvedRequest, buildRequest, routes, memory, approvals),
|
|
1328
1946
|
estimatedCredits,
|
|
1329
1947
|
warnings: context.warnings ?? []
|
|
1330
1948
|
};
|
|
@@ -1345,6 +1963,256 @@ function getMissingCampaignBuilderApprovals(plan, approval) {
|
|
|
1345
1963
|
return false;
|
|
1346
1964
|
});
|
|
1347
1965
|
}
|
|
1966
|
+
function createCampaignBuilderApproval(plan, input) {
|
|
1967
|
+
return {
|
|
1968
|
+
...input,
|
|
1969
|
+
planId: plan.planId,
|
|
1970
|
+
approvedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1971
|
+
};
|
|
1972
|
+
}
|
|
1973
|
+
function getCampaignBuilderStrategyTemplate(value) {
|
|
1974
|
+
const normalized = normalizeTemplateKey(value);
|
|
1975
|
+
if (!normalized) return void 0;
|
|
1976
|
+
return CAMPAIGN_BUILDER_STRATEGY_TEMPLATES.find(
|
|
1977
|
+
(template) => template.slug === normalized || template.aliases.some((alias) => normalizeTemplateKey(alias) === normalized)
|
|
1978
|
+
);
|
|
1979
|
+
}
|
|
1980
|
+
function getCampaignBuilderOperatingPlaybook(value) {
|
|
1981
|
+
const normalized = normalizeTemplateKey(value);
|
|
1982
|
+
if (!normalized) return void 0;
|
|
1983
|
+
return CAMPAIGN_BUILDER_OPERATING_PLAYBOOKS.find((playbook) => playbook.slug === normalized);
|
|
1984
|
+
}
|
|
1985
|
+
function getCampaignBuilderOperatingPlaybooksForRequest(request) {
|
|
1986
|
+
const template = getCampaignBuilderStrategyTemplate(request.strategyTemplate);
|
|
1987
|
+
const slugs = uniqueStrings([
|
|
1988
|
+
...template?.operatingPlaybookSlugs ?? [],
|
|
1989
|
+
...request.operatingPlaybooks ?? []
|
|
1990
|
+
]);
|
|
1991
|
+
return slugs.map(getCampaignBuilderOperatingPlaybook).filter((playbook) => Boolean(playbook));
|
|
1992
|
+
}
|
|
1993
|
+
function applyCampaignBuilderStrategyTemplate(request) {
|
|
1994
|
+
const template = getCampaignBuilderStrategyTemplate(request.strategyTemplate);
|
|
1995
|
+
if (!template) return request;
|
|
1996
|
+
return {
|
|
1997
|
+
...request,
|
|
1998
|
+
strategyTemplate: template.slug,
|
|
1999
|
+
campaignName: request.campaignName ?? template.campaignName,
|
|
2000
|
+
accountContext: mergeText(template.accountContext, campaignBuilderAccountContext(request)),
|
|
2001
|
+
targetCount: request.targetCount ?? template.defaultTargetCount,
|
|
2002
|
+
icp: mergeIcp(template.icp, request.icp),
|
|
2003
|
+
builtIns: request.builtIns ?? template.builtIns,
|
|
2004
|
+
operatingPlaybooks: uniqueStrings([
|
|
2005
|
+
...template.operatingPlaybookSlugs,
|
|
2006
|
+
...request.operatingPlaybooks ?? []
|
|
2007
|
+
]),
|
|
2008
|
+
preferredProviders: uniqueStrings([
|
|
2009
|
+
...template.preferredProviders,
|
|
2010
|
+
...request.preferredProviders ?? []
|
|
2011
|
+
]),
|
|
2012
|
+
memory: mergeMemoryPlan({
|
|
2013
|
+
enabled: true,
|
|
2014
|
+
useWorkspaceHistory: true,
|
|
2015
|
+
useNetworkPatterns: request.memory?.useNetworkPatterns,
|
|
2016
|
+
privacyMode: request.memory?.privacyMode,
|
|
2017
|
+
queries: template.memoryQueries
|
|
2018
|
+
}, request.memory),
|
|
2019
|
+
constraints: mergeConstraints(template.constraints, request.constraints),
|
|
2020
|
+
signalizDefaults: mergeSignalizDefaultOverrides(template.signalizDefaults, request.signalizDefaults),
|
|
2021
|
+
agencyContext: mergeAgencyContext(template.agencyContext, request.agencyContext)
|
|
2022
|
+
};
|
|
2023
|
+
}
|
|
2024
|
+
function createCampaignBuilderAgentRequestTemplate(input = {}) {
|
|
2025
|
+
const builtIns = new Set(input.builtIns ?? DEFAULT_CAMPAIGN_BUILDER_BUILT_INS);
|
|
2026
|
+
if (input.includeLocalLeads) builtIns.add("local_leads");
|
|
2027
|
+
const integrations = input.integrations ?? (input.includeCustomToolPlaceholder ? [createCampaignBuilderToolRoute({
|
|
2028
|
+
provider: "custom_mcp",
|
|
2029
|
+
layer: "enrichment",
|
|
2030
|
+
gtmLayers: ["company_enrichment"],
|
|
2031
|
+
toolName: "workspace_enrich",
|
|
2032
|
+
mcpServerName: "workspace-mcp",
|
|
2033
|
+
label: "Workspace enrichment MCP",
|
|
2034
|
+
mode: "if_available",
|
|
2035
|
+
approvalRequired: true
|
|
2036
|
+
})] : void 0);
|
|
2037
|
+
const preferredProviders = uniqueStrings([
|
|
2038
|
+
...input.preferredProviders ?? [],
|
|
2039
|
+
...input.includeNango === false ? [] : ["nango"]
|
|
2040
|
+
]);
|
|
2041
|
+
const templated = applyCampaignBuilderStrategyTemplate({
|
|
2042
|
+
goal: input.goal || "Build a strategy-template campaign for mature operators in the target ICP.",
|
|
2043
|
+
strategyTemplate: input.strategyTemplate || "non-medical-home-care",
|
|
2044
|
+
campaignName: input.campaignName,
|
|
2045
|
+
accountLabel: input.accountLabel || "Workspace Campaign",
|
|
2046
|
+
accountContext: input.accountContext || "Use private workspace memory, current suppression rules, verified-email quality gates, and approval-gated provider routes.",
|
|
2047
|
+
targetCount: input.targetCount,
|
|
2048
|
+
icp: input.icp ?? {
|
|
2049
|
+
personas: ["Operations leader", "Founder", "Revenue leader"],
|
|
2050
|
+
industries: ["B2B services", "Vertical software", "Local operators"],
|
|
2051
|
+
geographies: ["United States"],
|
|
2052
|
+
keywords: ["growth", "operations", "customer acquisition"],
|
|
2053
|
+
requireVerifiedEmail: true
|
|
2054
|
+
},
|
|
2055
|
+
builtIns: [...builtIns],
|
|
2056
|
+
integrations,
|
|
2057
|
+
customerTools: input.customerTools,
|
|
2058
|
+
preferredProviders,
|
|
2059
|
+
constraints: input.constraints,
|
|
2060
|
+
workspaceContext: input.workspaceContext,
|
|
2061
|
+
brainDefaults: input.brainDefaults,
|
|
2062
|
+
deliveryRisk: input.deliveryRisk,
|
|
2063
|
+
gtmCampaignId: input.gtmCampaignId
|
|
2064
|
+
});
|
|
2065
|
+
return compact({
|
|
2066
|
+
...templated,
|
|
2067
|
+
memory: mergeMemoryPlan({
|
|
2068
|
+
enabled: true,
|
|
2069
|
+
useWorkspaceHistory: true,
|
|
2070
|
+
useNetworkPatterns: false,
|
|
2071
|
+
privacyMode: "anonymized_patterns",
|
|
2072
|
+
queries: [{
|
|
2073
|
+
query: `${templated.strategyTemplate || "strategy-template"} campaign reply patterns, objections, qualification gates, and verified-email QA`,
|
|
2074
|
+
scopes: ["workspace", "operator_notes"],
|
|
2075
|
+
topK: 10,
|
|
2076
|
+
required: true,
|
|
2077
|
+
rationale: "Load approved private strategy and workflow patterns before campaign planning."
|
|
2078
|
+
}]
|
|
2079
|
+
}, input.memory),
|
|
2080
|
+
agencyContext: mergeAgencyContext({
|
|
2081
|
+
strategyModel: "strategy_template",
|
|
2082
|
+
includeStrategyPatterns: true,
|
|
2083
|
+
includeWorkflowPatterns: true,
|
|
2084
|
+
includeNangoCatalog: true,
|
|
2085
|
+
partnerEcosystem: input.includeNango === false ? ["signaliz"] : ["signaliz", "nango"]
|
|
2086
|
+
}, input.agencyContext),
|
|
2087
|
+
signalizDefaults: mergeSignalizDefaultOverrides({
|
|
2088
|
+
maxCredits: input.signalizDefaults?.maxCredits,
|
|
2089
|
+
delivery: {
|
|
2090
|
+
enabled: true,
|
|
2091
|
+
destinationType: input.signalizDefaults?.delivery?.destinationType ?? "json",
|
|
2092
|
+
approvalRequired: true
|
|
2093
|
+
}
|
|
2094
|
+
}, input.signalizDefaults),
|
|
2095
|
+
approvalPolicy: {
|
|
2096
|
+
requireHumanApproval: true,
|
|
2097
|
+
maxCreditsWithoutApproval: 0,
|
|
2098
|
+
requireApprovalFor: DEFAULT_CAMPAIGN_BUILDER_APPROVAL_TYPES,
|
|
2099
|
+
...input.approvalPolicy
|
|
2100
|
+
}
|
|
2101
|
+
});
|
|
2102
|
+
}
|
|
2103
|
+
function createCampaignBuilderToolRoute(input) {
|
|
2104
|
+
return {
|
|
2105
|
+
provider: input.provider ?? "custom_mcp",
|
|
2106
|
+
layer: input.layer,
|
|
2107
|
+
toolName: input.toolName,
|
|
2108
|
+
mcpServerName: input.mcpServerName,
|
|
2109
|
+
label: input.label,
|
|
2110
|
+
mode: input.mode ?? "if_available",
|
|
2111
|
+
gtmLayer: input.gtmLayer,
|
|
2112
|
+
gtmLayers: input.gtmLayers,
|
|
2113
|
+
approvalRequired: input.approvalRequired ?? input.mode === "required",
|
|
2114
|
+
config: input.config,
|
|
2115
|
+
rationale: `${input.label ?? input.provider ?? "Custom tool"} is a user-provided campaign-builder route for ${input.layer}.`
|
|
2116
|
+
};
|
|
2117
|
+
}
|
|
2118
|
+
function normalizeTemplateKey(value) {
|
|
2119
|
+
return String(value || "").trim().toLowerCase().replace(/[_\s]+/g, "-");
|
|
2120
|
+
}
|
|
2121
|
+
function mergeText(base, override) {
|
|
2122
|
+
if (base && override && !base.includes(override)) return `${base}
|
|
2123
|
+
${override}`;
|
|
2124
|
+
return override ?? base;
|
|
2125
|
+
}
|
|
2126
|
+
function mergeIcp(base, override) {
|
|
2127
|
+
if (!base) return override;
|
|
2128
|
+
if (!override) return base;
|
|
2129
|
+
return {
|
|
2130
|
+
...base,
|
|
2131
|
+
...override,
|
|
2132
|
+
personas: uniqueStrings([...base.personas ?? [], ...override.personas ?? []]),
|
|
2133
|
+
industries: uniqueStrings([...base.industries ?? [], ...override.industries ?? []]),
|
|
2134
|
+
companySizes: uniqueStrings([...base.companySizes ?? [], ...override.companySizes ?? []]),
|
|
2135
|
+
geographies: uniqueStrings([...base.geographies ?? [], ...override.geographies ?? []]),
|
|
2136
|
+
keywords: uniqueStrings([...base.keywords ?? [], ...override.keywords ?? []]),
|
|
2137
|
+
exclusions: uniqueStrings([...base.exclusions ?? [], ...override.exclusions ?? []]),
|
|
2138
|
+
requireVerifiedEmail: override.requireVerifiedEmail ?? base.requireVerifiedEmail
|
|
2139
|
+
};
|
|
2140
|
+
}
|
|
2141
|
+
function mergeMemoryPlan(base, override) {
|
|
2142
|
+
const queries = dedupeMemoryQueries([...base.queries ?? [], ...override?.queries ?? []]);
|
|
2143
|
+
return {
|
|
2144
|
+
...base,
|
|
2145
|
+
...override,
|
|
2146
|
+
queries: queries.length > 0 ? queries : void 0,
|
|
2147
|
+
enabled: override?.enabled ?? base.enabled,
|
|
2148
|
+
useWorkspaceHistory: override?.useWorkspaceHistory ?? base.useWorkspaceHistory,
|
|
2149
|
+
useNetworkPatterns: override?.useNetworkPatterns ?? base.useNetworkPatterns,
|
|
2150
|
+
privacyMode: override?.privacyMode ?? base.privacyMode
|
|
2151
|
+
};
|
|
2152
|
+
}
|
|
2153
|
+
function dedupeMemoryQueries(queries) {
|
|
2154
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2155
|
+
return queries.filter((query) => {
|
|
2156
|
+
const key = query.query.trim().toLowerCase();
|
|
2157
|
+
if (!key || seen.has(key)) return false;
|
|
2158
|
+
seen.add(key);
|
|
2159
|
+
return true;
|
|
2160
|
+
});
|
|
2161
|
+
}
|
|
2162
|
+
function mergeConstraints(base, override) {
|
|
2163
|
+
if (!base) return override;
|
|
2164
|
+
if (!override) return base;
|
|
2165
|
+
return {
|
|
2166
|
+
...base,
|
|
2167
|
+
...override,
|
|
2168
|
+
geographies: uniqueStrings([...base.geographies ?? [], ...override.geographies ?? []]),
|
|
2169
|
+
exclusions: uniqueStrings([...base.exclusions ?? [], ...override.exclusions ?? []]),
|
|
2170
|
+
deliverabilityNotes: uniqueStrings([...base.deliverabilityNotes ?? [], ...override.deliverabilityNotes ?? []]),
|
|
2171
|
+
maxDailySends: override.maxDailySends ?? base.maxDailySends
|
|
2172
|
+
};
|
|
2173
|
+
}
|
|
2174
|
+
function mergeSignalizDefaultOverrides(base, override) {
|
|
2175
|
+
if (!base) return override;
|
|
2176
|
+
if (!override) return base;
|
|
2177
|
+
return {
|
|
2178
|
+
...base,
|
|
2179
|
+
...override,
|
|
2180
|
+
signals: { ...base.signals, ...override.signals },
|
|
2181
|
+
qualification: { ...base.qualification, ...override.qualification },
|
|
2182
|
+
copy: { ...base.copy, ...override.copy },
|
|
2183
|
+
delivery: { ...base.delivery, ...override.delivery }
|
|
2184
|
+
};
|
|
2185
|
+
}
|
|
2186
|
+
function mergeAgencyContext(base, override) {
|
|
2187
|
+
if (!base) return override;
|
|
2188
|
+
if (!override) return base;
|
|
2189
|
+
return {
|
|
2190
|
+
...base,
|
|
2191
|
+
...override,
|
|
2192
|
+
partnerEcosystem: uniqueStrings([...base.partnerEcosystem ?? [], ...override.partnerEcosystem ?? []]),
|
|
2193
|
+
strategyModel: override.strategyModel ?? base.strategyModel,
|
|
2194
|
+
includeStrategyPatterns: override.includeStrategyPatterns ?? base.includeStrategyPatterns,
|
|
2195
|
+
includeWorkflowPatterns: override.includeWorkflowPatterns ?? base.includeWorkflowPatterns,
|
|
2196
|
+
includeClayPatterns: override.includeClayPatterns ?? base.includeClayPatterns,
|
|
2197
|
+
includeNangoCatalog: override.includeNangoCatalog ?? base.includeNangoCatalog,
|
|
2198
|
+
revenueMotion: override.revenueMotion ?? base.revenueMotion
|
|
2199
|
+
};
|
|
2200
|
+
}
|
|
2201
|
+
function campaignBuilderStrategyModel(agencyContext) {
|
|
2202
|
+
return agencyContext?.strategyModel ?? "strategy_template";
|
|
2203
|
+
}
|
|
2204
|
+
function campaignBuilderStrategyPatternsEnabled(agencyContext) {
|
|
2205
|
+
return agencyContext?.includeStrategyPatterns ?? true;
|
|
2206
|
+
}
|
|
2207
|
+
function campaignBuilderWorkflowPatternsEnabled(agencyContext) {
|
|
2208
|
+
return agencyContext?.includeWorkflowPatterns ?? agencyContext?.includeClayPatterns ?? true;
|
|
2209
|
+
}
|
|
2210
|
+
function campaignBuilderAccountLabel(request) {
|
|
2211
|
+
return request.accountLabel;
|
|
2212
|
+
}
|
|
2213
|
+
function campaignBuilderAccountContext(request) {
|
|
2214
|
+
return request.accountContext;
|
|
2215
|
+
}
|
|
1348
2216
|
function mergeDefaults(overrides) {
|
|
1349
2217
|
return {
|
|
1350
2218
|
...DEFAULT_SIGNALIZ_CAMPAIGN_BUILDER_DEFAULTS,
|
|
@@ -1357,12 +2225,9 @@ function mergeDefaults(overrides) {
|
|
|
1357
2225
|
}
|
|
1358
2226
|
function normalizeMemory(request) {
|
|
1359
2227
|
const configured = request.memory ?? {};
|
|
1360
|
-
const
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
topK: 8,
|
|
1364
|
-
rationale: "Seed the campaign plan with prior ICP, angle, source, and reply-performance patterns."
|
|
1365
|
-
}];
|
|
2228
|
+
const defaultQueries = defaultAgencyMemoryQueries(request, configured);
|
|
2229
|
+
const configuredQueries = configured.queries ?? [];
|
|
2230
|
+
const queries = configuredQueries.length > 0 ? request.strategyTemplate ? dedupeMemoryQueries([...configuredQueries, ...defaultQueries]) : configuredQueries : defaultQueries;
|
|
1366
2231
|
return {
|
|
1367
2232
|
enabled: configured.enabled !== false,
|
|
1368
2233
|
queries,
|
|
@@ -1371,40 +2236,130 @@ function normalizeMemory(request) {
|
|
|
1371
2236
|
privacyMode: configured.privacyMode ?? (configured.useNetworkPatterns ? "anonymized_patterns" : "workspace_only")
|
|
1372
2237
|
};
|
|
1373
2238
|
}
|
|
2239
|
+
function defaultAgencyMemoryQueries(request, configured) {
|
|
2240
|
+
const operatingPlaybookTerms = getCampaignBuilderOperatingPlaybooksForRequest(request).flatMap((playbook) => [playbook.label, ...playbook.memoryKeywords]).join(" ");
|
|
2241
|
+
const queries = [{
|
|
2242
|
+
query: request.goal,
|
|
2243
|
+
scopes: ["workspace", configured.useNetworkPatterns ? "network_patterns" : "operator_notes"],
|
|
2244
|
+
topK: 8,
|
|
2245
|
+
rationale: "Seed the campaign plan with prior ICP, angle, source, and reply-performance patterns."
|
|
2246
|
+
}];
|
|
2247
|
+
if (campaignBuilderStrategyModel(request.agencyContext) !== "custom" && campaignBuilderStrategyPatternsEnabled(request.agencyContext)) {
|
|
2248
|
+
queries.push({
|
|
2249
|
+
query: [
|
|
2250
|
+
"Private campaign strategy pattern library prior campaign casebook",
|
|
2251
|
+
campaignBuilderAccountLabel(request),
|
|
2252
|
+
operatingPlaybookTerms,
|
|
2253
|
+
request.goal
|
|
2254
|
+
].filter(Boolean).join(" "),
|
|
2255
|
+
scopes: ["workspace", "operator_notes"],
|
|
2256
|
+
topK: 8,
|
|
2257
|
+
required: true,
|
|
2258
|
+
rationale: "Anchor the plan in private strategy learnings from prior industrial, healthcare, agency-services, infrastructure, recruiting, media, and integration builds."
|
|
2259
|
+
});
|
|
2260
|
+
}
|
|
2261
|
+
if (campaignBuilderWorkflowPatternsEnabled(request.agencyContext)) {
|
|
2262
|
+
queries.push({
|
|
2263
|
+
query: [
|
|
2264
|
+
"Workflow table architecture enrichment qualification copy export gates",
|
|
2265
|
+
request.goal
|
|
2266
|
+
].filter(Boolean).join(" "),
|
|
2267
|
+
scopes: ["workspace", "operator_notes"],
|
|
2268
|
+
topK: 6,
|
|
2269
|
+
rationale: "Pull workflow patterns for source tables, enrichment order, qualification gates, and handoff controls."
|
|
2270
|
+
});
|
|
2271
|
+
}
|
|
2272
|
+
return queries;
|
|
2273
|
+
}
|
|
1374
2274
|
function normalizeRoutes(request) {
|
|
1375
|
-
const routes =
|
|
1376
|
-
|
|
1377
|
-
|
|
2275
|
+
const routes = builtInRoutesFor(request);
|
|
2276
|
+
routes.push(...routesFromCustomerTools(request.customerTools ?? []));
|
|
2277
|
+
routes.push(...request.integrations ?? []);
|
|
2278
|
+
return routes.map((route, index) => ({
|
|
2279
|
+
...route,
|
|
2280
|
+
id: route.id ?? `${route.provider}-${route.layer}-${index + 1}`,
|
|
2281
|
+
mode: route.mode ?? "if_available"
|
|
2282
|
+
}));
|
|
2283
|
+
}
|
|
2284
|
+
function builtInRoutesFor(request) {
|
|
2285
|
+
const builtIns = new Set(normalizeBuiltIns(request));
|
|
2286
|
+
const routes = [];
|
|
2287
|
+
if (builtIns.has("lead_generation")) {
|
|
2288
|
+
routes.push({
|
|
2289
|
+
id: "signaliz-lead-generation",
|
|
1378
2290
|
layer: "source",
|
|
2291
|
+
gtmLayers: ["find_company", "find_people", "lead_generation"],
|
|
1379
2292
|
provider: "signaliz",
|
|
1380
2293
|
mode: "required",
|
|
1381
2294
|
toolName: "generate_leads",
|
|
1382
2295
|
rationale: "Use Signaliz fresh workspace acquisition as the default source of truth."
|
|
1383
|
-
}
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
2296
|
+
});
|
|
2297
|
+
}
|
|
2298
|
+
if (builtIns.has("local_leads")) {
|
|
2299
|
+
routes.push({
|
|
2300
|
+
id: "signaliz-local-leads",
|
|
2301
|
+
layer: "source",
|
|
2302
|
+
gtmLayer: "local_leads",
|
|
2303
|
+
provider: "signaliz",
|
|
2304
|
+
mode: "if_available",
|
|
2305
|
+
toolName: "generate_local_leads",
|
|
2306
|
+
rationale: "Use Signaliz local-leads sourcing for geography-bound local business campaigns."
|
|
2307
|
+
});
|
|
2308
|
+
}
|
|
2309
|
+
if (builtIns.has("email_finding")) {
|
|
2310
|
+
routes.push({
|
|
2311
|
+
id: "signaliz-email-finding",
|
|
2312
|
+
layer: "enrichment",
|
|
2313
|
+
gtmLayer: "email_finding",
|
|
1387
2314
|
provider: "signaliz",
|
|
1388
2315
|
mode: "required",
|
|
1389
2316
|
toolName: "find_and_verify_emails",
|
|
2317
|
+
rationale: "Find contact emails before verification and campaign handoff."
|
|
2318
|
+
});
|
|
2319
|
+
}
|
|
2320
|
+
if (builtIns.has("email_verification")) {
|
|
2321
|
+
routes.push({
|
|
2322
|
+
id: "signaliz-email-verification",
|
|
2323
|
+
layer: "qualification",
|
|
2324
|
+
gtmLayer: "email_verification",
|
|
2325
|
+
provider: "signaliz",
|
|
2326
|
+
mode: "required",
|
|
2327
|
+
toolName: "verify_emails",
|
|
1390
2328
|
rationale: "Require verified contactability before sequence delivery."
|
|
1391
|
-
}
|
|
1392
|
-
|
|
2329
|
+
});
|
|
2330
|
+
}
|
|
2331
|
+
if (builtIns.has("signals")) {
|
|
2332
|
+
routes.push({
|
|
1393
2333
|
id: "signaliz-signals",
|
|
1394
2334
|
layer: "enrichment",
|
|
2335
|
+
gtmLayer: "company_enrichment",
|
|
1395
2336
|
provider: "signaliz",
|
|
1396
2337
|
mode: "if_available",
|
|
1397
2338
|
toolName: "enrich_company_signals",
|
|
1398
2339
|
rationale: "Attach current buying signals and evidence for qualification and copy."
|
|
1399
|
-
}
|
|
1400
|
-
|
|
1401
|
-
routes
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
2340
|
+
});
|
|
2341
|
+
}
|
|
2342
|
+
return routes;
|
|
2343
|
+
}
|
|
2344
|
+
function normalizeBuiltIns(request) {
|
|
2345
|
+
const configured = request.builtIns !== void 0 ? request.builtIns : DEFAULT_CAMPAIGN_BUILDER_BUILT_INS;
|
|
2346
|
+
const builtIns = new Set(configured);
|
|
2347
|
+
if (request.builtIns === void 0 && looksLikeLocalLeadCampaign(request)) {
|
|
2348
|
+
builtIns.add("local_leads");
|
|
2349
|
+
}
|
|
2350
|
+
return [...builtIns].filter(isCampaignBuilderBuiltInTool);
|
|
2351
|
+
}
|
|
2352
|
+
function isCampaignBuilderBuiltInTool(value) {
|
|
2353
|
+
return ["lead_generation", "local_leads", "email_finding", "email_verification", "signals"].includes(String(value));
|
|
2354
|
+
}
|
|
2355
|
+
function looksLikeLocalLeadCampaign(request) {
|
|
2356
|
+
const text = [
|
|
2357
|
+
request.goal,
|
|
2358
|
+
campaignBuilderAccountContext(request),
|
|
2359
|
+
...request.icp?.industries ?? [],
|
|
2360
|
+
...request.icp?.keywords ?? []
|
|
2361
|
+
].filter(Boolean).join(" ").toLowerCase();
|
|
2362
|
+
return /\b(local|google maps|near me|nearby|city|cities|location|locations|home services?|clinics?|restaurants?|contractors?)\b/.test(text);
|
|
1408
2363
|
}
|
|
1409
2364
|
function routesFromCustomerTools(tools) {
|
|
1410
2365
|
return tools.flatMap(
|
|
@@ -1422,7 +2377,7 @@ function routesFromCustomerTools(tools) {
|
|
|
1422
2377
|
...tool.config,
|
|
1423
2378
|
available_tools: tool.availableTools
|
|
1424
2379
|
},
|
|
1425
|
-
rationale: `${tool.label ?? tool.provider} is
|
|
2380
|
+
rationale: `${tool.label ?? tool.provider} is operator-provided for ${layer}.`
|
|
1426
2381
|
}))
|
|
1427
2382
|
);
|
|
1428
2383
|
}
|
|
@@ -1467,6 +2422,7 @@ function createBuildRequest(request, defaults, targetCount, campaignName, scopeB
|
|
|
1467
2422
|
return buildRequest;
|
|
1468
2423
|
}
|
|
1469
2424
|
function createBrainPreflight(request, buildRequest, routes, memory) {
|
|
2425
|
+
const operatingPlaybooks = getCampaignBuilderOperatingPlaybooksForRequest(request);
|
|
1470
2426
|
const layers = uniqueStrings([
|
|
1471
2427
|
"icp",
|
|
1472
2428
|
"email_finding",
|
|
@@ -1476,7 +2432,7 @@ function createBrainPreflight(request, buildRequest, routes, memory) {
|
|
|
1476
2432
|
["instantly", "smartlead", "heyreach"].some((provider) => routes.some((route) => route.provider === provider)) ? "sender" : void 0,
|
|
1477
2433
|
memory.enabled ? "feedback" : void 0
|
|
1478
2434
|
]);
|
|
1479
|
-
const providerChain = uniqueStrings(["signaliz", ...routes.map((route) => route.provider)]);
|
|
2435
|
+
const providerChain = uniqueStrings(["signaliz", ...request.preferredProviders ?? [], ...routes.map((route) => route.provider)]);
|
|
1480
2436
|
const targetIcp = compact({
|
|
1481
2437
|
personas: buildRequest.icp?.personas,
|
|
1482
2438
|
industries: buildRequest.icp?.industries,
|
|
@@ -1517,6 +2473,13 @@ function createBrainPreflight(request, buildRequest, routes, memory) {
|
|
|
1517
2473
|
required: true,
|
|
1518
2474
|
policy: "Run read-only GTM Brain preflight before build_campaign so learned defaults, memory, and deliverability risk stay attached to the build.",
|
|
1519
2475
|
layers,
|
|
2476
|
+
operating_playbooks: operatingPlaybooks.map((playbook) => ({
|
|
2477
|
+
slug: playbook.slug,
|
|
2478
|
+
label: playbook.label,
|
|
2479
|
+
quality_gates: playbook.qualityGates,
|
|
2480
|
+
required_fields: playbook.requiredFields,
|
|
2481
|
+
activation_boundary: playbook.activationBoundary
|
|
2482
|
+
})),
|
|
1520
2483
|
target_icp: targetIcp,
|
|
1521
2484
|
provider_chain: providerChain,
|
|
1522
2485
|
lead_source: providerChain[0] ?? "signaliz",
|
|
@@ -1649,6 +2612,47 @@ function createMcpFlow(request, buildRequest, routes, memory, approvals) {
|
|
|
1649
2612
|
approvalRequired: false
|
|
1650
2613
|
}
|
|
1651
2614
|
];
|
|
2615
|
+
steps.push({
|
|
2616
|
+
id: "gtm-provider-catalog",
|
|
2617
|
+
phase: "plan",
|
|
2618
|
+
tool: "gtm_provider_catalog",
|
|
2619
|
+
arguments: {
|
|
2620
|
+
include_layer_catalog: true,
|
|
2621
|
+
include_planned: true
|
|
2622
|
+
},
|
|
2623
|
+
readOnly: true,
|
|
2624
|
+
approvalRequired: false
|
|
2625
|
+
});
|
|
2626
|
+
if (request.agencyContext?.includeNangoCatalog !== false) {
|
|
2627
|
+
steps.push({
|
|
2628
|
+
id: "nango-tool-catalog",
|
|
2629
|
+
phase: "plan",
|
|
2630
|
+
tool: "nango_mcp_tools_list",
|
|
2631
|
+
arguments: {
|
|
2632
|
+
format: "mcp"
|
|
2633
|
+
},
|
|
2634
|
+
readOnly: true,
|
|
2635
|
+
approvalRequired: false
|
|
2636
|
+
});
|
|
2637
|
+
}
|
|
2638
|
+
if (memory.enabled) {
|
|
2639
|
+
steps.push({
|
|
2640
|
+
id: "strategy-memory-status",
|
|
2641
|
+
phase: "memory",
|
|
2642
|
+
tool: "gtm_campaign_strategy_memory_status",
|
|
2643
|
+
arguments: buildGtmCampaignStrategyMemoryStatusArgs(request, buildRequest),
|
|
2644
|
+
readOnly: true,
|
|
2645
|
+
approvalRequired: false
|
|
2646
|
+
});
|
|
2647
|
+
}
|
|
2648
|
+
steps.push({
|
|
2649
|
+
id: "agency-campaign-build-plan",
|
|
2650
|
+
phase: "plan",
|
|
2651
|
+
tool: "gtm_campaign_build_plan",
|
|
2652
|
+
arguments: buildGtmCampaignBuildPlanArgs(request, buildRequest, routes, memory),
|
|
2653
|
+
readOnly: true,
|
|
2654
|
+
approvalRequired: memory.useNetworkPatterns === true
|
|
2655
|
+
});
|
|
1652
2656
|
if (memory.enabled) {
|
|
1653
2657
|
for (const [index, query] of memory.queries.entries()) {
|
|
1654
2658
|
steps.push({
|
|
@@ -1662,6 +2666,25 @@ function createMcpFlow(request, buildRequest, routes, memory, approvals) {
|
|
|
1662
2666
|
}
|
|
1663
2667
|
}
|
|
1664
2668
|
for (const route of routes) {
|
|
2669
|
+
if (shouldPrepareProviderRoute(route)) {
|
|
2670
|
+
steps.push({
|
|
2671
|
+
id: `prepare-${route.id}`,
|
|
2672
|
+
phase: "plan",
|
|
2673
|
+
tool: "gtm_provider_recipe_prepare",
|
|
2674
|
+
arguments: buildProviderRecipePrepareArgs(route, buildRequest),
|
|
2675
|
+
readOnly: true,
|
|
2676
|
+
approvalRequired: false
|
|
2677
|
+
});
|
|
2678
|
+
steps.push({
|
|
2679
|
+
id: `activate-${route.id}-dry-run`,
|
|
2680
|
+
phase: "plan",
|
|
2681
|
+
tool: "gtm_provider_route_activate",
|
|
2682
|
+
arguments: buildProviderRouteActivateArgs(route, buildRequest),
|
|
2683
|
+
readOnly: true,
|
|
2684
|
+
approvalRequired: false
|
|
2685
|
+
});
|
|
2686
|
+
}
|
|
2687
|
+
const routeApprovalRequired = route.approvalRequired === true || route.provider !== "signaliz" && route.approvalRequired !== false && route.mode === "required" || route.layer === "delivery" || route.layer === "feedback";
|
|
1665
2688
|
steps.push({
|
|
1666
2689
|
id: `route-${route.id}`,
|
|
1667
2690
|
phase: route.layer,
|
|
@@ -1673,7 +2696,7 @@ function createMcpFlow(request, buildRequest, routes, memory, approvals) {
|
|
|
1673
2696
|
config: route.config
|
|
1674
2697
|
},
|
|
1675
2698
|
readOnly: !["delivery", "feedback"].includes(route.layer),
|
|
1676
|
-
approvalRequired:
|
|
2699
|
+
approvalRequired: routeApprovalRequired
|
|
1677
2700
|
});
|
|
1678
2701
|
}
|
|
1679
2702
|
steps.push({
|
|
@@ -1682,8 +2705,8 @@ function createMcpFlow(request, buildRequest, routes, memory, approvals) {
|
|
|
1682
2705
|
tool: "scope_campaign",
|
|
1683
2706
|
arguments: {
|
|
1684
2707
|
prompt: request.goal,
|
|
1685
|
-
|
|
1686
|
-
|
|
2708
|
+
account_label: campaignBuilderAccountLabel(request),
|
|
2709
|
+
account_context: campaignBuilderAccountContext(request),
|
|
1687
2710
|
target_count: request.targetCount
|
|
1688
2711
|
},
|
|
1689
2712
|
readOnly: true,
|
|
@@ -1745,9 +2768,199 @@ function createMcpFlow(request, buildRequest, routes, memory, approvals) {
|
|
|
1745
2768
|
});
|
|
1746
2769
|
return steps.map((step) => ({ ...step, arguments: compact(step.arguments) }));
|
|
1747
2770
|
}
|
|
2771
|
+
function shouldPrepareProviderRoute(route) {
|
|
2772
|
+
return !["signaliz", "csv"].includes(route.provider);
|
|
2773
|
+
}
|
|
2774
|
+
function buildProviderRecipePrepareArgs(route, buildRequest) {
|
|
2775
|
+
const layerCapabilities = uniqueStrings(gtmLayersForRoute(route));
|
|
2776
|
+
const layer = layerCapabilities[0] ?? mapCampaignBuilderLayerToGtmLayer(route.layer) ?? "custom";
|
|
2777
|
+
const config = asRecord(route.config);
|
|
2778
|
+
return compact({
|
|
2779
|
+
provider_id: route.provider,
|
|
2780
|
+
provider_name: route.label,
|
|
2781
|
+
layer,
|
|
2782
|
+
layer_capabilities: layerCapabilities.length > 0 ? layerCapabilities : void 0,
|
|
2783
|
+
invocation_type: route.providerCapability?.invocationType ?? inferProviderInvocationType(route),
|
|
2784
|
+
auth_strategy: inferProviderAuthStrategy(route),
|
|
2785
|
+
workspace_mcp_server_id: stringValue(config.workspace_mcp_server_id ?? config.workspaceMcpServerId ?? route.mcpServerName),
|
|
2786
|
+
workspace_integration_id: stringValue(config.workspace_integration_id ?? config.workspaceIntegrationId),
|
|
2787
|
+
workspace_connection_id: stringValue(config.workspace_connection_id ?? config.workspaceConnectionId),
|
|
2788
|
+
endpoint_url: stringValue(config.endpoint_url ?? config.endpointUrl ?? config.webhook_url ?? config.webhookUrl),
|
|
2789
|
+
request_template: asOptionalRecord(config.request_template ?? config.requestTemplate),
|
|
2790
|
+
response_mapping: asOptionalRecord(config.response_mapping ?? config.responseMapping),
|
|
2791
|
+
input_schema: asOptionalRecord(config.input_schema ?? config.inputSchema ?? route.providerCapability?.exampleInputSchema),
|
|
2792
|
+
output_schema: asOptionalRecord(config.output_schema ?? config.outputSchema ?? route.providerCapability?.exampleOutputSchema),
|
|
2793
|
+
readiness: asOptionalRecord(config.readiness),
|
|
2794
|
+
metadata: compact({
|
|
2795
|
+
source: "campaign-builder-agent",
|
|
2796
|
+
route_id: route.id,
|
|
2797
|
+
campaign_name: buildRequest.name,
|
|
2798
|
+
tool_name: route.toolName,
|
|
2799
|
+
mcp_server_name: route.mcpServerName,
|
|
2800
|
+
dry_run_only: true
|
|
2801
|
+
}),
|
|
2802
|
+
context: compact({
|
|
2803
|
+
source: "campaign-builder-agent",
|
|
2804
|
+
route_id: route.id,
|
|
2805
|
+
gtm_campaign_id: buildRequest.gtmCampaignId
|
|
2806
|
+
}),
|
|
2807
|
+
use_signaliz_fallback: route.routingPolicy?.useSignalizFallback ?? true,
|
|
2808
|
+
priority: numberOrUndefined2(config.priority),
|
|
2809
|
+
status: stringValue(config.status) ?? "needs_setup"
|
|
2810
|
+
});
|
|
2811
|
+
}
|
|
2812
|
+
function buildProviderRouteActivateArgs(route, buildRequest) {
|
|
2813
|
+
const layerCapabilities = uniqueStrings(gtmLayersForRoute(route));
|
|
2814
|
+
const config = asRecord(route.config);
|
|
2815
|
+
return compact({
|
|
2816
|
+
provider_id: route.provider,
|
|
2817
|
+
provider_name: route.label,
|
|
2818
|
+
campaign_id: buildRequest.gtmCampaignId,
|
|
2819
|
+
layer: layerCapabilities[0] ?? mapCampaignBuilderLayerToGtmLayer(route.layer) ?? "custom",
|
|
2820
|
+
layers: layerCapabilities.length > 0 ? layerCapabilities : void 0,
|
|
2821
|
+
invocation_type: route.providerCapability?.invocationType ?? inferProviderInvocationType(route),
|
|
2822
|
+
auth_strategy: inferProviderAuthStrategy(route),
|
|
2823
|
+
workspace_mcp_server_id: stringValue(config.workspace_mcp_server_id ?? config.workspaceMcpServerId ?? route.mcpServerName),
|
|
2824
|
+
workspace_integration_id: stringValue(config.workspace_integration_id ?? config.workspaceIntegrationId),
|
|
2825
|
+
workspace_connection_id: stringValue(config.workspace_connection_id ?? config.workspaceConnectionId),
|
|
2826
|
+
endpoint_url: stringValue(config.endpoint_url ?? config.endpointUrl ?? config.webhook_url ?? config.webhookUrl),
|
|
2827
|
+
route_config: compact({
|
|
2828
|
+
...asRecord(config.route_config ?? config.routeConfig),
|
|
2829
|
+
source: "campaign-builder-agent",
|
|
2830
|
+
route_id: route.id,
|
|
2831
|
+
tool_name: route.toolName,
|
|
2832
|
+
mcp_server_name: route.mcpServerName
|
|
2833
|
+
}),
|
|
2834
|
+
use_signaliz_fallback: route.routingPolicy?.useSignalizFallback ?? true,
|
|
2835
|
+
priority: numberOrUndefined2(config.priority),
|
|
2836
|
+
dry_run: true,
|
|
2837
|
+
confirm: false
|
|
2838
|
+
});
|
|
2839
|
+
}
|
|
2840
|
+
function inferProviderInvocationType(route) {
|
|
2841
|
+
if (route.provider === "airbyte") return "airbyte";
|
|
2842
|
+
if (route.provider === "nango") return "managed_integration";
|
|
2843
|
+
if (["custom_webhook", "webhook", "clay_webhook"].includes(route.provider)) return "webhook";
|
|
2844
|
+
if (["custom_api", "apollo", "ai_ark", "apify"].includes(route.provider)) return "api";
|
|
2845
|
+
if (route.mcpServerName || route.toolName || ["custom_mcp", "octave"].includes(route.provider)) return "mcp_tool";
|
|
2846
|
+
return "manual";
|
|
2847
|
+
}
|
|
2848
|
+
function inferProviderAuthStrategy(route) {
|
|
2849
|
+
const config = asRecord(route.config);
|
|
2850
|
+
const configured = stringValue(config.auth_strategy ?? config.authStrategy);
|
|
2851
|
+
if (configured) return configured;
|
|
2852
|
+
const invocationType = route.providerCapability?.invocationType ?? inferProviderInvocationType(route);
|
|
2853
|
+
if (invocationType === "webhook") return "webhook_secret";
|
|
2854
|
+
if (invocationType === "mcp_tool") return "mcp_auth";
|
|
2855
|
+
if (invocationType === "managed_integration") return "byo_runtime";
|
|
2856
|
+
if (invocationType === "api" || invocationType === "airbyte") return "integration_key";
|
|
2857
|
+
return void 0;
|
|
2858
|
+
}
|
|
2859
|
+
function refreshBuildStepArguments(plan) {
|
|
2860
|
+
for (const step of plan.mcpFlow) {
|
|
2861
|
+
if (step.id === "dry-run-build") {
|
|
2862
|
+
step.arguments = compact({
|
|
2863
|
+
...buildCampaignArgs({ ...plan.buildRequest, dryRun: true, confirmSpend: false }),
|
|
2864
|
+
dry_run: true
|
|
2865
|
+
});
|
|
2866
|
+
}
|
|
2867
|
+
if (step.id === "approved-build") {
|
|
2868
|
+
step.arguments = compact({
|
|
2869
|
+
...buildCampaignArgs({ ...plan.buildRequest, dryRun: false, confirmSpend: true }),
|
|
2870
|
+
required_approvals: plan.approvals.map((approval) => approval.id)
|
|
2871
|
+
});
|
|
2872
|
+
}
|
|
2873
|
+
}
|
|
2874
|
+
}
|
|
2875
|
+
function buildFallbackPlanSnapshot(plan) {
|
|
2876
|
+
const plannerStep = plan.mcpFlow.find((step) => step.id === "agency-campaign-build-plan");
|
|
2877
|
+
return compact({
|
|
2878
|
+
source_tool: "campaign-builder-agent",
|
|
2879
|
+
plan_id: plan.planId,
|
|
2880
|
+
query: asRecord(plannerStep?.arguments),
|
|
2881
|
+
campaign_name: plan.campaignName,
|
|
2882
|
+
goal: plan.goal,
|
|
2883
|
+
target_count: plan.targetCount,
|
|
2884
|
+
approvals: plan.approvals,
|
|
2885
|
+
brain_preflight: plan.brainPreflight,
|
|
2886
|
+
operating_playbooks: plan.operatingPlaybooks
|
|
2887
|
+
});
|
|
2888
|
+
}
|
|
2889
|
+
function mapPlanCommitResult(data) {
|
|
2890
|
+
const campaign = asRecord(data.campaign);
|
|
2891
|
+
const campaignBuild = asRecord(data.campaign_build ?? data.campaignBuild);
|
|
2892
|
+
const committedPlan = asRecord(data.committed_plan ?? data.committedPlan);
|
|
2893
|
+
const commitPlan = asRecord(data.commit_plan ?? data.commitPlan);
|
|
2894
|
+
const campaignArgs = asRecord(commitPlan.campaign_arguments ?? commitPlan.campaignArguments);
|
|
2895
|
+
return {
|
|
2896
|
+
dryRun: data.dry_run === true || data.dryRun === true,
|
|
2897
|
+
wroteState: data.wrote_state === true || data.wroteState === true,
|
|
2898
|
+
campaignId: stringValue(campaign.id ?? committedPlan.campaign_id ?? committedPlan.campaignId ?? commitPlan.campaign_id ?? commitPlan.campaignId ?? campaignArgs.id),
|
|
2899
|
+
campaignBuildId: stringValue(campaignBuild.id ?? committedPlan.campaign_build_id ?? committedPlan.campaignBuildId ?? campaignArgs.campaign_build_id ?? campaignArgs.campaignBuildId),
|
|
2900
|
+
raw: data
|
|
2901
|
+
};
|
|
2902
|
+
}
|
|
2903
|
+
function buildGtmCampaignBuildPlanArgs(request, buildRequest, routes, memory) {
|
|
2904
|
+
const agencyContext = request.agencyContext ?? {};
|
|
2905
|
+
const strategyModel = campaignBuilderStrategyModel(agencyContext);
|
|
2906
|
+
const partnerEcosystem = agencyContext.partnerEcosystem ?? (strategyModel === "custom" ? void 0 : ["clay", "instantly", "nango"]);
|
|
2907
|
+
const layers = uniqueStrings([
|
|
2908
|
+
"icp",
|
|
2909
|
+
buildRequest.icp?.requireVerifiedEmail !== false ? "email_finding" : void 0,
|
|
2910
|
+
buildRequest.icp?.requireVerifiedEmail !== false ? "email_verification" : void 0,
|
|
2911
|
+
...routes.flatMap(gtmLayersForRoute),
|
|
2912
|
+
buildRequest.delivery?.destinationType === "webhook" ? "destination_export" : void 0,
|
|
2913
|
+
memory.enabled ? "feedback" : void 0
|
|
2914
|
+
]);
|
|
2915
|
+
const preferredProviders = uniqueStrings([
|
|
2916
|
+
...request.preferredProviders ?? [],
|
|
2917
|
+
...routes.map((route) => route.provider).filter((provider) => provider !== "signaliz")
|
|
2918
|
+
]);
|
|
2919
|
+
const operatingPlaybooks = getCampaignBuilderOperatingPlaybooksForRequest(request);
|
|
2920
|
+
return compact({
|
|
2921
|
+
campaign_id: buildRequest.gtmCampaignId,
|
|
2922
|
+
campaign_brief: buildRequest.prompt || request.goal,
|
|
2923
|
+
strategy_template: request.strategyTemplate,
|
|
2924
|
+
target_icp: buildRequest.icp ? buildGtmTargetIcpContext(buildRequest.icp) : void 0,
|
|
2925
|
+
lead_count: buildRequest.targetCount,
|
|
2926
|
+
layers: layers.length > 0 ? layers : void 0,
|
|
2927
|
+
preferred_providers: preferredProviders.length > 0 ? preferredProviders : void 0,
|
|
2928
|
+
strategy_model: strategyModel,
|
|
2929
|
+
include_strategy_patterns: campaignBuilderStrategyPatternsEnabled(agencyContext),
|
|
2930
|
+
include_workflow_patterns: campaignBuilderWorkflowPatternsEnabled(agencyContext),
|
|
2931
|
+
include_nango_catalog: agencyContext.includeNangoCatalog !== false,
|
|
2932
|
+
partner_ecosystem: partnerEcosystem,
|
|
2933
|
+
operating_playbooks: operatingPlaybooks.map((playbook) => ({
|
|
2934
|
+
slug: playbook.slug,
|
|
2935
|
+
label: playbook.label,
|
|
2936
|
+
quality_gates: playbook.qualityGates,
|
|
2937
|
+
activation_boundary: playbook.activationBoundary
|
|
2938
|
+
})),
|
|
2939
|
+
include_memory: memory.enabled,
|
|
2940
|
+
include_brain: true,
|
|
2941
|
+
include_provider_routes: true,
|
|
2942
|
+
include_failure_patterns: true,
|
|
2943
|
+
include_planned_providers: true,
|
|
2944
|
+
limit: 25
|
|
2945
|
+
});
|
|
2946
|
+
}
|
|
2947
|
+
function buildGtmCampaignStrategyMemoryStatusArgs(request, buildRequest) {
|
|
2948
|
+
return compact({
|
|
2949
|
+
query: request.goal,
|
|
2950
|
+
campaign_brief: buildRequest.prompt || request.goal,
|
|
2951
|
+
strategy_template: request.strategyTemplate,
|
|
2952
|
+
target_icp: buildRequest.icp ? buildGtmTargetIcpContext(buildRequest.icp) : void 0,
|
|
2953
|
+
memory_dimension_filters: request.strategyTemplate ? { strategy_template: request.strategyTemplate } : void 0,
|
|
2954
|
+
require_memory_dimension_match: false,
|
|
2955
|
+
include_samples: false,
|
|
2956
|
+
include_sources: true,
|
|
2957
|
+
days: 3650,
|
|
2958
|
+
limit: 25
|
|
2959
|
+
});
|
|
2960
|
+
}
|
|
1748
2961
|
function buildGtmMemorySearchArgs(request, routes, query) {
|
|
1749
2962
|
const layers = uniqueStrings(routes.flatMap(gtmLayersForRoute));
|
|
1750
|
-
const providerChain = uniqueStrings(routes.map((route) => route.provider));
|
|
2963
|
+
const providerChain = uniqueStrings([...request.preferredProviders ?? [], ...routes.map((route) => route.provider)]);
|
|
1751
2964
|
return compact({
|
|
1752
2965
|
query: query.query,
|
|
1753
2966
|
limit: query.topK,
|
|
@@ -1769,6 +2982,26 @@ function buildGtmTargetIcpContext(icp) {
|
|
|
1769
2982
|
require_verified_email: icp.requireVerifiedEmail
|
|
1770
2983
|
});
|
|
1771
2984
|
}
|
|
2985
|
+
function mapCampaignBuilderLayerToGtmLayer(layer) {
|
|
2986
|
+
switch (layer) {
|
|
2987
|
+
case "source":
|
|
2988
|
+
return "lead_generation";
|
|
2989
|
+
case "enrichment":
|
|
2990
|
+
return "company_enrichment";
|
|
2991
|
+
case "qualification":
|
|
2992
|
+
return "qualification";
|
|
2993
|
+
case "copy":
|
|
2994
|
+
return "copy_enrichment";
|
|
2995
|
+
case "delivery":
|
|
2996
|
+
return "destination_export";
|
|
2997
|
+
case "feedback":
|
|
2998
|
+
return "feedback";
|
|
2999
|
+
case "approval":
|
|
3000
|
+
return "approval";
|
|
3001
|
+
default:
|
|
3002
|
+
return void 0;
|
|
3003
|
+
}
|
|
3004
|
+
}
|
|
1772
3005
|
function buildCampaignArgs(request) {
|
|
1773
3006
|
const args = {
|
|
1774
3007
|
name: request.name,
|
|
@@ -1949,8 +3182,8 @@ function estimateCredits(request, defaults, targetCount) {
|
|
|
1949
3182
|
}
|
|
1950
3183
|
function buildDescription(request) {
|
|
1951
3184
|
const parts = [
|
|
1952
|
-
request
|
|
1953
|
-
request
|
|
3185
|
+
campaignBuilderAccountLabel(request) ? `Account label: ${campaignBuilderAccountLabel(request)}` : void 0,
|
|
3186
|
+
campaignBuilderAccountContext(request) ? `Context: ${campaignBuilderAccountContext(request)}` : void 0,
|
|
1954
3187
|
request.constraints?.deliverabilityNotes?.length ? `Deliverability: ${request.constraints.deliverabilityNotes.join("; ")}` : void 0,
|
|
1955
3188
|
"Agent-built campaign plan layered on Signaliz kernel and existing MCP tools."
|
|
1956
3189
|
];
|
|
@@ -1973,6 +3206,10 @@ function compact(record) {
|
|
|
1973
3206
|
function asRecord(value) {
|
|
1974
3207
|
return value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
1975
3208
|
}
|
|
3209
|
+
function asOptionalRecord(value) {
|
|
3210
|
+
const record = asRecord(value);
|
|
3211
|
+
return Object.keys(record).length > 0 ? record : void 0;
|
|
3212
|
+
}
|
|
1976
3213
|
function stringValue(value) {
|
|
1977
3214
|
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
1978
3215
|
}
|
|
@@ -3717,7 +4954,7 @@ var GtmKernel = class {
|
|
|
3717
4954
|
campaigns: input.campaigns.map(campaignHistoryImportCampaignArgs)
|
|
3718
4955
|
});
|
|
3719
4956
|
}
|
|
3720
|
-
/** Queue a Trigger-backed campaign history import for larger
|
|
4957
|
+
/** Queue a Trigger-backed campaign history import for larger private campaign backfills. */
|
|
3721
4958
|
async importCampaignHistoryRun(input) {
|
|
3722
4959
|
return this.callMcp("gtm_campaign_history_import_run", {
|
|
3723
4960
|
source: input.source,
|
|
@@ -3848,6 +5085,25 @@ var GtmKernel = class {
|
|
|
3848
5085
|
write_routine_outcomes: input.writeRoutineOutcomes
|
|
3849
5086
|
});
|
|
3850
5087
|
}
|
|
5088
|
+
/** Run a read-only Campaign Audit and persist workspace-scoped failure findings. */
|
|
5089
|
+
async runCampaignAudit(input) {
|
|
5090
|
+
return this.callMcp("gtm_campaign_audit_run", {
|
|
5091
|
+
provider: input.provider,
|
|
5092
|
+
provider_campaign_id: input.providerCampaignId,
|
|
5093
|
+
campaign_id: input.campaignId,
|
|
5094
|
+
campaign_name: input.campaignName,
|
|
5095
|
+
lookback_days: input.lookbackDays,
|
|
5096
|
+
limit_findings: input.limitFindings
|
|
5097
|
+
});
|
|
5098
|
+
}
|
|
5099
|
+
/** Read a persisted Campaign Audit by audit id or campaign id. */
|
|
5100
|
+
async getCampaignAudit(options) {
|
|
5101
|
+
return this.callMcp("gtm_campaign_audit_get", {
|
|
5102
|
+
audit_id: options.auditId,
|
|
5103
|
+
campaign_id: options.campaignId,
|
|
5104
|
+
limit_findings: options.limitFindings
|
|
5105
|
+
});
|
|
5106
|
+
}
|
|
3851
5107
|
/** Normalize Instantly webhook/pull payloads and ingest row-level feedback through the GTM Kernel. */
|
|
3852
5108
|
async syncInstantlyFeedback(input) {
|
|
3853
5109
|
return this.callMcp("gtm_instantly_feedback_sync", {
|
|
@@ -4145,6 +5401,40 @@ var GtmKernel = class {
|
|
|
4145
5401
|
include_layer_catalog: options.includeLayerCatalog
|
|
4146
5402
|
});
|
|
4147
5403
|
}
|
|
5404
|
+
/** List private-safe campaign strategy templates agents can merge into campaign build plans. */
|
|
5405
|
+
async campaignStrategyTemplates(options = {}) {
|
|
5406
|
+
return this.callMcp("gtm_campaign_strategy_templates", {
|
|
5407
|
+
strategy_template: options.strategyTemplate,
|
|
5408
|
+
query: options.query,
|
|
5409
|
+
include_details: options.includeDetails
|
|
5410
|
+
});
|
|
5411
|
+
}
|
|
5412
|
+
/** Build the read-only Memory, Brain, risk, and provider-route runbook needed before planning a campaign. */
|
|
5413
|
+
async campaignStartContext(input = {}) {
|
|
5414
|
+
return this.callMcp("gtm_campaign_start_context", {
|
|
5415
|
+
campaign_id: input.campaignId,
|
|
5416
|
+
campaign_build_id: input.campaignBuildId,
|
|
5417
|
+
campaign_brief: input.campaignBrief,
|
|
5418
|
+
strategy_template: input.strategyTemplate,
|
|
5419
|
+
target_icp: input.targetIcp,
|
|
5420
|
+
lead_count: input.leadCount,
|
|
5421
|
+
layers: input.layers,
|
|
5422
|
+
preferred_providers: input.preferredProviders,
|
|
5423
|
+
memory_dimension_filters: input.memoryDimensionFilters,
|
|
5424
|
+
require_memory_dimension_match: input.requireMemoryDimensionMatch,
|
|
5425
|
+
include_memory: input.includeMemory,
|
|
5426
|
+
include_brain: input.includeBrain,
|
|
5427
|
+
include_provider_routes: input.includeProviderRoutes,
|
|
5428
|
+
include_failure_patterns: input.includeFailurePatterns,
|
|
5429
|
+
include_delivery_risk: input.includeDeliveryRisk,
|
|
5430
|
+
include_global_brain: input.includeGlobalBrain,
|
|
5431
|
+
include_planned_providers: input.includePlannedProviders,
|
|
5432
|
+
days: input.days,
|
|
5433
|
+
min_confidence: input.minConfidence,
|
|
5434
|
+
min_sample_size: input.minSampleSize,
|
|
5435
|
+
limit: input.limit
|
|
5436
|
+
});
|
|
5437
|
+
}
|
|
4148
5438
|
/** Inspect GTM integration activation cards for UI and agent routing without writing state. */
|
|
4149
5439
|
async integrationsActivationStatus(options = {}) {
|
|
4150
5440
|
return this.callMcp("gtm_integrations_activation_status", {
|
|
@@ -4160,10 +5450,16 @@ var GtmKernel = class {
|
|
|
4160
5450
|
campaign_id: input.campaignId,
|
|
4161
5451
|
campaign_build_id: input.campaignBuildId,
|
|
4162
5452
|
campaign_brief: input.campaignBrief,
|
|
5453
|
+
strategy_template: input.strategyTemplate,
|
|
4163
5454
|
target_icp: input.targetIcp,
|
|
4164
5455
|
lead_count: input.leadCount,
|
|
4165
5456
|
layers: input.layers,
|
|
4166
5457
|
preferred_providers: input.preferredProviders,
|
|
5458
|
+
strategy_model: input.strategyModel,
|
|
5459
|
+
include_strategy_patterns: input.includeStrategyPatterns,
|
|
5460
|
+
include_workflow_patterns: input.includeWorkflowPatterns ?? input.includeClayPatterns,
|
|
5461
|
+
include_nango_catalog: input.includeNangoCatalog,
|
|
5462
|
+
partner_ecosystem: input.partnerEcosystem,
|
|
4167
5463
|
memory_dimension_filters: input.memoryDimensionFilters,
|
|
4168
5464
|
require_memory_dimension_match: input.requireMemoryDimensionMatch,
|
|
4169
5465
|
include_memory: input.includeMemory,
|
|
@@ -4175,6 +5471,79 @@ var GtmKernel = class {
|
|
|
4175
5471
|
limit: input.limit
|
|
4176
5472
|
});
|
|
4177
5473
|
}
|
|
5474
|
+
/** Emit reusable CampaignBuilderAgentRequest JSON from hosted MCP strategy-template defaults without spending credits. */
|
|
5475
|
+
async campaignAgentRequestTemplate(input = {}) {
|
|
5476
|
+
return this.callMcp("gtm_campaign_agent_request_template", {
|
|
5477
|
+
goal: input.goal,
|
|
5478
|
+
campaign_brief: input.campaignBrief,
|
|
5479
|
+
campaign_name: input.campaignName,
|
|
5480
|
+
account_label: input.accountLabel,
|
|
5481
|
+
account_context: input.accountContext,
|
|
5482
|
+
strategy_template: input.strategyTemplate,
|
|
5483
|
+
operating_playbooks: input.operatingPlaybooks,
|
|
5484
|
+
target_icp: input.targetIcp,
|
|
5485
|
+
target_count: input.targetCount,
|
|
5486
|
+
builtins: input.builtIns,
|
|
5487
|
+
include_local_leads: input.includeLocalLeads,
|
|
5488
|
+
include_byo_placeholder: input.includeByoPlaceholder,
|
|
5489
|
+
include_nango_catalog: input.includeNangoCatalog,
|
|
5490
|
+
preferred_providers: input.preferredProviders,
|
|
5491
|
+
privacy_mode: input.privacyMode,
|
|
5492
|
+
destination_type: input.destinationType
|
|
5493
|
+
});
|
|
5494
|
+
}
|
|
5495
|
+
/** Compose a one-call read-only strategy-template campaign-agent runbook across built-ins, Memory, Brain, Nango, and BYO routes. */
|
|
5496
|
+
async campaignAgentPlan(input = {}) {
|
|
5497
|
+
return this.callMcp("gtm_campaign_agent_plan", {
|
|
5498
|
+
goal: input.goal,
|
|
5499
|
+
campaign_brief: input.campaignBrief,
|
|
5500
|
+
campaign_name: input.campaignName,
|
|
5501
|
+
campaign_id: input.campaignId,
|
|
5502
|
+
campaign_build_id: input.campaignBuildId,
|
|
5503
|
+
strategy_template: input.strategyTemplate,
|
|
5504
|
+
operating_playbooks: input.operatingPlaybooks,
|
|
5505
|
+
account_context: input.accountContext,
|
|
5506
|
+
target_icp: input.targetIcp,
|
|
5507
|
+
target_count: input.targetCount,
|
|
5508
|
+
lead_count: input.leadCount,
|
|
5509
|
+
builtins: input.builtIns,
|
|
5510
|
+
use_local_leads: input.useLocalLeads,
|
|
5511
|
+
layers: input.layers,
|
|
5512
|
+
preferred_providers: input.preferredProviders,
|
|
5513
|
+
custom_tools: input.customTools,
|
|
5514
|
+
integrations: input.integrations,
|
|
5515
|
+
strategy_model: input.strategyModel,
|
|
5516
|
+
include_strategy_patterns: input.includeStrategyPatterns,
|
|
5517
|
+
include_workflow_patterns: input.includeWorkflowPatterns,
|
|
5518
|
+
include_nango_catalog: input.includeNangoCatalog,
|
|
5519
|
+
partner_ecosystem: input.partnerEcosystem,
|
|
5520
|
+
memory_dimension_filters: input.memoryDimensionFilters,
|
|
5521
|
+
require_memory_dimension_match: input.requireMemoryDimensionMatch,
|
|
5522
|
+
include_memory: input.includeMemory,
|
|
5523
|
+
include_brain: input.includeBrain,
|
|
5524
|
+
include_provider_routes: input.includeProviderRoutes,
|
|
5525
|
+
include_failure_patterns: input.includeFailurePatterns,
|
|
5526
|
+
include_delivery_risk: input.includeDeliveryRisk,
|
|
5527
|
+
include_planned_providers: input.includePlannedProviders,
|
|
5528
|
+
days: input.days,
|
|
5529
|
+
limit: input.limit
|
|
5530
|
+
});
|
|
5531
|
+
}
|
|
5532
|
+
/** Inspect private-safe strategy-template/workflow memory readiness before campaign planning. */
|
|
5533
|
+
async campaignStrategyMemoryStatus(input = {}) {
|
|
5534
|
+
return this.callMcp("gtm_campaign_strategy_memory_status", {
|
|
5535
|
+
strategy_template: input.strategyTemplate,
|
|
5536
|
+
query: input.query,
|
|
5537
|
+
campaign_brief: input.campaignBrief,
|
|
5538
|
+
target_icp: input.targetIcp,
|
|
5539
|
+
memory_dimension_filters: input.memoryDimensionFilters,
|
|
5540
|
+
require_memory_dimension_match: input.requireMemoryDimensionMatch,
|
|
5541
|
+
include_samples: input.includeSamples,
|
|
5542
|
+
include_sources: input.includeSources,
|
|
5543
|
+
days: input.days,
|
|
5544
|
+
limit: input.limit
|
|
5545
|
+
});
|
|
5546
|
+
}
|
|
4178
5547
|
/** Persist a reviewed campaign build plan into a campaign object and audit log. Dry-run first by default. */
|
|
4179
5548
|
async commitCampaignBuildPlan(input = {}) {
|
|
4180
5549
|
return this.callMcp("gtm_campaign_build_plan_commit", {
|
|
@@ -4321,6 +5690,13 @@ var GtmKernel = class {
|
|
|
4321
5690
|
vendor_id: input.vendorId,
|
|
4322
5691
|
service_category: input.serviceCategory,
|
|
4323
5692
|
connection_type: input.connectionType,
|
|
5693
|
+
integration_id: input.integrationId,
|
|
5694
|
+
provider_config_key: input.providerConfigKey,
|
|
5695
|
+
allowed_integrations: input.allowedIntegrations,
|
|
5696
|
+
surface: input.surface,
|
|
5697
|
+
source: input.source,
|
|
5698
|
+
user_email: input.userEmail,
|
|
5699
|
+
user_display_name: input.userDisplayName,
|
|
4324
5700
|
status: input.status,
|
|
4325
5701
|
metadata: input.metadata
|
|
4326
5702
|
});
|
|
@@ -4377,6 +5753,20 @@ var GtmKernel = class {
|
|
|
4377
5753
|
context: input.context
|
|
4378
5754
|
});
|
|
4379
5755
|
}
|
|
5756
|
+
/** Create a short-lived Nango Connect session so a user can authorize a vendor API. */
|
|
5757
|
+
async createNangoConnectSession(input) {
|
|
5758
|
+
return this.callMcp("nango_connect_session_create", {
|
|
5759
|
+
provider_id: input.providerId,
|
|
5760
|
+
integration_id: input.integrationId,
|
|
5761
|
+
provider_display_name: input.providerDisplayName,
|
|
5762
|
+
integration_display_name: input.integrationDisplayName,
|
|
5763
|
+
allowed_integrations: input.allowedIntegrations,
|
|
5764
|
+
surface: input.surface,
|
|
5765
|
+
source: input.source,
|
|
5766
|
+
user_email: input.userEmail,
|
|
5767
|
+
user_display_name: input.userDisplayName
|
|
5768
|
+
});
|
|
5769
|
+
}
|
|
4380
5770
|
/** List Nango-backed action tools for a workspace connection without executing them. */
|
|
4381
5771
|
async listNangoTools(options = {}) {
|
|
4382
5772
|
return this.callMcp("nango_mcp_tools_list", {
|
|
@@ -4720,14 +6110,20 @@ var Signaliz = class {
|
|
|
4720
6110
|
|
|
4721
6111
|
// src/cli.ts
|
|
4722
6112
|
var apiKey = process.env.SIGNALIZ_API_KEY;
|
|
6113
|
+
var baseUrl = process.env.SIGNALIZ_BASE_URL || process.env.SIGNALIZ_API_URL;
|
|
4723
6114
|
async function main() {
|
|
4724
6115
|
const command = process.argv[2];
|
|
4725
|
-
if (!
|
|
6116
|
+
if (!command || command === "help" || command === "--help" || command === "-h") {
|
|
6117
|
+
printHelp();
|
|
6118
|
+
return;
|
|
6119
|
+
}
|
|
6120
|
+
const offlineCampaignAgentTemplate = (command === "campaign-agent" || command === "campaign-builder") && ["init", "template", "request-template", "new"].includes(String(process.argv[3] || ""));
|
|
6121
|
+
if (!apiKey && !offlineCampaignAgentTemplate) {
|
|
4726
6122
|
console.error("\u274C SIGNALIZ_API_KEY environment variable is required.");
|
|
4727
6123
|
console.error(" Set it with: export SIGNALIZ_API_KEY=sk_...");
|
|
4728
6124
|
process.exit(1);
|
|
4729
6125
|
}
|
|
4730
|
-
const signaliz = new Signaliz({ apiKey });
|
|
6126
|
+
const signaliz = new Signaliz({ apiKey: apiKey || "offline", baseUrl });
|
|
4731
6127
|
switch (command) {
|
|
4732
6128
|
case "test": {
|
|
4733
6129
|
try {
|
|
@@ -4758,18 +6154,962 @@ async function main() {
|
|
|
4758
6154
|
}
|
|
4759
6155
|
break;
|
|
4760
6156
|
}
|
|
6157
|
+
case "gtm": {
|
|
6158
|
+
await handleGtmCommand(signaliz, process.argv.slice(3));
|
|
6159
|
+
break;
|
|
6160
|
+
}
|
|
6161
|
+
case "campaign-agent":
|
|
6162
|
+
case "campaign-builder": {
|
|
6163
|
+
await handleCampaignAgentCommand(signaliz, process.argv.slice(3));
|
|
6164
|
+
break;
|
|
6165
|
+
}
|
|
4761
6166
|
default:
|
|
4762
|
-
|
|
6167
|
+
printHelp();
|
|
6168
|
+
}
|
|
6169
|
+
}
|
|
6170
|
+
async function handleGtmCommand(signaliz, argv) {
|
|
6171
|
+
const subcommand = argv[0];
|
|
6172
|
+
if (!subcommand || subcommand === "help" || subcommand === "--help" || subcommand === "-h") {
|
|
6173
|
+
printGtmHelp();
|
|
6174
|
+
return;
|
|
6175
|
+
}
|
|
6176
|
+
if (subcommand === "context") {
|
|
6177
|
+
const flags = parseFlags(argv.slice(1));
|
|
6178
|
+
const result = await signaliz.gtm.context({
|
|
6179
|
+
includeCampaigns: booleanFlag(flags, "include-campaigns"),
|
|
6180
|
+
includeMemory: booleanFlag(flags, "include-memory"),
|
|
6181
|
+
includeBrain: booleanFlag(flags, "include-brain"),
|
|
6182
|
+
includeConnections: booleanFlag(flags, "include-connections"),
|
|
6183
|
+
limit: numberFlag(flags, "limit")
|
|
6184
|
+
});
|
|
6185
|
+
printResult(result, flags);
|
|
6186
|
+
return;
|
|
6187
|
+
}
|
|
6188
|
+
if (subcommand === "bootstrap") {
|
|
6189
|
+
const flags = parseFlags(argv.slice(1));
|
|
6190
|
+
const result = await signaliz.gtm.bootstrapStatus({
|
|
6191
|
+
campaignId: stringFlag(flags, "campaign-id"),
|
|
6192
|
+
days: numberFlag(flags, "days"),
|
|
6193
|
+
minSampleSize: numberFlag(flags, "min-sample-size"),
|
|
6194
|
+
includeConnections: booleanFlag(flags, "include-connections"),
|
|
6195
|
+
includeSamples: booleanFlag(flags, "include-samples"),
|
|
6196
|
+
limit: numberFlag(flags, "limit")
|
|
6197
|
+
});
|
|
6198
|
+
printResult(result, flags);
|
|
6199
|
+
return;
|
|
6200
|
+
}
|
|
6201
|
+
if (subcommand === "memory" && argv[1] === "search") {
|
|
6202
|
+
const flags = parseFlags(argv.slice(2));
|
|
6203
|
+
const query = stringFlag(flags, "query", "q");
|
|
6204
|
+
if (!query) throw new Error("gtm memory search requires --query");
|
|
6205
|
+
const options = {
|
|
6206
|
+
query,
|
|
6207
|
+
campaignId: stringFlag(flags, "campaign-id"),
|
|
6208
|
+
memoryType: stringFlag(flags, "memory-type"),
|
|
6209
|
+
keywords: csvFlag(flags, "keywords"),
|
|
6210
|
+
outcomeType: stringFlag(flags, "outcome-type"),
|
|
6211
|
+
layers: csvFlag(flags, "layers"),
|
|
6212
|
+
providerChain: csvFlag(flags, "provider-chain", "providers"),
|
|
6213
|
+
days: numberFlag(flags, "days"),
|
|
6214
|
+
limit: numberFlag(flags, "limit")
|
|
6215
|
+
};
|
|
6216
|
+
const result = await signaliz.gtm.searchMemory(options);
|
|
6217
|
+
printResult(result, flags);
|
|
6218
|
+
return;
|
|
6219
|
+
}
|
|
6220
|
+
if (subcommand === "templates" || subcommand === "strategy-templates") {
|
|
6221
|
+
const flags = parseFlags(argv.slice(1));
|
|
6222
|
+
const result = await signaliz.gtm.campaignStrategyTemplates({
|
|
6223
|
+
strategyTemplate: stringFlag(flags, "strategy-template", "template"),
|
|
6224
|
+
query: stringFlag(flags, "query", "q"),
|
|
6225
|
+
includeDetails: !booleanFlag(flags, "summary")
|
|
6226
|
+
});
|
|
6227
|
+
printResult(result, flags);
|
|
6228
|
+
return;
|
|
6229
|
+
}
|
|
6230
|
+
if (subcommand === "start-context" || subcommand === "start") {
|
|
6231
|
+
const flags = parseFlags(argv.slice(1));
|
|
6232
|
+
const campaignBrief = stringFlag(flags, "brief", "campaign-brief", "goal");
|
|
6233
|
+
const strategyTemplate = stringFlag(flags, "strategy-template", "template");
|
|
6234
|
+
const targetIcp = jsonObjectFlag(flags, "target-icp", "icp");
|
|
6235
|
+
if (!campaignBrief && !stringFlag(flags, "campaign-id") && !stringFlag(flags, "campaign-build-id") && !strategyTemplate && !targetIcp) {
|
|
6236
|
+
throw new Error("gtm start-context requires --brief, --campaign-id, --campaign-build-id, --strategy-template, or --target-icp");
|
|
6237
|
+
}
|
|
6238
|
+
const input = {
|
|
6239
|
+
campaignId: stringFlag(flags, "campaign-id"),
|
|
6240
|
+
campaignBuildId: stringFlag(flags, "campaign-build-id"),
|
|
6241
|
+
campaignBrief,
|
|
6242
|
+
strategyTemplate,
|
|
6243
|
+
targetIcp,
|
|
6244
|
+
leadCount: numberFlag(flags, "lead-count", "target-count"),
|
|
6245
|
+
layers: csvFlag(flags, "layers"),
|
|
6246
|
+
preferredProviders: csvFlag(flags, "preferred-providers", "providers"),
|
|
6247
|
+
memoryDimensionFilters: jsonObjectFlag(flags, "memory-dimension-filters"),
|
|
6248
|
+
requireMemoryDimensionMatch: booleanFlag(flags, "require-memory-dimension-match"),
|
|
6249
|
+
includeMemory: booleanFlag(flags, "include-memory", true),
|
|
6250
|
+
includeBrain: booleanFlag(flags, "include-brain", true),
|
|
6251
|
+
includeProviderRoutes: booleanFlag(flags, "include-provider-routes", true),
|
|
6252
|
+
includeFailurePatterns: booleanFlag(flags, "include-failure-patterns", true),
|
|
6253
|
+
includeDeliveryRisk: booleanFlag(flags, "include-delivery-risk", true),
|
|
6254
|
+
includeGlobalBrain: booleanFlag(flags, "include-global-brain", true),
|
|
6255
|
+
includePlannedProviders: booleanFlag(flags, "include-planned-providers", true),
|
|
6256
|
+
days: numberFlag(flags, "days"),
|
|
6257
|
+
minConfidence: numberFlag(flags, "min-confidence"),
|
|
6258
|
+
minSampleSize: numberFlag(flags, "min-sample-size"),
|
|
6259
|
+
limit: numberFlag(flags, "limit")
|
|
6260
|
+
};
|
|
6261
|
+
const result = await signaliz.gtm.campaignStartContext(input);
|
|
6262
|
+
printResult(result, flags);
|
|
6263
|
+
return;
|
|
6264
|
+
}
|
|
6265
|
+
if (subcommand === "strategy-memory" || subcommand === "memory-status" || subcommand === "strategy-memory-status") {
|
|
6266
|
+
const flags = parseFlags(argv.slice(1));
|
|
6267
|
+
const input = {
|
|
6268
|
+
strategyTemplate: stringFlag(flags, "strategy-template", "template"),
|
|
6269
|
+
query: stringFlag(flags, "query", "goal", "q"),
|
|
6270
|
+
campaignBrief: stringFlag(flags, "brief", "campaign-brief"),
|
|
6271
|
+
targetIcp: jsonObjectFlag(flags, "target-icp", "icp"),
|
|
6272
|
+
memoryDimensionFilters: jsonObjectFlag(flags, "memory-dimension-filters"),
|
|
6273
|
+
requireMemoryDimensionMatch: booleanFlag(flags, "require-memory-dimension-match"),
|
|
6274
|
+
includeSamples: booleanFlag(flags, "include-samples"),
|
|
6275
|
+
includeSources: !booleanFlag(flags, "no-sources"),
|
|
6276
|
+
days: numberFlag(flags, "days"),
|
|
6277
|
+
limit: numberFlag(flags, "limit")
|
|
6278
|
+
};
|
|
6279
|
+
const result = await signaliz.gtm.campaignStrategyMemoryStatus(input);
|
|
6280
|
+
printResult(result, flags);
|
|
6281
|
+
return;
|
|
6282
|
+
}
|
|
6283
|
+
if (subcommand === "plan") {
|
|
6284
|
+
const flags = parseFlags(argv.slice(1));
|
|
6285
|
+
const campaignBrief = stringFlag(flags, "brief", "campaign-brief", "goal");
|
|
6286
|
+
if (!campaignBrief && !stringFlag(flags, "campaign-id") && !stringFlag(flags, "campaign-build-id")) {
|
|
6287
|
+
throw new Error("gtm plan requires --brief, --campaign-id, or --campaign-build-id");
|
|
6288
|
+
}
|
|
6289
|
+
const input = {
|
|
6290
|
+
campaignId: stringFlag(flags, "campaign-id"),
|
|
6291
|
+
campaignBuildId: stringFlag(flags, "campaign-build-id"),
|
|
6292
|
+
campaignBrief,
|
|
6293
|
+
strategyTemplate: stringFlag(flags, "strategy-template", "template"),
|
|
6294
|
+
targetIcp: jsonObjectFlag(flags, "target-icp", "icp"),
|
|
6295
|
+
leadCount: numberFlag(flags, "lead-count", "target-count"),
|
|
6296
|
+
layers: csvFlag(flags, "layers"),
|
|
6297
|
+
preferredProviders: csvFlag(flags, "preferred-providers", "providers"),
|
|
6298
|
+
strategyModel: stringFlag(flags, "strategy-model"),
|
|
6299
|
+
includeStrategyPatterns: !booleanFlag(flags, "no-strategy-patterns") && !booleanFlag(flags, "no-agency-patterns"),
|
|
6300
|
+
includeWorkflowPatterns: !booleanFlag(flags, "no-workflow-patterns") && !booleanFlag(flags, "no-clay-patterns"),
|
|
6301
|
+
includeNangoCatalog: !booleanFlag(flags, "no-nango-catalog"),
|
|
6302
|
+
partnerEcosystem: csvFlag(flags, "partner-ecosystem", "partners"),
|
|
6303
|
+
includeMemory: booleanFlag(flags, "include-memory", true),
|
|
6304
|
+
includeBrain: booleanFlag(flags, "include-brain", true),
|
|
6305
|
+
includeProviderRoutes: booleanFlag(flags, "include-provider-routes", true),
|
|
6306
|
+
includeFailurePatterns: booleanFlag(flags, "include-failure-patterns", true),
|
|
6307
|
+
includePlannedProviders: booleanFlag(flags, "include-planned-providers", true),
|
|
6308
|
+
days: numberFlag(flags, "days"),
|
|
6309
|
+
limit: numberFlag(flags, "limit")
|
|
6310
|
+
};
|
|
6311
|
+
const result = await signaliz.gtm.campaignBuildPlan(input);
|
|
6312
|
+
printResult(result, flags);
|
|
6313
|
+
return;
|
|
6314
|
+
}
|
|
6315
|
+
if (subcommand === "agent-plan" || subcommand === "campaign-agent-plan") {
|
|
6316
|
+
const flags = parseFlags(argv.slice(1));
|
|
6317
|
+
const goal = stringFlag(flags, "goal", "brief", "campaign-brief");
|
|
6318
|
+
if (!goal && !stringFlag(flags, "campaign-id") && !stringFlag(flags, "campaign-build-id") && !stringFlag(flags, "strategy-template", "template")) {
|
|
6319
|
+
throw new Error("gtm agent-plan requires --goal, --campaign-id, --campaign-build-id, or --strategy-template");
|
|
6320
|
+
}
|
|
6321
|
+
const input = {
|
|
6322
|
+
goal,
|
|
6323
|
+
campaignName: stringFlag(flags, "campaign-name", "name"),
|
|
6324
|
+
campaignId: stringFlag(flags, "campaign-id"),
|
|
6325
|
+
campaignBuildId: stringFlag(flags, "campaign-build-id", "build-id"),
|
|
6326
|
+
strategyTemplate: stringFlag(flags, "strategy-template", "template"),
|
|
6327
|
+
operatingPlaybooks: csvFlag(flags, "operating-playbooks", "playbooks"),
|
|
6328
|
+
accountContext: stringFlag(flags, "account-context", "workspace-context"),
|
|
6329
|
+
targetIcp: jsonObjectFlag(flags, "target-icp", "icp"),
|
|
6330
|
+
targetCount: numberFlag(flags, "target-count", "lead-count"),
|
|
6331
|
+
builtIns: campaignAgentBuiltInsFromFlags(flags),
|
|
6332
|
+
useLocalLeads: booleanFlag(flags, "use-local-leads") || void 0,
|
|
6333
|
+
layers: csvFlag(flags, "layers"),
|
|
6334
|
+
preferredProviders: csvFlag(flags, "preferred-providers", "providers"),
|
|
6335
|
+
customTools: campaignAgentCustomToolRoutesFromFlags(flags),
|
|
6336
|
+
strategyModel: stringFlag(flags, "strategy-model"),
|
|
6337
|
+
includeStrategyPatterns: !booleanFlag(flags, "no-strategy-patterns"),
|
|
6338
|
+
includeWorkflowPatterns: !booleanFlag(flags, "no-workflow-patterns"),
|
|
6339
|
+
includeNangoCatalog: !booleanFlag(flags, "no-nango-catalog"),
|
|
6340
|
+
partnerEcosystem: csvFlag(flags, "partner-ecosystem", "partners"),
|
|
6341
|
+
includeMemory: !booleanFlag(flags, "no-memory"),
|
|
6342
|
+
includeBrain: !booleanFlag(flags, "no-brain"),
|
|
6343
|
+
includeProviderRoutes: !booleanFlag(flags, "no-provider-routes"),
|
|
6344
|
+
includeFailurePatterns: !booleanFlag(flags, "no-failure-patterns"),
|
|
6345
|
+
includeDeliveryRisk: !booleanFlag(flags, "no-delivery-risk"),
|
|
6346
|
+
includePlannedProviders: !booleanFlag(flags, "no-planned-providers"),
|
|
6347
|
+
days: numberFlag(flags, "days"),
|
|
6348
|
+
limit: numberFlag(flags, "limit")
|
|
6349
|
+
};
|
|
6350
|
+
const result = await signaliz.gtm.campaignAgentPlan(input);
|
|
6351
|
+
printResult(result, flags);
|
|
6352
|
+
return;
|
|
6353
|
+
}
|
|
6354
|
+
if (subcommand === "agent-template" || subcommand === "campaign-agent-template" || subcommand === "request-template") {
|
|
6355
|
+
const flags = parseFlags(argv.slice(1));
|
|
6356
|
+
const input = {
|
|
6357
|
+
goal: stringFlag(flags, "goal", "brief", "campaign-brief"),
|
|
6358
|
+
campaignName: stringFlag(flags, "campaign-name", "name"),
|
|
6359
|
+
accountLabel: stringFlag(flags, "workspace-label", "account-label"),
|
|
6360
|
+
accountContext: stringFlag(flags, "account-context", "workspace-context"),
|
|
6361
|
+
strategyTemplate: stringFlag(flags, "strategy-template", "template"),
|
|
6362
|
+
operatingPlaybooks: csvFlag(flags, "operating-playbooks", "playbooks"),
|
|
6363
|
+
targetIcp: jsonObjectFlag(flags, "target-icp", "icp"),
|
|
6364
|
+
targetCount: numberFlag(flags, "target-count", "lead-count"),
|
|
6365
|
+
builtIns: campaignAgentBuiltInsFromFlags(flags),
|
|
6366
|
+
includeLocalLeads: booleanFlag(flags, "use-local-leads") || booleanFlag(flags, "include-local-leads") || void 0,
|
|
6367
|
+
includeByoPlaceholder: booleanFlag(flags, "with-byo-placeholder") || booleanFlag(flags, "include-byo-placeholder") || void 0,
|
|
6368
|
+
includeNangoCatalog: !booleanFlag(flags, "no-nango-catalog"),
|
|
6369
|
+
preferredProviders: csvFlag(flags, "preferred-providers", "providers"),
|
|
6370
|
+
privacyMode: stringFlag(flags, "privacy-mode"),
|
|
6371
|
+
destinationType: stringFlag(flags, "destination", "destination-type")
|
|
6372
|
+
};
|
|
6373
|
+
const result = await signaliz.gtm.campaignAgentRequestTemplate(input);
|
|
6374
|
+
printResult(result, flags);
|
|
6375
|
+
return;
|
|
6376
|
+
}
|
|
6377
|
+
if (subcommand === "provider-prepare" || subcommand === "prepare-provider" || subcommand === "recipe-prepare" || subcommand === "prepare-recipe") {
|
|
6378
|
+
const flags = parseFlags(argv.slice(1));
|
|
6379
|
+
const providerId = stringFlag(flags, "provider-id", "provider") || argv[1];
|
|
6380
|
+
if (!providerId) {
|
|
6381
|
+
throw new Error("gtm provider-prepare requires --provider-id or provider id");
|
|
6382
|
+
}
|
|
6383
|
+
const input = {
|
|
6384
|
+
providerId,
|
|
6385
|
+
providerName: stringFlag(flags, "provider-name", "name"),
|
|
6386
|
+
description: stringFlag(flags, "description"),
|
|
6387
|
+
layerCapabilities: csvFlag(flags, "layer-capabilities", "layers"),
|
|
6388
|
+
invocationType: stringFlag(flags, "invocation-type"),
|
|
6389
|
+
authStrategy: stringFlag(flags, "auth-strategy"),
|
|
6390
|
+
endpointUrl: stringFlag(flags, "endpoint-url"),
|
|
6391
|
+
httpMethod: stringFlag(flags, "http-method") || void 0,
|
|
6392
|
+
secretRef: stringFlag(flags, "secret-ref"),
|
|
6393
|
+
workspaceIntegrationId: stringFlag(flags, "workspace-integration-id"),
|
|
6394
|
+
workspaceMcpServerId: stringFlag(flags, "workspace-mcp-server-id"),
|
|
6395
|
+
workspaceConnectionId: stringFlag(flags, "workspace-connection-id"),
|
|
6396
|
+
requestTemplate: jsonObjectFlag(flags, "request-template"),
|
|
6397
|
+
responseMapping: jsonObjectFlag(flags, "response-mapping"),
|
|
6398
|
+
inputSchema: jsonObjectFlag(flags, "input-schema"),
|
|
6399
|
+
outputSchema: jsonObjectFlag(flags, "output-schema"),
|
|
6400
|
+
readiness: jsonObjectFlag(flags, "readiness"),
|
|
6401
|
+
metadata: jsonObjectFlag(flags, "metadata"),
|
|
6402
|
+
layer: stringFlag(flags, "layer"),
|
|
6403
|
+
campaignId: stringFlag(flags, "campaign-id"),
|
|
6404
|
+
useSignalizFallback: !booleanFlag(flags, "no-signaliz-fallback"),
|
|
6405
|
+
priority: numberFlag(flags, "priority"),
|
|
6406
|
+
status: stringFlag(flags, "status"),
|
|
6407
|
+
context: jsonObjectFlag(flags, "context")
|
|
6408
|
+
};
|
|
6409
|
+
const result = await signaliz.gtm.prepareProviderRecipe(input);
|
|
6410
|
+
printResult(result, flags);
|
|
6411
|
+
return;
|
|
6412
|
+
}
|
|
6413
|
+
if (subcommand === "activate-route" || subcommand === "route-activate") {
|
|
6414
|
+
const flags = parseFlags(argv.slice(1));
|
|
6415
|
+
const providerId = stringFlag(flags, "provider-id", "provider") || argv[1];
|
|
6416
|
+
if (!providerId) {
|
|
6417
|
+
throw new Error("gtm activate-route requires --provider-id or provider id");
|
|
6418
|
+
}
|
|
6419
|
+
const layers = csvFlag(flags, "layers");
|
|
6420
|
+
const layer = stringFlag(flags, "layer");
|
|
6421
|
+
if (!layer && !layers?.length) {
|
|
6422
|
+
throw new Error("gtm activate-route requires --layer or --layers");
|
|
6423
|
+
}
|
|
6424
|
+
const confirm = booleanFlag(flags, "confirm");
|
|
6425
|
+
const input = {
|
|
6426
|
+
providerId,
|
|
6427
|
+
providerName: stringFlag(flags, "provider-name", "name"),
|
|
6428
|
+
description: stringFlag(flags, "description"),
|
|
6429
|
+
campaignId: stringFlag(flags, "campaign-id"),
|
|
6430
|
+
layer,
|
|
6431
|
+
layers,
|
|
6432
|
+
invocationType: stringFlag(flags, "invocation-type"),
|
|
6433
|
+
authStrategy: stringFlag(flags, "auth-strategy"),
|
|
6434
|
+
endpointUrl: stringFlag(flags, "endpoint-url"),
|
|
6435
|
+
httpMethod: stringFlag(flags, "http-method") || void 0,
|
|
6436
|
+
secretRef: stringFlag(flags, "secret-ref"),
|
|
6437
|
+
workspaceIntegrationId: stringFlag(flags, "workspace-integration-id"),
|
|
6438
|
+
workspaceMcpServerId: stringFlag(flags, "workspace-mcp-server-id"),
|
|
6439
|
+
workspaceConnectionId: stringFlag(flags, "workspace-connection-id"),
|
|
6440
|
+
useSignalizFallback: !booleanFlag(flags, "no-signaliz-fallback"),
|
|
6441
|
+
priority: numberFlag(flags, "priority"),
|
|
6442
|
+
routeConfig: jsonObjectFlag(flags, "route-config"),
|
|
6443
|
+
requestTemplate: jsonObjectFlag(flags, "request-template"),
|
|
6444
|
+
responseMapping: jsonObjectFlag(flags, "response-mapping"),
|
|
6445
|
+
inputSchema: jsonObjectFlag(flags, "input-schema"),
|
|
6446
|
+
outputSchema: jsonObjectFlag(flags, "output-schema"),
|
|
6447
|
+
readiness: jsonObjectFlag(flags, "readiness"),
|
|
6448
|
+
metadata: jsonObjectFlag(flags, "metadata"),
|
|
6449
|
+
status: stringFlag(flags, "status"),
|
|
6450
|
+
routeStatus: stringFlag(flags, "route-status"),
|
|
6451
|
+
replaceExistingRoutes: !booleanFlag(flags, "keep-existing-routes"),
|
|
6452
|
+
dryRun: !confirm,
|
|
6453
|
+
confirm,
|
|
6454
|
+
context: jsonObjectFlag(flags, "context")
|
|
6455
|
+
};
|
|
6456
|
+
const result = await signaliz.gtm.activateProviderRoute(input);
|
|
6457
|
+
printResult(result, flags);
|
|
6458
|
+
return;
|
|
6459
|
+
}
|
|
6460
|
+
printGtmHelp();
|
|
6461
|
+
}
|
|
6462
|
+
async function handleCampaignAgentCommand(signaliz, argv) {
|
|
6463
|
+
const subcommand = argv[0];
|
|
6464
|
+
if (!subcommand || subcommand === "help" || subcommand === "--help" || subcommand === "-h") {
|
|
6465
|
+
printCampaignAgentHelp();
|
|
6466
|
+
return;
|
|
6467
|
+
}
|
|
6468
|
+
if (["init", "template", "request-template", "new"].includes(subcommand)) {
|
|
6469
|
+
const flags2 = parseFlags(argv.slice(1));
|
|
6470
|
+
const request2 = campaignAgentRequestTemplateFromFlags(flags2);
|
|
6471
|
+
const outputFile = stringFlag(flags2, "output-file", "out");
|
|
6472
|
+
if (outputFile) {
|
|
6473
|
+
(0, import_node_fs.writeFileSync)(outputFile, `${JSON.stringify(request2, null, 2)}
|
|
6474
|
+
`, "utf8");
|
|
6475
|
+
}
|
|
6476
|
+
if (booleanFlag(flags2, "json") || !outputFile) {
|
|
6477
|
+
printJson(request2);
|
|
6478
|
+
} else {
|
|
6479
|
+
console.log(`Campaign request template written: ${outputFile}`);
|
|
6480
|
+
console.log(`Next: signaliz campaign-agent plan --request-file ${outputFile} --json`);
|
|
6481
|
+
}
|
|
6482
|
+
return;
|
|
6483
|
+
}
|
|
6484
|
+
if (!["plan", "proof", "smoke", "commit-plan", "dry-run", "build-approved", "launch-approved"].includes(subcommand)) {
|
|
6485
|
+
printCampaignAgentHelp();
|
|
6486
|
+
return;
|
|
6487
|
+
}
|
|
6488
|
+
const flags = parseFlags(argv.slice(1));
|
|
6489
|
+
const requestFromFile = campaignAgentRequestFileFromFlags(flags);
|
|
6490
|
+
const goal = stringFlag(flags, "goal", "brief") ?? stringOrUndefined(requestFromFile?.goal);
|
|
6491
|
+
if (!goal) throw new Error(`campaign-agent ${subcommand} requires --goal or a request file with goal`);
|
|
6492
|
+
const isApprovedBuild = subcommand === "build-approved" || subcommand === "launch-approved";
|
|
6493
|
+
const isCommitPlan = subcommand === "commit-plan";
|
|
6494
|
+
const isConfirmedCommit = isCommitPlan && booleanFlag(flags, "confirm-write");
|
|
6495
|
+
const approvedBy = stringFlag(flags, "approved-by");
|
|
6496
|
+
if (isApprovedBuild) {
|
|
6497
|
+
if (!booleanFlag(flags, "confirm-launch")) {
|
|
6498
|
+
throw new Error(`campaign-agent ${subcommand} requires --confirm-launch`);
|
|
6499
|
+
}
|
|
6500
|
+
if (!approvedBy) throw new Error(`campaign-agent ${subcommand} requires --approved-by`);
|
|
6501
|
+
}
|
|
6502
|
+
if (isConfirmedCommit && !approvedBy) {
|
|
6503
|
+
throw new Error("campaign-agent commit-plan --confirm-write requires --approved-by");
|
|
6504
|
+
}
|
|
6505
|
+
const request = mergeCampaignAgentRequests(
|
|
6506
|
+
requestFromFile,
|
|
6507
|
+
campaignAgentRequestFromFlags(goal, flags, { includeDefaults: !requestFromFile })
|
|
6508
|
+
);
|
|
6509
|
+
const plan = await signaliz.campaignBuilderAgent.createPlan(request, {
|
|
6510
|
+
discoverCapabilities: !booleanFlag(flags, "skip-discovery"),
|
|
6511
|
+
scopeCampaign: !booleanFlag(flags, "skip-scope"),
|
|
6512
|
+
includeStrategyMemoryStatus: !booleanFlag(flags, "no-strategy-memory"),
|
|
6513
|
+
includeKernelPlan: !booleanFlag(flags, "no-kernel-plan"),
|
|
6514
|
+
includeDeliveryRisk: !booleanFlag(flags, "no-delivery-risk")
|
|
6515
|
+
});
|
|
6516
|
+
if (subcommand === "proof" || subcommand === "smoke") {
|
|
6517
|
+
const result = await signaliz.campaignBuilderAgent.dryRunPlan(plan, {
|
|
6518
|
+
idempotencyKey: stringFlag(flags, "idempotency-key")
|
|
6519
|
+
});
|
|
6520
|
+
const proof = createCampaignAgentProofReceipt(plan, result);
|
|
6521
|
+
if (booleanFlag(flags, "json")) {
|
|
6522
|
+
printJson(proof);
|
|
6523
|
+
} else {
|
|
6524
|
+
printCampaignAgentProof(proof);
|
|
6525
|
+
}
|
|
6526
|
+
if (!proof.success) process.exitCode = 1;
|
|
6527
|
+
return;
|
|
6528
|
+
}
|
|
6529
|
+
if (isCommitPlan) {
|
|
6530
|
+
const result = await signaliz.campaignBuilderAgent.commitPlan(plan, {
|
|
6531
|
+
confirm: isConfirmedCommit,
|
|
6532
|
+
dryRun: !isConfirmedCommit,
|
|
6533
|
+
approvedBy,
|
|
6534
|
+
idempotencyKey: stringFlag(flags, "idempotency-key"),
|
|
6535
|
+
rationale: stringFlag(flags, "rationale")
|
|
6536
|
+
});
|
|
6537
|
+
printCampaignAgentExecution({ plan, result }, flags);
|
|
6538
|
+
return;
|
|
6539
|
+
}
|
|
6540
|
+
if (subcommand === "dry-run") {
|
|
6541
|
+
const result = await signaliz.campaignBuilderAgent.dryRunPlan(plan, {
|
|
6542
|
+
idempotencyKey: stringFlag(flags, "idempotency-key")
|
|
6543
|
+
});
|
|
6544
|
+
printCampaignAgentExecution({ plan, result }, flags);
|
|
6545
|
+
return;
|
|
6546
|
+
}
|
|
6547
|
+
if (isApprovedBuild) {
|
|
6548
|
+
const approvedTypes = approvedTypesFromFlags(plan, flags);
|
|
6549
|
+
const approval = createCampaignBuilderApproval(plan, {
|
|
6550
|
+
approvedBy,
|
|
6551
|
+
approvedTypes,
|
|
6552
|
+
spendLimitCredits: numberFlag(flags, "spend-limit", "spend-limit-credits", "max-credits"),
|
|
6553
|
+
approvedRouteIds: approvedRouteIdsFromFlags(plan, flags),
|
|
6554
|
+
notes: stringFlag(flags, "approval-notes", "notes")
|
|
6555
|
+
});
|
|
6556
|
+
const result = await signaliz.campaignBuilderAgent.buildApprovedPlan(plan, approval, {
|
|
6557
|
+
idempotencyKey: stringFlag(flags, "idempotency-key"),
|
|
6558
|
+
commitBeforeLaunch: booleanFlag(flags, "commit-before-launch")
|
|
6559
|
+
});
|
|
6560
|
+
printCampaignAgentExecution({ plan, approval, result }, flags);
|
|
6561
|
+
return;
|
|
6562
|
+
}
|
|
6563
|
+
if (booleanFlag(flags, "json")) {
|
|
6564
|
+
printJson(plan);
|
|
6565
|
+
} else {
|
|
6566
|
+
printCampaignAgentPlan(plan);
|
|
6567
|
+
}
|
|
6568
|
+
}
|
|
6569
|
+
function campaignAgentRequestTemplateFromFlags(flags) {
|
|
6570
|
+
const goal = stringFlag(flags, "goal", "brief") || "Build a strategy-template campaign for mature operators in the target ICP.";
|
|
6571
|
+
const request = campaignAgentRequestFromFlags(goal, flags, { includeDefaults: true });
|
|
6572
|
+
const options = {
|
|
6573
|
+
...request,
|
|
6574
|
+
includeLocalLeads: booleanFlag(flags, "use-local-leads"),
|
|
6575
|
+
includeCustomToolPlaceholder: booleanFlag(flags, "with-byo-placeholder") || booleanFlag(flags, "include-custom-tool-placeholder") || booleanFlag(flags, "include-byo-placeholder"),
|
|
6576
|
+
includeNango: !booleanFlag(flags, "no-nango-catalog")
|
|
6577
|
+
};
|
|
6578
|
+
return createCampaignBuilderAgentRequestTemplate(options);
|
|
6579
|
+
}
|
|
6580
|
+
function campaignAgentRequestFileFromFlags(flags) {
|
|
6581
|
+
const file = stringFlag(flags, "request-file", "input-file", "campaign-file");
|
|
6582
|
+
if (!file) return void 0;
|
|
6583
|
+
const parsed = JSON.parse((0, import_node_fs.readFileSync)(file, "utf8"));
|
|
6584
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
6585
|
+
throw new Error(`Expected JSON object for --request-file`);
|
|
6586
|
+
}
|
|
6587
|
+
return parsed;
|
|
6588
|
+
}
|
|
6589
|
+
function campaignAgentRequestFromFlags(goal, flags, options = {}) {
|
|
6590
|
+
const builtIns = campaignAgentBuiltInsFromFlags(flags);
|
|
6591
|
+
const integrations = campaignAgentCustomToolRoutesFromFlags(flags);
|
|
6592
|
+
const includeDefaults = options.includeDefaults !== false;
|
|
6593
|
+
const request = {
|
|
6594
|
+
goal,
|
|
6595
|
+
campaignName: stringFlag(flags, "campaign-name", "name"),
|
|
6596
|
+
accountLabel: stringFlag(flags, "workspace-label", "account-label"),
|
|
6597
|
+
strategyTemplate: stringFlag(flags, "strategy-template", "template"),
|
|
6598
|
+
accountContext: stringFlag(flags, "account-context", "workspace-context"),
|
|
6599
|
+
targetCount: numberFlag(flags, "target-count", "lead-count"),
|
|
6600
|
+
gtmCampaignId: stringFlag(flags, "gtm-campaign-id", "campaign-id"),
|
|
6601
|
+
icp: jsonObjectFlag(flags, "icp", "target-icp"),
|
|
6602
|
+
brainDefaults: jsonObjectFlag(flags, "brain-defaults"),
|
|
6603
|
+
deliveryRisk: jsonObjectFlag(flags, "delivery-risk"),
|
|
6604
|
+
builtIns,
|
|
6605
|
+
operatingPlaybooks: csvFlag(flags, "operating-playbooks", "playbooks"),
|
|
6606
|
+
integrations,
|
|
6607
|
+
preferredProviders: csvFlag(flags, "preferred-providers", "providers")
|
|
6608
|
+
};
|
|
6609
|
+
if (includeDefaults || flagValue(flags, "strategy-model", "no-strategy-patterns", "no-agency-patterns", "no-workflow-patterns", "no-clay-patterns", "no-nango-catalog", "partners", "revenue-motion") !== void 0) {
|
|
6610
|
+
request.agencyContext = {
|
|
6611
|
+
strategyModel: stringFlag(flags, "strategy-model"),
|
|
6612
|
+
includeStrategyPatterns: !booleanFlag(flags, "no-strategy-patterns") && !booleanFlag(flags, "no-agency-patterns"),
|
|
6613
|
+
includeWorkflowPatterns: !booleanFlag(flags, "no-workflow-patterns") && !booleanFlag(flags, "no-clay-patterns"),
|
|
6614
|
+
includeNangoCatalog: !booleanFlag(flags, "no-nango-catalog"),
|
|
6615
|
+
partnerEcosystem: csvFlag(flags, "partners"),
|
|
6616
|
+
revenueMotion: stringFlag(flags, "revenue-motion")
|
|
6617
|
+
};
|
|
6618
|
+
}
|
|
6619
|
+
if (includeDefaults || flagValue(flags, "no-memory", "no-workspace-history", "use-network-patterns", "privacy-mode") !== void 0) {
|
|
6620
|
+
request.memory = {
|
|
6621
|
+
enabled: !booleanFlag(flags, "no-memory"),
|
|
6622
|
+
useWorkspaceHistory: !booleanFlag(flags, "no-workspace-history"),
|
|
6623
|
+
useNetworkPatterns: booleanFlag(flags, "use-network-patterns"),
|
|
6624
|
+
privacyMode: stringFlag(flags, "privacy-mode")
|
|
6625
|
+
};
|
|
6626
|
+
}
|
|
6627
|
+
if (includeDefaults || flagValue(flags, "max-credits", "no-delivery", "destination") !== void 0) {
|
|
6628
|
+
request.signalizDefaults = {
|
|
6629
|
+
maxCredits: numberFlag(flags, "max-credits"),
|
|
6630
|
+
delivery: {
|
|
6631
|
+
enabled: !booleanFlag(flags, "no-delivery"),
|
|
6632
|
+
destinationType: stringFlag(flags, "destination"),
|
|
6633
|
+
approvalRequired: true
|
|
6634
|
+
}
|
|
6635
|
+
};
|
|
6636
|
+
}
|
|
6637
|
+
if (includeDefaults || flagValue(flags, "no-human-approval", "max-credits-without-approval") !== void 0) {
|
|
6638
|
+
request.approvalPolicy = {
|
|
6639
|
+
requireHumanApproval: !booleanFlag(flags, "no-human-approval"),
|
|
6640
|
+
maxCreditsWithoutApproval: numberFlag(flags, "max-credits-without-approval"),
|
|
6641
|
+
requireApprovalFor: ["memory_retrieval", "spend", "customer_tool", "external_write", "delivery", "launch"]
|
|
6642
|
+
};
|
|
6643
|
+
}
|
|
6644
|
+
return compactRequest(request);
|
|
6645
|
+
}
|
|
6646
|
+
function mergeCampaignAgentRequests(base, override) {
|
|
6647
|
+
if (!base) return override;
|
|
6648
|
+
return compactRequest({
|
|
6649
|
+
...base,
|
|
6650
|
+
...override,
|
|
6651
|
+
icp: mergeRecords(base.icp, override.icp),
|
|
6652
|
+
memory: mergeRecords(base.memory, override.memory),
|
|
6653
|
+
agencyContext: mergeRecords(base.agencyContext, override.agencyContext),
|
|
6654
|
+
signalizDefaults: mergeRecords(base.signalizDefaults, override.signalizDefaults),
|
|
6655
|
+
approvalPolicy: mergeRecords(base.approvalPolicy, override.approvalPolicy),
|
|
6656
|
+
constraints: mergeRecords(base.constraints, override.constraints),
|
|
6657
|
+
workspaceContext: mergeRecords(base.workspaceContext, override.workspaceContext),
|
|
6658
|
+
builtIns: override.builtIns ?? base.builtIns,
|
|
6659
|
+
operatingPlaybooks: override.operatingPlaybooks ?? base.operatingPlaybooks,
|
|
6660
|
+
integrations: override.integrations ?? base.integrations,
|
|
6661
|
+
customerTools: override.customerTools ?? base.customerTools,
|
|
6662
|
+
preferredProviders: override.preferredProviders ?? base.preferredProviders
|
|
6663
|
+
});
|
|
6664
|
+
}
|
|
6665
|
+
function mergeRecords(base, override) {
|
|
6666
|
+
if (!base) return override;
|
|
6667
|
+
if (!override) return base;
|
|
6668
|
+
if (typeof base === "object" && typeof override === "object" && !Array.isArray(base) && !Array.isArray(override)) {
|
|
6669
|
+
return { ...base, ...override };
|
|
6670
|
+
}
|
|
6671
|
+
return override;
|
|
6672
|
+
}
|
|
6673
|
+
function compactRequest(record) {
|
|
6674
|
+
return Object.fromEntries(
|
|
6675
|
+
Object.entries(record).filter(([, value]) => value !== void 0)
|
|
6676
|
+
);
|
|
6677
|
+
}
|
|
6678
|
+
function campaignAgentBuiltInsFromFlags(flags) {
|
|
6679
|
+
const explicit = csvFlag(flags, "builtins", "builtin-tools", "signaliz-tools");
|
|
6680
|
+
const hasBuiltinFlag = Boolean(
|
|
6681
|
+
explicit?.length || flagValue(flags, "use-local-leads") !== void 0 || flagValue(flags, "no-lead-generation") !== void 0 || flagValue(flags, "no-email-finding") !== void 0 || flagValue(flags, "no-verification") !== void 0 || flagValue(flags, "no-signals") !== void 0
|
|
6682
|
+
);
|
|
6683
|
+
if (!hasBuiltinFlag) return void 0;
|
|
6684
|
+
const builtIns = new Set(
|
|
6685
|
+
explicit?.length ? explicit : ["lead_generation", "email_finding", "email_verification", "signals"]
|
|
6686
|
+
);
|
|
6687
|
+
if (booleanFlag(flags, "use-local-leads")) builtIns.add("local_leads");
|
|
6688
|
+
if (booleanFlag(flags, "no-lead-generation")) builtIns.delete("lead_generation");
|
|
6689
|
+
if (booleanFlag(flags, "no-email-finding")) builtIns.delete("email_finding");
|
|
6690
|
+
if (booleanFlag(flags, "no-verification")) builtIns.delete("email_verification");
|
|
6691
|
+
if (booleanFlag(flags, "no-signals")) builtIns.delete("signals");
|
|
6692
|
+
return [...builtIns];
|
|
6693
|
+
}
|
|
6694
|
+
function campaignAgentCustomToolRoutesFromFlags(flags) {
|
|
6695
|
+
const values = repeatedStringFlag(flags, "custom-tool", "customer-tool", "byo-tool", "integration-route");
|
|
6696
|
+
const routes = values.map(parseCampaignAgentCustomToolRoute);
|
|
6697
|
+
return routes.length > 0 ? routes : void 0;
|
|
6698
|
+
}
|
|
6699
|
+
function parseCampaignAgentCustomToolRoute(raw) {
|
|
6700
|
+
const record = raw.trim().startsWith("{") ? jsonObjectFromString(raw, "--custom-tool") : raw.includes("=") ? keyValueObject(raw) : colonRouteObject(raw);
|
|
6701
|
+
const layer = normalizeCampaignBuilderLayer(String(record.layer ?? record.use_for_layer ?? record.useForLayer ?? "enrichment"));
|
|
6702
|
+
const gtmLayers = stringArrayValue(record.gtm_layers ?? record.gtmLayers ?? record.capabilities);
|
|
6703
|
+
const provider = String(record.provider ?? record.provider_id ?? record.providerId ?? "custom_mcp");
|
|
6704
|
+
const toolName = stringOrUndefined(record.tool ?? record.tool_name ?? record.toolName);
|
|
6705
|
+
const label = stringOrUndefined(record.label ?? record.name) ?? provider;
|
|
6706
|
+
const mcpServerName = stringOrUndefined(record.mcp ?? record.server ?? record.mcp_server_name ?? record.mcpServerName);
|
|
6707
|
+
const mode = normalizeRouteMode(String(record.mode ?? "required"));
|
|
6708
|
+
return {
|
|
6709
|
+
provider,
|
|
6710
|
+
layer,
|
|
6711
|
+
gtmLayers,
|
|
6712
|
+
mode,
|
|
6713
|
+
toolName,
|
|
6714
|
+
mcpServerName,
|
|
6715
|
+
label,
|
|
6716
|
+
approvalRequired: optionalBoolean(record.approval_required ?? record.approvalRequired, true),
|
|
6717
|
+
config: {
|
|
6718
|
+
provider_id: record.provider_id ?? record.providerId,
|
|
6719
|
+
available_tools: stringArrayValue(record.available_tools ?? record.availableTools ?? record.tools),
|
|
6720
|
+
raw: raw.trim()
|
|
6721
|
+
},
|
|
6722
|
+
rationale: `${label} is a user-provided campaign-builder route declared from the CLI.`
|
|
6723
|
+
};
|
|
6724
|
+
}
|
|
6725
|
+
function colonRouteObject(raw) {
|
|
6726
|
+
const [provider, layer, tool, mcp] = raw.split(":").map((part) => part.trim()).filter(Boolean);
|
|
6727
|
+
if (!provider || !layer) {
|
|
6728
|
+
throw new Error("Expected --custom-tool provider:layer:tool[:mcp] or key=value pairs");
|
|
6729
|
+
}
|
|
6730
|
+
return { provider, layer, tool, mcp };
|
|
6731
|
+
}
|
|
6732
|
+
function keyValueObject(raw) {
|
|
6733
|
+
const record = {};
|
|
6734
|
+
for (const segment of raw.split(",")) {
|
|
6735
|
+
const eq = segment.indexOf("=");
|
|
6736
|
+
if (eq < 0) continue;
|
|
6737
|
+
const key = segment.slice(0, eq).trim().replace(/-/g, "_");
|
|
6738
|
+
const value = segment.slice(eq + 1).trim();
|
|
6739
|
+
record[key] = value;
|
|
6740
|
+
}
|
|
6741
|
+
return record;
|
|
6742
|
+
}
|
|
6743
|
+
function normalizeCampaignBuilderLayer(value) {
|
|
6744
|
+
const normalized = normalizeEnumValue(value);
|
|
6745
|
+
const allowed = ["workspace_context", "memory", "source", "enrichment", "qualification", "copy", "delivery", "feedback", "approval"];
|
|
6746
|
+
if (!allowed.includes(normalized)) {
|
|
6747
|
+
throw new Error(`Unknown campaign-builder layer "${value}". Use source, enrichment, qualification, copy, delivery, feedback, or approval.`);
|
|
6748
|
+
}
|
|
6749
|
+
return normalized;
|
|
6750
|
+
}
|
|
6751
|
+
function normalizeRouteMode(value) {
|
|
6752
|
+
const normalized = normalizeEnumValue(value);
|
|
6753
|
+
return ["required", "if_available", "fallback", "disabled"].includes(normalized) ? normalized : "required";
|
|
6754
|
+
}
|
|
6755
|
+
function normalizeEnumValue(value) {
|
|
6756
|
+
return value.trim().toLowerCase().replace(/-/g, "_");
|
|
6757
|
+
}
|
|
6758
|
+
function stringArrayValue(value) {
|
|
6759
|
+
const values = Array.isArray(value) ? value : value === void 0 ? [] : [value];
|
|
6760
|
+
const parsed = values.flatMap((item) => String(item).split(/[|,]/).map((part) => part.trim()).filter(Boolean));
|
|
6761
|
+
return parsed.length > 0 ? parsed : void 0;
|
|
6762
|
+
}
|
|
6763
|
+
function stringOrUndefined(value) {
|
|
6764
|
+
return typeof value === "string" && value.trim() ? value.trim() : void 0;
|
|
6765
|
+
}
|
|
6766
|
+
function optionalBoolean(value, defaultValue) {
|
|
6767
|
+
if (value === void 0) return defaultValue;
|
|
6768
|
+
if (typeof value === "boolean") return value;
|
|
6769
|
+
return parseBoolean(String(value), defaultValue);
|
|
6770
|
+
}
|
|
6771
|
+
function approvedTypesFromFlags(plan, flags) {
|
|
6772
|
+
const requested = csvFlag(flags, "approved-types", "approve-types");
|
|
6773
|
+
if (requested?.length) return requested;
|
|
6774
|
+
if (!booleanFlag(flags, "approve-all")) {
|
|
6775
|
+
throw new Error("campaign-agent build-approved requires --approve-all or --approved-types");
|
|
6776
|
+
}
|
|
6777
|
+
return [...new Set(plan.approvals.map((item) => item.type))];
|
|
6778
|
+
}
|
|
6779
|
+
function approvedRouteIdsFromFlags(plan, flags) {
|
|
6780
|
+
const requested = csvFlag(flags, "approved-route-ids", "route-ids");
|
|
6781
|
+
if (requested?.length) return requested;
|
|
6782
|
+
if (!booleanFlag(flags, "approve-all")) return void 0;
|
|
6783
|
+
const routeIds = plan.approvals.map((item) => item.routeId).filter((id) => Boolean(id));
|
|
6784
|
+
return routeIds.length > 0 ? routeIds : void 0;
|
|
6785
|
+
}
|
|
6786
|
+
function parseFlags(argv) {
|
|
6787
|
+
const flags = {};
|
|
6788
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
6789
|
+
const token = argv[i];
|
|
6790
|
+
if (!token.startsWith("--")) continue;
|
|
6791
|
+
const eq = token.indexOf("=");
|
|
6792
|
+
const key = normalizeFlagName(eq >= 0 ? token.slice(2, eq) : token.slice(2));
|
|
6793
|
+
const value = eq >= 0 ? token.slice(eq + 1) : argv[i + 1] && !argv[i + 1].startsWith("--") ? argv[++i] : true;
|
|
6794
|
+
const existing = flags[key];
|
|
6795
|
+
if (existing === void 0) {
|
|
6796
|
+
flags[key] = value;
|
|
6797
|
+
} else if (Array.isArray(existing)) {
|
|
6798
|
+
existing.push(String(value));
|
|
6799
|
+
} else {
|
|
6800
|
+
flags[key] = [String(existing), String(value)];
|
|
6801
|
+
}
|
|
6802
|
+
}
|
|
6803
|
+
return flags;
|
|
6804
|
+
}
|
|
6805
|
+
function normalizeFlagName(name) {
|
|
6806
|
+
return name.replace(/_/g, "-");
|
|
6807
|
+
}
|
|
6808
|
+
function flagValue(flags, ...names) {
|
|
6809
|
+
for (const name of names.map(normalizeFlagName)) {
|
|
6810
|
+
if (flags[name] !== void 0) return flags[name];
|
|
6811
|
+
}
|
|
6812
|
+
return void 0;
|
|
6813
|
+
}
|
|
6814
|
+
function stringFlag(flags, ...names) {
|
|
6815
|
+
const value = flagValue(flags, ...names);
|
|
6816
|
+
if (Array.isArray(value)) return value.at(-1);
|
|
6817
|
+
if (value === void 0 || value === true || value === false) return void 0;
|
|
6818
|
+
const trimmed = String(value).trim();
|
|
6819
|
+
return trimmed || void 0;
|
|
6820
|
+
}
|
|
6821
|
+
function numberFlag(flags, ...names) {
|
|
6822
|
+
const value = stringFlag(flags, ...names);
|
|
6823
|
+
if (!value) return void 0;
|
|
6824
|
+
const parsed = Number(value);
|
|
6825
|
+
if (!Number.isFinite(parsed)) throw new Error(`Expected numeric value for --${names[0]}`);
|
|
6826
|
+
return parsed;
|
|
6827
|
+
}
|
|
6828
|
+
function booleanFlag(flags, name, defaultValue = false) {
|
|
6829
|
+
const value = flagValue(flags, name);
|
|
6830
|
+
if (value === void 0) return defaultValue;
|
|
6831
|
+
if (Array.isArray(value)) return value.length > 0 ? parseBoolean(value.at(-1), defaultValue) : defaultValue;
|
|
6832
|
+
return parseBoolean(value, defaultValue);
|
|
6833
|
+
}
|
|
6834
|
+
function parseBoolean(value, defaultValue) {
|
|
6835
|
+
if (value === void 0) return defaultValue;
|
|
6836
|
+
if (typeof value === "boolean") return value;
|
|
6837
|
+
return !["0", "false", "no", "off"].includes(value.toLowerCase());
|
|
6838
|
+
}
|
|
6839
|
+
function csvFlag(flags, ...names) {
|
|
6840
|
+
const value = flagValue(flags, ...names);
|
|
6841
|
+
const values = Array.isArray(value) ? value : value === void 0 || typeof value === "boolean" ? [] : [value];
|
|
6842
|
+
const parsed = values.flatMap((item) => String(item).split(",").map((part) => part.trim()).filter(Boolean));
|
|
6843
|
+
return parsed.length > 0 ? parsed : void 0;
|
|
6844
|
+
}
|
|
6845
|
+
function repeatedStringFlag(flags, ...names) {
|
|
6846
|
+
const value = flagValue(flags, ...names);
|
|
6847
|
+
if (Array.isArray(value)) return value.map(String).map((item) => item.trim()).filter(Boolean);
|
|
6848
|
+
if (value === void 0 || typeof value === "boolean") return [];
|
|
6849
|
+
const trimmed = String(value).trim();
|
|
6850
|
+
return trimmed ? [trimmed] : [];
|
|
6851
|
+
}
|
|
6852
|
+
function jsonObjectFlag(flags, ...names) {
|
|
6853
|
+
const value = stringFlag(flags, ...names);
|
|
6854
|
+
if (!value) return void 0;
|
|
6855
|
+
return jsonObjectFromString(value, `--${names[0]}`);
|
|
6856
|
+
}
|
|
6857
|
+
function jsonObjectFromString(value, label) {
|
|
6858
|
+
const parsed = JSON.parse(value);
|
|
6859
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
6860
|
+
throw new Error(`Expected JSON object for ${label}`);
|
|
6861
|
+
}
|
|
6862
|
+
return parsed;
|
|
6863
|
+
}
|
|
6864
|
+
function printResult(result, flags) {
|
|
6865
|
+
if (booleanFlag(flags, "json")) {
|
|
6866
|
+
printJson(result);
|
|
6867
|
+
return;
|
|
6868
|
+
}
|
|
6869
|
+
if (result && typeof result === "object") {
|
|
6870
|
+
const record = result;
|
|
6871
|
+
const title = record.summary || record.message || record.next_action || record.status;
|
|
6872
|
+
if (title) console.log(String(title));
|
|
6873
|
+
printJson(result);
|
|
6874
|
+
return;
|
|
6875
|
+
}
|
|
6876
|
+
console.log(String(result ?? ""));
|
|
6877
|
+
}
|
|
6878
|
+
function printCampaignAgentPlan(plan) {
|
|
6879
|
+
console.log(`Plan: ${plan.campaignName}`);
|
|
6880
|
+
console.log(`Plan ID: ${plan.planId}`);
|
|
6881
|
+
console.log(`Target: ${plan.targetCount}`);
|
|
6882
|
+
console.log(`Estimated credits: ${plan.estimatedCredits}`);
|
|
6883
|
+
console.log(`Memory: ${plan.memory.enabled ? plan.memory.privacyMode : "disabled"}`);
|
|
6884
|
+
console.log(`Playbooks: ${plan.operatingPlaybooks.map((item) => item.slug).join(", ") || "none"}`);
|
|
6885
|
+
console.log(`Strategy memory: ${plan.strategyMemoryStatus ? plan.strategyMemoryStatus.ready === false ? "needs seeding" : "ready" : "not loaded"}`);
|
|
6886
|
+
console.log(`Kernel plan: ${plan.kernelPlan ? "loaded" : "not loaded"}`);
|
|
6887
|
+
console.log(`Approvals: ${plan.approvals.map((item) => item.type).join(", ") || "none"}`);
|
|
6888
|
+
if (plan.warnings.length > 0) {
|
|
6889
|
+
console.log(`Warnings: ${plan.warnings.join("; ")}`);
|
|
6890
|
+
}
|
|
6891
|
+
console.log("\nMCP flow:");
|
|
6892
|
+
for (const step of plan.mcpFlow) {
|
|
6893
|
+
console.log(`- ${step.id}: ${step.tool}${step.approvalRequired ? " (approval required)" : ""}`);
|
|
6894
|
+
}
|
|
6895
|
+
}
|
|
6896
|
+
function printCampaignAgentExecution(payload, flags) {
|
|
6897
|
+
if (booleanFlag(flags, "json")) {
|
|
6898
|
+
printJson(payload);
|
|
6899
|
+
return;
|
|
6900
|
+
}
|
|
6901
|
+
printCampaignAgentPlan(payload.plan);
|
|
6902
|
+
console.log("\nResult:");
|
|
6903
|
+
printJson(payload.result);
|
|
6904
|
+
}
|
|
6905
|
+
function asRecord4(value) {
|
|
6906
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
6907
|
+
}
|
|
6908
|
+
function createCampaignAgentProofReceipt(plan, result) {
|
|
6909
|
+
const strategyMemory = asRecord4(plan.strategyMemoryStatus);
|
|
6910
|
+
const dryRunResult = asRecord4(result);
|
|
6911
|
+
const memoryReady = plan.strategyMemoryStatus ? strategyMemory.ready !== false : false;
|
|
6912
|
+
const dryRunCompleted = dryRunResult.dryRun === true || dryRunResult.dry_run === true || dryRunResult.status === "dry_run";
|
|
6913
|
+
const noLaunch = dryRunCompleted && !dryRunResult.campaignBuildId && !dryRunResult.campaign_build_id;
|
|
6914
|
+
const gates = [
|
|
6915
|
+
{
|
|
6916
|
+
id: "strategy_memory_ready",
|
|
6917
|
+
passed: memoryReady,
|
|
6918
|
+
ready: strategyMemory.ready ?? null,
|
|
6919
|
+
blocker_count: Array.isArray(strategyMemory.blockers) ? strategyMemory.blockers.length : 0
|
|
6920
|
+
},
|
|
6921
|
+
{
|
|
6922
|
+
id: "campaign_plan_ready",
|
|
6923
|
+
passed: Boolean(plan.planId && plan.mcpFlow.length > 0),
|
|
6924
|
+
plan_id: plan.planId,
|
|
6925
|
+
flow_steps: plan.mcpFlow.length
|
|
6926
|
+
},
|
|
6927
|
+
{
|
|
6928
|
+
id: "approval_gates_present",
|
|
6929
|
+
passed: plan.approvals.length > 0,
|
|
6930
|
+
approval_types: plan.approvals.map((approval) => approval.type)
|
|
6931
|
+
},
|
|
6932
|
+
{
|
|
6933
|
+
id: "dry_run_completed",
|
|
6934
|
+
passed: dryRunCompleted,
|
|
6935
|
+
status: dryRunResult.status ?? null,
|
|
6936
|
+
current_phase: dryRunResult.currentPhase ?? dryRunResult.current_phase ?? null
|
|
6937
|
+
},
|
|
6938
|
+
{
|
|
6939
|
+
id: "no_spendful_launch",
|
|
6940
|
+
passed: noLaunch,
|
|
6941
|
+
campaign_build_id: dryRunResult.campaignBuildId ?? dryRunResult.campaign_build_id ?? null
|
|
6942
|
+
}
|
|
6943
|
+
];
|
|
6944
|
+
return {
|
|
6945
|
+
receipt_version: "campaign-agent-proof.v1",
|
|
6946
|
+
source: "signaliz campaign-agent proof",
|
|
6947
|
+
success: gates.every((gate) => gate.passed),
|
|
6948
|
+
safety: {
|
|
6949
|
+
spendful_tools_called: false,
|
|
6950
|
+
external_writes_called: false,
|
|
6951
|
+
sender_loads_called: false,
|
|
6952
|
+
email_sends_called: false,
|
|
6953
|
+
dry_run_only: true
|
|
6954
|
+
},
|
|
6955
|
+
campaign: {
|
|
6956
|
+
plan_id: plan.planId,
|
|
6957
|
+
campaign_name: plan.campaignName,
|
|
6958
|
+
strategy_template: campaignAgentStrategyTemplate(plan),
|
|
6959
|
+
target_count: plan.targetCount,
|
|
6960
|
+
estimated_credits: plan.estimatedCredits,
|
|
6961
|
+
operating_playbooks: plan.operatingPlaybooks.map((playbook) => playbook.slug)
|
|
6962
|
+
},
|
|
6963
|
+
gates,
|
|
6964
|
+
strategy_memory_status: summarizeCampaignAgentStrategyMemory(strategyMemory),
|
|
6965
|
+
dry_run_result: summarizeCampaignAgentDryRun(dryRunResult),
|
|
6966
|
+
recommended_next_actions: [
|
|
6967
|
+
"Review the plan, approvals, and dry-run result.",
|
|
6968
|
+
"Use campaign-agent commit-plan --confirm-write only after review.",
|
|
6969
|
+
"Use campaign-agent build-approved only with --confirm-launch, approval identity, approval types, and spend limit."
|
|
6970
|
+
]
|
|
6971
|
+
};
|
|
6972
|
+
}
|
|
6973
|
+
function campaignAgentString(...values) {
|
|
6974
|
+
for (const value of values) {
|
|
6975
|
+
if (typeof value === "string" && value.trim()) return value;
|
|
6976
|
+
}
|
|
6977
|
+
return null;
|
|
6978
|
+
}
|
|
6979
|
+
function campaignAgentStrategyTemplate(plan) {
|
|
6980
|
+
const buildRequest = asRecord4(plan.buildRequest);
|
|
6981
|
+
const strategyMemory = asRecord4(plan.strategyMemoryStatus);
|
|
6982
|
+
const statusTemplate = strategyMemory.strategy_template ?? strategyMemory.strategyTemplate;
|
|
6983
|
+
const statusTemplateRecord = asRecord4(statusTemplate);
|
|
6984
|
+
const flowTemplate = plan.mcpFlow.map((step) => asRecord4(step.arguments).strategy_template ?? asRecord4(step.arguments).strategyTemplate).find((value) => typeof value === "string" && value.trim());
|
|
6985
|
+
return campaignAgentString(
|
|
6986
|
+
buildRequest.strategyTemplate,
|
|
6987
|
+
buildRequest.strategy_template,
|
|
6988
|
+
statusTemplate,
|
|
6989
|
+
statusTemplateRecord.slug,
|
|
6990
|
+
statusTemplateRecord.id,
|
|
6991
|
+
flowTemplate
|
|
6992
|
+
);
|
|
6993
|
+
}
|
|
6994
|
+
function summarizeCampaignAgentStrategyMemory(strategyMemory) {
|
|
6995
|
+
if (Object.keys(strategyMemory).length === 0) return { ready: false };
|
|
6996
|
+
const template = strategyMemory.strategy_template ?? strategyMemory.strategyTemplate;
|
|
6997
|
+
const templateRecord = asRecord4(template);
|
|
6998
|
+
const coverage = asRecord4(strategyMemory.coverage);
|
|
6999
|
+
const rawSourceGroups = Array.isArray(strategyMemory.source_groups) ? strategyMemory.source_groups : Array.isArray(strategyMemory.sourceGroups) ? strategyMemory.sourceGroups : [];
|
|
7000
|
+
const sourceGroups = rawSourceGroups.map((group) => {
|
|
7001
|
+
const sourceGroup = asRecord4(group);
|
|
7002
|
+
return {
|
|
7003
|
+
id: sourceGroup.id ?? null,
|
|
7004
|
+
required: sourceGroup.required ?? null,
|
|
7005
|
+
ready: sourceGroup.ready ?? null,
|
|
7006
|
+
counts: asRecord4(sourceGroup.counts)
|
|
7007
|
+
};
|
|
7008
|
+
});
|
|
7009
|
+
return {
|
|
7010
|
+
ready: strategyMemory.ready ?? null,
|
|
7011
|
+
read_only: strategyMemory.read_only ?? strategyMemory.readOnly ?? null,
|
|
7012
|
+
source_tool: campaignAgentString(strategyMemory.source_tool, strategyMemory.sourceTool),
|
|
7013
|
+
strategy_template: {
|
|
7014
|
+
slug: campaignAgentString(template, templateRecord.slug, templateRecord.id),
|
|
7015
|
+
label: campaignAgentString(templateRecord.label)
|
|
7016
|
+
},
|
|
7017
|
+
coverage: {
|
|
7018
|
+
required_groups_ready: coverage.required_groups_ready ?? coverage.requiredGroupsReady ?? null,
|
|
7019
|
+
required_groups_total: coverage.required_groups_total ?? coverage.requiredGroupsTotal ?? null,
|
|
7020
|
+
source_groups_ready: coverage.source_groups_ready ?? coverage.sourceGroupsReady ?? null,
|
|
7021
|
+
source_groups_total: coverage.source_groups_total ?? coverage.sourceGroupsTotal ?? null,
|
|
7022
|
+
knowledge_docs: coverage.knowledge_docs ?? coverage.knowledgeDocs ?? null,
|
|
7023
|
+
memories: coverage.memories ?? null
|
|
7024
|
+
},
|
|
7025
|
+
source_groups: sourceGroups,
|
|
7026
|
+
blocker_count: Array.isArray(strategyMemory.blockers) ? strategyMemory.blockers.length : 0,
|
|
7027
|
+
warning_count: Array.isArray(strategyMemory.warnings) ? strategyMemory.warnings.length : 0
|
|
7028
|
+
};
|
|
7029
|
+
}
|
|
7030
|
+
function summarizeCampaignAgentDryRun(dryRunResult) {
|
|
7031
|
+
return {
|
|
7032
|
+
dryRun: dryRunResult.dryRun ?? dryRunResult.dry_run ?? null,
|
|
7033
|
+
status: dryRunResult.status ?? null,
|
|
7034
|
+
currentPhase: dryRunResult.currentPhase ?? dryRunResult.current_phase ?? null,
|
|
7035
|
+
campaignBuildId: dryRunResult.campaignBuildId ?? dryRunResult.campaign_build_id ?? null,
|
|
7036
|
+
plannedTargetCount: dryRunResult.plannedTargetCount ?? dryRunResult.planned_target_count ?? null
|
|
7037
|
+
};
|
|
7038
|
+
}
|
|
7039
|
+
function printCampaignAgentProof(proof) {
|
|
7040
|
+
console.log(`Campaign-agent proof: ${proof.success ? "passed" : "failed"}`);
|
|
7041
|
+
const campaign = asRecord4(proof.campaign);
|
|
7042
|
+
if (campaign.plan_id) console.log(`Plan ID: ${campaign.plan_id}`);
|
|
7043
|
+
if (campaign.strategy_template) console.log(`Strategy template: ${campaign.strategy_template}`);
|
|
7044
|
+
if (campaign.target_count !== void 0) console.log(`Target: ${campaign.target_count}`);
|
|
7045
|
+
console.log("\nGates:");
|
|
7046
|
+
const gates = Array.isArray(proof.gates) ? proof.gates : [];
|
|
7047
|
+
for (const gate of gates) {
|
|
7048
|
+
const gateRecord = asRecord4(gate);
|
|
7049
|
+
console.log(`- ${gateRecord.id}: ${gateRecord.passed ? "passed" : "failed"}`);
|
|
7050
|
+
}
|
|
7051
|
+
console.log("\nSafety: dry-run only; no spendful launch, external write, sender load, or email send.");
|
|
7052
|
+
}
|
|
7053
|
+
function printJson(value) {
|
|
7054
|
+
console.log(JSON.stringify(value, null, 2));
|
|
7055
|
+
}
|
|
7056
|
+
function printHelp() {
|
|
7057
|
+
console.log(`
|
|
4763
7058
|
Signaliz CLI v1.0.0
|
|
4764
7059
|
|
|
4765
7060
|
Usage:
|
|
4766
|
-
signaliz test
|
|
4767
|
-
signaliz tools
|
|
7061
|
+
signaliz test Verify API connectivity
|
|
7062
|
+
signaliz tools List all available MCP tools
|
|
7063
|
+
signaliz gtm context --json Load GTM Kernel workspace context
|
|
7064
|
+
signaliz gtm bootstrap --json Inspect GTM Kernel readiness
|
|
7065
|
+
signaliz gtm templates --json List private-safe campaign strategy templates
|
|
7066
|
+
signaliz gtm start-context --strategy-template non-medical-home-care --json
|
|
7067
|
+
signaliz gtm strategy-memory --strategy-template non-medical-home-care --include-samples --json
|
|
7068
|
+
signaliz gtm agent-plan --goal "Build a strategy-template campaign" --strategy-template non-medical-home-care --target-count 500 --json
|
|
7069
|
+
signaliz gtm provider-prepare --provider-id customer_mcp --layer company_enrichment --invocation-type mcp_tool --json
|
|
7070
|
+
signaliz gtm memory search --query "proof-first vertical gate" --json
|
|
7071
|
+
signaliz gtm plan --brief "Build 500 verified leads for..." --strategy-template non-medical-home-care --lead-count 500 --json
|
|
7072
|
+
signaliz campaign-agent init --strategy-template non-medical-home-care --target-count 250 --use-local-leads --json > campaign-request.json
|
|
7073
|
+
signaliz campaign-agent plan --goal "Build a strategy-template campaign..." --strategy-template industrial-ot-resilience --target-count 500 --builtins lead_generation,email_finding,email_verification,signals
|
|
7074
|
+
signaliz campaign-agent proof --goal "Build a strategy-template campaign..." --strategy-template non-medical-home-care --target-count 100 --json
|
|
7075
|
+
signaliz campaign-agent plan --request-file examples/campaign-builder-agent-request.json --target-count 250 --json
|
|
7076
|
+
signaliz campaign-agent commit-plan --goal "Build a strategy-template campaign..." --json
|
|
7077
|
+
signaliz campaign-agent dry-run --goal "Build a strategy-template campaign..." --target-count 500 --use-local-leads --json
|
|
7078
|
+
signaliz campaign-agent build-approved --goal "Build a strategy-template campaign..." --confirm-launch --approve-all --approved-by you@example.com --spend-limit 500
|
|
4768
7079
|
|
|
4769
7080
|
Environment:
|
|
4770
|
-
SIGNALIZ_API_KEY
|
|
7081
|
+
SIGNALIZ_API_KEY Your API key (not required for campaign-agent init)
|
|
7082
|
+
SIGNALIZ_BASE_URL Optional API base URL override
|
|
7083
|
+
`);
|
|
7084
|
+
}
|
|
7085
|
+
function printGtmHelp() {
|
|
7086
|
+
console.log(`
|
|
7087
|
+
Signaliz GTM commands:
|
|
7088
|
+
|
|
7089
|
+
signaliz gtm context [--include-campaigns] [--include-memory] [--include-brain] [--include-connections] [--limit N] [--json]
|
|
7090
|
+
signaliz gtm bootstrap [--campaign-id ID] [--days N] [--include-connections] [--include-samples] [--json]
|
|
7091
|
+
signaliz gtm templates [--query TEXT] [--strategy-template ID] [--summary] [--json]
|
|
7092
|
+
signaliz gtm start-context [--brief TEXT] [--strategy-template ID] [--target-count N] [--layers a,b] [--providers a,b] [--json]
|
|
7093
|
+
signaliz gtm strategy-memory [--query TEXT] [--strategy-template ID] [--include-samples] [--json]
|
|
7094
|
+
signaliz gtm provider-prepare --provider-id ID [--layer NAME] [--invocation-type webhook|mcp_tool|api] [--json]
|
|
7095
|
+
signaliz gtm activate-route --provider-id ID --layer NAME [--confirm] [--json]
|
|
7096
|
+
signaliz gtm memory search --query TEXT [--layers a,b] [--provider-chain a,b] [--limit N] [--json]
|
|
7097
|
+
signaliz gtm plan --brief TEXT [--strategy-template industrial-ot-resilience|non-medical-home-care|agency-founder-led|cloud-infrastructure-displacement] [--lead-count N] [--layers a,b] [--providers a,b] [--partners clay,instantly,nango] [--target-icp JSON] [--json]
|
|
7098
|
+
`);
|
|
7099
|
+
}
|
|
7100
|
+
function printCampaignAgentHelp() {
|
|
7101
|
+
console.log(`
|
|
7102
|
+
Signaliz campaign-agent commands:
|
|
7103
|
+
|
|
7104
|
+
signaliz campaign-agent init [--goal TEXT] [--strategy-template ID] [--target-count N] [--use-local-leads] [--with-byo-placeholder] [--output-file FILE] [--json]
|
|
7105
|
+
signaliz campaign-agent plan (--goal TEXT | --request-file FILE) [--campaign-name NAME] [--workspace-label NAME] [--strategy-template industrial-ot-resilience|non-medical-home-care|agency-founder-led|cloud-infrastructure-displacement] [--operating-playbooks proof-first-vertical-gate,signal-led-copy-approval] [--target-count N] [--icp JSON] [--builtins lead_generation,email_finding,email_verification,signals,local_leads] [--use-local-leads] [--custom-tool provider:layer:tool[:mcp]] [--preferred-providers signaliz_native,octave] [--partners clay,instantly,nango] [--no-strategy-memory] [--no-kernel-plan] [--no-delivery-risk] [--json]
|
|
7106
|
+
signaliz campaign-agent proof (--goal TEXT | --request-file FILE) [--strategy-template ID] [--target-count N] [--use-local-leads] [--custom-tool provider:layer:tool[:mcp]] [--idempotency-key KEY] [--json]
|
|
7107
|
+
signaliz campaign-agent commit-plan (--goal TEXT | --request-file FILE) [--confirm-write --approved-by EMAIL] [--idempotency-key KEY] [--json]
|
|
7108
|
+
signaliz campaign-agent dry-run (--goal TEXT | --request-file FILE) [--gtm-campaign-id ID] [--delivery-risk JSON] [--idempotency-key KEY] [--json]
|
|
7109
|
+
signaliz campaign-agent build-approved (--goal TEXT | --request-file FILE) --confirm-launch --approved-by EMAIL (--approve-all | --approved-types a,b) [--commit-before-launch] [--spend-limit N] [--approved-route-ids a,b] [--idempotency-key KEY] [--json]
|
|
7110
|
+
|
|
7111
|
+
The init command emits a reusable JSON CampaignBuilderAgentRequest. The plan command composes an approval-gated strategy-template MCP flow. Proof runs the same plan path plus build_campaign dry_run=true and returns a no-spend receipt. Use --request-file to load a reusable request, then override fields such as --target-count or --strategy-template from the command line. Use --strategy-template to merge a private-safe strategy pattern into the plan without exposing private account labels, and --operating-playbooks to add reusable build-loop gates such as proof-first vertical qualification, net-new suppression, cache-first inventory, and signal-led copy approval. Built-ins map to Signaliz-native tools: lead_generation -> generate_leads, local_leads -> generate_local_leads, email_finding -> find_and_verify_emails, email_verification -> verify_emails, signals -> enrich_company_signals. Add BYO tools with --custom-tool provider:layer:tool[:mcp] or key=value pairs such as provider=apollo,layer=source,tool=apollo_search,mcp=apollo. Use --no-strategy-patterns or --no-workflow-patterns to disable default private strategy memory hints. Commit-plan dry-runs by default and writes only with --confirm-write plus approval identity. Dry-run executes build_campaign with dry_run=true. Approved build requires explicit launch confirmation and approval metadata; add --commit-before-launch to persist the reviewed plan as a GTM campaign before launch.
|
|
4771
7112
|
`);
|
|
4772
|
-
}
|
|
4773
7113
|
}
|
|
4774
7114
|
main().catch((e) => {
|
|
4775
7115
|
console.error(e);
|