@signaliz/sdk 1.0.18 → 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/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
package/dist/mcp-config.js
CHANGED
|
@@ -479,6 +479,38 @@ var Signals = class {
|
|
|
479
479
|
constructor(client) {
|
|
480
480
|
this.client = client;
|
|
481
481
|
}
|
|
482
|
+
/** Turn the strongest supported company signal into three complete, evidence-backed emails. */
|
|
483
|
+
async signalToCopy(params) {
|
|
484
|
+
const data = await this.client.post("api/v1/signal-to-copy", {
|
|
485
|
+
company_domain: params.companyDomain,
|
|
486
|
+
person_name: params.personName,
|
|
487
|
+
title: params.title,
|
|
488
|
+
campaign_offer: params.campaignOffer,
|
|
489
|
+
research_prompt: params.researchPrompt
|
|
490
|
+
});
|
|
491
|
+
return {
|
|
492
|
+
success: data.success ?? true,
|
|
493
|
+
strongestSignal: data.strongest_signal ?? "",
|
|
494
|
+
whyNow: data.why_now ?? "",
|
|
495
|
+
subjectLine: data.subject_line ?? "",
|
|
496
|
+
openingLine: data.opening_line ?? "",
|
|
497
|
+
confidence: data.confidence ?? 0,
|
|
498
|
+
evidenceUrl: data.evidence_url ?? "",
|
|
499
|
+
researchPrompt: data.research_prompt,
|
|
500
|
+
variations: (data.variations ?? []).map((v) => ({
|
|
501
|
+
style: v.style,
|
|
502
|
+
subjectLine: v.subject_line ?? "",
|
|
503
|
+
openingLine: v.opening_line ?? "",
|
|
504
|
+
cta: v.cta ?? "",
|
|
505
|
+
prediction: v.prediction,
|
|
506
|
+
email: v.email
|
|
507
|
+
}))
|
|
508
|
+
};
|
|
509
|
+
}
|
|
510
|
+
/** @deprecated Use signalToCopy. Retained for compatibility. */
|
|
511
|
+
async personalize(params) {
|
|
512
|
+
return this.signalToCopy(params);
|
|
513
|
+
}
|
|
482
514
|
/** Enrich a company with actionable signals (V1) */
|
|
483
515
|
async enrich(params) {
|
|
484
516
|
const args = {
|
|
@@ -487,6 +519,9 @@ var Signals = class {
|
|
|
487
519
|
if (params.domain) args.domain = params.domain;
|
|
488
520
|
if (params.researchPrompt) args.research_prompt = params.researchPrompt;
|
|
489
521
|
if (params.signalTypes) args.signal_types = params.signalTypes;
|
|
522
|
+
if (params.targetSignalCount) args.target_signal_count = params.targetSignalCount;
|
|
523
|
+
if (params.lookbackDays) args.lookback_days = params.lookbackDays;
|
|
524
|
+
if (params.enableDeepSearch !== void 0) args.enable_deep_search = params.enableDeepSearch;
|
|
490
525
|
const data = await this.client.mcp("tools/call", {
|
|
491
526
|
name: "enrich_company_signals",
|
|
492
527
|
arguments: args
|
|
@@ -496,6 +531,16 @@ var Signals = class {
|
|
|
496
531
|
signals: (data.signals ?? []).map((s) => ({
|
|
497
532
|
title: s.title,
|
|
498
533
|
signalType: s.signal_type,
|
|
534
|
+
sourceType: s.source_type ?? s.signal_classification?.label ?? "unknown",
|
|
535
|
+
sourceProvenance: s.source_provenance ?? s.metadata?.source_provenance ?? null,
|
|
536
|
+
signalFamily: s.signal_family ?? s.signal_type ?? null,
|
|
537
|
+
signalEventType: s.signal_event_type ?? s.signal_classification?.slug ?? null,
|
|
538
|
+
signalEventLabel: s.signal_event_label ?? s.signal_classification?.label ?? null,
|
|
539
|
+
signalClassification: s.signal_classification ? {
|
|
540
|
+
label: s.signal_classification.label,
|
|
541
|
+
slug: s.signal_classification.slug,
|
|
542
|
+
rationale: s.signal_classification.rationale
|
|
543
|
+
} : null,
|
|
499
544
|
confidenceScore: s.confidence_score ?? 0,
|
|
500
545
|
detectedAt: s.detected_at ?? "",
|
|
501
546
|
url: s.url,
|
|
@@ -536,8 +581,17 @@ var Signals = class {
|
|
|
536
581
|
content: s.content ?? "",
|
|
537
582
|
date: s.date ?? null,
|
|
538
583
|
sourceUrl: s.source_url ?? null,
|
|
539
|
-
sourceType: s.source_type ?? "unknown",
|
|
540
|
-
|
|
584
|
+
sourceType: s.source_type ?? s.signal_classification?.label ?? "unknown",
|
|
585
|
+
sourceProvenance: s.source_provenance ?? s.metadata?.source_provenance ?? null,
|
|
586
|
+
signalFamily: s.signal_family ?? s.type ?? null,
|
|
587
|
+
signalEventType: s.signal_event_type ?? s.signal_classification?.slug ?? null,
|
|
588
|
+
signalEventLabel: s.signal_event_label ?? s.signal_classification?.label ?? null,
|
|
589
|
+
confidence: s.confidence ?? null,
|
|
590
|
+
signalClassification: s.signal_classification ? {
|
|
591
|
+
label: s.signal_classification.label,
|
|
592
|
+
slug: s.signal_classification.slug,
|
|
593
|
+
rationale: s.signal_classification.rationale
|
|
594
|
+
} : null
|
|
541
595
|
})),
|
|
542
596
|
signalCount: data.signal_count ?? 0,
|
|
543
597
|
intelligence: data.intelligence ? {
|
|
@@ -580,6 +634,58 @@ var Signals = class {
|
|
|
580
634
|
}
|
|
581
635
|
};
|
|
582
636
|
}
|
|
637
|
+
/** Plan or run experimental Signal Fusion with explicit spend controls. */
|
|
638
|
+
async fusion(params) {
|
|
639
|
+
const args = {};
|
|
640
|
+
if (params.companyName) args.company_name = params.companyName;
|
|
641
|
+
if (params.domain) args.domain = params.domain;
|
|
642
|
+
if (params.companyDomain) args.company_domain = params.companyDomain;
|
|
643
|
+
if (params.linkedinUrl) args.linkedin_url = params.linkedinUrl;
|
|
644
|
+
if (params.companies) args.companies = params.companies;
|
|
645
|
+
if (params.preset) args.preset = params.preset;
|
|
646
|
+
if (params.researchPrompt) args.research_prompt = params.researchPrompt;
|
|
647
|
+
if (params.signalTypes) args.signal_types = params.signalTypes;
|
|
648
|
+
if (params.lookbackDays) args.lookback_days = params.lookbackDays;
|
|
649
|
+
if (params.targetSignalCount) args.target_signal_count = params.targetSignalCount;
|
|
650
|
+
if (params.maxToolCalls) args.max_tool_calls = params.maxToolCalls;
|
|
651
|
+
if (params.maxTokens) args.max_tokens = params.maxTokens;
|
|
652
|
+
if (params.timeoutMs) args.timeout_ms = params.timeoutMs;
|
|
653
|
+
const dryRun = params.dryRun ?? params.dry_run;
|
|
654
|
+
const confirmSpend = params.confirmSpend ?? params.confirm_spend;
|
|
655
|
+
const maxCredits = params.maxCredits ?? params.max_credits;
|
|
656
|
+
const maxCostUsd = params.maxCostUsd ?? params.max_cost_usd;
|
|
657
|
+
if (dryRun !== void 0) args.dry_run = dryRun;
|
|
658
|
+
if (confirmSpend !== void 0) args.confirm_spend = confirmSpend;
|
|
659
|
+
if (maxCredits !== void 0) args.max_credits = maxCredits;
|
|
660
|
+
if (maxCostUsd !== void 0) args.max_cost_usd = maxCostUsd;
|
|
661
|
+
const data = await this.client.post("signal-fusion", args);
|
|
662
|
+
return {
|
|
663
|
+
success: data.success ?? false,
|
|
664
|
+
capability: data.capability ?? "signal_fusion",
|
|
665
|
+
displayName: data.display_name ?? "Signal Fusion",
|
|
666
|
+
company: data.company,
|
|
667
|
+
signals: (data.signals ?? []).map((s) => ({
|
|
668
|
+
id: s.id,
|
|
669
|
+
title: s.title,
|
|
670
|
+
type: s.type,
|
|
671
|
+
content: s.content ?? "",
|
|
672
|
+
date: s.date ?? null,
|
|
673
|
+
sourceUrl: s.source_url ?? null,
|
|
674
|
+
sourceType: s.source_type ?? "unknown",
|
|
675
|
+
confidence: s.confidence ?? null
|
|
676
|
+
})),
|
|
677
|
+
signalCount: data.signal_count ?? data.signals?.length ?? 0,
|
|
678
|
+
results: data.results ?? [],
|
|
679
|
+
model: data.model,
|
|
680
|
+
fusion: data.fusion,
|
|
681
|
+
costUsd: data.cost_usd ?? 0,
|
|
682
|
+
tokensUsed: data.tokens_used ?? 0,
|
|
683
|
+
costSummary: data.cost_summary,
|
|
684
|
+
creditsUsed: data.total_credits_used ?? data.credits_used ?? 0,
|
|
685
|
+
billingMetadata: data.billing_metadata,
|
|
686
|
+
raw: data
|
|
687
|
+
};
|
|
688
|
+
}
|
|
583
689
|
};
|
|
584
690
|
|
|
585
691
|
// src/resources/systems.ts
|
|
@@ -1018,6 +1124,7 @@ function mapCustomerRowCounts(value) {
|
|
|
1018
1124
|
acceptedRows: numberOrNull(record.accepted_rows) ?? void 0,
|
|
1019
1125
|
usableRows: numberOrNull(record.usable_rows) ?? void 0,
|
|
1020
1126
|
copiedRows: numberOrNull(record.copied_rows) ?? void 0,
|
|
1127
|
+
copySkippedRows: numberOrNull(record.copy_skipped_rows) ?? void 0,
|
|
1021
1128
|
approvalReadyRows: numberOrNull(record.approval_ready_rows) ?? void 0,
|
|
1022
1129
|
qaReadyRows: numberOrNull(record.qa_ready_rows) ?? void 0,
|
|
1023
1130
|
deliveredRows: numberOrNull(record.delivered_rows) ?? void 0,
|
|
@@ -1254,7 +1361,8 @@ function buildArgs(request) {
|
|
|
1254
1361
|
geographies: request.icp.geographies,
|
|
1255
1362
|
keywords: request.icp.keywords,
|
|
1256
1363
|
exclusions: request.icp.exclusions,
|
|
1257
|
-
require_verified_email: request.icp.requireVerifiedEmail
|
|
1364
|
+
require_verified_email: request.icp.requireVerifiedEmail,
|
|
1365
|
+
persona_expansion_mode: request.icp.personaExpansionMode
|
|
1258
1366
|
};
|
|
1259
1367
|
}
|
|
1260
1368
|
if (request.policy) {
|
|
@@ -1294,6 +1402,7 @@ function buildArgs(request) {
|
|
|
1294
1402
|
} : void 0,
|
|
1295
1403
|
sequence_steps: request.copy.sequenceSteps,
|
|
1296
1404
|
copy_schema: request.copy.copySchema,
|
|
1405
|
+
evidence_mode: request.copy.evidenceMode,
|
|
1297
1406
|
banned_phrases: request.copy.bannedPhrases,
|
|
1298
1407
|
approval_required: request.copy.approvalRequired,
|
|
1299
1408
|
quality_tier: request.copy.qualityTier
|
|
@@ -1350,7 +1459,8 @@ var DEFAULT_SIGNALIZ_CAMPAIGN_BUILDER_DEFAULTS = {
|
|
|
1350
1459
|
copy: {
|
|
1351
1460
|
enabled: true,
|
|
1352
1461
|
tone: "direct",
|
|
1353
|
-
maxBodyWords: 125
|
|
1462
|
+
maxBodyWords: 125,
|
|
1463
|
+
evidenceMode: "signal_led"
|
|
1354
1464
|
},
|
|
1355
1465
|
delivery: {
|
|
1356
1466
|
enabled: true,
|
|
@@ -1407,7 +1517,8 @@ var CAMPAIGN_BUILDER_OPERATING_PLAYBOOKS = [
|
|
|
1407
1517
|
"Block export when required identity, company, or email fields are missing."
|
|
1408
1518
|
],
|
|
1409
1519
|
activationBoundary: "Cache inventory is read-only. Fresh sourcing, cache writes, export, and sender loading require explicit approval.",
|
|
1410
|
-
memoryKeywords: ["cache inventory", "large list", "unique emails", "top-up sourcing", "source metadata"]
|
|
1520
|
+
memoryKeywords: ["cache inventory", "large list", "unique emails", "top-up sourcing", "source metadata"],
|
|
1521
|
+
knowledgeSources: ["data-ops/contact-data-lifecycle", "data-ops/credit-optimization-guide", "gtm/data-quality-ops", "gtm/lead-generation-strategies"]
|
|
1411
1522
|
},
|
|
1412
1523
|
{
|
|
1413
1524
|
slug: "net-new-suppressed-list",
|
|
@@ -1432,7 +1543,8 @@ var CAMPAIGN_BUILDER_OPERATING_PLAYBOOKS = [
|
|
|
1432
1543
|
"Do not describe rows as fully qualified when the approved path only proves net-new email status."
|
|
1433
1544
|
],
|
|
1434
1545
|
activationBoundary: "Suppression review must pass before export, upload, CRM sync, sender load, or sequence launch.",
|
|
1435
|
-
memoryKeywords: ["suppression", "net-new", "prior email overlap", "domain review", "provenance-rich QA"]
|
|
1546
|
+
memoryKeywords: ["suppression", "net-new", "prior email overlap", "domain review", "provenance-rich QA"],
|
|
1547
|
+
knowledgeSources: ["gtm/data-quality-ops", "data-ops/contact-data-lifecycle", "gtm/outbound-sequencing"]
|
|
1436
1548
|
},
|
|
1437
1549
|
{
|
|
1438
1550
|
slug: "proof-first-vertical-gate",
|
|
@@ -1457,7 +1569,8 @@ var CAMPAIGN_BUILDER_OPERATING_PLAYBOOKS = [
|
|
|
1457
1569
|
"Contact fit should meet the configured threshold before email finding or copy generation."
|
|
1458
1570
|
],
|
|
1459
1571
|
activationBoundary: "Proof gates are required before contact spend, copy, export, or external writes.",
|
|
1460
|
-
memoryKeywords: ["proof gate", "vertical exclusion", "company before contact", "pass review fail", "fit threshold"]
|
|
1572
|
+
memoryKeywords: ["proof gate", "vertical exclusion", "company before contact", "pass review fail", "fit threshold"],
|
|
1573
|
+
knowledgeSources: ["gtm/icp-design-framework", "gtm/strategy/scoring.yaml", "gtm/advanced/account-prioritization-frameworks", "gtm/advanced/predictive-lead-scoring", "gtm/verticals"]
|
|
1461
1574
|
},
|
|
1462
1575
|
{
|
|
1463
1576
|
slug: "signal-led-copy-approval",
|
|
@@ -1482,7 +1595,8 @@ var CAMPAIGN_BUILDER_OPERATING_PLAYBOOKS = [
|
|
|
1482
1595
|
"Destination fields must remain blocked until approval metadata is present."
|
|
1483
1596
|
],
|
|
1484
1597
|
activationBoundary: "Copy readiness is not delivery approval. Export, sync, sender load, and launch require a separate human-approved gate.",
|
|
1485
|
-
memoryKeywords: ["company signals", "evidence-fed copy", "why now", "copy blocker", "approval gate"]
|
|
1598
|
+
memoryKeywords: ["company signals", "evidence-fed copy", "why now", "copy blocker", "approval gate"],
|
|
1599
|
+
knowledgeSources: ["gtm/email-personalization", "gtm/signal-based-selling", "gtm/signal-combination-matrix", "gtm/advanced/buyer-journey-mapping"]
|
|
1486
1600
|
},
|
|
1487
1601
|
{
|
|
1488
1602
|
slug: "domain-first-recovery",
|
|
@@ -1507,7 +1621,8 @@ var CAMPAIGN_BUILDER_OPERATING_PLAYBOOKS = [
|
|
|
1507
1621
|
"Target count means final held rows, not raw sourced rows."
|
|
1508
1622
|
],
|
|
1509
1623
|
activationBoundary: "Domain recovery informs sourcing. Contact enrichment, paid qualification, and export still require approved gates.",
|
|
1510
|
-
memoryKeywords: ["domain-first", "yield modeling", "attrition", "accepted domains", "gap fill"]
|
|
1624
|
+
memoryKeywords: ["domain-first", "yield modeling", "attrition", "accepted domains", "gap fill"],
|
|
1625
|
+
knowledgeSources: ["gtm/lead-generation-strategies", "data-ops/enrichment-waterfall-strategy", "data-ops/credit-optimization-guide", "gtm/territory-account-planning"]
|
|
1511
1626
|
},
|
|
1512
1627
|
{
|
|
1513
1628
|
slug: "table-workflow-handoff",
|
|
@@ -1532,7 +1647,112 @@ var CAMPAIGN_BUILDER_OPERATING_PLAYBOOKS = [
|
|
|
1532
1647
|
"Provider route activation must dry-run before any external write."
|
|
1533
1648
|
],
|
|
1534
1649
|
activationBoundary: "MCP, webhook, managed integration, and destination routes remain dry-run until the reviewed route and campaign are approved.",
|
|
1535
|
-
memoryKeywords: ["table workflow", "request ready", "provider status", "export blocker", "BYO integration"]
|
|
1650
|
+
memoryKeywords: ["table workflow", "request ready", "provider status", "export blocker", "BYO integration"],
|
|
1651
|
+
knowledgeSources: ["gtm/multi-channel-orchestration", "data-ops/enrichment-waterfall-strategy", "recipes/clay-gtm-webhook-recipe", "systems/blueprints/multi-channel-orchestration"]
|
|
1652
|
+
},
|
|
1653
|
+
{
|
|
1654
|
+
slug: "icp-persona-segmentation",
|
|
1655
|
+
label: "ICP And Persona Segmentation",
|
|
1656
|
+
whenToUse: [
|
|
1657
|
+
"The brief has a broad market, multiple personas, or unclear buying committee.",
|
|
1658
|
+
"The campaign should rank account tiers, persona fit, vertical nuance, and exclusions before sourcing at scale."
|
|
1659
|
+
],
|
|
1660
|
+
sequence: [
|
|
1661
|
+
"Convert the brief into account tiers, persona roles, buying committee influence, and explicit exclusions.",
|
|
1662
|
+
"Choose vertical guidance only from the customer-safe GTM library and keep internal platform docs out of prompts.",
|
|
1663
|
+
"Score accounts before contacts, then score contacts against persona, seniority, function, geography, and intent fit.",
|
|
1664
|
+
"Return segment counts and review buckets before spend, copy, export, or launch."
|
|
1665
|
+
],
|
|
1666
|
+
requiredFields: {
|
|
1667
|
+
segment: ["segment_name", "tier", "persona_priority", "buying_committee_role", "fit_reason", "exclusion_reason"],
|
|
1668
|
+
scoring: ["account_fit_score", "persona_fit_score", "segment_confidence", "review_bucket"]
|
|
1669
|
+
},
|
|
1670
|
+
qualityGates: [
|
|
1671
|
+
"Do not treat adjacent personas or verticals as matches unless the brief allows them.",
|
|
1672
|
+
"Keep ICP, persona, and exclusion evidence visible in the proof packet.",
|
|
1673
|
+
"Low-confidence segments route to review before contact discovery or copy."
|
|
1674
|
+
],
|
|
1675
|
+
activationBoundary: "Segmentation is planning guidance. Paid sourcing, enrichment, export, and launch require the normal approval gates.",
|
|
1676
|
+
memoryKeywords: ["ICP design", "persona segmentation", "buying committee", "account tiers", "fit scoring", "vertical nuance"],
|
|
1677
|
+
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"]
|
|
1678
|
+
},
|
|
1679
|
+
{
|
|
1680
|
+
slug: "buying-signal-prioritization",
|
|
1681
|
+
label: "Buying Signal Prioritization",
|
|
1682
|
+
whenToUse: [
|
|
1683
|
+
"The campaign depends on timing, intent, trigger events, or account prioritization.",
|
|
1684
|
+
"The operator wants why-now proof instead of generic list generation."
|
|
1685
|
+
],
|
|
1686
|
+
sequence: [
|
|
1687
|
+
"Map the campaign goal to signal families, trigger freshness, and buyer-journey stage.",
|
|
1688
|
+
"Rank signals by relevance, recency, source quality, and persona-specific actionability.",
|
|
1689
|
+
"Attach evidence URLs or evidence summaries without exposing private memory rows.",
|
|
1690
|
+
"Use signal strength to decide source order, copy angle, and review priority."
|
|
1691
|
+
],
|
|
1692
|
+
requiredFields: {
|
|
1693
|
+
signal: ["signal_type", "signal_date", "signal_source", "why_now", "signal_confidence", "buyer_stage"],
|
|
1694
|
+
prioritization: ["priority_score", "priority_reason", "next_best_action", "review_reason"]
|
|
1695
|
+
},
|
|
1696
|
+
qualityGates: [
|
|
1697
|
+
"Do not use stale, unsupported, or weak signals as personalization proof.",
|
|
1698
|
+
"Signal fit cannot override hard ICP, geography, suppression, or verified-email gates.",
|
|
1699
|
+
"Rows with uncertain why-now evidence must stay review-only."
|
|
1700
|
+
],
|
|
1701
|
+
activationBoundary: "Signal ranking can prioritize review and copy. It does not approve outreach, sender loading, exports, or sends.",
|
|
1702
|
+
memoryKeywords: ["buying signals", "intent data", "funding trigger", "new executive", "tech adoption", "buyer journey", "why now"],
|
|
1703
|
+
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"]
|
|
1704
|
+
},
|
|
1705
|
+
{
|
|
1706
|
+
slug: "multi-channel-sequence-fit",
|
|
1707
|
+
label: "Multi-Channel Sequence Fit",
|
|
1708
|
+
whenToUse: [
|
|
1709
|
+
"The campaign needs email, LinkedIn, call, webhook, CRM, or sequencer coordination.",
|
|
1710
|
+
"Copy and delivery should adapt by persona, channel, deliverability risk, and proof strength."
|
|
1711
|
+
],
|
|
1712
|
+
sequence: [
|
|
1713
|
+
"Choose channel mix from persona, deal motion, evidence strength, deliverability constraints, and connected destination readiness.",
|
|
1714
|
+
"Draft sequence logic with email, LinkedIn, call, and task handoffs only where supported by the approved destination.",
|
|
1715
|
+
"Keep copy concise, proof-backed, channel-specific, and reviewable before delivery.",
|
|
1716
|
+
"Run deliverability and destination readiness checks before sender load or launch approval."
|
|
1717
|
+
],
|
|
1718
|
+
requiredFields: {
|
|
1719
|
+
channel: ["channel", "touch_number", "persona_context", "message_angle", "channel_blocker", "approval_status"],
|
|
1720
|
+
deliverability: ["verified_email", "domain_risk", "send_window", "unsubscribe_risk", "sender_ready"]
|
|
1721
|
+
},
|
|
1722
|
+
qualityGates: [
|
|
1723
|
+
"Email copy must be row-supported and under the configured campaign tone/length limits.",
|
|
1724
|
+
"LinkedIn, phone, CRM, webhook, and sequencer actions remain destination-locked until approved.",
|
|
1725
|
+
"Deliverability risk or missing sender readiness blocks launch even when rows are qualified."
|
|
1726
|
+
],
|
|
1727
|
+
activationBoundary: "Sequence strategy is draft-only. External writes, sender loading, launch, and sending need separate explicit approval.",
|
|
1728
|
+
memoryKeywords: ["outbound sequencing", "email personalization", "LinkedIn outreach", "cold calling", "multi-channel orchestration", "deliverability"],
|
|
1729
|
+
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"]
|
|
1730
|
+
},
|
|
1731
|
+
{
|
|
1732
|
+
slug: "revops-feedback-loop",
|
|
1733
|
+
label: "RevOps Feedback Loop",
|
|
1734
|
+
whenToUse: [
|
|
1735
|
+
"The campaign should improve from replies, meetings, delivery results, CRM outcomes, or operator QA.",
|
|
1736
|
+
"The operator needs post-build monitoring, governance, or continuous ops follow-up."
|
|
1737
|
+
],
|
|
1738
|
+
sequence: [
|
|
1739
|
+
"Define success metrics, guardrails, and feedback sources before launch.",
|
|
1740
|
+
"Collect aggregate outcomes, QA blockers, delivery health, and operator edits after each campaign phase.",
|
|
1741
|
+
"Separate workspace-private evidence from public-safe learnings and Brain defaults.",
|
|
1742
|
+
"Feed approved aggregate learnings back into future sourcing, qualification, copy, and suppression rules."
|
|
1743
|
+
],
|
|
1744
|
+
requiredFields: {
|
|
1745
|
+
feedback: ["source", "event_type", "metric", "sample_size", "confidence", "learning_candidate"],
|
|
1746
|
+
governance: ["approval_owner", "last_reviewed_at", "risk_flag", "next_review_action"]
|
|
1747
|
+
},
|
|
1748
|
+
qualityGates: [
|
|
1749
|
+
"Do not write memory or Brain learnings from raw replies, private labels, or provider payloads without approved redaction.",
|
|
1750
|
+
"Use holdouts or pre/post comparisons before claiming causal lift.",
|
|
1751
|
+
"Delivery, suppression, and opt-out signals must update future gates before scale-up."
|
|
1752
|
+
],
|
|
1753
|
+
activationBoundary: "Feedback review is read-only until memory writes, Brain writes, CRM updates, or campaign changes are explicitly approved.",
|
|
1754
|
+
memoryKeywords: ["RevOps", "feedback loop", "campaign learning", "reply outcomes", "sales marketing alignment", "data hygiene", "holdout"],
|
|
1755
|
+
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"]
|
|
1536
1756
|
}
|
|
1537
1757
|
];
|
|
1538
1758
|
var CAMPAIGN_BUILDER_STRATEGY_TEMPLATES = [
|
|
@@ -1619,7 +1839,15 @@ var CAMPAIGN_BUILDER_STRATEGY_TEMPLATES = [
|
|
|
1619
1839
|
agencyContext: {
|
|
1620
1840
|
partnerEcosystem: ["signaliz", "instantly", "nango"]
|
|
1621
1841
|
},
|
|
1622
|
-
operatingPlaybookSlugs: [
|
|
1842
|
+
operatingPlaybookSlugs: [
|
|
1843
|
+
"net-new-suppressed-list",
|
|
1844
|
+
"proof-first-vertical-gate",
|
|
1845
|
+
"signal-led-copy-approval",
|
|
1846
|
+
"icp-persona-segmentation",
|
|
1847
|
+
"buying-signal-prioritization",
|
|
1848
|
+
"multi-channel-sequence-fit",
|
|
1849
|
+
"revops-feedback-loop"
|
|
1850
|
+
]
|
|
1623
1851
|
},
|
|
1624
1852
|
{
|
|
1625
1853
|
slug: "non-medical-home-care",
|
|
@@ -1692,7 +1920,15 @@ var CAMPAIGN_BUILDER_STRATEGY_TEMPLATES = [
|
|
|
1692
1920
|
agencyContext: {
|
|
1693
1921
|
partnerEcosystem: ["clay", "octave", "signaliz", "instantly", "nango"]
|
|
1694
1922
|
},
|
|
1695
|
-
operatingPlaybookSlugs: [
|
|
1923
|
+
operatingPlaybookSlugs: [
|
|
1924
|
+
"proof-first-vertical-gate",
|
|
1925
|
+
"domain-first-recovery",
|
|
1926
|
+
"table-workflow-handoff",
|
|
1927
|
+
"icp-persona-segmentation",
|
|
1928
|
+
"buying-signal-prioritization",
|
|
1929
|
+
"multi-channel-sequence-fit",
|
|
1930
|
+
"revops-feedback-loop"
|
|
1931
|
+
]
|
|
1696
1932
|
},
|
|
1697
1933
|
{
|
|
1698
1934
|
slug: "agency-founder-led",
|
|
@@ -1753,7 +1989,15 @@ var CAMPAIGN_BUILDER_STRATEGY_TEMPLATES = [
|
|
|
1753
1989
|
agencyContext: {
|
|
1754
1990
|
partnerEcosystem: ["signaliz", "octave", "instantly", "nango"]
|
|
1755
1991
|
},
|
|
1756
|
-
operatingPlaybookSlugs: [
|
|
1992
|
+
operatingPlaybookSlugs: [
|
|
1993
|
+
"net-new-suppressed-list",
|
|
1994
|
+
"signal-led-copy-approval",
|
|
1995
|
+
"table-workflow-handoff",
|
|
1996
|
+
"icp-persona-segmentation",
|
|
1997
|
+
"buying-signal-prioritization",
|
|
1998
|
+
"multi-channel-sequence-fit",
|
|
1999
|
+
"revops-feedback-loop"
|
|
2000
|
+
]
|
|
1757
2001
|
},
|
|
1758
2002
|
{
|
|
1759
2003
|
slug: "cloud-infrastructure-displacement",
|
|
@@ -1840,7 +2084,15 @@ var CAMPAIGN_BUILDER_STRATEGY_TEMPLATES = [
|
|
|
1840
2084
|
agencyContext: {
|
|
1841
2085
|
partnerEcosystem: ["signaliz", "octave", "instantly", "nango"]
|
|
1842
2086
|
},
|
|
1843
|
-
operatingPlaybookSlugs: [
|
|
2087
|
+
operatingPlaybookSlugs: [
|
|
2088
|
+
"proof-first-vertical-gate",
|
|
2089
|
+
"domain-first-recovery",
|
|
2090
|
+
"signal-led-copy-approval",
|
|
2091
|
+
"icp-persona-segmentation",
|
|
2092
|
+
"buying-signal-prioritization",
|
|
2093
|
+
"multi-channel-sequence-fit",
|
|
2094
|
+
"revops-feedback-loop"
|
|
2095
|
+
]
|
|
1844
2096
|
}
|
|
1845
2097
|
];
|
|
1846
2098
|
var CampaignBuilderAgent = class {
|
|
@@ -1871,6 +2123,9 @@ var CampaignBuilderAgent = class {
|
|
|
1871
2123
|
const plan = await this.createPlan(request, options);
|
|
1872
2124
|
return createCampaignBuilderReadiness(plan);
|
|
1873
2125
|
}
|
|
2126
|
+
activeWorkContext(input) {
|
|
2127
|
+
return createCampaignBuilderActiveWorkContext(input);
|
|
2128
|
+
}
|
|
1874
2129
|
async proof(request, options = {}) {
|
|
1875
2130
|
const plan = await this.createPlan(request, options);
|
|
1876
2131
|
const result = await this.dryRunPlan(plan, {
|
|
@@ -2255,9 +2510,10 @@ function createCampaignBuilderAgentPlan(request, context = {}) {
|
|
|
2255
2510
|
const estimatedCredits = estimateCredits(resolvedRequest, defaults, targetCount);
|
|
2256
2511
|
const buildRequest = createBuildRequest(resolvedRequest, defaults, targetCount, campaignName, context.scopeBuildArgs, routes, memory, context.scopeBrainPreflight);
|
|
2257
2512
|
const brainPreflight = asRecord(buildRequest.brainPreflight);
|
|
2513
|
+
const evidence = buildRequest.evidence ?? null;
|
|
2258
2514
|
const approvals = deriveApprovals(resolvedRequest, routes, memory, estimatedCredits, defaults.delivery?.approvalRequired !== false);
|
|
2259
2515
|
return {
|
|
2260
|
-
planId: `cbp_${hashString(JSON.stringify({ goal: resolvedRequest.goal, campaignName, targetCount, routes }))}`,
|
|
2516
|
+
planId: `cbp_${hashString(JSON.stringify({ goal: resolvedRequest.goal, campaignName, targetCount, routes, evidence }))}`,
|
|
2261
2517
|
campaignName,
|
|
2262
2518
|
goal: resolvedRequest.goal,
|
|
2263
2519
|
targetCount,
|
|
@@ -2272,6 +2528,7 @@ function createCampaignBuilderAgentPlan(request, context = {}) {
|
|
|
2272
2528
|
approvals,
|
|
2273
2529
|
buildRequest,
|
|
2274
2530
|
brainPreflight,
|
|
2531
|
+
evidence,
|
|
2275
2532
|
operatingPlaybooks,
|
|
2276
2533
|
mcpFlow: createMcpFlow(resolvedRequest, buildRequest, routes, memory, approvals),
|
|
2277
2534
|
estimatedCredits,
|
|
@@ -2363,6 +2620,90 @@ function createCampaignBuilderReadiness(plan) {
|
|
|
2363
2620
|
nextActions: campaignReadinessNextActions(plan, ready, customRoutes.length)
|
|
2364
2621
|
};
|
|
2365
2622
|
}
|
|
2623
|
+
function createCampaignBuilderActiveWorkContext(input) {
|
|
2624
|
+
const plan = input.readiness?.plan ?? input.plan;
|
|
2625
|
+
const remembered = input.remembered ?? {};
|
|
2626
|
+
const lastResult = asRecord(input.lastResult);
|
|
2627
|
+
const readinessBlockers = input.readiness?.summary.blockers ?? [];
|
|
2628
|
+
const explicitBlockers = input.blockers ?? [];
|
|
2629
|
+
const blockers = uniqueStrings([...explicitBlockers, ...readinessBlockers]);
|
|
2630
|
+
const warnings = uniqueStrings([
|
|
2631
|
+
...input.warnings ?? [],
|
|
2632
|
+
...input.readiness?.summary.warnings ?? [],
|
|
2633
|
+
...plan?.warnings ?? []
|
|
2634
|
+
]);
|
|
2635
|
+
const missingApprovals = plan ? (input.approval ? getMissingCampaignBuilderApprovals(plan, input.approval) : plan.approvals.filter((approval) => approval.blocking)).map((approval) => approval.type) : [];
|
|
2636
|
+
const refs = normalizeCampaignBuilderActiveWorkRefs({
|
|
2637
|
+
plan,
|
|
2638
|
+
remembered,
|
|
2639
|
+
refs: input.refs,
|
|
2640
|
+
lastResult
|
|
2641
|
+
});
|
|
2642
|
+
const state = inferCampaignBuilderActiveWorkState({
|
|
2643
|
+
plan,
|
|
2644
|
+
readiness: input.readiness,
|
|
2645
|
+
remembered,
|
|
2646
|
+
lastResult,
|
|
2647
|
+
blockers,
|
|
2648
|
+
missingApprovals
|
|
2649
|
+
});
|
|
2650
|
+
const nextSafeAction = campaignBuilderActiveWorkNextAction(state, blockers, missingApprovals, refs);
|
|
2651
|
+
const approvalPacket = createCampaignBuilderApprovalPacket(plan, input.approval, missingApprovals);
|
|
2652
|
+
const nextSafeMcpAction = campaignBuilderActiveWorkNextMcpAction({
|
|
2653
|
+
state,
|
|
2654
|
+
plan,
|
|
2655
|
+
refs,
|
|
2656
|
+
approvalPacket
|
|
2657
|
+
});
|
|
2658
|
+
const summary = {
|
|
2659
|
+
plan_id: plan?.planId ?? remembered.planId ?? null,
|
|
2660
|
+
campaign_name: plan?.campaignName ?? null,
|
|
2661
|
+
target_count: plan?.targetCount ?? null,
|
|
2662
|
+
gtm_campaign_id: plan?.buildRequest.gtmCampaignId ?? remembered.gtmCampaignId ?? null,
|
|
2663
|
+
campaign_build_id: stringValue(lastResult.campaign_build_id ?? lastResult.campaignBuildId) ?? remembered.campaignBuildId ?? null,
|
|
2664
|
+
provider_campaign_id: remembered.providerCampaignId ?? null
|
|
2665
|
+
};
|
|
2666
|
+
const approvalBoundary = campaignBuilderActiveWorkApprovalBoundary(missingApprovals, state);
|
|
2667
|
+
const conversationStarters = campaignBuilderActiveWorkConversationStarters({
|
|
2668
|
+
state,
|
|
2669
|
+
blockers,
|
|
2670
|
+
missingApprovals,
|
|
2671
|
+
refs,
|
|
2672
|
+
nextSafeAction
|
|
2673
|
+
});
|
|
2674
|
+
return {
|
|
2675
|
+
packet_version: "campaign-builder-active-work-context.v1",
|
|
2676
|
+
read_only: true,
|
|
2677
|
+
no_spend: true,
|
|
2678
|
+
no_provider_writes: true,
|
|
2679
|
+
private_safe: true,
|
|
2680
|
+
state,
|
|
2681
|
+
summary,
|
|
2682
|
+
refs,
|
|
2683
|
+
blockers,
|
|
2684
|
+
warnings,
|
|
2685
|
+
missing_approval_types: missingApprovals,
|
|
2686
|
+
approval_packet: approvalPacket,
|
|
2687
|
+
approval_boundary: approvalBoundary,
|
|
2688
|
+
next_safe_action: nextSafeAction,
|
|
2689
|
+
next_safe_mcp_action: nextSafeMcpAction,
|
|
2690
|
+
conversation_starters: conversationStarters,
|
|
2691
|
+
openai_agent_handoff: createCampaignBuilderOpenAiAgentHandoff({
|
|
2692
|
+
plan,
|
|
2693
|
+
state,
|
|
2694
|
+
summary,
|
|
2695
|
+
refs,
|
|
2696
|
+
blockers,
|
|
2697
|
+
warnings,
|
|
2698
|
+
missingApprovals,
|
|
2699
|
+
approvalPacket,
|
|
2700
|
+
approvalBoundary,
|
|
2701
|
+
nextSafeAction,
|
|
2702
|
+
nextSafeMcpAction,
|
|
2703
|
+
conversationStarters
|
|
2704
|
+
})
|
|
2705
|
+
};
|
|
2706
|
+
}
|
|
2366
2707
|
function createCampaignBuilderProofReceipt(plan, result) {
|
|
2367
2708
|
const strategyMemory = asRecord(plan.strategyMemoryStatus);
|
|
2368
2709
|
const dryRunResult = asRecord(result);
|
|
@@ -2421,6 +2762,7 @@ function createCampaignBuilderProofReceipt(plan, result) {
|
|
|
2421
2762
|
estimated_credits: plan.estimatedCredits,
|
|
2422
2763
|
operating_playbooks: plan.operatingPlaybooks.map((playbook) => playbook.slug)
|
|
2423
2764
|
},
|
|
2765
|
+
evidence: plan.evidence,
|
|
2424
2766
|
gates,
|
|
2425
2767
|
strategy_memory_status: summarizeCampaignBuilderProofStrategyMemory(strategyMemory),
|
|
2426
2768
|
dry_run_result: summarizeCampaignBuilderProofDryRun(dryRunResult),
|
|
@@ -2469,6 +2811,56 @@ function getCampaignBuilderOperatingPlaybooksForRequest(request) {
|
|
|
2469
2811
|
]);
|
|
2470
2812
|
return slugs.map(getCampaignBuilderOperatingPlaybook).filter((playbook) => Boolean(playbook));
|
|
2471
2813
|
}
|
|
2814
|
+
function normalizeCampaignBuilderEvidence(evidence) {
|
|
2815
|
+
if (!evidence) return null;
|
|
2816
|
+
const attachmentSummary = (evidence.attachments ?? []).filter((attachment) => stringValue(attachment.name)).slice(0, 5).map((attachment) => ({
|
|
2817
|
+
name: stringValue(attachment.name) ?? "attachment",
|
|
2818
|
+
kind: stringValue(attachment.kind) ?? null,
|
|
2819
|
+
media_type: stringValue(attachment.mediaType) ?? null,
|
|
2820
|
+
redacted: attachment.redacted !== false,
|
|
2821
|
+
columns: uniqueStrings(attachment.columns ?? []).slice(0, 25),
|
|
2822
|
+
row_count: numberOrUndefined2(attachment.rowCount) ?? null,
|
|
2823
|
+
content_summary: stringValue(attachment.contentSummary)?.slice(0, 500) ?? null,
|
|
2824
|
+
evidence_fields: uniqueStrings(attachment.evidenceFields ?? []).slice(0, 25)
|
|
2825
|
+
}));
|
|
2826
|
+
const urlSummary = (evidence.urls ?? []).filter((url) => stringValue(url.url)).slice(0, 8).map((url) => {
|
|
2827
|
+
const rawUrl = stringValue(url.url) ?? "";
|
|
2828
|
+
return {
|
|
2829
|
+
url: rawUrl,
|
|
2830
|
+
host: stringValue(url.host) ?? hostFromUrl(rawUrl) ?? null,
|
|
2831
|
+
type: stringValue(url.type) ?? null,
|
|
2832
|
+
label: stringValue(url.label) ?? null,
|
|
2833
|
+
summary: stringValue(url.summary)?.slice(0, 500) ?? null,
|
|
2834
|
+
redacted: url.redacted === true
|
|
2835
|
+
};
|
|
2836
|
+
});
|
|
2837
|
+
const operatorNotes = uniqueStrings(evidence.notes ?? []).map((note) => note.slice(0, 240)).slice(0, 5);
|
|
2838
|
+
if (!attachmentSummary.length && !urlSummary.length && !operatorNotes.length) return null;
|
|
2839
|
+
return {
|
|
2840
|
+
packet_version: "campaign-builder-evidence.v1",
|
|
2841
|
+
private_safe: true,
|
|
2842
|
+
attachment_summary: attachmentSummary,
|
|
2843
|
+
url_summary: urlSummary,
|
|
2844
|
+
operator_notes: operatorNotes,
|
|
2845
|
+
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.",
|
|
2846
|
+
raw_private_fields_withheld: [
|
|
2847
|
+
"raw_private_attachment_text",
|
|
2848
|
+
"raw_attachment_rows",
|
|
2849
|
+
"raw_leads",
|
|
2850
|
+
"email_addresses",
|
|
2851
|
+
"provider_auth_payloads",
|
|
2852
|
+
"copy_bodies",
|
|
2853
|
+
"secrets"
|
|
2854
|
+
]
|
|
2855
|
+
};
|
|
2856
|
+
}
|
|
2857
|
+
function hostFromUrl(value) {
|
|
2858
|
+
try {
|
|
2859
|
+
return new URL(value).hostname || void 0;
|
|
2860
|
+
} catch {
|
|
2861
|
+
return void 0;
|
|
2862
|
+
}
|
|
2863
|
+
}
|
|
2472
2864
|
function applyCampaignBuilderStrategyTemplate(request) {
|
|
2473
2865
|
const template = getCampaignBuilderStrategyTemplate(request.strategyTemplate);
|
|
2474
2866
|
if (!template) return request;
|
|
@@ -3160,7 +3552,7 @@ function normalizeMemory(request) {
|
|
|
3160
3552
|
};
|
|
3161
3553
|
}
|
|
3162
3554
|
function defaultAgencyMemoryQueries(request, configured) {
|
|
3163
|
-
const operatingPlaybookTerms = getCampaignBuilderOperatingPlaybooksForRequest(request).flatMap((playbook) => [playbook.label, ...playbook.memoryKeywords]).join(" ");
|
|
3555
|
+
const operatingPlaybookTerms = getCampaignBuilderOperatingPlaybooksForRequest(request).flatMap((playbook) => [playbook.label, ...playbook.memoryKeywords, ...playbook.knowledgeSources]).join(" ");
|
|
3164
3556
|
const queries = [{
|
|
3165
3557
|
query: request.goal,
|
|
3166
3558
|
scopes: ["workspace", configured.useNetworkPatterns ? "network_patterns" : "operator_notes"],
|
|
@@ -3371,6 +3763,8 @@ function createBuildRequest(request, defaults, targetCount, campaignName, scopeB
|
|
|
3371
3763
|
fillPolicy: "aggressive"
|
|
3372
3764
|
}
|
|
3373
3765
|
};
|
|
3766
|
+
const evidence = normalizeCampaignBuilderEvidence(request.evidence);
|
|
3767
|
+
if (evidence) buildRequest.evidence = evidence;
|
|
3374
3768
|
const scoped = asRecord(scopeBuildArgs);
|
|
3375
3769
|
buildRequest.gtmCampaignId = request.gtmCampaignId ?? stringValue(scoped.gtm_campaign_id ?? scoped.gtmCampaignId);
|
|
3376
3770
|
buildRequest.learningHoldout = normalizeCampaignBuilderLearningHoldout(
|
|
@@ -3402,6 +3796,7 @@ function createBrainPreflight(request, buildRequest, routes, memory) {
|
|
|
3402
3796
|
memory.enabled ? "feedback" : void 0
|
|
3403
3797
|
]);
|
|
3404
3798
|
const providerChain = uniqueStrings(["signaliz", ...request.preferredProviders ?? [], ...routes.map((route) => route.provider)]);
|
|
3799
|
+
const evidence = buildRequest.evidence ?? normalizeCampaignBuilderEvidence(request.evidence);
|
|
3405
3800
|
const targetIcp = compact({
|
|
3406
3801
|
personas: buildRequest.icp?.personas,
|
|
3407
3802
|
industries: buildRequest.icp?.industries,
|
|
@@ -3414,6 +3809,7 @@ function createBrainPreflight(request, buildRequest, routes, memory) {
|
|
|
3414
3809
|
const learningArgs = compact({
|
|
3415
3810
|
campaign_brief: request.goal,
|
|
3416
3811
|
target_icp: targetIcp,
|
|
3812
|
+
evidence_context: evidence,
|
|
3417
3813
|
layers,
|
|
3418
3814
|
provider_chain: providerChain,
|
|
3419
3815
|
lead_source: providerChain[0] ?? "signaliz",
|
|
@@ -3425,6 +3821,7 @@ function createBrainPreflight(request, buildRequest, routes, memory) {
|
|
|
3425
3821
|
const defaultsArgs = compact({
|
|
3426
3822
|
campaign_brief: request.goal,
|
|
3427
3823
|
target_icp: targetIcp,
|
|
3824
|
+
evidence_context: evidence,
|
|
3428
3825
|
layers,
|
|
3429
3826
|
include_global: memory.useNetworkPatterns,
|
|
3430
3827
|
include_memory: memory.enabled,
|
|
@@ -3435,6 +3832,7 @@ function createBrainPreflight(request, buildRequest, routes, memory) {
|
|
|
3435
3832
|
provider_chain: providerChain,
|
|
3436
3833
|
lead_source: providerChain[0] ?? "signaliz",
|
|
3437
3834
|
target_icp: targetIcp,
|
|
3835
|
+
evidence_context: evidence,
|
|
3438
3836
|
include_global: memory.useNetworkPatterns,
|
|
3439
3837
|
limit: 25
|
|
3440
3838
|
});
|
|
@@ -3447,9 +3845,11 @@ function createBrainPreflight(request, buildRequest, routes, memory) {
|
|
|
3447
3845
|
label: playbook.label,
|
|
3448
3846
|
quality_gates: playbook.qualityGates,
|
|
3449
3847
|
required_fields: playbook.requiredFields,
|
|
3450
|
-
activation_boundary: playbook.activationBoundary
|
|
3848
|
+
activation_boundary: playbook.activationBoundary,
|
|
3849
|
+
knowledge_sources: playbook.knowledgeSources
|
|
3451
3850
|
})),
|
|
3452
3851
|
target_icp: targetIcp,
|
|
3852
|
+
evidence_context: evidence,
|
|
3453
3853
|
provider_chain: providerChain,
|
|
3454
3854
|
lead_source: providerChain[0] ?? "signaliz",
|
|
3455
3855
|
learning_holdout: buildRequest.learningHoldout,
|
|
@@ -3722,7 +4122,7 @@ function createMcpFlow(request, buildRequest, routes, memory, approvals) {
|
|
|
3722
4122
|
phase: "plan",
|
|
3723
4123
|
tool: "nango_mcp_tools_list",
|
|
3724
4124
|
arguments: {
|
|
3725
|
-
format: "
|
|
4125
|
+
format: "openai"
|
|
3726
4126
|
},
|
|
3727
4127
|
readOnly: true,
|
|
3728
4128
|
approvalRequired: false
|
|
@@ -4031,6 +4431,7 @@ function buildGtmCampaignBuildPlanArgs(request, buildRequest, routes, memory) {
|
|
|
4031
4431
|
layers: layers.length > 0 ? layers : void 0,
|
|
4032
4432
|
preferred_providers: preferredProviders.length > 0 ? preferredProviders : void 0,
|
|
4033
4433
|
strategy_model: strategyModel,
|
|
4434
|
+
evidence_context: buildRequest.evidence ?? normalizeCampaignBuilderEvidence(request.evidence),
|
|
4034
4435
|
include_strategy_patterns: campaignBuilderStrategyPatternsEnabled(agencyContext),
|
|
4035
4436
|
include_workflow_patterns: campaignBuilderWorkflowPatternsEnabled(agencyContext),
|
|
4036
4437
|
include_nango_catalog: agencyContext.includeNangoCatalog !== false,
|
|
@@ -4039,7 +4440,8 @@ function buildGtmCampaignBuildPlanArgs(request, buildRequest, routes, memory) {
|
|
|
4039
4440
|
slug: playbook.slug,
|
|
4040
4441
|
label: playbook.label,
|
|
4041
4442
|
quality_gates: playbook.qualityGates,
|
|
4042
|
-
activation_boundary: playbook.activationBoundary
|
|
4443
|
+
activation_boundary: playbook.activationBoundary,
|
|
4444
|
+
knowledge_sources: playbook.knowledgeSources
|
|
4043
4445
|
})),
|
|
4044
4446
|
include_memory: memory.enabled,
|
|
4045
4447
|
include_brain: true,
|
|
@@ -4132,6 +4534,7 @@ function buildCampaignArgs(request) {
|
|
|
4132
4534
|
}
|
|
4133
4535
|
if (request.campaignStrategyContext) args.campaign_strategy_context = request.campaignStrategyContext;
|
|
4134
4536
|
if (request.deliveryRisk) args.delivery_risk = request.deliveryRisk;
|
|
4537
|
+
if (request.evidence) args.evidence_context = request.evidence;
|
|
4135
4538
|
if (request.icp) {
|
|
4136
4539
|
args.icp = compact({
|
|
4137
4540
|
personas: request.icp.personas,
|
|
@@ -4181,7 +4584,8 @@ function buildCampaignArgs(request) {
|
|
|
4181
4584
|
max_body_words: request.copy.maxBodyWords,
|
|
4182
4585
|
sender_context: request.copy.senderContext,
|
|
4183
4586
|
offer_context: request.copy.offerContext,
|
|
4184
|
-
model: request.copy.model
|
|
4587
|
+
model: request.copy.model,
|
|
4588
|
+
evidence_mode: request.copy.evidenceMode
|
|
4185
4589
|
});
|
|
4186
4590
|
}
|
|
4187
4591
|
if (request.delivery) {
|
|
@@ -4458,6 +4862,7 @@ function mapAgentCustomerRowCounts(value) {
|
|
|
4458
4862
|
acceptedRows: numberOrUndefined2(record.accepted_rows),
|
|
4459
4863
|
usableRows: numberOrUndefined2(record.usable_rows),
|
|
4460
4864
|
copiedRows: numberOrUndefined2(record.copied_rows),
|
|
4865
|
+
copySkippedRows: numberOrUndefined2(record.copy_skipped_rows),
|
|
4461
4866
|
approvalReadyRows: numberOrUndefined2(record.approval_ready_rows),
|
|
4462
4867
|
qaReadyRows: numberOrUndefined2(record.qa_ready_rows),
|
|
4463
4868
|
deliveredRows: numberOrUndefined2(record.delivered_rows),
|
|
@@ -4568,7 +4973,7 @@ function createCampaignBuilderNorthStarScorecard(status, rows, artifacts, termin
|
|
|
4568
4973
|
const sampledRows = rows.rows.length;
|
|
4569
4974
|
const rowData = rows.rows.map((row) => asRecord(row.data));
|
|
4570
4975
|
const requestedTarget = status.customerRowCounts?.requestedTarget ?? status.recordsTotal ?? rows.count;
|
|
4571
|
-
const finalRows = status.customerRowCounts?.deliveredRows ?? status.customerRowCounts?.qaReadyRows ?? status.customerRowCounts?.copiedRows ?? status.customerRowCounts?.acceptedRows ?? rows.count;
|
|
4976
|
+
const finalRows = status.customerRowCounts?.deliveredRows ?? status.customerRowCounts?.qaReadyRows ?? status.customerRowCounts?.copySkippedRows ?? status.customerRowCounts?.copiedRows ?? status.customerRowCounts?.acceptedRows ?? rows.count;
|
|
4572
4977
|
const rowsWithEmail = rows.rows.filter(campaignReviewRowHasEmail).length;
|
|
4573
4978
|
const verifiedEmailRows = rowData.filter(campaignReviewDataHasVerifiedEmail).length;
|
|
4574
4979
|
const uniqueEmails = new Set(rowData.map(campaignReviewDataEmail).filter(Boolean)).size;
|
|
@@ -5059,6 +5464,342 @@ function createCampaignBuilderReadinessLane(route, plan) {
|
|
|
5059
5464
|
nextAction: customRoute ? `Review ${route.provider} route setup before launch approval.` : void 0
|
|
5060
5465
|
};
|
|
5061
5466
|
}
|
|
5467
|
+
function createCampaignBuilderApprovalPacket(plan, approval, missingTypes) {
|
|
5468
|
+
const requestedTypes = plan ? uniqueStrings(plan.approvals.filter((item) => item.blocking).map((item) => item.type)) : [];
|
|
5469
|
+
const approvalMatchesPlan = Boolean(plan && approval?.planId === plan.planId);
|
|
5470
|
+
const approvedTypes = approvalMatchesPlan ? approval?.approvedTypes ?? [] : [];
|
|
5471
|
+
const approvedRoutes = approvalMatchesPlan ? approval?.approvedRouteIds ?? [] : [];
|
|
5472
|
+
const missingIds = new Set(
|
|
5473
|
+
plan && approvalMatchesPlan && approval ? getMissingCampaignBuilderApprovals(plan, approval).map((item) => item.id) : plan?.approvals.filter((item) => item.blocking).map((item) => item.id) ?? []
|
|
5474
|
+
);
|
|
5475
|
+
const routeIdsRequired = plan ? uniqueStrings(plan.approvals.map((item) => item.routeId).filter((id) => Boolean(id))) : [];
|
|
5476
|
+
const spendLimitRequired = plan ? Math.max(0, ...plan.approvals.filter((item) => item.type === "spend" && item.blocking).map((item) => item.estimatedCredits ?? plan.estimatedCredits)) : 0;
|
|
5477
|
+
const normalizedSpendLimit = spendLimitRequired > 0 ? spendLimitRequired : null;
|
|
5478
|
+
const approvalState = !plan ? "unscoped" : missingTypes.length > 0 ? "requires_approval" : "approved";
|
|
5479
|
+
const approvalInput = {
|
|
5480
|
+
approved_by: approval?.approvedBy ?? null,
|
|
5481
|
+
approved_at: approval?.approvedAt ?? null,
|
|
5482
|
+
approved_types: approvedTypes,
|
|
5483
|
+
approved_route_ids: approvedRoutes,
|
|
5484
|
+
spend_limit_credits: approval?.spendLimitCredits ?? null,
|
|
5485
|
+
notes: approval?.notes
|
|
5486
|
+
};
|
|
5487
|
+
return {
|
|
5488
|
+
packet_version: "campaign-builder-approval-packet.v1",
|
|
5489
|
+
read_only: true,
|
|
5490
|
+
no_spend: true,
|
|
5491
|
+
no_provider_writes: true,
|
|
5492
|
+
private_safe: true,
|
|
5493
|
+
approval_state: approvalState,
|
|
5494
|
+
plan_id: plan?.planId ?? null,
|
|
5495
|
+
campaign_name: plan?.campaignName ?? null,
|
|
5496
|
+
requested_approval_types: requestedTypes,
|
|
5497
|
+
missing_approval_types: uniqueStrings(missingTypes),
|
|
5498
|
+
spend_limit_credits_required: normalizedSpendLimit,
|
|
5499
|
+
route_ids_required: routeIdsRequired,
|
|
5500
|
+
required_approvals: (plan?.approvals ?? []).map((item) => compact({
|
|
5501
|
+
id: item.id,
|
|
5502
|
+
type: item.type,
|
|
5503
|
+
label: item.label,
|
|
5504
|
+
reason: item.reason,
|
|
5505
|
+
blocking: item.blocking,
|
|
5506
|
+
route_id: item.routeId,
|
|
5507
|
+
provider: item.provider,
|
|
5508
|
+
estimated_credits: item.estimatedCredits,
|
|
5509
|
+
status: missingIds.has(item.id) ? "missing" : "approved"
|
|
5510
|
+
})),
|
|
5511
|
+
approval_input: approvalInput,
|
|
5512
|
+
cli_handoff: plan ? {
|
|
5513
|
+
command: campaignBuilderApprovalCliHandoff(requestedTypes, routeIdsRequired, normalizedSpendLimit),
|
|
5514
|
+
safety: "Template only: run after explicit human approval identity, approved types, route scope, and spend limit are filled in."
|
|
5515
|
+
} : null,
|
|
5516
|
+
sdk_handoff: plan ? {
|
|
5517
|
+
method: "campaignBuilderAgent.buildApprovedPlan",
|
|
5518
|
+
approval: compact({
|
|
5519
|
+
approvedBy: approval?.approvedBy ?? "<operator-email>",
|
|
5520
|
+
approvedTypes: requestedTypes,
|
|
5521
|
+
approvedRouteIds: routeIdsRequired,
|
|
5522
|
+
spendLimitCredits: normalizedSpendLimit ?? void 0,
|
|
5523
|
+
notes: approval?.notes
|
|
5524
|
+
}),
|
|
5525
|
+
options: {
|
|
5526
|
+
idempotencyKey: "<set-before-execution>"
|
|
5527
|
+
},
|
|
5528
|
+
safety: "Call only after the approval packet is accepted; this helper does not execute writes or spend."
|
|
5529
|
+
} : null,
|
|
5530
|
+
mcp_handoffs: plan ? campaignBuilderApprovalMcpHandoffs(plan, requestedTypes, routeIdsRequired, normalizedSpendLimit) : [],
|
|
5531
|
+
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."
|
|
5532
|
+
};
|
|
5533
|
+
}
|
|
5534
|
+
function campaignBuilderApprovalCliHandoff(requestedTypes, routeIds, spendLimit) {
|
|
5535
|
+
return [
|
|
5536
|
+
"signaliz campaign-agent build-approved --request-file campaign-request.json --confirm-launch",
|
|
5537
|
+
requestedTypes.length > 0 ? `--approved-types ${shellArg(requestedTypes.join(","))}` : "--approve-all",
|
|
5538
|
+
"--approved-by <operator-email>",
|
|
5539
|
+
spendLimit !== null ? `--spend-limit ${spendLimit}` : void 0,
|
|
5540
|
+
routeIds.length > 0 ? `--approved-route-ids ${shellArg(routeIds.join(","))}` : void 0
|
|
5541
|
+
].filter(Boolean).join(" ");
|
|
5542
|
+
}
|
|
5543
|
+
function campaignBuilderApprovalMcpHandoffs(plan, requestedTypes, routeIds, spendLimit) {
|
|
5544
|
+
const approvalContext = compact({
|
|
5545
|
+
plan_id: plan.planId,
|
|
5546
|
+
approval_types: requestedTypes,
|
|
5547
|
+
approved_route_ids: routeIds,
|
|
5548
|
+
spend_limit_credits: spendLimit,
|
|
5549
|
+
approved_by: "<operator-email>"
|
|
5550
|
+
});
|
|
5551
|
+
return plan.mcpFlow.filter((step) => ["execution-prepare", "approved-build", "delivery-approval"].includes(step.id)).map((step) => ({
|
|
5552
|
+
id: step.id,
|
|
5553
|
+
tool: step.tool,
|
|
5554
|
+
arguments: step.id === "approved-build" ? compact({ ...step.arguments, approval_context: approvalContext }) : step.arguments,
|
|
5555
|
+
read_only: step.readOnly,
|
|
5556
|
+
approval_required: step.approvalRequired,
|
|
5557
|
+
safety: step.readOnly ? "Read-only readiness handoff; safe to inspect before approval." : "Write-capable handoff; run only after the approval packet is accepted."
|
|
5558
|
+
}));
|
|
5559
|
+
}
|
|
5560
|
+
function campaignBuilderActiveWorkNextMcpAction(input) {
|
|
5561
|
+
const campaignBuildRef = input.refs.find((ref) => ref.kind === "campaign_build" && ref.id);
|
|
5562
|
+
if (campaignBuildRef) {
|
|
5563
|
+
return {
|
|
5564
|
+
id: "check-campaign-build-status",
|
|
5565
|
+
tool: "get_campaign_build_status",
|
|
5566
|
+
arguments: { campaign_build_id: campaignBuildRef.id },
|
|
5567
|
+
read_only: true,
|
|
5568
|
+
approval_required: false,
|
|
5569
|
+
safety: "Read-only status check for the remembered campaign build; does not spend, write, export, send, or approve anything."
|
|
5570
|
+
};
|
|
5571
|
+
}
|
|
5572
|
+
const campaignRef = input.refs.find((ref) => ref.kind === "gtm_campaign" && ref.id);
|
|
5573
|
+
if (campaignRef) {
|
|
5574
|
+
return {
|
|
5575
|
+
id: "check-gtm-campaign-status",
|
|
5576
|
+
tool: "gtm_campaign_execution_status",
|
|
5577
|
+
arguments: { campaign_id: campaignRef.id },
|
|
5578
|
+
read_only: true,
|
|
5579
|
+
approval_required: false,
|
|
5580
|
+
safety: "Read-only campaign execution status check; does not start or mutate the campaign."
|
|
5581
|
+
};
|
|
5582
|
+
}
|
|
5583
|
+
const preferredStepId = input.state === "ready_for_dry_run" ? "dry-run-build" : input.state === "planning" || input.state === "blocked" ? "agency-campaign-build-plan" : null;
|
|
5584
|
+
const preferredStep = preferredStepId ? input.plan?.mcpFlow.find((step) => step.id === preferredStepId && step.readOnly) : void 0;
|
|
5585
|
+
if (preferredStep) return campaignBuilderMcpStepToActiveWorkAction(preferredStep, "Read-only continuation from the saved campaign-agent plan.");
|
|
5586
|
+
const readOnlyApprovalHandoff = input.approvalPacket.mcp_handoffs.find((handoff) => handoff.read_only && !handoff.approval_required);
|
|
5587
|
+
if (readOnlyApprovalHandoff) return readOnlyApprovalHandoff;
|
|
5588
|
+
const firstReadOnlyPlanStep = input.plan?.mcpFlow.find((step) => step.readOnly && !step.approvalRequired);
|
|
5589
|
+
return firstReadOnlyPlanStep ? campaignBuilderMcpStepToActiveWorkAction(firstReadOnlyPlanStep, "Read-only saved plan check; safe before approvals or writes.") : null;
|
|
5590
|
+
}
|
|
5591
|
+
function campaignBuilderMcpStepToActiveWorkAction(step, safety) {
|
|
5592
|
+
return {
|
|
5593
|
+
id: step.id,
|
|
5594
|
+
tool: step.tool,
|
|
5595
|
+
arguments: step.arguments,
|
|
5596
|
+
read_only: step.readOnly,
|
|
5597
|
+
approval_required: step.approvalRequired,
|
|
5598
|
+
safety
|
|
5599
|
+
};
|
|
5600
|
+
}
|
|
5601
|
+
function normalizeCampaignBuilderActiveWorkRefs(input) {
|
|
5602
|
+
const refs = [];
|
|
5603
|
+
const pushRef = (ref) => {
|
|
5604
|
+
if (!ref?.id) return;
|
|
5605
|
+
refs.push(ref);
|
|
5606
|
+
};
|
|
5607
|
+
pushRef(input.plan?.planId ? { kind: "plan", id: input.plan.planId, label: input.plan.campaignName, source: "plan" } : void 0);
|
|
5608
|
+
pushRef(input.remembered.planId ? { kind: "plan", id: input.remembered.planId, source: "remembered" } : void 0);
|
|
5609
|
+
pushRef(
|
|
5610
|
+
input.plan?.buildRequest.gtmCampaignId ?? input.remembered.gtmCampaignId ? {
|
|
5611
|
+
kind: "gtm_campaign",
|
|
5612
|
+
id: input.plan?.buildRequest.gtmCampaignId ?? input.remembered.gtmCampaignId,
|
|
5613
|
+
label: input.plan?.campaignName,
|
|
5614
|
+
source: input.plan?.buildRequest.gtmCampaignId ? "plan" : "remembered"
|
|
5615
|
+
} : void 0
|
|
5616
|
+
);
|
|
5617
|
+
const campaignBuildId = stringValue(input.lastResult.campaign_build_id ?? input.lastResult.campaignBuildId) ?? input.remembered.campaignBuildId;
|
|
5618
|
+
pushRef(campaignBuildId ? { kind: "campaign_build", id: campaignBuildId, status: activeWorkStatus(input.lastResult) ?? input.remembered.status, source: "result" } : void 0);
|
|
5619
|
+
pushRef(
|
|
5620
|
+
input.remembered.providerCampaignId ? {
|
|
5621
|
+
kind: "provider_campaign",
|
|
5622
|
+
id: input.remembered.providerCampaignId,
|
|
5623
|
+
label: input.remembered.provider,
|
|
5624
|
+
status: input.remembered.status,
|
|
5625
|
+
source: "remembered"
|
|
5626
|
+
} : void 0
|
|
5627
|
+
);
|
|
5628
|
+
for (const ref of input.remembered.refs ?? []) pushRef(ref);
|
|
5629
|
+
for (const ref of input.refs ?? []) pushRef(ref);
|
|
5630
|
+
const seen = /* @__PURE__ */ new Set();
|
|
5631
|
+
return refs.filter((ref) => {
|
|
5632
|
+
const key = `${ref.kind}:${ref.id}`;
|
|
5633
|
+
if (seen.has(key)) return false;
|
|
5634
|
+
seen.add(key);
|
|
5635
|
+
return true;
|
|
5636
|
+
});
|
|
5637
|
+
}
|
|
5638
|
+
function inferCampaignBuilderActiveWorkState(input) {
|
|
5639
|
+
if (input.blockers.length > 0) return "blocked";
|
|
5640
|
+
const status = activeWorkStatus(input.lastResult) ?? input.remembered.status;
|
|
5641
|
+
const normalized = status?.toLowerCase();
|
|
5642
|
+
if (normalized && ["completed", "complete", "succeeded", "success", "done"].includes(normalized)) return "completed";
|
|
5643
|
+
if (normalized && ["queued", "running", "in_progress", "processing", "pending"].includes(normalized)) return "queued_or_running";
|
|
5644
|
+
const dryRunComplete = input.lastResult.dry_run === true || input.lastResult.dryRun === true || normalized === "dry_run";
|
|
5645
|
+
if (dryRunComplete) return input.missingApprovals.length > 0 ? "needs_approval" : "dry_run_complete";
|
|
5646
|
+
if (input.missingApprovals.length > 0) return "needs_approval";
|
|
5647
|
+
if (input.readiness?.summary.ready === true) return "ready_for_dry_run";
|
|
5648
|
+
if (input.plan) return "planning";
|
|
5649
|
+
return "unknown";
|
|
5650
|
+
}
|
|
5651
|
+
function campaignBuilderActiveWorkApprovalBoundary(missingApprovals, state) {
|
|
5652
|
+
if (missingApprovals.length > 0) {
|
|
5653
|
+
return `Blocked before spend, provider writes, delivery, or launch until approval covers: ${uniqueStrings(missingApprovals).join(", ")}.`;
|
|
5654
|
+
}
|
|
5655
|
+
if (state === "dry_run_complete" || state === "ready_for_dry_run") {
|
|
5656
|
+
return "Read-only planning and dry-runs are allowed; spend, provider writes, sender loading, delivery, and launch still require explicit approval.";
|
|
5657
|
+
}
|
|
5658
|
+
return "This packet is read-only and does not authorize spend, provider writes, sender loading, delivery, or launch.";
|
|
5659
|
+
}
|
|
5660
|
+
function campaignBuilderActiveWorkNextAction(state, blockers, missingApprovals, refs) {
|
|
5661
|
+
if (blockers.length > 0) return `Resolve blocker: ${blockers[0]}`;
|
|
5662
|
+
if (missingApprovals.length > 0) return `Ask the operator to approve ${uniqueStrings(missingApprovals).join(", ")} before any write or spend action.`;
|
|
5663
|
+
if (state === "ready_for_dry_run") return "Run or inspect the read-only campaign dry-run, then return the receipt for approval review.";
|
|
5664
|
+
if (state === "dry_run_complete") return "Review the dry-run receipt and collect explicit launch or delivery approval before any write action.";
|
|
5665
|
+
if (state === "queued_or_running") return "Poll the remembered campaign build or provider job status; do not start a duplicate job.";
|
|
5666
|
+
if (state === "completed") return "Review final artifacts and delivery gates before export, sync, sender load, or launch.";
|
|
5667
|
+
if (refs.length > 0) return "Use the remembered refs to fetch current read-only status before asking the operator for IDs.";
|
|
5668
|
+
return "Create or refresh a campaign-builder plan before taking any spendful or write action.";
|
|
5669
|
+
}
|
|
5670
|
+
function campaignBuilderActiveWorkConversationStarters(input) {
|
|
5671
|
+
const starters = [];
|
|
5672
|
+
if (input.blockers.length > 0) {
|
|
5673
|
+
starters.push(
|
|
5674
|
+
`I found a blocker: ${input.blockers[0]}. Want me to stay in read-only diagnostics and prepare the fix path?`
|
|
5675
|
+
);
|
|
5676
|
+
}
|
|
5677
|
+
if (input.missingApprovals.length > 0) {
|
|
5678
|
+
starters.push(
|
|
5679
|
+
`You still owe approval for ${uniqueStrings(input.missingApprovals).join(", ")}. Want the exact approval packet before anything writes or spends?`
|
|
5680
|
+
);
|
|
5681
|
+
}
|
|
5682
|
+
if (input.state === "queued_or_running") {
|
|
5683
|
+
const buildRef = input.refs.find((ref) => ref.kind === "campaign_build");
|
|
5684
|
+
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.");
|
|
5685
|
+
}
|
|
5686
|
+
if (input.state === "dry_run_complete") {
|
|
5687
|
+
starters.push("The dry run is complete. Want me to summarize blockers, artifacts, and the approval handoff?");
|
|
5688
|
+
}
|
|
5689
|
+
if (input.state === "ready_for_dry_run") {
|
|
5690
|
+
starters.push("Everything is ready for a safe dry run. Want me to run the no-spend preview first?");
|
|
5691
|
+
}
|
|
5692
|
+
if (input.state === "completed") {
|
|
5693
|
+
starters.push("The build looks complete. Want me to review rows, artifacts, and delivery gates before export or send approval?");
|
|
5694
|
+
}
|
|
5695
|
+
starters.push(`Next safe action: ${input.nextSafeAction}`);
|
|
5696
|
+
return uniqueStrings(starters).slice(0, 4);
|
|
5697
|
+
}
|
|
5698
|
+
function createCampaignBuilderOpenAiAgentHandoff(input) {
|
|
5699
|
+
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.")) ?? [];
|
|
5700
|
+
const routeSetupActions = readOnlyPlanActions.filter(
|
|
5701
|
+
(action) => action.tool === "gtm_provider_recipe_prepare" || action.tool === "gtm_provider_route_activate"
|
|
5702
|
+
);
|
|
5703
|
+
const safeReadActions = uniqueCampaignBuilderActiveWorkActions([
|
|
5704
|
+
input.nextSafeMcpAction,
|
|
5705
|
+
...routeSetupActions,
|
|
5706
|
+
...readOnlyPlanActions
|
|
5707
|
+
]);
|
|
5708
|
+
const approvalGatedActions = uniqueCampaignBuilderActiveWorkActions([
|
|
5709
|
+
...input.approvalPacket.mcp_handoffs.filter((action) => action.approval_required || !action.read_only),
|
|
5710
|
+
...input.plan?.mcpFlow.filter((step) => step.approvalRequired || !step.readOnly).map((step) => campaignBuilderMcpStepToActiveWorkAction(step, "Approval-gated Signaliz MCP continuation for the saved campaign-agent plan.")) ?? []
|
|
5711
|
+
]);
|
|
5712
|
+
const approvalTypes = uniqueStrings([
|
|
5713
|
+
...input.missingApprovals,
|
|
5714
|
+
...input.approvalPacket.requested_approval_types
|
|
5715
|
+
]);
|
|
5716
|
+
return {
|
|
5717
|
+
packet_version: "campaign-builder-openai-agent-handoff.v1",
|
|
5718
|
+
surface: "openai_agents_sdk",
|
|
5719
|
+
agent: {
|
|
5720
|
+
name: "Signaliz GTM Campaign Agent",
|
|
5721
|
+
handoff_description: "Owns safe, conversational GTM campaign planning and continuation across Signaliz MCP, SDK, attachments, URLs, customer tools, approvals, and sender/export gates.",
|
|
5722
|
+
instructions: [
|
|
5723
|
+
"Be warm, direct, and expert-level GTM. Translate the current state into plain operator language before proposing work.",
|
|
5724
|
+
"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.",
|
|
5725
|
+
"Use attachment_summary, url_summary, and operator_notes as first-class planning evidence, while honoring the evidence privacy_boundary and withheld raw fields.",
|
|
5726
|
+
"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.",
|
|
5727
|
+
"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.",
|
|
5728
|
+
"When approval is missing, show the approval_packet and the exact missing approval scope before any side-effecting step."
|
|
5729
|
+
],
|
|
5730
|
+
output_contract: [
|
|
5731
|
+
"current_state: one concise sentence describing where the campaign work stands.",
|
|
5732
|
+
"evidence_used: attachment, URL, memory, route, or integration evidence used without exposing private raw rows or secrets.",
|
|
5733
|
+
"next_safe_mcp_action: the read-only Signaliz MCP action to run next, or null when none is safe.",
|
|
5734
|
+
"approval_boundary: the human approval scope required before spend, provider writes, delivery, export, sender load, or launch.",
|
|
5735
|
+
"operator_reply: conversational GTM guidance with blockers, risks, and the safest next move."
|
|
5736
|
+
]
|
|
5737
|
+
},
|
|
5738
|
+
context: {
|
|
5739
|
+
state: input.state,
|
|
5740
|
+
summary: input.summary,
|
|
5741
|
+
refs: input.refs,
|
|
5742
|
+
blockers: input.blockers,
|
|
5743
|
+
warnings: input.warnings,
|
|
5744
|
+
evidence_context: input.plan?.evidence ?? null,
|
|
5745
|
+
approval_packet: input.approvalPacket,
|
|
5746
|
+
approval_boundary: input.approvalBoundary,
|
|
5747
|
+
next_safe_action: input.nextSafeAction,
|
|
5748
|
+
conversation_starters: input.conversationStarters
|
|
5749
|
+
},
|
|
5750
|
+
tools: {
|
|
5751
|
+
mcp_server_label: "signaliz",
|
|
5752
|
+
remote_mcp_compatible: true,
|
|
5753
|
+
next_safe_mcp_action: input.nextSafeMcpAction,
|
|
5754
|
+
safe_read_tools: safeReadActions.map(
|
|
5755
|
+
(action) => campaignBuilderOpenAiAgentTool(action, "Safe read-only Signaliz MCP action available before approval.")
|
|
5756
|
+
),
|
|
5757
|
+
approval_gated_tools: approvalGatedActions.map(
|
|
5758
|
+
(action) => campaignBuilderOpenAiAgentTool(action, "Requires explicit human review before execution.")
|
|
5759
|
+
)
|
|
5760
|
+
},
|
|
5761
|
+
guardrails: {
|
|
5762
|
+
input: [
|
|
5763
|
+
"Reject or pause requests to expose raw private attachment text, raw rows, leads, emails, provider payloads, copy bodies, API keys, or secrets.",
|
|
5764
|
+
"Pause when the user asks to spend credits, write to a provider, export, load a sender, deliver, or launch without explicit approval scope."
|
|
5765
|
+
],
|
|
5766
|
+
tool: [
|
|
5767
|
+
"Read-only tools may run when they match safe_read_tools and their arguments match this packet.",
|
|
5768
|
+
"Any tool with approval_required=true or read_only=false requires human review and the approval_packet scope first."
|
|
5769
|
+
],
|
|
5770
|
+
human_review_required_for: approvalTypes,
|
|
5771
|
+
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."
|
|
5772
|
+
}
|
|
5773
|
+
};
|
|
5774
|
+
}
|
|
5775
|
+
function campaignBuilderOpenAiAgentTool(action, purpose) {
|
|
5776
|
+
return {
|
|
5777
|
+
id: action.id,
|
|
5778
|
+
type: "mcp",
|
|
5779
|
+
server_label: "signaliz",
|
|
5780
|
+
name: action.tool,
|
|
5781
|
+
arguments: action.arguments,
|
|
5782
|
+
read_only: action.read_only,
|
|
5783
|
+
approval_required: action.approval_required,
|
|
5784
|
+
purpose,
|
|
5785
|
+
safety: action.safety
|
|
5786
|
+
};
|
|
5787
|
+
}
|
|
5788
|
+
function uniqueCampaignBuilderActiveWorkActions(actions) {
|
|
5789
|
+
const seen = /* @__PURE__ */ new Set();
|
|
5790
|
+
const unique = [];
|
|
5791
|
+
for (const action of actions) {
|
|
5792
|
+
if (!action) continue;
|
|
5793
|
+
const key = `${action.id}:${action.tool}`;
|
|
5794
|
+
if (seen.has(key)) continue;
|
|
5795
|
+
seen.add(key);
|
|
5796
|
+
unique.push(action);
|
|
5797
|
+
}
|
|
5798
|
+
return unique;
|
|
5799
|
+
}
|
|
5800
|
+
function activeWorkStatus(record) {
|
|
5801
|
+
return stringValue(record.status ?? record.state ?? record.phase);
|
|
5802
|
+
}
|
|
5062
5803
|
function campaignBuilderBuiltInForRoute(route) {
|
|
5063
5804
|
return Object.entries(CAMPAIGN_BUILDER_BUILT_IN_ROUTE_IDS).find(([, routeId]) => route.id === routeId)?.[0];
|
|
5064
5805
|
}
|
|
@@ -7855,6 +8596,36 @@ function recordsFromParams(params) {
|
|
|
7855
8596
|
if (params.input) return { input: params.input };
|
|
7856
8597
|
return { input: {} };
|
|
7857
8598
|
}
|
|
8599
|
+
function toFusionConfig(params) {
|
|
8600
|
+
return {
|
|
8601
|
+
system_prompt: params.systemPrompt || params.system_prompt,
|
|
8602
|
+
user_template: params.userTemplate || params.user_template || params.prompt,
|
|
8603
|
+
preset: params.preset,
|
|
8604
|
+
temperature: params.temperature,
|
|
8605
|
+
max_tool_calls: params.maxToolCalls || params.max_tool_calls,
|
|
8606
|
+
max_tokens: params.maxTokens || params.max_tokens,
|
|
8607
|
+
timeout_ms: params.timeoutMs || params.timeout_ms,
|
|
8608
|
+
output_fields: params.outputFields || params.output_fields || [{ name: "response", type: "text", description: "Structured Fusion enrichment result" }]
|
|
8609
|
+
};
|
|
8610
|
+
}
|
|
8611
|
+
function toFusionSpendControls(params) {
|
|
8612
|
+
const controls = {};
|
|
8613
|
+
const dryRun = params.dryRun ?? params.dry_run;
|
|
8614
|
+
const confirmSpend = params.confirmSpend ?? params.confirm_spend;
|
|
8615
|
+
const maxCredits = params.maxCredits ?? params.max_credits;
|
|
8616
|
+
const maxCostUsd = params.maxCostUsd ?? params.max_cost_usd;
|
|
8617
|
+
if (dryRun !== void 0) controls.dry_run = dryRun;
|
|
8618
|
+
if (confirmSpend !== void 0) controls.confirm_spend = confirmSpend;
|
|
8619
|
+
if (maxCredits !== void 0) controls.max_credits = maxCredits;
|
|
8620
|
+
if (maxCostUsd !== void 0) controls.max_cost_usd = maxCostUsd;
|
|
8621
|
+
return controls;
|
|
8622
|
+
}
|
|
8623
|
+
function fusionRecordsFromParams(params) {
|
|
8624
|
+
const records = params.records || params.inputs;
|
|
8625
|
+
if (records?.length) return { records };
|
|
8626
|
+
if (params.input) return { input: params.input };
|
|
8627
|
+
return { input: {} };
|
|
8628
|
+
}
|
|
7858
8629
|
var Ai = class {
|
|
7859
8630
|
constructor(client) {
|
|
7860
8631
|
this.client = client;
|
|
@@ -7888,6 +8659,33 @@ var Ai = class {
|
|
|
7888
8659
|
raw: data
|
|
7889
8660
|
};
|
|
7890
8661
|
}
|
|
8662
|
+
/**
|
|
8663
|
+
* Plan or run experimental AI Enrichment Fusion with explicit spend controls.
|
|
8664
|
+
*/
|
|
8665
|
+
async fusion(params) {
|
|
8666
|
+
if (!params.prompt && !params.userTemplate && !params.user_template) {
|
|
8667
|
+
throw new Error("prompt or userTemplate is required.");
|
|
8668
|
+
}
|
|
8669
|
+
const data = await this.client.post("ai-enrichment-fusion", {
|
|
8670
|
+
...fusionRecordsFromParams(params),
|
|
8671
|
+
config: toFusionConfig(params),
|
|
8672
|
+
...toFusionSpendControls(params)
|
|
8673
|
+
});
|
|
8674
|
+
return {
|
|
8675
|
+
success: data.success ?? false,
|
|
8676
|
+
capability: data.capability ?? "ai_enrichment_fusion",
|
|
8677
|
+
displayName: data.display_name ?? "AI Enrichment Fusion",
|
|
8678
|
+
results: data.results ?? [],
|
|
8679
|
+
creditsUsed: data.total_credits_used ?? data.credits_used ?? 0,
|
|
8680
|
+
model: data.model,
|
|
8681
|
+
fusion: data.fusion,
|
|
8682
|
+
tokensUsed: data.tokens_used ?? 0,
|
|
8683
|
+
costUsd: data.cost_usd ?? 0,
|
|
8684
|
+
costSummary: data.cost_summary,
|
|
8685
|
+
billingMetadata: data.billing_metadata,
|
|
8686
|
+
raw: data
|
|
8687
|
+
};
|
|
8688
|
+
}
|
|
7891
8689
|
};
|
|
7892
8690
|
|
|
7893
8691
|
// src/resources/gtm-kernel.ts
|
|
@@ -8427,6 +9225,24 @@ var GtmKernel = class {
|
|
|
8427
9225
|
limit: input.limit
|
|
8428
9226
|
});
|
|
8429
9227
|
}
|
|
9228
|
+
/** Predict booked-meeting likelihood for uploaded, inline, or MCP-sourced lead rows without persisting raw rows. */
|
|
9229
|
+
async predictMeetingLikelihood(input) {
|
|
9230
|
+
return this.callMcp("gtm_predict_meeting_likelihood", {
|
|
9231
|
+
lead_rows: input.leadRows,
|
|
9232
|
+
input_source: input.inputSource,
|
|
9233
|
+
campaign_id: input.campaignId,
|
|
9234
|
+
campaign_build_id: input.campaignBuildId,
|
|
9235
|
+
days: input.days,
|
|
9236
|
+
feedback_limit: input.feedbackLimit,
|
|
9237
|
+
include_features: input.includeFeatures,
|
|
9238
|
+
include_global: input.includeGlobal,
|
|
9239
|
+
min_feedback_events: input.minFeedbackEvents,
|
|
9240
|
+
min_historical_feature_sample_size: input.minHistoricalFeatureSampleSize,
|
|
9241
|
+
min_workspace_count: input.minWorkspaceCount,
|
|
9242
|
+
min_privacy_k: input.minPrivacyK,
|
|
9243
|
+
limit: input.limit
|
|
9244
|
+
});
|
|
9245
|
+
}
|
|
8430
9246
|
/** Rank provider-chain, ICP, source, copy, and sequence failure patterns without writing raw lead data. */
|
|
8431
9247
|
async failurePatterns(options = {}) {
|
|
8432
9248
|
return this.callMcp("gtm_brain_failure_patterns", {
|
|
@@ -9042,6 +9858,70 @@ function compact2(value) {
|
|
|
9042
9858
|
return out;
|
|
9043
9859
|
}
|
|
9044
9860
|
|
|
9861
|
+
// src/resources/public-ground-truth.ts
|
|
9862
|
+
var PublicGroundTruth = class {
|
|
9863
|
+
constructor(client) {
|
|
9864
|
+
this.client = client;
|
|
9865
|
+
}
|
|
9866
|
+
/**
|
|
9867
|
+
* Search the public-ground-truth cache by company/name/domain/native ID,
|
|
9868
|
+
* or by plain-language industry + location.
|
|
9869
|
+
* Results use the same snake_case wire shape returned by the hosted MCP API.
|
|
9870
|
+
*/
|
|
9871
|
+
async search(params) {
|
|
9872
|
+
return this.client.mcp("tools/call", {
|
|
9873
|
+
name: "search_public_ground_truth",
|
|
9874
|
+
arguments: {
|
|
9875
|
+
query: params.query ?? params.search,
|
|
9876
|
+
industry: params.industry,
|
|
9877
|
+
location: params.location,
|
|
9878
|
+
source_id: params.sourceId ?? params.source_id,
|
|
9879
|
+
entity_type: params.entityType ?? params.entity_type,
|
|
9880
|
+
native_id: params.nativeId ?? params.native_id,
|
|
9881
|
+
entity_name: params.entityName ?? params.entity_name,
|
|
9882
|
+
domain: params.domain,
|
|
9883
|
+
website_url: params.websiteUrl ?? params.website_url,
|
|
9884
|
+
phone: params.phone,
|
|
9885
|
+
email: params.email,
|
|
9886
|
+
city: params.city,
|
|
9887
|
+
state: params.state,
|
|
9888
|
+
postal_code: params.postalCode ?? params.postal_code,
|
|
9889
|
+
country: params.country,
|
|
9890
|
+
source_url: params.sourceUrl ?? params.source_url,
|
|
9891
|
+
join_keys: params.joinKeys ?? params.join_keys,
|
|
9892
|
+
row_data: params.rowData ?? params.row_data,
|
|
9893
|
+
naics: params.naics,
|
|
9894
|
+
industry_code: params.industryCode ?? params.industry_code,
|
|
9895
|
+
industry_type: params.industryType ?? params.industry_type,
|
|
9896
|
+
year: params.year,
|
|
9897
|
+
quarter: params.quarter,
|
|
9898
|
+
area_fips: params.areaFips ?? params.area_fips,
|
|
9899
|
+
geo_id: params.geoId ?? params.geo_id,
|
|
9900
|
+
own_code: params.ownCode ?? params.own_code,
|
|
9901
|
+
source_updated_after: params.sourceUpdatedAfter ?? params.source_updated_after,
|
|
9902
|
+
source_updated_before: params.sourceUpdatedBefore ?? params.source_updated_before,
|
|
9903
|
+
observed_after: params.observedAfter ?? params.observed_after,
|
|
9904
|
+
observed_before: params.observedBefore ?? params.observed_before,
|
|
9905
|
+
limit: params.limit,
|
|
9906
|
+
offset: params.offset
|
|
9907
|
+
}
|
|
9908
|
+
});
|
|
9909
|
+
}
|
|
9910
|
+
/**
|
|
9911
|
+
* List available public-ground-truth cache sources and their join-key metadata.
|
|
9912
|
+
*/
|
|
9913
|
+
async listSources(params = {}) {
|
|
9914
|
+
return this.client.mcp("tools/call", {
|
|
9915
|
+
name: "list_public_ground_truth_sources",
|
|
9916
|
+
arguments: {
|
|
9917
|
+
query: params.query ?? params.search,
|
|
9918
|
+
status: params.status,
|
|
9919
|
+
limit: params.limit
|
|
9920
|
+
}
|
|
9921
|
+
});
|
|
9922
|
+
}
|
|
9923
|
+
};
|
|
9924
|
+
|
|
9045
9925
|
// src/index.ts
|
|
9046
9926
|
var MCP_TOOL_CACHE_TTL_MS = 3e4;
|
|
9047
9927
|
function inferMcpToolCategory(toolName) {
|
|
@@ -9084,6 +9964,7 @@ function inferMcpToolCategory(toolName) {
|
|
|
9084
9964
|
}
|
|
9085
9965
|
if (toolName.includes("icp")) return "icp";
|
|
9086
9966
|
if (toolName.startsWith("ai_clean_")) return "data_cleaning";
|
|
9967
|
+
if (toolName.includes("public_ground_truth")) return "public_data";
|
|
9087
9968
|
if (toolName.includes("system") || toolName.includes("workflow")) return "automation";
|
|
9088
9969
|
if (toolName.includes("agent") || toolName.includes("platform_health") || toolName === "discover_capabilities") return "observability";
|
|
9089
9970
|
return void 0;
|
|
@@ -9135,6 +10016,7 @@ var Signaliz = class {
|
|
|
9135
10016
|
this.ops = new Ops(this.client);
|
|
9136
10017
|
this.ai = new Ai(this.client);
|
|
9137
10018
|
this.gtm = new GtmKernel(this.client);
|
|
10019
|
+
this.publicGroundTruth = new PublicGroundTruth(this.client);
|
|
9138
10020
|
}
|
|
9139
10021
|
/** Get current workspace info including credits */
|
|
9140
10022
|
async getWorkspace() {
|