@sellable/mcp 0.1.556 → 0.1.557
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 +13 -2
- package/agents/registry.json +2 -2
- package/dist/api.js +3 -6
- package/dist/auth.d.ts +0 -6
- package/dist/auth.js +2 -44
- package/dist/refill-run-client.d.ts +0 -5
- package/dist/refill-run-client.js +0 -15
- package/dist/refill-run-loop.d.ts +1 -12
- package/dist/refill-run-loop.js +13 -158
- package/dist/server.js +23 -0
- package/dist/tools/auth.d.ts +0 -5
- package/dist/tools/auth.js +12 -49
- package/dist/tools/campaign-message-preparation.d.ts +0 -62
- package/dist/tools/campaign-message-preparation.js +0 -41
- package/dist/tools/campaigns.js +2 -2
- package/dist/tools/csv-dnc.js +2 -2
- package/dist/tools/evergreen-refill-plan.d.ts +0 -3
- package/dist/tools/evergreen-refill-plan.js +7 -29
- package/dist/tools/find-leads-runs.d.ts +151 -0
- package/dist/tools/find-leads-runs.js +98 -0
- package/dist/tools/leads.d.ts +317 -32
- package/dist/tools/leads.js +171 -10
- package/dist/tools/model-quality.js +4 -6
- package/dist/tools/prompts.d.ts +3 -3
- package/dist/tools/prompts.js +7 -15
- package/dist/tools/provider-preflight.d.ts +65 -2
- package/dist/tools/provider-preflight.js +97 -10
- package/dist/tools/readiness.d.ts +89 -5
- package/dist/tools/readiness.js +66 -0
- package/dist/tools/refill-executors.d.ts +0 -38
- package/dist/tools/refill-executors.js +3 -222
- package/dist/tools/refill-sends-v2.d.ts +1 -118
- package/dist/tools/refill-sends-v2.js +2 -310
- package/dist/tools/refill-sends.d.ts +32 -678
- package/dist/tools/refill-sends.js +13 -274
- package/dist/tools/refill-target-plan.js +14 -486
- package/dist/tools/registry.d.ts +330 -115
- package/dist/tools/registry.js +7 -1
- package/dist/tools/scheduler-fill-capacity.js +1 -1
- package/dist/tools/scheduler-run.d.ts +0 -71
- package/dist/tools/scheduler-run.js +1 -203
- package/dist/tools/setup-evergreen-campaigns.js +1 -1
- package/dist/tools/workspace-context.d.ts +1 -1
- package/dist/tools/workspace-context.js +3 -8
- package/dist/tools/workspace-export.js +2 -2
- package/dist/tools/workspaces.d.ts +2 -48
- package/dist/tools/workspaces.js +5 -48
- package/package.json +1 -1
- package/skills/create-campaign/SKILL.md +3 -3
- package/skills/create-campaign-v2/SKILL.md +1 -1
- package/skills/create-evergreen-campaigns/SKILL.md +16 -16
- package/skills/find-leads/SKILL.md +48 -630
- package/skills/find-leads-v2/SKILL.md +70 -0
- package/skills/find-leads-v2/core/flow.v1.json +31 -0
- package/skills/refill-sends/SKILL.md +353 -91
- package/skills/refill-sends-v2/SKILL.md +6 -6
- package/skills/refill-sends-v2-workflow/SKILL.md +5 -5
- package/skills/refill-sends-v2-workflow/core/flow.v1.json +8 -8
- package/skills/refill-sends-workflow/SKILL.md +743 -100
- package/skills/refill-sends-workflow/core/flow.v1.json +1 -185
- package/dist/refill-contract.d.ts +0 -157
- package/dist/refill-contract.js +0 -487
- package/skills/refill-sends-workflow/core/contract.v2.json +0 -543
|
@@ -10,8 +10,6 @@ const SAFE_PACKET_ACTION_TYPES = new Set([
|
|
|
10
10
|
"approve_messages",
|
|
11
11
|
"start_paused_campaign",
|
|
12
12
|
"rerun_errored_cells",
|
|
13
|
-
"run_scheduler_sweep",
|
|
14
|
-
"scheduler_first_settle",
|
|
15
13
|
"wait_for_scheduler",
|
|
16
14
|
"wait_for_active_work",
|
|
17
15
|
"wait_for_source_import",
|
|
@@ -75,17 +73,6 @@ const PREP_FAILURE_RECOMMENDED_ACTIONS = new Set([
|
|
|
75
73
|
"approve_or_repair_approval_cells",
|
|
76
74
|
"inspect_rows",
|
|
77
75
|
]);
|
|
78
|
-
const SCHEDULER_SWEEP_ALLOWED_SIDE_EFFECTS = [
|
|
79
|
-
"schedule any eligible workspace cells on the approved date within scheduler gates",
|
|
80
|
-
];
|
|
81
|
-
const SCHEDULER_SWEEP_FORBIDDEN_SIDE_EFFECTS = [
|
|
82
|
-
"send directly",
|
|
83
|
-
"write scheduler fields directly",
|
|
84
|
-
"change campaign state",
|
|
85
|
-
"change sender limits",
|
|
86
|
-
"change source selection",
|
|
87
|
-
];
|
|
88
|
-
const SCHEDULER_SWEEP_RECEIPT_GROUPS = ["campaignId", "tableId", "actionType"];
|
|
89
76
|
async function postRefillTargetPlan(body, workspaceId) {
|
|
90
77
|
const api = getApi();
|
|
91
78
|
const requestOptions = workspaceRequestOptions(workspaceId);
|
|
@@ -212,289 +199,14 @@ function senderActionKey(senderId, actionType) {
|
|
|
212
199
|
function sanitizeCounts(counts, selectedKeys) {
|
|
213
200
|
if (!Array.isArray(counts))
|
|
214
201
|
return [];
|
|
215
|
-
return counts
|
|
216
|
-
.filter((item) => {
|
|
202
|
+
return counts.filter((item) => {
|
|
217
203
|
if (!isRecord(item))
|
|
218
204
|
return false;
|
|
219
205
|
const actionType = allowedActionType(item.actionType);
|
|
220
206
|
const key = senderActionKey(item.senderId, actionType);
|
|
221
207
|
return Boolean(key && selectedKeys.has(key));
|
|
222
|
-
})
|
|
223
|
-
.map((item) => ({
|
|
224
|
-
senderId: stringValue(item.senderId),
|
|
225
|
-
actionType: allowedActionType(item.actionType),
|
|
226
|
-
refillLaneKey: refillLaneKeyValue(item.refillLaneKey),
|
|
227
|
-
branchActionType: branchActionTypeValue(item.branchActionType),
|
|
228
|
-
date: stringValue(item.date),
|
|
229
|
-
count: nonNegativeNumber(item.count),
|
|
230
|
-
campaignId: stringValue(item.campaignId),
|
|
231
|
-
tableId: stringValue(item.tableId),
|
|
232
|
-
}));
|
|
233
|
-
}
|
|
234
|
-
const REFILL_BRANCH_ACTION_TYPES = new Set([
|
|
235
|
-
"send_invite",
|
|
236
|
-
"send_dm",
|
|
237
|
-
"send_inmail_open",
|
|
238
|
-
"send_inmail_closed",
|
|
239
|
-
"react_and_comment",
|
|
240
|
-
]);
|
|
241
|
-
function nonNegativeNumber(value) {
|
|
242
|
-
return typeof value === "number" && Number.isFinite(value)
|
|
243
|
-
? Math.max(0, value)
|
|
244
|
-
: 0;
|
|
245
|
-
}
|
|
246
|
-
function refillLaneKeyValue(value) {
|
|
247
|
-
if (value === "sales_nav_cascade")
|
|
248
|
-
return value;
|
|
249
|
-
return allowedActionType(value) ?? undefined;
|
|
250
|
-
}
|
|
251
|
-
function branchActionTypeValue(value) {
|
|
252
|
-
return typeof value === "string" && REFILL_BRANCH_ACTION_TYPES.has(value)
|
|
253
|
-
? value
|
|
254
|
-
: undefined;
|
|
255
|
-
}
|
|
256
|
-
function sanitizeBranchMetrics(value) {
|
|
257
|
-
if (!Array.isArray(value))
|
|
258
|
-
return [];
|
|
259
|
-
return value
|
|
260
|
-
.filter((metric) => isRecord(metric))
|
|
261
|
-
.map((metric) => ({
|
|
262
|
-
actionType: branchActionTypeValue(metric.actionType),
|
|
263
|
-
count: nonNegativeNumber(metric.count),
|
|
264
|
-
}))
|
|
265
|
-
.filter((metric) => Boolean(metric.actionType));
|
|
266
|
-
}
|
|
267
|
-
function sanitizeBranchMetricGroups(value) {
|
|
268
|
-
if (!isRecord(value)) {
|
|
269
|
-
return { sentScheduled: [], assignedReady: [], sharedReady: [] };
|
|
270
|
-
}
|
|
271
|
-
return {
|
|
272
|
-
sentScheduled: sanitizeBranchMetrics(value.sentScheduled),
|
|
273
|
-
assignedReady: sanitizeBranchMetrics(value.assignedReady),
|
|
274
|
-
sharedReady: sanitizeBranchMetrics(value.sharedReady),
|
|
275
|
-
};
|
|
276
|
-
}
|
|
277
|
-
function sanitizeLedgerViews(value) {
|
|
278
|
-
const views = isRecord(value) ? value : {};
|
|
279
|
-
const raw = isRecord(views.raw) ? views.raw : {};
|
|
280
|
-
const goalCapped = isRecord(views.goalCapped) ? views.goalCapped : {};
|
|
281
|
-
const allocatable = isRecord(views.allocatable) ? views.allocatable : {};
|
|
282
|
-
const unallocatable = isRecord(views.unallocatable)
|
|
283
|
-
? views.unallocatable
|
|
284
|
-
: {};
|
|
285
|
-
return {
|
|
286
|
-
raw: {
|
|
287
|
-
sentScheduled: nonNegativeNumber(raw.sentScheduled),
|
|
288
|
-
assignedReady: nonNegativeNumber(raw.assignedReady),
|
|
289
|
-
sharedReady: nonNegativeNumber(raw.sharedReady),
|
|
290
|
-
},
|
|
291
|
-
goalCapped: {
|
|
292
|
-
projected: nonNegativeNumber(goalCapped.projected),
|
|
293
|
-
ready: nonNegativeNumber(goalCapped.ready),
|
|
294
|
-
remaining: nonNegativeNumber(goalCapped.remaining),
|
|
295
|
-
},
|
|
296
|
-
allocatable: {
|
|
297
|
-
demand: nonNegativeNumber(allocatable.demand),
|
|
298
|
-
ready: nonNegativeNumber(allocatable.ready),
|
|
299
|
-
prepDeficit: nonNegativeNumber(allocatable.prepDeficit),
|
|
300
|
-
},
|
|
301
|
-
unallocatable: {
|
|
302
|
-
assignedReady: nonNegativeNumber(unallocatable.assignedReady),
|
|
303
|
-
sharedReady: nonNegativeNumber(unallocatable.sharedReady),
|
|
304
|
-
goalDeficit: nonNegativeNumber(unallocatable.goalDeficit),
|
|
305
|
-
},
|
|
306
|
-
};
|
|
307
|
-
}
|
|
308
|
-
function sanitizeIdentityChecks(value) {
|
|
309
|
-
const checks = isRecord(value) ? value : {};
|
|
310
|
-
return {
|
|
311
|
-
assignedConserved: checks.assignedConserved === true,
|
|
312
|
-
sharedConserved: checks.sharedConserved === true,
|
|
313
|
-
readyCapped: checks.readyCapped === true,
|
|
314
|
-
deficitConserved: checks.deficitConserved === true,
|
|
315
|
-
nonNegative: checks.nonNegative === true,
|
|
316
|
-
};
|
|
317
|
-
}
|
|
318
|
-
const LEDGER_NUMBER_FIELDS = [
|
|
319
|
-
"goal",
|
|
320
|
-
"sentScheduledRawUnique",
|
|
321
|
-
"goalAfterSentScheduled",
|
|
322
|
-
"schedulerFillableSlotsFromCandidateSimulation",
|
|
323
|
-
"preReadyAllocatableDemand",
|
|
324
|
-
"assignedRawReady",
|
|
325
|
-
"assignedCreditedReady",
|
|
326
|
-
"assignedUnallocatableReady",
|
|
327
|
-
"sharedRawReady",
|
|
328
|
-
"sharedAllocatedReady",
|
|
329
|
-
"sharedUnallocatableReady",
|
|
330
|
-
"readyGoalCredited",
|
|
331
|
-
"goalCappedProjected",
|
|
332
|
-
"remainingGoalGap",
|
|
333
|
-
"initialAllocatablePrepDeficit",
|
|
334
|
-
"unallocatableGoalDeficit",
|
|
335
|
-
"matchingCardinality",
|
|
336
|
-
];
|
|
337
|
-
function sanitizeLaneLedger(value, requireScope) {
|
|
338
|
-
if (!isRecord(value))
|
|
339
|
-
return null;
|
|
340
|
-
const senderId = stringValue(value.senderId);
|
|
341
|
-
const refillLaneKey = refillLaneKeyValue(value.refillLaneKey);
|
|
342
|
-
const targetDate = stringValue(value.targetDate);
|
|
343
|
-
if (requireScope && (!senderId || !refillLaneKey || !targetDate))
|
|
344
|
-
return null;
|
|
345
|
-
const numbers = Object.fromEntries(LEDGER_NUMBER_FIELDS.map((field) => [
|
|
346
|
-
field,
|
|
347
|
-
nonNegativeNumber(value[field]),
|
|
348
|
-
]));
|
|
349
|
-
return {
|
|
350
|
-
...(senderId ? { senderId } : {}),
|
|
351
|
-
...(refillLaneKey ? { refillLaneKey } : {}),
|
|
352
|
-
...(targetDate ? { targetDate } : {}),
|
|
353
|
-
...numbers,
|
|
354
|
-
unmatchedReadyReasons: numericRecord(value.unmatchedReadyReasons),
|
|
355
|
-
branchMetrics: sanitizeBranchMetricGroups(value.branchMetrics),
|
|
356
|
-
views: sanitizeLedgerViews(value.views),
|
|
357
|
-
identityChecks: sanitizeIdentityChecks(value.identityChecks),
|
|
358
|
-
};
|
|
359
|
-
}
|
|
360
|
-
function sanitizeLaneLedgers(value) {
|
|
361
|
-
if (!Array.isArray(value))
|
|
362
|
-
return [];
|
|
363
|
-
return value.flatMap((ledger) => {
|
|
364
|
-
const sanitized = sanitizeLaneLedger(ledger, true);
|
|
365
|
-
return sanitized ? [sanitized] : [];
|
|
366
208
|
});
|
|
367
209
|
}
|
|
368
|
-
function sanitizePhase98RefillContract(value) {
|
|
369
|
-
if (!isRecord(value))
|
|
370
|
-
return {};
|
|
371
|
-
const refillLaneKey = refillLaneKeyValue(value.refillLaneKey);
|
|
372
|
-
const laneLedgers = sanitizeLaneLedgers(value.laneLedgers);
|
|
373
|
-
const laneLedgerTotals = sanitizeLaneLedger(value.laneLedgerTotals, false);
|
|
374
|
-
const settleKey = stringValue(value.settleKey);
|
|
375
|
-
const settleDeadline = stringValue(value.settleDeadline);
|
|
376
|
-
const settleBasisRevision = stringValue(value.settleBasisRevision);
|
|
377
|
-
return {
|
|
378
|
-
...(refillLaneKey ? { refillLaneKey } : {}),
|
|
379
|
-
...(isRecord(value.branchMetrics)
|
|
380
|
-
? { branchMetrics: sanitizeBranchMetricGroups(value.branchMetrics) }
|
|
381
|
-
: {}),
|
|
382
|
-
...(Array.isArray(value.laneLedgers) ? { laneLedgers } : {}),
|
|
383
|
-
...(laneLedgerTotals ? { laneLedgerTotals } : {}),
|
|
384
|
-
...(settleKey?.startsWith("scheduler_first_settle:") ? { settleKey } : {}),
|
|
385
|
-
...(settleDeadline ? { settleDeadline } : {}),
|
|
386
|
-
...(settleBasisRevision ? { settleBasisRevision } : {}),
|
|
387
|
-
};
|
|
388
|
-
}
|
|
389
|
-
function sanitizeSelectedDay(value) {
|
|
390
|
-
if (!isRecord(value))
|
|
391
|
-
return null;
|
|
392
|
-
const senderId = stringValue(value.senderId);
|
|
393
|
-
const actionType = allowedActionType(value.actionType);
|
|
394
|
-
if (!senderId || !actionType)
|
|
395
|
-
return null;
|
|
396
|
-
return {
|
|
397
|
-
senderId,
|
|
398
|
-
senderName: stringValue(value.senderName) ?? senderId,
|
|
399
|
-
actionType,
|
|
400
|
-
refillLaneKey: refillLaneKeyValue(value.refillLaneKey),
|
|
401
|
-
date: stringValue(value.date),
|
|
402
|
-
timeZone: stringValue(value.timeZone),
|
|
403
|
-
startUtc: stringValue(value.startUtc),
|
|
404
|
-
endUtc: stringValue(value.endUtc),
|
|
405
|
-
limit: nonNegativeNumber(value.limit),
|
|
406
|
-
};
|
|
407
|
-
}
|
|
408
|
-
function sanitizeSenderPlan(value) {
|
|
409
|
-
if (!isRecord(value))
|
|
410
|
-
return null;
|
|
411
|
-
const senderId = stringValue(value.senderId);
|
|
412
|
-
const actionType = allowedActionType(value.actionType);
|
|
413
|
-
if (!senderId || !actionType)
|
|
414
|
-
return null;
|
|
415
|
-
const numericFields = [
|
|
416
|
-
"requestedTarget",
|
|
417
|
-
"grossTarget",
|
|
418
|
-
"effectiveTarget",
|
|
419
|
-
"sent",
|
|
420
|
-
"scheduled",
|
|
421
|
-
"projected",
|
|
422
|
-
"readyBuffer",
|
|
423
|
-
"remainingScheduledGap",
|
|
424
|
-
"remainingProjectedGap",
|
|
425
|
-
"remainingReadyOrProjectedGap",
|
|
426
|
-
"schedulerFillableSlots",
|
|
427
|
-
"schedulerCapacityTarget",
|
|
428
|
-
"remainingSchedulerFillableGap",
|
|
429
|
-
];
|
|
430
|
-
const numbers = Object.fromEntries(numericFields.map((field) => [field, nonNegativeNumber(value[field])]));
|
|
431
|
-
const campaigns = Array.isArray(value.campaigns)
|
|
432
|
-
? value.campaigns
|
|
433
|
-
.filter((campaign) => isRecord(campaign))
|
|
434
|
-
.map((campaign) => ({
|
|
435
|
-
campaignId: stringValue(campaign.campaignId),
|
|
436
|
-
campaignName: stringValue(campaign.campaignName) ?? "",
|
|
437
|
-
tableId: stringValue(campaign.tableId),
|
|
438
|
-
tableName: stringValue(campaign.tableName) ?? null,
|
|
439
|
-
campaignStatus: stringValue(campaign.campaignStatus) ?? null,
|
|
440
|
-
classification: campaignClassificationValue(campaign.classification),
|
|
441
|
-
selectedLeadListId: stringValue(campaign.selectedLeadListId) ?? null,
|
|
442
|
-
leadSourceProvider: stringValue(campaign.leadSourceProvider) ?? null,
|
|
443
|
-
sourceFingerprint: stringValue(campaign.sourceFingerprint) ?? null,
|
|
444
|
-
}))
|
|
445
|
-
: [];
|
|
446
|
-
return {
|
|
447
|
-
senderId,
|
|
448
|
-
senderName: stringValue(value.senderName) ?? senderId,
|
|
449
|
-
actionType,
|
|
450
|
-
...sanitizePhase98RefillContract(value),
|
|
451
|
-
selectedDays: Array.isArray(value.selectedDays)
|
|
452
|
-
? value.selectedDays
|
|
453
|
-
.map(sanitizeSelectedDay)
|
|
454
|
-
.filter((day) => Boolean(day))
|
|
455
|
-
: [],
|
|
456
|
-
campaigns,
|
|
457
|
-
...numbers,
|
|
458
|
-
schedulerFillableSlotsKnown: booleanValue(value.schedulerFillableSlotsKnown) ?? undefined,
|
|
459
|
-
schedulerCapacityMode: stringValue(value.schedulerCapacityMode),
|
|
460
|
-
allocationScope: stringValue(value.allocationScope),
|
|
461
|
-
schedulerWarnings: stringArray(value.schedulerWarnings),
|
|
462
|
-
paidInmail: sanitizePaidInmail(value.paidInmail),
|
|
463
|
-
refillReceipt: sanitizeRefillReceipt(value.refillReceipt),
|
|
464
|
-
};
|
|
465
|
-
}
|
|
466
|
-
function sanitizeActionSelection(value) {
|
|
467
|
-
if (!isRecord(value))
|
|
468
|
-
return null;
|
|
469
|
-
const senderId = stringValue(value.senderId);
|
|
470
|
-
if (!senderId)
|
|
471
|
-
return null;
|
|
472
|
-
const evidence = Array.isArray(value.evidence)
|
|
473
|
-
? value.evidence
|
|
474
|
-
.filter((item) => isRecord(item))
|
|
475
|
-
.map((item) => ({
|
|
476
|
-
senderId: stringValue(item.senderId),
|
|
477
|
-
actionType: allowedActionType(item.actionType),
|
|
478
|
-
refillLaneKey: refillLaneKeyValue(item.refillLaneKey),
|
|
479
|
-
source: stringValue(item.source),
|
|
480
|
-
count: nonNegativeNumber(item.count),
|
|
481
|
-
latestAt: stringValue(item.latestAt),
|
|
482
|
-
campaignId: stringValue(item.campaignId),
|
|
483
|
-
tableId: stringValue(item.tableId),
|
|
484
|
-
}))
|
|
485
|
-
: [];
|
|
486
|
-
const refillLaneKeys = Array.isArray(value.refillLaneKeys)
|
|
487
|
-
? value.refillLaneKeys.map(refillLaneKeyValue).filter(Boolean)
|
|
488
|
-
: [];
|
|
489
|
-
return {
|
|
490
|
-
senderId,
|
|
491
|
-
senderName: stringValue(value.senderName) ?? senderId,
|
|
492
|
-
actionTypes: actionTypesFrom(value.actionTypes),
|
|
493
|
-
...(refillLaneKeys.length > 0 ? { refillLaneKeys } : {}),
|
|
494
|
-
source: stringValue(value.source),
|
|
495
|
-
evidence,
|
|
496
|
-
};
|
|
497
|
-
}
|
|
498
210
|
function sanitizeActionCandidates(candidates, selectedKeys, paidRefreshNeededSenderIds, status, remainingReadyOrProjectedGap, remainingProjectedGap) {
|
|
499
211
|
const filtered = Array.isArray(candidates)
|
|
500
212
|
? candidates
|
|
@@ -565,7 +277,6 @@ function sanitizeActionCandidate(candidate) {
|
|
|
565
277
|
? "get_refill_target_plan"
|
|
566
278
|
: undefined,
|
|
567
279
|
reason: stringValue(candidate.reason),
|
|
568
|
-
...sanitizePhase98RefillContract(candidate),
|
|
569
280
|
};
|
|
570
281
|
}
|
|
571
282
|
function sanitizeRowSelector(value) {
|
|
@@ -754,16 +465,6 @@ function sanitizeToolInput(value) {
|
|
|
754
465
|
wait: sanitizeWait(value.wait),
|
|
755
466
|
refillReceipt: sanitizeRefillReceipt(value.refillReceipt),
|
|
756
467
|
capSaturated: booleanValue(value.capSaturated) === true ? true : undefined,
|
|
757
|
-
settleKey: stringValue(value.settleKey),
|
|
758
|
-
settleDeadline: stringValue(value.settleDeadline),
|
|
759
|
-
settleBasisRevision: stringValue(value.settleBasisRevision),
|
|
760
|
-
calibration: isRecord(value.calibration)
|
|
761
|
-
? {
|
|
762
|
-
trusted: value.calibration.trusted === true,
|
|
763
|
-
passRate: optionalNumberValue(value.calibration.passRate),
|
|
764
|
-
minimumRows: nonNegativeNumber(value.calibration.minimumRows),
|
|
765
|
-
}
|
|
766
|
-
: undefined,
|
|
767
468
|
};
|
|
768
469
|
}
|
|
769
470
|
function sanitizePacketIds(value) {
|
|
@@ -814,10 +515,8 @@ function sanitizeStructuredAction(action, selectedBySender, mode, rank) {
|
|
|
814
515
|
: null,
|
|
815
516
|
stopCondition: stringValue(action.stopCondition) ?? "",
|
|
816
517
|
yoloEligible,
|
|
817
|
-
actionKey: stringValue(action.actionKey),
|
|
818
518
|
capSaturated: booleanValue(action.capSaturated) === true ? true : undefined,
|
|
819
519
|
prepFailureDiagnosis: sanitizePrepFailureDiagnosis(action.prepFailureDiagnosis),
|
|
820
|
-
...sanitizePhase98RefillContract(action),
|
|
821
520
|
};
|
|
822
521
|
}
|
|
823
522
|
function sanitizeLedgerBlockers(value) {
|
|
@@ -1010,12 +709,7 @@ function paidInmailRefreshActionForSenderPlan(plan, paidInmail) {
|
|
|
1010
709
|
availableCredits: numberValue(paidInmail?.availableCredits),
|
|
1011
710
|
oldThreshold: numberValue(paidInmail?.threshold),
|
|
1012
711
|
maxStalenessSeconds: MCP_PAID_INMAIL_CREDITS_MAX_STALENESS_SECONDS,
|
|
1013
|
-
actionKey: [
|
|
1014
|
-
"refresh_paid_inmail_credits",
|
|
1015
|
-
senderId,
|
|
1016
|
-
campaignId,
|
|
1017
|
-
columnId,
|
|
1018
|
-
].join(":"),
|
|
712
|
+
actionKey: ["refresh_paid_inmail_credits", senderId, campaignId, columnId].join(":"),
|
|
1019
713
|
rereadAfter: "get_refill_target_plan",
|
|
1020
714
|
reason: stringValue(paidInmail?.reason) ??
|
|
1021
715
|
"MCP paid InMail sender-credit facts require refresh.",
|
|
@@ -1061,7 +755,6 @@ function sanitizeStructuredSenderPlans(value, selectedBySender) {
|
|
|
1061
755
|
senderName: stringValue(plan.senderName) ?? "",
|
|
1062
756
|
status: stringValue(plan.status) ?? "needs_refill",
|
|
1063
757
|
selectedLane: allowedActionType(plan.selectedLane),
|
|
1064
|
-
...sanitizePhase98RefillContract(plan),
|
|
1065
758
|
horizon: isRecord(plan.horizon)
|
|
1066
759
|
? {
|
|
1067
760
|
selectedDays: Array.isArray(plan.horizon.selectedDays)
|
|
@@ -1121,149 +814,6 @@ function buildSanitizedGlobalActionQueue(senderRefillPlans) {
|
|
|
1121
814
|
rank: index + 1,
|
|
1122
815
|
}));
|
|
1123
816
|
}
|
|
1124
|
-
function sortedUniqueStrings(value) {
|
|
1125
|
-
return [...new Set(stringArray(value))].sort();
|
|
1126
|
-
}
|
|
1127
|
-
function sameStrings(left, right) {
|
|
1128
|
-
return (left.length === right.length &&
|
|
1129
|
-
left.every((value, index) => value === right[index]));
|
|
1130
|
-
}
|
|
1131
|
-
function sanitizeSchedulerSweepSourceScopes(value) {
|
|
1132
|
-
if (!Array.isArray(value))
|
|
1133
|
-
return [];
|
|
1134
|
-
const scopes = value.flatMap((entry) => {
|
|
1135
|
-
if (!isRecord(entry))
|
|
1136
|
-
return [];
|
|
1137
|
-
const campaignId = stringValue(entry.campaignId)?.trim();
|
|
1138
|
-
const tableId = stringValue(entry.tableId)?.trim();
|
|
1139
|
-
const sourceLeadListId = stringValue(entry.sourceLeadListId)?.trim();
|
|
1140
|
-
const leadSourceProvider = stringValue(entry.leadSourceProvider)?.trim();
|
|
1141
|
-
if (!campaignId || !tableId || !sourceLeadListId || !leadSourceProvider) {
|
|
1142
|
-
return [];
|
|
1143
|
-
}
|
|
1144
|
-
return [{ campaignId, tableId, sourceLeadListId, leadSourceProvider }];
|
|
1145
|
-
});
|
|
1146
|
-
const unique = new Map(scopes.map((scope) => [
|
|
1147
|
-
[
|
|
1148
|
-
scope.campaignId,
|
|
1149
|
-
scope.tableId,
|
|
1150
|
-
scope.sourceLeadListId,
|
|
1151
|
-
scope.leadSourceProvider,
|
|
1152
|
-
].join(":"),
|
|
1153
|
-
scope,
|
|
1154
|
-
]));
|
|
1155
|
-
return [...unique.values()].sort((a, b) => {
|
|
1156
|
-
if (a.campaignId !== b.campaignId) {
|
|
1157
|
-
return a.campaignId.localeCompare(b.campaignId);
|
|
1158
|
-
}
|
|
1159
|
-
return a.tableId.localeCompare(b.tableId);
|
|
1160
|
-
});
|
|
1161
|
-
}
|
|
1162
|
-
function sanitizeTargetSchedulerSweep(params) {
|
|
1163
|
-
if (!Array.isArray(params.value) ||
|
|
1164
|
-
!params.expectedWorkspaceId ||
|
|
1165
|
-
!params.expectedTargetDate ||
|
|
1166
|
-
!/^\d{4}-\d{2}-\d{2}$/.test(params.expectedTargetDate) ||
|
|
1167
|
-
!params.expectedTargetShapeRevision ||
|
|
1168
|
-
!params.expectedStateRevision ||
|
|
1169
|
-
params.remainingProjectedGap <= 0 ||
|
|
1170
|
-
params.remainingReadyOrProjectedGap !== 0) {
|
|
1171
|
-
return null;
|
|
1172
|
-
}
|
|
1173
|
-
const expectedSenderIds = [...params.selectedBySender.keys()].sort();
|
|
1174
|
-
const expectedActionTypes = [
|
|
1175
|
-
...new Set(params.selectedBySender.values()),
|
|
1176
|
-
].sort();
|
|
1177
|
-
if (expectedSenderIds.length === 0 || expectedActionTypes.length === 0) {
|
|
1178
|
-
return null;
|
|
1179
|
-
}
|
|
1180
|
-
for (const rawAction of params.value) {
|
|
1181
|
-
if (!isRecord(rawAction) || rawAction.type !== "run_scheduler_sweep") {
|
|
1182
|
-
continue;
|
|
1183
|
-
}
|
|
1184
|
-
const input = isRecord(rawAction.toolInput) ? rawAction.toolInput : {};
|
|
1185
|
-
const actionKey = stringValue(rawAction.actionKey)?.trim();
|
|
1186
|
-
const requestKey = stringValue(input.requestKey)?.trim();
|
|
1187
|
-
const senderIds = sortedUniqueStrings(input.senderIds);
|
|
1188
|
-
const actionTypes = sortedUniqueStrings(input.actionTypes).filter((actionType) => allowedActionType(actionType) === actionType);
|
|
1189
|
-
const campaignIds = sortedUniqueStrings(input.campaignIds);
|
|
1190
|
-
const tableIds = sortedUniqueStrings(input.tableIds);
|
|
1191
|
-
const sourceScopes = sanitizeSchedulerSweepSourceScopes(input.sourceScopes);
|
|
1192
|
-
const receiptRequirements = isRecord(rawAction.receiptRequirements)
|
|
1193
|
-
? rawAction.receiptRequirements
|
|
1194
|
-
: {};
|
|
1195
|
-
const groupBy = stringArray(receiptRequirements.groupBy);
|
|
1196
|
-
const allowedSideEffects = stringArray(rawAction.allowedSideEffects);
|
|
1197
|
-
const forbiddenSideEffects = stringArray(rawAction.forbiddenSideEffects);
|
|
1198
|
-
const rawActionType = allowedActionType(rawAction.actionType);
|
|
1199
|
-
if (input.action !== "run" ||
|
|
1200
|
-
input.workspaceId !== params.expectedWorkspaceId ||
|
|
1201
|
-
input.targetDate !== params.expectedTargetDate ||
|
|
1202
|
-
input.targetDateKey !== params.expectedTargetDate ||
|
|
1203
|
-
input.targetShapeRevision !== params.expectedTargetShapeRevision ||
|
|
1204
|
-
input.stateRevision !== params.expectedStateRevision ||
|
|
1205
|
-
!actionKey ||
|
|
1206
|
-
requestKey !== actionKey ||
|
|
1207
|
-
!sameStrings(senderIds, expectedSenderIds) ||
|
|
1208
|
-
!sameStrings(actionTypes, expectedActionTypes) ||
|
|
1209
|
-
(expectedActionTypes.length === 1 &&
|
|
1210
|
-
rawActionType !== expectedActionTypes[0]) ||
|
|
1211
|
-
campaignIds.length === 0 ||
|
|
1212
|
-
tableIds.length === 0 ||
|
|
1213
|
-
sourceScopes.length === 0 ||
|
|
1214
|
-
sourceScopes.some((scope) => !campaignIds.includes(scope.campaignId) ||
|
|
1215
|
-
!tableIds.includes(scope.tableId)) ||
|
|
1216
|
-
rawAction.toolName !== "run_scheduler_sweep" ||
|
|
1217
|
-
rawAction.sideEffectClass !== "scheduler_placement" ||
|
|
1218
|
-
rawAction.workspaceWide !== true ||
|
|
1219
|
-
rawAction.yoloEligible !== true ||
|
|
1220
|
-
receiptRequirements.nonTruncated !== true ||
|
|
1221
|
-
!sameStrings(groupBy, SCHEDULER_SWEEP_RECEIPT_GROUPS) ||
|
|
1222
|
-
!sameStrings(allowedSideEffects, SCHEDULER_SWEEP_ALLOWED_SIDE_EFFECTS) ||
|
|
1223
|
-
!sameStrings(forbiddenSideEffects, SCHEDULER_SWEEP_FORBIDDEN_SIDE_EFFECTS)) {
|
|
1224
|
-
continue;
|
|
1225
|
-
}
|
|
1226
|
-
return {
|
|
1227
|
-
rank: 1,
|
|
1228
|
-
type: "run_scheduler_sweep",
|
|
1229
|
-
actionType: rawActionType,
|
|
1230
|
-
toolName: "run_scheduler_sweep",
|
|
1231
|
-
sideEffectClass: "scheduler_placement",
|
|
1232
|
-
ids: {},
|
|
1233
|
-
toolInput: {
|
|
1234
|
-
action: "run",
|
|
1235
|
-
workspaceId: params.expectedWorkspaceId,
|
|
1236
|
-
targetDate: params.expectedTargetDate,
|
|
1237
|
-
targetDateKey: params.expectedTargetDate,
|
|
1238
|
-
senderIds,
|
|
1239
|
-
actionTypes,
|
|
1240
|
-
campaignIds,
|
|
1241
|
-
tableIds,
|
|
1242
|
-
sourceScopes,
|
|
1243
|
-
targetShapeRevision: params.expectedTargetShapeRevision,
|
|
1244
|
-
stateRevision: params.expectedStateRevision,
|
|
1245
|
-
requestKey,
|
|
1246
|
-
},
|
|
1247
|
-
inputSummary: stringValue(rawAction.inputSummary) ?? "",
|
|
1248
|
-
reason: stringValue(rawAction.reason) ?? "",
|
|
1249
|
-
prerequisites: stringArray(rawAction.prerequisites),
|
|
1250
|
-
rereadAfter: rawAction.rereadAfter === "get_refill_target_plan"
|
|
1251
|
-
? "get_refill_target_plan"
|
|
1252
|
-
: null,
|
|
1253
|
-
stopCondition: stringValue(rawAction.stopCondition) ?? "",
|
|
1254
|
-
yoloEligible: true,
|
|
1255
|
-
workspaceWide: true,
|
|
1256
|
-
allowedSideEffects: [...SCHEDULER_SWEEP_ALLOWED_SIDE_EFFECTS],
|
|
1257
|
-
forbiddenSideEffects: [...SCHEDULER_SWEEP_FORBIDDEN_SIDE_EFFECTS],
|
|
1258
|
-
receiptRequirements: {
|
|
1259
|
-
nonTruncated: true,
|
|
1260
|
-
groupBy: [...SCHEDULER_SWEEP_RECEIPT_GROUPS],
|
|
1261
|
-
},
|
|
1262
|
-
actionKey,
|
|
1263
|
-
};
|
|
1264
|
-
}
|
|
1265
|
-
return null;
|
|
1266
|
-
}
|
|
1267
817
|
function paidRefreshNeededSenderIds(senderRefillPlans) {
|
|
1268
818
|
const senderIds = new Set();
|
|
1269
819
|
for (const plan of senderRefillPlans) {
|
|
@@ -1385,17 +935,11 @@ function sanitizeRefillTargetPlanResult(result) {
|
|
|
1385
935
|
const actionTypes = [...new Set(selectedBySender.values())];
|
|
1386
936
|
if (selectedKeys.size === 0)
|
|
1387
937
|
return emptyUnsupportedResult(result);
|
|
1388
|
-
const senderPlans = rawSenderPlans
|
|
1389
|
-
.
|
|
1390
|
-
selectedKeys.has(`${String(plan.senderId)}:${String(plan.actionType)}`))
|
|
1391
|
-
.map(sanitizeSenderPlan)
|
|
1392
|
-
.filter((plan) => Boolean(plan));
|
|
938
|
+
const senderPlans = rawSenderPlans.filter((plan) => isRecord(plan) &&
|
|
939
|
+
selectedKeys.has(`${String(plan.senderId)}:${String(plan.actionType)}`));
|
|
1393
940
|
const selectedDays = Array.isArray(target.selectedDays)
|
|
1394
|
-
? target.selectedDays
|
|
1395
|
-
.filter((day) => isRecord(day) &&
|
|
941
|
+
? target.selectedDays.filter((day) => isRecord(day) &&
|
|
1396
942
|
selectedKeys.has(`${String(day.senderId)}:${String(day.actionType)}`))
|
|
1397
|
-
.map(sanitizeSelectedDay)
|
|
1398
|
-
.filter((day) => Boolean(day))
|
|
1399
943
|
: [];
|
|
1400
944
|
const actionSelections = rawSelections
|
|
1401
945
|
.filter((selection) => isRecord(selection) &&
|
|
@@ -1403,22 +947,20 @@ function sanitizeRefillTargetPlanResult(result) {
|
|
|
1403
947
|
selectedBySender.has(selection.senderId))
|
|
1404
948
|
.map((selection) => {
|
|
1405
949
|
const actionType = selectedBySender.get(selection.senderId);
|
|
1406
|
-
const
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
const evidence = sanitized.evidence.filter((item) => item.actionType === actionType);
|
|
950
|
+
const evidence = Array.isArray(selection.evidence)
|
|
951
|
+
? selection.evidence.filter((item) => isRecord(item) && item.actionType === actionType)
|
|
952
|
+
: [];
|
|
1410
953
|
return {
|
|
1411
|
-
...
|
|
954
|
+
...selection,
|
|
1412
955
|
actionTypes: actionType ? [actionType] : [],
|
|
1413
956
|
evidence,
|
|
1414
957
|
};
|
|
1415
|
-
})
|
|
1416
|
-
.filter((selection) => Boolean(selection));
|
|
958
|
+
});
|
|
1417
959
|
const grossTarget = senderPlans.reduce((sum, plan) => sum + numberValue(plan.grossTarget), 0);
|
|
1418
960
|
const requestedTarget = senderPlans.reduce((sum, plan) => sum + numberValue(plan.requestedTarget), 0);
|
|
1419
961
|
const effectiveTarget = senderPlans.reduce((sum, plan) => {
|
|
1420
|
-
const target = typeof plan.
|
|
1421
|
-
? plan.
|
|
962
|
+
const target = typeof plan.schedulerCapacityTarget === "number"
|
|
963
|
+
? plan.schedulerCapacityTarget
|
|
1422
964
|
: numberValue(plan.grossTarget);
|
|
1423
965
|
return sum + target;
|
|
1424
966
|
}, 0);
|
|
@@ -1433,20 +975,7 @@ function sanitizeRefillTargetPlanResult(result) {
|
|
|
1433
975
|
const senderRefillPlans = sanitizeStructuredSenderPlans(target.senderRefillPlans, selectedBySender);
|
|
1434
976
|
const paidRefreshNeededSenderIdSet = paidRefreshNeededSenderIds(senderRefillPlans);
|
|
1435
977
|
const blockers = sanitizeBlockers(result.blockers, selectedKeys, paidRefreshNeededSenderIdSet);
|
|
1436
|
-
const
|
|
1437
|
-
const schedulerSweepAction = sanitizeTargetSchedulerSweep({
|
|
1438
|
-
value: target.globalActionQueue,
|
|
1439
|
-
selectedBySender,
|
|
1440
|
-
expectedWorkspaceId: stringValue(target.workspaceId),
|
|
1441
|
-
expectedTargetDate: stringValue(request.targetDate),
|
|
1442
|
-
expectedTargetShapeRevision: stringValue(result.targetShapeRevision),
|
|
1443
|
-
expectedStateRevision: stringValue(result.stateRevision),
|
|
1444
|
-
remainingProjectedGap,
|
|
1445
|
-
remainingReadyOrProjectedGap,
|
|
1446
|
-
});
|
|
1447
|
-
const globalActionQueue = schedulerSweepAction
|
|
1448
|
-
? [schedulerSweepAction]
|
|
1449
|
-
: buildSanitizedGlobalActionQueue(senderRefillPlans);
|
|
978
|
+
const globalActionQueue = buildSanitizedGlobalActionQueue(senderRefillPlans);
|
|
1450
979
|
const hasTerminalNoActionBlocker = globalActionQueue.length === 0 &&
|
|
1451
980
|
blockers.some((blocker) => TERMINAL_NO_ACTION_BLOCKER_CODES.has(String(blocker.code)));
|
|
1452
981
|
const status = remainingProjectedGap === 0
|
|
@@ -1483,7 +1012,6 @@ function sanitizeRefillTargetPlanResult(result) {
|
|
|
1483
1012
|
remainingProjectedGap,
|
|
1484
1013
|
remainingReadyOrProjectedGap,
|
|
1485
1014
|
remainingReadyOrScheduledGap: remainingReadyOrProjectedGap,
|
|
1486
|
-
...sanitizePhase98RefillContract(target),
|
|
1487
1015
|
},
|
|
1488
1016
|
coverage: isRecord(result.coverage)
|
|
1489
1017
|
? {
|
|
@@ -1501,7 +1029,7 @@ function sanitizeRefillTargetPlanResult(result) {
|
|
|
1501
1029
|
export const refillTargetPlanToolDefinitions = [
|
|
1502
1030
|
{
|
|
1503
1031
|
name: "get_refill_target_plan",
|
|
1504
|
-
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
|
|
1032
|
+
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.",
|
|
1505
1033
|
inputSchema: {
|
|
1506
1034
|
type: "object",
|
|
1507
1035
|
properties: {
|