@signaliz/sdk 1.0.17 → 1.0.19
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 +7 -2
- package/dist/{chunk-ZKE4L57J.mjs → chunk-PBJFIO72.mjs} +1535 -62
- package/dist/cli.js +1820 -65
- package/dist/cli.mjs +276 -2
- package/dist/index.d.mts +621 -4
- package/dist/index.d.ts +621 -4
- package/dist/index.js +1537 -62
- package/dist/index.mjs +5 -1
- package/dist/mcp-config.js +1533 -62
- package/dist/mcp-config.mjs +1 -1
- package/package.json +2 -2
|
@@ -448,6 +448,38 @@ var Signals = class {
|
|
|
448
448
|
constructor(client) {
|
|
449
449
|
this.client = client;
|
|
450
450
|
}
|
|
451
|
+
/** Turn the strongest supported company signal into three complete, evidence-backed emails. */
|
|
452
|
+
async signalToCopy(params) {
|
|
453
|
+
const data = await this.client.post("api/v1/signal-to-copy", {
|
|
454
|
+
company_domain: params.companyDomain,
|
|
455
|
+
person_name: params.personName,
|
|
456
|
+
title: params.title,
|
|
457
|
+
campaign_offer: params.campaignOffer,
|
|
458
|
+
research_prompt: params.researchPrompt
|
|
459
|
+
});
|
|
460
|
+
return {
|
|
461
|
+
success: data.success ?? true,
|
|
462
|
+
strongestSignal: data.strongest_signal ?? "",
|
|
463
|
+
whyNow: data.why_now ?? "",
|
|
464
|
+
subjectLine: data.subject_line ?? "",
|
|
465
|
+
openingLine: data.opening_line ?? "",
|
|
466
|
+
confidence: data.confidence ?? 0,
|
|
467
|
+
evidenceUrl: data.evidence_url ?? "",
|
|
468
|
+
researchPrompt: data.research_prompt,
|
|
469
|
+
variations: (data.variations ?? []).map((v) => ({
|
|
470
|
+
style: v.style,
|
|
471
|
+
subjectLine: v.subject_line ?? "",
|
|
472
|
+
openingLine: v.opening_line ?? "",
|
|
473
|
+
cta: v.cta ?? "",
|
|
474
|
+
prediction: v.prediction,
|
|
475
|
+
email: v.email
|
|
476
|
+
}))
|
|
477
|
+
};
|
|
478
|
+
}
|
|
479
|
+
/** @deprecated Use signalToCopy. Retained for compatibility. */
|
|
480
|
+
async personalize(params) {
|
|
481
|
+
return this.signalToCopy(params);
|
|
482
|
+
}
|
|
451
483
|
/** Enrich a company with actionable signals (V1) */
|
|
452
484
|
async enrich(params) {
|
|
453
485
|
const args = {
|
|
@@ -456,6 +488,9 @@ var Signals = class {
|
|
|
456
488
|
if (params.domain) args.domain = params.domain;
|
|
457
489
|
if (params.researchPrompt) args.research_prompt = params.researchPrompt;
|
|
458
490
|
if (params.signalTypes) args.signal_types = params.signalTypes;
|
|
491
|
+
if (params.targetSignalCount) args.target_signal_count = params.targetSignalCount;
|
|
492
|
+
if (params.lookbackDays) args.lookback_days = params.lookbackDays;
|
|
493
|
+
if (params.enableDeepSearch !== void 0) args.enable_deep_search = params.enableDeepSearch;
|
|
459
494
|
const data = await this.client.mcp("tools/call", {
|
|
460
495
|
name: "enrich_company_signals",
|
|
461
496
|
arguments: args
|
|
@@ -465,6 +500,16 @@ var Signals = class {
|
|
|
465
500
|
signals: (data.signals ?? []).map((s) => ({
|
|
466
501
|
title: s.title,
|
|
467
502
|
signalType: s.signal_type,
|
|
503
|
+
sourceType: s.source_type ?? s.signal_classification?.label ?? "unknown",
|
|
504
|
+
sourceProvenance: s.source_provenance ?? s.metadata?.source_provenance ?? null,
|
|
505
|
+
signalFamily: s.signal_family ?? s.signal_type ?? null,
|
|
506
|
+
signalEventType: s.signal_event_type ?? s.signal_classification?.slug ?? null,
|
|
507
|
+
signalEventLabel: s.signal_event_label ?? s.signal_classification?.label ?? null,
|
|
508
|
+
signalClassification: s.signal_classification ? {
|
|
509
|
+
label: s.signal_classification.label,
|
|
510
|
+
slug: s.signal_classification.slug,
|
|
511
|
+
rationale: s.signal_classification.rationale
|
|
512
|
+
} : null,
|
|
468
513
|
confidenceScore: s.confidence_score ?? 0,
|
|
469
514
|
detectedAt: s.detected_at ?? "",
|
|
470
515
|
url: s.url,
|
|
@@ -505,8 +550,17 @@ var Signals = class {
|
|
|
505
550
|
content: s.content ?? "",
|
|
506
551
|
date: s.date ?? null,
|
|
507
552
|
sourceUrl: s.source_url ?? null,
|
|
508
|
-
sourceType: s.source_type ?? "unknown",
|
|
509
|
-
|
|
553
|
+
sourceType: s.source_type ?? s.signal_classification?.label ?? "unknown",
|
|
554
|
+
sourceProvenance: s.source_provenance ?? s.metadata?.source_provenance ?? null,
|
|
555
|
+
signalFamily: s.signal_family ?? s.type ?? null,
|
|
556
|
+
signalEventType: s.signal_event_type ?? s.signal_classification?.slug ?? null,
|
|
557
|
+
signalEventLabel: s.signal_event_label ?? s.signal_classification?.label ?? null,
|
|
558
|
+
confidence: s.confidence ?? null,
|
|
559
|
+
signalClassification: s.signal_classification ? {
|
|
560
|
+
label: s.signal_classification.label,
|
|
561
|
+
slug: s.signal_classification.slug,
|
|
562
|
+
rationale: s.signal_classification.rationale
|
|
563
|
+
} : null
|
|
510
564
|
})),
|
|
511
565
|
signalCount: data.signal_count ?? 0,
|
|
512
566
|
intelligence: data.intelligence ? {
|
|
@@ -549,6 +603,58 @@ var Signals = class {
|
|
|
549
603
|
}
|
|
550
604
|
};
|
|
551
605
|
}
|
|
606
|
+
/** Plan or run experimental Signal Fusion with explicit spend controls. */
|
|
607
|
+
async fusion(params) {
|
|
608
|
+
const args = {};
|
|
609
|
+
if (params.companyName) args.company_name = params.companyName;
|
|
610
|
+
if (params.domain) args.domain = params.domain;
|
|
611
|
+
if (params.companyDomain) args.company_domain = params.companyDomain;
|
|
612
|
+
if (params.linkedinUrl) args.linkedin_url = params.linkedinUrl;
|
|
613
|
+
if (params.companies) args.companies = params.companies;
|
|
614
|
+
if (params.preset) args.preset = params.preset;
|
|
615
|
+
if (params.researchPrompt) args.research_prompt = params.researchPrompt;
|
|
616
|
+
if (params.signalTypes) args.signal_types = params.signalTypes;
|
|
617
|
+
if (params.lookbackDays) args.lookback_days = params.lookbackDays;
|
|
618
|
+
if (params.targetSignalCount) args.target_signal_count = params.targetSignalCount;
|
|
619
|
+
if (params.maxToolCalls) args.max_tool_calls = params.maxToolCalls;
|
|
620
|
+
if (params.maxTokens) args.max_tokens = params.maxTokens;
|
|
621
|
+
if (params.timeoutMs) args.timeout_ms = params.timeoutMs;
|
|
622
|
+
const dryRun = params.dryRun ?? params.dry_run;
|
|
623
|
+
const confirmSpend = params.confirmSpend ?? params.confirm_spend;
|
|
624
|
+
const maxCredits = params.maxCredits ?? params.max_credits;
|
|
625
|
+
const maxCostUsd = params.maxCostUsd ?? params.max_cost_usd;
|
|
626
|
+
if (dryRun !== void 0) args.dry_run = dryRun;
|
|
627
|
+
if (confirmSpend !== void 0) args.confirm_spend = confirmSpend;
|
|
628
|
+
if (maxCredits !== void 0) args.max_credits = maxCredits;
|
|
629
|
+
if (maxCostUsd !== void 0) args.max_cost_usd = maxCostUsd;
|
|
630
|
+
const data = await this.client.post("signal-fusion", args);
|
|
631
|
+
return {
|
|
632
|
+
success: data.success ?? false,
|
|
633
|
+
capability: data.capability ?? "signal_fusion",
|
|
634
|
+
displayName: data.display_name ?? "Signal Fusion",
|
|
635
|
+
company: data.company,
|
|
636
|
+
signals: (data.signals ?? []).map((s) => ({
|
|
637
|
+
id: s.id,
|
|
638
|
+
title: s.title,
|
|
639
|
+
type: s.type,
|
|
640
|
+
content: s.content ?? "",
|
|
641
|
+
date: s.date ?? null,
|
|
642
|
+
sourceUrl: s.source_url ?? null,
|
|
643
|
+
sourceType: s.source_type ?? "unknown",
|
|
644
|
+
confidence: s.confidence ?? null
|
|
645
|
+
})),
|
|
646
|
+
signalCount: data.signal_count ?? data.signals?.length ?? 0,
|
|
647
|
+
results: data.results ?? [],
|
|
648
|
+
model: data.model,
|
|
649
|
+
fusion: data.fusion,
|
|
650
|
+
costUsd: data.cost_usd ?? 0,
|
|
651
|
+
tokensUsed: data.tokens_used ?? 0,
|
|
652
|
+
costSummary: data.cost_summary,
|
|
653
|
+
creditsUsed: data.total_credits_used ?? data.credits_used ?? 0,
|
|
654
|
+
billingMetadata: data.billing_metadata,
|
|
655
|
+
raw: data
|
|
656
|
+
};
|
|
657
|
+
}
|
|
552
658
|
};
|
|
553
659
|
|
|
554
660
|
// src/resources/systems.ts
|
|
@@ -837,7 +943,11 @@ var Campaigns = class {
|
|
|
837
943
|
maxSupportedTargetCount: data.max_supported_target_count,
|
|
838
944
|
brainContext: data.brain_context ?? {},
|
|
839
945
|
learningHoldout: data.learning_holdout ?? {},
|
|
840
|
-
providerRoute: mapProviderRoute(data)
|
|
946
|
+
providerRoute: mapProviderRoute(data),
|
|
947
|
+
effectiveSourceRouting: recordOrNull(data.effective_source_routing ?? data.source_routing),
|
|
948
|
+
sourcePlan: recordOrNull(data.source_plan ?? data.plan?.source_plan),
|
|
949
|
+
sourceRoutes: recordArray(data.source_routes ?? data.source_plan?.routes ?? data.plan?.source_plan?.routes),
|
|
950
|
+
sourceShards: recordArray(data.source_shards ?? data.source_plan?.shards ?? data.plan?.source_plan?.shards)
|
|
841
951
|
};
|
|
842
952
|
}
|
|
843
953
|
async getCampaignBuildStatus(campaignBuildId) {
|
|
@@ -983,6 +1093,7 @@ function mapCustomerRowCounts(value) {
|
|
|
983
1093
|
acceptedRows: numberOrNull(record.accepted_rows) ?? void 0,
|
|
984
1094
|
usableRows: numberOrNull(record.usable_rows) ?? void 0,
|
|
985
1095
|
copiedRows: numberOrNull(record.copied_rows) ?? void 0,
|
|
1096
|
+
copySkippedRows: numberOrNull(record.copy_skipped_rows) ?? void 0,
|
|
986
1097
|
approvalReadyRows: numberOrNull(record.approval_ready_rows) ?? void 0,
|
|
987
1098
|
qaReadyRows: numberOrNull(record.qa_ready_rows) ?? void 0,
|
|
988
1099
|
deliveredRows: numberOrNull(record.delivered_rows) ?? void 0,
|
|
@@ -1029,6 +1140,9 @@ function recordOrNull(value) {
|
|
|
1029
1140
|
function stringArray(value) {
|
|
1030
1141
|
return Array.isArray(value) ? value.map((item) => String(item || "").trim()).filter(Boolean) : [];
|
|
1031
1142
|
}
|
|
1143
|
+
function recordArray(value) {
|
|
1144
|
+
return Array.isArray(value) ? value.map(recordOrNull).filter((item) => Boolean(item)) : [];
|
|
1145
|
+
}
|
|
1032
1146
|
function diagnosticMessages(value) {
|
|
1033
1147
|
if (!Array.isArray(value)) return [];
|
|
1034
1148
|
return value.map((item) => {
|
|
@@ -1190,7 +1304,8 @@ function buildArgs(request) {
|
|
|
1190
1304
|
suppress_prior_campaign_ids: request.cacheReusePolicy.suppressPriorCampaignIds,
|
|
1191
1305
|
suppress_prior_list_ids: request.cacheReusePolicy.suppressPriorListIds,
|
|
1192
1306
|
uniqueness: request.cacheReusePolicy.uniqueness,
|
|
1193
|
-
require_usage_metadata: request.cacheReusePolicy.requireUsageMetadata
|
|
1307
|
+
require_usage_metadata: request.cacheReusePolicy.requireUsageMetadata,
|
|
1308
|
+
verified_cache_ttl_days: request.cacheReusePolicy.verifiedCacheTtlDays
|
|
1194
1309
|
};
|
|
1195
1310
|
}
|
|
1196
1311
|
if (request.brainPreflight) args.brain_preflight = request.brainPreflight;
|
|
@@ -1215,7 +1330,8 @@ function buildArgs(request) {
|
|
|
1215
1330
|
geographies: request.icp.geographies,
|
|
1216
1331
|
keywords: request.icp.keywords,
|
|
1217
1332
|
exclusions: request.icp.exclusions,
|
|
1218
|
-
require_verified_email: request.icp.requireVerifiedEmail
|
|
1333
|
+
require_verified_email: request.icp.requireVerifiedEmail,
|
|
1334
|
+
persona_expansion_mode: request.icp.personaExpansionMode
|
|
1219
1335
|
};
|
|
1220
1336
|
}
|
|
1221
1337
|
if (request.policy) {
|
|
@@ -1255,6 +1371,7 @@ function buildArgs(request) {
|
|
|
1255
1371
|
} : void 0,
|
|
1256
1372
|
sequence_steps: request.copy.sequenceSteps,
|
|
1257
1373
|
copy_schema: request.copy.copySchema,
|
|
1374
|
+
evidence_mode: request.copy.evidenceMode,
|
|
1258
1375
|
banned_phrases: request.copy.bannedPhrases,
|
|
1259
1376
|
approval_required: request.copy.approvalRequired,
|
|
1260
1377
|
quality_tier: request.copy.qualityTier
|
|
@@ -1311,7 +1428,8 @@ var DEFAULT_SIGNALIZ_CAMPAIGN_BUILDER_DEFAULTS = {
|
|
|
1311
1428
|
copy: {
|
|
1312
1429
|
enabled: true,
|
|
1313
1430
|
tone: "direct",
|
|
1314
|
-
maxBodyWords: 125
|
|
1431
|
+
maxBodyWords: 125,
|
|
1432
|
+
evidenceMode: "signal_led"
|
|
1315
1433
|
},
|
|
1316
1434
|
delivery: {
|
|
1317
1435
|
enabled: true,
|
|
@@ -1368,7 +1486,8 @@ var CAMPAIGN_BUILDER_OPERATING_PLAYBOOKS = [
|
|
|
1368
1486
|
"Block export when required identity, company, or email fields are missing."
|
|
1369
1487
|
],
|
|
1370
1488
|
activationBoundary: "Cache inventory is read-only. Fresh sourcing, cache writes, export, and sender loading require explicit approval.",
|
|
1371
|
-
memoryKeywords: ["cache inventory", "large list", "unique emails", "top-up sourcing", "source metadata"]
|
|
1489
|
+
memoryKeywords: ["cache inventory", "large list", "unique emails", "top-up sourcing", "source metadata"],
|
|
1490
|
+
knowledgeSources: ["data-ops/contact-data-lifecycle", "data-ops/credit-optimization-guide", "gtm/data-quality-ops", "gtm/lead-generation-strategies"]
|
|
1372
1491
|
},
|
|
1373
1492
|
{
|
|
1374
1493
|
slug: "net-new-suppressed-list",
|
|
@@ -1393,7 +1512,8 @@ var CAMPAIGN_BUILDER_OPERATING_PLAYBOOKS = [
|
|
|
1393
1512
|
"Do not describe rows as fully qualified when the approved path only proves net-new email status."
|
|
1394
1513
|
],
|
|
1395
1514
|
activationBoundary: "Suppression review must pass before export, upload, CRM sync, sender load, or sequence launch.",
|
|
1396
|
-
memoryKeywords: ["suppression", "net-new", "prior email overlap", "domain review", "provenance-rich QA"]
|
|
1515
|
+
memoryKeywords: ["suppression", "net-new", "prior email overlap", "domain review", "provenance-rich QA"],
|
|
1516
|
+
knowledgeSources: ["gtm/data-quality-ops", "data-ops/contact-data-lifecycle", "gtm/outbound-sequencing"]
|
|
1397
1517
|
},
|
|
1398
1518
|
{
|
|
1399
1519
|
slug: "proof-first-vertical-gate",
|
|
@@ -1418,7 +1538,8 @@ var CAMPAIGN_BUILDER_OPERATING_PLAYBOOKS = [
|
|
|
1418
1538
|
"Contact fit should meet the configured threshold before email finding or copy generation."
|
|
1419
1539
|
],
|
|
1420
1540
|
activationBoundary: "Proof gates are required before contact spend, copy, export, or external writes.",
|
|
1421
|
-
memoryKeywords: ["proof gate", "vertical exclusion", "company before contact", "pass review fail", "fit threshold"]
|
|
1541
|
+
memoryKeywords: ["proof gate", "vertical exclusion", "company before contact", "pass review fail", "fit threshold"],
|
|
1542
|
+
knowledgeSources: ["gtm/icp-design-framework", "gtm/strategy/scoring.yaml", "gtm/advanced/account-prioritization-frameworks", "gtm/advanced/predictive-lead-scoring", "gtm/verticals"]
|
|
1422
1543
|
},
|
|
1423
1544
|
{
|
|
1424
1545
|
slug: "signal-led-copy-approval",
|
|
@@ -1443,7 +1564,8 @@ var CAMPAIGN_BUILDER_OPERATING_PLAYBOOKS = [
|
|
|
1443
1564
|
"Destination fields must remain blocked until approval metadata is present."
|
|
1444
1565
|
],
|
|
1445
1566
|
activationBoundary: "Copy readiness is not delivery approval. Export, sync, sender load, and launch require a separate human-approved gate.",
|
|
1446
|
-
memoryKeywords: ["company signals", "evidence-fed copy", "why now", "copy blocker", "approval gate"]
|
|
1567
|
+
memoryKeywords: ["company signals", "evidence-fed copy", "why now", "copy blocker", "approval gate"],
|
|
1568
|
+
knowledgeSources: ["gtm/email-personalization", "gtm/signal-based-selling", "gtm/signal-combination-matrix", "gtm/advanced/buyer-journey-mapping"]
|
|
1447
1569
|
},
|
|
1448
1570
|
{
|
|
1449
1571
|
slug: "domain-first-recovery",
|
|
@@ -1468,7 +1590,8 @@ var CAMPAIGN_BUILDER_OPERATING_PLAYBOOKS = [
|
|
|
1468
1590
|
"Target count means final held rows, not raw sourced rows."
|
|
1469
1591
|
],
|
|
1470
1592
|
activationBoundary: "Domain recovery informs sourcing. Contact enrichment, paid qualification, and export still require approved gates.",
|
|
1471
|
-
memoryKeywords: ["domain-first", "yield modeling", "attrition", "accepted domains", "gap fill"]
|
|
1593
|
+
memoryKeywords: ["domain-first", "yield modeling", "attrition", "accepted domains", "gap fill"],
|
|
1594
|
+
knowledgeSources: ["gtm/lead-generation-strategies", "data-ops/enrichment-waterfall-strategy", "data-ops/credit-optimization-guide", "gtm/territory-account-planning"]
|
|
1472
1595
|
},
|
|
1473
1596
|
{
|
|
1474
1597
|
slug: "table-workflow-handoff",
|
|
@@ -1493,7 +1616,112 @@ var CAMPAIGN_BUILDER_OPERATING_PLAYBOOKS = [
|
|
|
1493
1616
|
"Provider route activation must dry-run before any external write."
|
|
1494
1617
|
],
|
|
1495
1618
|
activationBoundary: "MCP, webhook, managed integration, and destination routes remain dry-run until the reviewed route and campaign are approved.",
|
|
1496
|
-
memoryKeywords: ["table workflow", "request ready", "provider status", "export blocker", "BYO integration"]
|
|
1619
|
+
memoryKeywords: ["table workflow", "request ready", "provider status", "export blocker", "BYO integration"],
|
|
1620
|
+
knowledgeSources: ["gtm/multi-channel-orchestration", "data-ops/enrichment-waterfall-strategy", "recipes/clay-gtm-webhook-recipe", "systems/blueprints/multi-channel-orchestration"]
|
|
1621
|
+
},
|
|
1622
|
+
{
|
|
1623
|
+
slug: "icp-persona-segmentation",
|
|
1624
|
+
label: "ICP And Persona Segmentation",
|
|
1625
|
+
whenToUse: [
|
|
1626
|
+
"The brief has a broad market, multiple personas, or unclear buying committee.",
|
|
1627
|
+
"The campaign should rank account tiers, persona fit, vertical nuance, and exclusions before sourcing at scale."
|
|
1628
|
+
],
|
|
1629
|
+
sequence: [
|
|
1630
|
+
"Convert the brief into account tiers, persona roles, buying committee influence, and explicit exclusions.",
|
|
1631
|
+
"Choose vertical guidance only from the customer-safe GTM library and keep internal platform docs out of prompts.",
|
|
1632
|
+
"Score accounts before contacts, then score contacts against persona, seniority, function, geography, and intent fit.",
|
|
1633
|
+
"Return segment counts and review buckets before spend, copy, export, or launch."
|
|
1634
|
+
],
|
|
1635
|
+
requiredFields: {
|
|
1636
|
+
segment: ["segment_name", "tier", "persona_priority", "buying_committee_role", "fit_reason", "exclusion_reason"],
|
|
1637
|
+
scoring: ["account_fit_score", "persona_fit_score", "segment_confidence", "review_bucket"]
|
|
1638
|
+
},
|
|
1639
|
+
qualityGates: [
|
|
1640
|
+
"Do not treat adjacent personas or verticals as matches unless the brief allows them.",
|
|
1641
|
+
"Keep ICP, persona, and exclusion evidence visible in the proof packet.",
|
|
1642
|
+
"Low-confidence segments route to review before contact discovery or copy."
|
|
1643
|
+
],
|
|
1644
|
+
activationBoundary: "Segmentation is planning guidance. Paid sourcing, enrichment, export, and launch require the normal approval gates.",
|
|
1645
|
+
memoryKeywords: ["ICP design", "persona segmentation", "buying committee", "account tiers", "fit scoring", "vertical nuance"],
|
|
1646
|
+
knowledgeSources: ["gtm/icp-design-framework", "gtm/personas/sdr.yaml", "gtm/personas/ae.yaml", "gtm/personas/cro.yaml", "gtm/personas/revops.yaml", "gtm/advanced/account-prioritization-frameworks", "gtm/verticals"]
|
|
1647
|
+
},
|
|
1648
|
+
{
|
|
1649
|
+
slug: "buying-signal-prioritization",
|
|
1650
|
+
label: "Buying Signal Prioritization",
|
|
1651
|
+
whenToUse: [
|
|
1652
|
+
"The campaign depends on timing, intent, trigger events, or account prioritization.",
|
|
1653
|
+
"The operator wants why-now proof instead of generic list generation."
|
|
1654
|
+
],
|
|
1655
|
+
sequence: [
|
|
1656
|
+
"Map the campaign goal to signal families, trigger freshness, and buyer-journey stage.",
|
|
1657
|
+
"Rank signals by relevance, recency, source quality, and persona-specific actionability.",
|
|
1658
|
+
"Attach evidence URLs or evidence summaries without exposing private memory rows.",
|
|
1659
|
+
"Use signal strength to decide source order, copy angle, and review priority."
|
|
1660
|
+
],
|
|
1661
|
+
requiredFields: {
|
|
1662
|
+
signal: ["signal_type", "signal_date", "signal_source", "why_now", "signal_confidence", "buyer_stage"],
|
|
1663
|
+
prioritization: ["priority_score", "priority_reason", "next_best_action", "review_reason"]
|
|
1664
|
+
},
|
|
1665
|
+
qualityGates: [
|
|
1666
|
+
"Do not use stale, unsupported, or weak signals as personalization proof.",
|
|
1667
|
+
"Signal fit cannot override hard ICP, geography, suppression, or verified-email gates.",
|
|
1668
|
+
"Rows with uncertain why-now evidence must stay review-only."
|
|
1669
|
+
],
|
|
1670
|
+
activationBoundary: "Signal ranking can prioritize review and copy. It does not approve outreach, sender loading, exports, or sends.",
|
|
1671
|
+
memoryKeywords: ["buying signals", "intent data", "funding trigger", "new executive", "tech adoption", "buyer journey", "why now"],
|
|
1672
|
+
knowledgeSources: ["gtm/signal-based-selling", "gtm/signal-combination-matrix", "gtm/advanced/intent-data-strategies", "gtm/advanced/buyer-journey-mapping", "gtm/signals/funding-round", "gtm/signals/new-executive", "gtm/signals/tech-adoption", "recipes/funding-trigger-outreach", "recipes/new-hire-outreach"]
|
|
1673
|
+
},
|
|
1674
|
+
{
|
|
1675
|
+
slug: "multi-channel-sequence-fit",
|
|
1676
|
+
label: "Multi-Channel Sequence Fit",
|
|
1677
|
+
whenToUse: [
|
|
1678
|
+
"The campaign needs email, LinkedIn, call, webhook, CRM, or sequencer coordination.",
|
|
1679
|
+
"Copy and delivery should adapt by persona, channel, deliverability risk, and proof strength."
|
|
1680
|
+
],
|
|
1681
|
+
sequence: [
|
|
1682
|
+
"Choose channel mix from persona, deal motion, evidence strength, deliverability constraints, and connected destination readiness.",
|
|
1683
|
+
"Draft sequence logic with email, LinkedIn, call, and task handoffs only where supported by the approved destination.",
|
|
1684
|
+
"Keep copy concise, proof-backed, channel-specific, and reviewable before delivery.",
|
|
1685
|
+
"Run deliverability and destination readiness checks before sender load or launch approval."
|
|
1686
|
+
],
|
|
1687
|
+
requiredFields: {
|
|
1688
|
+
channel: ["channel", "touch_number", "persona_context", "message_angle", "channel_blocker", "approval_status"],
|
|
1689
|
+
deliverability: ["verified_email", "domain_risk", "send_window", "unsubscribe_risk", "sender_ready"]
|
|
1690
|
+
},
|
|
1691
|
+
qualityGates: [
|
|
1692
|
+
"Email copy must be row-supported and under the configured campaign tone/length limits.",
|
|
1693
|
+
"LinkedIn, phone, CRM, webhook, and sequencer actions remain destination-locked until approved.",
|
|
1694
|
+
"Deliverability risk or missing sender readiness blocks launch even when rows are qualified."
|
|
1695
|
+
],
|
|
1696
|
+
activationBoundary: "Sequence strategy is draft-only. External writes, sender loading, launch, and sending need separate explicit approval.",
|
|
1697
|
+
memoryKeywords: ["outbound sequencing", "email personalization", "LinkedIn outreach", "cold calling", "multi-channel orchestration", "deliverability"],
|
|
1698
|
+
knowledgeSources: ["gtm/outbound-sequencing", "gtm/email-personalization", "gtm/linkedin-outreach-strategies", "gtm/cold-calling-frameworks", "gtm/multi-channel-orchestration", "gtm/advanced/email-deliverability", "systems/blueprints/multi-channel-orchestration"]
|
|
1699
|
+
},
|
|
1700
|
+
{
|
|
1701
|
+
slug: "revops-feedback-loop",
|
|
1702
|
+
label: "RevOps Feedback Loop",
|
|
1703
|
+
whenToUse: [
|
|
1704
|
+
"The campaign should improve from replies, meetings, delivery results, CRM outcomes, or operator QA.",
|
|
1705
|
+
"The operator needs post-build monitoring, governance, or continuous ops follow-up."
|
|
1706
|
+
],
|
|
1707
|
+
sequence: [
|
|
1708
|
+
"Define success metrics, guardrails, and feedback sources before launch.",
|
|
1709
|
+
"Collect aggregate outcomes, QA blockers, delivery health, and operator edits after each campaign phase.",
|
|
1710
|
+
"Separate workspace-private evidence from public-safe learnings and Brain defaults.",
|
|
1711
|
+
"Feed approved aggregate learnings back into future sourcing, qualification, copy, and suppression rules."
|
|
1712
|
+
],
|
|
1713
|
+
requiredFields: {
|
|
1714
|
+
feedback: ["source", "event_type", "metric", "sample_size", "confidence", "learning_candidate"],
|
|
1715
|
+
governance: ["approval_owner", "last_reviewed_at", "risk_flag", "next_review_action"]
|
|
1716
|
+
},
|
|
1717
|
+
qualityGates: [
|
|
1718
|
+
"Do not write memory or Brain learnings from raw replies, private labels, or provider payloads without approved redaction.",
|
|
1719
|
+
"Use holdouts or pre/post comparisons before claiming causal lift.",
|
|
1720
|
+
"Delivery, suppression, and opt-out signals must update future gates before scale-up."
|
|
1721
|
+
],
|
|
1722
|
+
activationBoundary: "Feedback review is read-only until memory writes, Brain writes, CRM updates, or campaign changes are explicitly approved.",
|
|
1723
|
+
memoryKeywords: ["RevOps", "feedback loop", "campaign learning", "reply outcomes", "sales marketing alignment", "data hygiene", "holdout"],
|
|
1724
|
+
knowledgeSources: ["gtm/revenue-operations", "gtm/advanced/sales-marketing-alignment", "gtm/advanced/predictive-lead-scoring", "gtm/data-quality-ops", "data-ops/contact-data-lifecycle", "recipes/crm-data-hygiene", "gtm/playbooks/revops-automation-playbook"]
|
|
1497
1725
|
}
|
|
1498
1726
|
];
|
|
1499
1727
|
var CAMPAIGN_BUILDER_STRATEGY_TEMPLATES = [
|
|
@@ -1580,7 +1808,15 @@ var CAMPAIGN_BUILDER_STRATEGY_TEMPLATES = [
|
|
|
1580
1808
|
agencyContext: {
|
|
1581
1809
|
partnerEcosystem: ["signaliz", "instantly", "nango"]
|
|
1582
1810
|
},
|
|
1583
|
-
operatingPlaybookSlugs: [
|
|
1811
|
+
operatingPlaybookSlugs: [
|
|
1812
|
+
"net-new-suppressed-list",
|
|
1813
|
+
"proof-first-vertical-gate",
|
|
1814
|
+
"signal-led-copy-approval",
|
|
1815
|
+
"icp-persona-segmentation",
|
|
1816
|
+
"buying-signal-prioritization",
|
|
1817
|
+
"multi-channel-sequence-fit",
|
|
1818
|
+
"revops-feedback-loop"
|
|
1819
|
+
]
|
|
1584
1820
|
},
|
|
1585
1821
|
{
|
|
1586
1822
|
slug: "non-medical-home-care",
|
|
@@ -1653,7 +1889,15 @@ var CAMPAIGN_BUILDER_STRATEGY_TEMPLATES = [
|
|
|
1653
1889
|
agencyContext: {
|
|
1654
1890
|
partnerEcosystem: ["clay", "octave", "signaliz", "instantly", "nango"]
|
|
1655
1891
|
},
|
|
1656
|
-
operatingPlaybookSlugs: [
|
|
1892
|
+
operatingPlaybookSlugs: [
|
|
1893
|
+
"proof-first-vertical-gate",
|
|
1894
|
+
"domain-first-recovery",
|
|
1895
|
+
"table-workflow-handoff",
|
|
1896
|
+
"icp-persona-segmentation",
|
|
1897
|
+
"buying-signal-prioritization",
|
|
1898
|
+
"multi-channel-sequence-fit",
|
|
1899
|
+
"revops-feedback-loop"
|
|
1900
|
+
]
|
|
1657
1901
|
},
|
|
1658
1902
|
{
|
|
1659
1903
|
slug: "agency-founder-led",
|
|
@@ -1714,7 +1958,15 @@ var CAMPAIGN_BUILDER_STRATEGY_TEMPLATES = [
|
|
|
1714
1958
|
agencyContext: {
|
|
1715
1959
|
partnerEcosystem: ["signaliz", "octave", "instantly", "nango"]
|
|
1716
1960
|
},
|
|
1717
|
-
operatingPlaybookSlugs: [
|
|
1961
|
+
operatingPlaybookSlugs: [
|
|
1962
|
+
"net-new-suppressed-list",
|
|
1963
|
+
"signal-led-copy-approval",
|
|
1964
|
+
"table-workflow-handoff",
|
|
1965
|
+
"icp-persona-segmentation",
|
|
1966
|
+
"buying-signal-prioritization",
|
|
1967
|
+
"multi-channel-sequence-fit",
|
|
1968
|
+
"revops-feedback-loop"
|
|
1969
|
+
]
|
|
1718
1970
|
},
|
|
1719
1971
|
{
|
|
1720
1972
|
slug: "cloud-infrastructure-displacement",
|
|
@@ -1801,7 +2053,15 @@ var CAMPAIGN_BUILDER_STRATEGY_TEMPLATES = [
|
|
|
1801
2053
|
agencyContext: {
|
|
1802
2054
|
partnerEcosystem: ["signaliz", "octave", "instantly", "nango"]
|
|
1803
2055
|
},
|
|
1804
|
-
operatingPlaybookSlugs: [
|
|
2056
|
+
operatingPlaybookSlugs: [
|
|
2057
|
+
"proof-first-vertical-gate",
|
|
2058
|
+
"domain-first-recovery",
|
|
2059
|
+
"signal-led-copy-approval",
|
|
2060
|
+
"icp-persona-segmentation",
|
|
2061
|
+
"buying-signal-prioritization",
|
|
2062
|
+
"multi-channel-sequence-fit",
|
|
2063
|
+
"revops-feedback-loop"
|
|
2064
|
+
]
|
|
1805
2065
|
}
|
|
1806
2066
|
];
|
|
1807
2067
|
var CampaignBuilderAgent = class {
|
|
@@ -1832,6 +2092,9 @@ var CampaignBuilderAgent = class {
|
|
|
1832
2092
|
const plan = await this.createPlan(request, options);
|
|
1833
2093
|
return createCampaignBuilderReadiness(plan);
|
|
1834
2094
|
}
|
|
2095
|
+
activeWorkContext(input) {
|
|
2096
|
+
return createCampaignBuilderActiveWorkContext(input);
|
|
2097
|
+
}
|
|
1835
2098
|
async proof(request, options = {}) {
|
|
1836
2099
|
const plan = await this.createPlan(request, options);
|
|
1837
2100
|
const result = await this.dryRunPlan(plan, {
|
|
@@ -1873,6 +2136,7 @@ var CampaignBuilderAgent = class {
|
|
|
1873
2136
|
},
|
|
1874
2137
|
brain_defaults: plan.buildRequest.brainDefaults,
|
|
1875
2138
|
brain_preflight: plan.buildRequest.brainPreflight,
|
|
2139
|
+
learning_holdout: plan.buildRequest.learningHoldout,
|
|
1876
2140
|
campaign_strategy_context: plan.buildRequest.campaignStrategyContext,
|
|
1877
2141
|
delivery_risk_preflight: plan.buildRequest.deliveryRisk,
|
|
1878
2142
|
delivery_risk: plan.buildRequest.deliveryRisk
|
|
@@ -1886,7 +2150,8 @@ var CampaignBuilderAgent = class {
|
|
|
1886
2150
|
estimated_credits: plan.estimatedCredits
|
|
1887
2151
|
},
|
|
1888
2152
|
brain_delivery_risk_preflight: plan.buildRequest.deliveryRisk,
|
|
1889
|
-
delivery_risk: plan.buildRequest.deliveryRisk
|
|
2153
|
+
delivery_risk: plan.buildRequest.deliveryRisk,
|
|
2154
|
+
learning_holdout: plan.buildRequest.learningHoldout
|
|
1890
2155
|
},
|
|
1891
2156
|
approval_required: plan.approvals.some((approval) => approval.blocking),
|
|
1892
2157
|
actor_type: "agent",
|
|
@@ -2214,9 +2479,10 @@ function createCampaignBuilderAgentPlan(request, context = {}) {
|
|
|
2214
2479
|
const estimatedCredits = estimateCredits(resolvedRequest, defaults, targetCount);
|
|
2215
2480
|
const buildRequest = createBuildRequest(resolvedRequest, defaults, targetCount, campaignName, context.scopeBuildArgs, routes, memory, context.scopeBrainPreflight);
|
|
2216
2481
|
const brainPreflight = asRecord(buildRequest.brainPreflight);
|
|
2482
|
+
const evidence = buildRequest.evidence ?? null;
|
|
2217
2483
|
const approvals = deriveApprovals(resolvedRequest, routes, memory, estimatedCredits, defaults.delivery?.approvalRequired !== false);
|
|
2218
2484
|
return {
|
|
2219
|
-
planId: `cbp_${hashString(JSON.stringify({ goal: resolvedRequest.goal, campaignName, targetCount, routes }))}`,
|
|
2485
|
+
planId: `cbp_${hashString(JSON.stringify({ goal: resolvedRequest.goal, campaignName, targetCount, routes, evidence }))}`,
|
|
2220
2486
|
campaignName,
|
|
2221
2487
|
goal: resolvedRequest.goal,
|
|
2222
2488
|
targetCount,
|
|
@@ -2231,6 +2497,7 @@ function createCampaignBuilderAgentPlan(request, context = {}) {
|
|
|
2231
2497
|
approvals,
|
|
2232
2498
|
buildRequest,
|
|
2233
2499
|
brainPreflight,
|
|
2500
|
+
evidence,
|
|
2234
2501
|
operatingPlaybooks,
|
|
2235
2502
|
mcpFlow: createMcpFlow(resolvedRequest, buildRequest, routes, memory, approvals),
|
|
2236
2503
|
estimatedCredits,
|
|
@@ -2322,6 +2589,90 @@ function createCampaignBuilderReadiness(plan) {
|
|
|
2322
2589
|
nextActions: campaignReadinessNextActions(plan, ready, customRoutes.length)
|
|
2323
2590
|
};
|
|
2324
2591
|
}
|
|
2592
|
+
function createCampaignBuilderActiveWorkContext(input) {
|
|
2593
|
+
const plan = input.readiness?.plan ?? input.plan;
|
|
2594
|
+
const remembered = input.remembered ?? {};
|
|
2595
|
+
const lastResult = asRecord(input.lastResult);
|
|
2596
|
+
const readinessBlockers = input.readiness?.summary.blockers ?? [];
|
|
2597
|
+
const explicitBlockers = input.blockers ?? [];
|
|
2598
|
+
const blockers = uniqueStrings([...explicitBlockers, ...readinessBlockers]);
|
|
2599
|
+
const warnings = uniqueStrings([
|
|
2600
|
+
...input.warnings ?? [],
|
|
2601
|
+
...input.readiness?.summary.warnings ?? [],
|
|
2602
|
+
...plan?.warnings ?? []
|
|
2603
|
+
]);
|
|
2604
|
+
const missingApprovals = plan ? (input.approval ? getMissingCampaignBuilderApprovals(plan, input.approval) : plan.approvals.filter((approval) => approval.blocking)).map((approval) => approval.type) : [];
|
|
2605
|
+
const refs = normalizeCampaignBuilderActiveWorkRefs({
|
|
2606
|
+
plan,
|
|
2607
|
+
remembered,
|
|
2608
|
+
refs: input.refs,
|
|
2609
|
+
lastResult
|
|
2610
|
+
});
|
|
2611
|
+
const state = inferCampaignBuilderActiveWorkState({
|
|
2612
|
+
plan,
|
|
2613
|
+
readiness: input.readiness,
|
|
2614
|
+
remembered,
|
|
2615
|
+
lastResult,
|
|
2616
|
+
blockers,
|
|
2617
|
+
missingApprovals
|
|
2618
|
+
});
|
|
2619
|
+
const nextSafeAction = campaignBuilderActiveWorkNextAction(state, blockers, missingApprovals, refs);
|
|
2620
|
+
const approvalPacket = createCampaignBuilderApprovalPacket(plan, input.approval, missingApprovals);
|
|
2621
|
+
const nextSafeMcpAction = campaignBuilderActiveWorkNextMcpAction({
|
|
2622
|
+
state,
|
|
2623
|
+
plan,
|
|
2624
|
+
refs,
|
|
2625
|
+
approvalPacket
|
|
2626
|
+
});
|
|
2627
|
+
const summary = {
|
|
2628
|
+
plan_id: plan?.planId ?? remembered.planId ?? null,
|
|
2629
|
+
campaign_name: plan?.campaignName ?? null,
|
|
2630
|
+
target_count: plan?.targetCount ?? null,
|
|
2631
|
+
gtm_campaign_id: plan?.buildRequest.gtmCampaignId ?? remembered.gtmCampaignId ?? null,
|
|
2632
|
+
campaign_build_id: stringValue(lastResult.campaign_build_id ?? lastResult.campaignBuildId) ?? remembered.campaignBuildId ?? null,
|
|
2633
|
+
provider_campaign_id: remembered.providerCampaignId ?? null
|
|
2634
|
+
};
|
|
2635
|
+
const approvalBoundary = campaignBuilderActiveWorkApprovalBoundary(missingApprovals, state);
|
|
2636
|
+
const conversationStarters = campaignBuilderActiveWorkConversationStarters({
|
|
2637
|
+
state,
|
|
2638
|
+
blockers,
|
|
2639
|
+
missingApprovals,
|
|
2640
|
+
refs,
|
|
2641
|
+
nextSafeAction
|
|
2642
|
+
});
|
|
2643
|
+
return {
|
|
2644
|
+
packet_version: "campaign-builder-active-work-context.v1",
|
|
2645
|
+
read_only: true,
|
|
2646
|
+
no_spend: true,
|
|
2647
|
+
no_provider_writes: true,
|
|
2648
|
+
private_safe: true,
|
|
2649
|
+
state,
|
|
2650
|
+
summary,
|
|
2651
|
+
refs,
|
|
2652
|
+
blockers,
|
|
2653
|
+
warnings,
|
|
2654
|
+
missing_approval_types: missingApprovals,
|
|
2655
|
+
approval_packet: approvalPacket,
|
|
2656
|
+
approval_boundary: approvalBoundary,
|
|
2657
|
+
next_safe_action: nextSafeAction,
|
|
2658
|
+
next_safe_mcp_action: nextSafeMcpAction,
|
|
2659
|
+
conversation_starters: conversationStarters,
|
|
2660
|
+
openai_agent_handoff: createCampaignBuilderOpenAiAgentHandoff({
|
|
2661
|
+
plan,
|
|
2662
|
+
state,
|
|
2663
|
+
summary,
|
|
2664
|
+
refs,
|
|
2665
|
+
blockers,
|
|
2666
|
+
warnings,
|
|
2667
|
+
missingApprovals,
|
|
2668
|
+
approvalPacket,
|
|
2669
|
+
approvalBoundary,
|
|
2670
|
+
nextSafeAction,
|
|
2671
|
+
nextSafeMcpAction,
|
|
2672
|
+
conversationStarters
|
|
2673
|
+
})
|
|
2674
|
+
};
|
|
2675
|
+
}
|
|
2325
2676
|
function createCampaignBuilderProofReceipt(plan, result) {
|
|
2326
2677
|
const strategyMemory = asRecord(plan.strategyMemoryStatus);
|
|
2327
2678
|
const dryRunResult = asRecord(result);
|
|
@@ -2380,6 +2731,7 @@ function createCampaignBuilderProofReceipt(plan, result) {
|
|
|
2380
2731
|
estimated_credits: plan.estimatedCredits,
|
|
2381
2732
|
operating_playbooks: plan.operatingPlaybooks.map((playbook) => playbook.slug)
|
|
2382
2733
|
},
|
|
2734
|
+
evidence: plan.evidence,
|
|
2383
2735
|
gates,
|
|
2384
2736
|
strategy_memory_status: summarizeCampaignBuilderProofStrategyMemory(strategyMemory),
|
|
2385
2737
|
dry_run_result: summarizeCampaignBuilderProofDryRun(dryRunResult),
|
|
@@ -2435,6 +2787,56 @@ function getCampaignBuilderOperatingPlaybooksForRequest(request) {
|
|
|
2435
2787
|
]);
|
|
2436
2788
|
return slugs.map(getCampaignBuilderOperatingPlaybook).filter((playbook) => Boolean(playbook));
|
|
2437
2789
|
}
|
|
2790
|
+
function normalizeCampaignBuilderEvidence(evidence) {
|
|
2791
|
+
if (!evidence) return null;
|
|
2792
|
+
const attachmentSummary = (evidence.attachments ?? []).filter((attachment) => stringValue(attachment.name)).slice(0, 5).map((attachment) => ({
|
|
2793
|
+
name: stringValue(attachment.name) ?? "attachment",
|
|
2794
|
+
kind: stringValue(attachment.kind) ?? null,
|
|
2795
|
+
media_type: stringValue(attachment.mediaType) ?? null,
|
|
2796
|
+
redacted: attachment.redacted !== false,
|
|
2797
|
+
columns: uniqueStrings(attachment.columns ?? []).slice(0, 25),
|
|
2798
|
+
row_count: numberOrUndefined2(attachment.rowCount) ?? null,
|
|
2799
|
+
content_summary: stringValue(attachment.contentSummary)?.slice(0, 500) ?? null,
|
|
2800
|
+
evidence_fields: uniqueStrings(attachment.evidenceFields ?? []).slice(0, 25)
|
|
2801
|
+
}));
|
|
2802
|
+
const urlSummary = (evidence.urls ?? []).filter((url) => stringValue(url.url)).slice(0, 8).map((url) => {
|
|
2803
|
+
const rawUrl = stringValue(url.url) ?? "";
|
|
2804
|
+
return {
|
|
2805
|
+
url: rawUrl,
|
|
2806
|
+
host: stringValue(url.host) ?? hostFromUrl(rawUrl) ?? null,
|
|
2807
|
+
type: stringValue(url.type) ?? null,
|
|
2808
|
+
label: stringValue(url.label) ?? null,
|
|
2809
|
+
summary: stringValue(url.summary)?.slice(0, 500) ?? null,
|
|
2810
|
+
redacted: url.redacted === true
|
|
2811
|
+
};
|
|
2812
|
+
});
|
|
2813
|
+
const operatorNotes = uniqueStrings(evidence.notes ?? []).map((note) => note.slice(0, 240)).slice(0, 5);
|
|
2814
|
+
if (!attachmentSummary.length && !urlSummary.length && !operatorNotes.length) return null;
|
|
2815
|
+
return {
|
|
2816
|
+
packet_version: "campaign-builder-evidence.v1",
|
|
2817
|
+
private_safe: true,
|
|
2818
|
+
attachment_summary: attachmentSummary,
|
|
2819
|
+
url_summary: urlSummary,
|
|
2820
|
+
operator_notes: operatorNotes,
|
|
2821
|
+
privacy_boundary: "Use these attachment and URL summaries as planning evidence only. Do not expose raw private attachment text, raw rows, leads, emails, provider payloads, copy bodies, or secrets.",
|
|
2822
|
+
raw_private_fields_withheld: [
|
|
2823
|
+
"raw_private_attachment_text",
|
|
2824
|
+
"raw_attachment_rows",
|
|
2825
|
+
"raw_leads",
|
|
2826
|
+
"email_addresses",
|
|
2827
|
+
"provider_auth_payloads",
|
|
2828
|
+
"copy_bodies",
|
|
2829
|
+
"secrets"
|
|
2830
|
+
]
|
|
2831
|
+
};
|
|
2832
|
+
}
|
|
2833
|
+
function hostFromUrl(value) {
|
|
2834
|
+
try {
|
|
2835
|
+
return new URL(value).hostname || void 0;
|
|
2836
|
+
} catch {
|
|
2837
|
+
return void 0;
|
|
2838
|
+
}
|
|
2839
|
+
}
|
|
2438
2840
|
function applyCampaignBuilderStrategyTemplate(request) {
|
|
2439
2841
|
const template = getCampaignBuilderStrategyTemplate(request.strategyTemplate);
|
|
2440
2842
|
if (!template) return request;
|
|
@@ -3126,7 +3528,7 @@ function normalizeMemory(request) {
|
|
|
3126
3528
|
};
|
|
3127
3529
|
}
|
|
3128
3530
|
function defaultAgencyMemoryQueries(request, configured) {
|
|
3129
|
-
const operatingPlaybookTerms = getCampaignBuilderOperatingPlaybooksForRequest(request).flatMap((playbook) => [playbook.label, ...playbook.memoryKeywords]).join(" ");
|
|
3531
|
+
const operatingPlaybookTerms = getCampaignBuilderOperatingPlaybooksForRequest(request).flatMap((playbook) => [playbook.label, ...playbook.memoryKeywords, ...playbook.knowledgeSources]).join(" ");
|
|
3130
3532
|
const queries = [{
|
|
3131
3533
|
query: request.goal,
|
|
3132
3534
|
scopes: ["workspace", configured.useNetworkPatterns ? "network_patterns" : "operator_notes"],
|
|
@@ -3292,6 +3694,21 @@ function routesFromCustomerTools(tools) {
|
|
|
3292
3694
|
}))
|
|
3293
3695
|
);
|
|
3294
3696
|
}
|
|
3697
|
+
function normalizeCampaignBuilderLearningHoldout(input, gtmCampaignId, campaignName) {
|
|
3698
|
+
const source = asRecord(input);
|
|
3699
|
+
if (source.enabled === false) return { enabled: false };
|
|
3700
|
+
const controlPercentage = numberOrUndefined2(source.control_percentage ?? source.controlPercentage);
|
|
3701
|
+
const minControlSize = numberOrUndefined2(source.min_control_size ?? source.minControlSize);
|
|
3702
|
+
const experimentKey = stringValue(source.experiment_key ?? source.experimentKey) ?? (gtmCampaignId ? `gtm_campaign:${gtmCampaignId}:learning_holdout` : `campaign_builder_agent:${hashString(campaignName)}:learning_holdout`);
|
|
3703
|
+
return {
|
|
3704
|
+
enabled: true,
|
|
3705
|
+
controlPercentage: controlPercentage ?? 0.2,
|
|
3706
|
+
minControlSize: minControlSize ?? 50,
|
|
3707
|
+
experimentKey,
|
|
3708
|
+
sourceCampaignId: stringValue(source.source_campaign_id ?? source.sourceCampaignId) ?? gtmCampaignId,
|
|
3709
|
+
primaryMetric: stringValue(source.primary_metric ?? source.primaryMetric) ?? "positive_reply_rate"
|
|
3710
|
+
};
|
|
3711
|
+
}
|
|
3295
3712
|
function createBuildRequest(request, defaults, targetCount, campaignName, scopeBuildArgs, routes = [], memory, scopeBrainPreflight) {
|
|
3296
3713
|
const buildRequest = {
|
|
3297
3714
|
name: campaignName,
|
|
@@ -3322,8 +3739,15 @@ function createBuildRequest(request, defaults, targetCount, campaignName, scopeB
|
|
|
3322
3739
|
fillPolicy: "aggressive"
|
|
3323
3740
|
}
|
|
3324
3741
|
};
|
|
3742
|
+
const evidence = normalizeCampaignBuilderEvidence(request.evidence);
|
|
3743
|
+
if (evidence) buildRequest.evidence = evidence;
|
|
3325
3744
|
const scoped = asRecord(scopeBuildArgs);
|
|
3326
3745
|
buildRequest.gtmCampaignId = request.gtmCampaignId ?? stringValue(scoped.gtm_campaign_id ?? scoped.gtmCampaignId);
|
|
3746
|
+
buildRequest.learningHoldout = normalizeCampaignBuilderLearningHoldout(
|
|
3747
|
+
request.learningHoldout ?? scoped.learning_holdout ?? scoped.learningHoldout,
|
|
3748
|
+
buildRequest.gtmCampaignId,
|
|
3749
|
+
campaignName
|
|
3750
|
+
);
|
|
3327
3751
|
if (typeof scoped.name === "string") buildRequest.name = scoped.name;
|
|
3328
3752
|
if (typeof scoped.prompt === "string") buildRequest.prompt = scoped.prompt;
|
|
3329
3753
|
if (typeof scoped.target_count === "number") buildRequest.targetCount = scoped.target_count;
|
|
@@ -3348,6 +3772,7 @@ function createBrainPreflight(request, buildRequest, routes, memory) {
|
|
|
3348
3772
|
memory.enabled ? "feedback" : void 0
|
|
3349
3773
|
]);
|
|
3350
3774
|
const providerChain = uniqueStrings(["signaliz", ...request.preferredProviders ?? [], ...routes.map((route) => route.provider)]);
|
|
3775
|
+
const evidence = buildRequest.evidence ?? normalizeCampaignBuilderEvidence(request.evidence);
|
|
3351
3776
|
const targetIcp = compact({
|
|
3352
3777
|
personas: buildRequest.icp?.personas,
|
|
3353
3778
|
industries: buildRequest.icp?.industries,
|
|
@@ -3360,6 +3785,7 @@ function createBrainPreflight(request, buildRequest, routes, memory) {
|
|
|
3360
3785
|
const learningArgs = compact({
|
|
3361
3786
|
campaign_brief: request.goal,
|
|
3362
3787
|
target_icp: targetIcp,
|
|
3788
|
+
evidence_context: evidence,
|
|
3363
3789
|
layers,
|
|
3364
3790
|
provider_chain: providerChain,
|
|
3365
3791
|
lead_source: providerChain[0] ?? "signaliz",
|
|
@@ -3371,6 +3797,7 @@ function createBrainPreflight(request, buildRequest, routes, memory) {
|
|
|
3371
3797
|
const defaultsArgs = compact({
|
|
3372
3798
|
campaign_brief: request.goal,
|
|
3373
3799
|
target_icp: targetIcp,
|
|
3800
|
+
evidence_context: evidence,
|
|
3374
3801
|
layers,
|
|
3375
3802
|
include_global: memory.useNetworkPatterns,
|
|
3376
3803
|
include_memory: memory.enabled,
|
|
@@ -3381,6 +3808,7 @@ function createBrainPreflight(request, buildRequest, routes, memory) {
|
|
|
3381
3808
|
provider_chain: providerChain,
|
|
3382
3809
|
lead_source: providerChain[0] ?? "signaliz",
|
|
3383
3810
|
target_icp: targetIcp,
|
|
3811
|
+
evidence_context: evidence,
|
|
3384
3812
|
include_global: memory.useNetworkPatterns,
|
|
3385
3813
|
limit: 25
|
|
3386
3814
|
});
|
|
@@ -3393,11 +3821,14 @@ function createBrainPreflight(request, buildRequest, routes, memory) {
|
|
|
3393
3821
|
label: playbook.label,
|
|
3394
3822
|
quality_gates: playbook.qualityGates,
|
|
3395
3823
|
required_fields: playbook.requiredFields,
|
|
3396
|
-
activation_boundary: playbook.activationBoundary
|
|
3824
|
+
activation_boundary: playbook.activationBoundary,
|
|
3825
|
+
knowledge_sources: playbook.knowledgeSources
|
|
3397
3826
|
})),
|
|
3398
3827
|
target_icp: targetIcp,
|
|
3828
|
+
evidence_context: evidence,
|
|
3399
3829
|
provider_chain: providerChain,
|
|
3400
3830
|
lead_source: providerChain[0] ?? "signaliz",
|
|
3831
|
+
learning_holdout: buildRequest.learningHoldout,
|
|
3401
3832
|
tool_sequence: [
|
|
3402
3833
|
{ tool: "gtm_brain_learning_cycle_plan", purpose: "Plan the Brain learning loop for this campaign.", arguments: learningArgs },
|
|
3403
3834
|
{ tool: "gtm_brain_seed_defaults", purpose: "Seed campaign defaults from workspace memory and safe aggregate patterns.", arguments: defaultsArgs },
|
|
@@ -3667,7 +4098,7 @@ function createMcpFlow(request, buildRequest, routes, memory, approvals) {
|
|
|
3667
4098
|
phase: "plan",
|
|
3668
4099
|
tool: "nango_mcp_tools_list",
|
|
3669
4100
|
arguments: {
|
|
3670
|
-
format: "
|
|
4101
|
+
format: "openai"
|
|
3671
4102
|
},
|
|
3672
4103
|
readOnly: true,
|
|
3673
4104
|
approvalRequired: false
|
|
@@ -3976,6 +4407,7 @@ function buildGtmCampaignBuildPlanArgs(request, buildRequest, routes, memory) {
|
|
|
3976
4407
|
layers: layers.length > 0 ? layers : void 0,
|
|
3977
4408
|
preferred_providers: preferredProviders.length > 0 ? preferredProviders : void 0,
|
|
3978
4409
|
strategy_model: strategyModel,
|
|
4410
|
+
evidence_context: buildRequest.evidence ?? normalizeCampaignBuilderEvidence(request.evidence),
|
|
3979
4411
|
include_strategy_patterns: campaignBuilderStrategyPatternsEnabled(agencyContext),
|
|
3980
4412
|
include_workflow_patterns: campaignBuilderWorkflowPatternsEnabled(agencyContext),
|
|
3981
4413
|
include_nango_catalog: agencyContext.includeNangoCatalog !== false,
|
|
@@ -3984,7 +4416,8 @@ function buildGtmCampaignBuildPlanArgs(request, buildRequest, routes, memory) {
|
|
|
3984
4416
|
slug: playbook.slug,
|
|
3985
4417
|
label: playbook.label,
|
|
3986
4418
|
quality_gates: playbook.qualityGates,
|
|
3987
|
-
activation_boundary: playbook.activationBoundary
|
|
4419
|
+
activation_boundary: playbook.activationBoundary,
|
|
4420
|
+
knowledge_sources: playbook.knowledgeSources
|
|
3988
4421
|
})),
|
|
3989
4422
|
include_memory: memory.enabled,
|
|
3990
4423
|
include_brain: true,
|
|
@@ -4065,8 +4498,19 @@ function buildCampaignArgs(request) {
|
|
|
4065
4498
|
if (request.dedupKeys) args.dedup_keys = request.dedupKeys;
|
|
4066
4499
|
if (request.brainPreflight) args.brain_preflight = request.brainPreflight;
|
|
4067
4500
|
if (request.brainDefaults) args.brain_defaults = request.brainDefaults;
|
|
4501
|
+
if (request.learningHoldout) {
|
|
4502
|
+
args.learning_holdout = compact({
|
|
4503
|
+
enabled: request.learningHoldout.enabled,
|
|
4504
|
+
control_percentage: request.learningHoldout.controlPercentage,
|
|
4505
|
+
min_control_size: request.learningHoldout.minControlSize,
|
|
4506
|
+
experiment_key: request.learningHoldout.experimentKey,
|
|
4507
|
+
source_campaign_id: request.learningHoldout.sourceCampaignId,
|
|
4508
|
+
primary_metric: request.learningHoldout.primaryMetric
|
|
4509
|
+
});
|
|
4510
|
+
}
|
|
4068
4511
|
if (request.campaignStrategyContext) args.campaign_strategy_context = request.campaignStrategyContext;
|
|
4069
4512
|
if (request.deliveryRisk) args.delivery_risk = request.deliveryRisk;
|
|
4513
|
+
if (request.evidence) args.evidence_context = request.evidence;
|
|
4070
4514
|
if (request.icp) {
|
|
4071
4515
|
args.icp = compact({
|
|
4072
4516
|
personas: request.icp.personas,
|
|
@@ -4116,7 +4560,8 @@ function buildCampaignArgs(request) {
|
|
|
4116
4560
|
max_body_words: request.copy.maxBodyWords,
|
|
4117
4561
|
sender_context: request.copy.senderContext,
|
|
4118
4562
|
offer_context: request.copy.offerContext,
|
|
4119
|
-
model: request.copy.model
|
|
4563
|
+
model: request.copy.model,
|
|
4564
|
+
evidence_mode: request.copy.evidenceMode
|
|
4120
4565
|
});
|
|
4121
4566
|
}
|
|
4122
4567
|
if (request.delivery) {
|
|
@@ -4161,6 +4606,7 @@ function buildExecutionPrepareArgs(request, dryRun, confirmSpend) {
|
|
|
4161
4606
|
delivery_risk: buildArgs2.delivery_risk,
|
|
4162
4607
|
dedup_keys: buildArgs2.dedup_keys,
|
|
4163
4608
|
policy: buildArgs2.policy,
|
|
4609
|
+
learning_holdout: buildArgs2.learning_holdout,
|
|
4164
4610
|
signals: buildArgs2.signals,
|
|
4165
4611
|
qualification: buildArgs2.qualification,
|
|
4166
4612
|
copy: buildArgs2.copy,
|
|
@@ -4195,10 +4641,145 @@ function mapBuildResult(data, dryRun) {
|
|
|
4195
4641
|
targetLimitReason: data.target_limit_reason,
|
|
4196
4642
|
maxSupportedTargetCount: data.max_supported_target_count,
|
|
4197
4643
|
brainContext: data.brain_context ?? {},
|
|
4644
|
+
learningHoldout: data.learning_holdout ?? {},
|
|
4198
4645
|
providerRoute: mapProviderRoute2(data)
|
|
4199
4646
|
};
|
|
4200
4647
|
}
|
|
4648
|
+
var CAMPAIGN_BUILDER_TERMINAL_STATUSES = /* @__PURE__ */ new Set(["completed", "failed", "canceled", "cancelled"]);
|
|
4649
|
+
var CAMPAIGN_BUILDER_BLOCKED_TERMINAL_STATUSES = /* @__PURE__ */ new Set(["failed", "canceled", "cancelled"]);
|
|
4650
|
+
function mapAgentCampaignPhaseHealth(value) {
|
|
4651
|
+
if (!Array.isArray(value)) return [];
|
|
4652
|
+
return value.map((phase) => {
|
|
4653
|
+
const record = asRecord(phase);
|
|
4654
|
+
return {
|
|
4655
|
+
phase: stringValue(record.phase) ?? "unknown",
|
|
4656
|
+
status: stringValue(record.status) ?? "unknown",
|
|
4657
|
+
recordsProcessed: numberOrNull2(record.records_processed ?? record.recordsProcessed),
|
|
4658
|
+
recordsSucceeded: numberOrNull2(record.records_succeeded ?? record.recordsSucceeded),
|
|
4659
|
+
recordsFailed: numberOrNull2(record.records_failed ?? record.recordsFailed),
|
|
4660
|
+
heartbeatAgeSeconds: numberOrNull2(record.heartbeat_age_seconds ?? record.heartbeatAgeSeconds ?? record.phase_age_seconds)
|
|
4661
|
+
};
|
|
4662
|
+
});
|
|
4663
|
+
}
|
|
4664
|
+
function deriveCampaignBuildTerminalState(input) {
|
|
4665
|
+
const status = input.status.toLowerCase();
|
|
4666
|
+
const heartbeatAgeSeconds = input.phaseAgeSeconds;
|
|
4667
|
+
const stale = input.staleRunningPhase === true;
|
|
4668
|
+
const safeWatchAction = input.triggerRunId ? `signaliz ops run-status ${input.triggerRunId} --watch` : "signaliz campaign-agent status <campaign_build_id>";
|
|
4669
|
+
if (CAMPAIGN_BUILDER_BLOCKED_TERMINAL_STATUSES.has(status)) {
|
|
4670
|
+
return {
|
|
4671
|
+
kind: "blocked",
|
|
4672
|
+
label: "Blocked terminal state",
|
|
4673
|
+
reviewable: true,
|
|
4674
|
+
terminal: true,
|
|
4675
|
+
stale: false,
|
|
4676
|
+
phase: input.phase,
|
|
4677
|
+
phaseStatus: input.phaseStatus,
|
|
4678
|
+
heartbeatAgeSeconds,
|
|
4679
|
+
nextPollAfterSeconds: input.nextPollAfterSeconds,
|
|
4680
|
+
terminalReason: input.terminalReason,
|
|
4681
|
+
staleReason: null,
|
|
4682
|
+
safeNextAction: input.nextAction || "Review errors and rerun only after the blocker is resolved."
|
|
4683
|
+
};
|
|
4684
|
+
}
|
|
4685
|
+
if (status === "pending_approval") {
|
|
4686
|
+
return {
|
|
4687
|
+
kind: "pending_approval",
|
|
4688
|
+
label: "Pending delivery approval",
|
|
4689
|
+
reviewable: true,
|
|
4690
|
+
terminal: false,
|
|
4691
|
+
stale: false,
|
|
4692
|
+
phase: input.phase,
|
|
4693
|
+
phaseStatus: input.phaseStatus,
|
|
4694
|
+
heartbeatAgeSeconds,
|
|
4695
|
+
nextPollAfterSeconds: input.nextPollAfterSeconds,
|
|
4696
|
+
terminalReason: input.terminalReason,
|
|
4697
|
+
staleReason: null,
|
|
4698
|
+
safeNextAction: input.approvalAction || input.nextAction || "Review rows and approve delivery only after the approval packet passes."
|
|
4699
|
+
};
|
|
4700
|
+
}
|
|
4701
|
+
if (CAMPAIGN_BUILDER_TERMINAL_STATUSES.has(status)) {
|
|
4702
|
+
return {
|
|
4703
|
+
kind: "terminal",
|
|
4704
|
+
label: "Terminal and reviewable",
|
|
4705
|
+
reviewable: true,
|
|
4706
|
+
terminal: true,
|
|
4707
|
+
stale: false,
|
|
4708
|
+
phase: input.phase,
|
|
4709
|
+
phaseStatus: input.phaseStatus,
|
|
4710
|
+
heartbeatAgeSeconds,
|
|
4711
|
+
nextPollAfterSeconds: input.nextPollAfterSeconds,
|
|
4712
|
+
terminalReason: input.terminalReason,
|
|
4713
|
+
staleReason: null,
|
|
4714
|
+
safeNextAction: input.nextAction || "Review rows, artifacts, scorecard, and approval locks before delivery."
|
|
4715
|
+
};
|
|
4716
|
+
}
|
|
4717
|
+
if (status === "running" || status === "queued" || status === "processing") {
|
|
4718
|
+
if (stale) {
|
|
4719
|
+
return {
|
|
4720
|
+
kind: "running_stale",
|
|
4721
|
+
label: "Running but stale",
|
|
4722
|
+
reviewable: false,
|
|
4723
|
+
terminal: false,
|
|
4724
|
+
stale: true,
|
|
4725
|
+
phase: input.phase,
|
|
4726
|
+
phaseStatus: input.phaseStatus,
|
|
4727
|
+
heartbeatAgeSeconds,
|
|
4728
|
+
nextPollAfterSeconds: input.nextPollAfterSeconds,
|
|
4729
|
+
terminalReason: null,
|
|
4730
|
+
staleReason: input.staleReason || "The active phase heartbeat is stale.",
|
|
4731
|
+
safeNextAction: input.nextAction || safeWatchAction
|
|
4732
|
+
};
|
|
4733
|
+
}
|
|
4734
|
+
return {
|
|
4735
|
+
kind: "running_healthy",
|
|
4736
|
+
label: "Running and healthy",
|
|
4737
|
+
reviewable: false,
|
|
4738
|
+
terminal: false,
|
|
4739
|
+
stale: false,
|
|
4740
|
+
phase: input.phase,
|
|
4741
|
+
phaseStatus: input.phaseStatus,
|
|
4742
|
+
heartbeatAgeSeconds,
|
|
4743
|
+
nextPollAfterSeconds: input.nextPollAfterSeconds,
|
|
4744
|
+
terminalReason: null,
|
|
4745
|
+
staleReason: null,
|
|
4746
|
+
safeNextAction: input.nextAction || safeWatchAction
|
|
4747
|
+
};
|
|
4748
|
+
}
|
|
4749
|
+
return {
|
|
4750
|
+
kind: "unknown",
|
|
4751
|
+
label: "Unknown build state",
|
|
4752
|
+
reviewable: false,
|
|
4753
|
+
terminal: false,
|
|
4754
|
+
stale,
|
|
4755
|
+
phase: input.phase,
|
|
4756
|
+
phaseStatus: input.phaseStatus,
|
|
4757
|
+
heartbeatAgeSeconds,
|
|
4758
|
+
nextPollAfterSeconds: input.nextPollAfterSeconds,
|
|
4759
|
+
terminalReason: input.terminalReason,
|
|
4760
|
+
staleReason: input.staleReason,
|
|
4761
|
+
safeNextAction: input.nextAction || "Read campaign build status again before making a launch or delivery decision."
|
|
4762
|
+
};
|
|
4763
|
+
}
|
|
4201
4764
|
function mapAgentCampaignBuildStatus(data) {
|
|
4765
|
+
const customerRowCounts = mapAgentCustomerRowCounts(data.customer_row_counts);
|
|
4766
|
+
const phaseHealth = mapAgentCampaignPhaseHealth(data.phases);
|
|
4767
|
+
const terminalReason = stringValue(data.terminal_reason) ?? customerRowCounts?.terminalReason ?? null;
|
|
4768
|
+
const staleReason = stringValue(data.stale_reason) ?? stringValue(asRecord(data.diagnostics).stale_reason) ?? null;
|
|
4769
|
+
const nextPollAfterSeconds = numberOrNull2(data.next_poll_after_seconds ?? data.nextPollAfterSeconds);
|
|
4770
|
+
const terminalState = deriveCampaignBuildTerminalState({
|
|
4771
|
+
status: stringValue(data.status) ?? "unknown",
|
|
4772
|
+
phase: stringValue(data.current_phase) ?? null,
|
|
4773
|
+
phaseStatus: stringValue(data.current_phase_status) ?? null,
|
|
4774
|
+
staleRunningPhase: data.stale_running_phase === true,
|
|
4775
|
+
phaseAgeSeconds: numberOrNull2(data.phase_age_seconds),
|
|
4776
|
+
nextPollAfterSeconds,
|
|
4777
|
+
terminalReason,
|
|
4778
|
+
staleReason,
|
|
4779
|
+
nextAction: formatAgentNextAction(data.next_action),
|
|
4780
|
+
approvalAction: formatAgentNextAction(data.approval_action),
|
|
4781
|
+
triggerRunId: stringValue(data.trigger_run_id) ?? null
|
|
4782
|
+
});
|
|
4202
4783
|
return {
|
|
4203
4784
|
campaignBuildId: stringValue(data.campaign_build_id) ?? "",
|
|
4204
4785
|
campaignId: stringValue(data.campaign_id) ?? null,
|
|
@@ -4216,12 +4797,18 @@ function mapAgentCampaignBuildStatus(data) {
|
|
|
4216
4797
|
errors: diagnosticMessages2(data.errors),
|
|
4217
4798
|
artifactCount: numberOrUndefined2(data.artifact_count) ?? 0,
|
|
4218
4799
|
artifactDownloads: Array.isArray(data.artifact_downloads) ? data.artifact_downloads.map(mapAgentCampaignArtifactDownload) : [],
|
|
4219
|
-
customerRowCounts
|
|
4800
|
+
customerRowCounts,
|
|
4220
4801
|
phaseAttemptTotals: nullableRecord(data.phase_attempt_totals) ?? void 0,
|
|
4221
4802
|
providerRoute: mapProviderRoute2(data),
|
|
4222
4803
|
triggerRunId: stringValue(data.trigger_run_id) ?? null,
|
|
4223
4804
|
staleRunningPhase: data.stale_running_phase === true,
|
|
4224
4805
|
phaseAgeSeconds: numberOrNull2(data.phase_age_seconds),
|
|
4806
|
+
nextPollAfterSeconds,
|
|
4807
|
+
terminalReason,
|
|
4808
|
+
staleReason,
|
|
4809
|
+
safeNextAction: terminalState.safeNextAction,
|
|
4810
|
+
terminalState,
|
|
4811
|
+
phaseHealth,
|
|
4225
4812
|
diagnostics: nullableRecord(data.diagnostics) ?? {},
|
|
4226
4813
|
nextAction: formatAgentNextAction(data.next_action),
|
|
4227
4814
|
approvalAction: formatAgentNextAction(data.approval_action),
|
|
@@ -4251,6 +4838,7 @@ function mapAgentCustomerRowCounts(value) {
|
|
|
4251
4838
|
acceptedRows: numberOrUndefined2(record.accepted_rows),
|
|
4252
4839
|
usableRows: numberOrUndefined2(record.usable_rows),
|
|
4253
4840
|
copiedRows: numberOrUndefined2(record.copied_rows),
|
|
4841
|
+
copySkippedRows: numberOrUndefined2(record.copy_skipped_rows),
|
|
4254
4842
|
approvalReadyRows: numberOrUndefined2(record.approval_ready_rows),
|
|
4255
4843
|
qaReadyRows: numberOrUndefined2(record.qa_ready_rows),
|
|
4256
4844
|
deliveredRows: numberOrUndefined2(record.delivered_rows),
|
|
@@ -4309,67 +4897,285 @@ function mapAgentCampaignArtifact(data) {
|
|
|
4309
4897
|
createdAt: stringValue(data.created_at) ?? ""
|
|
4310
4898
|
};
|
|
4311
4899
|
}
|
|
4900
|
+
var NORTH_STAR_BANNED_COPY_PHRASES = [
|
|
4901
|
+
"i have been following",
|
|
4902
|
+
"i saw that",
|
|
4903
|
+
"would you be opposed",
|
|
4904
|
+
"unlock new opportunities",
|
|
4905
|
+
"significant success",
|
|
4906
|
+
"we understand",
|
|
4907
|
+
"hope this finds you well"
|
|
4908
|
+
];
|
|
4909
|
+
function campaignReviewGate(id, label, status, detail) {
|
|
4910
|
+
return {
|
|
4911
|
+
id,
|
|
4912
|
+
label,
|
|
4913
|
+
status,
|
|
4914
|
+
passed: status !== "blocked",
|
|
4915
|
+
detail
|
|
4916
|
+
};
|
|
4917
|
+
}
|
|
4918
|
+
function northStarMetric(id, label, status, detail, value, target) {
|
|
4919
|
+
return {
|
|
4920
|
+
id,
|
|
4921
|
+
label,
|
|
4922
|
+
status,
|
|
4923
|
+
detail,
|
|
4924
|
+
...value !== void 0 ? { value } : {},
|
|
4925
|
+
...target !== void 0 ? { target } : {}
|
|
4926
|
+
};
|
|
4927
|
+
}
|
|
4928
|
+
function createCampaignBuilderNorthStarScorecard(status, rows, artifacts, terminalState) {
|
|
4929
|
+
if (!terminalState.reviewable) {
|
|
4930
|
+
const pendingMetric = northStarMetric(
|
|
4931
|
+
"terminal_state",
|
|
4932
|
+
"Terminal-state contract",
|
|
4933
|
+
terminalState.kind === "running_stale" ? "blocked" : "pending",
|
|
4934
|
+
terminalState.kind === "running_stale" ? `Build is stale in ${terminalState.phase || "unknown phase"}; do not grade output yet.` : `Build is ${terminalState.label.toLowerCase()}; wait for terminal or approval state before grading.`,
|
|
4935
|
+
terminalState.kind,
|
|
4936
|
+
"terminal or pending_approval"
|
|
4937
|
+
);
|
|
4938
|
+
return {
|
|
4939
|
+
version: "campaign-builder-north-star.v1",
|
|
4940
|
+
status: pendingMetric.status,
|
|
4941
|
+
score: null,
|
|
4942
|
+
moatState: "scaffolding_ready",
|
|
4943
|
+
metrics: [pendingMetric],
|
|
4944
|
+
blockers: pendingMetric.status === "blocked" ? [pendingMetric.detail] : [],
|
|
4945
|
+
warnings: pendingMetric.status === "pending" ? [pendingMetric.detail] : [],
|
|
4946
|
+
nextAction: terminalState.safeNextAction
|
|
4947
|
+
};
|
|
4948
|
+
}
|
|
4949
|
+
const sampledRows = rows.rows.length;
|
|
4950
|
+
const rowData = rows.rows.map((row) => asRecord(row.data));
|
|
4951
|
+
const requestedTarget = status.customerRowCounts?.requestedTarget ?? status.recordsTotal ?? rows.count;
|
|
4952
|
+
const finalRows = status.customerRowCounts?.deliveredRows ?? status.customerRowCounts?.qaReadyRows ?? status.customerRowCounts?.copySkippedRows ?? status.customerRowCounts?.copiedRows ?? status.customerRowCounts?.acceptedRows ?? rows.count;
|
|
4953
|
+
const rowsWithEmail = rows.rows.filter(campaignReviewRowHasEmail).length;
|
|
4954
|
+
const verifiedEmailRows = rowData.filter(campaignReviewDataHasVerifiedEmail).length;
|
|
4955
|
+
const uniqueEmails = new Set(rowData.map(campaignReviewDataEmail).filter(Boolean)).size;
|
|
4956
|
+
const uniqueDomains = new Set(rowData.map(campaignReviewDataDomain).filter(Boolean)).size;
|
|
4957
|
+
const copyReadyRows = rows.rows.filter(campaignReviewRowHasCopy).length;
|
|
4958
|
+
const copyQaIssuesByRow = rowData.map(campaignReviewDataCopyQaIssues).filter((issues) => issues.length > 0);
|
|
4959
|
+
const copyQaIssueCounts = countCampaignReviewIssues(copyQaIssuesByRow);
|
|
4960
|
+
const signalBackedRows = rowData.filter(campaignReviewDataHasSignalBasis).length;
|
|
4961
|
+
const noSupportedSignalRows = rowData.filter(campaignReviewDataHasNoSupportedSignal).length;
|
|
4962
|
+
const unsupportedSignalClaims = rowData.filter(campaignReviewDataHasUnsupportedSignalClaim).length;
|
|
4963
|
+
const approvalLockedRows = rowData.filter(campaignReviewDataHasApprovalLock).length;
|
|
4964
|
+
const holdoutRows = rowData.filter(campaignReviewDataHasHoldoutAttribution).length;
|
|
4965
|
+
const artifactCount = artifacts.length || status.artifactCount || 0;
|
|
4966
|
+
const deliveredRows = status.customerRowCounts?.deliveredRows ?? 0;
|
|
4967
|
+
const feedbackReady = campaignReviewStatusHasFeedbackReadiness(status);
|
|
4968
|
+
const feedbackRequiredForApproval = terminalState.kind === "pending_approval";
|
|
4969
|
+
const moat = campaignReviewMoatState(status, holdoutRows);
|
|
4970
|
+
const metrics = [
|
|
4971
|
+
northStarMetric(
|
|
4972
|
+
"terminal_state",
|
|
4973
|
+
"Terminal-state contract",
|
|
4974
|
+
terminalState.kind === "blocked" ? "blocked" : "pass",
|
|
4975
|
+
terminalState.label,
|
|
4976
|
+
terminalState.kind,
|
|
4977
|
+
"terminal or pending_approval"
|
|
4978
|
+
),
|
|
4979
|
+
northStarMetric(
|
|
4980
|
+
"target_fill",
|
|
4981
|
+
"Target fill",
|
|
4982
|
+
requestedTarget && finalRows < requestedTarget ? "review" : "pass",
|
|
4983
|
+
requestedTarget ? `${finalRows || 0}/${requestedTarget} final or reviewable row(s) are accounted for.` : "No requested target was reported; using sampled rows for review.",
|
|
4984
|
+
finalRows || sampledRows,
|
|
4985
|
+
requestedTarget || sampledRows
|
|
4986
|
+
),
|
|
4987
|
+
northStarMetric(
|
|
4988
|
+
"unique_emails",
|
|
4989
|
+
"Unique emails",
|
|
4990
|
+
sampledRows === 0 ? "blocked" : uniqueEmails === rowsWithEmail ? "pass" : "blocked",
|
|
4991
|
+
sampledRows === 0 ? "No sampled rows were available for email uniqueness review." : `${uniqueEmails}/${rowsWithEmail} sampled email(s) are unique.`,
|
|
4992
|
+
uniqueEmails,
|
|
4993
|
+
rowsWithEmail
|
|
4994
|
+
),
|
|
4995
|
+
northStarMetric(
|
|
4996
|
+
"unique_domains",
|
|
4997
|
+
"Unique domains",
|
|
4998
|
+
sampledRows === 0 ? "blocked" : uniqueDomains === sampledRows ? "pass" : "review",
|
|
4999
|
+
sampledRows === 0 ? "No sampled rows were available for domain uniqueness review." : `${uniqueDomains}/${sampledRows} sampled company domain(s) are unique.`,
|
|
5000
|
+
uniqueDomains,
|
|
5001
|
+
sampledRows
|
|
5002
|
+
),
|
|
5003
|
+
northStarMetric(
|
|
5004
|
+
"verified_email_rows",
|
|
5005
|
+
"Verified email rows",
|
|
5006
|
+
sampledRows === 0 ? "blocked" : verifiedEmailRows === sampledRows ? "pass" : rowsWithEmail === sampledRows ? "review" : "blocked",
|
|
5007
|
+
sampledRows === 0 ? "No sampled rows were available for email verification review." : `${verifiedEmailRows}/${sampledRows} sampled row(s) carry verified-email evidence.`,
|
|
5008
|
+
verifiedEmailRows,
|
|
5009
|
+
sampledRows
|
|
5010
|
+
),
|
|
5011
|
+
northStarMetric(
|
|
5012
|
+
"copy_completeness",
|
|
5013
|
+
"Copy completeness",
|
|
5014
|
+
sampledRows === 0 ? "blocked" : copyReadyRows === sampledRows ? "pass" : "blocked",
|
|
5015
|
+
sampledRows === 0 ? "No sampled rows were available for copy review." : `${copyReadyRows}/${sampledRows} sampled row(s) include generated copy.`,
|
|
5016
|
+
copyReadyRows,
|
|
5017
|
+
sampledRows
|
|
5018
|
+
),
|
|
5019
|
+
northStarMetric(
|
|
5020
|
+
"copy_quality",
|
|
5021
|
+
"Copy QA",
|
|
5022
|
+
copyQaIssuesByRow.length === 0 ? "pass" : "blocked",
|
|
5023
|
+
copyQaIssuesByRow.length === 0 ? "No sampled copy QA blockers were detected." : `${copyQaIssuesByRow.length}/${sampledRows} sampled row(s) have copy QA issue(s): ${formatCampaignReviewIssueCounts(copyQaIssueCounts)}.`,
|
|
5024
|
+
copyQaIssuesByRow.length,
|
|
5025
|
+
0
|
|
5026
|
+
),
|
|
5027
|
+
northStarMetric(
|
|
5028
|
+
"signal_grounding",
|
|
5029
|
+
"Signal grounding",
|
|
5030
|
+
unsupportedSignalClaims > 0 ? "blocked" : signalBackedRows > 0 ? "pass" : "review",
|
|
5031
|
+
unsupportedSignalClaims > 0 ? `${unsupportedSignalClaims} sampled row(s) make unsupported signal claims.` : signalBackedRows > 0 ? `${signalBackedRows}/${sampledRows} sampled row(s) include supported signal or personalization basis.` : noSupportedSignalRows > 0 ? `${noSupportedSignalRows}/${sampledRows} sampled row(s) are explicitly marked no_supported_signal; copy should stay conservative.` : "No sampled rows include supported signal evidence; copy should stay conservative.",
|
|
5032
|
+
signalBackedRows,
|
|
5033
|
+
sampledRows
|
|
5034
|
+
),
|
|
5035
|
+
northStarMetric(
|
|
5036
|
+
"approval_locks",
|
|
5037
|
+
"Approval locks",
|
|
5038
|
+
approvalLockedRows > 0 || deliveredRows === 0 ? "pass" : "review",
|
|
5039
|
+
approvalLockedRows > 0 ? `${approvalLockedRows}/${sampledRows} sampled row(s) show approval/export lock metadata.` : "Approval-lock metadata was not visible in sampled rows; preserve delivery approval gates.",
|
|
5040
|
+
approvalLockedRows,
|
|
5041
|
+
sampledRows
|
|
5042
|
+
),
|
|
5043
|
+
northStarMetric(
|
|
5044
|
+
"export_send_safety",
|
|
5045
|
+
"Export/send safety",
|
|
5046
|
+
deliveredRows > 0 && status.status !== "completed" ? "blocked" : "pass",
|
|
5047
|
+
deliveredRows > 0 ? `${deliveredRows} row(s) are delivered; status is ${status.status}.` : "No delivered rows are reported before approval.",
|
|
5048
|
+
deliveredRows,
|
|
5049
|
+
0
|
|
5050
|
+
),
|
|
5051
|
+
northStarMetric(
|
|
5052
|
+
"holdout_attribution",
|
|
5053
|
+
"Holdout attribution",
|
|
5054
|
+
holdoutRows > 0 ? "pass" : "review",
|
|
5055
|
+
holdoutRows > 0 ? `${holdoutRows}/${sampledRows} sampled row(s) preserve holdout attribution.` : "No holdout attribution was visible in the sampled rows.",
|
|
5056
|
+
holdoutRows,
|
|
5057
|
+
sampledRows
|
|
5058
|
+
),
|
|
5059
|
+
northStarMetric(
|
|
5060
|
+
"feedback_readiness",
|
|
5061
|
+
"Feedback readiness",
|
|
5062
|
+
feedbackReady ? "pass" : feedbackRequiredForApproval ? "blocked" : "review",
|
|
5063
|
+
feedbackReady ? "Feedback readiness is visible in status diagnostics." : feedbackRequiredForApproval ? "Feedback webhook or approved pull readiness is required before delivery approval." : "Feedback webhook or approved pull readiness was not visible; require it before real send approval.",
|
|
5064
|
+
feedbackReady,
|
|
5065
|
+
true
|
|
5066
|
+
),
|
|
5067
|
+
northStarMetric(
|
|
5068
|
+
"causal_moat",
|
|
5069
|
+
"Causal moat",
|
|
5070
|
+
moat.state === "proved" ? "pass" : "review",
|
|
5071
|
+
moat.detail,
|
|
5072
|
+
moat.state,
|
|
5073
|
+
"proved"
|
|
5074
|
+
),
|
|
5075
|
+
northStarMetric(
|
|
5076
|
+
"artifact_readback",
|
|
5077
|
+
"Artifact readback",
|
|
5078
|
+
artifactCount > 0 ? "pass" : "review",
|
|
5079
|
+
artifactCount > 0 ? `${artifactCount} artifact(s) are available for review.` : "No review artifact is available yet.",
|
|
5080
|
+
artifactCount,
|
|
5081
|
+
1
|
|
5082
|
+
)
|
|
5083
|
+
];
|
|
5084
|
+
const gradedMetrics = metrics.filter((metric) => metric.status !== "pending");
|
|
5085
|
+
const score = gradedMetrics.length === 0 ? null : Math.round(gradedMetrics.filter((metric) => metric.status === "pass").length / gradedMetrics.length * 100);
|
|
5086
|
+
const blockers = metrics.filter((metric) => metric.status === "blocked").map((metric) => metric.detail);
|
|
5087
|
+
const warnings = metrics.filter((metric) => metric.status === "review").map((metric) => metric.detail);
|
|
5088
|
+
const scorecardStatus = blockers.length > 0 ? "blocked" : warnings.length > 0 ? "review" : "pass";
|
|
5089
|
+
return {
|
|
5090
|
+
version: "campaign-builder-north-star.v1",
|
|
5091
|
+
status: scorecardStatus,
|
|
5092
|
+
score,
|
|
5093
|
+
moatState: moat.state,
|
|
5094
|
+
metrics,
|
|
5095
|
+
blockers,
|
|
5096
|
+
warnings,
|
|
5097
|
+
nextAction: scorecardStatus === "blocked" ? "Fix blocked North Star gates before approval or delivery." : terminalState.safeNextAction
|
|
5098
|
+
};
|
|
5099
|
+
}
|
|
4312
5100
|
function createCampaignBuilderBuildReview(status, rows, artifacts) {
|
|
5101
|
+
const terminalState = status.terminalState ?? deriveCampaignBuildTerminalState({
|
|
5102
|
+
status: status.status,
|
|
5103
|
+
phase: status.currentPhase,
|
|
5104
|
+
phaseStatus: status.currentPhaseStatus,
|
|
5105
|
+
staleRunningPhase: status.staleRunningPhase === true,
|
|
5106
|
+
phaseAgeSeconds: status.phaseAgeSeconds ?? null,
|
|
5107
|
+
nextPollAfterSeconds: status.nextPollAfterSeconds ?? null,
|
|
5108
|
+
terminalReason: status.terminalReason ?? status.customerRowCounts?.terminalReason ?? null,
|
|
5109
|
+
staleReason: status.staleReason ?? null,
|
|
5110
|
+
nextAction: status.nextAction,
|
|
5111
|
+
approvalAction: status.approvalAction,
|
|
5112
|
+
triggerRunId: status.triggerRunId ?? null
|
|
5113
|
+
});
|
|
4313
5114
|
const sampledRows = rows.rows.length;
|
|
4314
5115
|
const availableRows = rows.count || sampledRows;
|
|
4315
5116
|
const qualifiedRows = rows.rows.filter((row) => row.qualified !== false).length;
|
|
4316
5117
|
const rowsWithEmail = rows.rows.filter(campaignReviewRowHasEmail).length;
|
|
4317
5118
|
const copyReadyRows = rows.rows.filter(campaignReviewRowHasCopy).length;
|
|
4318
5119
|
const artifactCount = artifacts.length || status.artifactCount || 0;
|
|
5120
|
+
const northStarScorecard = createCampaignBuilderNorthStarScorecard(status, rows, artifacts, terminalState);
|
|
4319
5121
|
const gates = [
|
|
4320
|
-
|
|
4321
|
-
|
|
4322
|
-
|
|
4323
|
-
|
|
4324
|
-
|
|
4325
|
-
|
|
4326
|
-
|
|
4327
|
-
|
|
4328
|
-
|
|
4329
|
-
|
|
4330
|
-
|
|
4331
|
-
|
|
4332
|
-
|
|
4333
|
-
|
|
4334
|
-
|
|
4335
|
-
|
|
4336
|
-
|
|
4337
|
-
|
|
4338
|
-
|
|
4339
|
-
|
|
4340
|
-
|
|
4341
|
-
|
|
4342
|
-
|
|
4343
|
-
|
|
4344
|
-
|
|
4345
|
-
|
|
4346
|
-
|
|
4347
|
-
|
|
4348
|
-
|
|
4349
|
-
|
|
4350
|
-
|
|
4351
|
-
|
|
4352
|
-
|
|
4353
|
-
|
|
4354
|
-
|
|
4355
|
-
|
|
5122
|
+
campaignReviewGate(
|
|
5123
|
+
"build_reviewable",
|
|
5124
|
+
"Build reviewable",
|
|
5125
|
+
terminalState.kind === "running_healthy" ? "pending" : terminalState.kind === "running_stale" || terminalState.kind === "blocked" ? "blocked" : "pass",
|
|
5126
|
+
terminalState.label
|
|
5127
|
+
),
|
|
5128
|
+
campaignReviewGate(
|
|
5129
|
+
"rows_available",
|
|
5130
|
+
"Rows available",
|
|
5131
|
+
sampledRows > 0 ? "pass" : terminalState.reviewable ? "blocked" : "pending",
|
|
5132
|
+
sampledRows > 0 ? `${sampledRows} sampled row(s) are available for review.` : terminalState.reviewable ? "No rows were returned for review." : "Rows are not graded until the build is reviewable."
|
|
5133
|
+
),
|
|
5134
|
+
campaignReviewGate(
|
|
5135
|
+
"qualified_sample",
|
|
5136
|
+
"Sample rows qualified",
|
|
5137
|
+
sampledRows === 0 ? terminalState.reviewable ? "blocked" : "pending" : qualifiedRows === sampledRows ? "pass" : "blocked",
|
|
5138
|
+
sampledRows > 0 ? `${qualifiedRows}/${sampledRows} sampled row(s) are marked qualified.` : "Qualification could not be checked without sampled rows."
|
|
5139
|
+
),
|
|
5140
|
+
campaignReviewGate(
|
|
5141
|
+
"email_coverage",
|
|
5142
|
+
"Email coverage",
|
|
5143
|
+
sampledRows === 0 ? terminalState.reviewable ? "blocked" : "pending" : rowsWithEmail === sampledRows ? "pass" : "blocked",
|
|
5144
|
+
sampledRows > 0 ? `${rowsWithEmail}/${sampledRows} sampled row(s) include an email.` : "Email coverage could not be checked without sampled rows."
|
|
5145
|
+
),
|
|
5146
|
+
campaignReviewGate(
|
|
5147
|
+
"artifact_available",
|
|
5148
|
+
"Artifact available",
|
|
5149
|
+
artifactCount > 0 ? "pass" : terminalState.reviewable ? "review" : "pending",
|
|
5150
|
+
artifactCount > 0 ? `${artifactCount} artifact(s) are available.` : "No delivery artifact is available yet."
|
|
5151
|
+
),
|
|
5152
|
+
campaignReviewGate(
|
|
5153
|
+
"no_failed_rows",
|
|
5154
|
+
"No failed rows",
|
|
5155
|
+
status.recordsFailed === 0 ? "pass" : "blocked",
|
|
5156
|
+
status.recordsFailed === 0 ? "The build reports zero failed rows." : `${status.recordsFailed} row(s) failed during the build.`
|
|
5157
|
+
)
|
|
4356
5158
|
];
|
|
4357
|
-
const blockedReasons = gates.filter((gate) => !gate.passed).map((gate) => gate.detail);
|
|
5159
|
+
const blockedReasons = gates.filter((gate) => gate.status === "blocked" || !gate.passed).map((gate) => gate.detail);
|
|
4358
5160
|
const warnings = [
|
|
4359
5161
|
rows.hasMore ? "This review is based on a row sample; page through remaining rows before final approval." : void 0,
|
|
4360
5162
|
sampledRows > 0 && copyReadyRows < sampledRows ? `${copyReadyRows}/${sampledRows} sampled row(s) include generated copy.` : void 0,
|
|
4361
5163
|
...status.warnings
|
|
4362
5164
|
].filter((item) => Boolean(item));
|
|
4363
|
-
const readyForDeliveryApproval = blockedReasons.length === 0;
|
|
5165
|
+
const readyForDeliveryApproval = terminalState.reviewable && blockedReasons.length === 0 && northStarScorecard.status !== "blocked";
|
|
4364
5166
|
return {
|
|
4365
5167
|
campaignBuildId: status.campaignBuildId || rows.campaignBuildId,
|
|
4366
5168
|
status,
|
|
4367
5169
|
rows,
|
|
4368
5170
|
artifacts,
|
|
4369
5171
|
gates,
|
|
5172
|
+
northStarScorecard,
|
|
4370
5173
|
summary: {
|
|
4371
5174
|
status: status.status,
|
|
4372
5175
|
phase: status.currentPhase,
|
|
5176
|
+
terminalState: terminalState.kind,
|
|
5177
|
+
scorecardStatus: northStarScorecard.status,
|
|
5178
|
+
scorecardScore: northStarScorecard.score,
|
|
4373
5179
|
sampledRows,
|
|
4374
5180
|
availableRows,
|
|
4375
5181
|
qualifiedRows,
|
|
@@ -4423,6 +5229,184 @@ function campaignReviewRowHasCopy(row) {
|
|
|
4423
5229
|
stringValue(data.subject) || stringValue(data.subject_line) || stringValue(data.subjectLine) || stringValue(data.opener) || stringValue(data.body) || stringValue(data.cta) || stringValue(copy.subject) || stringValue(copy.body) || stringValue(rawCopy.subject) || stringValue(rawCopy.body)
|
|
4424
5230
|
);
|
|
4425
5231
|
}
|
|
5232
|
+
function campaignReviewDataEmail(data) {
|
|
5233
|
+
return stringValue(data.email) || stringValue(data.work_email) || stringValue(data.workEmail) || stringValue(asRecord(data.contact).email);
|
|
5234
|
+
}
|
|
5235
|
+
function campaignReviewDataDomain(data) {
|
|
5236
|
+
const domain = stringValue(data.company_domain) || stringValue(data.companyDomain) || stringValue(asRecord(data.company).domain);
|
|
5237
|
+
return domain?.toLowerCase();
|
|
5238
|
+
}
|
|
5239
|
+
function campaignReviewDataHasVerifiedEmail(data) {
|
|
5240
|
+
const status = String(data.email_status ?? data.emailStatus ?? asRecord(data.contact).email_status ?? "").toLowerCase();
|
|
5241
|
+
return data.email_verified === true || data.emailVerified === true || asRecord(data.contact).email_verified === true || ["valid", "validated", "verified"].includes(status);
|
|
5242
|
+
}
|
|
5243
|
+
function campaignReviewDataCopyParts(data) {
|
|
5244
|
+
const copy = asRecord(data.copy);
|
|
5245
|
+
const rawCopy = asRecord(data.raw_copy ?? data.rawCopy);
|
|
5246
|
+
return [
|
|
5247
|
+
stringValue(data.subject),
|
|
5248
|
+
stringValue(data.subject_line),
|
|
5249
|
+
stringValue(data.opener),
|
|
5250
|
+
stringValue(data.body),
|
|
5251
|
+
stringValue(data.cta),
|
|
5252
|
+
stringValue(copy.subject),
|
|
5253
|
+
stringValue(copy.opener),
|
|
5254
|
+
stringValue(copy.body),
|
|
5255
|
+
stringValue(copy.cta),
|
|
5256
|
+
stringValue(rawCopy.subject),
|
|
5257
|
+
stringValue(rawCopy.opener),
|
|
5258
|
+
stringValue(rawCopy.body),
|
|
5259
|
+
stringValue(rawCopy.cta)
|
|
5260
|
+
].filter((part) => Boolean(part));
|
|
5261
|
+
}
|
|
5262
|
+
function campaignReviewDataHasBadGreeting(data) {
|
|
5263
|
+
return campaignReviewDataCopyParts(data).some(
|
|
5264
|
+
(part) => /\bhi\s*(?:,|\{\{|\[)|\bhello\s*(?:,|\{\{|\[)/i.test(part) || /\b(first_name|firstname|name)\b/i.test(part)
|
|
5265
|
+
);
|
|
5266
|
+
}
|
|
5267
|
+
function campaignReviewDataHasBannedPhrase(data) {
|
|
5268
|
+
const text = campaignReviewDataCopyParts(data).join(" ").toLowerCase();
|
|
5269
|
+
return NORTH_STAR_BANNED_COPY_PHRASES.some((phrase) => text.includes(phrase));
|
|
5270
|
+
}
|
|
5271
|
+
function campaignReviewDataSubject(data) {
|
|
5272
|
+
const copy = asRecord(data.copy);
|
|
5273
|
+
const rawCopy = asRecord(data.raw_copy ?? data.rawCopy);
|
|
5274
|
+
return stringValue(data.subject) || stringValue(data.subject_line) || stringValue(data.subjectLine) || stringValue(copy.subject) || stringValue(rawCopy.subject);
|
|
5275
|
+
}
|
|
5276
|
+
function campaignReviewDataCta(data) {
|
|
5277
|
+
const copy = asRecord(data.copy);
|
|
5278
|
+
const rawCopy = asRecord(data.raw_copy ?? data.rawCopy);
|
|
5279
|
+
return stringValue(data.cta) || stringValue(copy.cta) || stringValue(rawCopy.cta);
|
|
5280
|
+
}
|
|
5281
|
+
function countCampaignReviewIssues(issueRows) {
|
|
5282
|
+
return issueRows.flat().reduce((acc, issue) => {
|
|
5283
|
+
acc[issue] = (acc[issue] || 0) + 1;
|
|
5284
|
+
return acc;
|
|
5285
|
+
}, {});
|
|
5286
|
+
}
|
|
5287
|
+
function formatCampaignReviewIssueCounts(counts) {
|
|
5288
|
+
const entries = Object.entries(counts);
|
|
5289
|
+
return entries.length > 0 ? entries.map(([issue, count]) => `${issue}=${count}`).join(", ") : "none";
|
|
5290
|
+
}
|
|
5291
|
+
function campaignReviewDataCopyQaIssues(data) {
|
|
5292
|
+
const issues = /* @__PURE__ */ new Set();
|
|
5293
|
+
const copyParts = campaignReviewDataCopyParts(data);
|
|
5294
|
+
if (copyParts.length === 0) return [];
|
|
5295
|
+
if (campaignReviewDataHasBadGreeting(data)) issues.add("bad_greeting");
|
|
5296
|
+
if (campaignReviewDataHasBannedPhrase(data)) issues.add("banned_or_vague_phrase");
|
|
5297
|
+
if (campaignReviewDataHasUnsupportedSignalClaim(data)) issues.add("unsupported_signal_claim");
|
|
5298
|
+
if (campaignReviewDataPersonalizationBasis(data).length === 0) issues.add("missing_personalization_basis");
|
|
5299
|
+
if (!campaignReviewDataCta(data)) issues.add("missing_cta");
|
|
5300
|
+
const subject = campaignReviewDataSubject(data);
|
|
5301
|
+
if (subject && subject.length > 70) issues.add("overlong_subject");
|
|
5302
|
+
return [...issues];
|
|
5303
|
+
}
|
|
5304
|
+
function campaignReviewDataPersonalizationBasis(data) {
|
|
5305
|
+
const rawCopy = asRecord(data.raw_copy ?? data.rawCopy);
|
|
5306
|
+
const copy = asRecord(data.copy);
|
|
5307
|
+
const metadata = asRecord(data.metadata);
|
|
5308
|
+
const signalEvidence = asRecord(data.signal_evidence ?? metadata.signal_evidence ?? metadata.signalEvidence);
|
|
5309
|
+
return [
|
|
5310
|
+
...arrayOfStrings(data.personalization_basis) ?? [],
|
|
5311
|
+
...arrayOfStrings(data.personalizationBasis) ?? [],
|
|
5312
|
+
...arrayOfStrings(copy.personalization_basis) ?? [],
|
|
5313
|
+
...arrayOfStrings(rawCopy.personalization_basis) ?? [],
|
|
5314
|
+
...arrayOfStrings(metadata.personalization_basis) ?? [],
|
|
5315
|
+
...arrayOfStrings(metadata.personalizationBasis) ?? [],
|
|
5316
|
+
...arrayOfStrings(signalEvidence.personalization_basis) ?? []
|
|
5317
|
+
];
|
|
5318
|
+
}
|
|
5319
|
+
function campaignReviewDataHasNoSupportedSignal(data) {
|
|
5320
|
+
const metadata = asRecord(data.metadata);
|
|
5321
|
+
const copy = asRecord(data.copy);
|
|
5322
|
+
const state = [
|
|
5323
|
+
data.copy_signal_state,
|
|
5324
|
+
data.signal_basis,
|
|
5325
|
+
data.signal_type,
|
|
5326
|
+
metadata.copy_signal_state,
|
|
5327
|
+
metadata.signal_basis,
|
|
5328
|
+
metadata.signal_type,
|
|
5329
|
+
copy.copy_signal_state
|
|
5330
|
+
].map((value) => stringValue(value)?.toLowerCase()).filter(Boolean);
|
|
5331
|
+
return data.no_supported_signal === true || metadata.no_supported_signal === true || state.includes("no_supported_signal");
|
|
5332
|
+
}
|
|
5333
|
+
function campaignReviewDataHasSignalBasis(data) {
|
|
5334
|
+
if (campaignReviewDataHasNoSupportedSignal(data)) return false;
|
|
5335
|
+
const metadata = asRecord(data.metadata);
|
|
5336
|
+
const signal = asRecord(data.signal);
|
|
5337
|
+
const signalEvidence = asRecord(data.signal_evidence ?? metadata.signal_evidence ?? metadata.signalEvidence);
|
|
5338
|
+
const basis = campaignReviewDataPersonalizationBasis(data);
|
|
5339
|
+
return Boolean(
|
|
5340
|
+
stringValue(data.signal_type) || stringValue(data.signalType) || stringValue(data.signal_summary) || stringValue(data.signalSummary) || stringValue(data.signal_source_url) || stringValue(data.signalSourceUrl) || stringValue(metadata.signal_type) || stringValue(metadata.signal_summary) || stringValue(metadata.signal_source_url) || stringValue(signal.type) || stringValue(signal.summary) || stringValue(signal.source_url) || stringValue(signalEvidence.signal_type) || stringValue(signalEvidence.summary) || stringValue(signalEvidence.source_url) || basis.some((item) => /\bsignal|hiring|funding|leadership|growth|launch|news|technology\b/i.test(item))
|
|
5341
|
+
);
|
|
5342
|
+
}
|
|
5343
|
+
function campaignReviewDataHasUnsupportedSignalClaim(data) {
|
|
5344
|
+
const copyText = campaignReviewDataCopyParts(data).join(" ").toLowerCase();
|
|
5345
|
+
const claimsSignal = /\b(hiring|funding|raised|launched|expanding|appointed|announced|recent news|new role|job posting)\b/.test(copyText);
|
|
5346
|
+
return claimsSignal && !campaignReviewDataHasSignalBasis(data);
|
|
5347
|
+
}
|
|
5348
|
+
function campaignReviewDataHasApprovalLock(data) {
|
|
5349
|
+
const metadata = asRecord(data.fit_metadata ?? data.metadata);
|
|
5350
|
+
const approval = String(data.approval_status ?? data.delivery_approval_status ?? metadata.approval_status ?? "").toLowerCase();
|
|
5351
|
+
const exportStatus = String(data.export_status ?? data.exportStatus ?? "").toLowerCase();
|
|
5352
|
+
return data.export_ready === false || data.exportReady === false || data.delivery_approved === false || data.deliveryApproved === false || ["pending", "pending_approval", "blocked", "approval_required", "held"].includes(approval) || ["pending", "blocked", "approval_required", "held"].includes(exportStatus);
|
|
5353
|
+
}
|
|
5354
|
+
function campaignReviewDataHasHoldoutAttribution(data) {
|
|
5355
|
+
const fitMetadata = asRecord(data.fit_metadata ?? data.fitMetadata);
|
|
5356
|
+
const metadata = asRecord(data.metadata);
|
|
5357
|
+
const holdout = asRecord(
|
|
5358
|
+
fitMetadata.learning_holdout ?? fitMetadata.learningHoldout ?? metadata.learning_holdout ?? metadata.learningHoldout ?? data.learning_holdout ?? data.learningHoldout
|
|
5359
|
+
);
|
|
5360
|
+
const experimentKey = stringValue(holdout.experiment_key ?? holdout.experimentKey ?? data.experiment_key ?? data.experimentKey);
|
|
5361
|
+
const cohort = stringValue(holdout.cohort_role ?? holdout.cohortRole ?? data.cohort_role ?? data.learning_cohort ?? data.learningCohort);
|
|
5362
|
+
const brainApplied = holdout.brain_applied ?? holdout.brainApplied ?? data.brain_applied ?? data.signaliz_brain_applied;
|
|
5363
|
+
return Boolean(experimentKey && cohort && brainApplied !== void 0);
|
|
5364
|
+
}
|
|
5365
|
+
function campaignReviewStatusHasFeedbackReadiness(status) {
|
|
5366
|
+
const diagnostics = asRecord(status.diagnostics);
|
|
5367
|
+
const feedbackReadiness = asRecord(diagnostics.feedback_readiness ?? diagnostics.feedbackReadiness);
|
|
5368
|
+
const feedbackSubstrate = asRecord(diagnostics.feedback_substrate ?? diagnostics.feedbackSubstrate);
|
|
5369
|
+
const evidenceCounts = asRecord(diagnostics.evidence_counts ?? diagnostics.evidenceCounts);
|
|
5370
|
+
return feedbackReadiness.ready === true || feedbackReadiness.webhook_configured === true || feedbackSubstrate.stage === "ready" || Number(evidenceCounts.feedback_events ?? 0) > 0;
|
|
5371
|
+
}
|
|
5372
|
+
function campaignReviewMoatState(status, holdoutRows) {
|
|
5373
|
+
const diagnostics = asRecord(status.diagnostics);
|
|
5374
|
+
const evidenceCounts = asRecord(diagnostics.evidence_counts ?? diagnostics.evidenceCounts);
|
|
5375
|
+
const embeddedHoldout = asRecord(diagnostics.embedded_holdout ?? diagnostics.embeddedHoldout);
|
|
5376
|
+
const holdoutLift = asRecord(diagnostics.holdout_lift ?? diagnostics.holdoutLift ?? diagnostics.holdout_measurement ?? diagnostics.holdoutMeasurement);
|
|
5377
|
+
const controlSample = Math.max(
|
|
5378
|
+
Number(evidenceCounts.holdout_control_sample_size ?? 0),
|
|
5379
|
+
Number(evidenceCounts.embedded_holdout_control_sample ?? 0),
|
|
5380
|
+
Number(embeddedHoldout.control_sample_size ?? 0)
|
|
5381
|
+
);
|
|
5382
|
+
const learnedSample = Math.max(
|
|
5383
|
+
Number(evidenceCounts.holdout_learned_sample_size ?? 0),
|
|
5384
|
+
Number(evidenceCounts.embedded_holdout_learned_sample ?? 0),
|
|
5385
|
+
Number(embeddedHoldout.learned_sample_size ?? 0)
|
|
5386
|
+
);
|
|
5387
|
+
const feedbackEvents = Math.max(
|
|
5388
|
+
Number(evidenceCounts.feedback_events ?? 0),
|
|
5389
|
+
Number(evidenceCounts.campaign_build_feedback_events ?? 0),
|
|
5390
|
+
Number(evidenceCounts.delivery_holdout_sent_outcomes ?? 0)
|
|
5391
|
+
);
|
|
5392
|
+
const proved = diagnostics.closed_loop_proof_ready === true || holdoutLift.honest_measurement === true && holdoutLift.positive_lift === true;
|
|
5393
|
+
if (proved) {
|
|
5394
|
+
return {
|
|
5395
|
+
state: "proved",
|
|
5396
|
+
detail: "Real attributed feedback shows positive lift for explicit control and learned cohorts."
|
|
5397
|
+
};
|
|
5398
|
+
}
|
|
5399
|
+
if (controlSample > 0 && learnedSample > 0 && feedbackEvents > 0) {
|
|
5400
|
+
return {
|
|
5401
|
+
state: "moved_needs_lift_volume",
|
|
5402
|
+
detail: `Control and learned cohorts have attributed feedback (${controlSample} control, ${learnedSample} learned, ${feedbackEvents} feedback event(s)); keep collecting lift volume before claiming proof.`
|
|
5403
|
+
};
|
|
5404
|
+
}
|
|
5405
|
+
return {
|
|
5406
|
+
state: "scaffolding_ready",
|
|
5407
|
+
detail: holdoutRows > 0 ? `${holdoutRows} sampled row(s) carry holdout attribution, but real control/learned feedback lift is not proved yet.` : "Holdout and feedback scaffolding may be ready, but no real control/learned feedback lift is proved yet."
|
|
5408
|
+
};
|
|
5409
|
+
}
|
|
4426
5410
|
function createCampaignBuilderReadinessLane(route, plan) {
|
|
4427
5411
|
const builtIn = campaignBuilderBuiltInForRoute(route);
|
|
4428
5412
|
const customRoute = route.provider !== "signaliz" && route.provider !== "csv" && builtIn === void 0;
|
|
@@ -4456,6 +5440,342 @@ function createCampaignBuilderReadinessLane(route, plan) {
|
|
|
4456
5440
|
nextAction: customRoute ? `Review ${route.provider} route setup before launch approval.` : void 0
|
|
4457
5441
|
};
|
|
4458
5442
|
}
|
|
5443
|
+
function createCampaignBuilderApprovalPacket(plan, approval, missingTypes) {
|
|
5444
|
+
const requestedTypes = plan ? uniqueStrings(plan.approvals.filter((item) => item.blocking).map((item) => item.type)) : [];
|
|
5445
|
+
const approvalMatchesPlan = Boolean(plan && approval?.planId === plan.planId);
|
|
5446
|
+
const approvedTypes = approvalMatchesPlan ? approval?.approvedTypes ?? [] : [];
|
|
5447
|
+
const approvedRoutes = approvalMatchesPlan ? approval?.approvedRouteIds ?? [] : [];
|
|
5448
|
+
const missingIds = new Set(
|
|
5449
|
+
plan && approvalMatchesPlan && approval ? getMissingCampaignBuilderApprovals(plan, approval).map((item) => item.id) : plan?.approvals.filter((item) => item.blocking).map((item) => item.id) ?? []
|
|
5450
|
+
);
|
|
5451
|
+
const routeIdsRequired = plan ? uniqueStrings(plan.approvals.map((item) => item.routeId).filter((id) => Boolean(id))) : [];
|
|
5452
|
+
const spendLimitRequired = plan ? Math.max(0, ...plan.approvals.filter((item) => item.type === "spend" && item.blocking).map((item) => item.estimatedCredits ?? plan.estimatedCredits)) : 0;
|
|
5453
|
+
const normalizedSpendLimit = spendLimitRequired > 0 ? spendLimitRequired : null;
|
|
5454
|
+
const approvalState = !plan ? "unscoped" : missingTypes.length > 0 ? "requires_approval" : "approved";
|
|
5455
|
+
const approvalInput = {
|
|
5456
|
+
approved_by: approval?.approvedBy ?? null,
|
|
5457
|
+
approved_at: approval?.approvedAt ?? null,
|
|
5458
|
+
approved_types: approvedTypes,
|
|
5459
|
+
approved_route_ids: approvedRoutes,
|
|
5460
|
+
spend_limit_credits: approval?.spendLimitCredits ?? null,
|
|
5461
|
+
notes: approval?.notes
|
|
5462
|
+
};
|
|
5463
|
+
return {
|
|
5464
|
+
packet_version: "campaign-builder-approval-packet.v1",
|
|
5465
|
+
read_only: true,
|
|
5466
|
+
no_spend: true,
|
|
5467
|
+
no_provider_writes: true,
|
|
5468
|
+
private_safe: true,
|
|
5469
|
+
approval_state: approvalState,
|
|
5470
|
+
plan_id: plan?.planId ?? null,
|
|
5471
|
+
campaign_name: plan?.campaignName ?? null,
|
|
5472
|
+
requested_approval_types: requestedTypes,
|
|
5473
|
+
missing_approval_types: uniqueStrings(missingTypes),
|
|
5474
|
+
spend_limit_credits_required: normalizedSpendLimit,
|
|
5475
|
+
route_ids_required: routeIdsRequired,
|
|
5476
|
+
required_approvals: (plan?.approvals ?? []).map((item) => compact({
|
|
5477
|
+
id: item.id,
|
|
5478
|
+
type: item.type,
|
|
5479
|
+
label: item.label,
|
|
5480
|
+
reason: item.reason,
|
|
5481
|
+
blocking: item.blocking,
|
|
5482
|
+
route_id: item.routeId,
|
|
5483
|
+
provider: item.provider,
|
|
5484
|
+
estimated_credits: item.estimatedCredits,
|
|
5485
|
+
status: missingIds.has(item.id) ? "missing" : "approved"
|
|
5486
|
+
})),
|
|
5487
|
+
approval_input: approvalInput,
|
|
5488
|
+
cli_handoff: plan ? {
|
|
5489
|
+
command: campaignBuilderApprovalCliHandoff(requestedTypes, routeIdsRequired, normalizedSpendLimit),
|
|
5490
|
+
safety: "Template only: run after explicit human approval identity, approved types, route scope, and spend limit are filled in."
|
|
5491
|
+
} : null,
|
|
5492
|
+
sdk_handoff: plan ? {
|
|
5493
|
+
method: "campaignBuilderAgent.buildApprovedPlan",
|
|
5494
|
+
approval: compact({
|
|
5495
|
+
approvedBy: approval?.approvedBy ?? "<operator-email>",
|
|
5496
|
+
approvedTypes: requestedTypes,
|
|
5497
|
+
approvedRouteIds: routeIdsRequired,
|
|
5498
|
+
spendLimitCredits: normalizedSpendLimit ?? void 0,
|
|
5499
|
+
notes: approval?.notes
|
|
5500
|
+
}),
|
|
5501
|
+
options: {
|
|
5502
|
+
idempotencyKey: "<set-before-execution>"
|
|
5503
|
+
},
|
|
5504
|
+
safety: "Call only after the approval packet is accepted; this helper does not execute writes or spend."
|
|
5505
|
+
} : null,
|
|
5506
|
+
mcp_handoffs: plan ? campaignBuilderApprovalMcpHandoffs(plan, requestedTypes, routeIdsRequired, normalizedSpendLimit) : [],
|
|
5507
|
+
safety_boundary: "This approval packet is a reusable request for human approval; it is not an approval grant and it does not authorize spend, provider writes, sender loading, delivery, or launch by itself."
|
|
5508
|
+
};
|
|
5509
|
+
}
|
|
5510
|
+
function campaignBuilderApprovalCliHandoff(requestedTypes, routeIds, spendLimit) {
|
|
5511
|
+
return [
|
|
5512
|
+
"signaliz campaign-agent build-approved --request-file campaign-request.json --confirm-launch",
|
|
5513
|
+
requestedTypes.length > 0 ? `--approved-types ${shellArg(requestedTypes.join(","))}` : "--approve-all",
|
|
5514
|
+
"--approved-by <operator-email>",
|
|
5515
|
+
spendLimit !== null ? `--spend-limit ${spendLimit}` : void 0,
|
|
5516
|
+
routeIds.length > 0 ? `--approved-route-ids ${shellArg(routeIds.join(","))}` : void 0
|
|
5517
|
+
].filter(Boolean).join(" ");
|
|
5518
|
+
}
|
|
5519
|
+
function campaignBuilderApprovalMcpHandoffs(plan, requestedTypes, routeIds, spendLimit) {
|
|
5520
|
+
const approvalContext = compact({
|
|
5521
|
+
plan_id: plan.planId,
|
|
5522
|
+
approval_types: requestedTypes,
|
|
5523
|
+
approved_route_ids: routeIds,
|
|
5524
|
+
spend_limit_credits: spendLimit,
|
|
5525
|
+
approved_by: "<operator-email>"
|
|
5526
|
+
});
|
|
5527
|
+
return plan.mcpFlow.filter((step) => ["execution-prepare", "approved-build", "delivery-approval"].includes(step.id)).map((step) => ({
|
|
5528
|
+
id: step.id,
|
|
5529
|
+
tool: step.tool,
|
|
5530
|
+
arguments: step.id === "approved-build" ? compact({ ...step.arguments, approval_context: approvalContext }) : step.arguments,
|
|
5531
|
+
read_only: step.readOnly,
|
|
5532
|
+
approval_required: step.approvalRequired,
|
|
5533
|
+
safety: step.readOnly ? "Read-only readiness handoff; safe to inspect before approval." : "Write-capable handoff; run only after the approval packet is accepted."
|
|
5534
|
+
}));
|
|
5535
|
+
}
|
|
5536
|
+
function campaignBuilderActiveWorkNextMcpAction(input) {
|
|
5537
|
+
const campaignBuildRef = input.refs.find((ref) => ref.kind === "campaign_build" && ref.id);
|
|
5538
|
+
if (campaignBuildRef) {
|
|
5539
|
+
return {
|
|
5540
|
+
id: "check-campaign-build-status",
|
|
5541
|
+
tool: "get_campaign_build_status",
|
|
5542
|
+
arguments: { campaign_build_id: campaignBuildRef.id },
|
|
5543
|
+
read_only: true,
|
|
5544
|
+
approval_required: false,
|
|
5545
|
+
safety: "Read-only status check for the remembered campaign build; does not spend, write, export, send, or approve anything."
|
|
5546
|
+
};
|
|
5547
|
+
}
|
|
5548
|
+
const campaignRef = input.refs.find((ref) => ref.kind === "gtm_campaign" && ref.id);
|
|
5549
|
+
if (campaignRef) {
|
|
5550
|
+
return {
|
|
5551
|
+
id: "check-gtm-campaign-status",
|
|
5552
|
+
tool: "gtm_campaign_execution_status",
|
|
5553
|
+
arguments: { campaign_id: campaignRef.id },
|
|
5554
|
+
read_only: true,
|
|
5555
|
+
approval_required: false,
|
|
5556
|
+
safety: "Read-only campaign execution status check; does not start or mutate the campaign."
|
|
5557
|
+
};
|
|
5558
|
+
}
|
|
5559
|
+
const preferredStepId = input.state === "ready_for_dry_run" ? "dry-run-build" : input.state === "planning" || input.state === "blocked" ? "agency-campaign-build-plan" : null;
|
|
5560
|
+
const preferredStep = preferredStepId ? input.plan?.mcpFlow.find((step) => step.id === preferredStepId && step.readOnly) : void 0;
|
|
5561
|
+
if (preferredStep) return campaignBuilderMcpStepToActiveWorkAction(preferredStep, "Read-only continuation from the saved campaign-agent plan.");
|
|
5562
|
+
const readOnlyApprovalHandoff = input.approvalPacket.mcp_handoffs.find((handoff) => handoff.read_only && !handoff.approval_required);
|
|
5563
|
+
if (readOnlyApprovalHandoff) return readOnlyApprovalHandoff;
|
|
5564
|
+
const firstReadOnlyPlanStep = input.plan?.mcpFlow.find((step) => step.readOnly && !step.approvalRequired);
|
|
5565
|
+
return firstReadOnlyPlanStep ? campaignBuilderMcpStepToActiveWorkAction(firstReadOnlyPlanStep, "Read-only saved plan check; safe before approvals or writes.") : null;
|
|
5566
|
+
}
|
|
5567
|
+
function campaignBuilderMcpStepToActiveWorkAction(step, safety) {
|
|
5568
|
+
return {
|
|
5569
|
+
id: step.id,
|
|
5570
|
+
tool: step.tool,
|
|
5571
|
+
arguments: step.arguments,
|
|
5572
|
+
read_only: step.readOnly,
|
|
5573
|
+
approval_required: step.approvalRequired,
|
|
5574
|
+
safety
|
|
5575
|
+
};
|
|
5576
|
+
}
|
|
5577
|
+
function normalizeCampaignBuilderActiveWorkRefs(input) {
|
|
5578
|
+
const refs = [];
|
|
5579
|
+
const pushRef = (ref) => {
|
|
5580
|
+
if (!ref?.id) return;
|
|
5581
|
+
refs.push(ref);
|
|
5582
|
+
};
|
|
5583
|
+
pushRef(input.plan?.planId ? { kind: "plan", id: input.plan.planId, label: input.plan.campaignName, source: "plan" } : void 0);
|
|
5584
|
+
pushRef(input.remembered.planId ? { kind: "plan", id: input.remembered.planId, source: "remembered" } : void 0);
|
|
5585
|
+
pushRef(
|
|
5586
|
+
input.plan?.buildRequest.gtmCampaignId ?? input.remembered.gtmCampaignId ? {
|
|
5587
|
+
kind: "gtm_campaign",
|
|
5588
|
+
id: input.plan?.buildRequest.gtmCampaignId ?? input.remembered.gtmCampaignId,
|
|
5589
|
+
label: input.plan?.campaignName,
|
|
5590
|
+
source: input.plan?.buildRequest.gtmCampaignId ? "plan" : "remembered"
|
|
5591
|
+
} : void 0
|
|
5592
|
+
);
|
|
5593
|
+
const campaignBuildId = stringValue(input.lastResult.campaign_build_id ?? input.lastResult.campaignBuildId) ?? input.remembered.campaignBuildId;
|
|
5594
|
+
pushRef(campaignBuildId ? { kind: "campaign_build", id: campaignBuildId, status: activeWorkStatus(input.lastResult) ?? input.remembered.status, source: "result" } : void 0);
|
|
5595
|
+
pushRef(
|
|
5596
|
+
input.remembered.providerCampaignId ? {
|
|
5597
|
+
kind: "provider_campaign",
|
|
5598
|
+
id: input.remembered.providerCampaignId,
|
|
5599
|
+
label: input.remembered.provider,
|
|
5600
|
+
status: input.remembered.status,
|
|
5601
|
+
source: "remembered"
|
|
5602
|
+
} : void 0
|
|
5603
|
+
);
|
|
5604
|
+
for (const ref of input.remembered.refs ?? []) pushRef(ref);
|
|
5605
|
+
for (const ref of input.refs ?? []) pushRef(ref);
|
|
5606
|
+
const seen = /* @__PURE__ */ new Set();
|
|
5607
|
+
return refs.filter((ref) => {
|
|
5608
|
+
const key = `${ref.kind}:${ref.id}`;
|
|
5609
|
+
if (seen.has(key)) return false;
|
|
5610
|
+
seen.add(key);
|
|
5611
|
+
return true;
|
|
5612
|
+
});
|
|
5613
|
+
}
|
|
5614
|
+
function inferCampaignBuilderActiveWorkState(input) {
|
|
5615
|
+
if (input.blockers.length > 0) return "blocked";
|
|
5616
|
+
const status = activeWorkStatus(input.lastResult) ?? input.remembered.status;
|
|
5617
|
+
const normalized = status?.toLowerCase();
|
|
5618
|
+
if (normalized && ["completed", "complete", "succeeded", "success", "done"].includes(normalized)) return "completed";
|
|
5619
|
+
if (normalized && ["queued", "running", "in_progress", "processing", "pending"].includes(normalized)) return "queued_or_running";
|
|
5620
|
+
const dryRunComplete = input.lastResult.dry_run === true || input.lastResult.dryRun === true || normalized === "dry_run";
|
|
5621
|
+
if (dryRunComplete) return input.missingApprovals.length > 0 ? "needs_approval" : "dry_run_complete";
|
|
5622
|
+
if (input.missingApprovals.length > 0) return "needs_approval";
|
|
5623
|
+
if (input.readiness?.summary.ready === true) return "ready_for_dry_run";
|
|
5624
|
+
if (input.plan) return "planning";
|
|
5625
|
+
return "unknown";
|
|
5626
|
+
}
|
|
5627
|
+
function campaignBuilderActiveWorkApprovalBoundary(missingApprovals, state) {
|
|
5628
|
+
if (missingApprovals.length > 0) {
|
|
5629
|
+
return `Blocked before spend, provider writes, delivery, or launch until approval covers: ${uniqueStrings(missingApprovals).join(", ")}.`;
|
|
5630
|
+
}
|
|
5631
|
+
if (state === "dry_run_complete" || state === "ready_for_dry_run") {
|
|
5632
|
+
return "Read-only planning and dry-runs are allowed; spend, provider writes, sender loading, delivery, and launch still require explicit approval.";
|
|
5633
|
+
}
|
|
5634
|
+
return "This packet is read-only and does not authorize spend, provider writes, sender loading, delivery, or launch.";
|
|
5635
|
+
}
|
|
5636
|
+
function campaignBuilderActiveWorkNextAction(state, blockers, missingApprovals, refs) {
|
|
5637
|
+
if (blockers.length > 0) return `Resolve blocker: ${blockers[0]}`;
|
|
5638
|
+
if (missingApprovals.length > 0) return `Ask the operator to approve ${uniqueStrings(missingApprovals).join(", ")} before any write or spend action.`;
|
|
5639
|
+
if (state === "ready_for_dry_run") return "Run or inspect the read-only campaign dry-run, then return the receipt for approval review.";
|
|
5640
|
+
if (state === "dry_run_complete") return "Review the dry-run receipt and collect explicit launch or delivery approval before any write action.";
|
|
5641
|
+
if (state === "queued_or_running") return "Poll the remembered campaign build or provider job status; do not start a duplicate job.";
|
|
5642
|
+
if (state === "completed") return "Review final artifacts and delivery gates before export, sync, sender load, or launch.";
|
|
5643
|
+
if (refs.length > 0) return "Use the remembered refs to fetch current read-only status before asking the operator for IDs.";
|
|
5644
|
+
return "Create or refresh a campaign-builder plan before taking any spendful or write action.";
|
|
5645
|
+
}
|
|
5646
|
+
function campaignBuilderActiveWorkConversationStarters(input) {
|
|
5647
|
+
const starters = [];
|
|
5648
|
+
if (input.blockers.length > 0) {
|
|
5649
|
+
starters.push(
|
|
5650
|
+
`I found a blocker: ${input.blockers[0]}. Want me to stay in read-only diagnostics and prepare the fix path?`
|
|
5651
|
+
);
|
|
5652
|
+
}
|
|
5653
|
+
if (input.missingApprovals.length > 0) {
|
|
5654
|
+
starters.push(
|
|
5655
|
+
`You still owe approval for ${uniqueStrings(input.missingApprovals).join(", ")}. Want the exact approval packet before anything writes or spends?`
|
|
5656
|
+
);
|
|
5657
|
+
}
|
|
5658
|
+
if (input.state === "queued_or_running") {
|
|
5659
|
+
const buildRef = input.refs.find((ref) => ref.kind === "campaign_build");
|
|
5660
|
+
starters.push(buildRef ? `I can check campaign build ${buildRef.id} now and avoid starting a duplicate job.` : "I can check the running job status now and avoid starting duplicate work.");
|
|
5661
|
+
}
|
|
5662
|
+
if (input.state === "dry_run_complete") {
|
|
5663
|
+
starters.push("The dry run is complete. Want me to summarize blockers, artifacts, and the approval handoff?");
|
|
5664
|
+
}
|
|
5665
|
+
if (input.state === "ready_for_dry_run") {
|
|
5666
|
+
starters.push("Everything is ready for a safe dry run. Want me to run the no-spend preview first?");
|
|
5667
|
+
}
|
|
5668
|
+
if (input.state === "completed") {
|
|
5669
|
+
starters.push("The build looks complete. Want me to review rows, artifacts, and delivery gates before export or send approval?");
|
|
5670
|
+
}
|
|
5671
|
+
starters.push(`Next safe action: ${input.nextSafeAction}`);
|
|
5672
|
+
return uniqueStrings(starters).slice(0, 4);
|
|
5673
|
+
}
|
|
5674
|
+
function createCampaignBuilderOpenAiAgentHandoff(input) {
|
|
5675
|
+
const readOnlyPlanActions = input.plan?.mcpFlow.filter((step) => step.readOnly && !step.approvalRequired).map((step) => campaignBuilderMcpStepToActiveWorkAction(step, "Read-only Signaliz MCP continuation for the saved campaign-agent plan.")) ?? [];
|
|
5676
|
+
const routeSetupActions = readOnlyPlanActions.filter(
|
|
5677
|
+
(action) => action.tool === "gtm_provider_recipe_prepare" || action.tool === "gtm_provider_route_activate"
|
|
5678
|
+
);
|
|
5679
|
+
const safeReadActions = uniqueCampaignBuilderActiveWorkActions([
|
|
5680
|
+
input.nextSafeMcpAction,
|
|
5681
|
+
...routeSetupActions,
|
|
5682
|
+
...readOnlyPlanActions
|
|
5683
|
+
]);
|
|
5684
|
+
const approvalGatedActions = uniqueCampaignBuilderActiveWorkActions([
|
|
5685
|
+
...input.approvalPacket.mcp_handoffs.filter((action) => action.approval_required || !action.read_only),
|
|
5686
|
+
...input.plan?.mcpFlow.filter((step) => step.approvalRequired || !step.readOnly).map((step) => campaignBuilderMcpStepToActiveWorkAction(step, "Approval-gated Signaliz MCP continuation for the saved campaign-agent plan.")) ?? []
|
|
5687
|
+
]);
|
|
5688
|
+
const approvalTypes = uniqueStrings([
|
|
5689
|
+
...input.missingApprovals,
|
|
5690
|
+
...input.approvalPacket.requested_approval_types
|
|
5691
|
+
]);
|
|
5692
|
+
return {
|
|
5693
|
+
packet_version: "campaign-builder-openai-agent-handoff.v1",
|
|
5694
|
+
surface: "openai_agents_sdk",
|
|
5695
|
+
agent: {
|
|
5696
|
+
name: "Signaliz GTM Campaign Agent",
|
|
5697
|
+
handoff_description: "Owns safe, conversational GTM campaign planning and continuation across Signaliz MCP, SDK, attachments, URLs, customer tools, approvals, and sender/export gates.",
|
|
5698
|
+
instructions: [
|
|
5699
|
+
"Be warm, direct, and expert-level GTM. Translate the current state into plain operator language before proposing work.",
|
|
5700
|
+
"Start from the packet state, refs, evidence_context, approval_boundary, and next_safe_action. Do not ask for IDs already present in refs or summary.",
|
|
5701
|
+
"Use attachment_summary, url_summary, and operator_notes as first-class planning evidence, while honoring the evidence privacy_boundary and withheld raw fields.",
|
|
5702
|
+
"Prefer Signaliz-native, cached, remembered, and read-only MCP actions before provider calls. Never start duplicate jobs when a campaign_build or provider job is queued or running.",
|
|
5703
|
+
"Call only tools listed in safe_read_tools without approval. Treat approval_gated_tools as human-review surfaces, not permission to spend, write, export, load senders, deliver, or launch.",
|
|
5704
|
+
"When approval is missing, show the approval_packet and the exact missing approval scope before any side-effecting step."
|
|
5705
|
+
],
|
|
5706
|
+
output_contract: [
|
|
5707
|
+
"current_state: one concise sentence describing where the campaign work stands.",
|
|
5708
|
+
"evidence_used: attachment, URL, memory, route, or integration evidence used without exposing private raw rows or secrets.",
|
|
5709
|
+
"next_safe_mcp_action: the read-only Signaliz MCP action to run next, or null when none is safe.",
|
|
5710
|
+
"approval_boundary: the human approval scope required before spend, provider writes, delivery, export, sender load, or launch.",
|
|
5711
|
+
"operator_reply: conversational GTM guidance with blockers, risks, and the safest next move."
|
|
5712
|
+
]
|
|
5713
|
+
},
|
|
5714
|
+
context: {
|
|
5715
|
+
state: input.state,
|
|
5716
|
+
summary: input.summary,
|
|
5717
|
+
refs: input.refs,
|
|
5718
|
+
blockers: input.blockers,
|
|
5719
|
+
warnings: input.warnings,
|
|
5720
|
+
evidence_context: input.plan?.evidence ?? null,
|
|
5721
|
+
approval_packet: input.approvalPacket,
|
|
5722
|
+
approval_boundary: input.approvalBoundary,
|
|
5723
|
+
next_safe_action: input.nextSafeAction,
|
|
5724
|
+
conversation_starters: input.conversationStarters
|
|
5725
|
+
},
|
|
5726
|
+
tools: {
|
|
5727
|
+
mcp_server_label: "signaliz",
|
|
5728
|
+
remote_mcp_compatible: true,
|
|
5729
|
+
next_safe_mcp_action: input.nextSafeMcpAction,
|
|
5730
|
+
safe_read_tools: safeReadActions.map(
|
|
5731
|
+
(action) => campaignBuilderOpenAiAgentTool(action, "Safe read-only Signaliz MCP action available before approval.")
|
|
5732
|
+
),
|
|
5733
|
+
approval_gated_tools: approvalGatedActions.map(
|
|
5734
|
+
(action) => campaignBuilderOpenAiAgentTool(action, "Requires explicit human review before execution.")
|
|
5735
|
+
)
|
|
5736
|
+
},
|
|
5737
|
+
guardrails: {
|
|
5738
|
+
input: [
|
|
5739
|
+
"Reject or pause requests to expose raw private attachment text, raw rows, leads, emails, provider payloads, copy bodies, API keys, or secrets.",
|
|
5740
|
+
"Pause when the user asks to spend credits, write to a provider, export, load a sender, deliver, or launch without explicit approval scope."
|
|
5741
|
+
],
|
|
5742
|
+
tool: [
|
|
5743
|
+
"Read-only tools may run when they match safe_read_tools and their arguments match this packet.",
|
|
5744
|
+
"Any tool with approval_required=true or read_only=false requires human review and the approval_packet scope first."
|
|
5745
|
+
],
|
|
5746
|
+
human_review_required_for: approvalTypes,
|
|
5747
|
+
privacy: input.plan?.evidence?.privacy_boundary ?? "Use summarized context only. Do not expose raw private attachment text, raw rows, leads, emails, provider payloads, copy bodies, secrets, or credentials."
|
|
5748
|
+
}
|
|
5749
|
+
};
|
|
5750
|
+
}
|
|
5751
|
+
function campaignBuilderOpenAiAgentTool(action, purpose) {
|
|
5752
|
+
return {
|
|
5753
|
+
id: action.id,
|
|
5754
|
+
type: "mcp",
|
|
5755
|
+
server_label: "signaliz",
|
|
5756
|
+
name: action.tool,
|
|
5757
|
+
arguments: action.arguments,
|
|
5758
|
+
read_only: action.read_only,
|
|
5759
|
+
approval_required: action.approval_required,
|
|
5760
|
+
purpose,
|
|
5761
|
+
safety: action.safety
|
|
5762
|
+
};
|
|
5763
|
+
}
|
|
5764
|
+
function uniqueCampaignBuilderActiveWorkActions(actions) {
|
|
5765
|
+
const seen = /* @__PURE__ */ new Set();
|
|
5766
|
+
const unique = [];
|
|
5767
|
+
for (const action of actions) {
|
|
5768
|
+
if (!action) continue;
|
|
5769
|
+
const key = `${action.id}:${action.tool}`;
|
|
5770
|
+
if (seen.has(key)) continue;
|
|
5771
|
+
seen.add(key);
|
|
5772
|
+
unique.push(action);
|
|
5773
|
+
}
|
|
5774
|
+
return unique;
|
|
5775
|
+
}
|
|
5776
|
+
function activeWorkStatus(record) {
|
|
5777
|
+
return stringValue(record.status ?? record.state ?? record.phase);
|
|
5778
|
+
}
|
|
4459
5779
|
function campaignBuilderBuiltInForRoute(route) {
|
|
4460
5780
|
return Object.entries(CAMPAIGN_BUILDER_BUILT_IN_ROUTE_IDS).find(([, routeId]) => route.id === routeId)?.[0];
|
|
4461
5781
|
}
|
|
@@ -7252,6 +8572,36 @@ function recordsFromParams(params) {
|
|
|
7252
8572
|
if (params.input) return { input: params.input };
|
|
7253
8573
|
return { input: {} };
|
|
7254
8574
|
}
|
|
8575
|
+
function toFusionConfig(params) {
|
|
8576
|
+
return {
|
|
8577
|
+
system_prompt: params.systemPrompt || params.system_prompt,
|
|
8578
|
+
user_template: params.userTemplate || params.user_template || params.prompt,
|
|
8579
|
+
preset: params.preset,
|
|
8580
|
+
temperature: params.temperature,
|
|
8581
|
+
max_tool_calls: params.maxToolCalls || params.max_tool_calls,
|
|
8582
|
+
max_tokens: params.maxTokens || params.max_tokens,
|
|
8583
|
+
timeout_ms: params.timeoutMs || params.timeout_ms,
|
|
8584
|
+
output_fields: params.outputFields || params.output_fields || [{ name: "response", type: "text", description: "Structured Fusion enrichment result" }]
|
|
8585
|
+
};
|
|
8586
|
+
}
|
|
8587
|
+
function toFusionSpendControls(params) {
|
|
8588
|
+
const controls = {};
|
|
8589
|
+
const dryRun = params.dryRun ?? params.dry_run;
|
|
8590
|
+
const confirmSpend = params.confirmSpend ?? params.confirm_spend;
|
|
8591
|
+
const maxCredits = params.maxCredits ?? params.max_credits;
|
|
8592
|
+
const maxCostUsd = params.maxCostUsd ?? params.max_cost_usd;
|
|
8593
|
+
if (dryRun !== void 0) controls.dry_run = dryRun;
|
|
8594
|
+
if (confirmSpend !== void 0) controls.confirm_spend = confirmSpend;
|
|
8595
|
+
if (maxCredits !== void 0) controls.max_credits = maxCredits;
|
|
8596
|
+
if (maxCostUsd !== void 0) controls.max_cost_usd = maxCostUsd;
|
|
8597
|
+
return controls;
|
|
8598
|
+
}
|
|
8599
|
+
function fusionRecordsFromParams(params) {
|
|
8600
|
+
const records = params.records || params.inputs;
|
|
8601
|
+
if (records?.length) return { records };
|
|
8602
|
+
if (params.input) return { input: params.input };
|
|
8603
|
+
return { input: {} };
|
|
8604
|
+
}
|
|
7255
8605
|
var Ai = class {
|
|
7256
8606
|
constructor(client) {
|
|
7257
8607
|
this.client = client;
|
|
@@ -7285,6 +8635,33 @@ var Ai = class {
|
|
|
7285
8635
|
raw: data
|
|
7286
8636
|
};
|
|
7287
8637
|
}
|
|
8638
|
+
/**
|
|
8639
|
+
* Plan or run experimental AI Enrichment Fusion with explicit spend controls.
|
|
8640
|
+
*/
|
|
8641
|
+
async fusion(params) {
|
|
8642
|
+
if (!params.prompt && !params.userTemplate && !params.user_template) {
|
|
8643
|
+
throw new Error("prompt or userTemplate is required.");
|
|
8644
|
+
}
|
|
8645
|
+
const data = await this.client.post("ai-enrichment-fusion", {
|
|
8646
|
+
...fusionRecordsFromParams(params),
|
|
8647
|
+
config: toFusionConfig(params),
|
|
8648
|
+
...toFusionSpendControls(params)
|
|
8649
|
+
});
|
|
8650
|
+
return {
|
|
8651
|
+
success: data.success ?? false,
|
|
8652
|
+
capability: data.capability ?? "ai_enrichment_fusion",
|
|
8653
|
+
displayName: data.display_name ?? "AI Enrichment Fusion",
|
|
8654
|
+
results: data.results ?? [],
|
|
8655
|
+
creditsUsed: data.total_credits_used ?? data.credits_used ?? 0,
|
|
8656
|
+
model: data.model,
|
|
8657
|
+
fusion: data.fusion,
|
|
8658
|
+
tokensUsed: data.tokens_used ?? 0,
|
|
8659
|
+
costUsd: data.cost_usd ?? 0,
|
|
8660
|
+
costSummary: data.cost_summary,
|
|
8661
|
+
billingMetadata: data.billing_metadata,
|
|
8662
|
+
raw: data
|
|
8663
|
+
};
|
|
8664
|
+
}
|
|
7288
8665
|
};
|
|
7289
8666
|
|
|
7290
8667
|
// src/resources/gtm-kernel.ts
|
|
@@ -7638,6 +9015,16 @@ var GtmKernel = class {
|
|
|
7638
9015
|
min_privacy_k: input.minPrivacyK
|
|
7639
9016
|
});
|
|
7640
9017
|
}
|
|
9018
|
+
/** Queue a dry-run-first bridge from imported historical feedback to attribution-only Campaign Build surrogates. */
|
|
9019
|
+
async runHistoricalCampaignBuildBridge(input = {}) {
|
|
9020
|
+
return this.callMcp("gtm_historical_campaign_build_bridge_run", {
|
|
9021
|
+
dry_run: input.dryRun,
|
|
9022
|
+
write_approved: input.writeApproved,
|
|
9023
|
+
max_events: input.maxEvents,
|
|
9024
|
+
max_campaigns: input.maxCampaigns,
|
|
9025
|
+
min_feedback_events: input.minFeedbackEvents
|
|
9026
|
+
});
|
|
9027
|
+
}
|
|
7641
9028
|
/** Prepare a provider-agnostic feedback webhook URL for Smartlead, HeyReach, Airbyte, or custom sender events. */
|
|
7642
9029
|
async prepareFeedbackWebhook(input) {
|
|
7643
9030
|
return this.callMcp("gtm_feedback_webhook_prepare", {
|
|
@@ -7814,6 +9201,24 @@ var GtmKernel = class {
|
|
|
7814
9201
|
limit: input.limit
|
|
7815
9202
|
});
|
|
7816
9203
|
}
|
|
9204
|
+
/** Predict booked-meeting likelihood for uploaded, inline, or MCP-sourced lead rows without persisting raw rows. */
|
|
9205
|
+
async predictMeetingLikelihood(input) {
|
|
9206
|
+
return this.callMcp("gtm_predict_meeting_likelihood", {
|
|
9207
|
+
lead_rows: input.leadRows,
|
|
9208
|
+
input_source: input.inputSource,
|
|
9209
|
+
campaign_id: input.campaignId,
|
|
9210
|
+
campaign_build_id: input.campaignBuildId,
|
|
9211
|
+
days: input.days,
|
|
9212
|
+
feedback_limit: input.feedbackLimit,
|
|
9213
|
+
include_features: input.includeFeatures,
|
|
9214
|
+
include_global: input.includeGlobal,
|
|
9215
|
+
min_feedback_events: input.minFeedbackEvents,
|
|
9216
|
+
min_historical_feature_sample_size: input.minHistoricalFeatureSampleSize,
|
|
9217
|
+
min_workspace_count: input.minWorkspaceCount,
|
|
9218
|
+
min_privacy_k: input.minPrivacyK,
|
|
9219
|
+
limit: input.limit
|
|
9220
|
+
});
|
|
9221
|
+
}
|
|
7817
9222
|
/** Rank provider-chain, ICP, source, copy, and sequence failure patterns without writing raw lead data. */
|
|
7818
9223
|
async failurePatterns(options = {}) {
|
|
7819
9224
|
return this.callMcp("gtm_brain_failure_patterns", {
|
|
@@ -8429,6 +9834,70 @@ function compact2(value) {
|
|
|
8429
9834
|
return out;
|
|
8430
9835
|
}
|
|
8431
9836
|
|
|
9837
|
+
// src/resources/public-ground-truth.ts
|
|
9838
|
+
var PublicGroundTruth = class {
|
|
9839
|
+
constructor(client) {
|
|
9840
|
+
this.client = client;
|
|
9841
|
+
}
|
|
9842
|
+
/**
|
|
9843
|
+
* Search the public-ground-truth cache by company/name/domain/native ID,
|
|
9844
|
+
* or by plain-language industry + location.
|
|
9845
|
+
* Results use the same snake_case wire shape returned by the hosted MCP API.
|
|
9846
|
+
*/
|
|
9847
|
+
async search(params) {
|
|
9848
|
+
return this.client.mcp("tools/call", {
|
|
9849
|
+
name: "search_public_ground_truth",
|
|
9850
|
+
arguments: {
|
|
9851
|
+
query: params.query ?? params.search,
|
|
9852
|
+
industry: params.industry,
|
|
9853
|
+
location: params.location,
|
|
9854
|
+
source_id: params.sourceId ?? params.source_id,
|
|
9855
|
+
entity_type: params.entityType ?? params.entity_type,
|
|
9856
|
+
native_id: params.nativeId ?? params.native_id,
|
|
9857
|
+
entity_name: params.entityName ?? params.entity_name,
|
|
9858
|
+
domain: params.domain,
|
|
9859
|
+
website_url: params.websiteUrl ?? params.website_url,
|
|
9860
|
+
phone: params.phone,
|
|
9861
|
+
email: params.email,
|
|
9862
|
+
city: params.city,
|
|
9863
|
+
state: params.state,
|
|
9864
|
+
postal_code: params.postalCode ?? params.postal_code,
|
|
9865
|
+
country: params.country,
|
|
9866
|
+
source_url: params.sourceUrl ?? params.source_url,
|
|
9867
|
+
join_keys: params.joinKeys ?? params.join_keys,
|
|
9868
|
+
row_data: params.rowData ?? params.row_data,
|
|
9869
|
+
naics: params.naics,
|
|
9870
|
+
industry_code: params.industryCode ?? params.industry_code,
|
|
9871
|
+
industry_type: params.industryType ?? params.industry_type,
|
|
9872
|
+
year: params.year,
|
|
9873
|
+
quarter: params.quarter,
|
|
9874
|
+
area_fips: params.areaFips ?? params.area_fips,
|
|
9875
|
+
geo_id: params.geoId ?? params.geo_id,
|
|
9876
|
+
own_code: params.ownCode ?? params.own_code,
|
|
9877
|
+
source_updated_after: params.sourceUpdatedAfter ?? params.source_updated_after,
|
|
9878
|
+
source_updated_before: params.sourceUpdatedBefore ?? params.source_updated_before,
|
|
9879
|
+
observed_after: params.observedAfter ?? params.observed_after,
|
|
9880
|
+
observed_before: params.observedBefore ?? params.observed_before,
|
|
9881
|
+
limit: params.limit,
|
|
9882
|
+
offset: params.offset
|
|
9883
|
+
}
|
|
9884
|
+
});
|
|
9885
|
+
}
|
|
9886
|
+
/**
|
|
9887
|
+
* List available public-ground-truth cache sources and their join-key metadata.
|
|
9888
|
+
*/
|
|
9889
|
+
async listSources(params = {}) {
|
|
9890
|
+
return this.client.mcp("tools/call", {
|
|
9891
|
+
name: "list_public_ground_truth_sources",
|
|
9892
|
+
arguments: {
|
|
9893
|
+
query: params.query ?? params.search,
|
|
9894
|
+
status: params.status,
|
|
9895
|
+
limit: params.limit
|
|
9896
|
+
}
|
|
9897
|
+
});
|
|
9898
|
+
}
|
|
9899
|
+
};
|
|
9900
|
+
|
|
8432
9901
|
// src/index.ts
|
|
8433
9902
|
var MCP_TOOL_CACHE_TTL_MS = 3e4;
|
|
8434
9903
|
function inferMcpToolCategory(toolName) {
|
|
@@ -8471,6 +9940,7 @@ function inferMcpToolCategory(toolName) {
|
|
|
8471
9940
|
}
|
|
8472
9941
|
if (toolName.includes("icp")) return "icp";
|
|
8473
9942
|
if (toolName.startsWith("ai_clean_")) return "data_cleaning";
|
|
9943
|
+
if (toolName.includes("public_ground_truth")) return "public_data";
|
|
8474
9944
|
if (toolName.includes("system") || toolName.includes("workflow")) return "automation";
|
|
8475
9945
|
if (toolName.includes("agent") || toolName.includes("platform_health") || toolName === "discover_capabilities") return "observability";
|
|
8476
9946
|
return void 0;
|
|
@@ -8522,6 +9992,7 @@ var Signaliz = class {
|
|
|
8522
9992
|
this.ops = new Ops(this.client);
|
|
8523
9993
|
this.ai = new Ai(this.client);
|
|
8524
9994
|
this.gtm = new GtmKernel(this.client);
|
|
9995
|
+
this.publicGroundTruth = new PublicGroundTruth(this.client);
|
|
8525
9996
|
}
|
|
8526
9997
|
/** Get current workspace info including credits */
|
|
8527
9998
|
async getWorkspace() {
|
|
@@ -8627,6 +10098,7 @@ export {
|
|
|
8627
10098
|
CampaignBuilderAgent,
|
|
8628
10099
|
createCampaignBuilderAgentPlan,
|
|
8629
10100
|
createCampaignBuilderReadiness,
|
|
10101
|
+
createCampaignBuilderActiveWorkContext,
|
|
8630
10102
|
createCampaignBuilderProofReceipt,
|
|
8631
10103
|
getMissingCampaignBuilderApprovals,
|
|
8632
10104
|
createCampaignBuilderApproval,
|
|
@@ -8644,5 +10116,6 @@ export {
|
|
|
8644
10116
|
Ops,
|
|
8645
10117
|
Ai,
|
|
8646
10118
|
GtmKernel,
|
|
10119
|
+
PublicGroundTruth,
|
|
8647
10120
|
Signaliz
|
|
8648
10121
|
};
|