@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/index.js
CHANGED
|
@@ -31,10 +31,12 @@ __export(index_exports, {
|
|
|
31
31
|
GtmKernel: () => GtmKernel,
|
|
32
32
|
Icps: () => Icps,
|
|
33
33
|
Ops: () => Ops,
|
|
34
|
+
PublicGroundTruth: () => PublicGroundTruth,
|
|
34
35
|
Signaliz: () => Signaliz,
|
|
35
36
|
SignalizError: () => SignalizError,
|
|
36
37
|
applyCampaignBuilderStrategyTemplate: () => applyCampaignBuilderStrategyTemplate,
|
|
37
38
|
collectExecutionReferences: () => collectExecutionReferences,
|
|
39
|
+
createCampaignBuilderActiveWorkContext: () => createCampaignBuilderActiveWorkContext,
|
|
38
40
|
createCampaignBuilderAgentPlan: () => createCampaignBuilderAgentPlan,
|
|
39
41
|
createCampaignBuilderAgentRequestTemplate: () => createCampaignBuilderAgentRequestTemplate,
|
|
40
42
|
createCampaignBuilderApproval: () => createCampaignBuilderApproval,
|
|
@@ -501,6 +503,38 @@ var Signals = class {
|
|
|
501
503
|
constructor(client) {
|
|
502
504
|
this.client = client;
|
|
503
505
|
}
|
|
506
|
+
/** Turn the strongest supported company signal into three complete, evidence-backed emails. */
|
|
507
|
+
async signalToCopy(params) {
|
|
508
|
+
const data = await this.client.post("api/v1/signal-to-copy", {
|
|
509
|
+
company_domain: params.companyDomain,
|
|
510
|
+
person_name: params.personName,
|
|
511
|
+
title: params.title,
|
|
512
|
+
campaign_offer: params.campaignOffer,
|
|
513
|
+
research_prompt: params.researchPrompt
|
|
514
|
+
});
|
|
515
|
+
return {
|
|
516
|
+
success: data.success ?? true,
|
|
517
|
+
strongestSignal: data.strongest_signal ?? "",
|
|
518
|
+
whyNow: data.why_now ?? "",
|
|
519
|
+
subjectLine: data.subject_line ?? "",
|
|
520
|
+
openingLine: data.opening_line ?? "",
|
|
521
|
+
confidence: data.confidence ?? 0,
|
|
522
|
+
evidenceUrl: data.evidence_url ?? "",
|
|
523
|
+
researchPrompt: data.research_prompt,
|
|
524
|
+
variations: (data.variations ?? []).map((v) => ({
|
|
525
|
+
style: v.style,
|
|
526
|
+
subjectLine: v.subject_line ?? "",
|
|
527
|
+
openingLine: v.opening_line ?? "",
|
|
528
|
+
cta: v.cta ?? "",
|
|
529
|
+
prediction: v.prediction,
|
|
530
|
+
email: v.email
|
|
531
|
+
}))
|
|
532
|
+
};
|
|
533
|
+
}
|
|
534
|
+
/** @deprecated Use signalToCopy. Retained for compatibility. */
|
|
535
|
+
async personalize(params) {
|
|
536
|
+
return this.signalToCopy(params);
|
|
537
|
+
}
|
|
504
538
|
/** Enrich a company with actionable signals (V1) */
|
|
505
539
|
async enrich(params) {
|
|
506
540
|
const args = {
|
|
@@ -509,6 +543,9 @@ var Signals = class {
|
|
|
509
543
|
if (params.domain) args.domain = params.domain;
|
|
510
544
|
if (params.researchPrompt) args.research_prompt = params.researchPrompt;
|
|
511
545
|
if (params.signalTypes) args.signal_types = params.signalTypes;
|
|
546
|
+
if (params.targetSignalCount) args.target_signal_count = params.targetSignalCount;
|
|
547
|
+
if (params.lookbackDays) args.lookback_days = params.lookbackDays;
|
|
548
|
+
if (params.enableDeepSearch !== void 0) args.enable_deep_search = params.enableDeepSearch;
|
|
512
549
|
const data = await this.client.mcp("tools/call", {
|
|
513
550
|
name: "enrich_company_signals",
|
|
514
551
|
arguments: args
|
|
@@ -518,6 +555,16 @@ var Signals = class {
|
|
|
518
555
|
signals: (data.signals ?? []).map((s) => ({
|
|
519
556
|
title: s.title,
|
|
520
557
|
signalType: s.signal_type,
|
|
558
|
+
sourceType: s.source_type ?? s.signal_classification?.label ?? "unknown",
|
|
559
|
+
sourceProvenance: s.source_provenance ?? s.metadata?.source_provenance ?? null,
|
|
560
|
+
signalFamily: s.signal_family ?? s.signal_type ?? null,
|
|
561
|
+
signalEventType: s.signal_event_type ?? s.signal_classification?.slug ?? null,
|
|
562
|
+
signalEventLabel: s.signal_event_label ?? s.signal_classification?.label ?? null,
|
|
563
|
+
signalClassification: s.signal_classification ? {
|
|
564
|
+
label: s.signal_classification.label,
|
|
565
|
+
slug: s.signal_classification.slug,
|
|
566
|
+
rationale: s.signal_classification.rationale
|
|
567
|
+
} : null,
|
|
521
568
|
confidenceScore: s.confidence_score ?? 0,
|
|
522
569
|
detectedAt: s.detected_at ?? "",
|
|
523
570
|
url: s.url,
|
|
@@ -558,8 +605,17 @@ var Signals = class {
|
|
|
558
605
|
content: s.content ?? "",
|
|
559
606
|
date: s.date ?? null,
|
|
560
607
|
sourceUrl: s.source_url ?? null,
|
|
561
|
-
sourceType: s.source_type ?? "unknown",
|
|
562
|
-
|
|
608
|
+
sourceType: s.source_type ?? s.signal_classification?.label ?? "unknown",
|
|
609
|
+
sourceProvenance: s.source_provenance ?? s.metadata?.source_provenance ?? null,
|
|
610
|
+
signalFamily: s.signal_family ?? s.type ?? null,
|
|
611
|
+
signalEventType: s.signal_event_type ?? s.signal_classification?.slug ?? null,
|
|
612
|
+
signalEventLabel: s.signal_event_label ?? s.signal_classification?.label ?? null,
|
|
613
|
+
confidence: s.confidence ?? null,
|
|
614
|
+
signalClassification: s.signal_classification ? {
|
|
615
|
+
label: s.signal_classification.label,
|
|
616
|
+
slug: s.signal_classification.slug,
|
|
617
|
+
rationale: s.signal_classification.rationale
|
|
618
|
+
} : null
|
|
563
619
|
})),
|
|
564
620
|
signalCount: data.signal_count ?? 0,
|
|
565
621
|
intelligence: data.intelligence ? {
|
|
@@ -602,6 +658,58 @@ var Signals = class {
|
|
|
602
658
|
}
|
|
603
659
|
};
|
|
604
660
|
}
|
|
661
|
+
/** Plan or run experimental Signal Fusion with explicit spend controls. */
|
|
662
|
+
async fusion(params) {
|
|
663
|
+
const args = {};
|
|
664
|
+
if (params.companyName) args.company_name = params.companyName;
|
|
665
|
+
if (params.domain) args.domain = params.domain;
|
|
666
|
+
if (params.companyDomain) args.company_domain = params.companyDomain;
|
|
667
|
+
if (params.linkedinUrl) args.linkedin_url = params.linkedinUrl;
|
|
668
|
+
if (params.companies) args.companies = params.companies;
|
|
669
|
+
if (params.preset) args.preset = params.preset;
|
|
670
|
+
if (params.researchPrompt) args.research_prompt = params.researchPrompt;
|
|
671
|
+
if (params.signalTypes) args.signal_types = params.signalTypes;
|
|
672
|
+
if (params.lookbackDays) args.lookback_days = params.lookbackDays;
|
|
673
|
+
if (params.targetSignalCount) args.target_signal_count = params.targetSignalCount;
|
|
674
|
+
if (params.maxToolCalls) args.max_tool_calls = params.maxToolCalls;
|
|
675
|
+
if (params.maxTokens) args.max_tokens = params.maxTokens;
|
|
676
|
+
if (params.timeoutMs) args.timeout_ms = params.timeoutMs;
|
|
677
|
+
const dryRun = params.dryRun ?? params.dry_run;
|
|
678
|
+
const confirmSpend = params.confirmSpend ?? params.confirm_spend;
|
|
679
|
+
const maxCredits = params.maxCredits ?? params.max_credits;
|
|
680
|
+
const maxCostUsd = params.maxCostUsd ?? params.max_cost_usd;
|
|
681
|
+
if (dryRun !== void 0) args.dry_run = dryRun;
|
|
682
|
+
if (confirmSpend !== void 0) args.confirm_spend = confirmSpend;
|
|
683
|
+
if (maxCredits !== void 0) args.max_credits = maxCredits;
|
|
684
|
+
if (maxCostUsd !== void 0) args.max_cost_usd = maxCostUsd;
|
|
685
|
+
const data = await this.client.post("signal-fusion", args);
|
|
686
|
+
return {
|
|
687
|
+
success: data.success ?? false,
|
|
688
|
+
capability: data.capability ?? "signal_fusion",
|
|
689
|
+
displayName: data.display_name ?? "Signal Fusion",
|
|
690
|
+
company: data.company,
|
|
691
|
+
signals: (data.signals ?? []).map((s) => ({
|
|
692
|
+
id: s.id,
|
|
693
|
+
title: s.title,
|
|
694
|
+
type: s.type,
|
|
695
|
+
content: s.content ?? "",
|
|
696
|
+
date: s.date ?? null,
|
|
697
|
+
sourceUrl: s.source_url ?? null,
|
|
698
|
+
sourceType: s.source_type ?? "unknown",
|
|
699
|
+
confidence: s.confidence ?? null
|
|
700
|
+
})),
|
|
701
|
+
signalCount: data.signal_count ?? data.signals?.length ?? 0,
|
|
702
|
+
results: data.results ?? [],
|
|
703
|
+
model: data.model,
|
|
704
|
+
fusion: data.fusion,
|
|
705
|
+
costUsd: data.cost_usd ?? 0,
|
|
706
|
+
tokensUsed: data.tokens_used ?? 0,
|
|
707
|
+
costSummary: data.cost_summary,
|
|
708
|
+
creditsUsed: data.total_credits_used ?? data.credits_used ?? 0,
|
|
709
|
+
billingMetadata: data.billing_metadata,
|
|
710
|
+
raw: data
|
|
711
|
+
};
|
|
712
|
+
}
|
|
605
713
|
};
|
|
606
714
|
|
|
607
715
|
// src/resources/systems.ts
|
|
@@ -890,7 +998,11 @@ var Campaigns = class {
|
|
|
890
998
|
maxSupportedTargetCount: data.max_supported_target_count,
|
|
891
999
|
brainContext: data.brain_context ?? {},
|
|
892
1000
|
learningHoldout: data.learning_holdout ?? {},
|
|
893
|
-
providerRoute: mapProviderRoute(data)
|
|
1001
|
+
providerRoute: mapProviderRoute(data),
|
|
1002
|
+
effectiveSourceRouting: recordOrNull(data.effective_source_routing ?? data.source_routing),
|
|
1003
|
+
sourcePlan: recordOrNull(data.source_plan ?? data.plan?.source_plan),
|
|
1004
|
+
sourceRoutes: recordArray(data.source_routes ?? data.source_plan?.routes ?? data.plan?.source_plan?.routes),
|
|
1005
|
+
sourceShards: recordArray(data.source_shards ?? data.source_plan?.shards ?? data.plan?.source_plan?.shards)
|
|
894
1006
|
};
|
|
895
1007
|
}
|
|
896
1008
|
async getCampaignBuildStatus(campaignBuildId) {
|
|
@@ -1036,6 +1148,7 @@ function mapCustomerRowCounts(value) {
|
|
|
1036
1148
|
acceptedRows: numberOrNull(record.accepted_rows) ?? void 0,
|
|
1037
1149
|
usableRows: numberOrNull(record.usable_rows) ?? void 0,
|
|
1038
1150
|
copiedRows: numberOrNull(record.copied_rows) ?? void 0,
|
|
1151
|
+
copySkippedRows: numberOrNull(record.copy_skipped_rows) ?? void 0,
|
|
1039
1152
|
approvalReadyRows: numberOrNull(record.approval_ready_rows) ?? void 0,
|
|
1040
1153
|
qaReadyRows: numberOrNull(record.qa_ready_rows) ?? void 0,
|
|
1041
1154
|
deliveredRows: numberOrNull(record.delivered_rows) ?? void 0,
|
|
@@ -1082,6 +1195,9 @@ function recordOrNull(value) {
|
|
|
1082
1195
|
function stringArray(value) {
|
|
1083
1196
|
return Array.isArray(value) ? value.map((item) => String(item || "").trim()).filter(Boolean) : [];
|
|
1084
1197
|
}
|
|
1198
|
+
function recordArray(value) {
|
|
1199
|
+
return Array.isArray(value) ? value.map(recordOrNull).filter((item) => Boolean(item)) : [];
|
|
1200
|
+
}
|
|
1085
1201
|
function diagnosticMessages(value) {
|
|
1086
1202
|
if (!Array.isArray(value)) return [];
|
|
1087
1203
|
return value.map((item) => {
|
|
@@ -1243,7 +1359,8 @@ function buildArgs(request) {
|
|
|
1243
1359
|
suppress_prior_campaign_ids: request.cacheReusePolicy.suppressPriorCampaignIds,
|
|
1244
1360
|
suppress_prior_list_ids: request.cacheReusePolicy.suppressPriorListIds,
|
|
1245
1361
|
uniqueness: request.cacheReusePolicy.uniqueness,
|
|
1246
|
-
require_usage_metadata: request.cacheReusePolicy.requireUsageMetadata
|
|
1362
|
+
require_usage_metadata: request.cacheReusePolicy.requireUsageMetadata,
|
|
1363
|
+
verified_cache_ttl_days: request.cacheReusePolicy.verifiedCacheTtlDays
|
|
1247
1364
|
};
|
|
1248
1365
|
}
|
|
1249
1366
|
if (request.brainPreflight) args.brain_preflight = request.brainPreflight;
|
|
@@ -1268,7 +1385,8 @@ function buildArgs(request) {
|
|
|
1268
1385
|
geographies: request.icp.geographies,
|
|
1269
1386
|
keywords: request.icp.keywords,
|
|
1270
1387
|
exclusions: request.icp.exclusions,
|
|
1271
|
-
require_verified_email: request.icp.requireVerifiedEmail
|
|
1388
|
+
require_verified_email: request.icp.requireVerifiedEmail,
|
|
1389
|
+
persona_expansion_mode: request.icp.personaExpansionMode
|
|
1272
1390
|
};
|
|
1273
1391
|
}
|
|
1274
1392
|
if (request.policy) {
|
|
@@ -1308,6 +1426,7 @@ function buildArgs(request) {
|
|
|
1308
1426
|
} : void 0,
|
|
1309
1427
|
sequence_steps: request.copy.sequenceSteps,
|
|
1310
1428
|
copy_schema: request.copy.copySchema,
|
|
1429
|
+
evidence_mode: request.copy.evidenceMode,
|
|
1311
1430
|
banned_phrases: request.copy.bannedPhrases,
|
|
1312
1431
|
approval_required: request.copy.approvalRequired,
|
|
1313
1432
|
quality_tier: request.copy.qualityTier
|
|
@@ -1364,7 +1483,8 @@ var DEFAULT_SIGNALIZ_CAMPAIGN_BUILDER_DEFAULTS = {
|
|
|
1364
1483
|
copy: {
|
|
1365
1484
|
enabled: true,
|
|
1366
1485
|
tone: "direct",
|
|
1367
|
-
maxBodyWords: 125
|
|
1486
|
+
maxBodyWords: 125,
|
|
1487
|
+
evidenceMode: "signal_led"
|
|
1368
1488
|
},
|
|
1369
1489
|
delivery: {
|
|
1370
1490
|
enabled: true,
|
|
@@ -1421,7 +1541,8 @@ var CAMPAIGN_BUILDER_OPERATING_PLAYBOOKS = [
|
|
|
1421
1541
|
"Block export when required identity, company, or email fields are missing."
|
|
1422
1542
|
],
|
|
1423
1543
|
activationBoundary: "Cache inventory is read-only. Fresh sourcing, cache writes, export, and sender loading require explicit approval.",
|
|
1424
|
-
memoryKeywords: ["cache inventory", "large list", "unique emails", "top-up sourcing", "source metadata"]
|
|
1544
|
+
memoryKeywords: ["cache inventory", "large list", "unique emails", "top-up sourcing", "source metadata"],
|
|
1545
|
+
knowledgeSources: ["data-ops/contact-data-lifecycle", "data-ops/credit-optimization-guide", "gtm/data-quality-ops", "gtm/lead-generation-strategies"]
|
|
1425
1546
|
},
|
|
1426
1547
|
{
|
|
1427
1548
|
slug: "net-new-suppressed-list",
|
|
@@ -1446,7 +1567,8 @@ var CAMPAIGN_BUILDER_OPERATING_PLAYBOOKS = [
|
|
|
1446
1567
|
"Do not describe rows as fully qualified when the approved path only proves net-new email status."
|
|
1447
1568
|
],
|
|
1448
1569
|
activationBoundary: "Suppression review must pass before export, upload, CRM sync, sender load, or sequence launch.",
|
|
1449
|
-
memoryKeywords: ["suppression", "net-new", "prior email overlap", "domain review", "provenance-rich QA"]
|
|
1570
|
+
memoryKeywords: ["suppression", "net-new", "prior email overlap", "domain review", "provenance-rich QA"],
|
|
1571
|
+
knowledgeSources: ["gtm/data-quality-ops", "data-ops/contact-data-lifecycle", "gtm/outbound-sequencing"]
|
|
1450
1572
|
},
|
|
1451
1573
|
{
|
|
1452
1574
|
slug: "proof-first-vertical-gate",
|
|
@@ -1471,7 +1593,8 @@ var CAMPAIGN_BUILDER_OPERATING_PLAYBOOKS = [
|
|
|
1471
1593
|
"Contact fit should meet the configured threshold before email finding or copy generation."
|
|
1472
1594
|
],
|
|
1473
1595
|
activationBoundary: "Proof gates are required before contact spend, copy, export, or external writes.",
|
|
1474
|
-
memoryKeywords: ["proof gate", "vertical exclusion", "company before contact", "pass review fail", "fit threshold"]
|
|
1596
|
+
memoryKeywords: ["proof gate", "vertical exclusion", "company before contact", "pass review fail", "fit threshold"],
|
|
1597
|
+
knowledgeSources: ["gtm/icp-design-framework", "gtm/strategy/scoring.yaml", "gtm/advanced/account-prioritization-frameworks", "gtm/advanced/predictive-lead-scoring", "gtm/verticals"]
|
|
1475
1598
|
},
|
|
1476
1599
|
{
|
|
1477
1600
|
slug: "signal-led-copy-approval",
|
|
@@ -1496,7 +1619,8 @@ var CAMPAIGN_BUILDER_OPERATING_PLAYBOOKS = [
|
|
|
1496
1619
|
"Destination fields must remain blocked until approval metadata is present."
|
|
1497
1620
|
],
|
|
1498
1621
|
activationBoundary: "Copy readiness is not delivery approval. Export, sync, sender load, and launch require a separate human-approved gate.",
|
|
1499
|
-
memoryKeywords: ["company signals", "evidence-fed copy", "why now", "copy blocker", "approval gate"]
|
|
1622
|
+
memoryKeywords: ["company signals", "evidence-fed copy", "why now", "copy blocker", "approval gate"],
|
|
1623
|
+
knowledgeSources: ["gtm/email-personalization", "gtm/signal-based-selling", "gtm/signal-combination-matrix", "gtm/advanced/buyer-journey-mapping"]
|
|
1500
1624
|
},
|
|
1501
1625
|
{
|
|
1502
1626
|
slug: "domain-first-recovery",
|
|
@@ -1521,7 +1645,8 @@ var CAMPAIGN_BUILDER_OPERATING_PLAYBOOKS = [
|
|
|
1521
1645
|
"Target count means final held rows, not raw sourced rows."
|
|
1522
1646
|
],
|
|
1523
1647
|
activationBoundary: "Domain recovery informs sourcing. Contact enrichment, paid qualification, and export still require approved gates.",
|
|
1524
|
-
memoryKeywords: ["domain-first", "yield modeling", "attrition", "accepted domains", "gap fill"]
|
|
1648
|
+
memoryKeywords: ["domain-first", "yield modeling", "attrition", "accepted domains", "gap fill"],
|
|
1649
|
+
knowledgeSources: ["gtm/lead-generation-strategies", "data-ops/enrichment-waterfall-strategy", "data-ops/credit-optimization-guide", "gtm/territory-account-planning"]
|
|
1525
1650
|
},
|
|
1526
1651
|
{
|
|
1527
1652
|
slug: "table-workflow-handoff",
|
|
@@ -1546,7 +1671,112 @@ var CAMPAIGN_BUILDER_OPERATING_PLAYBOOKS = [
|
|
|
1546
1671
|
"Provider route activation must dry-run before any external write."
|
|
1547
1672
|
],
|
|
1548
1673
|
activationBoundary: "MCP, webhook, managed integration, and destination routes remain dry-run until the reviewed route and campaign are approved.",
|
|
1549
|
-
memoryKeywords: ["table workflow", "request ready", "provider status", "export blocker", "BYO integration"]
|
|
1674
|
+
memoryKeywords: ["table workflow", "request ready", "provider status", "export blocker", "BYO integration"],
|
|
1675
|
+
knowledgeSources: ["gtm/multi-channel-orchestration", "data-ops/enrichment-waterfall-strategy", "recipes/clay-gtm-webhook-recipe", "systems/blueprints/multi-channel-orchestration"]
|
|
1676
|
+
},
|
|
1677
|
+
{
|
|
1678
|
+
slug: "icp-persona-segmentation",
|
|
1679
|
+
label: "ICP And Persona Segmentation",
|
|
1680
|
+
whenToUse: [
|
|
1681
|
+
"The brief has a broad market, multiple personas, or unclear buying committee.",
|
|
1682
|
+
"The campaign should rank account tiers, persona fit, vertical nuance, and exclusions before sourcing at scale."
|
|
1683
|
+
],
|
|
1684
|
+
sequence: [
|
|
1685
|
+
"Convert the brief into account tiers, persona roles, buying committee influence, and explicit exclusions.",
|
|
1686
|
+
"Choose vertical guidance only from the customer-safe GTM library and keep internal platform docs out of prompts.",
|
|
1687
|
+
"Score accounts before contacts, then score contacts against persona, seniority, function, geography, and intent fit.",
|
|
1688
|
+
"Return segment counts and review buckets before spend, copy, export, or launch."
|
|
1689
|
+
],
|
|
1690
|
+
requiredFields: {
|
|
1691
|
+
segment: ["segment_name", "tier", "persona_priority", "buying_committee_role", "fit_reason", "exclusion_reason"],
|
|
1692
|
+
scoring: ["account_fit_score", "persona_fit_score", "segment_confidence", "review_bucket"]
|
|
1693
|
+
},
|
|
1694
|
+
qualityGates: [
|
|
1695
|
+
"Do not treat adjacent personas or verticals as matches unless the brief allows them.",
|
|
1696
|
+
"Keep ICP, persona, and exclusion evidence visible in the proof packet.",
|
|
1697
|
+
"Low-confidence segments route to review before contact discovery or copy."
|
|
1698
|
+
],
|
|
1699
|
+
activationBoundary: "Segmentation is planning guidance. Paid sourcing, enrichment, export, and launch require the normal approval gates.",
|
|
1700
|
+
memoryKeywords: ["ICP design", "persona segmentation", "buying committee", "account tiers", "fit scoring", "vertical nuance"],
|
|
1701
|
+
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"]
|
|
1702
|
+
},
|
|
1703
|
+
{
|
|
1704
|
+
slug: "buying-signal-prioritization",
|
|
1705
|
+
label: "Buying Signal Prioritization",
|
|
1706
|
+
whenToUse: [
|
|
1707
|
+
"The campaign depends on timing, intent, trigger events, or account prioritization.",
|
|
1708
|
+
"The operator wants why-now proof instead of generic list generation."
|
|
1709
|
+
],
|
|
1710
|
+
sequence: [
|
|
1711
|
+
"Map the campaign goal to signal families, trigger freshness, and buyer-journey stage.",
|
|
1712
|
+
"Rank signals by relevance, recency, source quality, and persona-specific actionability.",
|
|
1713
|
+
"Attach evidence URLs or evidence summaries without exposing private memory rows.",
|
|
1714
|
+
"Use signal strength to decide source order, copy angle, and review priority."
|
|
1715
|
+
],
|
|
1716
|
+
requiredFields: {
|
|
1717
|
+
signal: ["signal_type", "signal_date", "signal_source", "why_now", "signal_confidence", "buyer_stage"],
|
|
1718
|
+
prioritization: ["priority_score", "priority_reason", "next_best_action", "review_reason"]
|
|
1719
|
+
},
|
|
1720
|
+
qualityGates: [
|
|
1721
|
+
"Do not use stale, unsupported, or weak signals as personalization proof.",
|
|
1722
|
+
"Signal fit cannot override hard ICP, geography, suppression, or verified-email gates.",
|
|
1723
|
+
"Rows with uncertain why-now evidence must stay review-only."
|
|
1724
|
+
],
|
|
1725
|
+
activationBoundary: "Signal ranking can prioritize review and copy. It does not approve outreach, sender loading, exports, or sends.",
|
|
1726
|
+
memoryKeywords: ["buying signals", "intent data", "funding trigger", "new executive", "tech adoption", "buyer journey", "why now"],
|
|
1727
|
+
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"]
|
|
1728
|
+
},
|
|
1729
|
+
{
|
|
1730
|
+
slug: "multi-channel-sequence-fit",
|
|
1731
|
+
label: "Multi-Channel Sequence Fit",
|
|
1732
|
+
whenToUse: [
|
|
1733
|
+
"The campaign needs email, LinkedIn, call, webhook, CRM, or sequencer coordination.",
|
|
1734
|
+
"Copy and delivery should adapt by persona, channel, deliverability risk, and proof strength."
|
|
1735
|
+
],
|
|
1736
|
+
sequence: [
|
|
1737
|
+
"Choose channel mix from persona, deal motion, evidence strength, deliverability constraints, and connected destination readiness.",
|
|
1738
|
+
"Draft sequence logic with email, LinkedIn, call, and task handoffs only where supported by the approved destination.",
|
|
1739
|
+
"Keep copy concise, proof-backed, channel-specific, and reviewable before delivery.",
|
|
1740
|
+
"Run deliverability and destination readiness checks before sender load or launch approval."
|
|
1741
|
+
],
|
|
1742
|
+
requiredFields: {
|
|
1743
|
+
channel: ["channel", "touch_number", "persona_context", "message_angle", "channel_blocker", "approval_status"],
|
|
1744
|
+
deliverability: ["verified_email", "domain_risk", "send_window", "unsubscribe_risk", "sender_ready"]
|
|
1745
|
+
},
|
|
1746
|
+
qualityGates: [
|
|
1747
|
+
"Email copy must be row-supported and under the configured campaign tone/length limits.",
|
|
1748
|
+
"LinkedIn, phone, CRM, webhook, and sequencer actions remain destination-locked until approved.",
|
|
1749
|
+
"Deliverability risk or missing sender readiness blocks launch even when rows are qualified."
|
|
1750
|
+
],
|
|
1751
|
+
activationBoundary: "Sequence strategy is draft-only. External writes, sender loading, launch, and sending need separate explicit approval.",
|
|
1752
|
+
memoryKeywords: ["outbound sequencing", "email personalization", "LinkedIn outreach", "cold calling", "multi-channel orchestration", "deliverability"],
|
|
1753
|
+
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"]
|
|
1754
|
+
},
|
|
1755
|
+
{
|
|
1756
|
+
slug: "revops-feedback-loop",
|
|
1757
|
+
label: "RevOps Feedback Loop",
|
|
1758
|
+
whenToUse: [
|
|
1759
|
+
"The campaign should improve from replies, meetings, delivery results, CRM outcomes, or operator QA.",
|
|
1760
|
+
"The operator needs post-build monitoring, governance, or continuous ops follow-up."
|
|
1761
|
+
],
|
|
1762
|
+
sequence: [
|
|
1763
|
+
"Define success metrics, guardrails, and feedback sources before launch.",
|
|
1764
|
+
"Collect aggregate outcomes, QA blockers, delivery health, and operator edits after each campaign phase.",
|
|
1765
|
+
"Separate workspace-private evidence from public-safe learnings and Brain defaults.",
|
|
1766
|
+
"Feed approved aggregate learnings back into future sourcing, qualification, copy, and suppression rules."
|
|
1767
|
+
],
|
|
1768
|
+
requiredFields: {
|
|
1769
|
+
feedback: ["source", "event_type", "metric", "sample_size", "confidence", "learning_candidate"],
|
|
1770
|
+
governance: ["approval_owner", "last_reviewed_at", "risk_flag", "next_review_action"]
|
|
1771
|
+
},
|
|
1772
|
+
qualityGates: [
|
|
1773
|
+
"Do not write memory or Brain learnings from raw replies, private labels, or provider payloads without approved redaction.",
|
|
1774
|
+
"Use holdouts or pre/post comparisons before claiming causal lift.",
|
|
1775
|
+
"Delivery, suppression, and opt-out signals must update future gates before scale-up."
|
|
1776
|
+
],
|
|
1777
|
+
activationBoundary: "Feedback review is read-only until memory writes, Brain writes, CRM updates, or campaign changes are explicitly approved.",
|
|
1778
|
+
memoryKeywords: ["RevOps", "feedback loop", "campaign learning", "reply outcomes", "sales marketing alignment", "data hygiene", "holdout"],
|
|
1779
|
+
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"]
|
|
1550
1780
|
}
|
|
1551
1781
|
];
|
|
1552
1782
|
var CAMPAIGN_BUILDER_STRATEGY_TEMPLATES = [
|
|
@@ -1633,7 +1863,15 @@ var CAMPAIGN_BUILDER_STRATEGY_TEMPLATES = [
|
|
|
1633
1863
|
agencyContext: {
|
|
1634
1864
|
partnerEcosystem: ["signaliz", "instantly", "nango"]
|
|
1635
1865
|
},
|
|
1636
|
-
operatingPlaybookSlugs: [
|
|
1866
|
+
operatingPlaybookSlugs: [
|
|
1867
|
+
"net-new-suppressed-list",
|
|
1868
|
+
"proof-first-vertical-gate",
|
|
1869
|
+
"signal-led-copy-approval",
|
|
1870
|
+
"icp-persona-segmentation",
|
|
1871
|
+
"buying-signal-prioritization",
|
|
1872
|
+
"multi-channel-sequence-fit",
|
|
1873
|
+
"revops-feedback-loop"
|
|
1874
|
+
]
|
|
1637
1875
|
},
|
|
1638
1876
|
{
|
|
1639
1877
|
slug: "non-medical-home-care",
|
|
@@ -1706,7 +1944,15 @@ var CAMPAIGN_BUILDER_STRATEGY_TEMPLATES = [
|
|
|
1706
1944
|
agencyContext: {
|
|
1707
1945
|
partnerEcosystem: ["clay", "octave", "signaliz", "instantly", "nango"]
|
|
1708
1946
|
},
|
|
1709
|
-
operatingPlaybookSlugs: [
|
|
1947
|
+
operatingPlaybookSlugs: [
|
|
1948
|
+
"proof-first-vertical-gate",
|
|
1949
|
+
"domain-first-recovery",
|
|
1950
|
+
"table-workflow-handoff",
|
|
1951
|
+
"icp-persona-segmentation",
|
|
1952
|
+
"buying-signal-prioritization",
|
|
1953
|
+
"multi-channel-sequence-fit",
|
|
1954
|
+
"revops-feedback-loop"
|
|
1955
|
+
]
|
|
1710
1956
|
},
|
|
1711
1957
|
{
|
|
1712
1958
|
slug: "agency-founder-led",
|
|
@@ -1767,7 +2013,15 @@ var CAMPAIGN_BUILDER_STRATEGY_TEMPLATES = [
|
|
|
1767
2013
|
agencyContext: {
|
|
1768
2014
|
partnerEcosystem: ["signaliz", "octave", "instantly", "nango"]
|
|
1769
2015
|
},
|
|
1770
|
-
operatingPlaybookSlugs: [
|
|
2016
|
+
operatingPlaybookSlugs: [
|
|
2017
|
+
"net-new-suppressed-list",
|
|
2018
|
+
"signal-led-copy-approval",
|
|
2019
|
+
"table-workflow-handoff",
|
|
2020
|
+
"icp-persona-segmentation",
|
|
2021
|
+
"buying-signal-prioritization",
|
|
2022
|
+
"multi-channel-sequence-fit",
|
|
2023
|
+
"revops-feedback-loop"
|
|
2024
|
+
]
|
|
1771
2025
|
},
|
|
1772
2026
|
{
|
|
1773
2027
|
slug: "cloud-infrastructure-displacement",
|
|
@@ -1854,7 +2108,15 @@ var CAMPAIGN_BUILDER_STRATEGY_TEMPLATES = [
|
|
|
1854
2108
|
agencyContext: {
|
|
1855
2109
|
partnerEcosystem: ["signaliz", "octave", "instantly", "nango"]
|
|
1856
2110
|
},
|
|
1857
|
-
operatingPlaybookSlugs: [
|
|
2111
|
+
operatingPlaybookSlugs: [
|
|
2112
|
+
"proof-first-vertical-gate",
|
|
2113
|
+
"domain-first-recovery",
|
|
2114
|
+
"signal-led-copy-approval",
|
|
2115
|
+
"icp-persona-segmentation",
|
|
2116
|
+
"buying-signal-prioritization",
|
|
2117
|
+
"multi-channel-sequence-fit",
|
|
2118
|
+
"revops-feedback-loop"
|
|
2119
|
+
]
|
|
1858
2120
|
}
|
|
1859
2121
|
];
|
|
1860
2122
|
var CampaignBuilderAgent = class {
|
|
@@ -1885,6 +2147,9 @@ var CampaignBuilderAgent = class {
|
|
|
1885
2147
|
const plan = await this.createPlan(request, options);
|
|
1886
2148
|
return createCampaignBuilderReadiness(plan);
|
|
1887
2149
|
}
|
|
2150
|
+
activeWorkContext(input) {
|
|
2151
|
+
return createCampaignBuilderActiveWorkContext(input);
|
|
2152
|
+
}
|
|
1888
2153
|
async proof(request, options = {}) {
|
|
1889
2154
|
const plan = await this.createPlan(request, options);
|
|
1890
2155
|
const result = await this.dryRunPlan(plan, {
|
|
@@ -1926,6 +2191,7 @@ var CampaignBuilderAgent = class {
|
|
|
1926
2191
|
},
|
|
1927
2192
|
brain_defaults: plan.buildRequest.brainDefaults,
|
|
1928
2193
|
brain_preflight: plan.buildRequest.brainPreflight,
|
|
2194
|
+
learning_holdout: plan.buildRequest.learningHoldout,
|
|
1929
2195
|
campaign_strategy_context: plan.buildRequest.campaignStrategyContext,
|
|
1930
2196
|
delivery_risk_preflight: plan.buildRequest.deliveryRisk,
|
|
1931
2197
|
delivery_risk: plan.buildRequest.deliveryRisk
|
|
@@ -1939,7 +2205,8 @@ var CampaignBuilderAgent = class {
|
|
|
1939
2205
|
estimated_credits: plan.estimatedCredits
|
|
1940
2206
|
},
|
|
1941
2207
|
brain_delivery_risk_preflight: plan.buildRequest.deliveryRisk,
|
|
1942
|
-
delivery_risk: plan.buildRequest.deliveryRisk
|
|
2208
|
+
delivery_risk: plan.buildRequest.deliveryRisk,
|
|
2209
|
+
learning_holdout: plan.buildRequest.learningHoldout
|
|
1943
2210
|
},
|
|
1944
2211
|
approval_required: plan.approvals.some((approval) => approval.blocking),
|
|
1945
2212
|
actor_type: "agent",
|
|
@@ -2267,9 +2534,10 @@ function createCampaignBuilderAgentPlan(request, context = {}) {
|
|
|
2267
2534
|
const estimatedCredits = estimateCredits(resolvedRequest, defaults, targetCount);
|
|
2268
2535
|
const buildRequest = createBuildRequest(resolvedRequest, defaults, targetCount, campaignName, context.scopeBuildArgs, routes, memory, context.scopeBrainPreflight);
|
|
2269
2536
|
const brainPreflight = asRecord(buildRequest.brainPreflight);
|
|
2537
|
+
const evidence = buildRequest.evidence ?? null;
|
|
2270
2538
|
const approvals = deriveApprovals(resolvedRequest, routes, memory, estimatedCredits, defaults.delivery?.approvalRequired !== false);
|
|
2271
2539
|
return {
|
|
2272
|
-
planId: `cbp_${hashString(JSON.stringify({ goal: resolvedRequest.goal, campaignName, targetCount, routes }))}`,
|
|
2540
|
+
planId: `cbp_${hashString(JSON.stringify({ goal: resolvedRequest.goal, campaignName, targetCount, routes, evidence }))}`,
|
|
2273
2541
|
campaignName,
|
|
2274
2542
|
goal: resolvedRequest.goal,
|
|
2275
2543
|
targetCount,
|
|
@@ -2284,6 +2552,7 @@ function createCampaignBuilderAgentPlan(request, context = {}) {
|
|
|
2284
2552
|
approvals,
|
|
2285
2553
|
buildRequest,
|
|
2286
2554
|
brainPreflight,
|
|
2555
|
+
evidence,
|
|
2287
2556
|
operatingPlaybooks,
|
|
2288
2557
|
mcpFlow: createMcpFlow(resolvedRequest, buildRequest, routes, memory, approvals),
|
|
2289
2558
|
estimatedCredits,
|
|
@@ -2375,6 +2644,90 @@ function createCampaignBuilderReadiness(plan) {
|
|
|
2375
2644
|
nextActions: campaignReadinessNextActions(plan, ready, customRoutes.length)
|
|
2376
2645
|
};
|
|
2377
2646
|
}
|
|
2647
|
+
function createCampaignBuilderActiveWorkContext(input) {
|
|
2648
|
+
const plan = input.readiness?.plan ?? input.plan;
|
|
2649
|
+
const remembered = input.remembered ?? {};
|
|
2650
|
+
const lastResult = asRecord(input.lastResult);
|
|
2651
|
+
const readinessBlockers = input.readiness?.summary.blockers ?? [];
|
|
2652
|
+
const explicitBlockers = input.blockers ?? [];
|
|
2653
|
+
const blockers = uniqueStrings([...explicitBlockers, ...readinessBlockers]);
|
|
2654
|
+
const warnings = uniqueStrings([
|
|
2655
|
+
...input.warnings ?? [],
|
|
2656
|
+
...input.readiness?.summary.warnings ?? [],
|
|
2657
|
+
...plan?.warnings ?? []
|
|
2658
|
+
]);
|
|
2659
|
+
const missingApprovals = plan ? (input.approval ? getMissingCampaignBuilderApprovals(plan, input.approval) : plan.approvals.filter((approval) => approval.blocking)).map((approval) => approval.type) : [];
|
|
2660
|
+
const refs = normalizeCampaignBuilderActiveWorkRefs({
|
|
2661
|
+
plan,
|
|
2662
|
+
remembered,
|
|
2663
|
+
refs: input.refs,
|
|
2664
|
+
lastResult
|
|
2665
|
+
});
|
|
2666
|
+
const state = inferCampaignBuilderActiveWorkState({
|
|
2667
|
+
plan,
|
|
2668
|
+
readiness: input.readiness,
|
|
2669
|
+
remembered,
|
|
2670
|
+
lastResult,
|
|
2671
|
+
blockers,
|
|
2672
|
+
missingApprovals
|
|
2673
|
+
});
|
|
2674
|
+
const nextSafeAction = campaignBuilderActiveWorkNextAction(state, blockers, missingApprovals, refs);
|
|
2675
|
+
const approvalPacket = createCampaignBuilderApprovalPacket(plan, input.approval, missingApprovals);
|
|
2676
|
+
const nextSafeMcpAction = campaignBuilderActiveWorkNextMcpAction({
|
|
2677
|
+
state,
|
|
2678
|
+
plan,
|
|
2679
|
+
refs,
|
|
2680
|
+
approvalPacket
|
|
2681
|
+
});
|
|
2682
|
+
const summary = {
|
|
2683
|
+
plan_id: plan?.planId ?? remembered.planId ?? null,
|
|
2684
|
+
campaign_name: plan?.campaignName ?? null,
|
|
2685
|
+
target_count: plan?.targetCount ?? null,
|
|
2686
|
+
gtm_campaign_id: plan?.buildRequest.gtmCampaignId ?? remembered.gtmCampaignId ?? null,
|
|
2687
|
+
campaign_build_id: stringValue(lastResult.campaign_build_id ?? lastResult.campaignBuildId) ?? remembered.campaignBuildId ?? null,
|
|
2688
|
+
provider_campaign_id: remembered.providerCampaignId ?? null
|
|
2689
|
+
};
|
|
2690
|
+
const approvalBoundary = campaignBuilderActiveWorkApprovalBoundary(missingApprovals, state);
|
|
2691
|
+
const conversationStarters = campaignBuilderActiveWorkConversationStarters({
|
|
2692
|
+
state,
|
|
2693
|
+
blockers,
|
|
2694
|
+
missingApprovals,
|
|
2695
|
+
refs,
|
|
2696
|
+
nextSafeAction
|
|
2697
|
+
});
|
|
2698
|
+
return {
|
|
2699
|
+
packet_version: "campaign-builder-active-work-context.v1",
|
|
2700
|
+
read_only: true,
|
|
2701
|
+
no_spend: true,
|
|
2702
|
+
no_provider_writes: true,
|
|
2703
|
+
private_safe: true,
|
|
2704
|
+
state,
|
|
2705
|
+
summary,
|
|
2706
|
+
refs,
|
|
2707
|
+
blockers,
|
|
2708
|
+
warnings,
|
|
2709
|
+
missing_approval_types: missingApprovals,
|
|
2710
|
+
approval_packet: approvalPacket,
|
|
2711
|
+
approval_boundary: approvalBoundary,
|
|
2712
|
+
next_safe_action: nextSafeAction,
|
|
2713
|
+
next_safe_mcp_action: nextSafeMcpAction,
|
|
2714
|
+
conversation_starters: conversationStarters,
|
|
2715
|
+
openai_agent_handoff: createCampaignBuilderOpenAiAgentHandoff({
|
|
2716
|
+
plan,
|
|
2717
|
+
state,
|
|
2718
|
+
summary,
|
|
2719
|
+
refs,
|
|
2720
|
+
blockers,
|
|
2721
|
+
warnings,
|
|
2722
|
+
missingApprovals,
|
|
2723
|
+
approvalPacket,
|
|
2724
|
+
approvalBoundary,
|
|
2725
|
+
nextSafeAction,
|
|
2726
|
+
nextSafeMcpAction,
|
|
2727
|
+
conversationStarters
|
|
2728
|
+
})
|
|
2729
|
+
};
|
|
2730
|
+
}
|
|
2378
2731
|
function createCampaignBuilderProofReceipt(plan, result) {
|
|
2379
2732
|
const strategyMemory = asRecord(plan.strategyMemoryStatus);
|
|
2380
2733
|
const dryRunResult = asRecord(result);
|
|
@@ -2433,6 +2786,7 @@ function createCampaignBuilderProofReceipt(plan, result) {
|
|
|
2433
2786
|
estimated_credits: plan.estimatedCredits,
|
|
2434
2787
|
operating_playbooks: plan.operatingPlaybooks.map((playbook) => playbook.slug)
|
|
2435
2788
|
},
|
|
2789
|
+
evidence: plan.evidence,
|
|
2436
2790
|
gates,
|
|
2437
2791
|
strategy_memory_status: summarizeCampaignBuilderProofStrategyMemory(strategyMemory),
|
|
2438
2792
|
dry_run_result: summarizeCampaignBuilderProofDryRun(dryRunResult),
|
|
@@ -2488,6 +2842,56 @@ function getCampaignBuilderOperatingPlaybooksForRequest(request) {
|
|
|
2488
2842
|
]);
|
|
2489
2843
|
return slugs.map(getCampaignBuilderOperatingPlaybook).filter((playbook) => Boolean(playbook));
|
|
2490
2844
|
}
|
|
2845
|
+
function normalizeCampaignBuilderEvidence(evidence) {
|
|
2846
|
+
if (!evidence) return null;
|
|
2847
|
+
const attachmentSummary = (evidence.attachments ?? []).filter((attachment) => stringValue(attachment.name)).slice(0, 5).map((attachment) => ({
|
|
2848
|
+
name: stringValue(attachment.name) ?? "attachment",
|
|
2849
|
+
kind: stringValue(attachment.kind) ?? null,
|
|
2850
|
+
media_type: stringValue(attachment.mediaType) ?? null,
|
|
2851
|
+
redacted: attachment.redacted !== false,
|
|
2852
|
+
columns: uniqueStrings(attachment.columns ?? []).slice(0, 25),
|
|
2853
|
+
row_count: numberOrUndefined2(attachment.rowCount) ?? null,
|
|
2854
|
+
content_summary: stringValue(attachment.contentSummary)?.slice(0, 500) ?? null,
|
|
2855
|
+
evidence_fields: uniqueStrings(attachment.evidenceFields ?? []).slice(0, 25)
|
|
2856
|
+
}));
|
|
2857
|
+
const urlSummary = (evidence.urls ?? []).filter((url) => stringValue(url.url)).slice(0, 8).map((url) => {
|
|
2858
|
+
const rawUrl = stringValue(url.url) ?? "";
|
|
2859
|
+
return {
|
|
2860
|
+
url: rawUrl,
|
|
2861
|
+
host: stringValue(url.host) ?? hostFromUrl(rawUrl) ?? null,
|
|
2862
|
+
type: stringValue(url.type) ?? null,
|
|
2863
|
+
label: stringValue(url.label) ?? null,
|
|
2864
|
+
summary: stringValue(url.summary)?.slice(0, 500) ?? null,
|
|
2865
|
+
redacted: url.redacted === true
|
|
2866
|
+
};
|
|
2867
|
+
});
|
|
2868
|
+
const operatorNotes = uniqueStrings(evidence.notes ?? []).map((note) => note.slice(0, 240)).slice(0, 5);
|
|
2869
|
+
if (!attachmentSummary.length && !urlSummary.length && !operatorNotes.length) return null;
|
|
2870
|
+
return {
|
|
2871
|
+
packet_version: "campaign-builder-evidence.v1",
|
|
2872
|
+
private_safe: true,
|
|
2873
|
+
attachment_summary: attachmentSummary,
|
|
2874
|
+
url_summary: urlSummary,
|
|
2875
|
+
operator_notes: operatorNotes,
|
|
2876
|
+
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.",
|
|
2877
|
+
raw_private_fields_withheld: [
|
|
2878
|
+
"raw_private_attachment_text",
|
|
2879
|
+
"raw_attachment_rows",
|
|
2880
|
+
"raw_leads",
|
|
2881
|
+
"email_addresses",
|
|
2882
|
+
"provider_auth_payloads",
|
|
2883
|
+
"copy_bodies",
|
|
2884
|
+
"secrets"
|
|
2885
|
+
]
|
|
2886
|
+
};
|
|
2887
|
+
}
|
|
2888
|
+
function hostFromUrl(value) {
|
|
2889
|
+
try {
|
|
2890
|
+
return new URL(value).hostname || void 0;
|
|
2891
|
+
} catch {
|
|
2892
|
+
return void 0;
|
|
2893
|
+
}
|
|
2894
|
+
}
|
|
2491
2895
|
function applyCampaignBuilderStrategyTemplate(request) {
|
|
2492
2896
|
const template = getCampaignBuilderStrategyTemplate(request.strategyTemplate);
|
|
2493
2897
|
if (!template) return request;
|
|
@@ -3179,7 +3583,7 @@ function normalizeMemory(request) {
|
|
|
3179
3583
|
};
|
|
3180
3584
|
}
|
|
3181
3585
|
function defaultAgencyMemoryQueries(request, configured) {
|
|
3182
|
-
const operatingPlaybookTerms = getCampaignBuilderOperatingPlaybooksForRequest(request).flatMap((playbook) => [playbook.label, ...playbook.memoryKeywords]).join(" ");
|
|
3586
|
+
const operatingPlaybookTerms = getCampaignBuilderOperatingPlaybooksForRequest(request).flatMap((playbook) => [playbook.label, ...playbook.memoryKeywords, ...playbook.knowledgeSources]).join(" ");
|
|
3183
3587
|
const queries = [{
|
|
3184
3588
|
query: request.goal,
|
|
3185
3589
|
scopes: ["workspace", configured.useNetworkPatterns ? "network_patterns" : "operator_notes"],
|
|
@@ -3345,6 +3749,21 @@ function routesFromCustomerTools(tools) {
|
|
|
3345
3749
|
}))
|
|
3346
3750
|
);
|
|
3347
3751
|
}
|
|
3752
|
+
function normalizeCampaignBuilderLearningHoldout(input, gtmCampaignId, campaignName) {
|
|
3753
|
+
const source = asRecord(input);
|
|
3754
|
+
if (source.enabled === false) return { enabled: false };
|
|
3755
|
+
const controlPercentage = numberOrUndefined2(source.control_percentage ?? source.controlPercentage);
|
|
3756
|
+
const minControlSize = numberOrUndefined2(source.min_control_size ?? source.minControlSize);
|
|
3757
|
+
const experimentKey = stringValue(source.experiment_key ?? source.experimentKey) ?? (gtmCampaignId ? `gtm_campaign:${gtmCampaignId}:learning_holdout` : `campaign_builder_agent:${hashString(campaignName)}:learning_holdout`);
|
|
3758
|
+
return {
|
|
3759
|
+
enabled: true,
|
|
3760
|
+
controlPercentage: controlPercentage ?? 0.2,
|
|
3761
|
+
minControlSize: minControlSize ?? 50,
|
|
3762
|
+
experimentKey,
|
|
3763
|
+
sourceCampaignId: stringValue(source.source_campaign_id ?? source.sourceCampaignId) ?? gtmCampaignId,
|
|
3764
|
+
primaryMetric: stringValue(source.primary_metric ?? source.primaryMetric) ?? "positive_reply_rate"
|
|
3765
|
+
};
|
|
3766
|
+
}
|
|
3348
3767
|
function createBuildRequest(request, defaults, targetCount, campaignName, scopeBuildArgs, routes = [], memory, scopeBrainPreflight) {
|
|
3349
3768
|
const buildRequest = {
|
|
3350
3769
|
name: campaignName,
|
|
@@ -3375,8 +3794,15 @@ function createBuildRequest(request, defaults, targetCount, campaignName, scopeB
|
|
|
3375
3794
|
fillPolicy: "aggressive"
|
|
3376
3795
|
}
|
|
3377
3796
|
};
|
|
3797
|
+
const evidence = normalizeCampaignBuilderEvidence(request.evidence);
|
|
3798
|
+
if (evidence) buildRequest.evidence = evidence;
|
|
3378
3799
|
const scoped = asRecord(scopeBuildArgs);
|
|
3379
3800
|
buildRequest.gtmCampaignId = request.gtmCampaignId ?? stringValue(scoped.gtm_campaign_id ?? scoped.gtmCampaignId);
|
|
3801
|
+
buildRequest.learningHoldout = normalizeCampaignBuilderLearningHoldout(
|
|
3802
|
+
request.learningHoldout ?? scoped.learning_holdout ?? scoped.learningHoldout,
|
|
3803
|
+
buildRequest.gtmCampaignId,
|
|
3804
|
+
campaignName
|
|
3805
|
+
);
|
|
3380
3806
|
if (typeof scoped.name === "string") buildRequest.name = scoped.name;
|
|
3381
3807
|
if (typeof scoped.prompt === "string") buildRequest.prompt = scoped.prompt;
|
|
3382
3808
|
if (typeof scoped.target_count === "number") buildRequest.targetCount = scoped.target_count;
|
|
@@ -3401,6 +3827,7 @@ function createBrainPreflight(request, buildRequest, routes, memory) {
|
|
|
3401
3827
|
memory.enabled ? "feedback" : void 0
|
|
3402
3828
|
]);
|
|
3403
3829
|
const providerChain = uniqueStrings(["signaliz", ...request.preferredProviders ?? [], ...routes.map((route) => route.provider)]);
|
|
3830
|
+
const evidence = buildRequest.evidence ?? normalizeCampaignBuilderEvidence(request.evidence);
|
|
3404
3831
|
const targetIcp = compact({
|
|
3405
3832
|
personas: buildRequest.icp?.personas,
|
|
3406
3833
|
industries: buildRequest.icp?.industries,
|
|
@@ -3413,6 +3840,7 @@ function createBrainPreflight(request, buildRequest, routes, memory) {
|
|
|
3413
3840
|
const learningArgs = compact({
|
|
3414
3841
|
campaign_brief: request.goal,
|
|
3415
3842
|
target_icp: targetIcp,
|
|
3843
|
+
evidence_context: evidence,
|
|
3416
3844
|
layers,
|
|
3417
3845
|
provider_chain: providerChain,
|
|
3418
3846
|
lead_source: providerChain[0] ?? "signaliz",
|
|
@@ -3424,6 +3852,7 @@ function createBrainPreflight(request, buildRequest, routes, memory) {
|
|
|
3424
3852
|
const defaultsArgs = compact({
|
|
3425
3853
|
campaign_brief: request.goal,
|
|
3426
3854
|
target_icp: targetIcp,
|
|
3855
|
+
evidence_context: evidence,
|
|
3427
3856
|
layers,
|
|
3428
3857
|
include_global: memory.useNetworkPatterns,
|
|
3429
3858
|
include_memory: memory.enabled,
|
|
@@ -3434,6 +3863,7 @@ function createBrainPreflight(request, buildRequest, routes, memory) {
|
|
|
3434
3863
|
provider_chain: providerChain,
|
|
3435
3864
|
lead_source: providerChain[0] ?? "signaliz",
|
|
3436
3865
|
target_icp: targetIcp,
|
|
3866
|
+
evidence_context: evidence,
|
|
3437
3867
|
include_global: memory.useNetworkPatterns,
|
|
3438
3868
|
limit: 25
|
|
3439
3869
|
});
|
|
@@ -3446,11 +3876,14 @@ function createBrainPreflight(request, buildRequest, routes, memory) {
|
|
|
3446
3876
|
label: playbook.label,
|
|
3447
3877
|
quality_gates: playbook.qualityGates,
|
|
3448
3878
|
required_fields: playbook.requiredFields,
|
|
3449
|
-
activation_boundary: playbook.activationBoundary
|
|
3879
|
+
activation_boundary: playbook.activationBoundary,
|
|
3880
|
+
knowledge_sources: playbook.knowledgeSources
|
|
3450
3881
|
})),
|
|
3451
3882
|
target_icp: targetIcp,
|
|
3883
|
+
evidence_context: evidence,
|
|
3452
3884
|
provider_chain: providerChain,
|
|
3453
3885
|
lead_source: providerChain[0] ?? "signaliz",
|
|
3886
|
+
learning_holdout: buildRequest.learningHoldout,
|
|
3454
3887
|
tool_sequence: [
|
|
3455
3888
|
{ tool: "gtm_brain_learning_cycle_plan", purpose: "Plan the Brain learning loop for this campaign.", arguments: learningArgs },
|
|
3456
3889
|
{ tool: "gtm_brain_seed_defaults", purpose: "Seed campaign defaults from workspace memory and safe aggregate patterns.", arguments: defaultsArgs },
|
|
@@ -3720,7 +4153,7 @@ function createMcpFlow(request, buildRequest, routes, memory, approvals) {
|
|
|
3720
4153
|
phase: "plan",
|
|
3721
4154
|
tool: "nango_mcp_tools_list",
|
|
3722
4155
|
arguments: {
|
|
3723
|
-
format: "
|
|
4156
|
+
format: "openai"
|
|
3724
4157
|
},
|
|
3725
4158
|
readOnly: true,
|
|
3726
4159
|
approvalRequired: false
|
|
@@ -4029,6 +4462,7 @@ function buildGtmCampaignBuildPlanArgs(request, buildRequest, routes, memory) {
|
|
|
4029
4462
|
layers: layers.length > 0 ? layers : void 0,
|
|
4030
4463
|
preferred_providers: preferredProviders.length > 0 ? preferredProviders : void 0,
|
|
4031
4464
|
strategy_model: strategyModel,
|
|
4465
|
+
evidence_context: buildRequest.evidence ?? normalizeCampaignBuilderEvidence(request.evidence),
|
|
4032
4466
|
include_strategy_patterns: campaignBuilderStrategyPatternsEnabled(agencyContext),
|
|
4033
4467
|
include_workflow_patterns: campaignBuilderWorkflowPatternsEnabled(agencyContext),
|
|
4034
4468
|
include_nango_catalog: agencyContext.includeNangoCatalog !== false,
|
|
@@ -4037,7 +4471,8 @@ function buildGtmCampaignBuildPlanArgs(request, buildRequest, routes, memory) {
|
|
|
4037
4471
|
slug: playbook.slug,
|
|
4038
4472
|
label: playbook.label,
|
|
4039
4473
|
quality_gates: playbook.qualityGates,
|
|
4040
|
-
activation_boundary: playbook.activationBoundary
|
|
4474
|
+
activation_boundary: playbook.activationBoundary,
|
|
4475
|
+
knowledge_sources: playbook.knowledgeSources
|
|
4041
4476
|
})),
|
|
4042
4477
|
include_memory: memory.enabled,
|
|
4043
4478
|
include_brain: true,
|
|
@@ -4118,8 +4553,19 @@ function buildCampaignArgs(request) {
|
|
|
4118
4553
|
if (request.dedupKeys) args.dedup_keys = request.dedupKeys;
|
|
4119
4554
|
if (request.brainPreflight) args.brain_preflight = request.brainPreflight;
|
|
4120
4555
|
if (request.brainDefaults) args.brain_defaults = request.brainDefaults;
|
|
4556
|
+
if (request.learningHoldout) {
|
|
4557
|
+
args.learning_holdout = compact({
|
|
4558
|
+
enabled: request.learningHoldout.enabled,
|
|
4559
|
+
control_percentage: request.learningHoldout.controlPercentage,
|
|
4560
|
+
min_control_size: request.learningHoldout.minControlSize,
|
|
4561
|
+
experiment_key: request.learningHoldout.experimentKey,
|
|
4562
|
+
source_campaign_id: request.learningHoldout.sourceCampaignId,
|
|
4563
|
+
primary_metric: request.learningHoldout.primaryMetric
|
|
4564
|
+
});
|
|
4565
|
+
}
|
|
4121
4566
|
if (request.campaignStrategyContext) args.campaign_strategy_context = request.campaignStrategyContext;
|
|
4122
4567
|
if (request.deliveryRisk) args.delivery_risk = request.deliveryRisk;
|
|
4568
|
+
if (request.evidence) args.evidence_context = request.evidence;
|
|
4123
4569
|
if (request.icp) {
|
|
4124
4570
|
args.icp = compact({
|
|
4125
4571
|
personas: request.icp.personas,
|
|
@@ -4169,7 +4615,8 @@ function buildCampaignArgs(request) {
|
|
|
4169
4615
|
max_body_words: request.copy.maxBodyWords,
|
|
4170
4616
|
sender_context: request.copy.senderContext,
|
|
4171
4617
|
offer_context: request.copy.offerContext,
|
|
4172
|
-
model: request.copy.model
|
|
4618
|
+
model: request.copy.model,
|
|
4619
|
+
evidence_mode: request.copy.evidenceMode
|
|
4173
4620
|
});
|
|
4174
4621
|
}
|
|
4175
4622
|
if (request.delivery) {
|
|
@@ -4214,6 +4661,7 @@ function buildExecutionPrepareArgs(request, dryRun, confirmSpend) {
|
|
|
4214
4661
|
delivery_risk: buildArgs2.delivery_risk,
|
|
4215
4662
|
dedup_keys: buildArgs2.dedup_keys,
|
|
4216
4663
|
policy: buildArgs2.policy,
|
|
4664
|
+
learning_holdout: buildArgs2.learning_holdout,
|
|
4217
4665
|
signals: buildArgs2.signals,
|
|
4218
4666
|
qualification: buildArgs2.qualification,
|
|
4219
4667
|
copy: buildArgs2.copy,
|
|
@@ -4248,10 +4696,145 @@ function mapBuildResult(data, dryRun) {
|
|
|
4248
4696
|
targetLimitReason: data.target_limit_reason,
|
|
4249
4697
|
maxSupportedTargetCount: data.max_supported_target_count,
|
|
4250
4698
|
brainContext: data.brain_context ?? {},
|
|
4699
|
+
learningHoldout: data.learning_holdout ?? {},
|
|
4251
4700
|
providerRoute: mapProviderRoute2(data)
|
|
4252
4701
|
};
|
|
4253
4702
|
}
|
|
4703
|
+
var CAMPAIGN_BUILDER_TERMINAL_STATUSES = /* @__PURE__ */ new Set(["completed", "failed", "canceled", "cancelled"]);
|
|
4704
|
+
var CAMPAIGN_BUILDER_BLOCKED_TERMINAL_STATUSES = /* @__PURE__ */ new Set(["failed", "canceled", "cancelled"]);
|
|
4705
|
+
function mapAgentCampaignPhaseHealth(value) {
|
|
4706
|
+
if (!Array.isArray(value)) return [];
|
|
4707
|
+
return value.map((phase) => {
|
|
4708
|
+
const record = asRecord(phase);
|
|
4709
|
+
return {
|
|
4710
|
+
phase: stringValue(record.phase) ?? "unknown",
|
|
4711
|
+
status: stringValue(record.status) ?? "unknown",
|
|
4712
|
+
recordsProcessed: numberOrNull2(record.records_processed ?? record.recordsProcessed),
|
|
4713
|
+
recordsSucceeded: numberOrNull2(record.records_succeeded ?? record.recordsSucceeded),
|
|
4714
|
+
recordsFailed: numberOrNull2(record.records_failed ?? record.recordsFailed),
|
|
4715
|
+
heartbeatAgeSeconds: numberOrNull2(record.heartbeat_age_seconds ?? record.heartbeatAgeSeconds ?? record.phase_age_seconds)
|
|
4716
|
+
};
|
|
4717
|
+
});
|
|
4718
|
+
}
|
|
4719
|
+
function deriveCampaignBuildTerminalState(input) {
|
|
4720
|
+
const status = input.status.toLowerCase();
|
|
4721
|
+
const heartbeatAgeSeconds = input.phaseAgeSeconds;
|
|
4722
|
+
const stale = input.staleRunningPhase === true;
|
|
4723
|
+
const safeWatchAction = input.triggerRunId ? `signaliz ops run-status ${input.triggerRunId} --watch` : "signaliz campaign-agent status <campaign_build_id>";
|
|
4724
|
+
if (CAMPAIGN_BUILDER_BLOCKED_TERMINAL_STATUSES.has(status)) {
|
|
4725
|
+
return {
|
|
4726
|
+
kind: "blocked",
|
|
4727
|
+
label: "Blocked terminal state",
|
|
4728
|
+
reviewable: true,
|
|
4729
|
+
terminal: true,
|
|
4730
|
+
stale: false,
|
|
4731
|
+
phase: input.phase,
|
|
4732
|
+
phaseStatus: input.phaseStatus,
|
|
4733
|
+
heartbeatAgeSeconds,
|
|
4734
|
+
nextPollAfterSeconds: input.nextPollAfterSeconds,
|
|
4735
|
+
terminalReason: input.terminalReason,
|
|
4736
|
+
staleReason: null,
|
|
4737
|
+
safeNextAction: input.nextAction || "Review errors and rerun only after the blocker is resolved."
|
|
4738
|
+
};
|
|
4739
|
+
}
|
|
4740
|
+
if (status === "pending_approval") {
|
|
4741
|
+
return {
|
|
4742
|
+
kind: "pending_approval",
|
|
4743
|
+
label: "Pending delivery approval",
|
|
4744
|
+
reviewable: true,
|
|
4745
|
+
terminal: false,
|
|
4746
|
+
stale: false,
|
|
4747
|
+
phase: input.phase,
|
|
4748
|
+
phaseStatus: input.phaseStatus,
|
|
4749
|
+
heartbeatAgeSeconds,
|
|
4750
|
+
nextPollAfterSeconds: input.nextPollAfterSeconds,
|
|
4751
|
+
terminalReason: input.terminalReason,
|
|
4752
|
+
staleReason: null,
|
|
4753
|
+
safeNextAction: input.approvalAction || input.nextAction || "Review rows and approve delivery only after the approval packet passes."
|
|
4754
|
+
};
|
|
4755
|
+
}
|
|
4756
|
+
if (CAMPAIGN_BUILDER_TERMINAL_STATUSES.has(status)) {
|
|
4757
|
+
return {
|
|
4758
|
+
kind: "terminal",
|
|
4759
|
+
label: "Terminal and reviewable",
|
|
4760
|
+
reviewable: true,
|
|
4761
|
+
terminal: true,
|
|
4762
|
+
stale: false,
|
|
4763
|
+
phase: input.phase,
|
|
4764
|
+
phaseStatus: input.phaseStatus,
|
|
4765
|
+
heartbeatAgeSeconds,
|
|
4766
|
+
nextPollAfterSeconds: input.nextPollAfterSeconds,
|
|
4767
|
+
terminalReason: input.terminalReason,
|
|
4768
|
+
staleReason: null,
|
|
4769
|
+
safeNextAction: input.nextAction || "Review rows, artifacts, scorecard, and approval locks before delivery."
|
|
4770
|
+
};
|
|
4771
|
+
}
|
|
4772
|
+
if (status === "running" || status === "queued" || status === "processing") {
|
|
4773
|
+
if (stale) {
|
|
4774
|
+
return {
|
|
4775
|
+
kind: "running_stale",
|
|
4776
|
+
label: "Running but stale",
|
|
4777
|
+
reviewable: false,
|
|
4778
|
+
terminal: false,
|
|
4779
|
+
stale: true,
|
|
4780
|
+
phase: input.phase,
|
|
4781
|
+
phaseStatus: input.phaseStatus,
|
|
4782
|
+
heartbeatAgeSeconds,
|
|
4783
|
+
nextPollAfterSeconds: input.nextPollAfterSeconds,
|
|
4784
|
+
terminalReason: null,
|
|
4785
|
+
staleReason: input.staleReason || "The active phase heartbeat is stale.",
|
|
4786
|
+
safeNextAction: input.nextAction || safeWatchAction
|
|
4787
|
+
};
|
|
4788
|
+
}
|
|
4789
|
+
return {
|
|
4790
|
+
kind: "running_healthy",
|
|
4791
|
+
label: "Running and healthy",
|
|
4792
|
+
reviewable: false,
|
|
4793
|
+
terminal: false,
|
|
4794
|
+
stale: false,
|
|
4795
|
+
phase: input.phase,
|
|
4796
|
+
phaseStatus: input.phaseStatus,
|
|
4797
|
+
heartbeatAgeSeconds,
|
|
4798
|
+
nextPollAfterSeconds: input.nextPollAfterSeconds,
|
|
4799
|
+
terminalReason: null,
|
|
4800
|
+
staleReason: null,
|
|
4801
|
+
safeNextAction: input.nextAction || safeWatchAction
|
|
4802
|
+
};
|
|
4803
|
+
}
|
|
4804
|
+
return {
|
|
4805
|
+
kind: "unknown",
|
|
4806
|
+
label: "Unknown build state",
|
|
4807
|
+
reviewable: false,
|
|
4808
|
+
terminal: false,
|
|
4809
|
+
stale,
|
|
4810
|
+
phase: input.phase,
|
|
4811
|
+
phaseStatus: input.phaseStatus,
|
|
4812
|
+
heartbeatAgeSeconds,
|
|
4813
|
+
nextPollAfterSeconds: input.nextPollAfterSeconds,
|
|
4814
|
+
terminalReason: input.terminalReason,
|
|
4815
|
+
staleReason: input.staleReason,
|
|
4816
|
+
safeNextAction: input.nextAction || "Read campaign build status again before making a launch or delivery decision."
|
|
4817
|
+
};
|
|
4818
|
+
}
|
|
4254
4819
|
function mapAgentCampaignBuildStatus(data) {
|
|
4820
|
+
const customerRowCounts = mapAgentCustomerRowCounts(data.customer_row_counts);
|
|
4821
|
+
const phaseHealth = mapAgentCampaignPhaseHealth(data.phases);
|
|
4822
|
+
const terminalReason = stringValue(data.terminal_reason) ?? customerRowCounts?.terminalReason ?? null;
|
|
4823
|
+
const staleReason = stringValue(data.stale_reason) ?? stringValue(asRecord(data.diagnostics).stale_reason) ?? null;
|
|
4824
|
+
const nextPollAfterSeconds = numberOrNull2(data.next_poll_after_seconds ?? data.nextPollAfterSeconds);
|
|
4825
|
+
const terminalState = deriveCampaignBuildTerminalState({
|
|
4826
|
+
status: stringValue(data.status) ?? "unknown",
|
|
4827
|
+
phase: stringValue(data.current_phase) ?? null,
|
|
4828
|
+
phaseStatus: stringValue(data.current_phase_status) ?? null,
|
|
4829
|
+
staleRunningPhase: data.stale_running_phase === true,
|
|
4830
|
+
phaseAgeSeconds: numberOrNull2(data.phase_age_seconds),
|
|
4831
|
+
nextPollAfterSeconds,
|
|
4832
|
+
terminalReason,
|
|
4833
|
+
staleReason,
|
|
4834
|
+
nextAction: formatAgentNextAction(data.next_action),
|
|
4835
|
+
approvalAction: formatAgentNextAction(data.approval_action),
|
|
4836
|
+
triggerRunId: stringValue(data.trigger_run_id) ?? null
|
|
4837
|
+
});
|
|
4255
4838
|
return {
|
|
4256
4839
|
campaignBuildId: stringValue(data.campaign_build_id) ?? "",
|
|
4257
4840
|
campaignId: stringValue(data.campaign_id) ?? null,
|
|
@@ -4269,12 +4852,18 @@ function mapAgentCampaignBuildStatus(data) {
|
|
|
4269
4852
|
errors: diagnosticMessages2(data.errors),
|
|
4270
4853
|
artifactCount: numberOrUndefined2(data.artifact_count) ?? 0,
|
|
4271
4854
|
artifactDownloads: Array.isArray(data.artifact_downloads) ? data.artifact_downloads.map(mapAgentCampaignArtifactDownload) : [],
|
|
4272
|
-
customerRowCounts
|
|
4855
|
+
customerRowCounts,
|
|
4273
4856
|
phaseAttemptTotals: nullableRecord(data.phase_attempt_totals) ?? void 0,
|
|
4274
4857
|
providerRoute: mapProviderRoute2(data),
|
|
4275
4858
|
triggerRunId: stringValue(data.trigger_run_id) ?? null,
|
|
4276
4859
|
staleRunningPhase: data.stale_running_phase === true,
|
|
4277
4860
|
phaseAgeSeconds: numberOrNull2(data.phase_age_seconds),
|
|
4861
|
+
nextPollAfterSeconds,
|
|
4862
|
+
terminalReason,
|
|
4863
|
+
staleReason,
|
|
4864
|
+
safeNextAction: terminalState.safeNextAction,
|
|
4865
|
+
terminalState,
|
|
4866
|
+
phaseHealth,
|
|
4278
4867
|
diagnostics: nullableRecord(data.diagnostics) ?? {},
|
|
4279
4868
|
nextAction: formatAgentNextAction(data.next_action),
|
|
4280
4869
|
approvalAction: formatAgentNextAction(data.approval_action),
|
|
@@ -4304,6 +4893,7 @@ function mapAgentCustomerRowCounts(value) {
|
|
|
4304
4893
|
acceptedRows: numberOrUndefined2(record.accepted_rows),
|
|
4305
4894
|
usableRows: numberOrUndefined2(record.usable_rows),
|
|
4306
4895
|
copiedRows: numberOrUndefined2(record.copied_rows),
|
|
4896
|
+
copySkippedRows: numberOrUndefined2(record.copy_skipped_rows),
|
|
4307
4897
|
approvalReadyRows: numberOrUndefined2(record.approval_ready_rows),
|
|
4308
4898
|
qaReadyRows: numberOrUndefined2(record.qa_ready_rows),
|
|
4309
4899
|
deliveredRows: numberOrUndefined2(record.delivered_rows),
|
|
@@ -4362,67 +4952,285 @@ function mapAgentCampaignArtifact(data) {
|
|
|
4362
4952
|
createdAt: stringValue(data.created_at) ?? ""
|
|
4363
4953
|
};
|
|
4364
4954
|
}
|
|
4955
|
+
var NORTH_STAR_BANNED_COPY_PHRASES = [
|
|
4956
|
+
"i have been following",
|
|
4957
|
+
"i saw that",
|
|
4958
|
+
"would you be opposed",
|
|
4959
|
+
"unlock new opportunities",
|
|
4960
|
+
"significant success",
|
|
4961
|
+
"we understand",
|
|
4962
|
+
"hope this finds you well"
|
|
4963
|
+
];
|
|
4964
|
+
function campaignReviewGate(id, label, status, detail) {
|
|
4965
|
+
return {
|
|
4966
|
+
id,
|
|
4967
|
+
label,
|
|
4968
|
+
status,
|
|
4969
|
+
passed: status !== "blocked",
|
|
4970
|
+
detail
|
|
4971
|
+
};
|
|
4972
|
+
}
|
|
4973
|
+
function northStarMetric(id, label, status, detail, value, target) {
|
|
4974
|
+
return {
|
|
4975
|
+
id,
|
|
4976
|
+
label,
|
|
4977
|
+
status,
|
|
4978
|
+
detail,
|
|
4979
|
+
...value !== void 0 ? { value } : {},
|
|
4980
|
+
...target !== void 0 ? { target } : {}
|
|
4981
|
+
};
|
|
4982
|
+
}
|
|
4983
|
+
function createCampaignBuilderNorthStarScorecard(status, rows, artifacts, terminalState) {
|
|
4984
|
+
if (!terminalState.reviewable) {
|
|
4985
|
+
const pendingMetric = northStarMetric(
|
|
4986
|
+
"terminal_state",
|
|
4987
|
+
"Terminal-state contract",
|
|
4988
|
+
terminalState.kind === "running_stale" ? "blocked" : "pending",
|
|
4989
|
+
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.`,
|
|
4990
|
+
terminalState.kind,
|
|
4991
|
+
"terminal or pending_approval"
|
|
4992
|
+
);
|
|
4993
|
+
return {
|
|
4994
|
+
version: "campaign-builder-north-star.v1",
|
|
4995
|
+
status: pendingMetric.status,
|
|
4996
|
+
score: null,
|
|
4997
|
+
moatState: "scaffolding_ready",
|
|
4998
|
+
metrics: [pendingMetric],
|
|
4999
|
+
blockers: pendingMetric.status === "blocked" ? [pendingMetric.detail] : [],
|
|
5000
|
+
warnings: pendingMetric.status === "pending" ? [pendingMetric.detail] : [],
|
|
5001
|
+
nextAction: terminalState.safeNextAction
|
|
5002
|
+
};
|
|
5003
|
+
}
|
|
5004
|
+
const sampledRows = rows.rows.length;
|
|
5005
|
+
const rowData = rows.rows.map((row) => asRecord(row.data));
|
|
5006
|
+
const requestedTarget = status.customerRowCounts?.requestedTarget ?? status.recordsTotal ?? rows.count;
|
|
5007
|
+
const finalRows = status.customerRowCounts?.deliveredRows ?? status.customerRowCounts?.qaReadyRows ?? status.customerRowCounts?.copySkippedRows ?? status.customerRowCounts?.copiedRows ?? status.customerRowCounts?.acceptedRows ?? rows.count;
|
|
5008
|
+
const rowsWithEmail = rows.rows.filter(campaignReviewRowHasEmail).length;
|
|
5009
|
+
const verifiedEmailRows = rowData.filter(campaignReviewDataHasVerifiedEmail).length;
|
|
5010
|
+
const uniqueEmails = new Set(rowData.map(campaignReviewDataEmail).filter(Boolean)).size;
|
|
5011
|
+
const uniqueDomains = new Set(rowData.map(campaignReviewDataDomain).filter(Boolean)).size;
|
|
5012
|
+
const copyReadyRows = rows.rows.filter(campaignReviewRowHasCopy).length;
|
|
5013
|
+
const copyQaIssuesByRow = rowData.map(campaignReviewDataCopyQaIssues).filter((issues) => issues.length > 0);
|
|
5014
|
+
const copyQaIssueCounts = countCampaignReviewIssues(copyQaIssuesByRow);
|
|
5015
|
+
const signalBackedRows = rowData.filter(campaignReviewDataHasSignalBasis).length;
|
|
5016
|
+
const noSupportedSignalRows = rowData.filter(campaignReviewDataHasNoSupportedSignal).length;
|
|
5017
|
+
const unsupportedSignalClaims = rowData.filter(campaignReviewDataHasUnsupportedSignalClaim).length;
|
|
5018
|
+
const approvalLockedRows = rowData.filter(campaignReviewDataHasApprovalLock).length;
|
|
5019
|
+
const holdoutRows = rowData.filter(campaignReviewDataHasHoldoutAttribution).length;
|
|
5020
|
+
const artifactCount = artifacts.length || status.artifactCount || 0;
|
|
5021
|
+
const deliveredRows = status.customerRowCounts?.deliveredRows ?? 0;
|
|
5022
|
+
const feedbackReady = campaignReviewStatusHasFeedbackReadiness(status);
|
|
5023
|
+
const feedbackRequiredForApproval = terminalState.kind === "pending_approval";
|
|
5024
|
+
const moat = campaignReviewMoatState(status, holdoutRows);
|
|
5025
|
+
const metrics = [
|
|
5026
|
+
northStarMetric(
|
|
5027
|
+
"terminal_state",
|
|
5028
|
+
"Terminal-state contract",
|
|
5029
|
+
terminalState.kind === "blocked" ? "blocked" : "pass",
|
|
5030
|
+
terminalState.label,
|
|
5031
|
+
terminalState.kind,
|
|
5032
|
+
"terminal or pending_approval"
|
|
5033
|
+
),
|
|
5034
|
+
northStarMetric(
|
|
5035
|
+
"target_fill",
|
|
5036
|
+
"Target fill",
|
|
5037
|
+
requestedTarget && finalRows < requestedTarget ? "review" : "pass",
|
|
5038
|
+
requestedTarget ? `${finalRows || 0}/${requestedTarget} final or reviewable row(s) are accounted for.` : "No requested target was reported; using sampled rows for review.",
|
|
5039
|
+
finalRows || sampledRows,
|
|
5040
|
+
requestedTarget || sampledRows
|
|
5041
|
+
),
|
|
5042
|
+
northStarMetric(
|
|
5043
|
+
"unique_emails",
|
|
5044
|
+
"Unique emails",
|
|
5045
|
+
sampledRows === 0 ? "blocked" : uniqueEmails === rowsWithEmail ? "pass" : "blocked",
|
|
5046
|
+
sampledRows === 0 ? "No sampled rows were available for email uniqueness review." : `${uniqueEmails}/${rowsWithEmail} sampled email(s) are unique.`,
|
|
5047
|
+
uniqueEmails,
|
|
5048
|
+
rowsWithEmail
|
|
5049
|
+
),
|
|
5050
|
+
northStarMetric(
|
|
5051
|
+
"unique_domains",
|
|
5052
|
+
"Unique domains",
|
|
5053
|
+
sampledRows === 0 ? "blocked" : uniqueDomains === sampledRows ? "pass" : "review",
|
|
5054
|
+
sampledRows === 0 ? "No sampled rows were available for domain uniqueness review." : `${uniqueDomains}/${sampledRows} sampled company domain(s) are unique.`,
|
|
5055
|
+
uniqueDomains,
|
|
5056
|
+
sampledRows
|
|
5057
|
+
),
|
|
5058
|
+
northStarMetric(
|
|
5059
|
+
"verified_email_rows",
|
|
5060
|
+
"Verified email rows",
|
|
5061
|
+
sampledRows === 0 ? "blocked" : verifiedEmailRows === sampledRows ? "pass" : rowsWithEmail === sampledRows ? "review" : "blocked",
|
|
5062
|
+
sampledRows === 0 ? "No sampled rows were available for email verification review." : `${verifiedEmailRows}/${sampledRows} sampled row(s) carry verified-email evidence.`,
|
|
5063
|
+
verifiedEmailRows,
|
|
5064
|
+
sampledRows
|
|
5065
|
+
),
|
|
5066
|
+
northStarMetric(
|
|
5067
|
+
"copy_completeness",
|
|
5068
|
+
"Copy completeness",
|
|
5069
|
+
sampledRows === 0 ? "blocked" : copyReadyRows === sampledRows ? "pass" : "blocked",
|
|
5070
|
+
sampledRows === 0 ? "No sampled rows were available for copy review." : `${copyReadyRows}/${sampledRows} sampled row(s) include generated copy.`,
|
|
5071
|
+
copyReadyRows,
|
|
5072
|
+
sampledRows
|
|
5073
|
+
),
|
|
5074
|
+
northStarMetric(
|
|
5075
|
+
"copy_quality",
|
|
5076
|
+
"Copy QA",
|
|
5077
|
+
copyQaIssuesByRow.length === 0 ? "pass" : "blocked",
|
|
5078
|
+
copyQaIssuesByRow.length === 0 ? "No sampled copy QA blockers were detected." : `${copyQaIssuesByRow.length}/${sampledRows} sampled row(s) have copy QA issue(s): ${formatCampaignReviewIssueCounts(copyQaIssueCounts)}.`,
|
|
5079
|
+
copyQaIssuesByRow.length,
|
|
5080
|
+
0
|
|
5081
|
+
),
|
|
5082
|
+
northStarMetric(
|
|
5083
|
+
"signal_grounding",
|
|
5084
|
+
"Signal grounding",
|
|
5085
|
+
unsupportedSignalClaims > 0 ? "blocked" : signalBackedRows > 0 ? "pass" : "review",
|
|
5086
|
+
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.",
|
|
5087
|
+
signalBackedRows,
|
|
5088
|
+
sampledRows
|
|
5089
|
+
),
|
|
5090
|
+
northStarMetric(
|
|
5091
|
+
"approval_locks",
|
|
5092
|
+
"Approval locks",
|
|
5093
|
+
approvalLockedRows > 0 || deliveredRows === 0 ? "pass" : "review",
|
|
5094
|
+
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.",
|
|
5095
|
+
approvalLockedRows,
|
|
5096
|
+
sampledRows
|
|
5097
|
+
),
|
|
5098
|
+
northStarMetric(
|
|
5099
|
+
"export_send_safety",
|
|
5100
|
+
"Export/send safety",
|
|
5101
|
+
deliveredRows > 0 && status.status !== "completed" ? "blocked" : "pass",
|
|
5102
|
+
deliveredRows > 0 ? `${deliveredRows} row(s) are delivered; status is ${status.status}.` : "No delivered rows are reported before approval.",
|
|
5103
|
+
deliveredRows,
|
|
5104
|
+
0
|
|
5105
|
+
),
|
|
5106
|
+
northStarMetric(
|
|
5107
|
+
"holdout_attribution",
|
|
5108
|
+
"Holdout attribution",
|
|
5109
|
+
holdoutRows > 0 ? "pass" : "review",
|
|
5110
|
+
holdoutRows > 0 ? `${holdoutRows}/${sampledRows} sampled row(s) preserve holdout attribution.` : "No holdout attribution was visible in the sampled rows.",
|
|
5111
|
+
holdoutRows,
|
|
5112
|
+
sampledRows
|
|
5113
|
+
),
|
|
5114
|
+
northStarMetric(
|
|
5115
|
+
"feedback_readiness",
|
|
5116
|
+
"Feedback readiness",
|
|
5117
|
+
feedbackReady ? "pass" : feedbackRequiredForApproval ? "blocked" : "review",
|
|
5118
|
+
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.",
|
|
5119
|
+
feedbackReady,
|
|
5120
|
+
true
|
|
5121
|
+
),
|
|
5122
|
+
northStarMetric(
|
|
5123
|
+
"causal_moat",
|
|
5124
|
+
"Causal moat",
|
|
5125
|
+
moat.state === "proved" ? "pass" : "review",
|
|
5126
|
+
moat.detail,
|
|
5127
|
+
moat.state,
|
|
5128
|
+
"proved"
|
|
5129
|
+
),
|
|
5130
|
+
northStarMetric(
|
|
5131
|
+
"artifact_readback",
|
|
5132
|
+
"Artifact readback",
|
|
5133
|
+
artifactCount > 0 ? "pass" : "review",
|
|
5134
|
+
artifactCount > 0 ? `${artifactCount} artifact(s) are available for review.` : "No review artifact is available yet.",
|
|
5135
|
+
artifactCount,
|
|
5136
|
+
1
|
|
5137
|
+
)
|
|
5138
|
+
];
|
|
5139
|
+
const gradedMetrics = metrics.filter((metric) => metric.status !== "pending");
|
|
5140
|
+
const score = gradedMetrics.length === 0 ? null : Math.round(gradedMetrics.filter((metric) => metric.status === "pass").length / gradedMetrics.length * 100);
|
|
5141
|
+
const blockers = metrics.filter((metric) => metric.status === "blocked").map((metric) => metric.detail);
|
|
5142
|
+
const warnings = metrics.filter((metric) => metric.status === "review").map((metric) => metric.detail);
|
|
5143
|
+
const scorecardStatus = blockers.length > 0 ? "blocked" : warnings.length > 0 ? "review" : "pass";
|
|
5144
|
+
return {
|
|
5145
|
+
version: "campaign-builder-north-star.v1",
|
|
5146
|
+
status: scorecardStatus,
|
|
5147
|
+
score,
|
|
5148
|
+
moatState: moat.state,
|
|
5149
|
+
metrics,
|
|
5150
|
+
blockers,
|
|
5151
|
+
warnings,
|
|
5152
|
+
nextAction: scorecardStatus === "blocked" ? "Fix blocked North Star gates before approval or delivery." : terminalState.safeNextAction
|
|
5153
|
+
};
|
|
5154
|
+
}
|
|
4365
5155
|
function createCampaignBuilderBuildReview(status, rows, artifacts) {
|
|
5156
|
+
const terminalState = status.terminalState ?? deriveCampaignBuildTerminalState({
|
|
5157
|
+
status: status.status,
|
|
5158
|
+
phase: status.currentPhase,
|
|
5159
|
+
phaseStatus: status.currentPhaseStatus,
|
|
5160
|
+
staleRunningPhase: status.staleRunningPhase === true,
|
|
5161
|
+
phaseAgeSeconds: status.phaseAgeSeconds ?? null,
|
|
5162
|
+
nextPollAfterSeconds: status.nextPollAfterSeconds ?? null,
|
|
5163
|
+
terminalReason: status.terminalReason ?? status.customerRowCounts?.terminalReason ?? null,
|
|
5164
|
+
staleReason: status.staleReason ?? null,
|
|
5165
|
+
nextAction: status.nextAction,
|
|
5166
|
+
approvalAction: status.approvalAction,
|
|
5167
|
+
triggerRunId: status.triggerRunId ?? null
|
|
5168
|
+
});
|
|
4366
5169
|
const sampledRows = rows.rows.length;
|
|
4367
5170
|
const availableRows = rows.count || sampledRows;
|
|
4368
5171
|
const qualifiedRows = rows.rows.filter((row) => row.qualified !== false).length;
|
|
4369
5172
|
const rowsWithEmail = rows.rows.filter(campaignReviewRowHasEmail).length;
|
|
4370
5173
|
const copyReadyRows = rows.rows.filter(campaignReviewRowHasCopy).length;
|
|
4371
5174
|
const artifactCount = artifacts.length || status.artifactCount || 0;
|
|
5175
|
+
const northStarScorecard = createCampaignBuilderNorthStarScorecard(status, rows, artifacts, terminalState);
|
|
4372
5176
|
const gates = [
|
|
4373
|
-
|
|
4374
|
-
|
|
4375
|
-
|
|
4376
|
-
|
|
4377
|
-
|
|
4378
|
-
|
|
4379
|
-
|
|
4380
|
-
|
|
4381
|
-
|
|
4382
|
-
|
|
4383
|
-
|
|
4384
|
-
|
|
4385
|
-
|
|
4386
|
-
|
|
4387
|
-
|
|
4388
|
-
|
|
4389
|
-
|
|
4390
|
-
|
|
4391
|
-
|
|
4392
|
-
|
|
4393
|
-
|
|
4394
|
-
|
|
4395
|
-
|
|
4396
|
-
|
|
4397
|
-
|
|
4398
|
-
|
|
4399
|
-
|
|
4400
|
-
|
|
4401
|
-
|
|
4402
|
-
|
|
4403
|
-
|
|
4404
|
-
|
|
4405
|
-
|
|
4406
|
-
|
|
4407
|
-
|
|
4408
|
-
|
|
5177
|
+
campaignReviewGate(
|
|
5178
|
+
"build_reviewable",
|
|
5179
|
+
"Build reviewable",
|
|
5180
|
+
terminalState.kind === "running_healthy" ? "pending" : terminalState.kind === "running_stale" || terminalState.kind === "blocked" ? "blocked" : "pass",
|
|
5181
|
+
terminalState.label
|
|
5182
|
+
),
|
|
5183
|
+
campaignReviewGate(
|
|
5184
|
+
"rows_available",
|
|
5185
|
+
"Rows available",
|
|
5186
|
+
sampledRows > 0 ? "pass" : terminalState.reviewable ? "blocked" : "pending",
|
|
5187
|
+
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."
|
|
5188
|
+
),
|
|
5189
|
+
campaignReviewGate(
|
|
5190
|
+
"qualified_sample",
|
|
5191
|
+
"Sample rows qualified",
|
|
5192
|
+
sampledRows === 0 ? terminalState.reviewable ? "blocked" : "pending" : qualifiedRows === sampledRows ? "pass" : "blocked",
|
|
5193
|
+
sampledRows > 0 ? `${qualifiedRows}/${sampledRows} sampled row(s) are marked qualified.` : "Qualification could not be checked without sampled rows."
|
|
5194
|
+
),
|
|
5195
|
+
campaignReviewGate(
|
|
5196
|
+
"email_coverage",
|
|
5197
|
+
"Email coverage",
|
|
5198
|
+
sampledRows === 0 ? terminalState.reviewable ? "blocked" : "pending" : rowsWithEmail === sampledRows ? "pass" : "blocked",
|
|
5199
|
+
sampledRows > 0 ? `${rowsWithEmail}/${sampledRows} sampled row(s) include an email.` : "Email coverage could not be checked without sampled rows."
|
|
5200
|
+
),
|
|
5201
|
+
campaignReviewGate(
|
|
5202
|
+
"artifact_available",
|
|
5203
|
+
"Artifact available",
|
|
5204
|
+
artifactCount > 0 ? "pass" : terminalState.reviewable ? "review" : "pending",
|
|
5205
|
+
artifactCount > 0 ? `${artifactCount} artifact(s) are available.` : "No delivery artifact is available yet."
|
|
5206
|
+
),
|
|
5207
|
+
campaignReviewGate(
|
|
5208
|
+
"no_failed_rows",
|
|
5209
|
+
"No failed rows",
|
|
5210
|
+
status.recordsFailed === 0 ? "pass" : "blocked",
|
|
5211
|
+
status.recordsFailed === 0 ? "The build reports zero failed rows." : `${status.recordsFailed} row(s) failed during the build.`
|
|
5212
|
+
)
|
|
4409
5213
|
];
|
|
4410
|
-
const blockedReasons = gates.filter((gate) => !gate.passed).map((gate) => gate.detail);
|
|
5214
|
+
const blockedReasons = gates.filter((gate) => gate.status === "blocked" || !gate.passed).map((gate) => gate.detail);
|
|
4411
5215
|
const warnings = [
|
|
4412
5216
|
rows.hasMore ? "This review is based on a row sample; page through remaining rows before final approval." : void 0,
|
|
4413
5217
|
sampledRows > 0 && copyReadyRows < sampledRows ? `${copyReadyRows}/${sampledRows} sampled row(s) include generated copy.` : void 0,
|
|
4414
5218
|
...status.warnings
|
|
4415
5219
|
].filter((item) => Boolean(item));
|
|
4416
|
-
const readyForDeliveryApproval = blockedReasons.length === 0;
|
|
5220
|
+
const readyForDeliveryApproval = terminalState.reviewable && blockedReasons.length === 0 && northStarScorecard.status !== "blocked";
|
|
4417
5221
|
return {
|
|
4418
5222
|
campaignBuildId: status.campaignBuildId || rows.campaignBuildId,
|
|
4419
5223
|
status,
|
|
4420
5224
|
rows,
|
|
4421
5225
|
artifacts,
|
|
4422
5226
|
gates,
|
|
5227
|
+
northStarScorecard,
|
|
4423
5228
|
summary: {
|
|
4424
5229
|
status: status.status,
|
|
4425
5230
|
phase: status.currentPhase,
|
|
5231
|
+
terminalState: terminalState.kind,
|
|
5232
|
+
scorecardStatus: northStarScorecard.status,
|
|
5233
|
+
scorecardScore: northStarScorecard.score,
|
|
4426
5234
|
sampledRows,
|
|
4427
5235
|
availableRows,
|
|
4428
5236
|
qualifiedRows,
|
|
@@ -4476,6 +5284,184 @@ function campaignReviewRowHasCopy(row) {
|
|
|
4476
5284
|
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)
|
|
4477
5285
|
);
|
|
4478
5286
|
}
|
|
5287
|
+
function campaignReviewDataEmail(data) {
|
|
5288
|
+
return stringValue(data.email) || stringValue(data.work_email) || stringValue(data.workEmail) || stringValue(asRecord(data.contact).email);
|
|
5289
|
+
}
|
|
5290
|
+
function campaignReviewDataDomain(data) {
|
|
5291
|
+
const domain = stringValue(data.company_domain) || stringValue(data.companyDomain) || stringValue(asRecord(data.company).domain);
|
|
5292
|
+
return domain?.toLowerCase();
|
|
5293
|
+
}
|
|
5294
|
+
function campaignReviewDataHasVerifiedEmail(data) {
|
|
5295
|
+
const status = String(data.email_status ?? data.emailStatus ?? asRecord(data.contact).email_status ?? "").toLowerCase();
|
|
5296
|
+
return data.email_verified === true || data.emailVerified === true || asRecord(data.contact).email_verified === true || ["valid", "validated", "verified"].includes(status);
|
|
5297
|
+
}
|
|
5298
|
+
function campaignReviewDataCopyParts(data) {
|
|
5299
|
+
const copy = asRecord(data.copy);
|
|
5300
|
+
const rawCopy = asRecord(data.raw_copy ?? data.rawCopy);
|
|
5301
|
+
return [
|
|
5302
|
+
stringValue(data.subject),
|
|
5303
|
+
stringValue(data.subject_line),
|
|
5304
|
+
stringValue(data.opener),
|
|
5305
|
+
stringValue(data.body),
|
|
5306
|
+
stringValue(data.cta),
|
|
5307
|
+
stringValue(copy.subject),
|
|
5308
|
+
stringValue(copy.opener),
|
|
5309
|
+
stringValue(copy.body),
|
|
5310
|
+
stringValue(copy.cta),
|
|
5311
|
+
stringValue(rawCopy.subject),
|
|
5312
|
+
stringValue(rawCopy.opener),
|
|
5313
|
+
stringValue(rawCopy.body),
|
|
5314
|
+
stringValue(rawCopy.cta)
|
|
5315
|
+
].filter((part) => Boolean(part));
|
|
5316
|
+
}
|
|
5317
|
+
function campaignReviewDataHasBadGreeting(data) {
|
|
5318
|
+
return campaignReviewDataCopyParts(data).some(
|
|
5319
|
+
(part) => /\bhi\s*(?:,|\{\{|\[)|\bhello\s*(?:,|\{\{|\[)/i.test(part) || /\b(first_name|firstname|name)\b/i.test(part)
|
|
5320
|
+
);
|
|
5321
|
+
}
|
|
5322
|
+
function campaignReviewDataHasBannedPhrase(data) {
|
|
5323
|
+
const text = campaignReviewDataCopyParts(data).join(" ").toLowerCase();
|
|
5324
|
+
return NORTH_STAR_BANNED_COPY_PHRASES.some((phrase) => text.includes(phrase));
|
|
5325
|
+
}
|
|
5326
|
+
function campaignReviewDataSubject(data) {
|
|
5327
|
+
const copy = asRecord(data.copy);
|
|
5328
|
+
const rawCopy = asRecord(data.raw_copy ?? data.rawCopy);
|
|
5329
|
+
return stringValue(data.subject) || stringValue(data.subject_line) || stringValue(data.subjectLine) || stringValue(copy.subject) || stringValue(rawCopy.subject);
|
|
5330
|
+
}
|
|
5331
|
+
function campaignReviewDataCta(data) {
|
|
5332
|
+
const copy = asRecord(data.copy);
|
|
5333
|
+
const rawCopy = asRecord(data.raw_copy ?? data.rawCopy);
|
|
5334
|
+
return stringValue(data.cta) || stringValue(copy.cta) || stringValue(rawCopy.cta);
|
|
5335
|
+
}
|
|
5336
|
+
function countCampaignReviewIssues(issueRows) {
|
|
5337
|
+
return issueRows.flat().reduce((acc, issue) => {
|
|
5338
|
+
acc[issue] = (acc[issue] || 0) + 1;
|
|
5339
|
+
return acc;
|
|
5340
|
+
}, {});
|
|
5341
|
+
}
|
|
5342
|
+
function formatCampaignReviewIssueCounts(counts) {
|
|
5343
|
+
const entries = Object.entries(counts);
|
|
5344
|
+
return entries.length > 0 ? entries.map(([issue, count]) => `${issue}=${count}`).join(", ") : "none";
|
|
5345
|
+
}
|
|
5346
|
+
function campaignReviewDataCopyQaIssues(data) {
|
|
5347
|
+
const issues = /* @__PURE__ */ new Set();
|
|
5348
|
+
const copyParts = campaignReviewDataCopyParts(data);
|
|
5349
|
+
if (copyParts.length === 0) return [];
|
|
5350
|
+
if (campaignReviewDataHasBadGreeting(data)) issues.add("bad_greeting");
|
|
5351
|
+
if (campaignReviewDataHasBannedPhrase(data)) issues.add("banned_or_vague_phrase");
|
|
5352
|
+
if (campaignReviewDataHasUnsupportedSignalClaim(data)) issues.add("unsupported_signal_claim");
|
|
5353
|
+
if (campaignReviewDataPersonalizationBasis(data).length === 0) issues.add("missing_personalization_basis");
|
|
5354
|
+
if (!campaignReviewDataCta(data)) issues.add("missing_cta");
|
|
5355
|
+
const subject = campaignReviewDataSubject(data);
|
|
5356
|
+
if (subject && subject.length > 70) issues.add("overlong_subject");
|
|
5357
|
+
return [...issues];
|
|
5358
|
+
}
|
|
5359
|
+
function campaignReviewDataPersonalizationBasis(data) {
|
|
5360
|
+
const rawCopy = asRecord(data.raw_copy ?? data.rawCopy);
|
|
5361
|
+
const copy = asRecord(data.copy);
|
|
5362
|
+
const metadata = asRecord(data.metadata);
|
|
5363
|
+
const signalEvidence = asRecord(data.signal_evidence ?? metadata.signal_evidence ?? metadata.signalEvidence);
|
|
5364
|
+
return [
|
|
5365
|
+
...arrayOfStrings(data.personalization_basis) ?? [],
|
|
5366
|
+
...arrayOfStrings(data.personalizationBasis) ?? [],
|
|
5367
|
+
...arrayOfStrings(copy.personalization_basis) ?? [],
|
|
5368
|
+
...arrayOfStrings(rawCopy.personalization_basis) ?? [],
|
|
5369
|
+
...arrayOfStrings(metadata.personalization_basis) ?? [],
|
|
5370
|
+
...arrayOfStrings(metadata.personalizationBasis) ?? [],
|
|
5371
|
+
...arrayOfStrings(signalEvidence.personalization_basis) ?? []
|
|
5372
|
+
];
|
|
5373
|
+
}
|
|
5374
|
+
function campaignReviewDataHasNoSupportedSignal(data) {
|
|
5375
|
+
const metadata = asRecord(data.metadata);
|
|
5376
|
+
const copy = asRecord(data.copy);
|
|
5377
|
+
const state = [
|
|
5378
|
+
data.copy_signal_state,
|
|
5379
|
+
data.signal_basis,
|
|
5380
|
+
data.signal_type,
|
|
5381
|
+
metadata.copy_signal_state,
|
|
5382
|
+
metadata.signal_basis,
|
|
5383
|
+
metadata.signal_type,
|
|
5384
|
+
copy.copy_signal_state
|
|
5385
|
+
].map((value) => stringValue(value)?.toLowerCase()).filter(Boolean);
|
|
5386
|
+
return data.no_supported_signal === true || metadata.no_supported_signal === true || state.includes("no_supported_signal");
|
|
5387
|
+
}
|
|
5388
|
+
function campaignReviewDataHasSignalBasis(data) {
|
|
5389
|
+
if (campaignReviewDataHasNoSupportedSignal(data)) return false;
|
|
5390
|
+
const metadata = asRecord(data.metadata);
|
|
5391
|
+
const signal = asRecord(data.signal);
|
|
5392
|
+
const signalEvidence = asRecord(data.signal_evidence ?? metadata.signal_evidence ?? metadata.signalEvidence);
|
|
5393
|
+
const basis = campaignReviewDataPersonalizationBasis(data);
|
|
5394
|
+
return Boolean(
|
|
5395
|
+
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))
|
|
5396
|
+
);
|
|
5397
|
+
}
|
|
5398
|
+
function campaignReviewDataHasUnsupportedSignalClaim(data) {
|
|
5399
|
+
const copyText = campaignReviewDataCopyParts(data).join(" ").toLowerCase();
|
|
5400
|
+
const claimsSignal = /\b(hiring|funding|raised|launched|expanding|appointed|announced|recent news|new role|job posting)\b/.test(copyText);
|
|
5401
|
+
return claimsSignal && !campaignReviewDataHasSignalBasis(data);
|
|
5402
|
+
}
|
|
5403
|
+
function campaignReviewDataHasApprovalLock(data) {
|
|
5404
|
+
const metadata = asRecord(data.fit_metadata ?? data.metadata);
|
|
5405
|
+
const approval = String(data.approval_status ?? data.delivery_approval_status ?? metadata.approval_status ?? "").toLowerCase();
|
|
5406
|
+
const exportStatus = String(data.export_status ?? data.exportStatus ?? "").toLowerCase();
|
|
5407
|
+
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);
|
|
5408
|
+
}
|
|
5409
|
+
function campaignReviewDataHasHoldoutAttribution(data) {
|
|
5410
|
+
const fitMetadata = asRecord(data.fit_metadata ?? data.fitMetadata);
|
|
5411
|
+
const metadata = asRecord(data.metadata);
|
|
5412
|
+
const holdout = asRecord(
|
|
5413
|
+
fitMetadata.learning_holdout ?? fitMetadata.learningHoldout ?? metadata.learning_holdout ?? metadata.learningHoldout ?? data.learning_holdout ?? data.learningHoldout
|
|
5414
|
+
);
|
|
5415
|
+
const experimentKey = stringValue(holdout.experiment_key ?? holdout.experimentKey ?? data.experiment_key ?? data.experimentKey);
|
|
5416
|
+
const cohort = stringValue(holdout.cohort_role ?? holdout.cohortRole ?? data.cohort_role ?? data.learning_cohort ?? data.learningCohort);
|
|
5417
|
+
const brainApplied = holdout.brain_applied ?? holdout.brainApplied ?? data.brain_applied ?? data.signaliz_brain_applied;
|
|
5418
|
+
return Boolean(experimentKey && cohort && brainApplied !== void 0);
|
|
5419
|
+
}
|
|
5420
|
+
function campaignReviewStatusHasFeedbackReadiness(status) {
|
|
5421
|
+
const diagnostics = asRecord(status.diagnostics);
|
|
5422
|
+
const feedbackReadiness = asRecord(diagnostics.feedback_readiness ?? diagnostics.feedbackReadiness);
|
|
5423
|
+
const feedbackSubstrate = asRecord(diagnostics.feedback_substrate ?? diagnostics.feedbackSubstrate);
|
|
5424
|
+
const evidenceCounts = asRecord(diagnostics.evidence_counts ?? diagnostics.evidenceCounts);
|
|
5425
|
+
return feedbackReadiness.ready === true || feedbackReadiness.webhook_configured === true || feedbackSubstrate.stage === "ready" || Number(evidenceCounts.feedback_events ?? 0) > 0;
|
|
5426
|
+
}
|
|
5427
|
+
function campaignReviewMoatState(status, holdoutRows) {
|
|
5428
|
+
const diagnostics = asRecord(status.diagnostics);
|
|
5429
|
+
const evidenceCounts = asRecord(diagnostics.evidence_counts ?? diagnostics.evidenceCounts);
|
|
5430
|
+
const embeddedHoldout = asRecord(diagnostics.embedded_holdout ?? diagnostics.embeddedHoldout);
|
|
5431
|
+
const holdoutLift = asRecord(diagnostics.holdout_lift ?? diagnostics.holdoutLift ?? diagnostics.holdout_measurement ?? diagnostics.holdoutMeasurement);
|
|
5432
|
+
const controlSample = Math.max(
|
|
5433
|
+
Number(evidenceCounts.holdout_control_sample_size ?? 0),
|
|
5434
|
+
Number(evidenceCounts.embedded_holdout_control_sample ?? 0),
|
|
5435
|
+
Number(embeddedHoldout.control_sample_size ?? 0)
|
|
5436
|
+
);
|
|
5437
|
+
const learnedSample = Math.max(
|
|
5438
|
+
Number(evidenceCounts.holdout_learned_sample_size ?? 0),
|
|
5439
|
+
Number(evidenceCounts.embedded_holdout_learned_sample ?? 0),
|
|
5440
|
+
Number(embeddedHoldout.learned_sample_size ?? 0)
|
|
5441
|
+
);
|
|
5442
|
+
const feedbackEvents = Math.max(
|
|
5443
|
+
Number(evidenceCounts.feedback_events ?? 0),
|
|
5444
|
+
Number(evidenceCounts.campaign_build_feedback_events ?? 0),
|
|
5445
|
+
Number(evidenceCounts.delivery_holdout_sent_outcomes ?? 0)
|
|
5446
|
+
);
|
|
5447
|
+
const proved = diagnostics.closed_loop_proof_ready === true || holdoutLift.honest_measurement === true && holdoutLift.positive_lift === true;
|
|
5448
|
+
if (proved) {
|
|
5449
|
+
return {
|
|
5450
|
+
state: "proved",
|
|
5451
|
+
detail: "Real attributed feedback shows positive lift for explicit control and learned cohorts."
|
|
5452
|
+
};
|
|
5453
|
+
}
|
|
5454
|
+
if (controlSample > 0 && learnedSample > 0 && feedbackEvents > 0) {
|
|
5455
|
+
return {
|
|
5456
|
+
state: "moved_needs_lift_volume",
|
|
5457
|
+
detail: `Control and learned cohorts have attributed feedback (${controlSample} control, ${learnedSample} learned, ${feedbackEvents} feedback event(s)); keep collecting lift volume before claiming proof.`
|
|
5458
|
+
};
|
|
5459
|
+
}
|
|
5460
|
+
return {
|
|
5461
|
+
state: "scaffolding_ready",
|
|
5462
|
+
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."
|
|
5463
|
+
};
|
|
5464
|
+
}
|
|
4479
5465
|
function createCampaignBuilderReadinessLane(route, plan) {
|
|
4480
5466
|
const builtIn = campaignBuilderBuiltInForRoute(route);
|
|
4481
5467
|
const customRoute = route.provider !== "signaliz" && route.provider !== "csv" && builtIn === void 0;
|
|
@@ -4509,6 +5495,342 @@ function createCampaignBuilderReadinessLane(route, plan) {
|
|
|
4509
5495
|
nextAction: customRoute ? `Review ${route.provider} route setup before launch approval.` : void 0
|
|
4510
5496
|
};
|
|
4511
5497
|
}
|
|
5498
|
+
function createCampaignBuilderApprovalPacket(plan, approval, missingTypes) {
|
|
5499
|
+
const requestedTypes = plan ? uniqueStrings(plan.approvals.filter((item) => item.blocking).map((item) => item.type)) : [];
|
|
5500
|
+
const approvalMatchesPlan = Boolean(plan && approval?.planId === plan.planId);
|
|
5501
|
+
const approvedTypes = approvalMatchesPlan ? approval?.approvedTypes ?? [] : [];
|
|
5502
|
+
const approvedRoutes = approvalMatchesPlan ? approval?.approvedRouteIds ?? [] : [];
|
|
5503
|
+
const missingIds = new Set(
|
|
5504
|
+
plan && approvalMatchesPlan && approval ? getMissingCampaignBuilderApprovals(plan, approval).map((item) => item.id) : plan?.approvals.filter((item) => item.blocking).map((item) => item.id) ?? []
|
|
5505
|
+
);
|
|
5506
|
+
const routeIdsRequired = plan ? uniqueStrings(plan.approvals.map((item) => item.routeId).filter((id) => Boolean(id))) : [];
|
|
5507
|
+
const spendLimitRequired = plan ? Math.max(0, ...plan.approvals.filter((item) => item.type === "spend" && item.blocking).map((item) => item.estimatedCredits ?? plan.estimatedCredits)) : 0;
|
|
5508
|
+
const normalizedSpendLimit = spendLimitRequired > 0 ? spendLimitRequired : null;
|
|
5509
|
+
const approvalState = !plan ? "unscoped" : missingTypes.length > 0 ? "requires_approval" : "approved";
|
|
5510
|
+
const approvalInput = {
|
|
5511
|
+
approved_by: approval?.approvedBy ?? null,
|
|
5512
|
+
approved_at: approval?.approvedAt ?? null,
|
|
5513
|
+
approved_types: approvedTypes,
|
|
5514
|
+
approved_route_ids: approvedRoutes,
|
|
5515
|
+
spend_limit_credits: approval?.spendLimitCredits ?? null,
|
|
5516
|
+
notes: approval?.notes
|
|
5517
|
+
};
|
|
5518
|
+
return {
|
|
5519
|
+
packet_version: "campaign-builder-approval-packet.v1",
|
|
5520
|
+
read_only: true,
|
|
5521
|
+
no_spend: true,
|
|
5522
|
+
no_provider_writes: true,
|
|
5523
|
+
private_safe: true,
|
|
5524
|
+
approval_state: approvalState,
|
|
5525
|
+
plan_id: plan?.planId ?? null,
|
|
5526
|
+
campaign_name: plan?.campaignName ?? null,
|
|
5527
|
+
requested_approval_types: requestedTypes,
|
|
5528
|
+
missing_approval_types: uniqueStrings(missingTypes),
|
|
5529
|
+
spend_limit_credits_required: normalizedSpendLimit,
|
|
5530
|
+
route_ids_required: routeIdsRequired,
|
|
5531
|
+
required_approvals: (plan?.approvals ?? []).map((item) => compact({
|
|
5532
|
+
id: item.id,
|
|
5533
|
+
type: item.type,
|
|
5534
|
+
label: item.label,
|
|
5535
|
+
reason: item.reason,
|
|
5536
|
+
blocking: item.blocking,
|
|
5537
|
+
route_id: item.routeId,
|
|
5538
|
+
provider: item.provider,
|
|
5539
|
+
estimated_credits: item.estimatedCredits,
|
|
5540
|
+
status: missingIds.has(item.id) ? "missing" : "approved"
|
|
5541
|
+
})),
|
|
5542
|
+
approval_input: approvalInput,
|
|
5543
|
+
cli_handoff: plan ? {
|
|
5544
|
+
command: campaignBuilderApprovalCliHandoff(requestedTypes, routeIdsRequired, normalizedSpendLimit),
|
|
5545
|
+
safety: "Template only: run after explicit human approval identity, approved types, route scope, and spend limit are filled in."
|
|
5546
|
+
} : null,
|
|
5547
|
+
sdk_handoff: plan ? {
|
|
5548
|
+
method: "campaignBuilderAgent.buildApprovedPlan",
|
|
5549
|
+
approval: compact({
|
|
5550
|
+
approvedBy: approval?.approvedBy ?? "<operator-email>",
|
|
5551
|
+
approvedTypes: requestedTypes,
|
|
5552
|
+
approvedRouteIds: routeIdsRequired,
|
|
5553
|
+
spendLimitCredits: normalizedSpendLimit ?? void 0,
|
|
5554
|
+
notes: approval?.notes
|
|
5555
|
+
}),
|
|
5556
|
+
options: {
|
|
5557
|
+
idempotencyKey: "<set-before-execution>"
|
|
5558
|
+
},
|
|
5559
|
+
safety: "Call only after the approval packet is accepted; this helper does not execute writes or spend."
|
|
5560
|
+
} : null,
|
|
5561
|
+
mcp_handoffs: plan ? campaignBuilderApprovalMcpHandoffs(plan, requestedTypes, routeIdsRequired, normalizedSpendLimit) : [],
|
|
5562
|
+
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."
|
|
5563
|
+
};
|
|
5564
|
+
}
|
|
5565
|
+
function campaignBuilderApprovalCliHandoff(requestedTypes, routeIds, spendLimit) {
|
|
5566
|
+
return [
|
|
5567
|
+
"signaliz campaign-agent build-approved --request-file campaign-request.json --confirm-launch",
|
|
5568
|
+
requestedTypes.length > 0 ? `--approved-types ${shellArg(requestedTypes.join(","))}` : "--approve-all",
|
|
5569
|
+
"--approved-by <operator-email>",
|
|
5570
|
+
spendLimit !== null ? `--spend-limit ${spendLimit}` : void 0,
|
|
5571
|
+
routeIds.length > 0 ? `--approved-route-ids ${shellArg(routeIds.join(","))}` : void 0
|
|
5572
|
+
].filter(Boolean).join(" ");
|
|
5573
|
+
}
|
|
5574
|
+
function campaignBuilderApprovalMcpHandoffs(plan, requestedTypes, routeIds, spendLimit) {
|
|
5575
|
+
const approvalContext = compact({
|
|
5576
|
+
plan_id: plan.planId,
|
|
5577
|
+
approval_types: requestedTypes,
|
|
5578
|
+
approved_route_ids: routeIds,
|
|
5579
|
+
spend_limit_credits: spendLimit,
|
|
5580
|
+
approved_by: "<operator-email>"
|
|
5581
|
+
});
|
|
5582
|
+
return plan.mcpFlow.filter((step) => ["execution-prepare", "approved-build", "delivery-approval"].includes(step.id)).map((step) => ({
|
|
5583
|
+
id: step.id,
|
|
5584
|
+
tool: step.tool,
|
|
5585
|
+
arguments: step.id === "approved-build" ? compact({ ...step.arguments, approval_context: approvalContext }) : step.arguments,
|
|
5586
|
+
read_only: step.readOnly,
|
|
5587
|
+
approval_required: step.approvalRequired,
|
|
5588
|
+
safety: step.readOnly ? "Read-only readiness handoff; safe to inspect before approval." : "Write-capable handoff; run only after the approval packet is accepted."
|
|
5589
|
+
}));
|
|
5590
|
+
}
|
|
5591
|
+
function campaignBuilderActiveWorkNextMcpAction(input) {
|
|
5592
|
+
const campaignBuildRef = input.refs.find((ref) => ref.kind === "campaign_build" && ref.id);
|
|
5593
|
+
if (campaignBuildRef) {
|
|
5594
|
+
return {
|
|
5595
|
+
id: "check-campaign-build-status",
|
|
5596
|
+
tool: "get_campaign_build_status",
|
|
5597
|
+
arguments: { campaign_build_id: campaignBuildRef.id },
|
|
5598
|
+
read_only: true,
|
|
5599
|
+
approval_required: false,
|
|
5600
|
+
safety: "Read-only status check for the remembered campaign build; does not spend, write, export, send, or approve anything."
|
|
5601
|
+
};
|
|
5602
|
+
}
|
|
5603
|
+
const campaignRef = input.refs.find((ref) => ref.kind === "gtm_campaign" && ref.id);
|
|
5604
|
+
if (campaignRef) {
|
|
5605
|
+
return {
|
|
5606
|
+
id: "check-gtm-campaign-status",
|
|
5607
|
+
tool: "gtm_campaign_execution_status",
|
|
5608
|
+
arguments: { campaign_id: campaignRef.id },
|
|
5609
|
+
read_only: true,
|
|
5610
|
+
approval_required: false,
|
|
5611
|
+
safety: "Read-only campaign execution status check; does not start or mutate the campaign."
|
|
5612
|
+
};
|
|
5613
|
+
}
|
|
5614
|
+
const preferredStepId = input.state === "ready_for_dry_run" ? "dry-run-build" : input.state === "planning" || input.state === "blocked" ? "agency-campaign-build-plan" : null;
|
|
5615
|
+
const preferredStep = preferredStepId ? input.plan?.mcpFlow.find((step) => step.id === preferredStepId && step.readOnly) : void 0;
|
|
5616
|
+
if (preferredStep) return campaignBuilderMcpStepToActiveWorkAction(preferredStep, "Read-only continuation from the saved campaign-agent plan.");
|
|
5617
|
+
const readOnlyApprovalHandoff = input.approvalPacket.mcp_handoffs.find((handoff) => handoff.read_only && !handoff.approval_required);
|
|
5618
|
+
if (readOnlyApprovalHandoff) return readOnlyApprovalHandoff;
|
|
5619
|
+
const firstReadOnlyPlanStep = input.plan?.mcpFlow.find((step) => step.readOnly && !step.approvalRequired);
|
|
5620
|
+
return firstReadOnlyPlanStep ? campaignBuilderMcpStepToActiveWorkAction(firstReadOnlyPlanStep, "Read-only saved plan check; safe before approvals or writes.") : null;
|
|
5621
|
+
}
|
|
5622
|
+
function campaignBuilderMcpStepToActiveWorkAction(step, safety) {
|
|
5623
|
+
return {
|
|
5624
|
+
id: step.id,
|
|
5625
|
+
tool: step.tool,
|
|
5626
|
+
arguments: step.arguments,
|
|
5627
|
+
read_only: step.readOnly,
|
|
5628
|
+
approval_required: step.approvalRequired,
|
|
5629
|
+
safety
|
|
5630
|
+
};
|
|
5631
|
+
}
|
|
5632
|
+
function normalizeCampaignBuilderActiveWorkRefs(input) {
|
|
5633
|
+
const refs = [];
|
|
5634
|
+
const pushRef = (ref) => {
|
|
5635
|
+
if (!ref?.id) return;
|
|
5636
|
+
refs.push(ref);
|
|
5637
|
+
};
|
|
5638
|
+
pushRef(input.plan?.planId ? { kind: "plan", id: input.plan.planId, label: input.plan.campaignName, source: "plan" } : void 0);
|
|
5639
|
+
pushRef(input.remembered.planId ? { kind: "plan", id: input.remembered.planId, source: "remembered" } : void 0);
|
|
5640
|
+
pushRef(
|
|
5641
|
+
input.plan?.buildRequest.gtmCampaignId ?? input.remembered.gtmCampaignId ? {
|
|
5642
|
+
kind: "gtm_campaign",
|
|
5643
|
+
id: input.plan?.buildRequest.gtmCampaignId ?? input.remembered.gtmCampaignId,
|
|
5644
|
+
label: input.plan?.campaignName,
|
|
5645
|
+
source: input.plan?.buildRequest.gtmCampaignId ? "plan" : "remembered"
|
|
5646
|
+
} : void 0
|
|
5647
|
+
);
|
|
5648
|
+
const campaignBuildId = stringValue(input.lastResult.campaign_build_id ?? input.lastResult.campaignBuildId) ?? input.remembered.campaignBuildId;
|
|
5649
|
+
pushRef(campaignBuildId ? { kind: "campaign_build", id: campaignBuildId, status: activeWorkStatus(input.lastResult) ?? input.remembered.status, source: "result" } : void 0);
|
|
5650
|
+
pushRef(
|
|
5651
|
+
input.remembered.providerCampaignId ? {
|
|
5652
|
+
kind: "provider_campaign",
|
|
5653
|
+
id: input.remembered.providerCampaignId,
|
|
5654
|
+
label: input.remembered.provider,
|
|
5655
|
+
status: input.remembered.status,
|
|
5656
|
+
source: "remembered"
|
|
5657
|
+
} : void 0
|
|
5658
|
+
);
|
|
5659
|
+
for (const ref of input.remembered.refs ?? []) pushRef(ref);
|
|
5660
|
+
for (const ref of input.refs ?? []) pushRef(ref);
|
|
5661
|
+
const seen = /* @__PURE__ */ new Set();
|
|
5662
|
+
return refs.filter((ref) => {
|
|
5663
|
+
const key = `${ref.kind}:${ref.id}`;
|
|
5664
|
+
if (seen.has(key)) return false;
|
|
5665
|
+
seen.add(key);
|
|
5666
|
+
return true;
|
|
5667
|
+
});
|
|
5668
|
+
}
|
|
5669
|
+
function inferCampaignBuilderActiveWorkState(input) {
|
|
5670
|
+
if (input.blockers.length > 0) return "blocked";
|
|
5671
|
+
const status = activeWorkStatus(input.lastResult) ?? input.remembered.status;
|
|
5672
|
+
const normalized = status?.toLowerCase();
|
|
5673
|
+
if (normalized && ["completed", "complete", "succeeded", "success", "done"].includes(normalized)) return "completed";
|
|
5674
|
+
if (normalized && ["queued", "running", "in_progress", "processing", "pending"].includes(normalized)) return "queued_or_running";
|
|
5675
|
+
const dryRunComplete = input.lastResult.dry_run === true || input.lastResult.dryRun === true || normalized === "dry_run";
|
|
5676
|
+
if (dryRunComplete) return input.missingApprovals.length > 0 ? "needs_approval" : "dry_run_complete";
|
|
5677
|
+
if (input.missingApprovals.length > 0) return "needs_approval";
|
|
5678
|
+
if (input.readiness?.summary.ready === true) return "ready_for_dry_run";
|
|
5679
|
+
if (input.plan) return "planning";
|
|
5680
|
+
return "unknown";
|
|
5681
|
+
}
|
|
5682
|
+
function campaignBuilderActiveWorkApprovalBoundary(missingApprovals, state) {
|
|
5683
|
+
if (missingApprovals.length > 0) {
|
|
5684
|
+
return `Blocked before spend, provider writes, delivery, or launch until approval covers: ${uniqueStrings(missingApprovals).join(", ")}.`;
|
|
5685
|
+
}
|
|
5686
|
+
if (state === "dry_run_complete" || state === "ready_for_dry_run") {
|
|
5687
|
+
return "Read-only planning and dry-runs are allowed; spend, provider writes, sender loading, delivery, and launch still require explicit approval.";
|
|
5688
|
+
}
|
|
5689
|
+
return "This packet is read-only and does not authorize spend, provider writes, sender loading, delivery, or launch.";
|
|
5690
|
+
}
|
|
5691
|
+
function campaignBuilderActiveWorkNextAction(state, blockers, missingApprovals, refs) {
|
|
5692
|
+
if (blockers.length > 0) return `Resolve blocker: ${blockers[0]}`;
|
|
5693
|
+
if (missingApprovals.length > 0) return `Ask the operator to approve ${uniqueStrings(missingApprovals).join(", ")} before any write or spend action.`;
|
|
5694
|
+
if (state === "ready_for_dry_run") return "Run or inspect the read-only campaign dry-run, then return the receipt for approval review.";
|
|
5695
|
+
if (state === "dry_run_complete") return "Review the dry-run receipt and collect explicit launch or delivery approval before any write action.";
|
|
5696
|
+
if (state === "queued_or_running") return "Poll the remembered campaign build or provider job status; do not start a duplicate job.";
|
|
5697
|
+
if (state === "completed") return "Review final artifacts and delivery gates before export, sync, sender load, or launch.";
|
|
5698
|
+
if (refs.length > 0) return "Use the remembered refs to fetch current read-only status before asking the operator for IDs.";
|
|
5699
|
+
return "Create or refresh a campaign-builder plan before taking any spendful or write action.";
|
|
5700
|
+
}
|
|
5701
|
+
function campaignBuilderActiveWorkConversationStarters(input) {
|
|
5702
|
+
const starters = [];
|
|
5703
|
+
if (input.blockers.length > 0) {
|
|
5704
|
+
starters.push(
|
|
5705
|
+
`I found a blocker: ${input.blockers[0]}. Want me to stay in read-only diagnostics and prepare the fix path?`
|
|
5706
|
+
);
|
|
5707
|
+
}
|
|
5708
|
+
if (input.missingApprovals.length > 0) {
|
|
5709
|
+
starters.push(
|
|
5710
|
+
`You still owe approval for ${uniqueStrings(input.missingApprovals).join(", ")}. Want the exact approval packet before anything writes or spends?`
|
|
5711
|
+
);
|
|
5712
|
+
}
|
|
5713
|
+
if (input.state === "queued_or_running") {
|
|
5714
|
+
const buildRef = input.refs.find((ref) => ref.kind === "campaign_build");
|
|
5715
|
+
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.");
|
|
5716
|
+
}
|
|
5717
|
+
if (input.state === "dry_run_complete") {
|
|
5718
|
+
starters.push("The dry run is complete. Want me to summarize blockers, artifacts, and the approval handoff?");
|
|
5719
|
+
}
|
|
5720
|
+
if (input.state === "ready_for_dry_run") {
|
|
5721
|
+
starters.push("Everything is ready for a safe dry run. Want me to run the no-spend preview first?");
|
|
5722
|
+
}
|
|
5723
|
+
if (input.state === "completed") {
|
|
5724
|
+
starters.push("The build looks complete. Want me to review rows, artifacts, and delivery gates before export or send approval?");
|
|
5725
|
+
}
|
|
5726
|
+
starters.push(`Next safe action: ${input.nextSafeAction}`);
|
|
5727
|
+
return uniqueStrings(starters).slice(0, 4);
|
|
5728
|
+
}
|
|
5729
|
+
function createCampaignBuilderOpenAiAgentHandoff(input) {
|
|
5730
|
+
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.")) ?? [];
|
|
5731
|
+
const routeSetupActions = readOnlyPlanActions.filter(
|
|
5732
|
+
(action) => action.tool === "gtm_provider_recipe_prepare" || action.tool === "gtm_provider_route_activate"
|
|
5733
|
+
);
|
|
5734
|
+
const safeReadActions = uniqueCampaignBuilderActiveWorkActions([
|
|
5735
|
+
input.nextSafeMcpAction,
|
|
5736
|
+
...routeSetupActions,
|
|
5737
|
+
...readOnlyPlanActions
|
|
5738
|
+
]);
|
|
5739
|
+
const approvalGatedActions = uniqueCampaignBuilderActiveWorkActions([
|
|
5740
|
+
...input.approvalPacket.mcp_handoffs.filter((action) => action.approval_required || !action.read_only),
|
|
5741
|
+
...input.plan?.mcpFlow.filter((step) => step.approvalRequired || !step.readOnly).map((step) => campaignBuilderMcpStepToActiveWorkAction(step, "Approval-gated Signaliz MCP continuation for the saved campaign-agent plan.")) ?? []
|
|
5742
|
+
]);
|
|
5743
|
+
const approvalTypes = uniqueStrings([
|
|
5744
|
+
...input.missingApprovals,
|
|
5745
|
+
...input.approvalPacket.requested_approval_types
|
|
5746
|
+
]);
|
|
5747
|
+
return {
|
|
5748
|
+
packet_version: "campaign-builder-openai-agent-handoff.v1",
|
|
5749
|
+
surface: "openai_agents_sdk",
|
|
5750
|
+
agent: {
|
|
5751
|
+
name: "Signaliz GTM Campaign Agent",
|
|
5752
|
+
handoff_description: "Owns safe, conversational GTM campaign planning and continuation across Signaliz MCP, SDK, attachments, URLs, customer tools, approvals, and sender/export gates.",
|
|
5753
|
+
instructions: [
|
|
5754
|
+
"Be warm, direct, and expert-level GTM. Translate the current state into plain operator language before proposing work.",
|
|
5755
|
+
"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.",
|
|
5756
|
+
"Use attachment_summary, url_summary, and operator_notes as first-class planning evidence, while honoring the evidence privacy_boundary and withheld raw fields.",
|
|
5757
|
+
"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.",
|
|
5758
|
+
"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.",
|
|
5759
|
+
"When approval is missing, show the approval_packet and the exact missing approval scope before any side-effecting step."
|
|
5760
|
+
],
|
|
5761
|
+
output_contract: [
|
|
5762
|
+
"current_state: one concise sentence describing where the campaign work stands.",
|
|
5763
|
+
"evidence_used: attachment, URL, memory, route, or integration evidence used without exposing private raw rows or secrets.",
|
|
5764
|
+
"next_safe_mcp_action: the read-only Signaliz MCP action to run next, or null when none is safe.",
|
|
5765
|
+
"approval_boundary: the human approval scope required before spend, provider writes, delivery, export, sender load, or launch.",
|
|
5766
|
+
"operator_reply: conversational GTM guidance with blockers, risks, and the safest next move."
|
|
5767
|
+
]
|
|
5768
|
+
},
|
|
5769
|
+
context: {
|
|
5770
|
+
state: input.state,
|
|
5771
|
+
summary: input.summary,
|
|
5772
|
+
refs: input.refs,
|
|
5773
|
+
blockers: input.blockers,
|
|
5774
|
+
warnings: input.warnings,
|
|
5775
|
+
evidence_context: input.plan?.evidence ?? null,
|
|
5776
|
+
approval_packet: input.approvalPacket,
|
|
5777
|
+
approval_boundary: input.approvalBoundary,
|
|
5778
|
+
next_safe_action: input.nextSafeAction,
|
|
5779
|
+
conversation_starters: input.conversationStarters
|
|
5780
|
+
},
|
|
5781
|
+
tools: {
|
|
5782
|
+
mcp_server_label: "signaliz",
|
|
5783
|
+
remote_mcp_compatible: true,
|
|
5784
|
+
next_safe_mcp_action: input.nextSafeMcpAction,
|
|
5785
|
+
safe_read_tools: safeReadActions.map(
|
|
5786
|
+
(action) => campaignBuilderOpenAiAgentTool(action, "Safe read-only Signaliz MCP action available before approval.")
|
|
5787
|
+
),
|
|
5788
|
+
approval_gated_tools: approvalGatedActions.map(
|
|
5789
|
+
(action) => campaignBuilderOpenAiAgentTool(action, "Requires explicit human review before execution.")
|
|
5790
|
+
)
|
|
5791
|
+
},
|
|
5792
|
+
guardrails: {
|
|
5793
|
+
input: [
|
|
5794
|
+
"Reject or pause requests to expose raw private attachment text, raw rows, leads, emails, provider payloads, copy bodies, API keys, or secrets.",
|
|
5795
|
+
"Pause when the user asks to spend credits, write to a provider, export, load a sender, deliver, or launch without explicit approval scope."
|
|
5796
|
+
],
|
|
5797
|
+
tool: [
|
|
5798
|
+
"Read-only tools may run when they match safe_read_tools and their arguments match this packet.",
|
|
5799
|
+
"Any tool with approval_required=true or read_only=false requires human review and the approval_packet scope first."
|
|
5800
|
+
],
|
|
5801
|
+
human_review_required_for: approvalTypes,
|
|
5802
|
+
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."
|
|
5803
|
+
}
|
|
5804
|
+
};
|
|
5805
|
+
}
|
|
5806
|
+
function campaignBuilderOpenAiAgentTool(action, purpose) {
|
|
5807
|
+
return {
|
|
5808
|
+
id: action.id,
|
|
5809
|
+
type: "mcp",
|
|
5810
|
+
server_label: "signaliz",
|
|
5811
|
+
name: action.tool,
|
|
5812
|
+
arguments: action.arguments,
|
|
5813
|
+
read_only: action.read_only,
|
|
5814
|
+
approval_required: action.approval_required,
|
|
5815
|
+
purpose,
|
|
5816
|
+
safety: action.safety
|
|
5817
|
+
};
|
|
5818
|
+
}
|
|
5819
|
+
function uniqueCampaignBuilderActiveWorkActions(actions) {
|
|
5820
|
+
const seen = /* @__PURE__ */ new Set();
|
|
5821
|
+
const unique = [];
|
|
5822
|
+
for (const action of actions) {
|
|
5823
|
+
if (!action) continue;
|
|
5824
|
+
const key = `${action.id}:${action.tool}`;
|
|
5825
|
+
if (seen.has(key)) continue;
|
|
5826
|
+
seen.add(key);
|
|
5827
|
+
unique.push(action);
|
|
5828
|
+
}
|
|
5829
|
+
return unique;
|
|
5830
|
+
}
|
|
5831
|
+
function activeWorkStatus(record) {
|
|
5832
|
+
return stringValue(record.status ?? record.state ?? record.phase);
|
|
5833
|
+
}
|
|
4512
5834
|
function campaignBuilderBuiltInForRoute(route) {
|
|
4513
5835
|
return Object.entries(CAMPAIGN_BUILDER_BUILT_IN_ROUTE_IDS).find(([, routeId]) => route.id === routeId)?.[0];
|
|
4514
5836
|
}
|
|
@@ -7305,6 +8627,36 @@ function recordsFromParams(params) {
|
|
|
7305
8627
|
if (params.input) return { input: params.input };
|
|
7306
8628
|
return { input: {} };
|
|
7307
8629
|
}
|
|
8630
|
+
function toFusionConfig(params) {
|
|
8631
|
+
return {
|
|
8632
|
+
system_prompt: params.systemPrompt || params.system_prompt,
|
|
8633
|
+
user_template: params.userTemplate || params.user_template || params.prompt,
|
|
8634
|
+
preset: params.preset,
|
|
8635
|
+
temperature: params.temperature,
|
|
8636
|
+
max_tool_calls: params.maxToolCalls || params.max_tool_calls,
|
|
8637
|
+
max_tokens: params.maxTokens || params.max_tokens,
|
|
8638
|
+
timeout_ms: params.timeoutMs || params.timeout_ms,
|
|
8639
|
+
output_fields: params.outputFields || params.output_fields || [{ name: "response", type: "text", description: "Structured Fusion enrichment result" }]
|
|
8640
|
+
};
|
|
8641
|
+
}
|
|
8642
|
+
function toFusionSpendControls(params) {
|
|
8643
|
+
const controls = {};
|
|
8644
|
+
const dryRun = params.dryRun ?? params.dry_run;
|
|
8645
|
+
const confirmSpend = params.confirmSpend ?? params.confirm_spend;
|
|
8646
|
+
const maxCredits = params.maxCredits ?? params.max_credits;
|
|
8647
|
+
const maxCostUsd = params.maxCostUsd ?? params.max_cost_usd;
|
|
8648
|
+
if (dryRun !== void 0) controls.dry_run = dryRun;
|
|
8649
|
+
if (confirmSpend !== void 0) controls.confirm_spend = confirmSpend;
|
|
8650
|
+
if (maxCredits !== void 0) controls.max_credits = maxCredits;
|
|
8651
|
+
if (maxCostUsd !== void 0) controls.max_cost_usd = maxCostUsd;
|
|
8652
|
+
return controls;
|
|
8653
|
+
}
|
|
8654
|
+
function fusionRecordsFromParams(params) {
|
|
8655
|
+
const records = params.records || params.inputs;
|
|
8656
|
+
if (records?.length) return { records };
|
|
8657
|
+
if (params.input) return { input: params.input };
|
|
8658
|
+
return { input: {} };
|
|
8659
|
+
}
|
|
7308
8660
|
var Ai = class {
|
|
7309
8661
|
constructor(client) {
|
|
7310
8662
|
this.client = client;
|
|
@@ -7338,6 +8690,33 @@ var Ai = class {
|
|
|
7338
8690
|
raw: data
|
|
7339
8691
|
};
|
|
7340
8692
|
}
|
|
8693
|
+
/**
|
|
8694
|
+
* Plan or run experimental AI Enrichment Fusion with explicit spend controls.
|
|
8695
|
+
*/
|
|
8696
|
+
async fusion(params) {
|
|
8697
|
+
if (!params.prompt && !params.userTemplate && !params.user_template) {
|
|
8698
|
+
throw new Error("prompt or userTemplate is required.");
|
|
8699
|
+
}
|
|
8700
|
+
const data = await this.client.post("ai-enrichment-fusion", {
|
|
8701
|
+
...fusionRecordsFromParams(params),
|
|
8702
|
+
config: toFusionConfig(params),
|
|
8703
|
+
...toFusionSpendControls(params)
|
|
8704
|
+
});
|
|
8705
|
+
return {
|
|
8706
|
+
success: data.success ?? false,
|
|
8707
|
+
capability: data.capability ?? "ai_enrichment_fusion",
|
|
8708
|
+
displayName: data.display_name ?? "AI Enrichment Fusion",
|
|
8709
|
+
results: data.results ?? [],
|
|
8710
|
+
creditsUsed: data.total_credits_used ?? data.credits_used ?? 0,
|
|
8711
|
+
model: data.model,
|
|
8712
|
+
fusion: data.fusion,
|
|
8713
|
+
tokensUsed: data.tokens_used ?? 0,
|
|
8714
|
+
costUsd: data.cost_usd ?? 0,
|
|
8715
|
+
costSummary: data.cost_summary,
|
|
8716
|
+
billingMetadata: data.billing_metadata,
|
|
8717
|
+
raw: data
|
|
8718
|
+
};
|
|
8719
|
+
}
|
|
7341
8720
|
};
|
|
7342
8721
|
|
|
7343
8722
|
// src/resources/gtm-kernel.ts
|
|
@@ -7691,6 +9070,16 @@ var GtmKernel = class {
|
|
|
7691
9070
|
min_privacy_k: input.minPrivacyK
|
|
7692
9071
|
});
|
|
7693
9072
|
}
|
|
9073
|
+
/** Queue a dry-run-first bridge from imported historical feedback to attribution-only Campaign Build surrogates. */
|
|
9074
|
+
async runHistoricalCampaignBuildBridge(input = {}) {
|
|
9075
|
+
return this.callMcp("gtm_historical_campaign_build_bridge_run", {
|
|
9076
|
+
dry_run: input.dryRun,
|
|
9077
|
+
write_approved: input.writeApproved,
|
|
9078
|
+
max_events: input.maxEvents,
|
|
9079
|
+
max_campaigns: input.maxCampaigns,
|
|
9080
|
+
min_feedback_events: input.minFeedbackEvents
|
|
9081
|
+
});
|
|
9082
|
+
}
|
|
7694
9083
|
/** Prepare a provider-agnostic feedback webhook URL for Smartlead, HeyReach, Airbyte, or custom sender events. */
|
|
7695
9084
|
async prepareFeedbackWebhook(input) {
|
|
7696
9085
|
return this.callMcp("gtm_feedback_webhook_prepare", {
|
|
@@ -7867,6 +9256,24 @@ var GtmKernel = class {
|
|
|
7867
9256
|
limit: input.limit
|
|
7868
9257
|
});
|
|
7869
9258
|
}
|
|
9259
|
+
/** Predict booked-meeting likelihood for uploaded, inline, or MCP-sourced lead rows without persisting raw rows. */
|
|
9260
|
+
async predictMeetingLikelihood(input) {
|
|
9261
|
+
return this.callMcp("gtm_predict_meeting_likelihood", {
|
|
9262
|
+
lead_rows: input.leadRows,
|
|
9263
|
+
input_source: input.inputSource,
|
|
9264
|
+
campaign_id: input.campaignId,
|
|
9265
|
+
campaign_build_id: input.campaignBuildId,
|
|
9266
|
+
days: input.days,
|
|
9267
|
+
feedback_limit: input.feedbackLimit,
|
|
9268
|
+
include_features: input.includeFeatures,
|
|
9269
|
+
include_global: input.includeGlobal,
|
|
9270
|
+
min_feedback_events: input.minFeedbackEvents,
|
|
9271
|
+
min_historical_feature_sample_size: input.minHistoricalFeatureSampleSize,
|
|
9272
|
+
min_workspace_count: input.minWorkspaceCount,
|
|
9273
|
+
min_privacy_k: input.minPrivacyK,
|
|
9274
|
+
limit: input.limit
|
|
9275
|
+
});
|
|
9276
|
+
}
|
|
7870
9277
|
/** Rank provider-chain, ICP, source, copy, and sequence failure patterns without writing raw lead data. */
|
|
7871
9278
|
async failurePatterns(options = {}) {
|
|
7872
9279
|
return this.callMcp("gtm_brain_failure_patterns", {
|
|
@@ -8482,6 +9889,70 @@ function compact2(value) {
|
|
|
8482
9889
|
return out;
|
|
8483
9890
|
}
|
|
8484
9891
|
|
|
9892
|
+
// src/resources/public-ground-truth.ts
|
|
9893
|
+
var PublicGroundTruth = class {
|
|
9894
|
+
constructor(client) {
|
|
9895
|
+
this.client = client;
|
|
9896
|
+
}
|
|
9897
|
+
/**
|
|
9898
|
+
* Search the public-ground-truth cache by company/name/domain/native ID,
|
|
9899
|
+
* or by plain-language industry + location.
|
|
9900
|
+
* Results use the same snake_case wire shape returned by the hosted MCP API.
|
|
9901
|
+
*/
|
|
9902
|
+
async search(params) {
|
|
9903
|
+
return this.client.mcp("tools/call", {
|
|
9904
|
+
name: "search_public_ground_truth",
|
|
9905
|
+
arguments: {
|
|
9906
|
+
query: params.query ?? params.search,
|
|
9907
|
+
industry: params.industry,
|
|
9908
|
+
location: params.location,
|
|
9909
|
+
source_id: params.sourceId ?? params.source_id,
|
|
9910
|
+
entity_type: params.entityType ?? params.entity_type,
|
|
9911
|
+
native_id: params.nativeId ?? params.native_id,
|
|
9912
|
+
entity_name: params.entityName ?? params.entity_name,
|
|
9913
|
+
domain: params.domain,
|
|
9914
|
+
website_url: params.websiteUrl ?? params.website_url,
|
|
9915
|
+
phone: params.phone,
|
|
9916
|
+
email: params.email,
|
|
9917
|
+
city: params.city,
|
|
9918
|
+
state: params.state,
|
|
9919
|
+
postal_code: params.postalCode ?? params.postal_code,
|
|
9920
|
+
country: params.country,
|
|
9921
|
+
source_url: params.sourceUrl ?? params.source_url,
|
|
9922
|
+
join_keys: params.joinKeys ?? params.join_keys,
|
|
9923
|
+
row_data: params.rowData ?? params.row_data,
|
|
9924
|
+
naics: params.naics,
|
|
9925
|
+
industry_code: params.industryCode ?? params.industry_code,
|
|
9926
|
+
industry_type: params.industryType ?? params.industry_type,
|
|
9927
|
+
year: params.year,
|
|
9928
|
+
quarter: params.quarter,
|
|
9929
|
+
area_fips: params.areaFips ?? params.area_fips,
|
|
9930
|
+
geo_id: params.geoId ?? params.geo_id,
|
|
9931
|
+
own_code: params.ownCode ?? params.own_code,
|
|
9932
|
+
source_updated_after: params.sourceUpdatedAfter ?? params.source_updated_after,
|
|
9933
|
+
source_updated_before: params.sourceUpdatedBefore ?? params.source_updated_before,
|
|
9934
|
+
observed_after: params.observedAfter ?? params.observed_after,
|
|
9935
|
+
observed_before: params.observedBefore ?? params.observed_before,
|
|
9936
|
+
limit: params.limit,
|
|
9937
|
+
offset: params.offset
|
|
9938
|
+
}
|
|
9939
|
+
});
|
|
9940
|
+
}
|
|
9941
|
+
/**
|
|
9942
|
+
* List available public-ground-truth cache sources and their join-key metadata.
|
|
9943
|
+
*/
|
|
9944
|
+
async listSources(params = {}) {
|
|
9945
|
+
return this.client.mcp("tools/call", {
|
|
9946
|
+
name: "list_public_ground_truth_sources",
|
|
9947
|
+
arguments: {
|
|
9948
|
+
query: params.query ?? params.search,
|
|
9949
|
+
status: params.status,
|
|
9950
|
+
limit: params.limit
|
|
9951
|
+
}
|
|
9952
|
+
});
|
|
9953
|
+
}
|
|
9954
|
+
};
|
|
9955
|
+
|
|
8485
9956
|
// src/index.ts
|
|
8486
9957
|
var MCP_TOOL_CACHE_TTL_MS = 3e4;
|
|
8487
9958
|
function inferMcpToolCategory(toolName) {
|
|
@@ -8524,6 +9995,7 @@ function inferMcpToolCategory(toolName) {
|
|
|
8524
9995
|
}
|
|
8525
9996
|
if (toolName.includes("icp")) return "icp";
|
|
8526
9997
|
if (toolName.startsWith("ai_clean_")) return "data_cleaning";
|
|
9998
|
+
if (toolName.includes("public_ground_truth")) return "public_data";
|
|
8527
9999
|
if (toolName.includes("system") || toolName.includes("workflow")) return "automation";
|
|
8528
10000
|
if (toolName.includes("agent") || toolName.includes("platform_health") || toolName === "discover_capabilities") return "observability";
|
|
8529
10001
|
return void 0;
|
|
@@ -8575,6 +10047,7 @@ var Signaliz = class {
|
|
|
8575
10047
|
this.ops = new Ops(this.client);
|
|
8576
10048
|
this.ai = new Ai(this.client);
|
|
8577
10049
|
this.gtm = new GtmKernel(this.client);
|
|
10050
|
+
this.publicGroundTruth = new PublicGroundTruth(this.client);
|
|
8578
10051
|
}
|
|
8579
10052
|
/** Get current workspace info including credits */
|
|
8580
10053
|
async getWorkspace() {
|
|
@@ -8681,10 +10154,12 @@ var Signaliz = class {
|
|
|
8681
10154
|
GtmKernel,
|
|
8682
10155
|
Icps,
|
|
8683
10156
|
Ops,
|
|
10157
|
+
PublicGroundTruth,
|
|
8684
10158
|
Signaliz,
|
|
8685
10159
|
SignalizError,
|
|
8686
10160
|
applyCampaignBuilderStrategyTemplate,
|
|
8687
10161
|
collectExecutionReferences,
|
|
10162
|
+
createCampaignBuilderActiveWorkContext,
|
|
8688
10163
|
createCampaignBuilderAgentPlan,
|
|
8689
10164
|
createCampaignBuilderAgentRequestTemplate,
|
|
8690
10165
|
createCampaignBuilderApproval,
|