@signaliz/sdk 1.0.18 → 1.0.20
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 -0
- package/dist/{chunk-VFBQCWOM.mjs → chunk-PBJFIO72.mjs} +905 -21
- package/dist/cli.js +1161 -22
- package/dist/cli.mjs +248 -1
- package/dist/index.d.mts +555 -4
- package/dist/index.d.ts +555 -4
- package/dist/index.js +907 -21
- package/dist/index.mjs +5 -1
- package/dist/mcp-config.js +903 -21
- package/dist/mcp-config.mjs +1 -1
- package/package.json +2 -2
|
@@ -448,6 +448,38 @@ var Signals = class {
|
|
|
448
448
|
constructor(client) {
|
|
449
449
|
this.client = client;
|
|
450
450
|
}
|
|
451
|
+
/** Turn the strongest supported company signal into three complete, evidence-backed emails. */
|
|
452
|
+
async signalToCopy(params) {
|
|
453
|
+
const data = await this.client.post("api/v1/signal-to-copy", {
|
|
454
|
+
company_domain: params.companyDomain,
|
|
455
|
+
person_name: params.personName,
|
|
456
|
+
title: params.title,
|
|
457
|
+
campaign_offer: params.campaignOffer,
|
|
458
|
+
research_prompt: params.researchPrompt
|
|
459
|
+
});
|
|
460
|
+
return {
|
|
461
|
+
success: data.success ?? true,
|
|
462
|
+
strongestSignal: data.strongest_signal ?? "",
|
|
463
|
+
whyNow: data.why_now ?? "",
|
|
464
|
+
subjectLine: data.subject_line ?? "",
|
|
465
|
+
openingLine: data.opening_line ?? "",
|
|
466
|
+
confidence: data.confidence ?? 0,
|
|
467
|
+
evidenceUrl: data.evidence_url ?? "",
|
|
468
|
+
researchPrompt: data.research_prompt,
|
|
469
|
+
variations: (data.variations ?? []).map((v) => ({
|
|
470
|
+
style: v.style,
|
|
471
|
+
subjectLine: v.subject_line ?? "",
|
|
472
|
+
openingLine: v.opening_line ?? "",
|
|
473
|
+
cta: v.cta ?? "",
|
|
474
|
+
prediction: v.prediction,
|
|
475
|
+
email: v.email
|
|
476
|
+
}))
|
|
477
|
+
};
|
|
478
|
+
}
|
|
479
|
+
/** @deprecated Use signalToCopy. Retained for compatibility. */
|
|
480
|
+
async personalize(params) {
|
|
481
|
+
return this.signalToCopy(params);
|
|
482
|
+
}
|
|
451
483
|
/** Enrich a company with actionable signals (V1) */
|
|
452
484
|
async enrich(params) {
|
|
453
485
|
const args = {
|
|
@@ -456,6 +488,9 @@ var Signals = class {
|
|
|
456
488
|
if (params.domain) args.domain = params.domain;
|
|
457
489
|
if (params.researchPrompt) args.research_prompt = params.researchPrompt;
|
|
458
490
|
if (params.signalTypes) args.signal_types = params.signalTypes;
|
|
491
|
+
if (params.targetSignalCount) args.target_signal_count = params.targetSignalCount;
|
|
492
|
+
if (params.lookbackDays) args.lookback_days = params.lookbackDays;
|
|
493
|
+
if (params.enableDeepSearch !== void 0) args.enable_deep_search = params.enableDeepSearch;
|
|
459
494
|
const data = await this.client.mcp("tools/call", {
|
|
460
495
|
name: "enrich_company_signals",
|
|
461
496
|
arguments: args
|
|
@@ -465,6 +500,16 @@ var Signals = class {
|
|
|
465
500
|
signals: (data.signals ?? []).map((s) => ({
|
|
466
501
|
title: s.title,
|
|
467
502
|
signalType: s.signal_type,
|
|
503
|
+
sourceType: s.source_type ?? s.signal_classification?.label ?? "unknown",
|
|
504
|
+
sourceProvenance: s.source_provenance ?? s.metadata?.source_provenance ?? null,
|
|
505
|
+
signalFamily: s.signal_family ?? s.signal_type ?? null,
|
|
506
|
+
signalEventType: s.signal_event_type ?? s.signal_classification?.slug ?? null,
|
|
507
|
+
signalEventLabel: s.signal_event_label ?? s.signal_classification?.label ?? null,
|
|
508
|
+
signalClassification: s.signal_classification ? {
|
|
509
|
+
label: s.signal_classification.label,
|
|
510
|
+
slug: s.signal_classification.slug,
|
|
511
|
+
rationale: s.signal_classification.rationale
|
|
512
|
+
} : null,
|
|
468
513
|
confidenceScore: s.confidence_score ?? 0,
|
|
469
514
|
detectedAt: s.detected_at ?? "",
|
|
470
515
|
url: s.url,
|
|
@@ -505,8 +550,17 @@ var Signals = class {
|
|
|
505
550
|
content: s.content ?? "",
|
|
506
551
|
date: s.date ?? null,
|
|
507
552
|
sourceUrl: s.source_url ?? null,
|
|
508
|
-
sourceType: s.source_type ?? "unknown",
|
|
509
|
-
|
|
553
|
+
sourceType: s.source_type ?? s.signal_classification?.label ?? "unknown",
|
|
554
|
+
sourceProvenance: s.source_provenance ?? s.metadata?.source_provenance ?? null,
|
|
555
|
+
signalFamily: s.signal_family ?? s.type ?? null,
|
|
556
|
+
signalEventType: s.signal_event_type ?? s.signal_classification?.slug ?? null,
|
|
557
|
+
signalEventLabel: s.signal_event_label ?? s.signal_classification?.label ?? null,
|
|
558
|
+
confidence: s.confidence ?? null,
|
|
559
|
+
signalClassification: s.signal_classification ? {
|
|
560
|
+
label: s.signal_classification.label,
|
|
561
|
+
slug: s.signal_classification.slug,
|
|
562
|
+
rationale: s.signal_classification.rationale
|
|
563
|
+
} : null
|
|
510
564
|
})),
|
|
511
565
|
signalCount: data.signal_count ?? 0,
|
|
512
566
|
intelligence: data.intelligence ? {
|
|
@@ -549,6 +603,58 @@ var Signals = class {
|
|
|
549
603
|
}
|
|
550
604
|
};
|
|
551
605
|
}
|
|
606
|
+
/** Plan or run experimental Signal Fusion with explicit spend controls. */
|
|
607
|
+
async fusion(params) {
|
|
608
|
+
const args = {};
|
|
609
|
+
if (params.companyName) args.company_name = params.companyName;
|
|
610
|
+
if (params.domain) args.domain = params.domain;
|
|
611
|
+
if (params.companyDomain) args.company_domain = params.companyDomain;
|
|
612
|
+
if (params.linkedinUrl) args.linkedin_url = params.linkedinUrl;
|
|
613
|
+
if (params.companies) args.companies = params.companies;
|
|
614
|
+
if (params.preset) args.preset = params.preset;
|
|
615
|
+
if (params.researchPrompt) args.research_prompt = params.researchPrompt;
|
|
616
|
+
if (params.signalTypes) args.signal_types = params.signalTypes;
|
|
617
|
+
if (params.lookbackDays) args.lookback_days = params.lookbackDays;
|
|
618
|
+
if (params.targetSignalCount) args.target_signal_count = params.targetSignalCount;
|
|
619
|
+
if (params.maxToolCalls) args.max_tool_calls = params.maxToolCalls;
|
|
620
|
+
if (params.maxTokens) args.max_tokens = params.maxTokens;
|
|
621
|
+
if (params.timeoutMs) args.timeout_ms = params.timeoutMs;
|
|
622
|
+
const dryRun = params.dryRun ?? params.dry_run;
|
|
623
|
+
const confirmSpend = params.confirmSpend ?? params.confirm_spend;
|
|
624
|
+
const maxCredits = params.maxCredits ?? params.max_credits;
|
|
625
|
+
const maxCostUsd = params.maxCostUsd ?? params.max_cost_usd;
|
|
626
|
+
if (dryRun !== void 0) args.dry_run = dryRun;
|
|
627
|
+
if (confirmSpend !== void 0) args.confirm_spend = confirmSpend;
|
|
628
|
+
if (maxCredits !== void 0) args.max_credits = maxCredits;
|
|
629
|
+
if (maxCostUsd !== void 0) args.max_cost_usd = maxCostUsd;
|
|
630
|
+
const data = await this.client.post("signal-fusion", args);
|
|
631
|
+
return {
|
|
632
|
+
success: data.success ?? false,
|
|
633
|
+
capability: data.capability ?? "signal_fusion",
|
|
634
|
+
displayName: data.display_name ?? "Signal Fusion",
|
|
635
|
+
company: data.company,
|
|
636
|
+
signals: (data.signals ?? []).map((s) => ({
|
|
637
|
+
id: s.id,
|
|
638
|
+
title: s.title,
|
|
639
|
+
type: s.type,
|
|
640
|
+
content: s.content ?? "",
|
|
641
|
+
date: s.date ?? null,
|
|
642
|
+
sourceUrl: s.source_url ?? null,
|
|
643
|
+
sourceType: s.source_type ?? "unknown",
|
|
644
|
+
confidence: s.confidence ?? null
|
|
645
|
+
})),
|
|
646
|
+
signalCount: data.signal_count ?? data.signals?.length ?? 0,
|
|
647
|
+
results: data.results ?? [],
|
|
648
|
+
model: data.model,
|
|
649
|
+
fusion: data.fusion,
|
|
650
|
+
costUsd: data.cost_usd ?? 0,
|
|
651
|
+
tokensUsed: data.tokens_used ?? 0,
|
|
652
|
+
costSummary: data.cost_summary,
|
|
653
|
+
creditsUsed: data.total_credits_used ?? data.credits_used ?? 0,
|
|
654
|
+
billingMetadata: data.billing_metadata,
|
|
655
|
+
raw: data
|
|
656
|
+
};
|
|
657
|
+
}
|
|
552
658
|
};
|
|
553
659
|
|
|
554
660
|
// src/resources/systems.ts
|
|
@@ -987,6 +1093,7 @@ function mapCustomerRowCounts(value) {
|
|
|
987
1093
|
acceptedRows: numberOrNull(record.accepted_rows) ?? void 0,
|
|
988
1094
|
usableRows: numberOrNull(record.usable_rows) ?? void 0,
|
|
989
1095
|
copiedRows: numberOrNull(record.copied_rows) ?? void 0,
|
|
1096
|
+
copySkippedRows: numberOrNull(record.copy_skipped_rows) ?? void 0,
|
|
990
1097
|
approvalReadyRows: numberOrNull(record.approval_ready_rows) ?? void 0,
|
|
991
1098
|
qaReadyRows: numberOrNull(record.qa_ready_rows) ?? void 0,
|
|
992
1099
|
deliveredRows: numberOrNull(record.delivered_rows) ?? void 0,
|
|
@@ -1223,7 +1330,8 @@ function buildArgs(request) {
|
|
|
1223
1330
|
geographies: request.icp.geographies,
|
|
1224
1331
|
keywords: request.icp.keywords,
|
|
1225
1332
|
exclusions: request.icp.exclusions,
|
|
1226
|
-
require_verified_email: request.icp.requireVerifiedEmail
|
|
1333
|
+
require_verified_email: request.icp.requireVerifiedEmail,
|
|
1334
|
+
persona_expansion_mode: request.icp.personaExpansionMode
|
|
1227
1335
|
};
|
|
1228
1336
|
}
|
|
1229
1337
|
if (request.policy) {
|
|
@@ -1263,6 +1371,7 @@ function buildArgs(request) {
|
|
|
1263
1371
|
} : void 0,
|
|
1264
1372
|
sequence_steps: request.copy.sequenceSteps,
|
|
1265
1373
|
copy_schema: request.copy.copySchema,
|
|
1374
|
+
evidence_mode: request.copy.evidenceMode,
|
|
1266
1375
|
banned_phrases: request.copy.bannedPhrases,
|
|
1267
1376
|
approval_required: request.copy.approvalRequired,
|
|
1268
1377
|
quality_tier: request.copy.qualityTier
|
|
@@ -1319,7 +1428,8 @@ var DEFAULT_SIGNALIZ_CAMPAIGN_BUILDER_DEFAULTS = {
|
|
|
1319
1428
|
copy: {
|
|
1320
1429
|
enabled: true,
|
|
1321
1430
|
tone: "direct",
|
|
1322
|
-
maxBodyWords: 125
|
|
1431
|
+
maxBodyWords: 125,
|
|
1432
|
+
evidenceMode: "signal_led"
|
|
1323
1433
|
},
|
|
1324
1434
|
delivery: {
|
|
1325
1435
|
enabled: true,
|
|
@@ -1376,7 +1486,8 @@ var CAMPAIGN_BUILDER_OPERATING_PLAYBOOKS = [
|
|
|
1376
1486
|
"Block export when required identity, company, or email fields are missing."
|
|
1377
1487
|
],
|
|
1378
1488
|
activationBoundary: "Cache inventory is read-only. Fresh sourcing, cache writes, export, and sender loading require explicit approval.",
|
|
1379
|
-
memoryKeywords: ["cache inventory", "large list", "unique emails", "top-up sourcing", "source metadata"]
|
|
1489
|
+
memoryKeywords: ["cache inventory", "large list", "unique emails", "top-up sourcing", "source metadata"],
|
|
1490
|
+
knowledgeSources: ["data-ops/contact-data-lifecycle", "data-ops/credit-optimization-guide", "gtm/data-quality-ops", "gtm/lead-generation-strategies"]
|
|
1380
1491
|
},
|
|
1381
1492
|
{
|
|
1382
1493
|
slug: "net-new-suppressed-list",
|
|
@@ -1401,7 +1512,8 @@ var CAMPAIGN_BUILDER_OPERATING_PLAYBOOKS = [
|
|
|
1401
1512
|
"Do not describe rows as fully qualified when the approved path only proves net-new email status."
|
|
1402
1513
|
],
|
|
1403
1514
|
activationBoundary: "Suppression review must pass before export, upload, CRM sync, sender load, or sequence launch.",
|
|
1404
|
-
memoryKeywords: ["suppression", "net-new", "prior email overlap", "domain review", "provenance-rich QA"]
|
|
1515
|
+
memoryKeywords: ["suppression", "net-new", "prior email overlap", "domain review", "provenance-rich QA"],
|
|
1516
|
+
knowledgeSources: ["gtm/data-quality-ops", "data-ops/contact-data-lifecycle", "gtm/outbound-sequencing"]
|
|
1405
1517
|
},
|
|
1406
1518
|
{
|
|
1407
1519
|
slug: "proof-first-vertical-gate",
|
|
@@ -1426,7 +1538,8 @@ var CAMPAIGN_BUILDER_OPERATING_PLAYBOOKS = [
|
|
|
1426
1538
|
"Contact fit should meet the configured threshold before email finding or copy generation."
|
|
1427
1539
|
],
|
|
1428
1540
|
activationBoundary: "Proof gates are required before contact spend, copy, export, or external writes.",
|
|
1429
|
-
memoryKeywords: ["proof gate", "vertical exclusion", "company before contact", "pass review fail", "fit threshold"]
|
|
1541
|
+
memoryKeywords: ["proof gate", "vertical exclusion", "company before contact", "pass review fail", "fit threshold"],
|
|
1542
|
+
knowledgeSources: ["gtm/icp-design-framework", "gtm/strategy/scoring.yaml", "gtm/advanced/account-prioritization-frameworks", "gtm/advanced/predictive-lead-scoring", "gtm/verticals"]
|
|
1430
1543
|
},
|
|
1431
1544
|
{
|
|
1432
1545
|
slug: "signal-led-copy-approval",
|
|
@@ -1451,7 +1564,8 @@ var CAMPAIGN_BUILDER_OPERATING_PLAYBOOKS = [
|
|
|
1451
1564
|
"Destination fields must remain blocked until approval metadata is present."
|
|
1452
1565
|
],
|
|
1453
1566
|
activationBoundary: "Copy readiness is not delivery approval. Export, sync, sender load, and launch require a separate human-approved gate.",
|
|
1454
|
-
memoryKeywords: ["company signals", "evidence-fed copy", "why now", "copy blocker", "approval gate"]
|
|
1567
|
+
memoryKeywords: ["company signals", "evidence-fed copy", "why now", "copy blocker", "approval gate"],
|
|
1568
|
+
knowledgeSources: ["gtm/email-personalization", "gtm/signal-based-selling", "gtm/signal-combination-matrix", "gtm/advanced/buyer-journey-mapping"]
|
|
1455
1569
|
},
|
|
1456
1570
|
{
|
|
1457
1571
|
slug: "domain-first-recovery",
|
|
@@ -1476,7 +1590,8 @@ var CAMPAIGN_BUILDER_OPERATING_PLAYBOOKS = [
|
|
|
1476
1590
|
"Target count means final held rows, not raw sourced rows."
|
|
1477
1591
|
],
|
|
1478
1592
|
activationBoundary: "Domain recovery informs sourcing. Contact enrichment, paid qualification, and export still require approved gates.",
|
|
1479
|
-
memoryKeywords: ["domain-first", "yield modeling", "attrition", "accepted domains", "gap fill"]
|
|
1593
|
+
memoryKeywords: ["domain-first", "yield modeling", "attrition", "accepted domains", "gap fill"],
|
|
1594
|
+
knowledgeSources: ["gtm/lead-generation-strategies", "data-ops/enrichment-waterfall-strategy", "data-ops/credit-optimization-guide", "gtm/territory-account-planning"]
|
|
1480
1595
|
},
|
|
1481
1596
|
{
|
|
1482
1597
|
slug: "table-workflow-handoff",
|
|
@@ -1501,7 +1616,112 @@ var CAMPAIGN_BUILDER_OPERATING_PLAYBOOKS = [
|
|
|
1501
1616
|
"Provider route activation must dry-run before any external write."
|
|
1502
1617
|
],
|
|
1503
1618
|
activationBoundary: "MCP, webhook, managed integration, and destination routes remain dry-run until the reviewed route and campaign are approved.",
|
|
1504
|
-
memoryKeywords: ["table workflow", "request ready", "provider status", "export blocker", "BYO integration"]
|
|
1619
|
+
memoryKeywords: ["table workflow", "request ready", "provider status", "export blocker", "BYO integration"],
|
|
1620
|
+
knowledgeSources: ["gtm/multi-channel-orchestration", "data-ops/enrichment-waterfall-strategy", "recipes/clay-gtm-webhook-recipe", "systems/blueprints/multi-channel-orchestration"]
|
|
1621
|
+
},
|
|
1622
|
+
{
|
|
1623
|
+
slug: "icp-persona-segmentation",
|
|
1624
|
+
label: "ICP And Persona Segmentation",
|
|
1625
|
+
whenToUse: [
|
|
1626
|
+
"The brief has a broad market, multiple personas, or unclear buying committee.",
|
|
1627
|
+
"The campaign should rank account tiers, persona fit, vertical nuance, and exclusions before sourcing at scale."
|
|
1628
|
+
],
|
|
1629
|
+
sequence: [
|
|
1630
|
+
"Convert the brief into account tiers, persona roles, buying committee influence, and explicit exclusions.",
|
|
1631
|
+
"Choose vertical guidance only from the customer-safe GTM library and keep internal platform docs out of prompts.",
|
|
1632
|
+
"Score accounts before contacts, then score contacts against persona, seniority, function, geography, and intent fit.",
|
|
1633
|
+
"Return segment counts and review buckets before spend, copy, export, or launch."
|
|
1634
|
+
],
|
|
1635
|
+
requiredFields: {
|
|
1636
|
+
segment: ["segment_name", "tier", "persona_priority", "buying_committee_role", "fit_reason", "exclusion_reason"],
|
|
1637
|
+
scoring: ["account_fit_score", "persona_fit_score", "segment_confidence", "review_bucket"]
|
|
1638
|
+
},
|
|
1639
|
+
qualityGates: [
|
|
1640
|
+
"Do not treat adjacent personas or verticals as matches unless the brief allows them.",
|
|
1641
|
+
"Keep ICP, persona, and exclusion evidence visible in the proof packet.",
|
|
1642
|
+
"Low-confidence segments route to review before contact discovery or copy."
|
|
1643
|
+
],
|
|
1644
|
+
activationBoundary: "Segmentation is planning guidance. Paid sourcing, enrichment, export, and launch require the normal approval gates.",
|
|
1645
|
+
memoryKeywords: ["ICP design", "persona segmentation", "buying committee", "account tiers", "fit scoring", "vertical nuance"],
|
|
1646
|
+
knowledgeSources: ["gtm/icp-design-framework", "gtm/personas/sdr.yaml", "gtm/personas/ae.yaml", "gtm/personas/cro.yaml", "gtm/personas/revops.yaml", "gtm/advanced/account-prioritization-frameworks", "gtm/verticals"]
|
|
1647
|
+
},
|
|
1648
|
+
{
|
|
1649
|
+
slug: "buying-signal-prioritization",
|
|
1650
|
+
label: "Buying Signal Prioritization",
|
|
1651
|
+
whenToUse: [
|
|
1652
|
+
"The campaign depends on timing, intent, trigger events, or account prioritization.",
|
|
1653
|
+
"The operator wants why-now proof instead of generic list generation."
|
|
1654
|
+
],
|
|
1655
|
+
sequence: [
|
|
1656
|
+
"Map the campaign goal to signal families, trigger freshness, and buyer-journey stage.",
|
|
1657
|
+
"Rank signals by relevance, recency, source quality, and persona-specific actionability.",
|
|
1658
|
+
"Attach evidence URLs or evidence summaries without exposing private memory rows.",
|
|
1659
|
+
"Use signal strength to decide source order, copy angle, and review priority."
|
|
1660
|
+
],
|
|
1661
|
+
requiredFields: {
|
|
1662
|
+
signal: ["signal_type", "signal_date", "signal_source", "why_now", "signal_confidence", "buyer_stage"],
|
|
1663
|
+
prioritization: ["priority_score", "priority_reason", "next_best_action", "review_reason"]
|
|
1664
|
+
},
|
|
1665
|
+
qualityGates: [
|
|
1666
|
+
"Do not use stale, unsupported, or weak signals as personalization proof.",
|
|
1667
|
+
"Signal fit cannot override hard ICP, geography, suppression, or verified-email gates.",
|
|
1668
|
+
"Rows with uncertain why-now evidence must stay review-only."
|
|
1669
|
+
],
|
|
1670
|
+
activationBoundary: "Signal ranking can prioritize review and copy. It does not approve outreach, sender loading, exports, or sends.",
|
|
1671
|
+
memoryKeywords: ["buying signals", "intent data", "funding trigger", "new executive", "tech adoption", "buyer journey", "why now"],
|
|
1672
|
+
knowledgeSources: ["gtm/signal-based-selling", "gtm/signal-combination-matrix", "gtm/advanced/intent-data-strategies", "gtm/advanced/buyer-journey-mapping", "gtm/signals/funding-round", "gtm/signals/new-executive", "gtm/signals/tech-adoption", "recipes/funding-trigger-outreach", "recipes/new-hire-outreach"]
|
|
1673
|
+
},
|
|
1674
|
+
{
|
|
1675
|
+
slug: "multi-channel-sequence-fit",
|
|
1676
|
+
label: "Multi-Channel Sequence Fit",
|
|
1677
|
+
whenToUse: [
|
|
1678
|
+
"The campaign needs email, LinkedIn, call, webhook, CRM, or sequencer coordination.",
|
|
1679
|
+
"Copy and delivery should adapt by persona, channel, deliverability risk, and proof strength."
|
|
1680
|
+
],
|
|
1681
|
+
sequence: [
|
|
1682
|
+
"Choose channel mix from persona, deal motion, evidence strength, deliverability constraints, and connected destination readiness.",
|
|
1683
|
+
"Draft sequence logic with email, LinkedIn, call, and task handoffs only where supported by the approved destination.",
|
|
1684
|
+
"Keep copy concise, proof-backed, channel-specific, and reviewable before delivery.",
|
|
1685
|
+
"Run deliverability and destination readiness checks before sender load or launch approval."
|
|
1686
|
+
],
|
|
1687
|
+
requiredFields: {
|
|
1688
|
+
channel: ["channel", "touch_number", "persona_context", "message_angle", "channel_blocker", "approval_status"],
|
|
1689
|
+
deliverability: ["verified_email", "domain_risk", "send_window", "unsubscribe_risk", "sender_ready"]
|
|
1690
|
+
},
|
|
1691
|
+
qualityGates: [
|
|
1692
|
+
"Email copy must be row-supported and under the configured campaign tone/length limits.",
|
|
1693
|
+
"LinkedIn, phone, CRM, webhook, and sequencer actions remain destination-locked until approved.",
|
|
1694
|
+
"Deliverability risk or missing sender readiness blocks launch even when rows are qualified."
|
|
1695
|
+
],
|
|
1696
|
+
activationBoundary: "Sequence strategy is draft-only. External writes, sender loading, launch, and sending need separate explicit approval.",
|
|
1697
|
+
memoryKeywords: ["outbound sequencing", "email personalization", "LinkedIn outreach", "cold calling", "multi-channel orchestration", "deliverability"],
|
|
1698
|
+
knowledgeSources: ["gtm/outbound-sequencing", "gtm/email-personalization", "gtm/linkedin-outreach-strategies", "gtm/cold-calling-frameworks", "gtm/multi-channel-orchestration", "gtm/advanced/email-deliverability", "systems/blueprints/multi-channel-orchestration"]
|
|
1699
|
+
},
|
|
1700
|
+
{
|
|
1701
|
+
slug: "revops-feedback-loop",
|
|
1702
|
+
label: "RevOps Feedback Loop",
|
|
1703
|
+
whenToUse: [
|
|
1704
|
+
"The campaign should improve from replies, meetings, delivery results, CRM outcomes, or operator QA.",
|
|
1705
|
+
"The operator needs post-build monitoring, governance, or continuous ops follow-up."
|
|
1706
|
+
],
|
|
1707
|
+
sequence: [
|
|
1708
|
+
"Define success metrics, guardrails, and feedback sources before launch.",
|
|
1709
|
+
"Collect aggregate outcomes, QA blockers, delivery health, and operator edits after each campaign phase.",
|
|
1710
|
+
"Separate workspace-private evidence from public-safe learnings and Brain defaults.",
|
|
1711
|
+
"Feed approved aggregate learnings back into future sourcing, qualification, copy, and suppression rules."
|
|
1712
|
+
],
|
|
1713
|
+
requiredFields: {
|
|
1714
|
+
feedback: ["source", "event_type", "metric", "sample_size", "confidence", "learning_candidate"],
|
|
1715
|
+
governance: ["approval_owner", "last_reviewed_at", "risk_flag", "next_review_action"]
|
|
1716
|
+
},
|
|
1717
|
+
qualityGates: [
|
|
1718
|
+
"Do not write memory or Brain learnings from raw replies, private labels, or provider payloads without approved redaction.",
|
|
1719
|
+
"Use holdouts or pre/post comparisons before claiming causal lift.",
|
|
1720
|
+
"Delivery, suppression, and opt-out signals must update future gates before scale-up."
|
|
1721
|
+
],
|
|
1722
|
+
activationBoundary: "Feedback review is read-only until memory writes, Brain writes, CRM updates, or campaign changes are explicitly approved.",
|
|
1723
|
+
memoryKeywords: ["RevOps", "feedback loop", "campaign learning", "reply outcomes", "sales marketing alignment", "data hygiene", "holdout"],
|
|
1724
|
+
knowledgeSources: ["gtm/revenue-operations", "gtm/advanced/sales-marketing-alignment", "gtm/advanced/predictive-lead-scoring", "gtm/data-quality-ops", "data-ops/contact-data-lifecycle", "recipes/crm-data-hygiene", "gtm/playbooks/revops-automation-playbook"]
|
|
1505
1725
|
}
|
|
1506
1726
|
];
|
|
1507
1727
|
var CAMPAIGN_BUILDER_STRATEGY_TEMPLATES = [
|
|
@@ -1588,7 +1808,15 @@ var CAMPAIGN_BUILDER_STRATEGY_TEMPLATES = [
|
|
|
1588
1808
|
agencyContext: {
|
|
1589
1809
|
partnerEcosystem: ["signaliz", "instantly", "nango"]
|
|
1590
1810
|
},
|
|
1591
|
-
operatingPlaybookSlugs: [
|
|
1811
|
+
operatingPlaybookSlugs: [
|
|
1812
|
+
"net-new-suppressed-list",
|
|
1813
|
+
"proof-first-vertical-gate",
|
|
1814
|
+
"signal-led-copy-approval",
|
|
1815
|
+
"icp-persona-segmentation",
|
|
1816
|
+
"buying-signal-prioritization",
|
|
1817
|
+
"multi-channel-sequence-fit",
|
|
1818
|
+
"revops-feedback-loop"
|
|
1819
|
+
]
|
|
1592
1820
|
},
|
|
1593
1821
|
{
|
|
1594
1822
|
slug: "non-medical-home-care",
|
|
@@ -1661,7 +1889,15 @@ var CAMPAIGN_BUILDER_STRATEGY_TEMPLATES = [
|
|
|
1661
1889
|
agencyContext: {
|
|
1662
1890
|
partnerEcosystem: ["clay", "octave", "signaliz", "instantly", "nango"]
|
|
1663
1891
|
},
|
|
1664
|
-
operatingPlaybookSlugs: [
|
|
1892
|
+
operatingPlaybookSlugs: [
|
|
1893
|
+
"proof-first-vertical-gate",
|
|
1894
|
+
"domain-first-recovery",
|
|
1895
|
+
"table-workflow-handoff",
|
|
1896
|
+
"icp-persona-segmentation",
|
|
1897
|
+
"buying-signal-prioritization",
|
|
1898
|
+
"multi-channel-sequence-fit",
|
|
1899
|
+
"revops-feedback-loop"
|
|
1900
|
+
]
|
|
1665
1901
|
},
|
|
1666
1902
|
{
|
|
1667
1903
|
slug: "agency-founder-led",
|
|
@@ -1722,7 +1958,15 @@ var CAMPAIGN_BUILDER_STRATEGY_TEMPLATES = [
|
|
|
1722
1958
|
agencyContext: {
|
|
1723
1959
|
partnerEcosystem: ["signaliz", "octave", "instantly", "nango"]
|
|
1724
1960
|
},
|
|
1725
|
-
operatingPlaybookSlugs: [
|
|
1961
|
+
operatingPlaybookSlugs: [
|
|
1962
|
+
"net-new-suppressed-list",
|
|
1963
|
+
"signal-led-copy-approval",
|
|
1964
|
+
"table-workflow-handoff",
|
|
1965
|
+
"icp-persona-segmentation",
|
|
1966
|
+
"buying-signal-prioritization",
|
|
1967
|
+
"multi-channel-sequence-fit",
|
|
1968
|
+
"revops-feedback-loop"
|
|
1969
|
+
]
|
|
1726
1970
|
},
|
|
1727
1971
|
{
|
|
1728
1972
|
slug: "cloud-infrastructure-displacement",
|
|
@@ -1809,7 +2053,15 @@ var CAMPAIGN_BUILDER_STRATEGY_TEMPLATES = [
|
|
|
1809
2053
|
agencyContext: {
|
|
1810
2054
|
partnerEcosystem: ["signaliz", "octave", "instantly", "nango"]
|
|
1811
2055
|
},
|
|
1812
|
-
operatingPlaybookSlugs: [
|
|
2056
|
+
operatingPlaybookSlugs: [
|
|
2057
|
+
"proof-first-vertical-gate",
|
|
2058
|
+
"domain-first-recovery",
|
|
2059
|
+
"signal-led-copy-approval",
|
|
2060
|
+
"icp-persona-segmentation",
|
|
2061
|
+
"buying-signal-prioritization",
|
|
2062
|
+
"multi-channel-sequence-fit",
|
|
2063
|
+
"revops-feedback-loop"
|
|
2064
|
+
]
|
|
1813
2065
|
}
|
|
1814
2066
|
];
|
|
1815
2067
|
var CampaignBuilderAgent = class {
|
|
@@ -1840,6 +2092,9 @@ var CampaignBuilderAgent = class {
|
|
|
1840
2092
|
const plan = await this.createPlan(request, options);
|
|
1841
2093
|
return createCampaignBuilderReadiness(plan);
|
|
1842
2094
|
}
|
|
2095
|
+
activeWorkContext(input) {
|
|
2096
|
+
return createCampaignBuilderActiveWorkContext(input);
|
|
2097
|
+
}
|
|
1843
2098
|
async proof(request, options = {}) {
|
|
1844
2099
|
const plan = await this.createPlan(request, options);
|
|
1845
2100
|
const result = await this.dryRunPlan(plan, {
|
|
@@ -2224,9 +2479,10 @@ function createCampaignBuilderAgentPlan(request, context = {}) {
|
|
|
2224
2479
|
const estimatedCredits = estimateCredits(resolvedRequest, defaults, targetCount);
|
|
2225
2480
|
const buildRequest = createBuildRequest(resolvedRequest, defaults, targetCount, campaignName, context.scopeBuildArgs, routes, memory, context.scopeBrainPreflight);
|
|
2226
2481
|
const brainPreflight = asRecord(buildRequest.brainPreflight);
|
|
2482
|
+
const evidence = buildRequest.evidence ?? null;
|
|
2227
2483
|
const approvals = deriveApprovals(resolvedRequest, routes, memory, estimatedCredits, defaults.delivery?.approvalRequired !== false);
|
|
2228
2484
|
return {
|
|
2229
|
-
planId: `cbp_${hashString(JSON.stringify({ goal: resolvedRequest.goal, campaignName, targetCount, routes }))}`,
|
|
2485
|
+
planId: `cbp_${hashString(JSON.stringify({ goal: resolvedRequest.goal, campaignName, targetCount, routes, evidence }))}`,
|
|
2230
2486
|
campaignName,
|
|
2231
2487
|
goal: resolvedRequest.goal,
|
|
2232
2488
|
targetCount,
|
|
@@ -2241,6 +2497,7 @@ function createCampaignBuilderAgentPlan(request, context = {}) {
|
|
|
2241
2497
|
approvals,
|
|
2242
2498
|
buildRequest,
|
|
2243
2499
|
brainPreflight,
|
|
2500
|
+
evidence,
|
|
2244
2501
|
operatingPlaybooks,
|
|
2245
2502
|
mcpFlow: createMcpFlow(resolvedRequest, buildRequest, routes, memory, approvals),
|
|
2246
2503
|
estimatedCredits,
|
|
@@ -2332,6 +2589,90 @@ function createCampaignBuilderReadiness(plan) {
|
|
|
2332
2589
|
nextActions: campaignReadinessNextActions(plan, ready, customRoutes.length)
|
|
2333
2590
|
};
|
|
2334
2591
|
}
|
|
2592
|
+
function createCampaignBuilderActiveWorkContext(input) {
|
|
2593
|
+
const plan = input.readiness?.plan ?? input.plan;
|
|
2594
|
+
const remembered = input.remembered ?? {};
|
|
2595
|
+
const lastResult = asRecord(input.lastResult);
|
|
2596
|
+
const readinessBlockers = input.readiness?.summary.blockers ?? [];
|
|
2597
|
+
const explicitBlockers = input.blockers ?? [];
|
|
2598
|
+
const blockers = uniqueStrings([...explicitBlockers, ...readinessBlockers]);
|
|
2599
|
+
const warnings = uniqueStrings([
|
|
2600
|
+
...input.warnings ?? [],
|
|
2601
|
+
...input.readiness?.summary.warnings ?? [],
|
|
2602
|
+
...plan?.warnings ?? []
|
|
2603
|
+
]);
|
|
2604
|
+
const missingApprovals = plan ? (input.approval ? getMissingCampaignBuilderApprovals(plan, input.approval) : plan.approvals.filter((approval) => approval.blocking)).map((approval) => approval.type) : [];
|
|
2605
|
+
const refs = normalizeCampaignBuilderActiveWorkRefs({
|
|
2606
|
+
plan,
|
|
2607
|
+
remembered,
|
|
2608
|
+
refs: input.refs,
|
|
2609
|
+
lastResult
|
|
2610
|
+
});
|
|
2611
|
+
const state = inferCampaignBuilderActiveWorkState({
|
|
2612
|
+
plan,
|
|
2613
|
+
readiness: input.readiness,
|
|
2614
|
+
remembered,
|
|
2615
|
+
lastResult,
|
|
2616
|
+
blockers,
|
|
2617
|
+
missingApprovals
|
|
2618
|
+
});
|
|
2619
|
+
const nextSafeAction = campaignBuilderActiveWorkNextAction(state, blockers, missingApprovals, refs);
|
|
2620
|
+
const approvalPacket = createCampaignBuilderApprovalPacket(plan, input.approval, missingApprovals);
|
|
2621
|
+
const nextSafeMcpAction = campaignBuilderActiveWorkNextMcpAction({
|
|
2622
|
+
state,
|
|
2623
|
+
plan,
|
|
2624
|
+
refs,
|
|
2625
|
+
approvalPacket
|
|
2626
|
+
});
|
|
2627
|
+
const summary = {
|
|
2628
|
+
plan_id: plan?.planId ?? remembered.planId ?? null,
|
|
2629
|
+
campaign_name: plan?.campaignName ?? null,
|
|
2630
|
+
target_count: plan?.targetCount ?? null,
|
|
2631
|
+
gtm_campaign_id: plan?.buildRequest.gtmCampaignId ?? remembered.gtmCampaignId ?? null,
|
|
2632
|
+
campaign_build_id: stringValue(lastResult.campaign_build_id ?? lastResult.campaignBuildId) ?? remembered.campaignBuildId ?? null,
|
|
2633
|
+
provider_campaign_id: remembered.providerCampaignId ?? null
|
|
2634
|
+
};
|
|
2635
|
+
const approvalBoundary = campaignBuilderActiveWorkApprovalBoundary(missingApprovals, state);
|
|
2636
|
+
const conversationStarters = campaignBuilderActiveWorkConversationStarters({
|
|
2637
|
+
state,
|
|
2638
|
+
blockers,
|
|
2639
|
+
missingApprovals,
|
|
2640
|
+
refs,
|
|
2641
|
+
nextSafeAction
|
|
2642
|
+
});
|
|
2643
|
+
return {
|
|
2644
|
+
packet_version: "campaign-builder-active-work-context.v1",
|
|
2645
|
+
read_only: true,
|
|
2646
|
+
no_spend: true,
|
|
2647
|
+
no_provider_writes: true,
|
|
2648
|
+
private_safe: true,
|
|
2649
|
+
state,
|
|
2650
|
+
summary,
|
|
2651
|
+
refs,
|
|
2652
|
+
blockers,
|
|
2653
|
+
warnings,
|
|
2654
|
+
missing_approval_types: missingApprovals,
|
|
2655
|
+
approval_packet: approvalPacket,
|
|
2656
|
+
approval_boundary: approvalBoundary,
|
|
2657
|
+
next_safe_action: nextSafeAction,
|
|
2658
|
+
next_safe_mcp_action: nextSafeMcpAction,
|
|
2659
|
+
conversation_starters: conversationStarters,
|
|
2660
|
+
openai_agent_handoff: createCampaignBuilderOpenAiAgentHandoff({
|
|
2661
|
+
plan,
|
|
2662
|
+
state,
|
|
2663
|
+
summary,
|
|
2664
|
+
refs,
|
|
2665
|
+
blockers,
|
|
2666
|
+
warnings,
|
|
2667
|
+
missingApprovals,
|
|
2668
|
+
approvalPacket,
|
|
2669
|
+
approvalBoundary,
|
|
2670
|
+
nextSafeAction,
|
|
2671
|
+
nextSafeMcpAction,
|
|
2672
|
+
conversationStarters
|
|
2673
|
+
})
|
|
2674
|
+
};
|
|
2675
|
+
}
|
|
2335
2676
|
function createCampaignBuilderProofReceipt(plan, result) {
|
|
2336
2677
|
const strategyMemory = asRecord(plan.strategyMemoryStatus);
|
|
2337
2678
|
const dryRunResult = asRecord(result);
|
|
@@ -2390,6 +2731,7 @@ function createCampaignBuilderProofReceipt(plan, result) {
|
|
|
2390
2731
|
estimated_credits: plan.estimatedCredits,
|
|
2391
2732
|
operating_playbooks: plan.operatingPlaybooks.map((playbook) => playbook.slug)
|
|
2392
2733
|
},
|
|
2734
|
+
evidence: plan.evidence,
|
|
2393
2735
|
gates,
|
|
2394
2736
|
strategy_memory_status: summarizeCampaignBuilderProofStrategyMemory(strategyMemory),
|
|
2395
2737
|
dry_run_result: summarizeCampaignBuilderProofDryRun(dryRunResult),
|
|
@@ -2445,6 +2787,56 @@ function getCampaignBuilderOperatingPlaybooksForRequest(request) {
|
|
|
2445
2787
|
]);
|
|
2446
2788
|
return slugs.map(getCampaignBuilderOperatingPlaybook).filter((playbook) => Boolean(playbook));
|
|
2447
2789
|
}
|
|
2790
|
+
function normalizeCampaignBuilderEvidence(evidence) {
|
|
2791
|
+
if (!evidence) return null;
|
|
2792
|
+
const attachmentSummary = (evidence.attachments ?? []).filter((attachment) => stringValue(attachment.name)).slice(0, 5).map((attachment) => ({
|
|
2793
|
+
name: stringValue(attachment.name) ?? "attachment",
|
|
2794
|
+
kind: stringValue(attachment.kind) ?? null,
|
|
2795
|
+
media_type: stringValue(attachment.mediaType) ?? null,
|
|
2796
|
+
redacted: attachment.redacted !== false,
|
|
2797
|
+
columns: uniqueStrings(attachment.columns ?? []).slice(0, 25),
|
|
2798
|
+
row_count: numberOrUndefined2(attachment.rowCount) ?? null,
|
|
2799
|
+
content_summary: stringValue(attachment.contentSummary)?.slice(0, 500) ?? null,
|
|
2800
|
+
evidence_fields: uniqueStrings(attachment.evidenceFields ?? []).slice(0, 25)
|
|
2801
|
+
}));
|
|
2802
|
+
const urlSummary = (evidence.urls ?? []).filter((url) => stringValue(url.url)).slice(0, 8).map((url) => {
|
|
2803
|
+
const rawUrl = stringValue(url.url) ?? "";
|
|
2804
|
+
return {
|
|
2805
|
+
url: rawUrl,
|
|
2806
|
+
host: stringValue(url.host) ?? hostFromUrl(rawUrl) ?? null,
|
|
2807
|
+
type: stringValue(url.type) ?? null,
|
|
2808
|
+
label: stringValue(url.label) ?? null,
|
|
2809
|
+
summary: stringValue(url.summary)?.slice(0, 500) ?? null,
|
|
2810
|
+
redacted: url.redacted === true
|
|
2811
|
+
};
|
|
2812
|
+
});
|
|
2813
|
+
const operatorNotes = uniqueStrings(evidence.notes ?? []).map((note) => note.slice(0, 240)).slice(0, 5);
|
|
2814
|
+
if (!attachmentSummary.length && !urlSummary.length && !operatorNotes.length) return null;
|
|
2815
|
+
return {
|
|
2816
|
+
packet_version: "campaign-builder-evidence.v1",
|
|
2817
|
+
private_safe: true,
|
|
2818
|
+
attachment_summary: attachmentSummary,
|
|
2819
|
+
url_summary: urlSummary,
|
|
2820
|
+
operator_notes: operatorNotes,
|
|
2821
|
+
privacy_boundary: "Use these attachment and URL summaries as planning evidence only. Do not expose raw private attachment text, raw rows, leads, emails, provider payloads, copy bodies, or secrets.",
|
|
2822
|
+
raw_private_fields_withheld: [
|
|
2823
|
+
"raw_private_attachment_text",
|
|
2824
|
+
"raw_attachment_rows",
|
|
2825
|
+
"raw_leads",
|
|
2826
|
+
"email_addresses",
|
|
2827
|
+
"provider_auth_payloads",
|
|
2828
|
+
"copy_bodies",
|
|
2829
|
+
"secrets"
|
|
2830
|
+
]
|
|
2831
|
+
};
|
|
2832
|
+
}
|
|
2833
|
+
function hostFromUrl(value) {
|
|
2834
|
+
try {
|
|
2835
|
+
return new URL(value).hostname || void 0;
|
|
2836
|
+
} catch {
|
|
2837
|
+
return void 0;
|
|
2838
|
+
}
|
|
2839
|
+
}
|
|
2448
2840
|
function applyCampaignBuilderStrategyTemplate(request) {
|
|
2449
2841
|
const template = getCampaignBuilderStrategyTemplate(request.strategyTemplate);
|
|
2450
2842
|
if (!template) return request;
|
|
@@ -3136,7 +3528,7 @@ function normalizeMemory(request) {
|
|
|
3136
3528
|
};
|
|
3137
3529
|
}
|
|
3138
3530
|
function defaultAgencyMemoryQueries(request, configured) {
|
|
3139
|
-
const operatingPlaybookTerms = getCampaignBuilderOperatingPlaybooksForRequest(request).flatMap((playbook) => [playbook.label, ...playbook.memoryKeywords]).join(" ");
|
|
3531
|
+
const operatingPlaybookTerms = getCampaignBuilderOperatingPlaybooksForRequest(request).flatMap((playbook) => [playbook.label, ...playbook.memoryKeywords, ...playbook.knowledgeSources]).join(" ");
|
|
3140
3532
|
const queries = [{
|
|
3141
3533
|
query: request.goal,
|
|
3142
3534
|
scopes: ["workspace", configured.useNetworkPatterns ? "network_patterns" : "operator_notes"],
|
|
@@ -3347,6 +3739,8 @@ function createBuildRequest(request, defaults, targetCount, campaignName, scopeB
|
|
|
3347
3739
|
fillPolicy: "aggressive"
|
|
3348
3740
|
}
|
|
3349
3741
|
};
|
|
3742
|
+
const evidence = normalizeCampaignBuilderEvidence(request.evidence);
|
|
3743
|
+
if (evidence) buildRequest.evidence = evidence;
|
|
3350
3744
|
const scoped = asRecord(scopeBuildArgs);
|
|
3351
3745
|
buildRequest.gtmCampaignId = request.gtmCampaignId ?? stringValue(scoped.gtm_campaign_id ?? scoped.gtmCampaignId);
|
|
3352
3746
|
buildRequest.learningHoldout = normalizeCampaignBuilderLearningHoldout(
|
|
@@ -3378,6 +3772,7 @@ function createBrainPreflight(request, buildRequest, routes, memory) {
|
|
|
3378
3772
|
memory.enabled ? "feedback" : void 0
|
|
3379
3773
|
]);
|
|
3380
3774
|
const providerChain = uniqueStrings(["signaliz", ...request.preferredProviders ?? [], ...routes.map((route) => route.provider)]);
|
|
3775
|
+
const evidence = buildRequest.evidence ?? normalizeCampaignBuilderEvidence(request.evidence);
|
|
3381
3776
|
const targetIcp = compact({
|
|
3382
3777
|
personas: buildRequest.icp?.personas,
|
|
3383
3778
|
industries: buildRequest.icp?.industries,
|
|
@@ -3390,6 +3785,7 @@ function createBrainPreflight(request, buildRequest, routes, memory) {
|
|
|
3390
3785
|
const learningArgs = compact({
|
|
3391
3786
|
campaign_brief: request.goal,
|
|
3392
3787
|
target_icp: targetIcp,
|
|
3788
|
+
evidence_context: evidence,
|
|
3393
3789
|
layers,
|
|
3394
3790
|
provider_chain: providerChain,
|
|
3395
3791
|
lead_source: providerChain[0] ?? "signaliz",
|
|
@@ -3401,6 +3797,7 @@ function createBrainPreflight(request, buildRequest, routes, memory) {
|
|
|
3401
3797
|
const defaultsArgs = compact({
|
|
3402
3798
|
campaign_brief: request.goal,
|
|
3403
3799
|
target_icp: targetIcp,
|
|
3800
|
+
evidence_context: evidence,
|
|
3404
3801
|
layers,
|
|
3405
3802
|
include_global: memory.useNetworkPatterns,
|
|
3406
3803
|
include_memory: memory.enabled,
|
|
@@ -3411,6 +3808,7 @@ function createBrainPreflight(request, buildRequest, routes, memory) {
|
|
|
3411
3808
|
provider_chain: providerChain,
|
|
3412
3809
|
lead_source: providerChain[0] ?? "signaliz",
|
|
3413
3810
|
target_icp: targetIcp,
|
|
3811
|
+
evidence_context: evidence,
|
|
3414
3812
|
include_global: memory.useNetworkPatterns,
|
|
3415
3813
|
limit: 25
|
|
3416
3814
|
});
|
|
@@ -3423,9 +3821,11 @@ function createBrainPreflight(request, buildRequest, routes, memory) {
|
|
|
3423
3821
|
label: playbook.label,
|
|
3424
3822
|
quality_gates: playbook.qualityGates,
|
|
3425
3823
|
required_fields: playbook.requiredFields,
|
|
3426
|
-
activation_boundary: playbook.activationBoundary
|
|
3824
|
+
activation_boundary: playbook.activationBoundary,
|
|
3825
|
+
knowledge_sources: playbook.knowledgeSources
|
|
3427
3826
|
})),
|
|
3428
3827
|
target_icp: targetIcp,
|
|
3828
|
+
evidence_context: evidence,
|
|
3429
3829
|
provider_chain: providerChain,
|
|
3430
3830
|
lead_source: providerChain[0] ?? "signaliz",
|
|
3431
3831
|
learning_holdout: buildRequest.learningHoldout,
|
|
@@ -3698,7 +4098,7 @@ function createMcpFlow(request, buildRequest, routes, memory, approvals) {
|
|
|
3698
4098
|
phase: "plan",
|
|
3699
4099
|
tool: "nango_mcp_tools_list",
|
|
3700
4100
|
arguments: {
|
|
3701
|
-
format: "
|
|
4101
|
+
format: "openai"
|
|
3702
4102
|
},
|
|
3703
4103
|
readOnly: true,
|
|
3704
4104
|
approvalRequired: false
|
|
@@ -4007,6 +4407,7 @@ function buildGtmCampaignBuildPlanArgs(request, buildRequest, routes, memory) {
|
|
|
4007
4407
|
layers: layers.length > 0 ? layers : void 0,
|
|
4008
4408
|
preferred_providers: preferredProviders.length > 0 ? preferredProviders : void 0,
|
|
4009
4409
|
strategy_model: strategyModel,
|
|
4410
|
+
evidence_context: buildRequest.evidence ?? normalizeCampaignBuilderEvidence(request.evidence),
|
|
4010
4411
|
include_strategy_patterns: campaignBuilderStrategyPatternsEnabled(agencyContext),
|
|
4011
4412
|
include_workflow_patterns: campaignBuilderWorkflowPatternsEnabled(agencyContext),
|
|
4012
4413
|
include_nango_catalog: agencyContext.includeNangoCatalog !== false,
|
|
@@ -4015,7 +4416,8 @@ function buildGtmCampaignBuildPlanArgs(request, buildRequest, routes, memory) {
|
|
|
4015
4416
|
slug: playbook.slug,
|
|
4016
4417
|
label: playbook.label,
|
|
4017
4418
|
quality_gates: playbook.qualityGates,
|
|
4018
|
-
activation_boundary: playbook.activationBoundary
|
|
4419
|
+
activation_boundary: playbook.activationBoundary,
|
|
4420
|
+
knowledge_sources: playbook.knowledgeSources
|
|
4019
4421
|
})),
|
|
4020
4422
|
include_memory: memory.enabled,
|
|
4021
4423
|
include_brain: true,
|
|
@@ -4108,6 +4510,7 @@ function buildCampaignArgs(request) {
|
|
|
4108
4510
|
}
|
|
4109
4511
|
if (request.campaignStrategyContext) args.campaign_strategy_context = request.campaignStrategyContext;
|
|
4110
4512
|
if (request.deliveryRisk) args.delivery_risk = request.deliveryRisk;
|
|
4513
|
+
if (request.evidence) args.evidence_context = request.evidence;
|
|
4111
4514
|
if (request.icp) {
|
|
4112
4515
|
args.icp = compact({
|
|
4113
4516
|
personas: request.icp.personas,
|
|
@@ -4157,7 +4560,8 @@ function buildCampaignArgs(request) {
|
|
|
4157
4560
|
max_body_words: request.copy.maxBodyWords,
|
|
4158
4561
|
sender_context: request.copy.senderContext,
|
|
4159
4562
|
offer_context: request.copy.offerContext,
|
|
4160
|
-
model: request.copy.model
|
|
4563
|
+
model: request.copy.model,
|
|
4564
|
+
evidence_mode: request.copy.evidenceMode
|
|
4161
4565
|
});
|
|
4162
4566
|
}
|
|
4163
4567
|
if (request.delivery) {
|
|
@@ -4434,6 +4838,7 @@ function mapAgentCustomerRowCounts(value) {
|
|
|
4434
4838
|
acceptedRows: numberOrUndefined2(record.accepted_rows),
|
|
4435
4839
|
usableRows: numberOrUndefined2(record.usable_rows),
|
|
4436
4840
|
copiedRows: numberOrUndefined2(record.copied_rows),
|
|
4841
|
+
copySkippedRows: numberOrUndefined2(record.copy_skipped_rows),
|
|
4437
4842
|
approvalReadyRows: numberOrUndefined2(record.approval_ready_rows),
|
|
4438
4843
|
qaReadyRows: numberOrUndefined2(record.qa_ready_rows),
|
|
4439
4844
|
deliveredRows: numberOrUndefined2(record.delivered_rows),
|
|
@@ -4544,7 +4949,7 @@ function createCampaignBuilderNorthStarScorecard(status, rows, artifacts, termin
|
|
|
4544
4949
|
const sampledRows = rows.rows.length;
|
|
4545
4950
|
const rowData = rows.rows.map((row) => asRecord(row.data));
|
|
4546
4951
|
const requestedTarget = status.customerRowCounts?.requestedTarget ?? status.recordsTotal ?? rows.count;
|
|
4547
|
-
const finalRows = status.customerRowCounts?.deliveredRows ?? status.customerRowCounts?.qaReadyRows ?? status.customerRowCounts?.copiedRows ?? status.customerRowCounts?.acceptedRows ?? rows.count;
|
|
4952
|
+
const finalRows = status.customerRowCounts?.deliveredRows ?? status.customerRowCounts?.qaReadyRows ?? status.customerRowCounts?.copySkippedRows ?? status.customerRowCounts?.copiedRows ?? status.customerRowCounts?.acceptedRows ?? rows.count;
|
|
4548
4953
|
const rowsWithEmail = rows.rows.filter(campaignReviewRowHasEmail).length;
|
|
4549
4954
|
const verifiedEmailRows = rowData.filter(campaignReviewDataHasVerifiedEmail).length;
|
|
4550
4955
|
const uniqueEmails = new Set(rowData.map(campaignReviewDataEmail).filter(Boolean)).size;
|
|
@@ -5035,6 +5440,342 @@ function createCampaignBuilderReadinessLane(route, plan) {
|
|
|
5035
5440
|
nextAction: customRoute ? `Review ${route.provider} route setup before launch approval.` : void 0
|
|
5036
5441
|
};
|
|
5037
5442
|
}
|
|
5443
|
+
function createCampaignBuilderApprovalPacket(plan, approval, missingTypes) {
|
|
5444
|
+
const requestedTypes = plan ? uniqueStrings(plan.approvals.filter((item) => item.blocking).map((item) => item.type)) : [];
|
|
5445
|
+
const approvalMatchesPlan = Boolean(plan && approval?.planId === plan.planId);
|
|
5446
|
+
const approvedTypes = approvalMatchesPlan ? approval?.approvedTypes ?? [] : [];
|
|
5447
|
+
const approvedRoutes = approvalMatchesPlan ? approval?.approvedRouteIds ?? [] : [];
|
|
5448
|
+
const missingIds = new Set(
|
|
5449
|
+
plan && approvalMatchesPlan && approval ? getMissingCampaignBuilderApprovals(plan, approval).map((item) => item.id) : plan?.approvals.filter((item) => item.blocking).map((item) => item.id) ?? []
|
|
5450
|
+
);
|
|
5451
|
+
const routeIdsRequired = plan ? uniqueStrings(plan.approvals.map((item) => item.routeId).filter((id) => Boolean(id))) : [];
|
|
5452
|
+
const spendLimitRequired = plan ? Math.max(0, ...plan.approvals.filter((item) => item.type === "spend" && item.blocking).map((item) => item.estimatedCredits ?? plan.estimatedCredits)) : 0;
|
|
5453
|
+
const normalizedSpendLimit = spendLimitRequired > 0 ? spendLimitRequired : null;
|
|
5454
|
+
const approvalState = !plan ? "unscoped" : missingTypes.length > 0 ? "requires_approval" : "approved";
|
|
5455
|
+
const approvalInput = {
|
|
5456
|
+
approved_by: approval?.approvedBy ?? null,
|
|
5457
|
+
approved_at: approval?.approvedAt ?? null,
|
|
5458
|
+
approved_types: approvedTypes,
|
|
5459
|
+
approved_route_ids: approvedRoutes,
|
|
5460
|
+
spend_limit_credits: approval?.spendLimitCredits ?? null,
|
|
5461
|
+
notes: approval?.notes
|
|
5462
|
+
};
|
|
5463
|
+
return {
|
|
5464
|
+
packet_version: "campaign-builder-approval-packet.v1",
|
|
5465
|
+
read_only: true,
|
|
5466
|
+
no_spend: true,
|
|
5467
|
+
no_provider_writes: true,
|
|
5468
|
+
private_safe: true,
|
|
5469
|
+
approval_state: approvalState,
|
|
5470
|
+
plan_id: plan?.planId ?? null,
|
|
5471
|
+
campaign_name: plan?.campaignName ?? null,
|
|
5472
|
+
requested_approval_types: requestedTypes,
|
|
5473
|
+
missing_approval_types: uniqueStrings(missingTypes),
|
|
5474
|
+
spend_limit_credits_required: normalizedSpendLimit,
|
|
5475
|
+
route_ids_required: routeIdsRequired,
|
|
5476
|
+
required_approvals: (plan?.approvals ?? []).map((item) => compact({
|
|
5477
|
+
id: item.id,
|
|
5478
|
+
type: item.type,
|
|
5479
|
+
label: item.label,
|
|
5480
|
+
reason: item.reason,
|
|
5481
|
+
blocking: item.blocking,
|
|
5482
|
+
route_id: item.routeId,
|
|
5483
|
+
provider: item.provider,
|
|
5484
|
+
estimated_credits: item.estimatedCredits,
|
|
5485
|
+
status: missingIds.has(item.id) ? "missing" : "approved"
|
|
5486
|
+
})),
|
|
5487
|
+
approval_input: approvalInput,
|
|
5488
|
+
cli_handoff: plan ? {
|
|
5489
|
+
command: campaignBuilderApprovalCliHandoff(requestedTypes, routeIdsRequired, normalizedSpendLimit),
|
|
5490
|
+
safety: "Template only: run after explicit human approval identity, approved types, route scope, and spend limit are filled in."
|
|
5491
|
+
} : null,
|
|
5492
|
+
sdk_handoff: plan ? {
|
|
5493
|
+
method: "campaignBuilderAgent.buildApprovedPlan",
|
|
5494
|
+
approval: compact({
|
|
5495
|
+
approvedBy: approval?.approvedBy ?? "<operator-email>",
|
|
5496
|
+
approvedTypes: requestedTypes,
|
|
5497
|
+
approvedRouteIds: routeIdsRequired,
|
|
5498
|
+
spendLimitCredits: normalizedSpendLimit ?? void 0,
|
|
5499
|
+
notes: approval?.notes
|
|
5500
|
+
}),
|
|
5501
|
+
options: {
|
|
5502
|
+
idempotencyKey: "<set-before-execution>"
|
|
5503
|
+
},
|
|
5504
|
+
safety: "Call only after the approval packet is accepted; this helper does not execute writes or spend."
|
|
5505
|
+
} : null,
|
|
5506
|
+
mcp_handoffs: plan ? campaignBuilderApprovalMcpHandoffs(plan, requestedTypes, routeIdsRequired, normalizedSpendLimit) : [],
|
|
5507
|
+
safety_boundary: "This approval packet is a reusable request for human approval; it is not an approval grant and it does not authorize spend, provider writes, sender loading, delivery, or launch by itself."
|
|
5508
|
+
};
|
|
5509
|
+
}
|
|
5510
|
+
function campaignBuilderApprovalCliHandoff(requestedTypes, routeIds, spendLimit) {
|
|
5511
|
+
return [
|
|
5512
|
+
"signaliz campaign-agent build-approved --request-file campaign-request.json --confirm-launch",
|
|
5513
|
+
requestedTypes.length > 0 ? `--approved-types ${shellArg(requestedTypes.join(","))}` : "--approve-all",
|
|
5514
|
+
"--approved-by <operator-email>",
|
|
5515
|
+
spendLimit !== null ? `--spend-limit ${spendLimit}` : void 0,
|
|
5516
|
+
routeIds.length > 0 ? `--approved-route-ids ${shellArg(routeIds.join(","))}` : void 0
|
|
5517
|
+
].filter(Boolean).join(" ");
|
|
5518
|
+
}
|
|
5519
|
+
function campaignBuilderApprovalMcpHandoffs(plan, requestedTypes, routeIds, spendLimit) {
|
|
5520
|
+
const approvalContext = compact({
|
|
5521
|
+
plan_id: plan.planId,
|
|
5522
|
+
approval_types: requestedTypes,
|
|
5523
|
+
approved_route_ids: routeIds,
|
|
5524
|
+
spend_limit_credits: spendLimit,
|
|
5525
|
+
approved_by: "<operator-email>"
|
|
5526
|
+
});
|
|
5527
|
+
return plan.mcpFlow.filter((step) => ["execution-prepare", "approved-build", "delivery-approval"].includes(step.id)).map((step) => ({
|
|
5528
|
+
id: step.id,
|
|
5529
|
+
tool: step.tool,
|
|
5530
|
+
arguments: step.id === "approved-build" ? compact({ ...step.arguments, approval_context: approvalContext }) : step.arguments,
|
|
5531
|
+
read_only: step.readOnly,
|
|
5532
|
+
approval_required: step.approvalRequired,
|
|
5533
|
+
safety: step.readOnly ? "Read-only readiness handoff; safe to inspect before approval." : "Write-capable handoff; run only after the approval packet is accepted."
|
|
5534
|
+
}));
|
|
5535
|
+
}
|
|
5536
|
+
function campaignBuilderActiveWorkNextMcpAction(input) {
|
|
5537
|
+
const campaignBuildRef = input.refs.find((ref) => ref.kind === "campaign_build" && ref.id);
|
|
5538
|
+
if (campaignBuildRef) {
|
|
5539
|
+
return {
|
|
5540
|
+
id: "check-campaign-build-status",
|
|
5541
|
+
tool: "get_campaign_build_status",
|
|
5542
|
+
arguments: { campaign_build_id: campaignBuildRef.id },
|
|
5543
|
+
read_only: true,
|
|
5544
|
+
approval_required: false,
|
|
5545
|
+
safety: "Read-only status check for the remembered campaign build; does not spend, write, export, send, or approve anything."
|
|
5546
|
+
};
|
|
5547
|
+
}
|
|
5548
|
+
const campaignRef = input.refs.find((ref) => ref.kind === "gtm_campaign" && ref.id);
|
|
5549
|
+
if (campaignRef) {
|
|
5550
|
+
return {
|
|
5551
|
+
id: "check-gtm-campaign-status",
|
|
5552
|
+
tool: "gtm_campaign_execution_status",
|
|
5553
|
+
arguments: { campaign_id: campaignRef.id },
|
|
5554
|
+
read_only: true,
|
|
5555
|
+
approval_required: false,
|
|
5556
|
+
safety: "Read-only campaign execution status check; does not start or mutate the campaign."
|
|
5557
|
+
};
|
|
5558
|
+
}
|
|
5559
|
+
const preferredStepId = input.state === "ready_for_dry_run" ? "dry-run-build" : input.state === "planning" || input.state === "blocked" ? "agency-campaign-build-plan" : null;
|
|
5560
|
+
const preferredStep = preferredStepId ? input.plan?.mcpFlow.find((step) => step.id === preferredStepId && step.readOnly) : void 0;
|
|
5561
|
+
if (preferredStep) return campaignBuilderMcpStepToActiveWorkAction(preferredStep, "Read-only continuation from the saved campaign-agent plan.");
|
|
5562
|
+
const readOnlyApprovalHandoff = input.approvalPacket.mcp_handoffs.find((handoff) => handoff.read_only && !handoff.approval_required);
|
|
5563
|
+
if (readOnlyApprovalHandoff) return readOnlyApprovalHandoff;
|
|
5564
|
+
const firstReadOnlyPlanStep = input.plan?.mcpFlow.find((step) => step.readOnly && !step.approvalRequired);
|
|
5565
|
+
return firstReadOnlyPlanStep ? campaignBuilderMcpStepToActiveWorkAction(firstReadOnlyPlanStep, "Read-only saved plan check; safe before approvals or writes.") : null;
|
|
5566
|
+
}
|
|
5567
|
+
function campaignBuilderMcpStepToActiveWorkAction(step, safety) {
|
|
5568
|
+
return {
|
|
5569
|
+
id: step.id,
|
|
5570
|
+
tool: step.tool,
|
|
5571
|
+
arguments: step.arguments,
|
|
5572
|
+
read_only: step.readOnly,
|
|
5573
|
+
approval_required: step.approvalRequired,
|
|
5574
|
+
safety
|
|
5575
|
+
};
|
|
5576
|
+
}
|
|
5577
|
+
function normalizeCampaignBuilderActiveWorkRefs(input) {
|
|
5578
|
+
const refs = [];
|
|
5579
|
+
const pushRef = (ref) => {
|
|
5580
|
+
if (!ref?.id) return;
|
|
5581
|
+
refs.push(ref);
|
|
5582
|
+
};
|
|
5583
|
+
pushRef(input.plan?.planId ? { kind: "plan", id: input.plan.planId, label: input.plan.campaignName, source: "plan" } : void 0);
|
|
5584
|
+
pushRef(input.remembered.planId ? { kind: "plan", id: input.remembered.planId, source: "remembered" } : void 0);
|
|
5585
|
+
pushRef(
|
|
5586
|
+
input.plan?.buildRequest.gtmCampaignId ?? input.remembered.gtmCampaignId ? {
|
|
5587
|
+
kind: "gtm_campaign",
|
|
5588
|
+
id: input.plan?.buildRequest.gtmCampaignId ?? input.remembered.gtmCampaignId,
|
|
5589
|
+
label: input.plan?.campaignName,
|
|
5590
|
+
source: input.plan?.buildRequest.gtmCampaignId ? "plan" : "remembered"
|
|
5591
|
+
} : void 0
|
|
5592
|
+
);
|
|
5593
|
+
const campaignBuildId = stringValue(input.lastResult.campaign_build_id ?? input.lastResult.campaignBuildId) ?? input.remembered.campaignBuildId;
|
|
5594
|
+
pushRef(campaignBuildId ? { kind: "campaign_build", id: campaignBuildId, status: activeWorkStatus(input.lastResult) ?? input.remembered.status, source: "result" } : void 0);
|
|
5595
|
+
pushRef(
|
|
5596
|
+
input.remembered.providerCampaignId ? {
|
|
5597
|
+
kind: "provider_campaign",
|
|
5598
|
+
id: input.remembered.providerCampaignId,
|
|
5599
|
+
label: input.remembered.provider,
|
|
5600
|
+
status: input.remembered.status,
|
|
5601
|
+
source: "remembered"
|
|
5602
|
+
} : void 0
|
|
5603
|
+
);
|
|
5604
|
+
for (const ref of input.remembered.refs ?? []) pushRef(ref);
|
|
5605
|
+
for (const ref of input.refs ?? []) pushRef(ref);
|
|
5606
|
+
const seen = /* @__PURE__ */ new Set();
|
|
5607
|
+
return refs.filter((ref) => {
|
|
5608
|
+
const key = `${ref.kind}:${ref.id}`;
|
|
5609
|
+
if (seen.has(key)) return false;
|
|
5610
|
+
seen.add(key);
|
|
5611
|
+
return true;
|
|
5612
|
+
});
|
|
5613
|
+
}
|
|
5614
|
+
function inferCampaignBuilderActiveWorkState(input) {
|
|
5615
|
+
if (input.blockers.length > 0) return "blocked";
|
|
5616
|
+
const status = activeWorkStatus(input.lastResult) ?? input.remembered.status;
|
|
5617
|
+
const normalized = status?.toLowerCase();
|
|
5618
|
+
if (normalized && ["completed", "complete", "succeeded", "success", "done"].includes(normalized)) return "completed";
|
|
5619
|
+
if (normalized && ["queued", "running", "in_progress", "processing", "pending"].includes(normalized)) return "queued_or_running";
|
|
5620
|
+
const dryRunComplete = input.lastResult.dry_run === true || input.lastResult.dryRun === true || normalized === "dry_run";
|
|
5621
|
+
if (dryRunComplete) return input.missingApprovals.length > 0 ? "needs_approval" : "dry_run_complete";
|
|
5622
|
+
if (input.missingApprovals.length > 0) return "needs_approval";
|
|
5623
|
+
if (input.readiness?.summary.ready === true) return "ready_for_dry_run";
|
|
5624
|
+
if (input.plan) return "planning";
|
|
5625
|
+
return "unknown";
|
|
5626
|
+
}
|
|
5627
|
+
function campaignBuilderActiveWorkApprovalBoundary(missingApprovals, state) {
|
|
5628
|
+
if (missingApprovals.length > 0) {
|
|
5629
|
+
return `Blocked before spend, provider writes, delivery, or launch until approval covers: ${uniqueStrings(missingApprovals).join(", ")}.`;
|
|
5630
|
+
}
|
|
5631
|
+
if (state === "dry_run_complete" || state === "ready_for_dry_run") {
|
|
5632
|
+
return "Read-only planning and dry-runs are allowed; spend, provider writes, sender loading, delivery, and launch still require explicit approval.";
|
|
5633
|
+
}
|
|
5634
|
+
return "This packet is read-only and does not authorize spend, provider writes, sender loading, delivery, or launch.";
|
|
5635
|
+
}
|
|
5636
|
+
function campaignBuilderActiveWorkNextAction(state, blockers, missingApprovals, refs) {
|
|
5637
|
+
if (blockers.length > 0) return `Resolve blocker: ${blockers[0]}`;
|
|
5638
|
+
if (missingApprovals.length > 0) return `Ask the operator to approve ${uniqueStrings(missingApprovals).join(", ")} before any write or spend action.`;
|
|
5639
|
+
if (state === "ready_for_dry_run") return "Run or inspect the read-only campaign dry-run, then return the receipt for approval review.";
|
|
5640
|
+
if (state === "dry_run_complete") return "Review the dry-run receipt and collect explicit launch or delivery approval before any write action.";
|
|
5641
|
+
if (state === "queued_or_running") return "Poll the remembered campaign build or provider job status; do not start a duplicate job.";
|
|
5642
|
+
if (state === "completed") return "Review final artifacts and delivery gates before export, sync, sender load, or launch.";
|
|
5643
|
+
if (refs.length > 0) return "Use the remembered refs to fetch current read-only status before asking the operator for IDs.";
|
|
5644
|
+
return "Create or refresh a campaign-builder plan before taking any spendful or write action.";
|
|
5645
|
+
}
|
|
5646
|
+
function campaignBuilderActiveWorkConversationStarters(input) {
|
|
5647
|
+
const starters = [];
|
|
5648
|
+
if (input.blockers.length > 0) {
|
|
5649
|
+
starters.push(
|
|
5650
|
+
`I found a blocker: ${input.blockers[0]}. Want me to stay in read-only diagnostics and prepare the fix path?`
|
|
5651
|
+
);
|
|
5652
|
+
}
|
|
5653
|
+
if (input.missingApprovals.length > 0) {
|
|
5654
|
+
starters.push(
|
|
5655
|
+
`You still owe approval for ${uniqueStrings(input.missingApprovals).join(", ")}. Want the exact approval packet before anything writes or spends?`
|
|
5656
|
+
);
|
|
5657
|
+
}
|
|
5658
|
+
if (input.state === "queued_or_running") {
|
|
5659
|
+
const buildRef = input.refs.find((ref) => ref.kind === "campaign_build");
|
|
5660
|
+
starters.push(buildRef ? `I can check campaign build ${buildRef.id} now and avoid starting a duplicate job.` : "I can check the running job status now and avoid starting duplicate work.");
|
|
5661
|
+
}
|
|
5662
|
+
if (input.state === "dry_run_complete") {
|
|
5663
|
+
starters.push("The dry run is complete. Want me to summarize blockers, artifacts, and the approval handoff?");
|
|
5664
|
+
}
|
|
5665
|
+
if (input.state === "ready_for_dry_run") {
|
|
5666
|
+
starters.push("Everything is ready for a safe dry run. Want me to run the no-spend preview first?");
|
|
5667
|
+
}
|
|
5668
|
+
if (input.state === "completed") {
|
|
5669
|
+
starters.push("The build looks complete. Want me to review rows, artifacts, and delivery gates before export or send approval?");
|
|
5670
|
+
}
|
|
5671
|
+
starters.push(`Next safe action: ${input.nextSafeAction}`);
|
|
5672
|
+
return uniqueStrings(starters).slice(0, 4);
|
|
5673
|
+
}
|
|
5674
|
+
function createCampaignBuilderOpenAiAgentHandoff(input) {
|
|
5675
|
+
const readOnlyPlanActions = input.plan?.mcpFlow.filter((step) => step.readOnly && !step.approvalRequired).map((step) => campaignBuilderMcpStepToActiveWorkAction(step, "Read-only Signaliz MCP continuation for the saved campaign-agent plan.")) ?? [];
|
|
5676
|
+
const routeSetupActions = readOnlyPlanActions.filter(
|
|
5677
|
+
(action) => action.tool === "gtm_provider_recipe_prepare" || action.tool === "gtm_provider_route_activate"
|
|
5678
|
+
);
|
|
5679
|
+
const safeReadActions = uniqueCampaignBuilderActiveWorkActions([
|
|
5680
|
+
input.nextSafeMcpAction,
|
|
5681
|
+
...routeSetupActions,
|
|
5682
|
+
...readOnlyPlanActions
|
|
5683
|
+
]);
|
|
5684
|
+
const approvalGatedActions = uniqueCampaignBuilderActiveWorkActions([
|
|
5685
|
+
...input.approvalPacket.mcp_handoffs.filter((action) => action.approval_required || !action.read_only),
|
|
5686
|
+
...input.plan?.mcpFlow.filter((step) => step.approvalRequired || !step.readOnly).map((step) => campaignBuilderMcpStepToActiveWorkAction(step, "Approval-gated Signaliz MCP continuation for the saved campaign-agent plan.")) ?? []
|
|
5687
|
+
]);
|
|
5688
|
+
const approvalTypes = uniqueStrings([
|
|
5689
|
+
...input.missingApprovals,
|
|
5690
|
+
...input.approvalPacket.requested_approval_types
|
|
5691
|
+
]);
|
|
5692
|
+
return {
|
|
5693
|
+
packet_version: "campaign-builder-openai-agent-handoff.v1",
|
|
5694
|
+
surface: "openai_agents_sdk",
|
|
5695
|
+
agent: {
|
|
5696
|
+
name: "Signaliz GTM Campaign Agent",
|
|
5697
|
+
handoff_description: "Owns safe, conversational GTM campaign planning and continuation across Signaliz MCP, SDK, attachments, URLs, customer tools, approvals, and sender/export gates.",
|
|
5698
|
+
instructions: [
|
|
5699
|
+
"Be warm, direct, and expert-level GTM. Translate the current state into plain operator language before proposing work.",
|
|
5700
|
+
"Start from the packet state, refs, evidence_context, approval_boundary, and next_safe_action. Do not ask for IDs already present in refs or summary.",
|
|
5701
|
+
"Use attachment_summary, url_summary, and operator_notes as first-class planning evidence, while honoring the evidence privacy_boundary and withheld raw fields.",
|
|
5702
|
+
"Prefer Signaliz-native, cached, remembered, and read-only MCP actions before provider calls. Never start duplicate jobs when a campaign_build or provider job is queued or running.",
|
|
5703
|
+
"Call only tools listed in safe_read_tools without approval. Treat approval_gated_tools as human-review surfaces, not permission to spend, write, export, load senders, deliver, or launch.",
|
|
5704
|
+
"When approval is missing, show the approval_packet and the exact missing approval scope before any side-effecting step."
|
|
5705
|
+
],
|
|
5706
|
+
output_contract: [
|
|
5707
|
+
"current_state: one concise sentence describing where the campaign work stands.",
|
|
5708
|
+
"evidence_used: attachment, URL, memory, route, or integration evidence used without exposing private raw rows or secrets.",
|
|
5709
|
+
"next_safe_mcp_action: the read-only Signaliz MCP action to run next, or null when none is safe.",
|
|
5710
|
+
"approval_boundary: the human approval scope required before spend, provider writes, delivery, export, sender load, or launch.",
|
|
5711
|
+
"operator_reply: conversational GTM guidance with blockers, risks, and the safest next move."
|
|
5712
|
+
]
|
|
5713
|
+
},
|
|
5714
|
+
context: {
|
|
5715
|
+
state: input.state,
|
|
5716
|
+
summary: input.summary,
|
|
5717
|
+
refs: input.refs,
|
|
5718
|
+
blockers: input.blockers,
|
|
5719
|
+
warnings: input.warnings,
|
|
5720
|
+
evidence_context: input.plan?.evidence ?? null,
|
|
5721
|
+
approval_packet: input.approvalPacket,
|
|
5722
|
+
approval_boundary: input.approvalBoundary,
|
|
5723
|
+
next_safe_action: input.nextSafeAction,
|
|
5724
|
+
conversation_starters: input.conversationStarters
|
|
5725
|
+
},
|
|
5726
|
+
tools: {
|
|
5727
|
+
mcp_server_label: "signaliz",
|
|
5728
|
+
remote_mcp_compatible: true,
|
|
5729
|
+
next_safe_mcp_action: input.nextSafeMcpAction,
|
|
5730
|
+
safe_read_tools: safeReadActions.map(
|
|
5731
|
+
(action) => campaignBuilderOpenAiAgentTool(action, "Safe read-only Signaliz MCP action available before approval.")
|
|
5732
|
+
),
|
|
5733
|
+
approval_gated_tools: approvalGatedActions.map(
|
|
5734
|
+
(action) => campaignBuilderOpenAiAgentTool(action, "Requires explicit human review before execution.")
|
|
5735
|
+
)
|
|
5736
|
+
},
|
|
5737
|
+
guardrails: {
|
|
5738
|
+
input: [
|
|
5739
|
+
"Reject or pause requests to expose raw private attachment text, raw rows, leads, emails, provider payloads, copy bodies, API keys, or secrets.",
|
|
5740
|
+
"Pause when the user asks to spend credits, write to a provider, export, load a sender, deliver, or launch without explicit approval scope."
|
|
5741
|
+
],
|
|
5742
|
+
tool: [
|
|
5743
|
+
"Read-only tools may run when they match safe_read_tools and their arguments match this packet.",
|
|
5744
|
+
"Any tool with approval_required=true or read_only=false requires human review and the approval_packet scope first."
|
|
5745
|
+
],
|
|
5746
|
+
human_review_required_for: approvalTypes,
|
|
5747
|
+
privacy: input.plan?.evidence?.privacy_boundary ?? "Use summarized context only. Do not expose raw private attachment text, raw rows, leads, emails, provider payloads, copy bodies, secrets, or credentials."
|
|
5748
|
+
}
|
|
5749
|
+
};
|
|
5750
|
+
}
|
|
5751
|
+
function campaignBuilderOpenAiAgentTool(action, purpose) {
|
|
5752
|
+
return {
|
|
5753
|
+
id: action.id,
|
|
5754
|
+
type: "mcp",
|
|
5755
|
+
server_label: "signaliz",
|
|
5756
|
+
name: action.tool,
|
|
5757
|
+
arguments: action.arguments,
|
|
5758
|
+
read_only: action.read_only,
|
|
5759
|
+
approval_required: action.approval_required,
|
|
5760
|
+
purpose,
|
|
5761
|
+
safety: action.safety
|
|
5762
|
+
};
|
|
5763
|
+
}
|
|
5764
|
+
function uniqueCampaignBuilderActiveWorkActions(actions) {
|
|
5765
|
+
const seen = /* @__PURE__ */ new Set();
|
|
5766
|
+
const unique = [];
|
|
5767
|
+
for (const action of actions) {
|
|
5768
|
+
if (!action) continue;
|
|
5769
|
+
const key = `${action.id}:${action.tool}`;
|
|
5770
|
+
if (seen.has(key)) continue;
|
|
5771
|
+
seen.add(key);
|
|
5772
|
+
unique.push(action);
|
|
5773
|
+
}
|
|
5774
|
+
return unique;
|
|
5775
|
+
}
|
|
5776
|
+
function activeWorkStatus(record) {
|
|
5777
|
+
return stringValue(record.status ?? record.state ?? record.phase);
|
|
5778
|
+
}
|
|
5038
5779
|
function campaignBuilderBuiltInForRoute(route) {
|
|
5039
5780
|
return Object.entries(CAMPAIGN_BUILDER_BUILT_IN_ROUTE_IDS).find(([, routeId]) => route.id === routeId)?.[0];
|
|
5040
5781
|
}
|
|
@@ -7831,6 +8572,36 @@ function recordsFromParams(params) {
|
|
|
7831
8572
|
if (params.input) return { input: params.input };
|
|
7832
8573
|
return { input: {} };
|
|
7833
8574
|
}
|
|
8575
|
+
function toFusionConfig(params) {
|
|
8576
|
+
return {
|
|
8577
|
+
system_prompt: params.systemPrompt || params.system_prompt,
|
|
8578
|
+
user_template: params.userTemplate || params.user_template || params.prompt,
|
|
8579
|
+
preset: params.preset,
|
|
8580
|
+
temperature: params.temperature,
|
|
8581
|
+
max_tool_calls: params.maxToolCalls || params.max_tool_calls,
|
|
8582
|
+
max_tokens: params.maxTokens || params.max_tokens,
|
|
8583
|
+
timeout_ms: params.timeoutMs || params.timeout_ms,
|
|
8584
|
+
output_fields: params.outputFields || params.output_fields || [{ name: "response", type: "text", description: "Structured Fusion enrichment result" }]
|
|
8585
|
+
};
|
|
8586
|
+
}
|
|
8587
|
+
function toFusionSpendControls(params) {
|
|
8588
|
+
const controls = {};
|
|
8589
|
+
const dryRun = params.dryRun ?? params.dry_run;
|
|
8590
|
+
const confirmSpend = params.confirmSpend ?? params.confirm_spend;
|
|
8591
|
+
const maxCredits = params.maxCredits ?? params.max_credits;
|
|
8592
|
+
const maxCostUsd = params.maxCostUsd ?? params.max_cost_usd;
|
|
8593
|
+
if (dryRun !== void 0) controls.dry_run = dryRun;
|
|
8594
|
+
if (confirmSpend !== void 0) controls.confirm_spend = confirmSpend;
|
|
8595
|
+
if (maxCredits !== void 0) controls.max_credits = maxCredits;
|
|
8596
|
+
if (maxCostUsd !== void 0) controls.max_cost_usd = maxCostUsd;
|
|
8597
|
+
return controls;
|
|
8598
|
+
}
|
|
8599
|
+
function fusionRecordsFromParams(params) {
|
|
8600
|
+
const records = params.records || params.inputs;
|
|
8601
|
+
if (records?.length) return { records };
|
|
8602
|
+
if (params.input) return { input: params.input };
|
|
8603
|
+
return { input: {} };
|
|
8604
|
+
}
|
|
7834
8605
|
var Ai = class {
|
|
7835
8606
|
constructor(client) {
|
|
7836
8607
|
this.client = client;
|
|
@@ -7864,6 +8635,33 @@ var Ai = class {
|
|
|
7864
8635
|
raw: data
|
|
7865
8636
|
};
|
|
7866
8637
|
}
|
|
8638
|
+
/**
|
|
8639
|
+
* Plan or run experimental AI Enrichment Fusion with explicit spend controls.
|
|
8640
|
+
*/
|
|
8641
|
+
async fusion(params) {
|
|
8642
|
+
if (!params.prompt && !params.userTemplate && !params.user_template) {
|
|
8643
|
+
throw new Error("prompt or userTemplate is required.");
|
|
8644
|
+
}
|
|
8645
|
+
const data = await this.client.post("ai-enrichment-fusion", {
|
|
8646
|
+
...fusionRecordsFromParams(params),
|
|
8647
|
+
config: toFusionConfig(params),
|
|
8648
|
+
...toFusionSpendControls(params)
|
|
8649
|
+
});
|
|
8650
|
+
return {
|
|
8651
|
+
success: data.success ?? false,
|
|
8652
|
+
capability: data.capability ?? "ai_enrichment_fusion",
|
|
8653
|
+
displayName: data.display_name ?? "AI Enrichment Fusion",
|
|
8654
|
+
results: data.results ?? [],
|
|
8655
|
+
creditsUsed: data.total_credits_used ?? data.credits_used ?? 0,
|
|
8656
|
+
model: data.model,
|
|
8657
|
+
fusion: data.fusion,
|
|
8658
|
+
tokensUsed: data.tokens_used ?? 0,
|
|
8659
|
+
costUsd: data.cost_usd ?? 0,
|
|
8660
|
+
costSummary: data.cost_summary,
|
|
8661
|
+
billingMetadata: data.billing_metadata,
|
|
8662
|
+
raw: data
|
|
8663
|
+
};
|
|
8664
|
+
}
|
|
7867
8665
|
};
|
|
7868
8666
|
|
|
7869
8667
|
// src/resources/gtm-kernel.ts
|
|
@@ -8403,6 +9201,24 @@ var GtmKernel = class {
|
|
|
8403
9201
|
limit: input.limit
|
|
8404
9202
|
});
|
|
8405
9203
|
}
|
|
9204
|
+
/** Predict booked-meeting likelihood for uploaded, inline, or MCP-sourced lead rows without persisting raw rows. */
|
|
9205
|
+
async predictMeetingLikelihood(input) {
|
|
9206
|
+
return this.callMcp("gtm_predict_meeting_likelihood", {
|
|
9207
|
+
lead_rows: input.leadRows,
|
|
9208
|
+
input_source: input.inputSource,
|
|
9209
|
+
campaign_id: input.campaignId,
|
|
9210
|
+
campaign_build_id: input.campaignBuildId,
|
|
9211
|
+
days: input.days,
|
|
9212
|
+
feedback_limit: input.feedbackLimit,
|
|
9213
|
+
include_features: input.includeFeatures,
|
|
9214
|
+
include_global: input.includeGlobal,
|
|
9215
|
+
min_feedback_events: input.minFeedbackEvents,
|
|
9216
|
+
min_historical_feature_sample_size: input.minHistoricalFeatureSampleSize,
|
|
9217
|
+
min_workspace_count: input.minWorkspaceCount,
|
|
9218
|
+
min_privacy_k: input.minPrivacyK,
|
|
9219
|
+
limit: input.limit
|
|
9220
|
+
});
|
|
9221
|
+
}
|
|
8406
9222
|
/** Rank provider-chain, ICP, source, copy, and sequence failure patterns without writing raw lead data. */
|
|
8407
9223
|
async failurePatterns(options = {}) {
|
|
8408
9224
|
return this.callMcp("gtm_brain_failure_patterns", {
|
|
@@ -9018,6 +9834,70 @@ function compact2(value) {
|
|
|
9018
9834
|
return out;
|
|
9019
9835
|
}
|
|
9020
9836
|
|
|
9837
|
+
// src/resources/public-ground-truth.ts
|
|
9838
|
+
var PublicGroundTruth = class {
|
|
9839
|
+
constructor(client) {
|
|
9840
|
+
this.client = client;
|
|
9841
|
+
}
|
|
9842
|
+
/**
|
|
9843
|
+
* Search the public-ground-truth cache by company/name/domain/native ID,
|
|
9844
|
+
* or by plain-language industry + location.
|
|
9845
|
+
* Results use the same snake_case wire shape returned by the hosted MCP API.
|
|
9846
|
+
*/
|
|
9847
|
+
async search(params) {
|
|
9848
|
+
return this.client.mcp("tools/call", {
|
|
9849
|
+
name: "search_public_ground_truth",
|
|
9850
|
+
arguments: {
|
|
9851
|
+
query: params.query ?? params.search,
|
|
9852
|
+
industry: params.industry,
|
|
9853
|
+
location: params.location,
|
|
9854
|
+
source_id: params.sourceId ?? params.source_id,
|
|
9855
|
+
entity_type: params.entityType ?? params.entity_type,
|
|
9856
|
+
native_id: params.nativeId ?? params.native_id,
|
|
9857
|
+
entity_name: params.entityName ?? params.entity_name,
|
|
9858
|
+
domain: params.domain,
|
|
9859
|
+
website_url: params.websiteUrl ?? params.website_url,
|
|
9860
|
+
phone: params.phone,
|
|
9861
|
+
email: params.email,
|
|
9862
|
+
city: params.city,
|
|
9863
|
+
state: params.state,
|
|
9864
|
+
postal_code: params.postalCode ?? params.postal_code,
|
|
9865
|
+
country: params.country,
|
|
9866
|
+
source_url: params.sourceUrl ?? params.source_url,
|
|
9867
|
+
join_keys: params.joinKeys ?? params.join_keys,
|
|
9868
|
+
row_data: params.rowData ?? params.row_data,
|
|
9869
|
+
naics: params.naics,
|
|
9870
|
+
industry_code: params.industryCode ?? params.industry_code,
|
|
9871
|
+
industry_type: params.industryType ?? params.industry_type,
|
|
9872
|
+
year: params.year,
|
|
9873
|
+
quarter: params.quarter,
|
|
9874
|
+
area_fips: params.areaFips ?? params.area_fips,
|
|
9875
|
+
geo_id: params.geoId ?? params.geo_id,
|
|
9876
|
+
own_code: params.ownCode ?? params.own_code,
|
|
9877
|
+
source_updated_after: params.sourceUpdatedAfter ?? params.source_updated_after,
|
|
9878
|
+
source_updated_before: params.sourceUpdatedBefore ?? params.source_updated_before,
|
|
9879
|
+
observed_after: params.observedAfter ?? params.observed_after,
|
|
9880
|
+
observed_before: params.observedBefore ?? params.observed_before,
|
|
9881
|
+
limit: params.limit,
|
|
9882
|
+
offset: params.offset
|
|
9883
|
+
}
|
|
9884
|
+
});
|
|
9885
|
+
}
|
|
9886
|
+
/**
|
|
9887
|
+
* List available public-ground-truth cache sources and their join-key metadata.
|
|
9888
|
+
*/
|
|
9889
|
+
async listSources(params = {}) {
|
|
9890
|
+
return this.client.mcp("tools/call", {
|
|
9891
|
+
name: "list_public_ground_truth_sources",
|
|
9892
|
+
arguments: {
|
|
9893
|
+
query: params.query ?? params.search,
|
|
9894
|
+
status: params.status,
|
|
9895
|
+
limit: params.limit
|
|
9896
|
+
}
|
|
9897
|
+
});
|
|
9898
|
+
}
|
|
9899
|
+
};
|
|
9900
|
+
|
|
9021
9901
|
// src/index.ts
|
|
9022
9902
|
var MCP_TOOL_CACHE_TTL_MS = 3e4;
|
|
9023
9903
|
function inferMcpToolCategory(toolName) {
|
|
@@ -9060,6 +9940,7 @@ function inferMcpToolCategory(toolName) {
|
|
|
9060
9940
|
}
|
|
9061
9941
|
if (toolName.includes("icp")) return "icp";
|
|
9062
9942
|
if (toolName.startsWith("ai_clean_")) return "data_cleaning";
|
|
9943
|
+
if (toolName.includes("public_ground_truth")) return "public_data";
|
|
9063
9944
|
if (toolName.includes("system") || toolName.includes("workflow")) return "automation";
|
|
9064
9945
|
if (toolName.includes("agent") || toolName.includes("platform_health") || toolName === "discover_capabilities") return "observability";
|
|
9065
9946
|
return void 0;
|
|
@@ -9111,6 +9992,7 @@ var Signaliz = class {
|
|
|
9111
9992
|
this.ops = new Ops(this.client);
|
|
9112
9993
|
this.ai = new Ai(this.client);
|
|
9113
9994
|
this.gtm = new GtmKernel(this.client);
|
|
9995
|
+
this.publicGroundTruth = new PublicGroundTruth(this.client);
|
|
9114
9996
|
}
|
|
9115
9997
|
/** Get current workspace info including credits */
|
|
9116
9998
|
async getWorkspace() {
|
|
@@ -9216,6 +10098,7 @@ export {
|
|
|
9216
10098
|
CampaignBuilderAgent,
|
|
9217
10099
|
createCampaignBuilderAgentPlan,
|
|
9218
10100
|
createCampaignBuilderReadiness,
|
|
10101
|
+
createCampaignBuilderActiveWorkContext,
|
|
9219
10102
|
createCampaignBuilderProofReceipt,
|
|
9220
10103
|
getMissingCampaignBuilderApprovals,
|
|
9221
10104
|
createCampaignBuilderApproval,
|
|
@@ -9233,5 +10116,6 @@ export {
|
|
|
9233
10116
|
Ops,
|
|
9234
10117
|
Ai,
|
|
9235
10118
|
GtmKernel,
|
|
10119
|
+
PublicGroundTruth,
|
|
9236
10120
|
Signaliz
|
|
9237
10121
|
};
|