@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
package/dist/cli.js
CHANGED
|
@@ -483,6 +483,38 @@ var init_signals = __esm({
|
|
|
483
483
|
constructor(client) {
|
|
484
484
|
this.client = client;
|
|
485
485
|
}
|
|
486
|
+
/** Turn the strongest supported company signal into three complete, evidence-backed emails. */
|
|
487
|
+
async signalToCopy(params) {
|
|
488
|
+
const data = await this.client.post("api/v1/signal-to-copy", {
|
|
489
|
+
company_domain: params.companyDomain,
|
|
490
|
+
person_name: params.personName,
|
|
491
|
+
title: params.title,
|
|
492
|
+
campaign_offer: params.campaignOffer,
|
|
493
|
+
research_prompt: params.researchPrompt
|
|
494
|
+
});
|
|
495
|
+
return {
|
|
496
|
+
success: data.success ?? true,
|
|
497
|
+
strongestSignal: data.strongest_signal ?? "",
|
|
498
|
+
whyNow: data.why_now ?? "",
|
|
499
|
+
subjectLine: data.subject_line ?? "",
|
|
500
|
+
openingLine: data.opening_line ?? "",
|
|
501
|
+
confidence: data.confidence ?? 0,
|
|
502
|
+
evidenceUrl: data.evidence_url ?? "",
|
|
503
|
+
researchPrompt: data.research_prompt,
|
|
504
|
+
variations: (data.variations ?? []).map((v) => ({
|
|
505
|
+
style: v.style,
|
|
506
|
+
subjectLine: v.subject_line ?? "",
|
|
507
|
+
openingLine: v.opening_line ?? "",
|
|
508
|
+
cta: v.cta ?? "",
|
|
509
|
+
prediction: v.prediction,
|
|
510
|
+
email: v.email
|
|
511
|
+
}))
|
|
512
|
+
};
|
|
513
|
+
}
|
|
514
|
+
/** @deprecated Use signalToCopy. Retained for compatibility. */
|
|
515
|
+
async personalize(params) {
|
|
516
|
+
return this.signalToCopy(params);
|
|
517
|
+
}
|
|
486
518
|
/** Enrich a company with actionable signals (V1) */
|
|
487
519
|
async enrich(params) {
|
|
488
520
|
const args = {
|
|
@@ -491,6 +523,9 @@ var init_signals = __esm({
|
|
|
491
523
|
if (params.domain) args.domain = params.domain;
|
|
492
524
|
if (params.researchPrompt) args.research_prompt = params.researchPrompt;
|
|
493
525
|
if (params.signalTypes) args.signal_types = params.signalTypes;
|
|
526
|
+
if (params.targetSignalCount) args.target_signal_count = params.targetSignalCount;
|
|
527
|
+
if (params.lookbackDays) args.lookback_days = params.lookbackDays;
|
|
528
|
+
if (params.enableDeepSearch !== void 0) args.enable_deep_search = params.enableDeepSearch;
|
|
494
529
|
const data = await this.client.mcp("tools/call", {
|
|
495
530
|
name: "enrich_company_signals",
|
|
496
531
|
arguments: args
|
|
@@ -500,6 +535,16 @@ var init_signals = __esm({
|
|
|
500
535
|
signals: (data.signals ?? []).map((s) => ({
|
|
501
536
|
title: s.title,
|
|
502
537
|
signalType: s.signal_type,
|
|
538
|
+
sourceType: s.source_type ?? s.signal_classification?.label ?? "unknown",
|
|
539
|
+
sourceProvenance: s.source_provenance ?? s.metadata?.source_provenance ?? null,
|
|
540
|
+
signalFamily: s.signal_family ?? s.signal_type ?? null,
|
|
541
|
+
signalEventType: s.signal_event_type ?? s.signal_classification?.slug ?? null,
|
|
542
|
+
signalEventLabel: s.signal_event_label ?? s.signal_classification?.label ?? null,
|
|
543
|
+
signalClassification: s.signal_classification ? {
|
|
544
|
+
label: s.signal_classification.label,
|
|
545
|
+
slug: s.signal_classification.slug,
|
|
546
|
+
rationale: s.signal_classification.rationale
|
|
547
|
+
} : null,
|
|
503
548
|
confidenceScore: s.confidence_score ?? 0,
|
|
504
549
|
detectedAt: s.detected_at ?? "",
|
|
505
550
|
url: s.url,
|
|
@@ -540,8 +585,17 @@ var init_signals = __esm({
|
|
|
540
585
|
content: s.content ?? "",
|
|
541
586
|
date: s.date ?? null,
|
|
542
587
|
sourceUrl: s.source_url ?? null,
|
|
543
|
-
sourceType: s.source_type ?? "unknown",
|
|
544
|
-
|
|
588
|
+
sourceType: s.source_type ?? s.signal_classification?.label ?? "unknown",
|
|
589
|
+
sourceProvenance: s.source_provenance ?? s.metadata?.source_provenance ?? null,
|
|
590
|
+
signalFamily: s.signal_family ?? s.type ?? null,
|
|
591
|
+
signalEventType: s.signal_event_type ?? s.signal_classification?.slug ?? null,
|
|
592
|
+
signalEventLabel: s.signal_event_label ?? s.signal_classification?.label ?? null,
|
|
593
|
+
confidence: s.confidence ?? null,
|
|
594
|
+
signalClassification: s.signal_classification ? {
|
|
595
|
+
label: s.signal_classification.label,
|
|
596
|
+
slug: s.signal_classification.slug,
|
|
597
|
+
rationale: s.signal_classification.rationale
|
|
598
|
+
} : null
|
|
545
599
|
})),
|
|
546
600
|
signalCount: data.signal_count ?? 0,
|
|
547
601
|
intelligence: data.intelligence ? {
|
|
@@ -584,6 +638,58 @@ var init_signals = __esm({
|
|
|
584
638
|
}
|
|
585
639
|
};
|
|
586
640
|
}
|
|
641
|
+
/** Plan or run experimental Signal Fusion with explicit spend controls. */
|
|
642
|
+
async fusion(params) {
|
|
643
|
+
const args = {};
|
|
644
|
+
if (params.companyName) args.company_name = params.companyName;
|
|
645
|
+
if (params.domain) args.domain = params.domain;
|
|
646
|
+
if (params.companyDomain) args.company_domain = params.companyDomain;
|
|
647
|
+
if (params.linkedinUrl) args.linkedin_url = params.linkedinUrl;
|
|
648
|
+
if (params.companies) args.companies = params.companies;
|
|
649
|
+
if (params.preset) args.preset = params.preset;
|
|
650
|
+
if (params.researchPrompt) args.research_prompt = params.researchPrompt;
|
|
651
|
+
if (params.signalTypes) args.signal_types = params.signalTypes;
|
|
652
|
+
if (params.lookbackDays) args.lookback_days = params.lookbackDays;
|
|
653
|
+
if (params.targetSignalCount) args.target_signal_count = params.targetSignalCount;
|
|
654
|
+
if (params.maxToolCalls) args.max_tool_calls = params.maxToolCalls;
|
|
655
|
+
if (params.maxTokens) args.max_tokens = params.maxTokens;
|
|
656
|
+
if (params.timeoutMs) args.timeout_ms = params.timeoutMs;
|
|
657
|
+
const dryRun = params.dryRun ?? params.dry_run;
|
|
658
|
+
const confirmSpend = params.confirmSpend ?? params.confirm_spend;
|
|
659
|
+
const maxCredits = params.maxCredits ?? params.max_credits;
|
|
660
|
+
const maxCostUsd = params.maxCostUsd ?? params.max_cost_usd;
|
|
661
|
+
if (dryRun !== void 0) args.dry_run = dryRun;
|
|
662
|
+
if (confirmSpend !== void 0) args.confirm_spend = confirmSpend;
|
|
663
|
+
if (maxCredits !== void 0) args.max_credits = maxCredits;
|
|
664
|
+
if (maxCostUsd !== void 0) args.max_cost_usd = maxCostUsd;
|
|
665
|
+
const data = await this.client.post("signal-fusion", args);
|
|
666
|
+
return {
|
|
667
|
+
success: data.success ?? false,
|
|
668
|
+
capability: data.capability ?? "signal_fusion",
|
|
669
|
+
displayName: data.display_name ?? "Signal Fusion",
|
|
670
|
+
company: data.company,
|
|
671
|
+
signals: (data.signals ?? []).map((s) => ({
|
|
672
|
+
id: s.id,
|
|
673
|
+
title: s.title,
|
|
674
|
+
type: s.type,
|
|
675
|
+
content: s.content ?? "",
|
|
676
|
+
date: s.date ?? null,
|
|
677
|
+
sourceUrl: s.source_url ?? null,
|
|
678
|
+
sourceType: s.source_type ?? "unknown",
|
|
679
|
+
confidence: s.confidence ?? null
|
|
680
|
+
})),
|
|
681
|
+
signalCount: data.signal_count ?? data.signals?.length ?? 0,
|
|
682
|
+
results: data.results ?? [],
|
|
683
|
+
model: data.model,
|
|
684
|
+
fusion: data.fusion,
|
|
685
|
+
costUsd: data.cost_usd ?? 0,
|
|
686
|
+
tokensUsed: data.tokens_used ?? 0,
|
|
687
|
+
costSummary: data.cost_summary,
|
|
688
|
+
creditsUsed: data.total_credits_used ?? data.credits_used ?? 0,
|
|
689
|
+
billingMetadata: data.billing_metadata,
|
|
690
|
+
raw: data
|
|
691
|
+
};
|
|
692
|
+
}
|
|
587
693
|
};
|
|
588
694
|
}
|
|
589
695
|
});
|
|
@@ -835,6 +941,7 @@ function mapCustomerRowCounts(value) {
|
|
|
835
941
|
acceptedRows: numberOrNull(record.accepted_rows) ?? void 0,
|
|
836
942
|
usableRows: numberOrNull(record.usable_rows) ?? void 0,
|
|
837
943
|
copiedRows: numberOrNull(record.copied_rows) ?? void 0,
|
|
944
|
+
copySkippedRows: numberOrNull(record.copy_skipped_rows) ?? void 0,
|
|
838
945
|
approvalReadyRows: numberOrNull(record.approval_ready_rows) ?? void 0,
|
|
839
946
|
qaReadyRows: numberOrNull(record.qa_ready_rows) ?? void 0,
|
|
840
947
|
deliveredRows: numberOrNull(record.delivered_rows) ?? void 0,
|
|
@@ -881,6 +988,9 @@ function recordOrNull(value) {
|
|
|
881
988
|
function stringArray(value) {
|
|
882
989
|
return Array.isArray(value) ? value.map((item) => String(item || "").trim()).filter(Boolean) : [];
|
|
883
990
|
}
|
|
991
|
+
function recordArray(value) {
|
|
992
|
+
return Array.isArray(value) ? value.map(recordOrNull).filter((item) => Boolean(item)) : [];
|
|
993
|
+
}
|
|
884
994
|
function diagnosticMessages(value) {
|
|
885
995
|
if (!Array.isArray(value)) return [];
|
|
886
996
|
return value.map((item) => {
|
|
@@ -1042,7 +1152,8 @@ function buildArgs(request) {
|
|
|
1042
1152
|
suppress_prior_campaign_ids: request.cacheReusePolicy.suppressPriorCampaignIds,
|
|
1043
1153
|
suppress_prior_list_ids: request.cacheReusePolicy.suppressPriorListIds,
|
|
1044
1154
|
uniqueness: request.cacheReusePolicy.uniqueness,
|
|
1045
|
-
require_usage_metadata: request.cacheReusePolicy.requireUsageMetadata
|
|
1155
|
+
require_usage_metadata: request.cacheReusePolicy.requireUsageMetadata,
|
|
1156
|
+
verified_cache_ttl_days: request.cacheReusePolicy.verifiedCacheTtlDays
|
|
1046
1157
|
};
|
|
1047
1158
|
}
|
|
1048
1159
|
if (request.brainPreflight) args.brain_preflight = request.brainPreflight;
|
|
@@ -1067,7 +1178,8 @@ function buildArgs(request) {
|
|
|
1067
1178
|
geographies: request.icp.geographies,
|
|
1068
1179
|
keywords: request.icp.keywords,
|
|
1069
1180
|
exclusions: request.icp.exclusions,
|
|
1070
|
-
require_verified_email: request.icp.requireVerifiedEmail
|
|
1181
|
+
require_verified_email: request.icp.requireVerifiedEmail,
|
|
1182
|
+
persona_expansion_mode: request.icp.personaExpansionMode
|
|
1071
1183
|
};
|
|
1072
1184
|
}
|
|
1073
1185
|
if (request.policy) {
|
|
@@ -1107,6 +1219,7 @@ function buildArgs(request) {
|
|
|
1107
1219
|
} : void 0,
|
|
1108
1220
|
sequence_steps: request.copy.sequenceSteps,
|
|
1109
1221
|
copy_schema: request.copy.copySchema,
|
|
1222
|
+
evidence_mode: request.copy.evidenceMode,
|
|
1110
1223
|
banned_phrases: request.copy.bannedPhrases,
|
|
1111
1224
|
approval_required: request.copy.approvalRequired,
|
|
1112
1225
|
quality_tier: request.copy.qualityTier
|
|
@@ -1247,7 +1360,11 @@ var init_campaigns = __esm({
|
|
|
1247
1360
|
maxSupportedTargetCount: data.max_supported_target_count,
|
|
1248
1361
|
brainContext: data.brain_context ?? {},
|
|
1249
1362
|
learningHoldout: data.learning_holdout ?? {},
|
|
1250
|
-
providerRoute: mapProviderRoute(data)
|
|
1363
|
+
providerRoute: mapProviderRoute(data),
|
|
1364
|
+
effectiveSourceRouting: recordOrNull(data.effective_source_routing ?? data.source_routing),
|
|
1365
|
+
sourcePlan: recordOrNull(data.source_plan ?? data.plan?.source_plan),
|
|
1366
|
+
sourceRoutes: recordArray(data.source_routes ?? data.source_plan?.routes ?? data.plan?.source_plan?.routes),
|
|
1367
|
+
sourceShards: recordArray(data.source_shards ?? data.source_plan?.shards ?? data.plan?.source_plan?.shards)
|
|
1251
1368
|
};
|
|
1252
1369
|
}
|
|
1253
1370
|
async getCampaignBuildStatus(campaignBuildId) {
|
|
@@ -1368,9 +1485,10 @@ function createCampaignBuilderAgentPlan(request, context = {}) {
|
|
|
1368
1485
|
const estimatedCredits = estimateCredits(resolvedRequest, defaults, targetCount);
|
|
1369
1486
|
const buildRequest = createBuildRequest(resolvedRequest, defaults, targetCount, campaignName, context.scopeBuildArgs, routes, memory, context.scopeBrainPreflight);
|
|
1370
1487
|
const brainPreflight = asRecord(buildRequest.brainPreflight);
|
|
1488
|
+
const evidence = buildRequest.evidence ?? null;
|
|
1371
1489
|
const approvals = deriveApprovals(resolvedRequest, routes, memory, estimatedCredits, defaults.delivery?.approvalRequired !== false);
|
|
1372
1490
|
return {
|
|
1373
|
-
planId: `cbp_${hashString(JSON.stringify({ goal: resolvedRequest.goal, campaignName, targetCount, routes }))}`,
|
|
1491
|
+
planId: `cbp_${hashString(JSON.stringify({ goal: resolvedRequest.goal, campaignName, targetCount, routes, evidence }))}`,
|
|
1374
1492
|
campaignName,
|
|
1375
1493
|
goal: resolvedRequest.goal,
|
|
1376
1494
|
targetCount,
|
|
@@ -1385,6 +1503,7 @@ function createCampaignBuilderAgentPlan(request, context = {}) {
|
|
|
1385
1503
|
approvals,
|
|
1386
1504
|
buildRequest,
|
|
1387
1505
|
brainPreflight,
|
|
1506
|
+
evidence,
|
|
1388
1507
|
operatingPlaybooks,
|
|
1389
1508
|
mcpFlow: createMcpFlow(resolvedRequest, buildRequest, routes, memory, approvals),
|
|
1390
1509
|
estimatedCredits,
|
|
@@ -1476,6 +1595,90 @@ function createCampaignBuilderReadiness(plan) {
|
|
|
1476
1595
|
nextActions: campaignReadinessNextActions(plan, ready, customRoutes.length)
|
|
1477
1596
|
};
|
|
1478
1597
|
}
|
|
1598
|
+
function createCampaignBuilderActiveWorkContext(input) {
|
|
1599
|
+
const plan = input.readiness?.plan ?? input.plan;
|
|
1600
|
+
const remembered = input.remembered ?? {};
|
|
1601
|
+
const lastResult = asRecord(input.lastResult);
|
|
1602
|
+
const readinessBlockers = input.readiness?.summary.blockers ?? [];
|
|
1603
|
+
const explicitBlockers = input.blockers ?? [];
|
|
1604
|
+
const blockers = uniqueStrings([...explicitBlockers, ...readinessBlockers]);
|
|
1605
|
+
const warnings = uniqueStrings([
|
|
1606
|
+
...input.warnings ?? [],
|
|
1607
|
+
...input.readiness?.summary.warnings ?? [],
|
|
1608
|
+
...plan?.warnings ?? []
|
|
1609
|
+
]);
|
|
1610
|
+
const missingApprovals = plan ? (input.approval ? getMissingCampaignBuilderApprovals(plan, input.approval) : plan.approvals.filter((approval) => approval.blocking)).map((approval) => approval.type) : [];
|
|
1611
|
+
const refs = normalizeCampaignBuilderActiveWorkRefs({
|
|
1612
|
+
plan,
|
|
1613
|
+
remembered,
|
|
1614
|
+
refs: input.refs,
|
|
1615
|
+
lastResult
|
|
1616
|
+
});
|
|
1617
|
+
const state = inferCampaignBuilderActiveWorkState({
|
|
1618
|
+
plan,
|
|
1619
|
+
readiness: input.readiness,
|
|
1620
|
+
remembered,
|
|
1621
|
+
lastResult,
|
|
1622
|
+
blockers,
|
|
1623
|
+
missingApprovals
|
|
1624
|
+
});
|
|
1625
|
+
const nextSafeAction = campaignBuilderActiveWorkNextAction(state, blockers, missingApprovals, refs);
|
|
1626
|
+
const approvalPacket = createCampaignBuilderApprovalPacket(plan, input.approval, missingApprovals);
|
|
1627
|
+
const nextSafeMcpAction = campaignBuilderActiveWorkNextMcpAction({
|
|
1628
|
+
state,
|
|
1629
|
+
plan,
|
|
1630
|
+
refs,
|
|
1631
|
+
approvalPacket
|
|
1632
|
+
});
|
|
1633
|
+
const summary = {
|
|
1634
|
+
plan_id: plan?.planId ?? remembered.planId ?? null,
|
|
1635
|
+
campaign_name: plan?.campaignName ?? null,
|
|
1636
|
+
target_count: plan?.targetCount ?? null,
|
|
1637
|
+
gtm_campaign_id: plan?.buildRequest.gtmCampaignId ?? remembered.gtmCampaignId ?? null,
|
|
1638
|
+
campaign_build_id: stringValue(lastResult.campaign_build_id ?? lastResult.campaignBuildId) ?? remembered.campaignBuildId ?? null,
|
|
1639
|
+
provider_campaign_id: remembered.providerCampaignId ?? null
|
|
1640
|
+
};
|
|
1641
|
+
const approvalBoundary = campaignBuilderActiveWorkApprovalBoundary(missingApprovals, state);
|
|
1642
|
+
const conversationStarters = campaignBuilderActiveWorkConversationStarters({
|
|
1643
|
+
state,
|
|
1644
|
+
blockers,
|
|
1645
|
+
missingApprovals,
|
|
1646
|
+
refs,
|
|
1647
|
+
nextSafeAction
|
|
1648
|
+
});
|
|
1649
|
+
return {
|
|
1650
|
+
packet_version: "campaign-builder-active-work-context.v1",
|
|
1651
|
+
read_only: true,
|
|
1652
|
+
no_spend: true,
|
|
1653
|
+
no_provider_writes: true,
|
|
1654
|
+
private_safe: true,
|
|
1655
|
+
state,
|
|
1656
|
+
summary,
|
|
1657
|
+
refs,
|
|
1658
|
+
blockers,
|
|
1659
|
+
warnings,
|
|
1660
|
+
missing_approval_types: missingApprovals,
|
|
1661
|
+
approval_packet: approvalPacket,
|
|
1662
|
+
approval_boundary: approvalBoundary,
|
|
1663
|
+
next_safe_action: nextSafeAction,
|
|
1664
|
+
next_safe_mcp_action: nextSafeMcpAction,
|
|
1665
|
+
conversation_starters: conversationStarters,
|
|
1666
|
+
openai_agent_handoff: createCampaignBuilderOpenAiAgentHandoff({
|
|
1667
|
+
plan,
|
|
1668
|
+
state,
|
|
1669
|
+
summary,
|
|
1670
|
+
refs,
|
|
1671
|
+
blockers,
|
|
1672
|
+
warnings,
|
|
1673
|
+
missingApprovals,
|
|
1674
|
+
approvalPacket,
|
|
1675
|
+
approvalBoundary,
|
|
1676
|
+
nextSafeAction,
|
|
1677
|
+
nextSafeMcpAction,
|
|
1678
|
+
conversationStarters
|
|
1679
|
+
})
|
|
1680
|
+
};
|
|
1681
|
+
}
|
|
1479
1682
|
function createCampaignBuilderProofReceipt(plan, result) {
|
|
1480
1683
|
const strategyMemory = asRecord(plan.strategyMemoryStatus);
|
|
1481
1684
|
const dryRunResult = asRecord(result);
|
|
@@ -1534,6 +1737,7 @@ function createCampaignBuilderProofReceipt(plan, result) {
|
|
|
1534
1737
|
estimated_credits: plan.estimatedCredits,
|
|
1535
1738
|
operating_playbooks: plan.operatingPlaybooks.map((playbook) => playbook.slug)
|
|
1536
1739
|
},
|
|
1740
|
+
evidence: plan.evidence,
|
|
1537
1741
|
gates,
|
|
1538
1742
|
strategy_memory_status: summarizeCampaignBuilderProofStrategyMemory(strategyMemory),
|
|
1539
1743
|
dry_run_result: summarizeCampaignBuilderProofDryRun(dryRunResult),
|
|
@@ -1589,6 +1793,56 @@ function getCampaignBuilderOperatingPlaybooksForRequest(request) {
|
|
|
1589
1793
|
]);
|
|
1590
1794
|
return slugs.map(getCampaignBuilderOperatingPlaybook).filter((playbook) => Boolean(playbook));
|
|
1591
1795
|
}
|
|
1796
|
+
function normalizeCampaignBuilderEvidence(evidence) {
|
|
1797
|
+
if (!evidence) return null;
|
|
1798
|
+
const attachmentSummary = (evidence.attachments ?? []).filter((attachment) => stringValue(attachment.name)).slice(0, 5).map((attachment) => ({
|
|
1799
|
+
name: stringValue(attachment.name) ?? "attachment",
|
|
1800
|
+
kind: stringValue(attachment.kind) ?? null,
|
|
1801
|
+
media_type: stringValue(attachment.mediaType) ?? null,
|
|
1802
|
+
redacted: attachment.redacted !== false,
|
|
1803
|
+
columns: uniqueStrings(attachment.columns ?? []).slice(0, 25),
|
|
1804
|
+
row_count: numberOrUndefined2(attachment.rowCount) ?? null,
|
|
1805
|
+
content_summary: stringValue(attachment.contentSummary)?.slice(0, 500) ?? null,
|
|
1806
|
+
evidence_fields: uniqueStrings(attachment.evidenceFields ?? []).slice(0, 25)
|
|
1807
|
+
}));
|
|
1808
|
+
const urlSummary = (evidence.urls ?? []).filter((url) => stringValue(url.url)).slice(0, 8).map((url) => {
|
|
1809
|
+
const rawUrl = stringValue(url.url) ?? "";
|
|
1810
|
+
return {
|
|
1811
|
+
url: rawUrl,
|
|
1812
|
+
host: stringValue(url.host) ?? hostFromUrl(rawUrl) ?? null,
|
|
1813
|
+
type: stringValue(url.type) ?? null,
|
|
1814
|
+
label: stringValue(url.label) ?? null,
|
|
1815
|
+
summary: stringValue(url.summary)?.slice(0, 500) ?? null,
|
|
1816
|
+
redacted: url.redacted === true
|
|
1817
|
+
};
|
|
1818
|
+
});
|
|
1819
|
+
const operatorNotes = uniqueStrings(evidence.notes ?? []).map((note) => note.slice(0, 240)).slice(0, 5);
|
|
1820
|
+
if (!attachmentSummary.length && !urlSummary.length && !operatorNotes.length) return null;
|
|
1821
|
+
return {
|
|
1822
|
+
packet_version: "campaign-builder-evidence.v1",
|
|
1823
|
+
private_safe: true,
|
|
1824
|
+
attachment_summary: attachmentSummary,
|
|
1825
|
+
url_summary: urlSummary,
|
|
1826
|
+
operator_notes: operatorNotes,
|
|
1827
|
+
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.",
|
|
1828
|
+
raw_private_fields_withheld: [
|
|
1829
|
+
"raw_private_attachment_text",
|
|
1830
|
+
"raw_attachment_rows",
|
|
1831
|
+
"raw_leads",
|
|
1832
|
+
"email_addresses",
|
|
1833
|
+
"provider_auth_payloads",
|
|
1834
|
+
"copy_bodies",
|
|
1835
|
+
"secrets"
|
|
1836
|
+
]
|
|
1837
|
+
};
|
|
1838
|
+
}
|
|
1839
|
+
function hostFromUrl(value) {
|
|
1840
|
+
try {
|
|
1841
|
+
return new URL(value).hostname || void 0;
|
|
1842
|
+
} catch {
|
|
1843
|
+
return void 0;
|
|
1844
|
+
}
|
|
1845
|
+
}
|
|
1592
1846
|
function applyCampaignBuilderStrategyTemplate(request) {
|
|
1593
1847
|
const template = getCampaignBuilderStrategyTemplate(request.strategyTemplate);
|
|
1594
1848
|
if (!template) return request;
|
|
@@ -2280,7 +2534,7 @@ function normalizeMemory(request) {
|
|
|
2280
2534
|
};
|
|
2281
2535
|
}
|
|
2282
2536
|
function defaultAgencyMemoryQueries(request, configured) {
|
|
2283
|
-
const operatingPlaybookTerms = getCampaignBuilderOperatingPlaybooksForRequest(request).flatMap((playbook) => [playbook.label, ...playbook.memoryKeywords]).join(" ");
|
|
2537
|
+
const operatingPlaybookTerms = getCampaignBuilderOperatingPlaybooksForRequest(request).flatMap((playbook) => [playbook.label, ...playbook.memoryKeywords, ...playbook.knowledgeSources]).join(" ");
|
|
2284
2538
|
const queries = [{
|
|
2285
2539
|
query: request.goal,
|
|
2286
2540
|
scopes: ["workspace", configured.useNetworkPatterns ? "network_patterns" : "operator_notes"],
|
|
@@ -2446,6 +2700,21 @@ function routesFromCustomerTools(tools) {
|
|
|
2446
2700
|
}))
|
|
2447
2701
|
);
|
|
2448
2702
|
}
|
|
2703
|
+
function normalizeCampaignBuilderLearningHoldout(input, gtmCampaignId, campaignName) {
|
|
2704
|
+
const source = asRecord(input);
|
|
2705
|
+
if (source.enabled === false) return { enabled: false };
|
|
2706
|
+
const controlPercentage = numberOrUndefined2(source.control_percentage ?? source.controlPercentage);
|
|
2707
|
+
const minControlSize = numberOrUndefined2(source.min_control_size ?? source.minControlSize);
|
|
2708
|
+
const experimentKey = stringValue(source.experiment_key ?? source.experimentKey) ?? (gtmCampaignId ? `gtm_campaign:${gtmCampaignId}:learning_holdout` : `campaign_builder_agent:${hashString(campaignName)}:learning_holdout`);
|
|
2709
|
+
return {
|
|
2710
|
+
enabled: true,
|
|
2711
|
+
controlPercentage: controlPercentage ?? 0.2,
|
|
2712
|
+
minControlSize: minControlSize ?? 50,
|
|
2713
|
+
experimentKey,
|
|
2714
|
+
sourceCampaignId: stringValue(source.source_campaign_id ?? source.sourceCampaignId) ?? gtmCampaignId,
|
|
2715
|
+
primaryMetric: stringValue(source.primary_metric ?? source.primaryMetric) ?? "positive_reply_rate"
|
|
2716
|
+
};
|
|
2717
|
+
}
|
|
2449
2718
|
function createBuildRequest(request, defaults, targetCount, campaignName, scopeBuildArgs, routes = [], memory, scopeBrainPreflight) {
|
|
2450
2719
|
const buildRequest = {
|
|
2451
2720
|
name: campaignName,
|
|
@@ -2476,8 +2745,15 @@ function createBuildRequest(request, defaults, targetCount, campaignName, scopeB
|
|
|
2476
2745
|
fillPolicy: "aggressive"
|
|
2477
2746
|
}
|
|
2478
2747
|
};
|
|
2748
|
+
const evidence = normalizeCampaignBuilderEvidence(request.evidence);
|
|
2749
|
+
if (evidence) buildRequest.evidence = evidence;
|
|
2479
2750
|
const scoped = asRecord(scopeBuildArgs);
|
|
2480
2751
|
buildRequest.gtmCampaignId = request.gtmCampaignId ?? stringValue(scoped.gtm_campaign_id ?? scoped.gtmCampaignId);
|
|
2752
|
+
buildRequest.learningHoldout = normalizeCampaignBuilderLearningHoldout(
|
|
2753
|
+
request.learningHoldout ?? scoped.learning_holdout ?? scoped.learningHoldout,
|
|
2754
|
+
buildRequest.gtmCampaignId,
|
|
2755
|
+
campaignName
|
|
2756
|
+
);
|
|
2481
2757
|
if (typeof scoped.name === "string") buildRequest.name = scoped.name;
|
|
2482
2758
|
if (typeof scoped.prompt === "string") buildRequest.prompt = scoped.prompt;
|
|
2483
2759
|
if (typeof scoped.target_count === "number") buildRequest.targetCount = scoped.target_count;
|
|
@@ -2502,6 +2778,7 @@ function createBrainPreflight(request, buildRequest, routes, memory) {
|
|
|
2502
2778
|
memory.enabled ? "feedback" : void 0
|
|
2503
2779
|
]);
|
|
2504
2780
|
const providerChain = uniqueStrings(["signaliz", ...request.preferredProviders ?? [], ...routes.map((route) => route.provider)]);
|
|
2781
|
+
const evidence = buildRequest.evidence ?? normalizeCampaignBuilderEvidence(request.evidence);
|
|
2505
2782
|
const targetIcp = compact({
|
|
2506
2783
|
personas: buildRequest.icp?.personas,
|
|
2507
2784
|
industries: buildRequest.icp?.industries,
|
|
@@ -2514,6 +2791,7 @@ function createBrainPreflight(request, buildRequest, routes, memory) {
|
|
|
2514
2791
|
const learningArgs = compact({
|
|
2515
2792
|
campaign_brief: request.goal,
|
|
2516
2793
|
target_icp: targetIcp,
|
|
2794
|
+
evidence_context: evidence,
|
|
2517
2795
|
layers,
|
|
2518
2796
|
provider_chain: providerChain,
|
|
2519
2797
|
lead_source: providerChain[0] ?? "signaliz",
|
|
@@ -2525,6 +2803,7 @@ function createBrainPreflight(request, buildRequest, routes, memory) {
|
|
|
2525
2803
|
const defaultsArgs = compact({
|
|
2526
2804
|
campaign_brief: request.goal,
|
|
2527
2805
|
target_icp: targetIcp,
|
|
2806
|
+
evidence_context: evidence,
|
|
2528
2807
|
layers,
|
|
2529
2808
|
include_global: memory.useNetworkPatterns,
|
|
2530
2809
|
include_memory: memory.enabled,
|
|
@@ -2535,6 +2814,7 @@ function createBrainPreflight(request, buildRequest, routes, memory) {
|
|
|
2535
2814
|
provider_chain: providerChain,
|
|
2536
2815
|
lead_source: providerChain[0] ?? "signaliz",
|
|
2537
2816
|
target_icp: targetIcp,
|
|
2817
|
+
evidence_context: evidence,
|
|
2538
2818
|
include_global: memory.useNetworkPatterns,
|
|
2539
2819
|
limit: 25
|
|
2540
2820
|
});
|
|
@@ -2547,11 +2827,14 @@ function createBrainPreflight(request, buildRequest, routes, memory) {
|
|
|
2547
2827
|
label: playbook.label,
|
|
2548
2828
|
quality_gates: playbook.qualityGates,
|
|
2549
2829
|
required_fields: playbook.requiredFields,
|
|
2550
|
-
activation_boundary: playbook.activationBoundary
|
|
2830
|
+
activation_boundary: playbook.activationBoundary,
|
|
2831
|
+
knowledge_sources: playbook.knowledgeSources
|
|
2551
2832
|
})),
|
|
2552
2833
|
target_icp: targetIcp,
|
|
2834
|
+
evidence_context: evidence,
|
|
2553
2835
|
provider_chain: providerChain,
|
|
2554
2836
|
lead_source: providerChain[0] ?? "signaliz",
|
|
2837
|
+
learning_holdout: buildRequest.learningHoldout,
|
|
2555
2838
|
tool_sequence: [
|
|
2556
2839
|
{ tool: "gtm_brain_learning_cycle_plan", purpose: "Plan the Brain learning loop for this campaign.", arguments: learningArgs },
|
|
2557
2840
|
{ tool: "gtm_brain_seed_defaults", purpose: "Seed campaign defaults from workspace memory and safe aggregate patterns.", arguments: defaultsArgs },
|
|
@@ -2821,7 +3104,7 @@ function createMcpFlow(request, buildRequest, routes, memory, approvals) {
|
|
|
2821
3104
|
phase: "plan",
|
|
2822
3105
|
tool: "nango_mcp_tools_list",
|
|
2823
3106
|
arguments: {
|
|
2824
|
-
format: "
|
|
3107
|
+
format: "openai"
|
|
2825
3108
|
},
|
|
2826
3109
|
readOnly: true,
|
|
2827
3110
|
approvalRequired: false
|
|
@@ -3130,6 +3413,7 @@ function buildGtmCampaignBuildPlanArgs(request, buildRequest, routes, memory) {
|
|
|
3130
3413
|
layers: layers.length > 0 ? layers : void 0,
|
|
3131
3414
|
preferred_providers: preferredProviders.length > 0 ? preferredProviders : void 0,
|
|
3132
3415
|
strategy_model: strategyModel,
|
|
3416
|
+
evidence_context: buildRequest.evidence ?? normalizeCampaignBuilderEvidence(request.evidence),
|
|
3133
3417
|
include_strategy_patterns: campaignBuilderStrategyPatternsEnabled(agencyContext),
|
|
3134
3418
|
include_workflow_patterns: campaignBuilderWorkflowPatternsEnabled(agencyContext),
|
|
3135
3419
|
include_nango_catalog: agencyContext.includeNangoCatalog !== false,
|
|
@@ -3138,7 +3422,8 @@ function buildGtmCampaignBuildPlanArgs(request, buildRequest, routes, memory) {
|
|
|
3138
3422
|
slug: playbook.slug,
|
|
3139
3423
|
label: playbook.label,
|
|
3140
3424
|
quality_gates: playbook.qualityGates,
|
|
3141
|
-
activation_boundary: playbook.activationBoundary
|
|
3425
|
+
activation_boundary: playbook.activationBoundary,
|
|
3426
|
+
knowledge_sources: playbook.knowledgeSources
|
|
3142
3427
|
})),
|
|
3143
3428
|
include_memory: memory.enabled,
|
|
3144
3429
|
include_brain: true,
|
|
@@ -3219,8 +3504,19 @@ function buildCampaignArgs(request) {
|
|
|
3219
3504
|
if (request.dedupKeys) args.dedup_keys = request.dedupKeys;
|
|
3220
3505
|
if (request.brainPreflight) args.brain_preflight = request.brainPreflight;
|
|
3221
3506
|
if (request.brainDefaults) args.brain_defaults = request.brainDefaults;
|
|
3507
|
+
if (request.learningHoldout) {
|
|
3508
|
+
args.learning_holdout = compact({
|
|
3509
|
+
enabled: request.learningHoldout.enabled,
|
|
3510
|
+
control_percentage: request.learningHoldout.controlPercentage,
|
|
3511
|
+
min_control_size: request.learningHoldout.minControlSize,
|
|
3512
|
+
experiment_key: request.learningHoldout.experimentKey,
|
|
3513
|
+
source_campaign_id: request.learningHoldout.sourceCampaignId,
|
|
3514
|
+
primary_metric: request.learningHoldout.primaryMetric
|
|
3515
|
+
});
|
|
3516
|
+
}
|
|
3222
3517
|
if (request.campaignStrategyContext) args.campaign_strategy_context = request.campaignStrategyContext;
|
|
3223
3518
|
if (request.deliveryRisk) args.delivery_risk = request.deliveryRisk;
|
|
3519
|
+
if (request.evidence) args.evidence_context = request.evidence;
|
|
3224
3520
|
if (request.icp) {
|
|
3225
3521
|
args.icp = compact({
|
|
3226
3522
|
personas: request.icp.personas,
|
|
@@ -3270,7 +3566,8 @@ function buildCampaignArgs(request) {
|
|
|
3270
3566
|
max_body_words: request.copy.maxBodyWords,
|
|
3271
3567
|
sender_context: request.copy.senderContext,
|
|
3272
3568
|
offer_context: request.copy.offerContext,
|
|
3273
|
-
model: request.copy.model
|
|
3569
|
+
model: request.copy.model,
|
|
3570
|
+
evidence_mode: request.copy.evidenceMode
|
|
3274
3571
|
});
|
|
3275
3572
|
}
|
|
3276
3573
|
if (request.delivery) {
|
|
@@ -3315,6 +3612,7 @@ function buildExecutionPrepareArgs(request, dryRun, confirmSpend) {
|
|
|
3315
3612
|
delivery_risk: buildArgs2.delivery_risk,
|
|
3316
3613
|
dedup_keys: buildArgs2.dedup_keys,
|
|
3317
3614
|
policy: buildArgs2.policy,
|
|
3615
|
+
learning_holdout: buildArgs2.learning_holdout,
|
|
3318
3616
|
signals: buildArgs2.signals,
|
|
3319
3617
|
qualification: buildArgs2.qualification,
|
|
3320
3618
|
copy: buildArgs2.copy,
|
|
@@ -3349,10 +3647,143 @@ function mapBuildResult(data, dryRun) {
|
|
|
3349
3647
|
targetLimitReason: data.target_limit_reason,
|
|
3350
3648
|
maxSupportedTargetCount: data.max_supported_target_count,
|
|
3351
3649
|
brainContext: data.brain_context ?? {},
|
|
3650
|
+
learningHoldout: data.learning_holdout ?? {},
|
|
3352
3651
|
providerRoute: mapProviderRoute2(data)
|
|
3353
3652
|
};
|
|
3354
3653
|
}
|
|
3654
|
+
function mapAgentCampaignPhaseHealth(value) {
|
|
3655
|
+
if (!Array.isArray(value)) return [];
|
|
3656
|
+
return value.map((phase) => {
|
|
3657
|
+
const record = asRecord(phase);
|
|
3658
|
+
return {
|
|
3659
|
+
phase: stringValue(record.phase) ?? "unknown",
|
|
3660
|
+
status: stringValue(record.status) ?? "unknown",
|
|
3661
|
+
recordsProcessed: numberOrNull2(record.records_processed ?? record.recordsProcessed),
|
|
3662
|
+
recordsSucceeded: numberOrNull2(record.records_succeeded ?? record.recordsSucceeded),
|
|
3663
|
+
recordsFailed: numberOrNull2(record.records_failed ?? record.recordsFailed),
|
|
3664
|
+
heartbeatAgeSeconds: numberOrNull2(record.heartbeat_age_seconds ?? record.heartbeatAgeSeconds ?? record.phase_age_seconds)
|
|
3665
|
+
};
|
|
3666
|
+
});
|
|
3667
|
+
}
|
|
3668
|
+
function deriveCampaignBuildTerminalState(input) {
|
|
3669
|
+
const status = input.status.toLowerCase();
|
|
3670
|
+
const heartbeatAgeSeconds = input.phaseAgeSeconds;
|
|
3671
|
+
const stale = input.staleRunningPhase === true;
|
|
3672
|
+
const safeWatchAction = input.triggerRunId ? `signaliz ops run-status ${input.triggerRunId} --watch` : "signaliz campaign-agent status <campaign_build_id>";
|
|
3673
|
+
if (CAMPAIGN_BUILDER_BLOCKED_TERMINAL_STATUSES.has(status)) {
|
|
3674
|
+
return {
|
|
3675
|
+
kind: "blocked",
|
|
3676
|
+
label: "Blocked terminal state",
|
|
3677
|
+
reviewable: true,
|
|
3678
|
+
terminal: true,
|
|
3679
|
+
stale: false,
|
|
3680
|
+
phase: input.phase,
|
|
3681
|
+
phaseStatus: input.phaseStatus,
|
|
3682
|
+
heartbeatAgeSeconds,
|
|
3683
|
+
nextPollAfterSeconds: input.nextPollAfterSeconds,
|
|
3684
|
+
terminalReason: input.terminalReason,
|
|
3685
|
+
staleReason: null,
|
|
3686
|
+
safeNextAction: input.nextAction || "Review errors and rerun only after the blocker is resolved."
|
|
3687
|
+
};
|
|
3688
|
+
}
|
|
3689
|
+
if (status === "pending_approval") {
|
|
3690
|
+
return {
|
|
3691
|
+
kind: "pending_approval",
|
|
3692
|
+
label: "Pending delivery approval",
|
|
3693
|
+
reviewable: true,
|
|
3694
|
+
terminal: false,
|
|
3695
|
+
stale: false,
|
|
3696
|
+
phase: input.phase,
|
|
3697
|
+
phaseStatus: input.phaseStatus,
|
|
3698
|
+
heartbeatAgeSeconds,
|
|
3699
|
+
nextPollAfterSeconds: input.nextPollAfterSeconds,
|
|
3700
|
+
terminalReason: input.terminalReason,
|
|
3701
|
+
staleReason: null,
|
|
3702
|
+
safeNextAction: input.approvalAction || input.nextAction || "Review rows and approve delivery only after the approval packet passes."
|
|
3703
|
+
};
|
|
3704
|
+
}
|
|
3705
|
+
if (CAMPAIGN_BUILDER_TERMINAL_STATUSES.has(status)) {
|
|
3706
|
+
return {
|
|
3707
|
+
kind: "terminal",
|
|
3708
|
+
label: "Terminal and reviewable",
|
|
3709
|
+
reviewable: true,
|
|
3710
|
+
terminal: true,
|
|
3711
|
+
stale: false,
|
|
3712
|
+
phase: input.phase,
|
|
3713
|
+
phaseStatus: input.phaseStatus,
|
|
3714
|
+
heartbeatAgeSeconds,
|
|
3715
|
+
nextPollAfterSeconds: input.nextPollAfterSeconds,
|
|
3716
|
+
terminalReason: input.terminalReason,
|
|
3717
|
+
staleReason: null,
|
|
3718
|
+
safeNextAction: input.nextAction || "Review rows, artifacts, scorecard, and approval locks before delivery."
|
|
3719
|
+
};
|
|
3720
|
+
}
|
|
3721
|
+
if (status === "running" || status === "queued" || status === "processing") {
|
|
3722
|
+
if (stale) {
|
|
3723
|
+
return {
|
|
3724
|
+
kind: "running_stale",
|
|
3725
|
+
label: "Running but stale",
|
|
3726
|
+
reviewable: false,
|
|
3727
|
+
terminal: false,
|
|
3728
|
+
stale: true,
|
|
3729
|
+
phase: input.phase,
|
|
3730
|
+
phaseStatus: input.phaseStatus,
|
|
3731
|
+
heartbeatAgeSeconds,
|
|
3732
|
+
nextPollAfterSeconds: input.nextPollAfterSeconds,
|
|
3733
|
+
terminalReason: null,
|
|
3734
|
+
staleReason: input.staleReason || "The active phase heartbeat is stale.",
|
|
3735
|
+
safeNextAction: input.nextAction || safeWatchAction
|
|
3736
|
+
};
|
|
3737
|
+
}
|
|
3738
|
+
return {
|
|
3739
|
+
kind: "running_healthy",
|
|
3740
|
+
label: "Running and healthy",
|
|
3741
|
+
reviewable: false,
|
|
3742
|
+
terminal: false,
|
|
3743
|
+
stale: false,
|
|
3744
|
+
phase: input.phase,
|
|
3745
|
+
phaseStatus: input.phaseStatus,
|
|
3746
|
+
heartbeatAgeSeconds,
|
|
3747
|
+
nextPollAfterSeconds: input.nextPollAfterSeconds,
|
|
3748
|
+
terminalReason: null,
|
|
3749
|
+
staleReason: null,
|
|
3750
|
+
safeNextAction: input.nextAction || safeWatchAction
|
|
3751
|
+
};
|
|
3752
|
+
}
|
|
3753
|
+
return {
|
|
3754
|
+
kind: "unknown",
|
|
3755
|
+
label: "Unknown build state",
|
|
3756
|
+
reviewable: false,
|
|
3757
|
+
terminal: false,
|
|
3758
|
+
stale,
|
|
3759
|
+
phase: input.phase,
|
|
3760
|
+
phaseStatus: input.phaseStatus,
|
|
3761
|
+
heartbeatAgeSeconds,
|
|
3762
|
+
nextPollAfterSeconds: input.nextPollAfterSeconds,
|
|
3763
|
+
terminalReason: input.terminalReason,
|
|
3764
|
+
staleReason: input.staleReason,
|
|
3765
|
+
safeNextAction: input.nextAction || "Read campaign build status again before making a launch or delivery decision."
|
|
3766
|
+
};
|
|
3767
|
+
}
|
|
3355
3768
|
function mapAgentCampaignBuildStatus(data) {
|
|
3769
|
+
const customerRowCounts = mapAgentCustomerRowCounts(data.customer_row_counts);
|
|
3770
|
+
const phaseHealth = mapAgentCampaignPhaseHealth(data.phases);
|
|
3771
|
+
const terminalReason = stringValue(data.terminal_reason) ?? customerRowCounts?.terminalReason ?? null;
|
|
3772
|
+
const staleReason = stringValue(data.stale_reason) ?? stringValue(asRecord(data.diagnostics).stale_reason) ?? null;
|
|
3773
|
+
const nextPollAfterSeconds = numberOrNull2(data.next_poll_after_seconds ?? data.nextPollAfterSeconds);
|
|
3774
|
+
const terminalState = deriveCampaignBuildTerminalState({
|
|
3775
|
+
status: stringValue(data.status) ?? "unknown",
|
|
3776
|
+
phase: stringValue(data.current_phase) ?? null,
|
|
3777
|
+
phaseStatus: stringValue(data.current_phase_status) ?? null,
|
|
3778
|
+
staleRunningPhase: data.stale_running_phase === true,
|
|
3779
|
+
phaseAgeSeconds: numberOrNull2(data.phase_age_seconds),
|
|
3780
|
+
nextPollAfterSeconds,
|
|
3781
|
+
terminalReason,
|
|
3782
|
+
staleReason,
|
|
3783
|
+
nextAction: formatAgentNextAction(data.next_action),
|
|
3784
|
+
approvalAction: formatAgentNextAction(data.approval_action),
|
|
3785
|
+
triggerRunId: stringValue(data.trigger_run_id) ?? null
|
|
3786
|
+
});
|
|
3356
3787
|
return {
|
|
3357
3788
|
campaignBuildId: stringValue(data.campaign_build_id) ?? "",
|
|
3358
3789
|
campaignId: stringValue(data.campaign_id) ?? null,
|
|
@@ -3370,12 +3801,18 @@ function mapAgentCampaignBuildStatus(data) {
|
|
|
3370
3801
|
errors: diagnosticMessages2(data.errors),
|
|
3371
3802
|
artifactCount: numberOrUndefined2(data.artifact_count) ?? 0,
|
|
3372
3803
|
artifactDownloads: Array.isArray(data.artifact_downloads) ? data.artifact_downloads.map(mapAgentCampaignArtifactDownload) : [],
|
|
3373
|
-
customerRowCounts
|
|
3804
|
+
customerRowCounts,
|
|
3374
3805
|
phaseAttemptTotals: nullableRecord(data.phase_attempt_totals) ?? void 0,
|
|
3375
3806
|
providerRoute: mapProviderRoute2(data),
|
|
3376
3807
|
triggerRunId: stringValue(data.trigger_run_id) ?? null,
|
|
3377
3808
|
staleRunningPhase: data.stale_running_phase === true,
|
|
3378
3809
|
phaseAgeSeconds: numberOrNull2(data.phase_age_seconds),
|
|
3810
|
+
nextPollAfterSeconds,
|
|
3811
|
+
terminalReason,
|
|
3812
|
+
staleReason,
|
|
3813
|
+
safeNextAction: terminalState.safeNextAction,
|
|
3814
|
+
terminalState,
|
|
3815
|
+
phaseHealth,
|
|
3379
3816
|
diagnostics: nullableRecord(data.diagnostics) ?? {},
|
|
3380
3817
|
nextAction: formatAgentNextAction(data.next_action),
|
|
3381
3818
|
approvalAction: formatAgentNextAction(data.approval_action),
|
|
@@ -3405,6 +3842,7 @@ function mapAgentCustomerRowCounts(value) {
|
|
|
3405
3842
|
acceptedRows: numberOrUndefined2(record.accepted_rows),
|
|
3406
3843
|
usableRows: numberOrUndefined2(record.usable_rows),
|
|
3407
3844
|
copiedRows: numberOrUndefined2(record.copied_rows),
|
|
3845
|
+
copySkippedRows: numberOrUndefined2(record.copy_skipped_rows),
|
|
3408
3846
|
approvalReadyRows: numberOrUndefined2(record.approval_ready_rows),
|
|
3409
3847
|
qaReadyRows: numberOrUndefined2(record.qa_ready_rows),
|
|
3410
3848
|
deliveredRows: numberOrUndefined2(record.delivered_rows),
|
|
@@ -3463,67 +3901,276 @@ function mapAgentCampaignArtifact(data) {
|
|
|
3463
3901
|
createdAt: stringValue(data.created_at) ?? ""
|
|
3464
3902
|
};
|
|
3465
3903
|
}
|
|
3904
|
+
function campaignReviewGate(id, label, status, detail) {
|
|
3905
|
+
return {
|
|
3906
|
+
id,
|
|
3907
|
+
label,
|
|
3908
|
+
status,
|
|
3909
|
+
passed: status !== "blocked",
|
|
3910
|
+
detail
|
|
3911
|
+
};
|
|
3912
|
+
}
|
|
3913
|
+
function northStarMetric(id, label, status, detail, value, target) {
|
|
3914
|
+
return {
|
|
3915
|
+
id,
|
|
3916
|
+
label,
|
|
3917
|
+
status,
|
|
3918
|
+
detail,
|
|
3919
|
+
...value !== void 0 ? { value } : {},
|
|
3920
|
+
...target !== void 0 ? { target } : {}
|
|
3921
|
+
};
|
|
3922
|
+
}
|
|
3923
|
+
function createCampaignBuilderNorthStarScorecard(status, rows, artifacts, terminalState) {
|
|
3924
|
+
if (!terminalState.reviewable) {
|
|
3925
|
+
const pendingMetric = northStarMetric(
|
|
3926
|
+
"terminal_state",
|
|
3927
|
+
"Terminal-state contract",
|
|
3928
|
+
terminalState.kind === "running_stale" ? "blocked" : "pending",
|
|
3929
|
+
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.`,
|
|
3930
|
+
terminalState.kind,
|
|
3931
|
+
"terminal or pending_approval"
|
|
3932
|
+
);
|
|
3933
|
+
return {
|
|
3934
|
+
version: "campaign-builder-north-star.v1",
|
|
3935
|
+
status: pendingMetric.status,
|
|
3936
|
+
score: null,
|
|
3937
|
+
moatState: "scaffolding_ready",
|
|
3938
|
+
metrics: [pendingMetric],
|
|
3939
|
+
blockers: pendingMetric.status === "blocked" ? [pendingMetric.detail] : [],
|
|
3940
|
+
warnings: pendingMetric.status === "pending" ? [pendingMetric.detail] : [],
|
|
3941
|
+
nextAction: terminalState.safeNextAction
|
|
3942
|
+
};
|
|
3943
|
+
}
|
|
3944
|
+
const sampledRows = rows.rows.length;
|
|
3945
|
+
const rowData = rows.rows.map((row) => asRecord(row.data));
|
|
3946
|
+
const requestedTarget = status.customerRowCounts?.requestedTarget ?? status.recordsTotal ?? rows.count;
|
|
3947
|
+
const finalRows = status.customerRowCounts?.deliveredRows ?? status.customerRowCounts?.qaReadyRows ?? status.customerRowCounts?.copySkippedRows ?? status.customerRowCounts?.copiedRows ?? status.customerRowCounts?.acceptedRows ?? rows.count;
|
|
3948
|
+
const rowsWithEmail = rows.rows.filter(campaignReviewRowHasEmail).length;
|
|
3949
|
+
const verifiedEmailRows = rowData.filter(campaignReviewDataHasVerifiedEmail).length;
|
|
3950
|
+
const uniqueEmails = new Set(rowData.map(campaignReviewDataEmail).filter(Boolean)).size;
|
|
3951
|
+
const uniqueDomains = new Set(rowData.map(campaignReviewDataDomain).filter(Boolean)).size;
|
|
3952
|
+
const copyReadyRows = rows.rows.filter(campaignReviewRowHasCopy).length;
|
|
3953
|
+
const copyQaIssuesByRow = rowData.map(campaignReviewDataCopyQaIssues).filter((issues) => issues.length > 0);
|
|
3954
|
+
const copyQaIssueCounts = countCampaignReviewIssues(copyQaIssuesByRow);
|
|
3955
|
+
const signalBackedRows = rowData.filter(campaignReviewDataHasSignalBasis).length;
|
|
3956
|
+
const noSupportedSignalRows = rowData.filter(campaignReviewDataHasNoSupportedSignal).length;
|
|
3957
|
+
const unsupportedSignalClaims = rowData.filter(campaignReviewDataHasUnsupportedSignalClaim).length;
|
|
3958
|
+
const approvalLockedRows = rowData.filter(campaignReviewDataHasApprovalLock).length;
|
|
3959
|
+
const holdoutRows = rowData.filter(campaignReviewDataHasHoldoutAttribution).length;
|
|
3960
|
+
const artifactCount = artifacts.length || status.artifactCount || 0;
|
|
3961
|
+
const deliveredRows = status.customerRowCounts?.deliveredRows ?? 0;
|
|
3962
|
+
const feedbackReady = campaignReviewStatusHasFeedbackReadiness(status);
|
|
3963
|
+
const feedbackRequiredForApproval = terminalState.kind === "pending_approval";
|
|
3964
|
+
const moat = campaignReviewMoatState(status, holdoutRows);
|
|
3965
|
+
const metrics = [
|
|
3966
|
+
northStarMetric(
|
|
3967
|
+
"terminal_state",
|
|
3968
|
+
"Terminal-state contract",
|
|
3969
|
+
terminalState.kind === "blocked" ? "blocked" : "pass",
|
|
3970
|
+
terminalState.label,
|
|
3971
|
+
terminalState.kind,
|
|
3972
|
+
"terminal or pending_approval"
|
|
3973
|
+
),
|
|
3974
|
+
northStarMetric(
|
|
3975
|
+
"target_fill",
|
|
3976
|
+
"Target fill",
|
|
3977
|
+
requestedTarget && finalRows < requestedTarget ? "review" : "pass",
|
|
3978
|
+
requestedTarget ? `${finalRows || 0}/${requestedTarget} final or reviewable row(s) are accounted for.` : "No requested target was reported; using sampled rows for review.",
|
|
3979
|
+
finalRows || sampledRows,
|
|
3980
|
+
requestedTarget || sampledRows
|
|
3981
|
+
),
|
|
3982
|
+
northStarMetric(
|
|
3983
|
+
"unique_emails",
|
|
3984
|
+
"Unique emails",
|
|
3985
|
+
sampledRows === 0 ? "blocked" : uniqueEmails === rowsWithEmail ? "pass" : "blocked",
|
|
3986
|
+
sampledRows === 0 ? "No sampled rows were available for email uniqueness review." : `${uniqueEmails}/${rowsWithEmail} sampled email(s) are unique.`,
|
|
3987
|
+
uniqueEmails,
|
|
3988
|
+
rowsWithEmail
|
|
3989
|
+
),
|
|
3990
|
+
northStarMetric(
|
|
3991
|
+
"unique_domains",
|
|
3992
|
+
"Unique domains",
|
|
3993
|
+
sampledRows === 0 ? "blocked" : uniqueDomains === sampledRows ? "pass" : "review",
|
|
3994
|
+
sampledRows === 0 ? "No sampled rows were available for domain uniqueness review." : `${uniqueDomains}/${sampledRows} sampled company domain(s) are unique.`,
|
|
3995
|
+
uniqueDomains,
|
|
3996
|
+
sampledRows
|
|
3997
|
+
),
|
|
3998
|
+
northStarMetric(
|
|
3999
|
+
"verified_email_rows",
|
|
4000
|
+
"Verified email rows",
|
|
4001
|
+
sampledRows === 0 ? "blocked" : verifiedEmailRows === sampledRows ? "pass" : rowsWithEmail === sampledRows ? "review" : "blocked",
|
|
4002
|
+
sampledRows === 0 ? "No sampled rows were available for email verification review." : `${verifiedEmailRows}/${sampledRows} sampled row(s) carry verified-email evidence.`,
|
|
4003
|
+
verifiedEmailRows,
|
|
4004
|
+
sampledRows
|
|
4005
|
+
),
|
|
4006
|
+
northStarMetric(
|
|
4007
|
+
"copy_completeness",
|
|
4008
|
+
"Copy completeness",
|
|
4009
|
+
sampledRows === 0 ? "blocked" : copyReadyRows === sampledRows ? "pass" : "blocked",
|
|
4010
|
+
sampledRows === 0 ? "No sampled rows were available for copy review." : `${copyReadyRows}/${sampledRows} sampled row(s) include generated copy.`,
|
|
4011
|
+
copyReadyRows,
|
|
4012
|
+
sampledRows
|
|
4013
|
+
),
|
|
4014
|
+
northStarMetric(
|
|
4015
|
+
"copy_quality",
|
|
4016
|
+
"Copy QA",
|
|
4017
|
+
copyQaIssuesByRow.length === 0 ? "pass" : "blocked",
|
|
4018
|
+
copyQaIssuesByRow.length === 0 ? "No sampled copy QA blockers were detected." : `${copyQaIssuesByRow.length}/${sampledRows} sampled row(s) have copy QA issue(s): ${formatCampaignReviewIssueCounts(copyQaIssueCounts)}.`,
|
|
4019
|
+
copyQaIssuesByRow.length,
|
|
4020
|
+
0
|
|
4021
|
+
),
|
|
4022
|
+
northStarMetric(
|
|
4023
|
+
"signal_grounding",
|
|
4024
|
+
"Signal grounding",
|
|
4025
|
+
unsupportedSignalClaims > 0 ? "blocked" : signalBackedRows > 0 ? "pass" : "review",
|
|
4026
|
+
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.",
|
|
4027
|
+
signalBackedRows,
|
|
4028
|
+
sampledRows
|
|
4029
|
+
),
|
|
4030
|
+
northStarMetric(
|
|
4031
|
+
"approval_locks",
|
|
4032
|
+
"Approval locks",
|
|
4033
|
+
approvalLockedRows > 0 || deliveredRows === 0 ? "pass" : "review",
|
|
4034
|
+
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.",
|
|
4035
|
+
approvalLockedRows,
|
|
4036
|
+
sampledRows
|
|
4037
|
+
),
|
|
4038
|
+
northStarMetric(
|
|
4039
|
+
"export_send_safety",
|
|
4040
|
+
"Export/send safety",
|
|
4041
|
+
deliveredRows > 0 && status.status !== "completed" ? "blocked" : "pass",
|
|
4042
|
+
deliveredRows > 0 ? `${deliveredRows} row(s) are delivered; status is ${status.status}.` : "No delivered rows are reported before approval.",
|
|
4043
|
+
deliveredRows,
|
|
4044
|
+
0
|
|
4045
|
+
),
|
|
4046
|
+
northStarMetric(
|
|
4047
|
+
"holdout_attribution",
|
|
4048
|
+
"Holdout attribution",
|
|
4049
|
+
holdoutRows > 0 ? "pass" : "review",
|
|
4050
|
+
holdoutRows > 0 ? `${holdoutRows}/${sampledRows} sampled row(s) preserve holdout attribution.` : "No holdout attribution was visible in the sampled rows.",
|
|
4051
|
+
holdoutRows,
|
|
4052
|
+
sampledRows
|
|
4053
|
+
),
|
|
4054
|
+
northStarMetric(
|
|
4055
|
+
"feedback_readiness",
|
|
4056
|
+
"Feedback readiness",
|
|
4057
|
+
feedbackReady ? "pass" : feedbackRequiredForApproval ? "blocked" : "review",
|
|
4058
|
+
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.",
|
|
4059
|
+
feedbackReady,
|
|
4060
|
+
true
|
|
4061
|
+
),
|
|
4062
|
+
northStarMetric(
|
|
4063
|
+
"causal_moat",
|
|
4064
|
+
"Causal moat",
|
|
4065
|
+
moat.state === "proved" ? "pass" : "review",
|
|
4066
|
+
moat.detail,
|
|
4067
|
+
moat.state,
|
|
4068
|
+
"proved"
|
|
4069
|
+
),
|
|
4070
|
+
northStarMetric(
|
|
4071
|
+
"artifact_readback",
|
|
4072
|
+
"Artifact readback",
|
|
4073
|
+
artifactCount > 0 ? "pass" : "review",
|
|
4074
|
+
artifactCount > 0 ? `${artifactCount} artifact(s) are available for review.` : "No review artifact is available yet.",
|
|
4075
|
+
artifactCount,
|
|
4076
|
+
1
|
|
4077
|
+
)
|
|
4078
|
+
];
|
|
4079
|
+
const gradedMetrics = metrics.filter((metric) => metric.status !== "pending");
|
|
4080
|
+
const score = gradedMetrics.length === 0 ? null : Math.round(gradedMetrics.filter((metric) => metric.status === "pass").length / gradedMetrics.length * 100);
|
|
4081
|
+
const blockers = metrics.filter((metric) => metric.status === "blocked").map((metric) => metric.detail);
|
|
4082
|
+
const warnings = metrics.filter((metric) => metric.status === "review").map((metric) => metric.detail);
|
|
4083
|
+
const scorecardStatus = blockers.length > 0 ? "blocked" : warnings.length > 0 ? "review" : "pass";
|
|
4084
|
+
return {
|
|
4085
|
+
version: "campaign-builder-north-star.v1",
|
|
4086
|
+
status: scorecardStatus,
|
|
4087
|
+
score,
|
|
4088
|
+
moatState: moat.state,
|
|
4089
|
+
metrics,
|
|
4090
|
+
blockers,
|
|
4091
|
+
warnings,
|
|
4092
|
+
nextAction: scorecardStatus === "blocked" ? "Fix blocked North Star gates before approval or delivery." : terminalState.safeNextAction
|
|
4093
|
+
};
|
|
4094
|
+
}
|
|
3466
4095
|
function createCampaignBuilderBuildReview(status, rows, artifacts) {
|
|
4096
|
+
const terminalState = status.terminalState ?? deriveCampaignBuildTerminalState({
|
|
4097
|
+
status: status.status,
|
|
4098
|
+
phase: status.currentPhase,
|
|
4099
|
+
phaseStatus: status.currentPhaseStatus,
|
|
4100
|
+
staleRunningPhase: status.staleRunningPhase === true,
|
|
4101
|
+
phaseAgeSeconds: status.phaseAgeSeconds ?? null,
|
|
4102
|
+
nextPollAfterSeconds: status.nextPollAfterSeconds ?? null,
|
|
4103
|
+
terminalReason: status.terminalReason ?? status.customerRowCounts?.terminalReason ?? null,
|
|
4104
|
+
staleReason: status.staleReason ?? null,
|
|
4105
|
+
nextAction: status.nextAction,
|
|
4106
|
+
approvalAction: status.approvalAction,
|
|
4107
|
+
triggerRunId: status.triggerRunId ?? null
|
|
4108
|
+
});
|
|
3467
4109
|
const sampledRows = rows.rows.length;
|
|
3468
4110
|
const availableRows = rows.count || sampledRows;
|
|
3469
4111
|
const qualifiedRows = rows.rows.filter((row) => row.qualified !== false).length;
|
|
3470
4112
|
const rowsWithEmail = rows.rows.filter(campaignReviewRowHasEmail).length;
|
|
3471
4113
|
const copyReadyRows = rows.rows.filter(campaignReviewRowHasCopy).length;
|
|
3472
4114
|
const artifactCount = artifacts.length || status.artifactCount || 0;
|
|
4115
|
+
const northStarScorecard = createCampaignBuilderNorthStarScorecard(status, rows, artifacts, terminalState);
|
|
3473
4116
|
const gates = [
|
|
3474
|
-
|
|
3475
|
-
|
|
3476
|
-
|
|
3477
|
-
|
|
3478
|
-
|
|
3479
|
-
|
|
3480
|
-
|
|
3481
|
-
|
|
3482
|
-
|
|
3483
|
-
|
|
3484
|
-
|
|
3485
|
-
|
|
3486
|
-
|
|
3487
|
-
|
|
3488
|
-
|
|
3489
|
-
|
|
3490
|
-
|
|
3491
|
-
|
|
3492
|
-
|
|
3493
|
-
|
|
3494
|
-
|
|
3495
|
-
|
|
3496
|
-
|
|
3497
|
-
|
|
3498
|
-
|
|
3499
|
-
|
|
3500
|
-
|
|
3501
|
-
|
|
3502
|
-
|
|
3503
|
-
|
|
3504
|
-
|
|
3505
|
-
|
|
3506
|
-
|
|
3507
|
-
|
|
3508
|
-
|
|
3509
|
-
|
|
4117
|
+
campaignReviewGate(
|
|
4118
|
+
"build_reviewable",
|
|
4119
|
+
"Build reviewable",
|
|
4120
|
+
terminalState.kind === "running_healthy" ? "pending" : terminalState.kind === "running_stale" || terminalState.kind === "blocked" ? "blocked" : "pass",
|
|
4121
|
+
terminalState.label
|
|
4122
|
+
),
|
|
4123
|
+
campaignReviewGate(
|
|
4124
|
+
"rows_available",
|
|
4125
|
+
"Rows available",
|
|
4126
|
+
sampledRows > 0 ? "pass" : terminalState.reviewable ? "blocked" : "pending",
|
|
4127
|
+
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."
|
|
4128
|
+
),
|
|
4129
|
+
campaignReviewGate(
|
|
4130
|
+
"qualified_sample",
|
|
4131
|
+
"Sample rows qualified",
|
|
4132
|
+
sampledRows === 0 ? terminalState.reviewable ? "blocked" : "pending" : qualifiedRows === sampledRows ? "pass" : "blocked",
|
|
4133
|
+
sampledRows > 0 ? `${qualifiedRows}/${sampledRows} sampled row(s) are marked qualified.` : "Qualification could not be checked without sampled rows."
|
|
4134
|
+
),
|
|
4135
|
+
campaignReviewGate(
|
|
4136
|
+
"email_coverage",
|
|
4137
|
+
"Email coverage",
|
|
4138
|
+
sampledRows === 0 ? terminalState.reviewable ? "blocked" : "pending" : rowsWithEmail === sampledRows ? "pass" : "blocked",
|
|
4139
|
+
sampledRows > 0 ? `${rowsWithEmail}/${sampledRows} sampled row(s) include an email.` : "Email coverage could not be checked without sampled rows."
|
|
4140
|
+
),
|
|
4141
|
+
campaignReviewGate(
|
|
4142
|
+
"artifact_available",
|
|
4143
|
+
"Artifact available",
|
|
4144
|
+
artifactCount > 0 ? "pass" : terminalState.reviewable ? "review" : "pending",
|
|
4145
|
+
artifactCount > 0 ? `${artifactCount} artifact(s) are available.` : "No delivery artifact is available yet."
|
|
4146
|
+
),
|
|
4147
|
+
campaignReviewGate(
|
|
4148
|
+
"no_failed_rows",
|
|
4149
|
+
"No failed rows",
|
|
4150
|
+
status.recordsFailed === 0 ? "pass" : "blocked",
|
|
4151
|
+
status.recordsFailed === 0 ? "The build reports zero failed rows." : `${status.recordsFailed} row(s) failed during the build.`
|
|
4152
|
+
)
|
|
3510
4153
|
];
|
|
3511
|
-
const blockedReasons = gates.filter((gate) => !gate.passed).map((gate) => gate.detail);
|
|
4154
|
+
const blockedReasons = gates.filter((gate) => gate.status === "blocked" || !gate.passed).map((gate) => gate.detail);
|
|
3512
4155
|
const warnings = [
|
|
3513
4156
|
rows.hasMore ? "This review is based on a row sample; page through remaining rows before final approval." : void 0,
|
|
3514
4157
|
sampledRows > 0 && copyReadyRows < sampledRows ? `${copyReadyRows}/${sampledRows} sampled row(s) include generated copy.` : void 0,
|
|
3515
4158
|
...status.warnings
|
|
3516
4159
|
].filter((item) => Boolean(item));
|
|
3517
|
-
const readyForDeliveryApproval = blockedReasons.length === 0;
|
|
4160
|
+
const readyForDeliveryApproval = terminalState.reviewable && blockedReasons.length === 0 && northStarScorecard.status !== "blocked";
|
|
3518
4161
|
return {
|
|
3519
4162
|
campaignBuildId: status.campaignBuildId || rows.campaignBuildId,
|
|
3520
4163
|
status,
|
|
3521
4164
|
rows,
|
|
3522
4165
|
artifacts,
|
|
3523
4166
|
gates,
|
|
4167
|
+
northStarScorecard,
|
|
3524
4168
|
summary: {
|
|
3525
4169
|
status: status.status,
|
|
3526
4170
|
phase: status.currentPhase,
|
|
4171
|
+
terminalState: terminalState.kind,
|
|
4172
|
+
scorecardStatus: northStarScorecard.status,
|
|
4173
|
+
scorecardScore: northStarScorecard.score,
|
|
3527
4174
|
sampledRows,
|
|
3528
4175
|
availableRows,
|
|
3529
4176
|
qualifiedRows,
|
|
@@ -3577,6 +4224,184 @@ function campaignReviewRowHasCopy(row) {
|
|
|
3577
4224
|
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)
|
|
3578
4225
|
);
|
|
3579
4226
|
}
|
|
4227
|
+
function campaignReviewDataEmail(data) {
|
|
4228
|
+
return stringValue(data.email) || stringValue(data.work_email) || stringValue(data.workEmail) || stringValue(asRecord(data.contact).email);
|
|
4229
|
+
}
|
|
4230
|
+
function campaignReviewDataDomain(data) {
|
|
4231
|
+
const domain = stringValue(data.company_domain) || stringValue(data.companyDomain) || stringValue(asRecord(data.company).domain);
|
|
4232
|
+
return domain?.toLowerCase();
|
|
4233
|
+
}
|
|
4234
|
+
function campaignReviewDataHasVerifiedEmail(data) {
|
|
4235
|
+
const status = String(data.email_status ?? data.emailStatus ?? asRecord(data.contact).email_status ?? "").toLowerCase();
|
|
4236
|
+
return data.email_verified === true || data.emailVerified === true || asRecord(data.contact).email_verified === true || ["valid", "validated", "verified"].includes(status);
|
|
4237
|
+
}
|
|
4238
|
+
function campaignReviewDataCopyParts(data) {
|
|
4239
|
+
const copy = asRecord(data.copy);
|
|
4240
|
+
const rawCopy = asRecord(data.raw_copy ?? data.rawCopy);
|
|
4241
|
+
return [
|
|
4242
|
+
stringValue(data.subject),
|
|
4243
|
+
stringValue(data.subject_line),
|
|
4244
|
+
stringValue(data.opener),
|
|
4245
|
+
stringValue(data.body),
|
|
4246
|
+
stringValue(data.cta),
|
|
4247
|
+
stringValue(copy.subject),
|
|
4248
|
+
stringValue(copy.opener),
|
|
4249
|
+
stringValue(copy.body),
|
|
4250
|
+
stringValue(copy.cta),
|
|
4251
|
+
stringValue(rawCopy.subject),
|
|
4252
|
+
stringValue(rawCopy.opener),
|
|
4253
|
+
stringValue(rawCopy.body),
|
|
4254
|
+
stringValue(rawCopy.cta)
|
|
4255
|
+
].filter((part) => Boolean(part));
|
|
4256
|
+
}
|
|
4257
|
+
function campaignReviewDataHasBadGreeting(data) {
|
|
4258
|
+
return campaignReviewDataCopyParts(data).some(
|
|
4259
|
+
(part) => /\bhi\s*(?:,|\{\{|\[)|\bhello\s*(?:,|\{\{|\[)/i.test(part) || /\b(first_name|firstname|name)\b/i.test(part)
|
|
4260
|
+
);
|
|
4261
|
+
}
|
|
4262
|
+
function campaignReviewDataHasBannedPhrase(data) {
|
|
4263
|
+
const text = campaignReviewDataCopyParts(data).join(" ").toLowerCase();
|
|
4264
|
+
return NORTH_STAR_BANNED_COPY_PHRASES.some((phrase) => text.includes(phrase));
|
|
4265
|
+
}
|
|
4266
|
+
function campaignReviewDataSubject(data) {
|
|
4267
|
+
const copy = asRecord(data.copy);
|
|
4268
|
+
const rawCopy = asRecord(data.raw_copy ?? data.rawCopy);
|
|
4269
|
+
return stringValue(data.subject) || stringValue(data.subject_line) || stringValue(data.subjectLine) || stringValue(copy.subject) || stringValue(rawCopy.subject);
|
|
4270
|
+
}
|
|
4271
|
+
function campaignReviewDataCta(data) {
|
|
4272
|
+
const copy = asRecord(data.copy);
|
|
4273
|
+
const rawCopy = asRecord(data.raw_copy ?? data.rawCopy);
|
|
4274
|
+
return stringValue(data.cta) || stringValue(copy.cta) || stringValue(rawCopy.cta);
|
|
4275
|
+
}
|
|
4276
|
+
function countCampaignReviewIssues(issueRows) {
|
|
4277
|
+
return issueRows.flat().reduce((acc, issue) => {
|
|
4278
|
+
acc[issue] = (acc[issue] || 0) + 1;
|
|
4279
|
+
return acc;
|
|
4280
|
+
}, {});
|
|
4281
|
+
}
|
|
4282
|
+
function formatCampaignReviewIssueCounts(counts) {
|
|
4283
|
+
const entries = Object.entries(counts);
|
|
4284
|
+
return entries.length > 0 ? entries.map(([issue, count]) => `${issue}=${count}`).join(", ") : "none";
|
|
4285
|
+
}
|
|
4286
|
+
function campaignReviewDataCopyQaIssues(data) {
|
|
4287
|
+
const issues = /* @__PURE__ */ new Set();
|
|
4288
|
+
const copyParts = campaignReviewDataCopyParts(data);
|
|
4289
|
+
if (copyParts.length === 0) return [];
|
|
4290
|
+
if (campaignReviewDataHasBadGreeting(data)) issues.add("bad_greeting");
|
|
4291
|
+
if (campaignReviewDataHasBannedPhrase(data)) issues.add("banned_or_vague_phrase");
|
|
4292
|
+
if (campaignReviewDataHasUnsupportedSignalClaim(data)) issues.add("unsupported_signal_claim");
|
|
4293
|
+
if (campaignReviewDataPersonalizationBasis(data).length === 0) issues.add("missing_personalization_basis");
|
|
4294
|
+
if (!campaignReviewDataCta(data)) issues.add("missing_cta");
|
|
4295
|
+
const subject = campaignReviewDataSubject(data);
|
|
4296
|
+
if (subject && subject.length > 70) issues.add("overlong_subject");
|
|
4297
|
+
return [...issues];
|
|
4298
|
+
}
|
|
4299
|
+
function campaignReviewDataPersonalizationBasis(data) {
|
|
4300
|
+
const rawCopy = asRecord(data.raw_copy ?? data.rawCopy);
|
|
4301
|
+
const copy = asRecord(data.copy);
|
|
4302
|
+
const metadata = asRecord(data.metadata);
|
|
4303
|
+
const signalEvidence = asRecord(data.signal_evidence ?? metadata.signal_evidence ?? metadata.signalEvidence);
|
|
4304
|
+
return [
|
|
4305
|
+
...arrayOfStrings(data.personalization_basis) ?? [],
|
|
4306
|
+
...arrayOfStrings(data.personalizationBasis) ?? [],
|
|
4307
|
+
...arrayOfStrings(copy.personalization_basis) ?? [],
|
|
4308
|
+
...arrayOfStrings(rawCopy.personalization_basis) ?? [],
|
|
4309
|
+
...arrayOfStrings(metadata.personalization_basis) ?? [],
|
|
4310
|
+
...arrayOfStrings(metadata.personalizationBasis) ?? [],
|
|
4311
|
+
...arrayOfStrings(signalEvidence.personalization_basis) ?? []
|
|
4312
|
+
];
|
|
4313
|
+
}
|
|
4314
|
+
function campaignReviewDataHasNoSupportedSignal(data) {
|
|
4315
|
+
const metadata = asRecord(data.metadata);
|
|
4316
|
+
const copy = asRecord(data.copy);
|
|
4317
|
+
const state = [
|
|
4318
|
+
data.copy_signal_state,
|
|
4319
|
+
data.signal_basis,
|
|
4320
|
+
data.signal_type,
|
|
4321
|
+
metadata.copy_signal_state,
|
|
4322
|
+
metadata.signal_basis,
|
|
4323
|
+
metadata.signal_type,
|
|
4324
|
+
copy.copy_signal_state
|
|
4325
|
+
].map((value) => stringValue(value)?.toLowerCase()).filter(Boolean);
|
|
4326
|
+
return data.no_supported_signal === true || metadata.no_supported_signal === true || state.includes("no_supported_signal");
|
|
4327
|
+
}
|
|
4328
|
+
function campaignReviewDataHasSignalBasis(data) {
|
|
4329
|
+
if (campaignReviewDataHasNoSupportedSignal(data)) return false;
|
|
4330
|
+
const metadata = asRecord(data.metadata);
|
|
4331
|
+
const signal = asRecord(data.signal);
|
|
4332
|
+
const signalEvidence = asRecord(data.signal_evidence ?? metadata.signal_evidence ?? metadata.signalEvidence);
|
|
4333
|
+
const basis = campaignReviewDataPersonalizationBasis(data);
|
|
4334
|
+
return Boolean(
|
|
4335
|
+
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))
|
|
4336
|
+
);
|
|
4337
|
+
}
|
|
4338
|
+
function campaignReviewDataHasUnsupportedSignalClaim(data) {
|
|
4339
|
+
const copyText = campaignReviewDataCopyParts(data).join(" ").toLowerCase();
|
|
4340
|
+
const claimsSignal = /\b(hiring|funding|raised|launched|expanding|appointed|announced|recent news|new role|job posting)\b/.test(copyText);
|
|
4341
|
+
return claimsSignal && !campaignReviewDataHasSignalBasis(data);
|
|
4342
|
+
}
|
|
4343
|
+
function campaignReviewDataHasApprovalLock(data) {
|
|
4344
|
+
const metadata = asRecord(data.fit_metadata ?? data.metadata);
|
|
4345
|
+
const approval = String(data.approval_status ?? data.delivery_approval_status ?? metadata.approval_status ?? "").toLowerCase();
|
|
4346
|
+
const exportStatus = String(data.export_status ?? data.exportStatus ?? "").toLowerCase();
|
|
4347
|
+
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);
|
|
4348
|
+
}
|
|
4349
|
+
function campaignReviewDataHasHoldoutAttribution(data) {
|
|
4350
|
+
const fitMetadata = asRecord(data.fit_metadata ?? data.fitMetadata);
|
|
4351
|
+
const metadata = asRecord(data.metadata);
|
|
4352
|
+
const holdout = asRecord(
|
|
4353
|
+
fitMetadata.learning_holdout ?? fitMetadata.learningHoldout ?? metadata.learning_holdout ?? metadata.learningHoldout ?? data.learning_holdout ?? data.learningHoldout
|
|
4354
|
+
);
|
|
4355
|
+
const experimentKey = stringValue(holdout.experiment_key ?? holdout.experimentKey ?? data.experiment_key ?? data.experimentKey);
|
|
4356
|
+
const cohort = stringValue(holdout.cohort_role ?? holdout.cohortRole ?? data.cohort_role ?? data.learning_cohort ?? data.learningCohort);
|
|
4357
|
+
const brainApplied = holdout.brain_applied ?? holdout.brainApplied ?? data.brain_applied ?? data.signaliz_brain_applied;
|
|
4358
|
+
return Boolean(experimentKey && cohort && brainApplied !== void 0);
|
|
4359
|
+
}
|
|
4360
|
+
function campaignReviewStatusHasFeedbackReadiness(status) {
|
|
4361
|
+
const diagnostics = asRecord(status.diagnostics);
|
|
4362
|
+
const feedbackReadiness = asRecord(diagnostics.feedback_readiness ?? diagnostics.feedbackReadiness);
|
|
4363
|
+
const feedbackSubstrate = asRecord(diagnostics.feedback_substrate ?? diagnostics.feedbackSubstrate);
|
|
4364
|
+
const evidenceCounts = asRecord(diagnostics.evidence_counts ?? diagnostics.evidenceCounts);
|
|
4365
|
+
return feedbackReadiness.ready === true || feedbackReadiness.webhook_configured === true || feedbackSubstrate.stage === "ready" || Number(evidenceCounts.feedback_events ?? 0) > 0;
|
|
4366
|
+
}
|
|
4367
|
+
function campaignReviewMoatState(status, holdoutRows) {
|
|
4368
|
+
const diagnostics = asRecord(status.diagnostics);
|
|
4369
|
+
const evidenceCounts = asRecord(diagnostics.evidence_counts ?? diagnostics.evidenceCounts);
|
|
4370
|
+
const embeddedHoldout = asRecord(diagnostics.embedded_holdout ?? diagnostics.embeddedHoldout);
|
|
4371
|
+
const holdoutLift = asRecord(diagnostics.holdout_lift ?? diagnostics.holdoutLift ?? diagnostics.holdout_measurement ?? diagnostics.holdoutMeasurement);
|
|
4372
|
+
const controlSample = Math.max(
|
|
4373
|
+
Number(evidenceCounts.holdout_control_sample_size ?? 0),
|
|
4374
|
+
Number(evidenceCounts.embedded_holdout_control_sample ?? 0),
|
|
4375
|
+
Number(embeddedHoldout.control_sample_size ?? 0)
|
|
4376
|
+
);
|
|
4377
|
+
const learnedSample = Math.max(
|
|
4378
|
+
Number(evidenceCounts.holdout_learned_sample_size ?? 0),
|
|
4379
|
+
Number(evidenceCounts.embedded_holdout_learned_sample ?? 0),
|
|
4380
|
+
Number(embeddedHoldout.learned_sample_size ?? 0)
|
|
4381
|
+
);
|
|
4382
|
+
const feedbackEvents = Math.max(
|
|
4383
|
+
Number(evidenceCounts.feedback_events ?? 0),
|
|
4384
|
+
Number(evidenceCounts.campaign_build_feedback_events ?? 0),
|
|
4385
|
+
Number(evidenceCounts.delivery_holdout_sent_outcomes ?? 0)
|
|
4386
|
+
);
|
|
4387
|
+
const proved = diagnostics.closed_loop_proof_ready === true || holdoutLift.honest_measurement === true && holdoutLift.positive_lift === true;
|
|
4388
|
+
if (proved) {
|
|
4389
|
+
return {
|
|
4390
|
+
state: "proved",
|
|
4391
|
+
detail: "Real attributed feedback shows positive lift for explicit control and learned cohorts."
|
|
4392
|
+
};
|
|
4393
|
+
}
|
|
4394
|
+
if (controlSample > 0 && learnedSample > 0 && feedbackEvents > 0) {
|
|
4395
|
+
return {
|
|
4396
|
+
state: "moved_needs_lift_volume",
|
|
4397
|
+
detail: `Control and learned cohorts have attributed feedback (${controlSample} control, ${learnedSample} learned, ${feedbackEvents} feedback event(s)); keep collecting lift volume before claiming proof.`
|
|
4398
|
+
};
|
|
4399
|
+
}
|
|
4400
|
+
return {
|
|
4401
|
+
state: "scaffolding_ready",
|
|
4402
|
+
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."
|
|
4403
|
+
};
|
|
4404
|
+
}
|
|
3580
4405
|
function createCampaignBuilderReadinessLane(route, plan) {
|
|
3581
4406
|
const builtIn = campaignBuilderBuiltInForRoute(route);
|
|
3582
4407
|
const customRoute = route.provider !== "signaliz" && route.provider !== "csv" && builtIn === void 0;
|
|
@@ -3610,6 +4435,342 @@ function createCampaignBuilderReadinessLane(route, plan) {
|
|
|
3610
4435
|
nextAction: customRoute ? `Review ${route.provider} route setup before launch approval.` : void 0
|
|
3611
4436
|
};
|
|
3612
4437
|
}
|
|
4438
|
+
function createCampaignBuilderApprovalPacket(plan, approval, missingTypes) {
|
|
4439
|
+
const requestedTypes = plan ? uniqueStrings(plan.approvals.filter((item) => item.blocking).map((item) => item.type)) : [];
|
|
4440
|
+
const approvalMatchesPlan = Boolean(plan && approval?.planId === plan.planId);
|
|
4441
|
+
const approvedTypes = approvalMatchesPlan ? approval?.approvedTypes ?? [] : [];
|
|
4442
|
+
const approvedRoutes = approvalMatchesPlan ? approval?.approvedRouteIds ?? [] : [];
|
|
4443
|
+
const missingIds = new Set(
|
|
4444
|
+
plan && approvalMatchesPlan && approval ? getMissingCampaignBuilderApprovals(plan, approval).map((item) => item.id) : plan?.approvals.filter((item) => item.blocking).map((item) => item.id) ?? []
|
|
4445
|
+
);
|
|
4446
|
+
const routeIdsRequired = plan ? uniqueStrings(plan.approvals.map((item) => item.routeId).filter((id) => Boolean(id))) : [];
|
|
4447
|
+
const spendLimitRequired = plan ? Math.max(0, ...plan.approvals.filter((item) => item.type === "spend" && item.blocking).map((item) => item.estimatedCredits ?? plan.estimatedCredits)) : 0;
|
|
4448
|
+
const normalizedSpendLimit = spendLimitRequired > 0 ? spendLimitRequired : null;
|
|
4449
|
+
const approvalState = !plan ? "unscoped" : missingTypes.length > 0 ? "requires_approval" : "approved";
|
|
4450
|
+
const approvalInput = {
|
|
4451
|
+
approved_by: approval?.approvedBy ?? null,
|
|
4452
|
+
approved_at: approval?.approvedAt ?? null,
|
|
4453
|
+
approved_types: approvedTypes,
|
|
4454
|
+
approved_route_ids: approvedRoutes,
|
|
4455
|
+
spend_limit_credits: approval?.spendLimitCredits ?? null,
|
|
4456
|
+
notes: approval?.notes
|
|
4457
|
+
};
|
|
4458
|
+
return {
|
|
4459
|
+
packet_version: "campaign-builder-approval-packet.v1",
|
|
4460
|
+
read_only: true,
|
|
4461
|
+
no_spend: true,
|
|
4462
|
+
no_provider_writes: true,
|
|
4463
|
+
private_safe: true,
|
|
4464
|
+
approval_state: approvalState,
|
|
4465
|
+
plan_id: plan?.planId ?? null,
|
|
4466
|
+
campaign_name: plan?.campaignName ?? null,
|
|
4467
|
+
requested_approval_types: requestedTypes,
|
|
4468
|
+
missing_approval_types: uniqueStrings(missingTypes),
|
|
4469
|
+
spend_limit_credits_required: normalizedSpendLimit,
|
|
4470
|
+
route_ids_required: routeIdsRequired,
|
|
4471
|
+
required_approvals: (plan?.approvals ?? []).map((item) => compact({
|
|
4472
|
+
id: item.id,
|
|
4473
|
+
type: item.type,
|
|
4474
|
+
label: item.label,
|
|
4475
|
+
reason: item.reason,
|
|
4476
|
+
blocking: item.blocking,
|
|
4477
|
+
route_id: item.routeId,
|
|
4478
|
+
provider: item.provider,
|
|
4479
|
+
estimated_credits: item.estimatedCredits,
|
|
4480
|
+
status: missingIds.has(item.id) ? "missing" : "approved"
|
|
4481
|
+
})),
|
|
4482
|
+
approval_input: approvalInput,
|
|
4483
|
+
cli_handoff: plan ? {
|
|
4484
|
+
command: campaignBuilderApprovalCliHandoff(requestedTypes, routeIdsRequired, normalizedSpendLimit),
|
|
4485
|
+
safety: "Template only: run after explicit human approval identity, approved types, route scope, and spend limit are filled in."
|
|
4486
|
+
} : null,
|
|
4487
|
+
sdk_handoff: plan ? {
|
|
4488
|
+
method: "campaignBuilderAgent.buildApprovedPlan",
|
|
4489
|
+
approval: compact({
|
|
4490
|
+
approvedBy: approval?.approvedBy ?? "<operator-email>",
|
|
4491
|
+
approvedTypes: requestedTypes,
|
|
4492
|
+
approvedRouteIds: routeIdsRequired,
|
|
4493
|
+
spendLimitCredits: normalizedSpendLimit ?? void 0,
|
|
4494
|
+
notes: approval?.notes
|
|
4495
|
+
}),
|
|
4496
|
+
options: {
|
|
4497
|
+
idempotencyKey: "<set-before-execution>"
|
|
4498
|
+
},
|
|
4499
|
+
safety: "Call only after the approval packet is accepted; this helper does not execute writes or spend."
|
|
4500
|
+
} : null,
|
|
4501
|
+
mcp_handoffs: plan ? campaignBuilderApprovalMcpHandoffs(plan, requestedTypes, routeIdsRequired, normalizedSpendLimit) : [],
|
|
4502
|
+
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."
|
|
4503
|
+
};
|
|
4504
|
+
}
|
|
4505
|
+
function campaignBuilderApprovalCliHandoff(requestedTypes, routeIds, spendLimit) {
|
|
4506
|
+
return [
|
|
4507
|
+
"signaliz campaign-agent build-approved --request-file campaign-request.json --confirm-launch",
|
|
4508
|
+
requestedTypes.length > 0 ? `--approved-types ${shellArg(requestedTypes.join(","))}` : "--approve-all",
|
|
4509
|
+
"--approved-by <operator-email>",
|
|
4510
|
+
spendLimit !== null ? `--spend-limit ${spendLimit}` : void 0,
|
|
4511
|
+
routeIds.length > 0 ? `--approved-route-ids ${shellArg(routeIds.join(","))}` : void 0
|
|
4512
|
+
].filter(Boolean).join(" ");
|
|
4513
|
+
}
|
|
4514
|
+
function campaignBuilderApprovalMcpHandoffs(plan, requestedTypes, routeIds, spendLimit) {
|
|
4515
|
+
const approvalContext = compact({
|
|
4516
|
+
plan_id: plan.planId,
|
|
4517
|
+
approval_types: requestedTypes,
|
|
4518
|
+
approved_route_ids: routeIds,
|
|
4519
|
+
spend_limit_credits: spendLimit,
|
|
4520
|
+
approved_by: "<operator-email>"
|
|
4521
|
+
});
|
|
4522
|
+
return plan.mcpFlow.filter((step) => ["execution-prepare", "approved-build", "delivery-approval"].includes(step.id)).map((step) => ({
|
|
4523
|
+
id: step.id,
|
|
4524
|
+
tool: step.tool,
|
|
4525
|
+
arguments: step.id === "approved-build" ? compact({ ...step.arguments, approval_context: approvalContext }) : step.arguments,
|
|
4526
|
+
read_only: step.readOnly,
|
|
4527
|
+
approval_required: step.approvalRequired,
|
|
4528
|
+
safety: step.readOnly ? "Read-only readiness handoff; safe to inspect before approval." : "Write-capable handoff; run only after the approval packet is accepted."
|
|
4529
|
+
}));
|
|
4530
|
+
}
|
|
4531
|
+
function campaignBuilderActiveWorkNextMcpAction(input) {
|
|
4532
|
+
const campaignBuildRef = input.refs.find((ref) => ref.kind === "campaign_build" && ref.id);
|
|
4533
|
+
if (campaignBuildRef) {
|
|
4534
|
+
return {
|
|
4535
|
+
id: "check-campaign-build-status",
|
|
4536
|
+
tool: "get_campaign_build_status",
|
|
4537
|
+
arguments: { campaign_build_id: campaignBuildRef.id },
|
|
4538
|
+
read_only: true,
|
|
4539
|
+
approval_required: false,
|
|
4540
|
+
safety: "Read-only status check for the remembered campaign build; does not spend, write, export, send, or approve anything."
|
|
4541
|
+
};
|
|
4542
|
+
}
|
|
4543
|
+
const campaignRef = input.refs.find((ref) => ref.kind === "gtm_campaign" && ref.id);
|
|
4544
|
+
if (campaignRef) {
|
|
4545
|
+
return {
|
|
4546
|
+
id: "check-gtm-campaign-status",
|
|
4547
|
+
tool: "gtm_campaign_execution_status",
|
|
4548
|
+
arguments: { campaign_id: campaignRef.id },
|
|
4549
|
+
read_only: true,
|
|
4550
|
+
approval_required: false,
|
|
4551
|
+
safety: "Read-only campaign execution status check; does not start or mutate the campaign."
|
|
4552
|
+
};
|
|
4553
|
+
}
|
|
4554
|
+
const preferredStepId = input.state === "ready_for_dry_run" ? "dry-run-build" : input.state === "planning" || input.state === "blocked" ? "agency-campaign-build-plan" : null;
|
|
4555
|
+
const preferredStep = preferredStepId ? input.plan?.mcpFlow.find((step) => step.id === preferredStepId && step.readOnly) : void 0;
|
|
4556
|
+
if (preferredStep) return campaignBuilderMcpStepToActiveWorkAction(preferredStep, "Read-only continuation from the saved campaign-agent plan.");
|
|
4557
|
+
const readOnlyApprovalHandoff = input.approvalPacket.mcp_handoffs.find((handoff) => handoff.read_only && !handoff.approval_required);
|
|
4558
|
+
if (readOnlyApprovalHandoff) return readOnlyApprovalHandoff;
|
|
4559
|
+
const firstReadOnlyPlanStep = input.plan?.mcpFlow.find((step) => step.readOnly && !step.approvalRequired);
|
|
4560
|
+
return firstReadOnlyPlanStep ? campaignBuilderMcpStepToActiveWorkAction(firstReadOnlyPlanStep, "Read-only saved plan check; safe before approvals or writes.") : null;
|
|
4561
|
+
}
|
|
4562
|
+
function campaignBuilderMcpStepToActiveWorkAction(step, safety) {
|
|
4563
|
+
return {
|
|
4564
|
+
id: step.id,
|
|
4565
|
+
tool: step.tool,
|
|
4566
|
+
arguments: step.arguments,
|
|
4567
|
+
read_only: step.readOnly,
|
|
4568
|
+
approval_required: step.approvalRequired,
|
|
4569
|
+
safety
|
|
4570
|
+
};
|
|
4571
|
+
}
|
|
4572
|
+
function normalizeCampaignBuilderActiveWorkRefs(input) {
|
|
4573
|
+
const refs = [];
|
|
4574
|
+
const pushRef = (ref) => {
|
|
4575
|
+
if (!ref?.id) return;
|
|
4576
|
+
refs.push(ref);
|
|
4577
|
+
};
|
|
4578
|
+
pushRef(input.plan?.planId ? { kind: "plan", id: input.plan.planId, label: input.plan.campaignName, source: "plan" } : void 0);
|
|
4579
|
+
pushRef(input.remembered.planId ? { kind: "plan", id: input.remembered.planId, source: "remembered" } : void 0);
|
|
4580
|
+
pushRef(
|
|
4581
|
+
input.plan?.buildRequest.gtmCampaignId ?? input.remembered.gtmCampaignId ? {
|
|
4582
|
+
kind: "gtm_campaign",
|
|
4583
|
+
id: input.plan?.buildRequest.gtmCampaignId ?? input.remembered.gtmCampaignId,
|
|
4584
|
+
label: input.plan?.campaignName,
|
|
4585
|
+
source: input.plan?.buildRequest.gtmCampaignId ? "plan" : "remembered"
|
|
4586
|
+
} : void 0
|
|
4587
|
+
);
|
|
4588
|
+
const campaignBuildId = stringValue(input.lastResult.campaign_build_id ?? input.lastResult.campaignBuildId) ?? input.remembered.campaignBuildId;
|
|
4589
|
+
pushRef(campaignBuildId ? { kind: "campaign_build", id: campaignBuildId, status: activeWorkStatus(input.lastResult) ?? input.remembered.status, source: "result" } : void 0);
|
|
4590
|
+
pushRef(
|
|
4591
|
+
input.remembered.providerCampaignId ? {
|
|
4592
|
+
kind: "provider_campaign",
|
|
4593
|
+
id: input.remembered.providerCampaignId,
|
|
4594
|
+
label: input.remembered.provider,
|
|
4595
|
+
status: input.remembered.status,
|
|
4596
|
+
source: "remembered"
|
|
4597
|
+
} : void 0
|
|
4598
|
+
);
|
|
4599
|
+
for (const ref of input.remembered.refs ?? []) pushRef(ref);
|
|
4600
|
+
for (const ref of input.refs ?? []) pushRef(ref);
|
|
4601
|
+
const seen = /* @__PURE__ */ new Set();
|
|
4602
|
+
return refs.filter((ref) => {
|
|
4603
|
+
const key = `${ref.kind}:${ref.id}`;
|
|
4604
|
+
if (seen.has(key)) return false;
|
|
4605
|
+
seen.add(key);
|
|
4606
|
+
return true;
|
|
4607
|
+
});
|
|
4608
|
+
}
|
|
4609
|
+
function inferCampaignBuilderActiveWorkState(input) {
|
|
4610
|
+
if (input.blockers.length > 0) return "blocked";
|
|
4611
|
+
const status = activeWorkStatus(input.lastResult) ?? input.remembered.status;
|
|
4612
|
+
const normalized = status?.toLowerCase();
|
|
4613
|
+
if (normalized && ["completed", "complete", "succeeded", "success", "done"].includes(normalized)) return "completed";
|
|
4614
|
+
if (normalized && ["queued", "running", "in_progress", "processing", "pending"].includes(normalized)) return "queued_or_running";
|
|
4615
|
+
const dryRunComplete = input.lastResult.dry_run === true || input.lastResult.dryRun === true || normalized === "dry_run";
|
|
4616
|
+
if (dryRunComplete) return input.missingApprovals.length > 0 ? "needs_approval" : "dry_run_complete";
|
|
4617
|
+
if (input.missingApprovals.length > 0) return "needs_approval";
|
|
4618
|
+
if (input.readiness?.summary.ready === true) return "ready_for_dry_run";
|
|
4619
|
+
if (input.plan) return "planning";
|
|
4620
|
+
return "unknown";
|
|
4621
|
+
}
|
|
4622
|
+
function campaignBuilderActiveWorkApprovalBoundary(missingApprovals, state) {
|
|
4623
|
+
if (missingApprovals.length > 0) {
|
|
4624
|
+
return `Blocked before spend, provider writes, delivery, or launch until approval covers: ${uniqueStrings(missingApprovals).join(", ")}.`;
|
|
4625
|
+
}
|
|
4626
|
+
if (state === "dry_run_complete" || state === "ready_for_dry_run") {
|
|
4627
|
+
return "Read-only planning and dry-runs are allowed; spend, provider writes, sender loading, delivery, and launch still require explicit approval.";
|
|
4628
|
+
}
|
|
4629
|
+
return "This packet is read-only and does not authorize spend, provider writes, sender loading, delivery, or launch.";
|
|
4630
|
+
}
|
|
4631
|
+
function campaignBuilderActiveWorkNextAction(state, blockers, missingApprovals, refs) {
|
|
4632
|
+
if (blockers.length > 0) return `Resolve blocker: ${blockers[0]}`;
|
|
4633
|
+
if (missingApprovals.length > 0) return `Ask the operator to approve ${uniqueStrings(missingApprovals).join(", ")} before any write or spend action.`;
|
|
4634
|
+
if (state === "ready_for_dry_run") return "Run or inspect the read-only campaign dry-run, then return the receipt for approval review.";
|
|
4635
|
+
if (state === "dry_run_complete") return "Review the dry-run receipt and collect explicit launch or delivery approval before any write action.";
|
|
4636
|
+
if (state === "queued_or_running") return "Poll the remembered campaign build or provider job status; do not start a duplicate job.";
|
|
4637
|
+
if (state === "completed") return "Review final artifacts and delivery gates before export, sync, sender load, or launch.";
|
|
4638
|
+
if (refs.length > 0) return "Use the remembered refs to fetch current read-only status before asking the operator for IDs.";
|
|
4639
|
+
return "Create or refresh a campaign-builder plan before taking any spendful or write action.";
|
|
4640
|
+
}
|
|
4641
|
+
function campaignBuilderActiveWorkConversationStarters(input) {
|
|
4642
|
+
const starters = [];
|
|
4643
|
+
if (input.blockers.length > 0) {
|
|
4644
|
+
starters.push(
|
|
4645
|
+
`I found a blocker: ${input.blockers[0]}. Want me to stay in read-only diagnostics and prepare the fix path?`
|
|
4646
|
+
);
|
|
4647
|
+
}
|
|
4648
|
+
if (input.missingApprovals.length > 0) {
|
|
4649
|
+
starters.push(
|
|
4650
|
+
`You still owe approval for ${uniqueStrings(input.missingApprovals).join(", ")}. Want the exact approval packet before anything writes or spends?`
|
|
4651
|
+
);
|
|
4652
|
+
}
|
|
4653
|
+
if (input.state === "queued_or_running") {
|
|
4654
|
+
const buildRef = input.refs.find((ref) => ref.kind === "campaign_build");
|
|
4655
|
+
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.");
|
|
4656
|
+
}
|
|
4657
|
+
if (input.state === "dry_run_complete") {
|
|
4658
|
+
starters.push("The dry run is complete. Want me to summarize blockers, artifacts, and the approval handoff?");
|
|
4659
|
+
}
|
|
4660
|
+
if (input.state === "ready_for_dry_run") {
|
|
4661
|
+
starters.push("Everything is ready for a safe dry run. Want me to run the no-spend preview first?");
|
|
4662
|
+
}
|
|
4663
|
+
if (input.state === "completed") {
|
|
4664
|
+
starters.push("The build looks complete. Want me to review rows, artifacts, and delivery gates before export or send approval?");
|
|
4665
|
+
}
|
|
4666
|
+
starters.push(`Next safe action: ${input.nextSafeAction}`);
|
|
4667
|
+
return uniqueStrings(starters).slice(0, 4);
|
|
4668
|
+
}
|
|
4669
|
+
function createCampaignBuilderOpenAiAgentHandoff(input) {
|
|
4670
|
+
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.")) ?? [];
|
|
4671
|
+
const routeSetupActions = readOnlyPlanActions.filter(
|
|
4672
|
+
(action) => action.tool === "gtm_provider_recipe_prepare" || action.tool === "gtm_provider_route_activate"
|
|
4673
|
+
);
|
|
4674
|
+
const safeReadActions = uniqueCampaignBuilderActiveWorkActions([
|
|
4675
|
+
input.nextSafeMcpAction,
|
|
4676
|
+
...routeSetupActions,
|
|
4677
|
+
...readOnlyPlanActions
|
|
4678
|
+
]);
|
|
4679
|
+
const approvalGatedActions = uniqueCampaignBuilderActiveWorkActions([
|
|
4680
|
+
...input.approvalPacket.mcp_handoffs.filter((action) => action.approval_required || !action.read_only),
|
|
4681
|
+
...input.plan?.mcpFlow.filter((step) => step.approvalRequired || !step.readOnly).map((step) => campaignBuilderMcpStepToActiveWorkAction(step, "Approval-gated Signaliz MCP continuation for the saved campaign-agent plan.")) ?? []
|
|
4682
|
+
]);
|
|
4683
|
+
const approvalTypes = uniqueStrings([
|
|
4684
|
+
...input.missingApprovals,
|
|
4685
|
+
...input.approvalPacket.requested_approval_types
|
|
4686
|
+
]);
|
|
4687
|
+
return {
|
|
4688
|
+
packet_version: "campaign-builder-openai-agent-handoff.v1",
|
|
4689
|
+
surface: "openai_agents_sdk",
|
|
4690
|
+
agent: {
|
|
4691
|
+
name: "Signaliz GTM Campaign Agent",
|
|
4692
|
+
handoff_description: "Owns safe, conversational GTM campaign planning and continuation across Signaliz MCP, SDK, attachments, URLs, customer tools, approvals, and sender/export gates.",
|
|
4693
|
+
instructions: [
|
|
4694
|
+
"Be warm, direct, and expert-level GTM. Translate the current state into plain operator language before proposing work.",
|
|
4695
|
+
"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.",
|
|
4696
|
+
"Use attachment_summary, url_summary, and operator_notes as first-class planning evidence, while honoring the evidence privacy_boundary and withheld raw fields.",
|
|
4697
|
+
"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.",
|
|
4698
|
+
"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.",
|
|
4699
|
+
"When approval is missing, show the approval_packet and the exact missing approval scope before any side-effecting step."
|
|
4700
|
+
],
|
|
4701
|
+
output_contract: [
|
|
4702
|
+
"current_state: one concise sentence describing where the campaign work stands.",
|
|
4703
|
+
"evidence_used: attachment, URL, memory, route, or integration evidence used without exposing private raw rows or secrets.",
|
|
4704
|
+
"next_safe_mcp_action: the read-only Signaliz MCP action to run next, or null when none is safe.",
|
|
4705
|
+
"approval_boundary: the human approval scope required before spend, provider writes, delivery, export, sender load, or launch.",
|
|
4706
|
+
"operator_reply: conversational GTM guidance with blockers, risks, and the safest next move."
|
|
4707
|
+
]
|
|
4708
|
+
},
|
|
4709
|
+
context: {
|
|
4710
|
+
state: input.state,
|
|
4711
|
+
summary: input.summary,
|
|
4712
|
+
refs: input.refs,
|
|
4713
|
+
blockers: input.blockers,
|
|
4714
|
+
warnings: input.warnings,
|
|
4715
|
+
evidence_context: input.plan?.evidence ?? null,
|
|
4716
|
+
approval_packet: input.approvalPacket,
|
|
4717
|
+
approval_boundary: input.approvalBoundary,
|
|
4718
|
+
next_safe_action: input.nextSafeAction,
|
|
4719
|
+
conversation_starters: input.conversationStarters
|
|
4720
|
+
},
|
|
4721
|
+
tools: {
|
|
4722
|
+
mcp_server_label: "signaliz",
|
|
4723
|
+
remote_mcp_compatible: true,
|
|
4724
|
+
next_safe_mcp_action: input.nextSafeMcpAction,
|
|
4725
|
+
safe_read_tools: safeReadActions.map(
|
|
4726
|
+
(action) => campaignBuilderOpenAiAgentTool(action, "Safe read-only Signaliz MCP action available before approval.")
|
|
4727
|
+
),
|
|
4728
|
+
approval_gated_tools: approvalGatedActions.map(
|
|
4729
|
+
(action) => campaignBuilderOpenAiAgentTool(action, "Requires explicit human review before execution.")
|
|
4730
|
+
)
|
|
4731
|
+
},
|
|
4732
|
+
guardrails: {
|
|
4733
|
+
input: [
|
|
4734
|
+
"Reject or pause requests to expose raw private attachment text, raw rows, leads, emails, provider payloads, copy bodies, API keys, or secrets.",
|
|
4735
|
+
"Pause when the user asks to spend credits, write to a provider, export, load a sender, deliver, or launch without explicit approval scope."
|
|
4736
|
+
],
|
|
4737
|
+
tool: [
|
|
4738
|
+
"Read-only tools may run when they match safe_read_tools and their arguments match this packet.",
|
|
4739
|
+
"Any tool with approval_required=true or read_only=false requires human review and the approval_packet scope first."
|
|
4740
|
+
],
|
|
4741
|
+
human_review_required_for: approvalTypes,
|
|
4742
|
+
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."
|
|
4743
|
+
}
|
|
4744
|
+
};
|
|
4745
|
+
}
|
|
4746
|
+
function campaignBuilderOpenAiAgentTool(action, purpose) {
|
|
4747
|
+
return {
|
|
4748
|
+
id: action.id,
|
|
4749
|
+
type: "mcp",
|
|
4750
|
+
server_label: "signaliz",
|
|
4751
|
+
name: action.tool,
|
|
4752
|
+
arguments: action.arguments,
|
|
4753
|
+
read_only: action.read_only,
|
|
4754
|
+
approval_required: action.approval_required,
|
|
4755
|
+
purpose,
|
|
4756
|
+
safety: action.safety
|
|
4757
|
+
};
|
|
4758
|
+
}
|
|
4759
|
+
function uniqueCampaignBuilderActiveWorkActions(actions) {
|
|
4760
|
+
const seen = /* @__PURE__ */ new Set();
|
|
4761
|
+
const unique = [];
|
|
4762
|
+
for (const action of actions) {
|
|
4763
|
+
if (!action) continue;
|
|
4764
|
+
const key = `${action.id}:${action.tool}`;
|
|
4765
|
+
if (seen.has(key)) continue;
|
|
4766
|
+
seen.add(key);
|
|
4767
|
+
unique.push(action);
|
|
4768
|
+
}
|
|
4769
|
+
return unique;
|
|
4770
|
+
}
|
|
4771
|
+
function activeWorkStatus(record) {
|
|
4772
|
+
return stringValue(record.status ?? record.state ?? record.phase);
|
|
4773
|
+
}
|
|
3613
4774
|
function campaignBuilderBuiltInForRoute(route) {
|
|
3614
4775
|
return Object.entries(CAMPAIGN_BUILDER_BUILT_IN_ROUTE_IDS).find(([, routeId]) => route.id === routeId)?.[0];
|
|
3615
4776
|
}
|
|
@@ -3877,7 +5038,7 @@ function hashString(input) {
|
|
|
3877
5038
|
function errorMessage(error) {
|
|
3878
5039
|
return error instanceof Error ? error.message : String(error);
|
|
3879
5040
|
}
|
|
3880
|
-
var DEFAULT_SIGNALIZ_CAMPAIGN_BUILDER_DEFAULTS, DEFAULT_CAMPAIGN_BUILDER_BUILT_INS, CAMPAIGN_BUILDER_BUILT_IN_ROUTE_IDS, DEFAULT_CAMPAIGN_BUILDER_APPROVAL_TYPES, CAMPAIGN_BUILDER_OPERATING_PLAYBOOKS, CAMPAIGN_BUILDER_STRATEGY_TEMPLATES, CampaignBuilderAgent;
|
|
5041
|
+
var DEFAULT_SIGNALIZ_CAMPAIGN_BUILDER_DEFAULTS, DEFAULT_CAMPAIGN_BUILDER_BUILT_INS, CAMPAIGN_BUILDER_BUILT_IN_ROUTE_IDS, DEFAULT_CAMPAIGN_BUILDER_APPROVAL_TYPES, CAMPAIGN_BUILDER_OPERATING_PLAYBOOKS, CAMPAIGN_BUILDER_STRATEGY_TEMPLATES, CampaignBuilderAgent, CAMPAIGN_BUILDER_TERMINAL_STATUSES, CAMPAIGN_BUILDER_BLOCKED_TERMINAL_STATUSES, NORTH_STAR_BANNED_COPY_PHRASES;
|
|
3881
5042
|
var init_campaign_builder_agent = __esm({
|
|
3882
5043
|
"src/resources/campaign-builder-agent.ts"() {
|
|
3883
5044
|
"use strict";
|
|
@@ -3897,7 +5058,8 @@ var init_campaign_builder_agent = __esm({
|
|
|
3897
5058
|
copy: {
|
|
3898
5059
|
enabled: true,
|
|
3899
5060
|
tone: "direct",
|
|
3900
|
-
maxBodyWords: 125
|
|
5061
|
+
maxBodyWords: 125,
|
|
5062
|
+
evidenceMode: "signal_led"
|
|
3901
5063
|
},
|
|
3902
5064
|
delivery: {
|
|
3903
5065
|
enabled: true,
|
|
@@ -3954,7 +5116,8 @@ var init_campaign_builder_agent = __esm({
|
|
|
3954
5116
|
"Block export when required identity, company, or email fields are missing."
|
|
3955
5117
|
],
|
|
3956
5118
|
activationBoundary: "Cache inventory is read-only. Fresh sourcing, cache writes, export, and sender loading require explicit approval.",
|
|
3957
|
-
memoryKeywords: ["cache inventory", "large list", "unique emails", "top-up sourcing", "source metadata"]
|
|
5119
|
+
memoryKeywords: ["cache inventory", "large list", "unique emails", "top-up sourcing", "source metadata"],
|
|
5120
|
+
knowledgeSources: ["data-ops/contact-data-lifecycle", "data-ops/credit-optimization-guide", "gtm/data-quality-ops", "gtm/lead-generation-strategies"]
|
|
3958
5121
|
},
|
|
3959
5122
|
{
|
|
3960
5123
|
slug: "net-new-suppressed-list",
|
|
@@ -3979,7 +5142,8 @@ var init_campaign_builder_agent = __esm({
|
|
|
3979
5142
|
"Do not describe rows as fully qualified when the approved path only proves net-new email status."
|
|
3980
5143
|
],
|
|
3981
5144
|
activationBoundary: "Suppression review must pass before export, upload, CRM sync, sender load, or sequence launch.",
|
|
3982
|
-
memoryKeywords: ["suppression", "net-new", "prior email overlap", "domain review", "provenance-rich QA"]
|
|
5145
|
+
memoryKeywords: ["suppression", "net-new", "prior email overlap", "domain review", "provenance-rich QA"],
|
|
5146
|
+
knowledgeSources: ["gtm/data-quality-ops", "data-ops/contact-data-lifecycle", "gtm/outbound-sequencing"]
|
|
3983
5147
|
},
|
|
3984
5148
|
{
|
|
3985
5149
|
slug: "proof-first-vertical-gate",
|
|
@@ -4004,7 +5168,8 @@ var init_campaign_builder_agent = __esm({
|
|
|
4004
5168
|
"Contact fit should meet the configured threshold before email finding or copy generation."
|
|
4005
5169
|
],
|
|
4006
5170
|
activationBoundary: "Proof gates are required before contact spend, copy, export, or external writes.",
|
|
4007
|
-
memoryKeywords: ["proof gate", "vertical exclusion", "company before contact", "pass review fail", "fit threshold"]
|
|
5171
|
+
memoryKeywords: ["proof gate", "vertical exclusion", "company before contact", "pass review fail", "fit threshold"],
|
|
5172
|
+
knowledgeSources: ["gtm/icp-design-framework", "gtm/strategy/scoring.yaml", "gtm/advanced/account-prioritization-frameworks", "gtm/advanced/predictive-lead-scoring", "gtm/verticals"]
|
|
4008
5173
|
},
|
|
4009
5174
|
{
|
|
4010
5175
|
slug: "signal-led-copy-approval",
|
|
@@ -4029,7 +5194,8 @@ var init_campaign_builder_agent = __esm({
|
|
|
4029
5194
|
"Destination fields must remain blocked until approval metadata is present."
|
|
4030
5195
|
],
|
|
4031
5196
|
activationBoundary: "Copy readiness is not delivery approval. Export, sync, sender load, and launch require a separate human-approved gate.",
|
|
4032
|
-
memoryKeywords: ["company signals", "evidence-fed copy", "why now", "copy blocker", "approval gate"]
|
|
5197
|
+
memoryKeywords: ["company signals", "evidence-fed copy", "why now", "copy blocker", "approval gate"],
|
|
5198
|
+
knowledgeSources: ["gtm/email-personalization", "gtm/signal-based-selling", "gtm/signal-combination-matrix", "gtm/advanced/buyer-journey-mapping"]
|
|
4033
5199
|
},
|
|
4034
5200
|
{
|
|
4035
5201
|
slug: "domain-first-recovery",
|
|
@@ -4054,7 +5220,8 @@ var init_campaign_builder_agent = __esm({
|
|
|
4054
5220
|
"Target count means final held rows, not raw sourced rows."
|
|
4055
5221
|
],
|
|
4056
5222
|
activationBoundary: "Domain recovery informs sourcing. Contact enrichment, paid qualification, and export still require approved gates.",
|
|
4057
|
-
memoryKeywords: ["domain-first", "yield modeling", "attrition", "accepted domains", "gap fill"]
|
|
5223
|
+
memoryKeywords: ["domain-first", "yield modeling", "attrition", "accepted domains", "gap fill"],
|
|
5224
|
+
knowledgeSources: ["gtm/lead-generation-strategies", "data-ops/enrichment-waterfall-strategy", "data-ops/credit-optimization-guide", "gtm/territory-account-planning"]
|
|
4058
5225
|
},
|
|
4059
5226
|
{
|
|
4060
5227
|
slug: "table-workflow-handoff",
|
|
@@ -4079,7 +5246,112 @@ var init_campaign_builder_agent = __esm({
|
|
|
4079
5246
|
"Provider route activation must dry-run before any external write."
|
|
4080
5247
|
],
|
|
4081
5248
|
activationBoundary: "MCP, webhook, managed integration, and destination routes remain dry-run until the reviewed route and campaign are approved.",
|
|
4082
|
-
memoryKeywords: ["table workflow", "request ready", "provider status", "export blocker", "BYO integration"]
|
|
5249
|
+
memoryKeywords: ["table workflow", "request ready", "provider status", "export blocker", "BYO integration"],
|
|
5250
|
+
knowledgeSources: ["gtm/multi-channel-orchestration", "data-ops/enrichment-waterfall-strategy", "recipes/clay-gtm-webhook-recipe", "systems/blueprints/multi-channel-orchestration"]
|
|
5251
|
+
},
|
|
5252
|
+
{
|
|
5253
|
+
slug: "icp-persona-segmentation",
|
|
5254
|
+
label: "ICP And Persona Segmentation",
|
|
5255
|
+
whenToUse: [
|
|
5256
|
+
"The brief has a broad market, multiple personas, or unclear buying committee.",
|
|
5257
|
+
"The campaign should rank account tiers, persona fit, vertical nuance, and exclusions before sourcing at scale."
|
|
5258
|
+
],
|
|
5259
|
+
sequence: [
|
|
5260
|
+
"Convert the brief into account tiers, persona roles, buying committee influence, and explicit exclusions.",
|
|
5261
|
+
"Choose vertical guidance only from the customer-safe GTM library and keep internal platform docs out of prompts.",
|
|
5262
|
+
"Score accounts before contacts, then score contacts against persona, seniority, function, geography, and intent fit.",
|
|
5263
|
+
"Return segment counts and review buckets before spend, copy, export, or launch."
|
|
5264
|
+
],
|
|
5265
|
+
requiredFields: {
|
|
5266
|
+
segment: ["segment_name", "tier", "persona_priority", "buying_committee_role", "fit_reason", "exclusion_reason"],
|
|
5267
|
+
scoring: ["account_fit_score", "persona_fit_score", "segment_confidence", "review_bucket"]
|
|
5268
|
+
},
|
|
5269
|
+
qualityGates: [
|
|
5270
|
+
"Do not treat adjacent personas or verticals as matches unless the brief allows them.",
|
|
5271
|
+
"Keep ICP, persona, and exclusion evidence visible in the proof packet.",
|
|
5272
|
+
"Low-confidence segments route to review before contact discovery or copy."
|
|
5273
|
+
],
|
|
5274
|
+
activationBoundary: "Segmentation is planning guidance. Paid sourcing, enrichment, export, and launch require the normal approval gates.",
|
|
5275
|
+
memoryKeywords: ["ICP design", "persona segmentation", "buying committee", "account tiers", "fit scoring", "vertical nuance"],
|
|
5276
|
+
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"]
|
|
5277
|
+
},
|
|
5278
|
+
{
|
|
5279
|
+
slug: "buying-signal-prioritization",
|
|
5280
|
+
label: "Buying Signal Prioritization",
|
|
5281
|
+
whenToUse: [
|
|
5282
|
+
"The campaign depends on timing, intent, trigger events, or account prioritization.",
|
|
5283
|
+
"The operator wants why-now proof instead of generic list generation."
|
|
5284
|
+
],
|
|
5285
|
+
sequence: [
|
|
5286
|
+
"Map the campaign goal to signal families, trigger freshness, and buyer-journey stage.",
|
|
5287
|
+
"Rank signals by relevance, recency, source quality, and persona-specific actionability.",
|
|
5288
|
+
"Attach evidence URLs or evidence summaries without exposing private memory rows.",
|
|
5289
|
+
"Use signal strength to decide source order, copy angle, and review priority."
|
|
5290
|
+
],
|
|
5291
|
+
requiredFields: {
|
|
5292
|
+
signal: ["signal_type", "signal_date", "signal_source", "why_now", "signal_confidence", "buyer_stage"],
|
|
5293
|
+
prioritization: ["priority_score", "priority_reason", "next_best_action", "review_reason"]
|
|
5294
|
+
},
|
|
5295
|
+
qualityGates: [
|
|
5296
|
+
"Do not use stale, unsupported, or weak signals as personalization proof.",
|
|
5297
|
+
"Signal fit cannot override hard ICP, geography, suppression, or verified-email gates.",
|
|
5298
|
+
"Rows with uncertain why-now evidence must stay review-only."
|
|
5299
|
+
],
|
|
5300
|
+
activationBoundary: "Signal ranking can prioritize review and copy. It does not approve outreach, sender loading, exports, or sends.",
|
|
5301
|
+
memoryKeywords: ["buying signals", "intent data", "funding trigger", "new executive", "tech adoption", "buyer journey", "why now"],
|
|
5302
|
+
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"]
|
|
5303
|
+
},
|
|
5304
|
+
{
|
|
5305
|
+
slug: "multi-channel-sequence-fit",
|
|
5306
|
+
label: "Multi-Channel Sequence Fit",
|
|
5307
|
+
whenToUse: [
|
|
5308
|
+
"The campaign needs email, LinkedIn, call, webhook, CRM, or sequencer coordination.",
|
|
5309
|
+
"Copy and delivery should adapt by persona, channel, deliverability risk, and proof strength."
|
|
5310
|
+
],
|
|
5311
|
+
sequence: [
|
|
5312
|
+
"Choose channel mix from persona, deal motion, evidence strength, deliverability constraints, and connected destination readiness.",
|
|
5313
|
+
"Draft sequence logic with email, LinkedIn, call, and task handoffs only where supported by the approved destination.",
|
|
5314
|
+
"Keep copy concise, proof-backed, channel-specific, and reviewable before delivery.",
|
|
5315
|
+
"Run deliverability and destination readiness checks before sender load or launch approval."
|
|
5316
|
+
],
|
|
5317
|
+
requiredFields: {
|
|
5318
|
+
channel: ["channel", "touch_number", "persona_context", "message_angle", "channel_blocker", "approval_status"],
|
|
5319
|
+
deliverability: ["verified_email", "domain_risk", "send_window", "unsubscribe_risk", "sender_ready"]
|
|
5320
|
+
},
|
|
5321
|
+
qualityGates: [
|
|
5322
|
+
"Email copy must be row-supported and under the configured campaign tone/length limits.",
|
|
5323
|
+
"LinkedIn, phone, CRM, webhook, and sequencer actions remain destination-locked until approved.",
|
|
5324
|
+
"Deliverability risk or missing sender readiness blocks launch even when rows are qualified."
|
|
5325
|
+
],
|
|
5326
|
+
activationBoundary: "Sequence strategy is draft-only. External writes, sender loading, launch, and sending need separate explicit approval.",
|
|
5327
|
+
memoryKeywords: ["outbound sequencing", "email personalization", "LinkedIn outreach", "cold calling", "multi-channel orchestration", "deliverability"],
|
|
5328
|
+
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"]
|
|
5329
|
+
},
|
|
5330
|
+
{
|
|
5331
|
+
slug: "revops-feedback-loop",
|
|
5332
|
+
label: "RevOps Feedback Loop",
|
|
5333
|
+
whenToUse: [
|
|
5334
|
+
"The campaign should improve from replies, meetings, delivery results, CRM outcomes, or operator QA.",
|
|
5335
|
+
"The operator needs post-build monitoring, governance, or continuous ops follow-up."
|
|
5336
|
+
],
|
|
5337
|
+
sequence: [
|
|
5338
|
+
"Define success metrics, guardrails, and feedback sources before launch.",
|
|
5339
|
+
"Collect aggregate outcomes, QA blockers, delivery health, and operator edits after each campaign phase.",
|
|
5340
|
+
"Separate workspace-private evidence from public-safe learnings and Brain defaults.",
|
|
5341
|
+
"Feed approved aggregate learnings back into future sourcing, qualification, copy, and suppression rules."
|
|
5342
|
+
],
|
|
5343
|
+
requiredFields: {
|
|
5344
|
+
feedback: ["source", "event_type", "metric", "sample_size", "confidence", "learning_candidate"],
|
|
5345
|
+
governance: ["approval_owner", "last_reviewed_at", "risk_flag", "next_review_action"]
|
|
5346
|
+
},
|
|
5347
|
+
qualityGates: [
|
|
5348
|
+
"Do not write memory or Brain learnings from raw replies, private labels, or provider payloads without approved redaction.",
|
|
5349
|
+
"Use holdouts or pre/post comparisons before claiming causal lift.",
|
|
5350
|
+
"Delivery, suppression, and opt-out signals must update future gates before scale-up."
|
|
5351
|
+
],
|
|
5352
|
+
activationBoundary: "Feedback review is read-only until memory writes, Brain writes, CRM updates, or campaign changes are explicitly approved.",
|
|
5353
|
+
memoryKeywords: ["RevOps", "feedback loop", "campaign learning", "reply outcomes", "sales marketing alignment", "data hygiene", "holdout"],
|
|
5354
|
+
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"]
|
|
4083
5355
|
}
|
|
4084
5356
|
];
|
|
4085
5357
|
CAMPAIGN_BUILDER_STRATEGY_TEMPLATES = [
|
|
@@ -4166,7 +5438,15 @@ var init_campaign_builder_agent = __esm({
|
|
|
4166
5438
|
agencyContext: {
|
|
4167
5439
|
partnerEcosystem: ["signaliz", "instantly", "nango"]
|
|
4168
5440
|
},
|
|
4169
|
-
operatingPlaybookSlugs: [
|
|
5441
|
+
operatingPlaybookSlugs: [
|
|
5442
|
+
"net-new-suppressed-list",
|
|
5443
|
+
"proof-first-vertical-gate",
|
|
5444
|
+
"signal-led-copy-approval",
|
|
5445
|
+
"icp-persona-segmentation",
|
|
5446
|
+
"buying-signal-prioritization",
|
|
5447
|
+
"multi-channel-sequence-fit",
|
|
5448
|
+
"revops-feedback-loop"
|
|
5449
|
+
]
|
|
4170
5450
|
},
|
|
4171
5451
|
{
|
|
4172
5452
|
slug: "non-medical-home-care",
|
|
@@ -4239,7 +5519,15 @@ var init_campaign_builder_agent = __esm({
|
|
|
4239
5519
|
agencyContext: {
|
|
4240
5520
|
partnerEcosystem: ["clay", "octave", "signaliz", "instantly", "nango"]
|
|
4241
5521
|
},
|
|
4242
|
-
operatingPlaybookSlugs: [
|
|
5522
|
+
operatingPlaybookSlugs: [
|
|
5523
|
+
"proof-first-vertical-gate",
|
|
5524
|
+
"domain-first-recovery",
|
|
5525
|
+
"table-workflow-handoff",
|
|
5526
|
+
"icp-persona-segmentation",
|
|
5527
|
+
"buying-signal-prioritization",
|
|
5528
|
+
"multi-channel-sequence-fit",
|
|
5529
|
+
"revops-feedback-loop"
|
|
5530
|
+
]
|
|
4243
5531
|
},
|
|
4244
5532
|
{
|
|
4245
5533
|
slug: "agency-founder-led",
|
|
@@ -4300,7 +5588,15 @@ var init_campaign_builder_agent = __esm({
|
|
|
4300
5588
|
agencyContext: {
|
|
4301
5589
|
partnerEcosystem: ["signaliz", "octave", "instantly", "nango"]
|
|
4302
5590
|
},
|
|
4303
|
-
operatingPlaybookSlugs: [
|
|
5591
|
+
operatingPlaybookSlugs: [
|
|
5592
|
+
"net-new-suppressed-list",
|
|
5593
|
+
"signal-led-copy-approval",
|
|
5594
|
+
"table-workflow-handoff",
|
|
5595
|
+
"icp-persona-segmentation",
|
|
5596
|
+
"buying-signal-prioritization",
|
|
5597
|
+
"multi-channel-sequence-fit",
|
|
5598
|
+
"revops-feedback-loop"
|
|
5599
|
+
]
|
|
4304
5600
|
},
|
|
4305
5601
|
{
|
|
4306
5602
|
slug: "cloud-infrastructure-displacement",
|
|
@@ -4387,7 +5683,15 @@ var init_campaign_builder_agent = __esm({
|
|
|
4387
5683
|
agencyContext: {
|
|
4388
5684
|
partnerEcosystem: ["signaliz", "octave", "instantly", "nango"]
|
|
4389
5685
|
},
|
|
4390
|
-
operatingPlaybookSlugs: [
|
|
5686
|
+
operatingPlaybookSlugs: [
|
|
5687
|
+
"proof-first-vertical-gate",
|
|
5688
|
+
"domain-first-recovery",
|
|
5689
|
+
"signal-led-copy-approval",
|
|
5690
|
+
"icp-persona-segmentation",
|
|
5691
|
+
"buying-signal-prioritization",
|
|
5692
|
+
"multi-channel-sequence-fit",
|
|
5693
|
+
"revops-feedback-loop"
|
|
5694
|
+
]
|
|
4391
5695
|
}
|
|
4392
5696
|
];
|
|
4393
5697
|
CampaignBuilderAgent = class {
|
|
@@ -4418,6 +5722,9 @@ var init_campaign_builder_agent = __esm({
|
|
|
4418
5722
|
const plan = await this.createPlan(request, options);
|
|
4419
5723
|
return createCampaignBuilderReadiness(plan);
|
|
4420
5724
|
}
|
|
5725
|
+
activeWorkContext(input) {
|
|
5726
|
+
return createCampaignBuilderActiveWorkContext(input);
|
|
5727
|
+
}
|
|
4421
5728
|
async proof(request, options = {}) {
|
|
4422
5729
|
const plan = await this.createPlan(request, options);
|
|
4423
5730
|
const result = await this.dryRunPlan(plan, {
|
|
@@ -4459,6 +5766,7 @@ var init_campaign_builder_agent = __esm({
|
|
|
4459
5766
|
},
|
|
4460
5767
|
brain_defaults: plan.buildRequest.brainDefaults,
|
|
4461
5768
|
brain_preflight: plan.buildRequest.brainPreflight,
|
|
5769
|
+
learning_holdout: plan.buildRequest.learningHoldout,
|
|
4462
5770
|
campaign_strategy_context: plan.buildRequest.campaignStrategyContext,
|
|
4463
5771
|
delivery_risk_preflight: plan.buildRequest.deliveryRisk,
|
|
4464
5772
|
delivery_risk: plan.buildRequest.deliveryRisk
|
|
@@ -4472,7 +5780,8 @@ var init_campaign_builder_agent = __esm({
|
|
|
4472
5780
|
estimated_credits: plan.estimatedCredits
|
|
4473
5781
|
},
|
|
4474
5782
|
brain_delivery_risk_preflight: plan.buildRequest.deliveryRisk,
|
|
4475
|
-
delivery_risk: plan.buildRequest.deliveryRisk
|
|
5783
|
+
delivery_risk: plan.buildRequest.deliveryRisk,
|
|
5784
|
+
learning_holdout: plan.buildRequest.learningHoldout
|
|
4476
5785
|
},
|
|
4477
5786
|
approval_required: plan.approvals.some((approval) => approval.blocking),
|
|
4478
5787
|
actor_type: "agent",
|
|
@@ -4788,6 +6097,17 @@ var init_campaign_builder_agent = __esm({
|
|
|
4788
6097
|
return this.client.mcp("tools/call", { name: tool, arguments: compact(args) });
|
|
4789
6098
|
}
|
|
4790
6099
|
};
|
|
6100
|
+
CAMPAIGN_BUILDER_TERMINAL_STATUSES = /* @__PURE__ */ new Set(["completed", "failed", "canceled", "cancelled"]);
|
|
6101
|
+
CAMPAIGN_BUILDER_BLOCKED_TERMINAL_STATUSES = /* @__PURE__ */ new Set(["failed", "canceled", "cancelled"]);
|
|
6102
|
+
NORTH_STAR_BANNED_COPY_PHRASES = [
|
|
6103
|
+
"i have been following",
|
|
6104
|
+
"i saw that",
|
|
6105
|
+
"would you be opposed",
|
|
6106
|
+
"unlock new opportunities",
|
|
6107
|
+
"significant success",
|
|
6108
|
+
"we understand",
|
|
6109
|
+
"hope this finds you well"
|
|
6110
|
+
];
|
|
4791
6111
|
}
|
|
4792
6112
|
});
|
|
4793
6113
|
|
|
@@ -7345,6 +8665,36 @@ function recordsFromParams(params) {
|
|
|
7345
8665
|
if (params.input) return { input: params.input };
|
|
7346
8666
|
return { input: {} };
|
|
7347
8667
|
}
|
|
8668
|
+
function toFusionConfig(params) {
|
|
8669
|
+
return {
|
|
8670
|
+
system_prompt: params.systemPrompt || params.system_prompt,
|
|
8671
|
+
user_template: params.userTemplate || params.user_template || params.prompt,
|
|
8672
|
+
preset: params.preset,
|
|
8673
|
+
temperature: params.temperature,
|
|
8674
|
+
max_tool_calls: params.maxToolCalls || params.max_tool_calls,
|
|
8675
|
+
max_tokens: params.maxTokens || params.max_tokens,
|
|
8676
|
+
timeout_ms: params.timeoutMs || params.timeout_ms,
|
|
8677
|
+
output_fields: params.outputFields || params.output_fields || [{ name: "response", type: "text", description: "Structured Fusion enrichment result" }]
|
|
8678
|
+
};
|
|
8679
|
+
}
|
|
8680
|
+
function toFusionSpendControls(params) {
|
|
8681
|
+
const controls = {};
|
|
8682
|
+
const dryRun = params.dryRun ?? params.dry_run;
|
|
8683
|
+
const confirmSpend = params.confirmSpend ?? params.confirm_spend;
|
|
8684
|
+
const maxCredits = params.maxCredits ?? params.max_credits;
|
|
8685
|
+
const maxCostUsd = params.maxCostUsd ?? params.max_cost_usd;
|
|
8686
|
+
if (dryRun !== void 0) controls.dry_run = dryRun;
|
|
8687
|
+
if (confirmSpend !== void 0) controls.confirm_spend = confirmSpend;
|
|
8688
|
+
if (maxCredits !== void 0) controls.max_credits = maxCredits;
|
|
8689
|
+
if (maxCostUsd !== void 0) controls.max_cost_usd = maxCostUsd;
|
|
8690
|
+
return controls;
|
|
8691
|
+
}
|
|
8692
|
+
function fusionRecordsFromParams(params) {
|
|
8693
|
+
const records = params.records || params.inputs;
|
|
8694
|
+
if (records?.length) return { records };
|
|
8695
|
+
if (params.input) return { input: params.input };
|
|
8696
|
+
return { input: {} };
|
|
8697
|
+
}
|
|
7348
8698
|
var Ai;
|
|
7349
8699
|
var init_ai = __esm({
|
|
7350
8700
|
"src/resources/ai.ts"() {
|
|
@@ -7382,6 +8732,33 @@ var init_ai = __esm({
|
|
|
7382
8732
|
raw: data
|
|
7383
8733
|
};
|
|
7384
8734
|
}
|
|
8735
|
+
/**
|
|
8736
|
+
* Plan or run experimental AI Enrichment Fusion with explicit spend controls.
|
|
8737
|
+
*/
|
|
8738
|
+
async fusion(params) {
|
|
8739
|
+
if (!params.prompt && !params.userTemplate && !params.user_template) {
|
|
8740
|
+
throw new Error("prompt or userTemplate is required.");
|
|
8741
|
+
}
|
|
8742
|
+
const data = await this.client.post("ai-enrichment-fusion", {
|
|
8743
|
+
...fusionRecordsFromParams(params),
|
|
8744
|
+
config: toFusionConfig(params),
|
|
8745
|
+
...toFusionSpendControls(params)
|
|
8746
|
+
});
|
|
8747
|
+
return {
|
|
8748
|
+
success: data.success ?? false,
|
|
8749
|
+
capability: data.capability ?? "ai_enrichment_fusion",
|
|
8750
|
+
displayName: data.display_name ?? "AI Enrichment Fusion",
|
|
8751
|
+
results: data.results ?? [],
|
|
8752
|
+
creditsUsed: data.total_credits_used ?? data.credits_used ?? 0,
|
|
8753
|
+
model: data.model,
|
|
8754
|
+
fusion: data.fusion,
|
|
8755
|
+
tokensUsed: data.tokens_used ?? 0,
|
|
8756
|
+
costUsd: data.cost_usd ?? 0,
|
|
8757
|
+
costSummary: data.cost_summary,
|
|
8758
|
+
billingMetadata: data.billing_metadata,
|
|
8759
|
+
raw: data
|
|
8760
|
+
};
|
|
8761
|
+
}
|
|
7385
8762
|
};
|
|
7386
8763
|
}
|
|
7387
8764
|
});
|
|
@@ -7858,6 +9235,16 @@ var init_gtm_kernel = __esm({
|
|
|
7858
9235
|
min_privacy_k: input.minPrivacyK
|
|
7859
9236
|
});
|
|
7860
9237
|
}
|
|
9238
|
+
/** Queue a dry-run-first bridge from imported historical feedback to attribution-only Campaign Build surrogates. */
|
|
9239
|
+
async runHistoricalCampaignBuildBridge(input = {}) {
|
|
9240
|
+
return this.callMcp("gtm_historical_campaign_build_bridge_run", {
|
|
9241
|
+
dry_run: input.dryRun,
|
|
9242
|
+
write_approved: input.writeApproved,
|
|
9243
|
+
max_events: input.maxEvents,
|
|
9244
|
+
max_campaigns: input.maxCampaigns,
|
|
9245
|
+
min_feedback_events: input.minFeedbackEvents
|
|
9246
|
+
});
|
|
9247
|
+
}
|
|
7861
9248
|
/** Prepare a provider-agnostic feedback webhook URL for Smartlead, HeyReach, Airbyte, or custom sender events. */
|
|
7862
9249
|
async prepareFeedbackWebhook(input) {
|
|
7863
9250
|
return this.callMcp("gtm_feedback_webhook_prepare", {
|
|
@@ -8034,6 +9421,24 @@ var init_gtm_kernel = __esm({
|
|
|
8034
9421
|
limit: input.limit
|
|
8035
9422
|
});
|
|
8036
9423
|
}
|
|
9424
|
+
/** Predict booked-meeting likelihood for uploaded, inline, or MCP-sourced lead rows without persisting raw rows. */
|
|
9425
|
+
async predictMeetingLikelihood(input) {
|
|
9426
|
+
return this.callMcp("gtm_predict_meeting_likelihood", {
|
|
9427
|
+
lead_rows: input.leadRows,
|
|
9428
|
+
input_source: input.inputSource,
|
|
9429
|
+
campaign_id: input.campaignId,
|
|
9430
|
+
campaign_build_id: input.campaignBuildId,
|
|
9431
|
+
days: input.days,
|
|
9432
|
+
feedback_limit: input.feedbackLimit,
|
|
9433
|
+
include_features: input.includeFeatures,
|
|
9434
|
+
include_global: input.includeGlobal,
|
|
9435
|
+
min_feedback_events: input.minFeedbackEvents,
|
|
9436
|
+
min_historical_feature_sample_size: input.minHistoricalFeatureSampleSize,
|
|
9437
|
+
min_workspace_count: input.minWorkspaceCount,
|
|
9438
|
+
min_privacy_k: input.minPrivacyK,
|
|
9439
|
+
limit: input.limit
|
|
9440
|
+
});
|
|
9441
|
+
}
|
|
8037
9442
|
/** Rank provider-chain, ICP, source, copy, and sequence failure patterns without writing raw lead data. */
|
|
8038
9443
|
async failurePatterns(options = {}) {
|
|
8039
9444
|
return this.callMcp("gtm_brain_failure_patterns", {
|
|
@@ -8534,6 +9939,76 @@ var init_gtm_kernel = __esm({
|
|
|
8534
9939
|
}
|
|
8535
9940
|
});
|
|
8536
9941
|
|
|
9942
|
+
// src/resources/public-ground-truth.ts
|
|
9943
|
+
var PublicGroundTruth;
|
|
9944
|
+
var init_public_ground_truth = __esm({
|
|
9945
|
+
"src/resources/public-ground-truth.ts"() {
|
|
9946
|
+
"use strict";
|
|
9947
|
+
PublicGroundTruth = class {
|
|
9948
|
+
constructor(client) {
|
|
9949
|
+
this.client = client;
|
|
9950
|
+
}
|
|
9951
|
+
/**
|
|
9952
|
+
* Search the public-ground-truth cache by company/name/domain/native ID,
|
|
9953
|
+
* or by plain-language industry + location.
|
|
9954
|
+
* Results use the same snake_case wire shape returned by the hosted MCP API.
|
|
9955
|
+
*/
|
|
9956
|
+
async search(params) {
|
|
9957
|
+
return this.client.mcp("tools/call", {
|
|
9958
|
+
name: "search_public_ground_truth",
|
|
9959
|
+
arguments: {
|
|
9960
|
+
query: params.query ?? params.search,
|
|
9961
|
+
industry: params.industry,
|
|
9962
|
+
location: params.location,
|
|
9963
|
+
source_id: params.sourceId ?? params.source_id,
|
|
9964
|
+
entity_type: params.entityType ?? params.entity_type,
|
|
9965
|
+
native_id: params.nativeId ?? params.native_id,
|
|
9966
|
+
entity_name: params.entityName ?? params.entity_name,
|
|
9967
|
+
domain: params.domain,
|
|
9968
|
+
website_url: params.websiteUrl ?? params.website_url,
|
|
9969
|
+
phone: params.phone,
|
|
9970
|
+
email: params.email,
|
|
9971
|
+
city: params.city,
|
|
9972
|
+
state: params.state,
|
|
9973
|
+
postal_code: params.postalCode ?? params.postal_code,
|
|
9974
|
+
country: params.country,
|
|
9975
|
+
source_url: params.sourceUrl ?? params.source_url,
|
|
9976
|
+
join_keys: params.joinKeys ?? params.join_keys,
|
|
9977
|
+
row_data: params.rowData ?? params.row_data,
|
|
9978
|
+
naics: params.naics,
|
|
9979
|
+
industry_code: params.industryCode ?? params.industry_code,
|
|
9980
|
+
industry_type: params.industryType ?? params.industry_type,
|
|
9981
|
+
year: params.year,
|
|
9982
|
+
quarter: params.quarter,
|
|
9983
|
+
area_fips: params.areaFips ?? params.area_fips,
|
|
9984
|
+
geo_id: params.geoId ?? params.geo_id,
|
|
9985
|
+
own_code: params.ownCode ?? params.own_code,
|
|
9986
|
+
source_updated_after: params.sourceUpdatedAfter ?? params.source_updated_after,
|
|
9987
|
+
source_updated_before: params.sourceUpdatedBefore ?? params.source_updated_before,
|
|
9988
|
+
observed_after: params.observedAfter ?? params.observed_after,
|
|
9989
|
+
observed_before: params.observedBefore ?? params.observed_before,
|
|
9990
|
+
limit: params.limit,
|
|
9991
|
+
offset: params.offset
|
|
9992
|
+
}
|
|
9993
|
+
});
|
|
9994
|
+
}
|
|
9995
|
+
/**
|
|
9996
|
+
* List available public-ground-truth cache sources and their join-key metadata.
|
|
9997
|
+
*/
|
|
9998
|
+
async listSources(params = {}) {
|
|
9999
|
+
return this.client.mcp("tools/call", {
|
|
10000
|
+
name: "list_public_ground_truth_sources",
|
|
10001
|
+
arguments: {
|
|
10002
|
+
query: params.query ?? params.search,
|
|
10003
|
+
status: params.status,
|
|
10004
|
+
limit: params.limit
|
|
10005
|
+
}
|
|
10006
|
+
});
|
|
10007
|
+
}
|
|
10008
|
+
};
|
|
10009
|
+
}
|
|
10010
|
+
});
|
|
10011
|
+
|
|
8537
10012
|
// src/index.ts
|
|
8538
10013
|
var index_exports = {};
|
|
8539
10014
|
__export(index_exports, {
|
|
@@ -8548,10 +10023,12 @@ __export(index_exports, {
|
|
|
8548
10023
|
GtmKernel: () => GtmKernel,
|
|
8549
10024
|
Icps: () => Icps,
|
|
8550
10025
|
Ops: () => Ops,
|
|
10026
|
+
PublicGroundTruth: () => PublicGroundTruth,
|
|
8551
10027
|
Signaliz: () => Signaliz,
|
|
8552
10028
|
SignalizError: () => SignalizError,
|
|
8553
10029
|
applyCampaignBuilderStrategyTemplate: () => applyCampaignBuilderStrategyTemplate,
|
|
8554
10030
|
collectExecutionReferences: () => collectExecutionReferences,
|
|
10031
|
+
createCampaignBuilderActiveWorkContext: () => createCampaignBuilderActiveWorkContext,
|
|
8555
10032
|
createCampaignBuilderAgentPlan: () => createCampaignBuilderAgentPlan,
|
|
8556
10033
|
createCampaignBuilderAgentRequestTemplate: () => createCampaignBuilderAgentRequestTemplate,
|
|
8557
10034
|
createCampaignBuilderApproval: () => createCampaignBuilderApproval,
|
|
@@ -8606,6 +10083,7 @@ function inferMcpToolCategory(toolName) {
|
|
|
8606
10083
|
}
|
|
8607
10084
|
if (toolName.includes("icp")) return "icp";
|
|
8608
10085
|
if (toolName.startsWith("ai_clean_")) return "data_cleaning";
|
|
10086
|
+
if (toolName.includes("public_ground_truth")) return "public_data";
|
|
8609
10087
|
if (toolName.includes("system") || toolName.includes("workflow")) return "automation";
|
|
8610
10088
|
if (toolName.includes("agent") || toolName.includes("platform_health") || toolName === "discover_capabilities") return "observability";
|
|
8611
10089
|
return void 0;
|
|
@@ -8659,9 +10137,11 @@ var init_index = __esm({
|
|
|
8659
10137
|
init_ops();
|
|
8660
10138
|
init_ai();
|
|
8661
10139
|
init_gtm_kernel();
|
|
10140
|
+
init_public_ground_truth();
|
|
8662
10141
|
init_errors();
|
|
8663
10142
|
init_ai();
|
|
8664
10143
|
init_gtm_kernel();
|
|
10144
|
+
init_public_ground_truth();
|
|
8665
10145
|
init_campaigns();
|
|
8666
10146
|
init_campaign_builder_agent();
|
|
8667
10147
|
init_icps();
|
|
@@ -8683,6 +10163,7 @@ var init_index = __esm({
|
|
|
8683
10163
|
this.ops = new Ops(this.client);
|
|
8684
10164
|
this.ai = new Ai(this.client);
|
|
8685
10165
|
this.gtm = new GtmKernel(this.client);
|
|
10166
|
+
this.publicGroundTruth = new PublicGroundTruth(this.client);
|
|
8686
10167
|
}
|
|
8687
10168
|
/** Get current workspace info including credits */
|
|
8688
10169
|
async getWorkspace() {
|
|
@@ -8841,6 +10322,13 @@ async function main() {
|
|
|
8841
10322
|
await handleGtmCommand(signaliz, process.argv.slice(3));
|
|
8842
10323
|
break;
|
|
8843
10324
|
}
|
|
10325
|
+
case "public-data":
|
|
10326
|
+
case "ground-truth":
|
|
10327
|
+
case "public-ground-truth": {
|
|
10328
|
+
const signaliz = await createSignalizClient();
|
|
10329
|
+
await handlePublicGroundTruthCommand(signaliz, process.argv.slice(3));
|
|
10330
|
+
break;
|
|
10331
|
+
}
|
|
8844
10332
|
case "campaign-agent":
|
|
8845
10333
|
case "campaign-builder": {
|
|
8846
10334
|
await handleCampaignAgentCommand(createSignalizClient, process.argv.slice(3));
|
|
@@ -8850,6 +10338,51 @@ async function main() {
|
|
|
8850
10338
|
printHelp();
|
|
8851
10339
|
}
|
|
8852
10340
|
}
|
|
10341
|
+
async function handlePublicGroundTruthCommand(signaliz, argv) {
|
|
10342
|
+
const subcommand = argv[0] && !argv[0].startsWith("--") ? argv[0] : "search";
|
|
10343
|
+
if (!subcommand || subcommand === "help" || subcommand === "--help" || subcommand === "-h") {
|
|
10344
|
+
printPublicGroundTruthHelp();
|
|
10345
|
+
return;
|
|
10346
|
+
}
|
|
10347
|
+
if (subcommand === "sources" || subcommand === "list-sources") {
|
|
10348
|
+
const flags2 = parseFlags(argv.slice(subcommand === argv[0] ? 1 : 0));
|
|
10349
|
+
const result2 = await signaliz.publicGroundTruth.listSources({
|
|
10350
|
+
query: stringFlag(flags2, "query", "q", "search"),
|
|
10351
|
+
status: stringFlag(flags2, "status"),
|
|
10352
|
+
limit: numberFlag(flags2, "limit")
|
|
10353
|
+
});
|
|
10354
|
+
if (booleanFlag(flags2, "json")) {
|
|
10355
|
+
printJson(result2);
|
|
10356
|
+
} else {
|
|
10357
|
+
printPublicGroundTruthSources(result2);
|
|
10358
|
+
}
|
|
10359
|
+
return;
|
|
10360
|
+
}
|
|
10361
|
+
if (subcommand !== "search") {
|
|
10362
|
+
throw new Error(`Unknown public-data command: ${subcommand}`);
|
|
10363
|
+
}
|
|
10364
|
+
const flags = parseFlags(argv.slice(subcommand === argv[0] ? 1 : 0));
|
|
10365
|
+
const query = stringFlag(flags, "query", "q", "search");
|
|
10366
|
+
const sourceId = stringFlag(flags, "source-id", "sourceId");
|
|
10367
|
+
const entityType = stringFlag(flags, "entity-type", "entityType");
|
|
10368
|
+
const filters = publicGroundTruthFiltersFromFlags(flags);
|
|
10369
|
+
if (!query && !sourceId && !entityType && Object.keys(filters).length === 0) {
|
|
10370
|
+
throw new Error("public-data search requires --query or at least one filter");
|
|
10371
|
+
}
|
|
10372
|
+
const result = await signaliz.publicGroundTruth.search({
|
|
10373
|
+
query,
|
|
10374
|
+
sourceId,
|
|
10375
|
+
entityType,
|
|
10376
|
+
...filters,
|
|
10377
|
+
limit: numberFlag(flags, "limit"),
|
|
10378
|
+
offset: numberFlag(flags, "offset")
|
|
10379
|
+
});
|
|
10380
|
+
if (booleanFlag(flags, "json")) {
|
|
10381
|
+
printJson(result);
|
|
10382
|
+
} else {
|
|
10383
|
+
printPublicGroundTruthSearch(result);
|
|
10384
|
+
}
|
|
10385
|
+
}
|
|
8853
10386
|
async function handleGtmCommand(signaliz, argv) {
|
|
8854
10387
|
const subcommand = argv[0];
|
|
8855
10388
|
if (!subcommand || subcommand === "help" || subcommand === "--help" || subcommand === "-h") {
|
|
@@ -9836,6 +11369,69 @@ function jsonObjectFromString(value, label) {
|
|
|
9836
11369
|
}
|
|
9837
11370
|
return parsed;
|
|
9838
11371
|
}
|
|
11372
|
+
var PUBLIC_GROUND_TRUTH_CLI_FILTERS = [
|
|
11373
|
+
["industry", "industry"],
|
|
11374
|
+
["location", "location"],
|
|
11375
|
+
["nativeId", "native-id", "nativeId"],
|
|
11376
|
+
["entityName", "entity-name", "entityName"],
|
|
11377
|
+
["domain", "domain"],
|
|
11378
|
+
["websiteUrl", "website-url", "websiteUrl"],
|
|
11379
|
+
["phone", "phone"],
|
|
11380
|
+
["email", "email"],
|
|
11381
|
+
["city", "city"],
|
|
11382
|
+
["state", "state"],
|
|
11383
|
+
["postalCode", "postal-code", "postalCode"],
|
|
11384
|
+
["country", "country"],
|
|
11385
|
+
["sourceUrl", "source-url", "sourceUrl"],
|
|
11386
|
+
["naics", "naics"],
|
|
11387
|
+
["industryCode", "industry-code", "industryCode"],
|
|
11388
|
+
["industryType", "industry-type", "industryType"],
|
|
11389
|
+
["year", "year"],
|
|
11390
|
+
["quarter", "quarter"],
|
|
11391
|
+
["areaFips", "area-fips", "areaFips"],
|
|
11392
|
+
["geoId", "geo-id", "geoId"],
|
|
11393
|
+
["ownCode", "own-code", "ownCode"],
|
|
11394
|
+
["sourceUpdatedAfter", "source-updated-after", "sourceUpdatedAfter"],
|
|
11395
|
+
["sourceUpdatedBefore", "source-updated-before", "sourceUpdatedBefore"],
|
|
11396
|
+
["observedAfter", "observed-after", "observedAfter"],
|
|
11397
|
+
["observedBefore", "observed-before", "observedBefore"]
|
|
11398
|
+
];
|
|
11399
|
+
function objectFromKeyValueFlags(flags, keyValueNames, jsonNames) {
|
|
11400
|
+
const object = {};
|
|
11401
|
+
for (const jsonName of jsonNames) {
|
|
11402
|
+
const parsed = jsonObjectFlag(flags, jsonName);
|
|
11403
|
+
if (parsed) Object.assign(object, parsed);
|
|
11404
|
+
}
|
|
11405
|
+
for (const pair of repeatedStringFlag(flags, ...keyValueNames)) {
|
|
11406
|
+
const eq = pair.indexOf("=");
|
|
11407
|
+
if (eq <= 0) throw new Error(`Expected key=value for --${keyValueNames[0]}`);
|
|
11408
|
+
const key = pair.slice(0, eq).trim();
|
|
11409
|
+
const value = pair.slice(eq + 1).trim();
|
|
11410
|
+
if (!key) throw new Error(`Expected non-empty key for --${keyValueNames[0]}`);
|
|
11411
|
+
object[key] = value;
|
|
11412
|
+
}
|
|
11413
|
+
return Object.keys(object).length > 0 ? object : void 0;
|
|
11414
|
+
}
|
|
11415
|
+
function publicGroundTruthFiltersFromFlags(flags) {
|
|
11416
|
+
const filters = {};
|
|
11417
|
+
for (const [paramName, ...flagNames] of PUBLIC_GROUND_TRUTH_CLI_FILTERS) {
|
|
11418
|
+
const value = stringFlag(flags, ...flagNames);
|
|
11419
|
+
if (value) filters[paramName] = value;
|
|
11420
|
+
}
|
|
11421
|
+
const joinKeys = objectFromKeyValueFlags(
|
|
11422
|
+
flags,
|
|
11423
|
+
["join-key", "joinKey"],
|
|
11424
|
+
["join-keys-json", "joinKeysJson"]
|
|
11425
|
+
);
|
|
11426
|
+
const rowData = objectFromKeyValueFlags(
|
|
11427
|
+
flags,
|
|
11428
|
+
["row-data", "rowData"],
|
|
11429
|
+
["row-data-json", "rowDataJson"]
|
|
11430
|
+
);
|
|
11431
|
+
if (joinKeys) filters.joinKeys = joinKeys;
|
|
11432
|
+
if (rowData) filters.rowData = rowData;
|
|
11433
|
+
return filters;
|
|
11434
|
+
}
|
|
9839
11435
|
function printResult(result, flags) {
|
|
9840
11436
|
if (booleanFlag(flags, "json")) {
|
|
9841
11437
|
printJson(result);
|
|
@@ -9912,10 +11508,59 @@ function printCampaignAgentExecution(payload, flags) {
|
|
|
9912
11508
|
printJson(payload);
|
|
9913
11509
|
return;
|
|
9914
11510
|
}
|
|
11511
|
+
printCampaignAgentOperatorVerdict(payload);
|
|
9915
11512
|
printCampaignAgentPlan(payload.plan);
|
|
9916
11513
|
console.log("\nResult:");
|
|
9917
11514
|
printJson(payload.result);
|
|
9918
11515
|
}
|
|
11516
|
+
function printCampaignAgentOperatorVerdict(payload) {
|
|
11517
|
+
const result = asRecord4(payload.result);
|
|
11518
|
+
const build = hasRecordKeys(asRecord4(result.build)) ? asRecord4(result.build) : result;
|
|
11519
|
+
const finalStatus = asRecord4(result.finalStatus);
|
|
11520
|
+
const deliveryApproval = asRecord4(result.deliveryApproval);
|
|
11521
|
+
const status = textFromRecord(finalStatus, "status") ?? textFromRecord(build, "status") ?? "unknown";
|
|
11522
|
+
const dryRun = build.dryRun === true || build.dry_run === true || status === "dry_run";
|
|
11523
|
+
const campaignBuildId = textFromRecord(build, "campaignBuildId", "campaign_build_id") ?? textFromRecord(finalStatus, "campaignBuildId", "campaign_build_id");
|
|
11524
|
+
const campaignId = textFromRecord(build, "campaignId", "campaign_id") ?? textFromRecord(finalStatus, "campaignId", "campaign_id");
|
|
11525
|
+
if (dryRun) {
|
|
11526
|
+
console.log("Operator verdict: dry run complete; nothing launched.");
|
|
11527
|
+
console.log("Safety: Dry-run only. No spend, provider write, sender load, delivery, or launch ran.");
|
|
11528
|
+
} else if (textFromRecord(finalStatus, "status") === "completed") {
|
|
11529
|
+
console.log("Operator verdict: approved campaign build completed.");
|
|
11530
|
+
console.log("Safety: Approved build path. Review rows and artifacts before any delivery expansion.");
|
|
11531
|
+
} else {
|
|
11532
|
+
console.log(`Operator verdict: approved campaign build ${status}.`);
|
|
11533
|
+
console.log("Safety: Approved build path. Spend and provider writes require the supplied approval packet; delivery remains separately gated.");
|
|
11534
|
+
}
|
|
11535
|
+
console.log(`Approval state: ${campaignAgentApprovalState(payload)}`);
|
|
11536
|
+
if (campaignId) console.log(`Campaign ID: ${campaignId}`);
|
|
11537
|
+
if (campaignBuildId) console.log(`Campaign build ID: ${campaignBuildId}`);
|
|
11538
|
+
if (hasRecordKeys(finalStatus)) console.log(`Final status: ${textFromRecord(finalStatus, "status") ?? "unknown"}`);
|
|
11539
|
+
if (hasRecordKeys(deliveryApproval)) console.log(`Delivery approval: ${textFromRecord(deliveryApproval, "status") ?? "unknown"}`);
|
|
11540
|
+
console.log(`Next safe command: ${campaignAgentNextSafeCommand(payload.plan, dryRun, campaignBuildId)}`);
|
|
11541
|
+
console.log("");
|
|
11542
|
+
}
|
|
11543
|
+
function campaignAgentApprovalState(payload) {
|
|
11544
|
+
if (payload.approval) return "approval packet supplied";
|
|
11545
|
+
const required = payload.plan.approvals.map((item) => item.type);
|
|
11546
|
+
return required.length ? `missing ${required.join(", ")}` : "no explicit approvals required";
|
|
11547
|
+
}
|
|
11548
|
+
function campaignAgentNextSafeCommand(plan, dryRun, campaignBuildId) {
|
|
11549
|
+
if (campaignBuildId) return `signaliz campaign-agent review ${campaignBuildId} --limit 100`;
|
|
11550
|
+
if (!dryRun) return "signaliz campaign-agent status <campaign-build-id>";
|
|
11551
|
+
return [
|
|
11552
|
+
"signaliz campaign-agent build-approved",
|
|
11553
|
+
"--goal",
|
|
11554
|
+
shellQuote(plan.campaignName),
|
|
11555
|
+
"--target-count",
|
|
11556
|
+
String(plan.targetCount),
|
|
11557
|
+
"--confirm-launch",
|
|
11558
|
+
"--approve-all",
|
|
11559
|
+
"--approved-by <operator-email>",
|
|
11560
|
+
"--spend-limit",
|
|
11561
|
+
String(plan.estimatedCredits)
|
|
11562
|
+
].join(" ");
|
|
11563
|
+
}
|
|
9919
11564
|
function printCampaignAgentReadiness(readiness) {
|
|
9920
11565
|
const summary = asRecord4(readiness.summary);
|
|
9921
11566
|
const plan = readiness.plan;
|
|
@@ -9954,6 +11599,13 @@ function printCampaignAgentBuildStatus(status) {
|
|
|
9954
11599
|
if (status.campaignId) console.log(`Campaign ID: ${status.campaignId}`);
|
|
9955
11600
|
console.log(`Status: ${status.status}`);
|
|
9956
11601
|
console.log(`Phase: ${status.currentPhase || "N/A"}`);
|
|
11602
|
+
const terminalState = asRecord4(status.terminalState);
|
|
11603
|
+
if (terminalState.kind) {
|
|
11604
|
+
console.log(`Terminal state: ${terminalState.kind} (${terminalState.label || "no label"})`);
|
|
11605
|
+
if (terminalState.heartbeatAgeSeconds !== void 0 && terminalState.heartbeatAgeSeconds !== null) {
|
|
11606
|
+
console.log(`Heartbeat age: ${terminalState.heartbeatAgeSeconds}s`);
|
|
11607
|
+
}
|
|
11608
|
+
}
|
|
9957
11609
|
console.log(`Rows: ${status.recordsSucceeded}/${status.recordsTotal} succeeded, ${status.recordsFailed} failed`);
|
|
9958
11610
|
printCampaignCustomerRowCounts(status);
|
|
9959
11611
|
console.log(`Artifacts: ${status.artifactCount}`);
|
|
@@ -9975,6 +11627,8 @@ function printCampaignAgentBuildStatus(status) {
|
|
|
9975
11627
|
console.log(`Next: ${status.nextAction}`);
|
|
9976
11628
|
} else if (status.status === "pending_approval") {
|
|
9977
11629
|
console.log(`Next: signaliz campaign-agent approve ${status.campaignBuildId} --destination-type webhook`);
|
|
11630
|
+
} else if (terminalState.safeNextAction) {
|
|
11631
|
+
console.log(`Next: ${terminalState.safeNextAction}`);
|
|
9978
11632
|
}
|
|
9979
11633
|
}
|
|
9980
11634
|
function printCampaignCustomerRowCounts(status) {
|
|
@@ -9982,7 +11636,10 @@ function printCampaignCustomerRowCounts(status) {
|
|
|
9982
11636
|
if (!counts || typeof counts !== "object") return;
|
|
9983
11637
|
const value = (camel, snake) => counts[camel] ?? counts[snake] ?? "n/a";
|
|
9984
11638
|
const requested = value("requestedTarget", "requested_target");
|
|
9985
|
-
|
|
11639
|
+
const copied = value("copiedRows", "copied_rows");
|
|
11640
|
+
const copySkipped = value("copySkippedRows", "copy_skipped_rows");
|
|
11641
|
+
const copyLabel = typeof copySkipped === "number" && copySkipped > 0 && (!copied || copied === "n/a") ? `copy-skipped ${copySkipped}` : `copied ${copied}`;
|
|
11642
|
+
console.log(`Customer rows: accepted ${value("acceptedRows", "accepted_rows")}/${requested}, ${copyLabel}, approval-ready ${value("approvalReadyRows", "approval_ready_rows")}, QA-ready ${value("qaReadyRows", "qa_ready_rows")}, delivered ${value("deliveredRows", "delivered_rows")}`);
|
|
9986
11643
|
const shortfalls = [
|
|
9987
11644
|
["accepted", value("acceptedShortfall", "accepted_shortfall")],
|
|
9988
11645
|
["usable", value("usableShortfall", "usable_shortfall")],
|
|
@@ -9998,17 +11655,20 @@ function printCampaignAgentBuildReview(review) {
|
|
|
9998
11655
|
console.log(`Campaign: ${review.status?.name || review.campaignBuildId}`);
|
|
9999
11656
|
console.log(`Status: ${summary.status || review.status?.status}`);
|
|
10000
11657
|
console.log(`Phase: ${summary.phase || review.status?.currentPhase || "N/A"}`);
|
|
11658
|
+
console.log(`Terminal state: ${summary.terminalState || review.status?.terminalState?.kind || "unknown"}`);
|
|
10001
11659
|
console.log(`Rows: ${summary.sampledRows || 0} sampled, ${summary.availableRows || 0} available`);
|
|
10002
11660
|
console.log(`Qualified: ${summary.qualifiedRows || 0}`);
|
|
10003
11661
|
console.log(`Emails: ${summary.rowsWithEmail || 0}`);
|
|
10004
11662
|
console.log(`Copy ready: ${summary.copyReadyRows || 0}`);
|
|
10005
11663
|
console.log(`Artifacts: ${summary.artifactCount || 0}`);
|
|
11664
|
+
printCampaignAgentNorthStarScorecard(review.northStarScorecard);
|
|
10006
11665
|
if (review.campaignBuildId) printCampaignArtifactDownload(review.status, review.campaignBuildId);
|
|
10007
11666
|
console.log(`Delivery approval ready: ${summary.readyForDeliveryApproval === true ? "yes" : "no"}`);
|
|
10008
11667
|
if (Array.isArray(review.gates) && review.gates.length > 0) {
|
|
10009
11668
|
console.log("\nGates:");
|
|
10010
11669
|
for (const gate of review.gates) {
|
|
10011
|
-
|
|
11670
|
+
const status = String(gate.status || (gate.passed ? "pass" : "blocked")).toUpperCase();
|
|
11671
|
+
console.log(`- ${status} ${gate.label}: ${gate.detail}`);
|
|
10012
11672
|
}
|
|
10013
11673
|
}
|
|
10014
11674
|
const warnings = Array.isArray(summary.warnings) ? summary.warnings : [];
|
|
@@ -10022,6 +11682,21 @@ function printCampaignAgentBuildReview(review) {
|
|
|
10022
11682
|
for (const action of nextActions) console.log(`- ${action}`);
|
|
10023
11683
|
}
|
|
10024
11684
|
}
|
|
11685
|
+
function printCampaignAgentNorthStarScorecard(scorecard) {
|
|
11686
|
+
const card = asRecord4(scorecard);
|
|
11687
|
+
if (!card.version) return;
|
|
11688
|
+
const score = card.score === null || card.score === void 0 ? "pending" : `${card.score}%`;
|
|
11689
|
+
console.log(`North Star: ${String(card.status || "unknown")} (${score})`);
|
|
11690
|
+
if (card.moatState) console.log(`Moat state: ${card.moatState}`);
|
|
11691
|
+
const metrics = Array.isArray(card.metrics) ? card.metrics : [];
|
|
11692
|
+
if (metrics.length > 0) {
|
|
11693
|
+
console.log("\nNorth Star gates:");
|
|
11694
|
+
for (const metric of metrics.slice(0, 12)) {
|
|
11695
|
+
const item = asRecord4(metric);
|
|
11696
|
+
console.log(`- ${String(item.status || "review").toUpperCase()} ${item.label || item.id}: ${item.detail || ""}`);
|
|
11697
|
+
}
|
|
11698
|
+
}
|
|
11699
|
+
}
|
|
10025
11700
|
function formatCampaignAgentRows(rows) {
|
|
10026
11701
|
return rows.map((row) => {
|
|
10027
11702
|
const data = asRecord4(row.data);
|
|
@@ -10099,6 +11774,20 @@ function printCampaignAgentCopySnippets(rows, limit = 5) {
|
|
|
10099
11774
|
function asRecord4(value) {
|
|
10100
11775
|
return value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
10101
11776
|
}
|
|
11777
|
+
function hasRecordKeys(value) {
|
|
11778
|
+
return Object.keys(value).length > 0;
|
|
11779
|
+
}
|
|
11780
|
+
function textFromRecord(record, ...keys) {
|
|
11781
|
+
for (const key of keys) {
|
|
11782
|
+
const value = record[key];
|
|
11783
|
+
if (typeof value === "string" && value.trim()) return value.trim();
|
|
11784
|
+
if (typeof value === "number" && Number.isFinite(value)) return String(value);
|
|
11785
|
+
}
|
|
11786
|
+
return void 0;
|
|
11787
|
+
}
|
|
11788
|
+
function shellQuote(value) {
|
|
11789
|
+
return `'${String(value || "").replace(/'/g, `'\\''`)}'`;
|
|
11790
|
+
}
|
|
10102
11791
|
function printCampaignAgentProof(proof) {
|
|
10103
11792
|
console.log(`Campaign-agent proof: ${proof.success ? "passed" : "failed"}`);
|
|
10104
11793
|
const campaign = asRecord4(proof.campaign);
|
|
@@ -10116,6 +11805,51 @@ function printCampaignAgentProof(proof) {
|
|
|
10116
11805
|
function printJson(value) {
|
|
10117
11806
|
console.log(JSON.stringify(value, null, 2));
|
|
10118
11807
|
}
|
|
11808
|
+
function truncateCell(value, width) {
|
|
11809
|
+
const text = String(value ?? "").replace(/\s+/g, " ").trim();
|
|
11810
|
+
return text.length > width ? `${text.slice(0, Math.max(width - 3, 0))}...` : text;
|
|
11811
|
+
}
|
|
11812
|
+
function printPublicGroundTruthSearch(result) {
|
|
11813
|
+
const records = Array.isArray(result.records) ? result.records : [];
|
|
11814
|
+
console.log(`Public data search: ${result.total_count ?? 0} matches (${records.length} returned)`);
|
|
11815
|
+
if (result.query) console.log(`Query: ${result.query}`);
|
|
11816
|
+
if (result.source_id) console.log(`Source: ${result.source_id}`);
|
|
11817
|
+
if (result.entity_type) console.log(`Entity type: ${result.entity_type}`);
|
|
11818
|
+
if (!records.length) {
|
|
11819
|
+
console.log("No records matched.");
|
|
11820
|
+
return;
|
|
11821
|
+
}
|
|
11822
|
+
console.log("");
|
|
11823
|
+
console.log("Source".padEnd(22) + "Native ID".padEnd(22) + "Name".padEnd(42) + "Industry".padEnd(28) + "Domain".padEnd(24) + "Loc".padEnd(12) + "Match");
|
|
11824
|
+
console.log("-".repeat(160));
|
|
11825
|
+
for (const record of records) {
|
|
11826
|
+
const loc = [record.city, record.state].filter(Boolean).join(", ");
|
|
11827
|
+
const industry = [record.industry_code, record.industry_name].filter(Boolean).join(" ");
|
|
11828
|
+
console.log(
|
|
11829
|
+
truncateCell(record.source_id, 21).padEnd(22) + truncateCell(record.native_id, 21).padEnd(22) + truncateCell(record.entity_name, 41).padEnd(42) + truncateCell(industry, 27).padEnd(28) + truncateCell(record.domain, 23).padEnd(24) + truncateCell(loc, 11).padEnd(12) + truncateCell(record.match_type, 16)
|
|
11830
|
+
);
|
|
11831
|
+
}
|
|
11832
|
+
if (result.next_offset !== null && result.next_offset !== void 0) {
|
|
11833
|
+
console.log(`
|
|
11834
|
+
Next page: --offset ${result.next_offset}`);
|
|
11835
|
+
}
|
|
11836
|
+
}
|
|
11837
|
+
function printPublicGroundTruthSources(result) {
|
|
11838
|
+
const sources = Array.isArray(result.sources) ? result.sources : [];
|
|
11839
|
+
console.log(`Public data sources: ${sources.length}/${result.total ?? sources.length}`);
|
|
11840
|
+
if (!sources.length) {
|
|
11841
|
+
console.log("No sources matched.");
|
|
11842
|
+
return;
|
|
11843
|
+
}
|
|
11844
|
+
console.log("");
|
|
11845
|
+
console.log("Source ID".padEnd(30) + "Status".padEnd(12) + "Rung".padEnd(7) + "Join key".padEnd(20) + "Cadence".padEnd(16) + "Name");
|
|
11846
|
+
console.log("-".repeat(120));
|
|
11847
|
+
for (const source of sources) {
|
|
11848
|
+
console.log(
|
|
11849
|
+
truncateCell(source.id, 29).padEnd(30) + truncateCell(source.ingestion_status, 11).padEnd(12) + String(source.ground_truth_rung ?? "").padEnd(7) + truncateCell(source.primary_join_key || source.join_key_quality, 19).padEnd(20) + truncateCell(source.update_cadence, 15).padEnd(16) + truncateCell(source.name, 40)
|
|
11850
|
+
);
|
|
11851
|
+
}
|
|
11852
|
+
}
|
|
10119
11853
|
function printHelp() {
|
|
10120
11854
|
console.log(`
|
|
10121
11855
|
Signaliz CLI v1.0.0
|
|
@@ -10123,6 +11857,8 @@ Signaliz CLI v1.0.0
|
|
|
10123
11857
|
Usage:
|
|
10124
11858
|
signaliz test Verify API connectivity
|
|
10125
11859
|
signaliz tools List all available MCP tools
|
|
11860
|
+
signaliz public-data search --query "swift transportation" --limit 10
|
|
11861
|
+
signaliz public-data sources --status ready
|
|
10126
11862
|
signaliz gtm context --json Load GTM Kernel workspace context
|
|
10127
11863
|
signaliz gtm bootstrap --json Inspect GTM Kernel readiness
|
|
10128
11864
|
signaliz gtm templates --json List private-safe campaign strategy templates
|
|
@@ -10153,6 +11889,25 @@ Environment:
|
|
|
10153
11889
|
SIGNALIZ_BASE_URL Optional API base URL override
|
|
10154
11890
|
`);
|
|
10155
11891
|
}
|
|
11892
|
+
function printPublicGroundTruthHelp() {
|
|
11893
|
+
console.log(`
|
|
11894
|
+
Signaliz public-data commands:
|
|
11895
|
+
|
|
11896
|
+
signaliz public-data search [--query TEXT] [--industry TEXT] [--location TEXT] [--source-id ID] [--domain DOMAIN] [--naics CODE] [--state ST] [--year YYYY] [--join-key k=v] [--row-data k=v] [--limit N] [--offset N] [--json]
|
|
11897
|
+
signaliz public-data sources [--query TEXT] [--status ready|partial|blocked|planned] [--limit N] [--json]
|
|
11898
|
+
|
|
11899
|
+
Aliases:
|
|
11900
|
+
signaliz ground-truth search ...
|
|
11901
|
+
|
|
11902
|
+
Examples:
|
|
11903
|
+
signaliz public-data search --query "swift transportation" --source-id fmcsa_company_census --limit 10
|
|
11904
|
+
signaliz public-data search --industry "software publishers" --location CA --limit 25 --json
|
|
11905
|
+
signaliz public-data search --source-id bls_qcew --naics 541511 --state CA --year 2025 --json
|
|
11906
|
+
signaliz public-data search --domain swifttrans.com --json
|
|
11907
|
+
signaliz public-data search --join-key ein=123456789 --json
|
|
11908
|
+
signaliz public-data sources --status ready --json
|
|
11909
|
+
`);
|
|
11910
|
+
}
|
|
10156
11911
|
function printGtmHelp() {
|
|
10157
11912
|
console.log(`
|
|
10158
11913
|
Signaliz GTM commands:
|