@signaliz/sdk 1.0.11 → 1.0.13
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 +16 -0
- package/dist/{chunk-QQW6DZQ4.mjs → chunk-DJVOGXVD.mjs} +285 -0
- package/dist/cli.js +389 -6
- package/dist/cli.mjs +106 -7
- package/dist/index.d.mts +78 -1
- package/dist/index.d.ts +78 -1
- package/dist/index.js +286 -0
- package/dist/index.mjs +3 -1
- package/dist/mcp-config.js +284 -0
- package/dist/mcp-config.mjs +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -38,6 +38,7 @@ __export(index_exports, {
|
|
|
38
38
|
createCampaignBuilderAgentPlan: () => createCampaignBuilderAgentPlan,
|
|
39
39
|
createCampaignBuilderAgentRequestTemplate: () => createCampaignBuilderAgentRequestTemplate,
|
|
40
40
|
createCampaignBuilderApproval: () => createCampaignBuilderApproval,
|
|
41
|
+
createCampaignBuilderReadiness: () => createCampaignBuilderReadiness,
|
|
41
42
|
createCampaignBuilderToolRoute: () => createCampaignBuilderToolRoute,
|
|
42
43
|
getCampaignBuilderOperatingPlaybook: () => getCampaignBuilderOperatingPlaybook,
|
|
43
44
|
getCampaignBuilderOperatingPlaybooksForRequest: () => getCampaignBuilderOperatingPlaybooksForRequest,
|
|
@@ -1240,6 +1241,13 @@ var DEFAULT_CAMPAIGN_BUILDER_BUILT_INS = [
|
|
|
1240
1241
|
"email_verification",
|
|
1241
1242
|
"signals"
|
|
1242
1243
|
];
|
|
1244
|
+
var CAMPAIGN_BUILDER_BUILT_IN_ROUTE_IDS = {
|
|
1245
|
+
lead_generation: "signaliz-lead-generation",
|
|
1246
|
+
local_leads: "signaliz-local-leads",
|
|
1247
|
+
email_finding: "signaliz-email-finding",
|
|
1248
|
+
email_verification: "signaliz-email-verification",
|
|
1249
|
+
signals: "signaliz-signals"
|
|
1250
|
+
};
|
|
1243
1251
|
var DEFAULT_CAMPAIGN_BUILDER_APPROVAL_TYPES = [
|
|
1244
1252
|
"memory_retrieval",
|
|
1245
1253
|
"spend",
|
|
@@ -1736,6 +1744,10 @@ var CampaignBuilderAgent = class {
|
|
|
1736
1744
|
}
|
|
1737
1745
|
return plan;
|
|
1738
1746
|
}
|
|
1747
|
+
async readiness(request, options = {}) {
|
|
1748
|
+
const plan = await this.createPlan(request, options);
|
|
1749
|
+
return createCampaignBuilderReadiness(plan);
|
|
1750
|
+
}
|
|
1739
1751
|
async commitPlan(plan, options = {}) {
|
|
1740
1752
|
const writeMode = options.confirm === true && options.dryRun === false;
|
|
1741
1753
|
if (writeMode && !options.approvedBy) {
|
|
@@ -1923,6 +1935,15 @@ var CampaignBuilderAgent = class {
|
|
|
1923
1935
|
async approveDelivery(campaignBuildId, destinationType, options) {
|
|
1924
1936
|
return this.approveCampaignDelivery(campaignBuildId, destinationType, options);
|
|
1925
1937
|
}
|
|
1938
|
+
async reviewBuild(campaignBuildId, options = {}) {
|
|
1939
|
+
const status = await this.getBuildStatus(campaignBuildId);
|
|
1940
|
+
const rows = await this.getBuildRows(campaignBuildId, {
|
|
1941
|
+
...options,
|
|
1942
|
+
limit: options.limit ?? 100
|
|
1943
|
+
});
|
|
1944
|
+
const artifacts = await this.listBuildArtifacts(campaignBuildId);
|
|
1945
|
+
return createCampaignBuilderBuildReview(status, rows, artifacts);
|
|
1946
|
+
}
|
|
1926
1947
|
async getCampaignBuildStatus(campaignBuildId) {
|
|
1927
1948
|
const data = await this.callMcp("get_campaign_build_status", {
|
|
1928
1949
|
campaign_build_id: campaignBuildId
|
|
@@ -2087,6 +2108,91 @@ function createCampaignBuilderAgentPlan(request, context = {}) {
|
|
|
2087
2108
|
warnings: context.warnings ?? []
|
|
2088
2109
|
};
|
|
2089
2110
|
}
|
|
2111
|
+
function createCampaignBuilderReadiness(plan) {
|
|
2112
|
+
const lanes = plan.routes.map((route) => createCampaignBuilderReadinessLane(route, plan));
|
|
2113
|
+
const builtInLanes = lanes.filter((lane) => lane.builtIn);
|
|
2114
|
+
const customRoutes = lanes.filter((lane) => lane.customRoute);
|
|
2115
|
+
const strategyMemory = asRecord(plan.strategyMemoryStatus);
|
|
2116
|
+
const deliveryRisk = asRecord(plan.buildRequest.deliveryRisk);
|
|
2117
|
+
const deliveryRiskBlockers = arrayOfStrings(deliveryRisk.blockers) ?? [];
|
|
2118
|
+
const deliveryRiskValue = asRecord(deliveryRisk.risk);
|
|
2119
|
+
const deliveryRiskLevel = stringValue(deliveryRiskValue.risk_level ?? deliveryRiskValue.riskLevel);
|
|
2120
|
+
const memoryReady = !plan.strategyMemoryStatus || strategyMemory.ready !== false;
|
|
2121
|
+
const kernelPlanReady = Object.keys(asRecord(plan.kernelPlan)).length > 0;
|
|
2122
|
+
const deliveryRiskReady = !plan.buildRequest.deliveryRisk || deliveryRiskBlockers.length === 0 && !["high", "critical", "blocked"].includes(String(deliveryRiskLevel ?? "").toLowerCase());
|
|
2123
|
+
const builtInsReady = builtInLanes.length > 0 && builtInLanes.every((lane) => lane.ready);
|
|
2124
|
+
const customRoutesReady = customRoutes.every((lane) => lane.ready);
|
|
2125
|
+
const approvalGatesReady = plan.approvals.length > 0;
|
|
2126
|
+
const gates = [
|
|
2127
|
+
{
|
|
2128
|
+
id: "campaign_plan_created",
|
|
2129
|
+
label: "Campaign plan created",
|
|
2130
|
+
passed: Boolean(plan.planId && plan.mcpFlow.length > 0),
|
|
2131
|
+
detail: plan.planId ? `Plan ${plan.planId} has ${plan.mcpFlow.length} MCP step(s).` : "No campaign-builder plan was created."
|
|
2132
|
+
},
|
|
2133
|
+
{
|
|
2134
|
+
id: "built_in_lanes_ready",
|
|
2135
|
+
label: "Built-in lanes ready",
|
|
2136
|
+
passed: builtInsReady,
|
|
2137
|
+
detail: `${builtInLanes.filter((lane) => lane.ready).length}/${builtInLanes.length} Signaliz built-in lane(s) are present.`
|
|
2138
|
+
},
|
|
2139
|
+
{
|
|
2140
|
+
id: "strategy_memory_ready",
|
|
2141
|
+
label: "Strategy memory ready",
|
|
2142
|
+
passed: memoryReady,
|
|
2143
|
+
detail: plan.strategyMemoryStatus ? "Strategy memory readiness was checked." : "Strategy memory readiness was not requested."
|
|
2144
|
+
},
|
|
2145
|
+
{
|
|
2146
|
+
id: "kernel_plan_attached",
|
|
2147
|
+
label: "Kernel plan attached",
|
|
2148
|
+
passed: kernelPlanReady,
|
|
2149
|
+
detail: kernelPlanReady ? "Kernel planner evidence is attached." : "Kernel planner evidence is not attached."
|
|
2150
|
+
},
|
|
2151
|
+
{
|
|
2152
|
+
id: "delivery_risk_clear",
|
|
2153
|
+
label: "Delivery risk clear",
|
|
2154
|
+
passed: deliveryRiskReady,
|
|
2155
|
+
detail: plan.buildRequest.deliveryRisk ? `Delivery risk is ${deliveryRiskLevel || "available"} with ${deliveryRiskBlockers.length} blocker(s).` : "Delivery risk preflight was not requested."
|
|
2156
|
+
},
|
|
2157
|
+
{
|
|
2158
|
+
id: "custom_routes_prepared",
|
|
2159
|
+
label: "Custom routes prepared",
|
|
2160
|
+
passed: customRoutesReady,
|
|
2161
|
+
detail: customRoutes.length === 0 ? "No BYO routes were requested." : `${customRoutes.filter((lane) => lane.ready).length}/${customRoutes.length} BYO route(s) have read-only setup steps.`
|
|
2162
|
+
},
|
|
2163
|
+
{
|
|
2164
|
+
id: "approval_gates_present",
|
|
2165
|
+
label: "Approval gates present",
|
|
2166
|
+
passed: approvalGatesReady,
|
|
2167
|
+
detail: approvalGatesReady ? `${plan.approvals.length} approval gate(s) are attached.` : "No approval gates are attached."
|
|
2168
|
+
}
|
|
2169
|
+
];
|
|
2170
|
+
const blockers = [
|
|
2171
|
+
...gates.filter((gate) => !gate.passed).map((gate) => gate.detail),
|
|
2172
|
+
...lanes.flatMap((lane) => lane.blockers)
|
|
2173
|
+
];
|
|
2174
|
+
const score = gates.length === 0 ? 0 : Math.round(gates.filter((gate) => gate.passed).length / gates.length * 100);
|
|
2175
|
+
const ready = blockers.length === 0;
|
|
2176
|
+
return {
|
|
2177
|
+
plan,
|
|
2178
|
+
lanes,
|
|
2179
|
+
gates,
|
|
2180
|
+
summary: {
|
|
2181
|
+
ready,
|
|
2182
|
+
score,
|
|
2183
|
+
targetCount: plan.targetCount,
|
|
2184
|
+
estimatedCredits: plan.estimatedCredits,
|
|
2185
|
+
builtInLanesReady: builtInLanes.filter((lane) => lane.ready).length,
|
|
2186
|
+
builtInLanesTotal: builtInLanes.length,
|
|
2187
|
+
customRoutesReady: customRoutes.filter((lane) => lane.ready).length,
|
|
2188
|
+
customRoutesTotal: customRoutes.length,
|
|
2189
|
+
approvalGateCount: plan.approvals.length,
|
|
2190
|
+
blockers,
|
|
2191
|
+
warnings: plan.warnings
|
|
2192
|
+
},
|
|
2193
|
+
nextActions: campaignReadinessNextActions(plan, ready, customRoutes.length)
|
|
2194
|
+
};
|
|
2195
|
+
}
|
|
2090
2196
|
function getMissingCampaignBuilderApprovals(plan, approval) {
|
|
2091
2197
|
if (approval.planId !== plan.planId) {
|
|
2092
2198
|
return plan.approvals;
|
|
@@ -3350,6 +3456,185 @@ function mapAgentCampaignArtifact(data) {
|
|
|
3350
3456
|
createdAt: stringValue(data.created_at) ?? ""
|
|
3351
3457
|
};
|
|
3352
3458
|
}
|
|
3459
|
+
function createCampaignBuilderBuildReview(status, rows, artifacts) {
|
|
3460
|
+
const sampledRows = rows.rows.length;
|
|
3461
|
+
const availableRows = rows.count || sampledRows;
|
|
3462
|
+
const qualifiedRows = rows.rows.filter((row) => row.qualified !== false).length;
|
|
3463
|
+
const rowsWithEmail = rows.rows.filter(campaignReviewRowHasEmail).length;
|
|
3464
|
+
const copyReadyRows = rows.rows.filter(campaignReviewRowHasCopy).length;
|
|
3465
|
+
const artifactCount = artifacts.length || status.artifactCount || 0;
|
|
3466
|
+
const gates = [
|
|
3467
|
+
{
|
|
3468
|
+
id: "build_completed",
|
|
3469
|
+
label: "Build completed",
|
|
3470
|
+
passed: status.status === "completed",
|
|
3471
|
+
detail: status.status === "completed" ? "The campaign build is completed." : `The campaign build is ${status.status}; review again after completion.`
|
|
3472
|
+
},
|
|
3473
|
+
{
|
|
3474
|
+
id: "rows_available",
|
|
3475
|
+
label: "Rows available",
|
|
3476
|
+
passed: sampledRows > 0,
|
|
3477
|
+
detail: sampledRows > 0 ? `${sampledRows} sampled row(s) are available for review.` : "No rows were returned for review."
|
|
3478
|
+
},
|
|
3479
|
+
{
|
|
3480
|
+
id: "qualified_sample",
|
|
3481
|
+
label: "Sample rows qualified",
|
|
3482
|
+
passed: sampledRows > 0 && qualifiedRows === sampledRows,
|
|
3483
|
+
detail: sampledRows > 0 ? `${qualifiedRows}/${sampledRows} sampled row(s) are marked qualified.` : "Qualification could not be checked without sampled rows."
|
|
3484
|
+
},
|
|
3485
|
+
{
|
|
3486
|
+
id: "email_coverage",
|
|
3487
|
+
label: "Email coverage",
|
|
3488
|
+
passed: sampledRows > 0 && rowsWithEmail === sampledRows,
|
|
3489
|
+
detail: sampledRows > 0 ? `${rowsWithEmail}/${sampledRows} sampled row(s) include an email.` : "Email coverage could not be checked without sampled rows."
|
|
3490
|
+
},
|
|
3491
|
+
{
|
|
3492
|
+
id: "artifact_available",
|
|
3493
|
+
label: "Artifact available",
|
|
3494
|
+
passed: artifactCount > 0,
|
|
3495
|
+
detail: artifactCount > 0 ? `${artifactCount} artifact(s) are available.` : "No delivery artifact is available yet."
|
|
3496
|
+
},
|
|
3497
|
+
{
|
|
3498
|
+
id: "no_failed_rows",
|
|
3499
|
+
label: "No failed rows",
|
|
3500
|
+
passed: status.recordsFailed === 0,
|
|
3501
|
+
detail: status.recordsFailed === 0 ? "The build reports zero failed rows." : `${status.recordsFailed} row(s) failed during the build.`
|
|
3502
|
+
}
|
|
3503
|
+
];
|
|
3504
|
+
const blockedReasons = gates.filter((gate) => !gate.passed).map((gate) => gate.detail);
|
|
3505
|
+
const warnings = [
|
|
3506
|
+
rows.hasMore ? "This review is based on a row sample; page through remaining rows before final approval." : void 0,
|
|
3507
|
+
sampledRows > 0 && copyReadyRows < sampledRows ? `${copyReadyRows}/${sampledRows} sampled row(s) include generated copy.` : void 0,
|
|
3508
|
+
...status.warnings
|
|
3509
|
+
].filter((item) => Boolean(item));
|
|
3510
|
+
const readyForDeliveryApproval = blockedReasons.length === 0;
|
|
3511
|
+
return {
|
|
3512
|
+
campaignBuildId: status.campaignBuildId || rows.campaignBuildId,
|
|
3513
|
+
status,
|
|
3514
|
+
rows,
|
|
3515
|
+
artifacts,
|
|
3516
|
+
gates,
|
|
3517
|
+
summary: {
|
|
3518
|
+
status: status.status,
|
|
3519
|
+
phase: status.currentPhase,
|
|
3520
|
+
sampledRows,
|
|
3521
|
+
availableRows,
|
|
3522
|
+
qualifiedRows,
|
|
3523
|
+
rowsWithEmail,
|
|
3524
|
+
copyReadyRows,
|
|
3525
|
+
artifactCount,
|
|
3526
|
+
readyForDeliveryApproval,
|
|
3527
|
+
blockedReasons,
|
|
3528
|
+
warnings
|
|
3529
|
+
},
|
|
3530
|
+
nextActions: campaignReviewNextActions(status, readyForDeliveryApproval)
|
|
3531
|
+
};
|
|
3532
|
+
}
|
|
3533
|
+
function campaignReviewNextActions(status, readyForDeliveryApproval) {
|
|
3534
|
+
const buildId = status.campaignBuildId;
|
|
3535
|
+
if (!buildId) return [];
|
|
3536
|
+
if (status.status === "completed" && readyForDeliveryApproval) {
|
|
3537
|
+
return [
|
|
3538
|
+
`signaliz campaign-agent approve ${buildId} --destination-type json`,
|
|
3539
|
+
`signaliz campaign-agent artifacts ${buildId}`
|
|
3540
|
+
];
|
|
3541
|
+
}
|
|
3542
|
+
if (status.status === "completed") {
|
|
3543
|
+
return [
|
|
3544
|
+
`signaliz campaign-agent rows ${buildId} --limit 100`,
|
|
3545
|
+
`signaliz campaign-agent artifacts ${buildId}`
|
|
3546
|
+
];
|
|
3547
|
+
}
|
|
3548
|
+
if (status.status === "pending_approval") {
|
|
3549
|
+
return [
|
|
3550
|
+
`signaliz campaign-agent rows ${buildId} --limit 100`,
|
|
3551
|
+
`signaliz campaign-agent approve ${buildId} --destination-type json`
|
|
3552
|
+
];
|
|
3553
|
+
}
|
|
3554
|
+
if ((status.status === "queued" || status.status === "running") && status.triggerRunId) {
|
|
3555
|
+
return [`signaliz ops run-status ${status.triggerRunId} --watch`];
|
|
3556
|
+
}
|
|
3557
|
+
return [`signaliz campaign-agent status ${buildId}`];
|
|
3558
|
+
}
|
|
3559
|
+
function campaignReviewRowHasEmail(row) {
|
|
3560
|
+
const data = asRecord(row.data);
|
|
3561
|
+
return Boolean(
|
|
3562
|
+
stringValue(data.email) || stringValue(data.work_email) || stringValue(data.workEmail)
|
|
3563
|
+
);
|
|
3564
|
+
}
|
|
3565
|
+
function campaignReviewRowHasCopy(row) {
|
|
3566
|
+
const data = asRecord(row.data);
|
|
3567
|
+
const copy = asRecord(data.copy);
|
|
3568
|
+
const rawCopy = asRecord(data.raw_copy ?? data.rawCopy);
|
|
3569
|
+
return row.status === "copy_ready" || data.copy_ready === true || Boolean(
|
|
3570
|
+
stringValue(data.subject) || stringValue(data.subject_line) || stringValue(data.subjectLine) || stringValue(data.opener) || stringValue(data.body) || stringValue(data.cta) || stringValue(copy.subject) || stringValue(copy.body) || stringValue(rawCopy.subject) || stringValue(rawCopy.body)
|
|
3571
|
+
);
|
|
3572
|
+
}
|
|
3573
|
+
function createCampaignBuilderReadinessLane(route, plan) {
|
|
3574
|
+
const builtIn = campaignBuilderBuiltInForRoute(route);
|
|
3575
|
+
const customRoute = route.provider !== "signaliz" && route.provider !== "csv" && builtIn === void 0;
|
|
3576
|
+
const prepareStep = plan.mcpFlow.find(
|
|
3577
|
+
(step) => step.tool === "gtm_provider_recipe_prepare" && step.arguments.provider_id === route.provider
|
|
3578
|
+
);
|
|
3579
|
+
const activateStep = plan.mcpFlow.find(
|
|
3580
|
+
(step) => step.tool === "gtm_provider_route_activate" && step.arguments.provider_id === route.provider
|
|
3581
|
+
);
|
|
3582
|
+
const readOnlySetup = !customRoute || prepareStep?.readOnly === true && activateStep?.readOnly === true && activateStep.arguments.dry_run === true && activateStep.arguments.confirm === false;
|
|
3583
|
+
const blockers = [
|
|
3584
|
+
customRoute && !prepareStep ? `${route.label ?? route.provider} is missing provider recipe setup.` : void 0,
|
|
3585
|
+
customRoute && !activateStep ? `${route.label ?? route.provider} is missing provider route dry-run setup.` : void 0,
|
|
3586
|
+
customRoute && !readOnlySetup ? `${route.label ?? route.provider} route setup must stay read-only before approval.` : void 0,
|
|
3587
|
+
route.mode === "required" && !route.toolName && customRoute ? `${route.label ?? route.provider} is required but has no tool name.` : void 0
|
|
3588
|
+
].filter((item) => Boolean(item));
|
|
3589
|
+
return {
|
|
3590
|
+
id: route.id ?? `${route.provider}-${route.layer}`,
|
|
3591
|
+
label: route.label ?? readinessLaneLabel(route, builtIn),
|
|
3592
|
+
layer: route.layer,
|
|
3593
|
+
gtmLayers: gtmLayersForRoute(route),
|
|
3594
|
+
provider: route.provider,
|
|
3595
|
+
toolName: route.toolName,
|
|
3596
|
+
mode: route.mode ?? "if_available",
|
|
3597
|
+
builtIn,
|
|
3598
|
+
approvalRequired: route.approvalRequired === true || plan.approvals.some((approval) => approval.routeId === route.id),
|
|
3599
|
+
customRoute,
|
|
3600
|
+
readOnlySetup,
|
|
3601
|
+
ready: blockers.length === 0,
|
|
3602
|
+
blockers,
|
|
3603
|
+
nextAction: customRoute ? `Review ${route.provider} route setup before launch approval.` : void 0
|
|
3604
|
+
};
|
|
3605
|
+
}
|
|
3606
|
+
function campaignBuilderBuiltInForRoute(route) {
|
|
3607
|
+
return Object.entries(CAMPAIGN_BUILDER_BUILT_IN_ROUTE_IDS).find(([, routeId]) => route.id === routeId)?.[0];
|
|
3608
|
+
}
|
|
3609
|
+
function readinessLaneLabel(route, builtIn) {
|
|
3610
|
+
if (builtIn) {
|
|
3611
|
+
const labels = {
|
|
3612
|
+
lead_generation: "Signaliz lead generation",
|
|
3613
|
+
local_leads: "Signaliz local leads",
|
|
3614
|
+
email_finding: "Signaliz email finding",
|
|
3615
|
+
email_verification: "Signaliz email verification",
|
|
3616
|
+
signals: "Signaliz signals"
|
|
3617
|
+
};
|
|
3618
|
+
return labels[builtIn];
|
|
3619
|
+
}
|
|
3620
|
+
return `${route.provider} ${route.layer}`;
|
|
3621
|
+
}
|
|
3622
|
+
function campaignReadinessNextActions(plan, ready, customRouteCount) {
|
|
3623
|
+
const requestHint = "--request-file campaign-request.json";
|
|
3624
|
+
if (ready) {
|
|
3625
|
+
return [
|
|
3626
|
+
`signaliz campaign-agent proof ${requestHint} --json`,
|
|
3627
|
+
`signaliz campaign-agent commit-plan ${requestHint} --json`,
|
|
3628
|
+
`signaliz campaign-agent build-approved ${requestHint} --confirm-launch --approve-all --approved-by operator@example.com --spend-limit ${plan.estimatedCredits}`
|
|
3629
|
+
];
|
|
3630
|
+
}
|
|
3631
|
+
const actions = [
|
|
3632
|
+
plan.strategyMemoryStatus && asRecord(plan.strategyMemoryStatus).ready === false ? "signaliz gtm strategy-memory --strategy-template <strategy_template> --include-samples --json" : void 0,
|
|
3633
|
+
customRouteCount > 0 ? "Review BYO provider recipe and route dry-run steps in the readiness packet." : void 0,
|
|
3634
|
+
`signaliz campaign-agent plan ${requestHint} --json`
|
|
3635
|
+
];
|
|
3636
|
+
return actions.filter((item) => Boolean(item));
|
|
3637
|
+
}
|
|
3353
3638
|
function diagnosticMessages2(value) {
|
|
3354
3639
|
if (!Array.isArray(value)) return [];
|
|
3355
3640
|
return value.map((item) => {
|
|
@@ -6369,6 +6654,7 @@ var Signaliz = class {
|
|
|
6369
6654
|
createCampaignBuilderAgentPlan,
|
|
6370
6655
|
createCampaignBuilderAgentRequestTemplate,
|
|
6371
6656
|
createCampaignBuilderApproval,
|
|
6657
|
+
createCampaignBuilderReadiness,
|
|
6372
6658
|
createCampaignBuilderToolRoute,
|
|
6373
6659
|
getCampaignBuilderOperatingPlaybook,
|
|
6374
6660
|
getCampaignBuilderOperatingPlaybooksForRequest,
|
package/dist/index.mjs
CHANGED
|
@@ -17,13 +17,14 @@ import {
|
|
|
17
17
|
createCampaignBuilderAgentPlan,
|
|
18
18
|
createCampaignBuilderAgentRequestTemplate,
|
|
19
19
|
createCampaignBuilderApproval,
|
|
20
|
+
createCampaignBuilderReadiness,
|
|
20
21
|
createCampaignBuilderToolRoute,
|
|
21
22
|
getCampaignBuilderOperatingPlaybook,
|
|
22
23
|
getCampaignBuilderOperatingPlaybooksForRequest,
|
|
23
24
|
getCampaignBuilderStrategyTemplate,
|
|
24
25
|
getMissingCampaignBuilderApprovals,
|
|
25
26
|
normalizeExecutionReference
|
|
26
|
-
} from "./chunk-
|
|
27
|
+
} from "./chunk-DJVOGXVD.mjs";
|
|
27
28
|
export {
|
|
28
29
|
Ai,
|
|
29
30
|
CAMPAIGN_BUILDER_OPERATING_PLAYBOOKS,
|
|
@@ -43,6 +44,7 @@ export {
|
|
|
43
44
|
createCampaignBuilderAgentPlan,
|
|
44
45
|
createCampaignBuilderAgentRequestTemplate,
|
|
45
46
|
createCampaignBuilderApproval,
|
|
47
|
+
createCampaignBuilderReadiness,
|
|
46
48
|
createCampaignBuilderToolRoute,
|
|
47
49
|
getCampaignBuilderOperatingPlaybook,
|
|
48
50
|
getCampaignBuilderOperatingPlaybooksForRequest,
|
package/dist/mcp-config.js
CHANGED
|
@@ -1222,6 +1222,13 @@ var DEFAULT_CAMPAIGN_BUILDER_BUILT_INS = [
|
|
|
1222
1222
|
"email_verification",
|
|
1223
1223
|
"signals"
|
|
1224
1224
|
];
|
|
1225
|
+
var CAMPAIGN_BUILDER_BUILT_IN_ROUTE_IDS = {
|
|
1226
|
+
lead_generation: "signaliz-lead-generation",
|
|
1227
|
+
local_leads: "signaliz-local-leads",
|
|
1228
|
+
email_finding: "signaliz-email-finding",
|
|
1229
|
+
email_verification: "signaliz-email-verification",
|
|
1230
|
+
signals: "signaliz-signals"
|
|
1231
|
+
};
|
|
1225
1232
|
var CAMPAIGN_BUILDER_OPERATING_PLAYBOOKS = [
|
|
1226
1233
|
{
|
|
1227
1234
|
slug: "cache-first-large-list",
|
|
@@ -1710,6 +1717,10 @@ var CampaignBuilderAgent = class {
|
|
|
1710
1717
|
}
|
|
1711
1718
|
return plan;
|
|
1712
1719
|
}
|
|
1720
|
+
async readiness(request, options = {}) {
|
|
1721
|
+
const plan = await this.createPlan(request, options);
|
|
1722
|
+
return createCampaignBuilderReadiness(plan);
|
|
1723
|
+
}
|
|
1713
1724
|
async commitPlan(plan, options = {}) {
|
|
1714
1725
|
const writeMode = options.confirm === true && options.dryRun === false;
|
|
1715
1726
|
if (writeMode && !options.approvedBy) {
|
|
@@ -1897,6 +1908,15 @@ var CampaignBuilderAgent = class {
|
|
|
1897
1908
|
async approveDelivery(campaignBuildId, destinationType, options) {
|
|
1898
1909
|
return this.approveCampaignDelivery(campaignBuildId, destinationType, options);
|
|
1899
1910
|
}
|
|
1911
|
+
async reviewBuild(campaignBuildId, options = {}) {
|
|
1912
|
+
const status = await this.getBuildStatus(campaignBuildId);
|
|
1913
|
+
const rows = await this.getBuildRows(campaignBuildId, {
|
|
1914
|
+
...options,
|
|
1915
|
+
limit: options.limit ?? 100
|
|
1916
|
+
});
|
|
1917
|
+
const artifacts = await this.listBuildArtifacts(campaignBuildId);
|
|
1918
|
+
return createCampaignBuilderBuildReview(status, rows, artifacts);
|
|
1919
|
+
}
|
|
1900
1920
|
async getCampaignBuildStatus(campaignBuildId) {
|
|
1901
1921
|
const data = await this.callMcp("get_campaign_build_status", {
|
|
1902
1922
|
campaign_build_id: campaignBuildId
|
|
@@ -2061,6 +2081,91 @@ function createCampaignBuilderAgentPlan(request, context = {}) {
|
|
|
2061
2081
|
warnings: context.warnings ?? []
|
|
2062
2082
|
};
|
|
2063
2083
|
}
|
|
2084
|
+
function createCampaignBuilderReadiness(plan) {
|
|
2085
|
+
const lanes = plan.routes.map((route) => createCampaignBuilderReadinessLane(route, plan));
|
|
2086
|
+
const builtInLanes = lanes.filter((lane) => lane.builtIn);
|
|
2087
|
+
const customRoutes = lanes.filter((lane) => lane.customRoute);
|
|
2088
|
+
const strategyMemory = asRecord(plan.strategyMemoryStatus);
|
|
2089
|
+
const deliveryRisk = asRecord(plan.buildRequest.deliveryRisk);
|
|
2090
|
+
const deliveryRiskBlockers = arrayOfStrings(deliveryRisk.blockers) ?? [];
|
|
2091
|
+
const deliveryRiskValue = asRecord(deliveryRisk.risk);
|
|
2092
|
+
const deliveryRiskLevel = stringValue(deliveryRiskValue.risk_level ?? deliveryRiskValue.riskLevel);
|
|
2093
|
+
const memoryReady = !plan.strategyMemoryStatus || strategyMemory.ready !== false;
|
|
2094
|
+
const kernelPlanReady = Object.keys(asRecord(plan.kernelPlan)).length > 0;
|
|
2095
|
+
const deliveryRiskReady = !plan.buildRequest.deliveryRisk || deliveryRiskBlockers.length === 0 && !["high", "critical", "blocked"].includes(String(deliveryRiskLevel ?? "").toLowerCase());
|
|
2096
|
+
const builtInsReady = builtInLanes.length > 0 && builtInLanes.every((lane) => lane.ready);
|
|
2097
|
+
const customRoutesReady = customRoutes.every((lane) => lane.ready);
|
|
2098
|
+
const approvalGatesReady = plan.approvals.length > 0;
|
|
2099
|
+
const gates = [
|
|
2100
|
+
{
|
|
2101
|
+
id: "campaign_plan_created",
|
|
2102
|
+
label: "Campaign plan created",
|
|
2103
|
+
passed: Boolean(plan.planId && plan.mcpFlow.length > 0),
|
|
2104
|
+
detail: plan.planId ? `Plan ${plan.planId} has ${plan.mcpFlow.length} MCP step(s).` : "No campaign-builder plan was created."
|
|
2105
|
+
},
|
|
2106
|
+
{
|
|
2107
|
+
id: "built_in_lanes_ready",
|
|
2108
|
+
label: "Built-in lanes ready",
|
|
2109
|
+
passed: builtInsReady,
|
|
2110
|
+
detail: `${builtInLanes.filter((lane) => lane.ready).length}/${builtInLanes.length} Signaliz built-in lane(s) are present.`
|
|
2111
|
+
},
|
|
2112
|
+
{
|
|
2113
|
+
id: "strategy_memory_ready",
|
|
2114
|
+
label: "Strategy memory ready",
|
|
2115
|
+
passed: memoryReady,
|
|
2116
|
+
detail: plan.strategyMemoryStatus ? "Strategy memory readiness was checked." : "Strategy memory readiness was not requested."
|
|
2117
|
+
},
|
|
2118
|
+
{
|
|
2119
|
+
id: "kernel_plan_attached",
|
|
2120
|
+
label: "Kernel plan attached",
|
|
2121
|
+
passed: kernelPlanReady,
|
|
2122
|
+
detail: kernelPlanReady ? "Kernel planner evidence is attached." : "Kernel planner evidence is not attached."
|
|
2123
|
+
},
|
|
2124
|
+
{
|
|
2125
|
+
id: "delivery_risk_clear",
|
|
2126
|
+
label: "Delivery risk clear",
|
|
2127
|
+
passed: deliveryRiskReady,
|
|
2128
|
+
detail: plan.buildRequest.deliveryRisk ? `Delivery risk is ${deliveryRiskLevel || "available"} with ${deliveryRiskBlockers.length} blocker(s).` : "Delivery risk preflight was not requested."
|
|
2129
|
+
},
|
|
2130
|
+
{
|
|
2131
|
+
id: "custom_routes_prepared",
|
|
2132
|
+
label: "Custom routes prepared",
|
|
2133
|
+
passed: customRoutesReady,
|
|
2134
|
+
detail: customRoutes.length === 0 ? "No BYO routes were requested." : `${customRoutes.filter((lane) => lane.ready).length}/${customRoutes.length} BYO route(s) have read-only setup steps.`
|
|
2135
|
+
},
|
|
2136
|
+
{
|
|
2137
|
+
id: "approval_gates_present",
|
|
2138
|
+
label: "Approval gates present",
|
|
2139
|
+
passed: approvalGatesReady,
|
|
2140
|
+
detail: approvalGatesReady ? `${plan.approvals.length} approval gate(s) are attached.` : "No approval gates are attached."
|
|
2141
|
+
}
|
|
2142
|
+
];
|
|
2143
|
+
const blockers = [
|
|
2144
|
+
...gates.filter((gate) => !gate.passed).map((gate) => gate.detail),
|
|
2145
|
+
...lanes.flatMap((lane) => lane.blockers)
|
|
2146
|
+
];
|
|
2147
|
+
const score = gates.length === 0 ? 0 : Math.round(gates.filter((gate) => gate.passed).length / gates.length * 100);
|
|
2148
|
+
const ready = blockers.length === 0;
|
|
2149
|
+
return {
|
|
2150
|
+
plan,
|
|
2151
|
+
lanes,
|
|
2152
|
+
gates,
|
|
2153
|
+
summary: {
|
|
2154
|
+
ready,
|
|
2155
|
+
score,
|
|
2156
|
+
targetCount: plan.targetCount,
|
|
2157
|
+
estimatedCredits: plan.estimatedCredits,
|
|
2158
|
+
builtInLanesReady: builtInLanes.filter((lane) => lane.ready).length,
|
|
2159
|
+
builtInLanesTotal: builtInLanes.length,
|
|
2160
|
+
customRoutesReady: customRoutes.filter((lane) => lane.ready).length,
|
|
2161
|
+
customRoutesTotal: customRoutes.length,
|
|
2162
|
+
approvalGateCount: plan.approvals.length,
|
|
2163
|
+
blockers,
|
|
2164
|
+
warnings: plan.warnings
|
|
2165
|
+
},
|
|
2166
|
+
nextActions: campaignReadinessNextActions(plan, ready, customRoutes.length)
|
|
2167
|
+
};
|
|
2168
|
+
}
|
|
2064
2169
|
function getMissingCampaignBuilderApprovals(plan, approval) {
|
|
2065
2170
|
if (approval.planId !== plan.planId) {
|
|
2066
2171
|
return plan.approvals;
|
|
@@ -3223,6 +3328,185 @@ function mapAgentCampaignArtifact(data) {
|
|
|
3223
3328
|
createdAt: stringValue(data.created_at) ?? ""
|
|
3224
3329
|
};
|
|
3225
3330
|
}
|
|
3331
|
+
function createCampaignBuilderBuildReview(status, rows, artifacts) {
|
|
3332
|
+
const sampledRows = rows.rows.length;
|
|
3333
|
+
const availableRows = rows.count || sampledRows;
|
|
3334
|
+
const qualifiedRows = rows.rows.filter((row) => row.qualified !== false).length;
|
|
3335
|
+
const rowsWithEmail = rows.rows.filter(campaignReviewRowHasEmail).length;
|
|
3336
|
+
const copyReadyRows = rows.rows.filter(campaignReviewRowHasCopy).length;
|
|
3337
|
+
const artifactCount = artifacts.length || status.artifactCount || 0;
|
|
3338
|
+
const gates = [
|
|
3339
|
+
{
|
|
3340
|
+
id: "build_completed",
|
|
3341
|
+
label: "Build completed",
|
|
3342
|
+
passed: status.status === "completed",
|
|
3343
|
+
detail: status.status === "completed" ? "The campaign build is completed." : `The campaign build is ${status.status}; review again after completion.`
|
|
3344
|
+
},
|
|
3345
|
+
{
|
|
3346
|
+
id: "rows_available",
|
|
3347
|
+
label: "Rows available",
|
|
3348
|
+
passed: sampledRows > 0,
|
|
3349
|
+
detail: sampledRows > 0 ? `${sampledRows} sampled row(s) are available for review.` : "No rows were returned for review."
|
|
3350
|
+
},
|
|
3351
|
+
{
|
|
3352
|
+
id: "qualified_sample",
|
|
3353
|
+
label: "Sample rows qualified",
|
|
3354
|
+
passed: sampledRows > 0 && qualifiedRows === sampledRows,
|
|
3355
|
+
detail: sampledRows > 0 ? `${qualifiedRows}/${sampledRows} sampled row(s) are marked qualified.` : "Qualification could not be checked without sampled rows."
|
|
3356
|
+
},
|
|
3357
|
+
{
|
|
3358
|
+
id: "email_coverage",
|
|
3359
|
+
label: "Email coverage",
|
|
3360
|
+
passed: sampledRows > 0 && rowsWithEmail === sampledRows,
|
|
3361
|
+
detail: sampledRows > 0 ? `${rowsWithEmail}/${sampledRows} sampled row(s) include an email.` : "Email coverage could not be checked without sampled rows."
|
|
3362
|
+
},
|
|
3363
|
+
{
|
|
3364
|
+
id: "artifact_available",
|
|
3365
|
+
label: "Artifact available",
|
|
3366
|
+
passed: artifactCount > 0,
|
|
3367
|
+
detail: artifactCount > 0 ? `${artifactCount} artifact(s) are available.` : "No delivery artifact is available yet."
|
|
3368
|
+
},
|
|
3369
|
+
{
|
|
3370
|
+
id: "no_failed_rows",
|
|
3371
|
+
label: "No failed rows",
|
|
3372
|
+
passed: status.recordsFailed === 0,
|
|
3373
|
+
detail: status.recordsFailed === 0 ? "The build reports zero failed rows." : `${status.recordsFailed} row(s) failed during the build.`
|
|
3374
|
+
}
|
|
3375
|
+
];
|
|
3376
|
+
const blockedReasons = gates.filter((gate) => !gate.passed).map((gate) => gate.detail);
|
|
3377
|
+
const warnings = [
|
|
3378
|
+
rows.hasMore ? "This review is based on a row sample; page through remaining rows before final approval." : void 0,
|
|
3379
|
+
sampledRows > 0 && copyReadyRows < sampledRows ? `${copyReadyRows}/${sampledRows} sampled row(s) include generated copy.` : void 0,
|
|
3380
|
+
...status.warnings
|
|
3381
|
+
].filter((item) => Boolean(item));
|
|
3382
|
+
const readyForDeliveryApproval = blockedReasons.length === 0;
|
|
3383
|
+
return {
|
|
3384
|
+
campaignBuildId: status.campaignBuildId || rows.campaignBuildId,
|
|
3385
|
+
status,
|
|
3386
|
+
rows,
|
|
3387
|
+
artifacts,
|
|
3388
|
+
gates,
|
|
3389
|
+
summary: {
|
|
3390
|
+
status: status.status,
|
|
3391
|
+
phase: status.currentPhase,
|
|
3392
|
+
sampledRows,
|
|
3393
|
+
availableRows,
|
|
3394
|
+
qualifiedRows,
|
|
3395
|
+
rowsWithEmail,
|
|
3396
|
+
copyReadyRows,
|
|
3397
|
+
artifactCount,
|
|
3398
|
+
readyForDeliveryApproval,
|
|
3399
|
+
blockedReasons,
|
|
3400
|
+
warnings
|
|
3401
|
+
},
|
|
3402
|
+
nextActions: campaignReviewNextActions(status, readyForDeliveryApproval)
|
|
3403
|
+
};
|
|
3404
|
+
}
|
|
3405
|
+
function campaignReviewNextActions(status, readyForDeliveryApproval) {
|
|
3406
|
+
const buildId = status.campaignBuildId;
|
|
3407
|
+
if (!buildId) return [];
|
|
3408
|
+
if (status.status === "completed" && readyForDeliveryApproval) {
|
|
3409
|
+
return [
|
|
3410
|
+
`signaliz campaign-agent approve ${buildId} --destination-type json`,
|
|
3411
|
+
`signaliz campaign-agent artifacts ${buildId}`
|
|
3412
|
+
];
|
|
3413
|
+
}
|
|
3414
|
+
if (status.status === "completed") {
|
|
3415
|
+
return [
|
|
3416
|
+
`signaliz campaign-agent rows ${buildId} --limit 100`,
|
|
3417
|
+
`signaliz campaign-agent artifacts ${buildId}`
|
|
3418
|
+
];
|
|
3419
|
+
}
|
|
3420
|
+
if (status.status === "pending_approval") {
|
|
3421
|
+
return [
|
|
3422
|
+
`signaliz campaign-agent rows ${buildId} --limit 100`,
|
|
3423
|
+
`signaliz campaign-agent approve ${buildId} --destination-type json`
|
|
3424
|
+
];
|
|
3425
|
+
}
|
|
3426
|
+
if ((status.status === "queued" || status.status === "running") && status.triggerRunId) {
|
|
3427
|
+
return [`signaliz ops run-status ${status.triggerRunId} --watch`];
|
|
3428
|
+
}
|
|
3429
|
+
return [`signaliz campaign-agent status ${buildId}`];
|
|
3430
|
+
}
|
|
3431
|
+
function campaignReviewRowHasEmail(row) {
|
|
3432
|
+
const data = asRecord(row.data);
|
|
3433
|
+
return Boolean(
|
|
3434
|
+
stringValue(data.email) || stringValue(data.work_email) || stringValue(data.workEmail)
|
|
3435
|
+
);
|
|
3436
|
+
}
|
|
3437
|
+
function campaignReviewRowHasCopy(row) {
|
|
3438
|
+
const data = asRecord(row.data);
|
|
3439
|
+
const copy = asRecord(data.copy);
|
|
3440
|
+
const rawCopy = asRecord(data.raw_copy ?? data.rawCopy);
|
|
3441
|
+
return row.status === "copy_ready" || data.copy_ready === true || Boolean(
|
|
3442
|
+
stringValue(data.subject) || stringValue(data.subject_line) || stringValue(data.subjectLine) || stringValue(data.opener) || stringValue(data.body) || stringValue(data.cta) || stringValue(copy.subject) || stringValue(copy.body) || stringValue(rawCopy.subject) || stringValue(rawCopy.body)
|
|
3443
|
+
);
|
|
3444
|
+
}
|
|
3445
|
+
function createCampaignBuilderReadinessLane(route, plan) {
|
|
3446
|
+
const builtIn = campaignBuilderBuiltInForRoute(route);
|
|
3447
|
+
const customRoute = route.provider !== "signaliz" && route.provider !== "csv" && builtIn === void 0;
|
|
3448
|
+
const prepareStep = plan.mcpFlow.find(
|
|
3449
|
+
(step) => step.tool === "gtm_provider_recipe_prepare" && step.arguments.provider_id === route.provider
|
|
3450
|
+
);
|
|
3451
|
+
const activateStep = plan.mcpFlow.find(
|
|
3452
|
+
(step) => step.tool === "gtm_provider_route_activate" && step.arguments.provider_id === route.provider
|
|
3453
|
+
);
|
|
3454
|
+
const readOnlySetup = !customRoute || prepareStep?.readOnly === true && activateStep?.readOnly === true && activateStep.arguments.dry_run === true && activateStep.arguments.confirm === false;
|
|
3455
|
+
const blockers = [
|
|
3456
|
+
customRoute && !prepareStep ? `${route.label ?? route.provider} is missing provider recipe setup.` : void 0,
|
|
3457
|
+
customRoute && !activateStep ? `${route.label ?? route.provider} is missing provider route dry-run setup.` : void 0,
|
|
3458
|
+
customRoute && !readOnlySetup ? `${route.label ?? route.provider} route setup must stay read-only before approval.` : void 0,
|
|
3459
|
+
route.mode === "required" && !route.toolName && customRoute ? `${route.label ?? route.provider} is required but has no tool name.` : void 0
|
|
3460
|
+
].filter((item) => Boolean(item));
|
|
3461
|
+
return {
|
|
3462
|
+
id: route.id ?? `${route.provider}-${route.layer}`,
|
|
3463
|
+
label: route.label ?? readinessLaneLabel(route, builtIn),
|
|
3464
|
+
layer: route.layer,
|
|
3465
|
+
gtmLayers: gtmLayersForRoute(route),
|
|
3466
|
+
provider: route.provider,
|
|
3467
|
+
toolName: route.toolName,
|
|
3468
|
+
mode: route.mode ?? "if_available",
|
|
3469
|
+
builtIn,
|
|
3470
|
+
approvalRequired: route.approvalRequired === true || plan.approvals.some((approval) => approval.routeId === route.id),
|
|
3471
|
+
customRoute,
|
|
3472
|
+
readOnlySetup,
|
|
3473
|
+
ready: blockers.length === 0,
|
|
3474
|
+
blockers,
|
|
3475
|
+
nextAction: customRoute ? `Review ${route.provider} route setup before launch approval.` : void 0
|
|
3476
|
+
};
|
|
3477
|
+
}
|
|
3478
|
+
function campaignBuilderBuiltInForRoute(route) {
|
|
3479
|
+
return Object.entries(CAMPAIGN_BUILDER_BUILT_IN_ROUTE_IDS).find(([, routeId]) => route.id === routeId)?.[0];
|
|
3480
|
+
}
|
|
3481
|
+
function readinessLaneLabel(route, builtIn) {
|
|
3482
|
+
if (builtIn) {
|
|
3483
|
+
const labels = {
|
|
3484
|
+
lead_generation: "Signaliz lead generation",
|
|
3485
|
+
local_leads: "Signaliz local leads",
|
|
3486
|
+
email_finding: "Signaliz email finding",
|
|
3487
|
+
email_verification: "Signaliz email verification",
|
|
3488
|
+
signals: "Signaliz signals"
|
|
3489
|
+
};
|
|
3490
|
+
return labels[builtIn];
|
|
3491
|
+
}
|
|
3492
|
+
return `${route.provider} ${route.layer}`;
|
|
3493
|
+
}
|
|
3494
|
+
function campaignReadinessNextActions(plan, ready, customRouteCount) {
|
|
3495
|
+
const requestHint = "--request-file campaign-request.json";
|
|
3496
|
+
if (ready) {
|
|
3497
|
+
return [
|
|
3498
|
+
`signaliz campaign-agent proof ${requestHint} --json`,
|
|
3499
|
+
`signaliz campaign-agent commit-plan ${requestHint} --json`,
|
|
3500
|
+
`signaliz campaign-agent build-approved ${requestHint} --confirm-launch --approve-all --approved-by operator@example.com --spend-limit ${plan.estimatedCredits}`
|
|
3501
|
+
];
|
|
3502
|
+
}
|
|
3503
|
+
const actions = [
|
|
3504
|
+
plan.strategyMemoryStatus && asRecord(plan.strategyMemoryStatus).ready === false ? "signaliz gtm strategy-memory --strategy-template <strategy_template> --include-samples --json" : void 0,
|
|
3505
|
+
customRouteCount > 0 ? "Review BYO provider recipe and route dry-run steps in the readiness packet." : void 0,
|
|
3506
|
+
`signaliz campaign-agent plan ${requestHint} --json`
|
|
3507
|
+
];
|
|
3508
|
+
return actions.filter((item) => Boolean(item));
|
|
3509
|
+
}
|
|
3226
3510
|
function diagnosticMessages2(value) {
|
|
3227
3511
|
if (!Array.isArray(value)) return [];
|
|
3228
3512
|
return value.map((item) => {
|