@sellable/mcp 0.1.475 → 0.1.477
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/tools/leads.d.ts +50 -3
- package/dist/tools/leads.js +29 -17
- package/dist/tools/prompts.js +1 -1
- package/dist/tools/refill-sends.d.ts +27 -0
- package/dist/tools/refill-sends.js +166 -6
- package/dist/tools/refill-target-plan.js +56 -2
- package/dist/tools/registry.d.ts +45 -0
- package/dist/tools/sequencer.js +5 -6
- package/package.json +1 -1
- package/skills/create-campaign-v2/references/final-handoff-contract.md +9 -7
- package/skills/create-campaign-v2-tail/SKILL.md +13 -10
- package/skills/create-evergreen-campaigns/SKILL.md +11 -6
- package/skills/refill-sends/SKILL.md +40 -22
- package/skills/refill-sends-workflow/SKILL.md +45 -24
- package/skills/workflow-sequences/SKILL.md +1 -1
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { getRefillTargetPlan } from "./refill-target-plan.js";
|
|
2
2
|
import { refreshPaidInmailCredits } from "./senders.js";
|
|
3
|
+
import { startPrepareCampaignMessages } from "./campaign-message-preparation.js";
|
|
4
|
+
import { confirmLeadList } from "./leads.js";
|
|
3
5
|
const DEFAULT_SCHEDULER_FORWARD_HOURS = 48;
|
|
4
6
|
function normalizeStrings(values) {
|
|
5
7
|
if (!Array.isArray(values))
|
|
@@ -58,7 +60,7 @@ function normalizeTargetDate(value) {
|
|
|
58
60
|
export const refillSendsToolDefinitions = [
|
|
59
61
|
{
|
|
60
62
|
name: "refill_sends",
|
|
61
|
-
description: "Typed command entrypoint for Sellable refill sends. Accepts --yolo semantics and optional sender selectors, then returns the bounded execution contract for the skill-led refill workflow. In --yolo, it may refresh stale paid InMail credit cache facts
|
|
63
|
+
description: "Typed command entrypoint for Sellable refill sends. Accepts --yolo semantics and optional sender selectors, then returns the bounded execution contract for the skill-led refill workflow. In --yolo, it may refresh stale paid InMail credit cache facts once, or execute exactly one safe primitive from target.globalActionQueue[0] (bounded existing-row preparation, bounded same-source copy, or read-only wait) and reread. It does not approve messages without the bounded approval gate, lower paid InMail thresholds, switch source families, create campaigns, schedule sends, launch, archive, delete, or write scheduler rows.",
|
|
62
64
|
inputSchema: {
|
|
63
65
|
type: "object",
|
|
64
66
|
properties: {
|
|
@@ -197,7 +199,7 @@ export function refillSendsCommand(input = {}) {
|
|
|
197
199
|
"Render target.eligibleSenderLedger and target.senderRefillPlans before mutation. Preserve the coverage labels Need to prepare, Goal, Already sent, Scheduled, Ready and waiting to be scheduled, and Still need.",
|
|
198
200
|
"Use target.globalActionQueue as the only cross-sender yolo queue: execute only target.globalActionQueue[0], one globally ranked primitive, then rerun get_refill_target_plan before choosing another action.",
|
|
199
201
|
"If get_refill_target_plan returns status complete, report eligible sender ledger, target.senderRefillPlans, gross target, selected days, sent count, scheduled count, projected count, campaign ids, targetShapeRevision, and no-op proof without asking for approval.",
|
|
200
|
-
"Refill target lanes are
|
|
202
|
+
"Refill target lanes are connection invites (send_invite), standalone paid InMails (send_inmail_closed), or unified Sales Nav cascades represented publicly as send_inmail_closed with campaign classification sales_nav_cascade. For a Sales Nav cascade, refill the selected campaign first; its sequence can route prospects to Open InMail, paid InMail while fresh credits are >= 5, or same-campaign connection fallback without asking for separate open/paid/connection campaigns. Do not count send_dm as horizon target capacity.",
|
|
201
203
|
"If remainingReadyOrProjectedGap is 0 but remainingProjectedGap is positive, run only a persistent read-only scheduler wait/reread loop; do not ask for prep/import/approval and do not close out while scheduler pickup is the only remaining state.",
|
|
202
204
|
`Resolve route with resolve_campaign_fill_route({ intent: "${intent}"${input.campaignId ? `, campaignId: "${input.campaignId}"` : ""}${input.tableId ? `, tableId: "${input.tableId}"` : ""} }).`,
|
|
203
205
|
'If the plain route shows stale managed waterfall evidence, archived/completed shared slots, or targets that do not cover the selected sender set, immediately call resolve_campaign_fill_route({ intent: "active" }) and inspect current dashboard-active ACTIVE/PAUSED campaign-backed sequence campaigns before declaring a sender blocked.',
|
|
@@ -213,14 +215,14 @@ export function refillSendsCommand(input = {}) {
|
|
|
213
215
|
"Treat current dashboard-active PAUSED campaign-backed sequence campaigns as start-eligible candidates: read refill state before deciding whether to prep, approve, start, or skip.",
|
|
214
216
|
"Fresh reread get_campaign_refill_state immediately before any import, prep, approval, or horizon-fill mutation.",
|
|
215
217
|
"Maintain a target-window saturation ledger per selected sender from get_refill_target_plan: selected days, gross capacity, actual sent counts, future scheduler-owned scheduled counts, projected counts, ready-to-schedule buffer, remaining projected gap, paid InMail threshold feasibility, targetShapeRevision, stateRevision, and next MCP primitive.",
|
|
216
|
-
"In --yolo, this tool automatically maintains a run-local refreshedPaidInmailSenderIds set: when the first target plan returns refresh_paid_inmail_credits candidates for selected paid-InMail lanes, it refreshes each exact sender at most once, reruns get_refill_target_plan, and returns the post-refresh targetPlan before any prep/
|
|
218
|
+
"In --yolo, this tool automatically maintains a run-local refreshedPaidInmailSenderIds set: when the first target plan returns refresh_paid_inmail_credits candidates for selected paid-InMail lanes, it refreshes each exact sender at most once, reruns get_refill_target_plan, and returns the post-refresh targetPlan before any prep/source-copy/read-only wait action is chosen.",
|
|
217
219
|
"Do not present paid-credit refresh as the next operator action after refill_sends returns autoPaidInmailRefresh and the post-refresh targetPlan.",
|
|
218
|
-
"If paid InMail feasibility remains below threshold after that automatic refresh, report the exact sender/campaign/table/column threshold action or connection fallback; --yolo must not lower paid InMail thresholds or create campaigns.",
|
|
220
|
+
"If paid InMail feasibility remains below threshold after that automatic refresh, report the exact sender/campaign/table/column threshold action or same-campaign connection fallback; --yolo must not lower paid InMail thresholds or create campaigns.",
|
|
219
221
|
"In --yolo or after one Accept, continue through every safe selected sender/campaign action covered by the rendered target packet; sent/scheduled-count progress changes stateRevision and should continue while targetShapeRevision is stable.",
|
|
220
222
|
"Do not complete a fill/schedule request until a final get_refill_target_plan or refill-state reread proves projected coverage (sent + scheduled) fills the scheduler-forward target window. Treat awaiting_scheduler_after_ready_buffer as loaded, awaiting scheduler when ready buffer covers the gap; do not import/prep more rows in that state, and keep polling unless Christian stops/statuses the run or a concrete non-scheduler blocker such as paid_inmail_below_threshold appears.",
|
|
221
223
|
],
|
|
222
224
|
approvalContract: yolo
|
|
223
|
-
? "Auto-accept only the rendered bounded refill target packet after get_refill_target_plan and fresh reread. Execute one globally ranked primitive from target.globalActionQueue at a time, then rerun get_refill_target_plan before taking another action. Continue through every safe
|
|
225
|
+
? "Auto-accept only the rendered bounded refill target packet after get_refill_target_plan and fresh reread. Execute one globally ranked primitive from target.globalActionQueue at a time, then rerun get_refill_target_plan before taking another action. Continue through every safe prep/source-copy/read-only wait action inside that packet. Approval, start_campaign, source-family switches, threshold changes, and campaign creation require their own explicit gates. After each safe action, rerun get_refill_target_plan; keep going while targetShapeRevision is stable and projected coverage (sent + scheduled) progresses toward the target, even though stateRevision changes. Ready-to-schedule rows are buffer, not completion. If ready buffer covers the projected gap, use only persistent read-only scheduler wait/reread and keep the run open until projected coverage fills or Christian stops/statuses it. Stop immediately if targetShapeRevision changes because sender set, route, ids, caps, dates, blockers, action class, paid InMail threshold feasibility, or side-effect class drifts. --yolo does not authorize lowering paid InMail thresholds or creating connection campaigns."
|
|
224
226
|
: hasSenderSelectors
|
|
225
227
|
? "Before mutation, post the full bounded refill packet in normal chat as Markdown, including workspace, sender scope, campaign table, exact ids, caps/dates, gross target, sent count, scheduled count, projected count, ready buffer, remaining projected gap, paid InMail threshold feasibility, targetShapeRevision/stateRevision, side effects, forbidden actions, and stop condition. Then ask the final Accept/Decline structured approval question with a compact body that refers back to the posted packet instead of duplicating it. Only ask when get_refill_target_plan reports a positive remaining projected/ready gap. If target is complete by projected coverage, no-op without approval. If ready buffer covers the projected gap, run only persistent read-only scheduler wait/reread and keep the run open until projected coverage fills or Christian stops/statuses it. Threshold changes and campaign creation need separate explicit approval."
|
|
226
228
|
: "Ask which eligible enrolled senders to refill first, then, before mutation, post the full bounded refill packet in normal chat as Markdown and ask the final Accept/Decline structured approval question with a compact body that refers back to the posted packet.",
|
|
@@ -302,6 +304,14 @@ function recordValue(value) {
|
|
|
302
304
|
function stringValue(value) {
|
|
303
305
|
return typeof value === "string" && value.trim() ? value.trim() : null;
|
|
304
306
|
}
|
|
307
|
+
function numberValue(value) {
|
|
308
|
+
return typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
309
|
+
}
|
|
310
|
+
function stringArray(value) {
|
|
311
|
+
if (!Array.isArray(value))
|
|
312
|
+
return [];
|
|
313
|
+
return value.filter((item) => typeof item === "string");
|
|
314
|
+
}
|
|
305
315
|
function paidRefreshActionFrom(value) {
|
|
306
316
|
const action = recordValue(value);
|
|
307
317
|
if (!action || action.type !== "refresh_paid_inmail_credits")
|
|
@@ -349,6 +359,121 @@ function collectPaidInmailRefreshActions(plan) {
|
|
|
349
359
|
add(action);
|
|
350
360
|
return [...bySender.values()];
|
|
351
361
|
}
|
|
362
|
+
function firstGlobalAction(plan) {
|
|
363
|
+
const root = recordValue(plan);
|
|
364
|
+
const target = recordValue(root?.target);
|
|
365
|
+
const globalActionQueue = Array.isArray(target?.globalActionQueue)
|
|
366
|
+
? target.globalActionQueue
|
|
367
|
+
: [];
|
|
368
|
+
const [first] = globalActionQueue;
|
|
369
|
+
return recordValue(first);
|
|
370
|
+
}
|
|
371
|
+
function actionIds(action) {
|
|
372
|
+
return recordValue(action.ids) ?? {};
|
|
373
|
+
}
|
|
374
|
+
function actionToolInput(action) {
|
|
375
|
+
return recordValue(action.toolInput) ?? {};
|
|
376
|
+
}
|
|
377
|
+
function actionCampaignId(action) {
|
|
378
|
+
const ids = actionIds(action);
|
|
379
|
+
const toolInput = actionToolInput(action);
|
|
380
|
+
return (stringValue(toolInput.campaignId) ??
|
|
381
|
+
stringValue(toolInput.campaignOfferId) ??
|
|
382
|
+
stringValue(ids.campaignId) ??
|
|
383
|
+
stringValue(action.campaignId));
|
|
384
|
+
}
|
|
385
|
+
function actionTableId(action) {
|
|
386
|
+
const ids = actionIds(action);
|
|
387
|
+
const toolInput = actionToolInput(action);
|
|
388
|
+
return (stringValue(toolInput.tableId) ??
|
|
389
|
+
stringValue(ids.tableId) ??
|
|
390
|
+
stringValue(action.tableId));
|
|
391
|
+
}
|
|
392
|
+
function actionSourceLeadListId(action) {
|
|
393
|
+
const ids = actionIds(action);
|
|
394
|
+
const toolInput = actionToolInput(action);
|
|
395
|
+
return (stringValue(toolInput.sourceLeadListId) ??
|
|
396
|
+
stringValue(ids.sourceLeadListId) ??
|
|
397
|
+
stringValue(action.sourceLeadListId));
|
|
398
|
+
}
|
|
399
|
+
async function executeOneYoloPrimitive(action) {
|
|
400
|
+
if (!action)
|
|
401
|
+
return { status: "no_action" };
|
|
402
|
+
if (action.yoloEligible === false) {
|
|
403
|
+
return {
|
|
404
|
+
status: "refused",
|
|
405
|
+
refusalReason: "first global action is not yolo eligible",
|
|
406
|
+
};
|
|
407
|
+
}
|
|
408
|
+
switch (action.type) {
|
|
409
|
+
case "wait_for_scheduler":
|
|
410
|
+
case "wait_for_active_work":
|
|
411
|
+
case "wait_for_source_import":
|
|
412
|
+
return { status: "read_only_reread", result: { waited: true } };
|
|
413
|
+
case "prepare_messages": {
|
|
414
|
+
const campaignId = actionCampaignId(action);
|
|
415
|
+
const tableId = actionTableId(action) ?? undefined;
|
|
416
|
+
const toolInput = actionToolInput(action);
|
|
417
|
+
const targetPreparedMessages = numberValue(toolInput.targetPreparedMessages);
|
|
418
|
+
const approvalMode = toolInput.approvalMode === "approve" ? "approve" : "mark_ready";
|
|
419
|
+
if (!campaignId || !targetPreparedMessages || targetPreparedMessages <= 0) {
|
|
420
|
+
return {
|
|
421
|
+
status: "refused",
|
|
422
|
+
refusalReason: "prepare_messages action is missing campaignId or bounded targetPreparedMessages",
|
|
423
|
+
};
|
|
424
|
+
}
|
|
425
|
+
const result = await startPrepareCampaignMessages({
|
|
426
|
+
campaignId,
|
|
427
|
+
tableId,
|
|
428
|
+
targetPreparedMessages,
|
|
429
|
+
approvalMode,
|
|
430
|
+
autoContinue: true,
|
|
431
|
+
});
|
|
432
|
+
return { status: "executed_and_reread", result };
|
|
433
|
+
}
|
|
434
|
+
case "copy_selected_source_rows": {
|
|
435
|
+
const campaignOfferId = actionCampaignId(action);
|
|
436
|
+
const sourceLeadListId = actionSourceLeadListId(action);
|
|
437
|
+
const toolInput = actionToolInput(action);
|
|
438
|
+
const sourceRowIds = stringArray(toolInput.sourceRowIds);
|
|
439
|
+
const sourceRowLimit = numberValue(toolInput.sourceRowLimit);
|
|
440
|
+
const sourceFingerprint = stringValue(toolInput.sourceFingerprint) ??
|
|
441
|
+
stringValue(actionIds(action).sourceFingerprint);
|
|
442
|
+
if (!campaignOfferId || !sourceLeadListId || !sourceFingerprint) {
|
|
443
|
+
return {
|
|
444
|
+
status: "refused",
|
|
445
|
+
refusalReason: "copy_selected_source_rows action is missing campaignOfferId, sourceLeadListId, or sourceFingerprint",
|
|
446
|
+
};
|
|
447
|
+
}
|
|
448
|
+
if (sourceRowIds.length === 0 && (!sourceRowLimit || sourceRowLimit <= 0)) {
|
|
449
|
+
return {
|
|
450
|
+
status: "refused",
|
|
451
|
+
refusalReason: "copy_selected_source_rows action is missing exact sourceRowIds or a bounded sourceRowLimit",
|
|
452
|
+
};
|
|
453
|
+
}
|
|
454
|
+
const result = await confirmLeadList({
|
|
455
|
+
campaignOfferId,
|
|
456
|
+
sourceLeadListId,
|
|
457
|
+
currentStep: null,
|
|
458
|
+
confirmed: true,
|
|
459
|
+
sourceRowIds: sourceRowIds.length > 0 ? sourceRowIds : undefined,
|
|
460
|
+
sourceRowLimit: sourceRowIds.length > 0 ? undefined : sourceRowLimit ?? undefined,
|
|
461
|
+
reviewBatchLimit: sourceRowIds.length > 0 ? sourceRowIds.length : sourceRowLimit ?? undefined,
|
|
462
|
+
});
|
|
463
|
+
return { status: "executed_and_reread", result };
|
|
464
|
+
}
|
|
465
|
+
case "approve_messages":
|
|
466
|
+
return {
|
|
467
|
+
status: "refused",
|
|
468
|
+
refusalReason: "approve_messages requires the bounded approval mutation gate; refill_sends yolo will not treat select_campaign_cells as approval",
|
|
469
|
+
};
|
|
470
|
+
default:
|
|
471
|
+
return {
|
|
472
|
+
status: "refused",
|
|
473
|
+
refusalReason: `action ${String(action.type)} is not a safe yolo primitive`,
|
|
474
|
+
};
|
|
475
|
+
}
|
|
476
|
+
}
|
|
352
477
|
export async function executeRefillSendsCommand(input = {}) {
|
|
353
478
|
const command = refillSendsCommand(input);
|
|
354
479
|
if (input.yolo !== true) {
|
|
@@ -361,6 +486,12 @@ export async function executeRefillSendsCommand(input = {}) {
|
|
|
361
486
|
failedPaidInmailRefreshes: [],
|
|
362
487
|
note: "Automatic paid InMail credit refresh only runs for --yolo refill_sends calls.",
|
|
363
488
|
},
|
|
489
|
+
yoloExecution: {
|
|
490
|
+
enabled: false,
|
|
491
|
+
status: "not_run_without_yolo",
|
|
492
|
+
selectedAction: null,
|
|
493
|
+
targetPlanReread: false,
|
|
494
|
+
},
|
|
364
495
|
};
|
|
365
496
|
}
|
|
366
497
|
const targetPlanInput = targetPlanInputFor(input);
|
|
@@ -391,10 +522,21 @@ export async function executeRefillSendsCommand(input = {}) {
|
|
|
391
522
|
const targetPlan = refreshActions.length > 0
|
|
392
523
|
? await getRefillTargetPlan(targetPlanInput)
|
|
393
524
|
: targetPlanBeforePaidRefresh;
|
|
525
|
+
const selectedAction = refreshActions.length > 0 ? null : firstGlobalAction(targetPlan);
|
|
526
|
+
const primitiveAttempt = refreshActions.length > 0
|
|
527
|
+
? null
|
|
528
|
+
: await executeOneYoloPrimitive(selectedAction);
|
|
529
|
+
const shouldRereadAfterPrimitive = primitiveAttempt?.status === "executed_and_reread" ||
|
|
530
|
+
primitiveAttempt?.status === "read_only_reread";
|
|
531
|
+
const postActionTargetPlan = shouldRereadAfterPrimitive
|
|
532
|
+
? await getRefillTargetPlan(targetPlanInput)
|
|
533
|
+
: null;
|
|
534
|
+
const finalTargetPlan = postActionTargetPlan ?? targetPlan;
|
|
394
535
|
return {
|
|
395
536
|
...command,
|
|
396
|
-
targetPlan,
|
|
537
|
+
targetPlan: finalTargetPlan,
|
|
397
538
|
targetPlanBeforePaidRefresh: refreshActions.length > 0 ? targetPlanBeforePaidRefresh : null,
|
|
539
|
+
targetPlanBeforeYoloPrimitive: refreshActions.length === 0 && postActionTargetPlan ? targetPlan : null,
|
|
398
540
|
autoPaidInmailRefresh: {
|
|
399
541
|
enabled: true,
|
|
400
542
|
status: refreshActions.length === 0
|
|
@@ -411,5 +553,23 @@ export async function executeRefillSendsCommand(input = {}) {
|
|
|
411
553
|
? "refill_sends refreshed stale paid InMail credit facts internally, once per sender, then returned the post-refresh targetPlan."
|
|
412
554
|
: "No stale or missing paid InMail credit refresh candidates were present in the initial target plan.",
|
|
413
555
|
},
|
|
556
|
+
yoloExecution: refreshActions.length > 0
|
|
557
|
+
? {
|
|
558
|
+
enabled: true,
|
|
559
|
+
status: "skipped_after_paid_refresh",
|
|
560
|
+
selectedAction: null,
|
|
561
|
+
targetPlanReread: true,
|
|
562
|
+
}
|
|
563
|
+
: {
|
|
564
|
+
enabled: true,
|
|
565
|
+
status: primitiveAttempt?.status ?? "no_action",
|
|
566
|
+
selectedAction,
|
|
567
|
+
result: primitiveAttempt?.result,
|
|
568
|
+
targetPlanReread: shouldRereadAfterPrimitive,
|
|
569
|
+
refusalReason: primitiveAttempt?.refusalReason,
|
|
570
|
+
postActionFirstAction: postActionTargetPlan
|
|
571
|
+
? firstGlobalAction(postActionTargetPlan)
|
|
572
|
+
: null,
|
|
573
|
+
},
|
|
414
574
|
};
|
|
415
575
|
}
|
|
@@ -9,6 +9,13 @@ const SAFE_PACKET_ACTION_TYPES = new Set([
|
|
|
9
9
|
"approve_messages",
|
|
10
10
|
"start_paused_campaign",
|
|
11
11
|
"wait_for_scheduler",
|
|
12
|
+
"wait_for_active_work",
|
|
13
|
+
"wait_for_source_import",
|
|
14
|
+
"copy_selected_source_rows",
|
|
15
|
+
"continue_signal_discovery_source",
|
|
16
|
+
"continue_sales_nav_source",
|
|
17
|
+
"continue_prospeo_source",
|
|
18
|
+
"manual_source_replenishment",
|
|
12
19
|
"refresh_paid_inmail_credits",
|
|
13
20
|
"lower_paid_inmail_threshold",
|
|
14
21
|
"switch_to_connection_lane",
|
|
@@ -18,6 +25,10 @@ const MANUAL_ONLY_PACKET_ACTION_TYPES = new Set([
|
|
|
18
25
|
"lower_paid_inmail_threshold",
|
|
19
26
|
"switch_to_connection_lane",
|
|
20
27
|
"create_connection_campaign",
|
|
28
|
+
"continue_signal_discovery_source",
|
|
29
|
+
"continue_sales_nav_source",
|
|
30
|
+
"continue_prospeo_source",
|
|
31
|
+
"manual_source_replenishment",
|
|
21
32
|
]);
|
|
22
33
|
const SOURCE_PLAN_STATES = new Set([
|
|
23
34
|
"not_needed",
|
|
@@ -26,6 +37,8 @@ const SOURCE_PLAN_STATES = new Set([
|
|
|
26
37
|
"needs_signal_import",
|
|
27
38
|
"waiting_for_import",
|
|
28
39
|
"needs_confirm",
|
|
40
|
+
"needs_same_source_copy",
|
|
41
|
+
"needs_provider_continuation",
|
|
29
42
|
"source_shortfall",
|
|
30
43
|
"provider_exhausted",
|
|
31
44
|
"provider_missing",
|
|
@@ -57,6 +70,9 @@ function stringValue(value) {
|
|
|
57
70
|
function booleanValue(value) {
|
|
58
71
|
return typeof value === "boolean" ? value : undefined;
|
|
59
72
|
}
|
|
73
|
+
function campaignClassificationValue(value) {
|
|
74
|
+
return value === "sales_nav_cascade" ? "sales_nav_cascade" : undefined;
|
|
75
|
+
}
|
|
60
76
|
function stringArray(value) {
|
|
61
77
|
if (!Array.isArray(value))
|
|
62
78
|
return [];
|
|
@@ -149,6 +165,16 @@ function sanitizeActionCandidate(candidate) {
|
|
|
149
165
|
tableId: stringValue(candidate.tableId),
|
|
150
166
|
tableName: stringValue(candidate.tableName) ?? null,
|
|
151
167
|
columnId: stringValue(candidate.columnId) ?? null,
|
|
168
|
+
sourceLeadListId: stringValue(candidate.sourceLeadListId) ?? null,
|
|
169
|
+
leadSourceProvider: stringValue(candidate.leadSourceProvider) ?? null,
|
|
170
|
+
sourceFingerprint: stringValue(candidate.sourceFingerprint) ?? null,
|
|
171
|
+
sourceInventoryStatus: stringValue(candidate.sourceInventoryStatus) ?? null,
|
|
172
|
+
sourceRowIds: stringArray(candidate.sourceRowIds),
|
|
173
|
+
sourceRowLimit: typeof candidate.sourceRowLimit === "number"
|
|
174
|
+
? candidate.sourceRowLimit
|
|
175
|
+
: undefined,
|
|
176
|
+
activeJobId: stringValue(candidate.activeJobId) ?? null,
|
|
177
|
+
activeImportStatus: stringValue(candidate.activeImportStatus) ?? null,
|
|
152
178
|
targetRows: typeof candidate.targetRows === "number" ? candidate.targetRows : undefined,
|
|
153
179
|
columnRole: stringValue(candidate.columnRole),
|
|
154
180
|
rowSelector: sanitizeRowSelector(candidate.rowSelector),
|
|
@@ -186,6 +212,21 @@ function sanitizeToolInput(value) {
|
|
|
186
212
|
campaignId: stringValue(value.campaignId),
|
|
187
213
|
tableId: stringValue(value.tableId),
|
|
188
214
|
columnId: stringValue(value.columnId) ?? null,
|
|
215
|
+
sourceLeadListId: stringValue(value.sourceLeadListId) ?? null,
|
|
216
|
+
leadSourceProvider: stringValue(value.leadSourceProvider) ?? null,
|
|
217
|
+
sourceFingerprint: stringValue(value.sourceFingerprint) ?? null,
|
|
218
|
+
activeJobId: stringValue(value.activeJobId) ?? null,
|
|
219
|
+
activeImportStatus: stringValue(value.activeImportStatus) ?? null,
|
|
220
|
+
sourceInventoryStatus: stringValue(value.sourceInventoryStatus) ?? null,
|
|
221
|
+
sourceRowIds: stringArray(value.sourceRowIds),
|
|
222
|
+
sourceRowLimit: typeof value.sourceRowLimit === "number"
|
|
223
|
+
? value.sourceRowLimit
|
|
224
|
+
: undefined,
|
|
225
|
+
campaignOfferId: stringValue(value.campaignOfferId),
|
|
226
|
+
provider: stringValue(value.provider),
|
|
227
|
+
allowDifferentSourceLeadList: typeof value.allowDifferentSourceLeadList === "boolean"
|
|
228
|
+
? value.allowDifferentSourceLeadList
|
|
229
|
+
: undefined,
|
|
189
230
|
targetPreparedMessages: typeof value.targetPreparedMessages === "number"
|
|
190
231
|
? value.targetPreparedMessages
|
|
191
232
|
: undefined,
|
|
@@ -212,6 +253,10 @@ function sanitizePacketIds(value) {
|
|
|
212
253
|
campaignId: stringValue(value.campaignId),
|
|
213
254
|
tableId: stringValue(value.tableId),
|
|
214
255
|
columnId: stringValue(value.columnId) ?? null,
|
|
256
|
+
sourceLeadListId: stringValue(value.sourceLeadListId) ?? null,
|
|
257
|
+
leadSourceProvider: stringValue(value.leadSourceProvider) ?? null,
|
|
258
|
+
sourceFingerprint: stringValue(value.sourceFingerprint) ?? null,
|
|
259
|
+
activeJobId: stringValue(value.activeJobId) ?? null,
|
|
215
260
|
};
|
|
216
261
|
}
|
|
217
262
|
function sanitizeStructuredAction(action, selectedBySender, mode, rank) {
|
|
@@ -307,6 +352,7 @@ function sanitizeCampaignRanking(value) {
|
|
|
307
352
|
tableId: stringValue(option.tableId) ?? "",
|
|
308
353
|
tableName: stringValue(option.tableName) ?? null,
|
|
309
354
|
campaignStatus: stringValue(option.campaignStatus) ?? null,
|
|
355
|
+
classification: campaignClassificationValue(option.classification),
|
|
310
356
|
supportsSelectedLane: option.supportsSelectedLane === true,
|
|
311
357
|
rankSignals: stringArray(option.rankSignals),
|
|
312
358
|
rankReason: stringValue(option.rankReason) ?? "",
|
|
@@ -330,6 +376,9 @@ function sanitizeSourcePlan(value) {
|
|
|
330
376
|
reason: stringValue(value.reason),
|
|
331
377
|
campaignId: stringValue(value.campaignId),
|
|
332
378
|
tableId: stringValue(value.tableId),
|
|
379
|
+
sourceLeadListId: stringValue(value.sourceLeadListId) ?? null,
|
|
380
|
+
leadSourceProvider: stringValue(value.leadSourceProvider) ?? null,
|
|
381
|
+
sourceFingerprint: stringValue(value.sourceFingerprint) ?? null,
|
|
333
382
|
remainingRowsNeeded: typeof value.remainingRowsNeeded === "number"
|
|
334
383
|
? value.remainingRowsNeeded
|
|
335
384
|
: undefined,
|
|
@@ -351,6 +400,11 @@ function sanitizePaidInmail(value) {
|
|
|
351
400
|
tableId: stringValue(value.tableId) ?? null,
|
|
352
401
|
tableName: stringValue(value.tableName) ?? null,
|
|
353
402
|
columnId: stringValue(value.columnId) ?? null,
|
|
403
|
+
maxStalenessSeconds: numberValue(value.maxStalenessSeconds),
|
|
404
|
+
campaignClassification: campaignClassificationValue(value.campaignClassification) ?? null,
|
|
405
|
+
connectionFallbackAvailable: booleanValue(value.connectionFallbackAvailable) ?? false,
|
|
406
|
+
connectionFallbackCampaignId: stringValue(value.connectionFallbackCampaignId) ?? null,
|
|
407
|
+
connectionFallbackCampaignName: stringValue(value.connectionFallbackCampaignName) ?? null,
|
|
354
408
|
suggestedThreshold: typeof value.suggestedThreshold === "number"
|
|
355
409
|
? value.suggestedThreshold
|
|
356
410
|
: null,
|
|
@@ -622,7 +676,7 @@ function sanitizeRefillTargetPlanResult(result) {
|
|
|
622
676
|
export const refillTargetPlanToolDefinitions = [
|
|
623
677
|
{
|
|
624
678
|
name: "get_refill_target_plan",
|
|
625
|
-
description: "read-only refill target planner to call before any refill mutation. It identifies eligible senders and infers one implicit refill lane per sender
|
|
679
|
+
description: "read-only refill target planner to call before any refill mutation. It identifies eligible senders and infers one implicit refill lane per sender. For unified Sales Nav cascade campaigns, the public refill lane is the paid-InMail cascade target (send_inmail_closed) with campaign classification sales_nav_cascade; the same campaign can still route prospects to Open InMail or connection-request fallback based on row eligibility and fresh paid credits >= 5. Non-cascade lanes remain connection invites or paid InMails, chosen from future scheduled, recent scheduled, and ready-to-schedule evidence in active campaign-backed sequence campaigns before falling back to campaign sequences. DMs remain follow-up sequence actions, not refill target lanes. By default the planner computes the scheduler-forward 48-hour target window, selected sender-local days whose sending windows overlap that window, gross target, actual sent coverage, scheduler-owned scheduled coverage, projected coverage (sent + scheduled), ready buffer, remaining projected gap, paid InMail credit/threshold/freshness feasibility, same-campaign connection fallback availability, bounded action candidates, and targetRevision drift proof. This tool does not create rows, import leads, prepare messages, approve messages, does not schedule sends, start campaigns, lower paid InMail thresholds, create campaigns, launch, spend InMail credits, or write scheduler fields. Complete projected targets no-op without approval; loaded, awaiting scheduler targets use read-only wait/reread until projected coverage fills.",
|
|
626
680
|
inputSchema: {
|
|
627
681
|
type: "object",
|
|
628
682
|
properties: {
|
|
@@ -676,7 +730,7 @@ export const refillTargetPlanToolDefinitions = [
|
|
|
676
730
|
type: "string",
|
|
677
731
|
enum: ["send_invite", "send_inmail_closed"],
|
|
678
732
|
},
|
|
679
|
-
description: "Optional refill target lane override. Supported refill lanes are connection invites (send_invite) and paid InMails (send_inmail_closed) only. If omitted, the planner infers one per-sender lane from active campaign future scheduled, recent scheduled, and ready-to-schedule evidence before falling back to selected active campaign sequences.",
|
|
733
|
+
description: "Optional refill target lane override. Supported public refill lanes are connection invites (send_invite) and paid InMails / unified Sales Nav cascades (send_inmail_closed) only. If omitted, the planner infers one per-sender lane from active campaign future scheduled, recent scheduled, and ready-to-schedule evidence before falling back to selected active campaign sequences.",
|
|
680
734
|
},
|
|
681
735
|
approvalMode: {
|
|
682
736
|
type: "string",
|
package/dist/tools/registry.d.ts
CHANGED
|
@@ -2952,6 +2952,8 @@ export declare const allTools: ({
|
|
|
2952
2952
|
keepInSync?: undefined;
|
|
2953
2953
|
jobId?: undefined;
|
|
2954
2954
|
reviewBatchLimit?: undefined;
|
|
2955
|
+
sourceRowIds?: undefined;
|
|
2956
|
+
sourceRowLimit?: undefined;
|
|
2955
2957
|
allowPartialSourceList?: undefined;
|
|
2956
2958
|
includeRawImportResult?: undefined;
|
|
2957
2959
|
selections?: undefined;
|
|
@@ -3146,6 +3148,8 @@ export declare const allTools: ({
|
|
|
3146
3148
|
keepInSync?: undefined;
|
|
3147
3149
|
jobId?: undefined;
|
|
3148
3150
|
reviewBatchLimit?: undefined;
|
|
3151
|
+
sourceRowIds?: undefined;
|
|
3152
|
+
sourceRowLimit?: undefined;
|
|
3149
3153
|
allowPartialSourceList?: undefined;
|
|
3150
3154
|
includeRawImportResult?: undefined;
|
|
3151
3155
|
selections?: undefined;
|
|
@@ -3239,6 +3243,8 @@ export declare const allTools: ({
|
|
|
3239
3243
|
keepInSync?: undefined;
|
|
3240
3244
|
jobId?: undefined;
|
|
3241
3245
|
reviewBatchLimit?: undefined;
|
|
3246
|
+
sourceRowIds?: undefined;
|
|
3247
|
+
sourceRowLimit?: undefined;
|
|
3242
3248
|
allowPartialSourceList?: undefined;
|
|
3243
3249
|
includeRawImportResult?: undefined;
|
|
3244
3250
|
selections?: undefined;
|
|
@@ -3404,6 +3410,8 @@ export declare const allTools: ({
|
|
|
3404
3410
|
keepInSync?: undefined;
|
|
3405
3411
|
jobId?: undefined;
|
|
3406
3412
|
reviewBatchLimit?: undefined;
|
|
3413
|
+
sourceRowIds?: undefined;
|
|
3414
|
+
sourceRowLimit?: undefined;
|
|
3407
3415
|
allowPartialSourceList?: undefined;
|
|
3408
3416
|
includeRawImportResult?: undefined;
|
|
3409
3417
|
selections?: undefined;
|
|
@@ -3511,6 +3519,8 @@ export declare const allTools: ({
|
|
|
3511
3519
|
keepInSync?: undefined;
|
|
3512
3520
|
jobId?: undefined;
|
|
3513
3521
|
reviewBatchLimit?: undefined;
|
|
3522
|
+
sourceRowIds?: undefined;
|
|
3523
|
+
sourceRowLimit?: undefined;
|
|
3514
3524
|
allowPartialSourceList?: undefined;
|
|
3515
3525
|
includeRawImportResult?: undefined;
|
|
3516
3526
|
selections?: undefined;
|
|
@@ -3627,6 +3637,8 @@ export declare const allTools: ({
|
|
|
3627
3637
|
keepInSync?: undefined;
|
|
3628
3638
|
jobId?: undefined;
|
|
3629
3639
|
reviewBatchLimit?: undefined;
|
|
3640
|
+
sourceRowIds?: undefined;
|
|
3641
|
+
sourceRowLimit?: undefined;
|
|
3630
3642
|
allowPartialSourceList?: undefined;
|
|
3631
3643
|
includeRawImportResult?: undefined;
|
|
3632
3644
|
selections?: undefined;
|
|
@@ -3732,6 +3744,8 @@ export declare const allTools: ({
|
|
|
3732
3744
|
keepInSync?: undefined;
|
|
3733
3745
|
jobId?: undefined;
|
|
3734
3746
|
reviewBatchLimit?: undefined;
|
|
3747
|
+
sourceRowIds?: undefined;
|
|
3748
|
+
sourceRowLimit?: undefined;
|
|
3735
3749
|
allowPartialSourceList?: undefined;
|
|
3736
3750
|
includeRawImportResult?: undefined;
|
|
3737
3751
|
selections?: undefined;
|
|
@@ -3842,6 +3856,8 @@ export declare const allTools: ({
|
|
|
3842
3856
|
keepInSync?: undefined;
|
|
3843
3857
|
jobId?: undefined;
|
|
3844
3858
|
reviewBatchLimit?: undefined;
|
|
3859
|
+
sourceRowIds?: undefined;
|
|
3860
|
+
sourceRowLimit?: undefined;
|
|
3845
3861
|
allowPartialSourceList?: undefined;
|
|
3846
3862
|
includeRawImportResult?: undefined;
|
|
3847
3863
|
selections?: undefined;
|
|
@@ -3940,6 +3956,8 @@ export declare const allTools: ({
|
|
|
3940
3956
|
keepInSync?: undefined;
|
|
3941
3957
|
jobId?: undefined;
|
|
3942
3958
|
reviewBatchLimit?: undefined;
|
|
3959
|
+
sourceRowIds?: undefined;
|
|
3960
|
+
sourceRowLimit?: undefined;
|
|
3943
3961
|
allowPartialSourceList?: undefined;
|
|
3944
3962
|
includeRawImportResult?: undefined;
|
|
3945
3963
|
selections?: undefined;
|
|
@@ -4830,6 +4848,8 @@ export declare const allTools: ({
|
|
|
4830
4848
|
keepInSync?: undefined;
|
|
4831
4849
|
jobId?: undefined;
|
|
4832
4850
|
reviewBatchLimit?: undefined;
|
|
4851
|
+
sourceRowIds?: undefined;
|
|
4852
|
+
sourceRowLimit?: undefined;
|
|
4833
4853
|
allowPartialSourceList?: undefined;
|
|
4834
4854
|
includeRawImportResult?: undefined;
|
|
4835
4855
|
selections?: undefined;
|
|
@@ -4937,6 +4957,8 @@ export declare const allTools: ({
|
|
|
4937
4957
|
keepInSync?: undefined;
|
|
4938
4958
|
jobId?: undefined;
|
|
4939
4959
|
reviewBatchLimit?: undefined;
|
|
4960
|
+
sourceRowIds?: undefined;
|
|
4961
|
+
sourceRowLimit?: undefined;
|
|
4940
4962
|
allowPartialSourceList?: undefined;
|
|
4941
4963
|
includeRawImportResult?: undefined;
|
|
4942
4964
|
selections?: undefined;
|
|
@@ -5982,6 +6004,8 @@ export declare const allTools: ({
|
|
|
5982
6004
|
keepInSync?: undefined;
|
|
5983
6005
|
jobId?: undefined;
|
|
5984
6006
|
reviewBatchLimit?: undefined;
|
|
6007
|
+
sourceRowIds?: undefined;
|
|
6008
|
+
sourceRowLimit?: undefined;
|
|
5985
6009
|
allowPartialSourceList?: undefined;
|
|
5986
6010
|
includeRawImportResult?: undefined;
|
|
5987
6011
|
selections?: undefined;
|
|
@@ -6136,6 +6160,8 @@ export declare const allTools: ({
|
|
|
6136
6160
|
keepInSync?: undefined;
|
|
6137
6161
|
jobId?: undefined;
|
|
6138
6162
|
reviewBatchLimit?: undefined;
|
|
6163
|
+
sourceRowIds?: undefined;
|
|
6164
|
+
sourceRowLimit?: undefined;
|
|
6139
6165
|
allowPartialSourceList?: undefined;
|
|
6140
6166
|
includeRawImportResult?: undefined;
|
|
6141
6167
|
selections?: undefined;
|
|
@@ -6277,6 +6303,8 @@ export declare const allTools: ({
|
|
|
6277
6303
|
keepInSync?: undefined;
|
|
6278
6304
|
jobId?: undefined;
|
|
6279
6305
|
reviewBatchLimit?: undefined;
|
|
6306
|
+
sourceRowIds?: undefined;
|
|
6307
|
+
sourceRowLimit?: undefined;
|
|
6280
6308
|
allowPartialSourceList?: undefined;
|
|
6281
6309
|
includeRawImportResult?: undefined;
|
|
6282
6310
|
selections?: undefined;
|
|
@@ -6373,6 +6401,8 @@ export declare const allTools: ({
|
|
|
6373
6401
|
keepInSync?: undefined;
|
|
6374
6402
|
jobId?: undefined;
|
|
6375
6403
|
reviewBatchLimit?: undefined;
|
|
6404
|
+
sourceRowIds?: undefined;
|
|
6405
|
+
sourceRowLimit?: undefined;
|
|
6376
6406
|
allowPartialSourceList?: undefined;
|
|
6377
6407
|
includeRawImportResult?: undefined;
|
|
6378
6408
|
selections?: undefined;
|
|
@@ -6419,6 +6449,17 @@ export declare const allTools: ({
|
|
|
6419
6449
|
type: string;
|
|
6420
6450
|
description: string;
|
|
6421
6451
|
};
|
|
6452
|
+
sourceRowIds: {
|
|
6453
|
+
type: string;
|
|
6454
|
+
items: {
|
|
6455
|
+
type: string;
|
|
6456
|
+
};
|
|
6457
|
+
description: string;
|
|
6458
|
+
};
|
|
6459
|
+
sourceRowLimit: {
|
|
6460
|
+
type: string;
|
|
6461
|
+
description: string;
|
|
6462
|
+
};
|
|
6422
6463
|
allowPartialSourceList: {
|
|
6423
6464
|
type: string;
|
|
6424
6465
|
description: string;
|
|
@@ -6628,6 +6669,8 @@ export declare const allTools: ({
|
|
|
6628
6669
|
keepInSync?: undefined;
|
|
6629
6670
|
jobId?: undefined;
|
|
6630
6671
|
reviewBatchLimit?: undefined;
|
|
6672
|
+
sourceRowIds?: undefined;
|
|
6673
|
+
sourceRowLimit?: undefined;
|
|
6631
6674
|
allowPartialSourceList?: undefined;
|
|
6632
6675
|
includeRawImportResult?: undefined;
|
|
6633
6676
|
};
|
|
@@ -6725,6 +6768,8 @@ export declare const allTools: ({
|
|
|
6725
6768
|
keepInSync?: undefined;
|
|
6726
6769
|
jobId?: undefined;
|
|
6727
6770
|
reviewBatchLimit?: undefined;
|
|
6771
|
+
sourceRowIds?: undefined;
|
|
6772
|
+
sourceRowLimit?: undefined;
|
|
6728
6773
|
allowPartialSourceList?: undefined;
|
|
6729
6774
|
includeRawImportResult?: undefined;
|
|
6730
6775
|
selections?: undefined;
|
package/dist/tools/sequencer.js
CHANGED
|
@@ -65,13 +65,12 @@ export const sequencerToolDefinitions = [
|
|
|
65
65
|
name: "attach_recommended_sequence",
|
|
66
66
|
description: "Attach the tier-recommended sequence template to a campaign. " +
|
|
67
67
|
"Delegates template selection to the backend's existing tier-aware selector " +
|
|
68
|
-
"(selectTemplateForTiers), which picks
|
|
69
|
-
"
|
|
70
|
-
"
|
|
71
|
-
"
|
|
68
|
+
"(selectTemplateForTiers), which picks the unified Sales Nav cascade for Sales Nav/Recruiter senders: " +
|
|
69
|
+
"Open Profile check -> Open InMail, otherwise fresh paid credits >= 5 -> paid InMail, otherwise same-campaign connection request -> accepted wait -> DM. " +
|
|
70
|
+
"Basic, Premium, or mixed sender sets still get `INVITE -> accepted -> DM`. " +
|
|
71
|
+
"This is the default Sales Nav product path; use attach_sequence directly only when the caller needs a custom non-recommended cadence. " +
|
|
72
72
|
"Prefer this over attach_sequence during the create-campaign-v2 autonomous tail — " +
|
|
73
|
-
"it removes the risk of hand-authoring an invalid template mid-long-context.
|
|
74
|
-
"Use attach_sequence directly only when the caller needs a custom non-recommended cadence.",
|
|
73
|
+
"it removes the risk of hand-authoring an invalid template mid-long-context.",
|
|
75
74
|
inputSchema: {
|
|
76
75
|
type: "object",
|
|
77
76
|
properties: {
|
package/package.json
CHANGED
|
@@ -58,10 +58,12 @@ currentStep: "sequence" })` to attach the sender via the v3 senders route and
|
|
|
58
58
|
move the watched app to Sequence.
|
|
59
59
|
8. Call `attach_recommended_sequence({ campaignId, currentStep: "send" })` to
|
|
60
60
|
bind the tier-aware recommended sequence. Explain the sequence choice in the
|
|
61
|
-
handoff: Sales Nav/Recruiter senders get the Sales Nav
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
61
|
+
handoff: Sales Nav/Recruiter senders get the unified Sales Nav cascade
|
|
62
|
+
(Open Profile -> Open InMail, otherwise fresh paid credits >= 5 -> paid
|
|
63
|
+
InMail, otherwise connection request -> accepted wait -> DM), while
|
|
64
|
+
Basic/Premium/mixed senders get the Premium invite-to-DM strategy. The manual
|
|
65
|
+
Paid InMail Campaign remains an explicit custom template, not the normal
|
|
66
|
+
recommended path. If that response does not persist `currentStep:
|
|
65
67
|
"send"`, call `update_campaign({ campaignId, currentStep: "send" })`.
|
|
66
68
|
Then reread `get_campaign({ campaignId })` and `list_tables()` and verify the
|
|
67
69
|
current `workflowTableId` has `hasSequence:true`. A campaign-level
|
|
@@ -69,9 +71,9 @@ currentStep: "sequence" })` to attach the sender via the v3 senders route and
|
|
|
69
71
|
copy step has moved the campaign to a new current campaign table while an old
|
|
70
72
|
stale shell table still owns the sequence columns. In that stale-shell case,
|
|
71
73
|
either repair only the current workflowTableId with `attach_sequence` using
|
|
72
|
-
the same
|
|
73
|
-
|
|
74
|
-
|
|
74
|
+
the same product template the recommended selector would have chosen, or stop
|
|
75
|
+
and report the stale-shell sequence blocker if replacement was not explicitly
|
|
76
|
+
approved. Do not substitute the manual Paid InMail Campaign for this repair.
|
|
75
77
|
9. Surface the `handoff.orientation` string from `auto-execute.yaml` and
|
|
76
78
|
summarize the visible Settings/Sequence/Send state without repeating the
|
|
77
79
|
watch URL.
|