@sellable/mcp 0.1.536 → 0.1.537
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 +2 -5
- package/dist/index-dev.js +0 -0
- package/dist/index.js +0 -0
- package/dist/refill-run-loop.d.ts +1 -9
- package/dist/refill-run-loop.js +84 -138
- package/dist/tools/evergreen-refill-plan.d.ts +0 -19
- package/dist/tools/evergreen-refill-plan.js +0 -19
- package/dist/tools/refill-executors.d.ts +7 -0
- package/dist/tools/refill-executors.js +22 -0
- package/dist/tools/refill-sends-v2.d.ts +0 -19
- package/dist/tools/refill-sends-v2.js +2 -31
- package/dist/tools/refill-sends.d.ts +12 -0
- package/dist/tools/refill-sends.js +58 -36
- package/dist/tools/refill-target-plan.js +6 -19
- package/dist/tools/registry.d.ts +0 -36
- package/dist/tools/scheduler-fill-capacity.js +1 -1
- package/dist/tools/scheduler-run.d.ts +0 -5
- package/dist/tools/scheduler-run.js +1 -24
- package/dist/tools/senders.d.ts +14 -8
- package/dist/tools/senders.js +21 -10
- package/package.json +1 -1
- package/skills/refill-sends/SKILL.md +1 -9
- package/skills/refill-sends-v2/SKILL.md +5 -18
- package/skills/refill-sends-v2-workflow/SKILL.md +2 -16
- package/skills/refill-sends-v2-workflow/core/flow.v1.json +3 -19
- package/skills/refill-sends-workflow/SKILL.md +3 -5
- package/skills/refill-sends-workflow/core/flow.v1.json +1 -1
- package/dist/refill-date-window.d.ts +0 -34
- package/dist/refill-date-window.js +0 -210
- package/dist/tools/refill-sends-evergreen.d.ts +0 -28
- package/dist/tools/refill-sends-evergreen.js +0 -47
|
@@ -1,18 +1,14 @@
|
|
|
1
|
-
import { actionIds, collectPaidInmailRefreshActions, executeOneYoloPrimitive, firstGlobalAction, normalizeStrings, numberValue, recordValue, refreshPaidInmailCreditsWithRetry, stringValue, } from "./refill-executors.js";
|
|
1
|
+
import { actionIds, classifyPaidInmailRefreshReceipt, collectPaidInmailRefreshActions, executeOneYoloPrimitive, firstGlobalAction, normalizeStrings, numberValue, recordValue, refreshPaidInmailCreditsWithRetry, stringValue, } from "./refill-executors.js";
|
|
2
2
|
import { getRefillTargetPlan } from "./refill-target-plan.js";
|
|
3
3
|
import { createWorkspaceContext, normalizeExplicitWorkspaceId, } from "./workspace-context.js";
|
|
4
4
|
const DEFAULT_SCHEDULER_FORWARD_HOURS = 48;
|
|
5
5
|
const MCP_PAID_INMAIL_CREDITS_MAX_STALENESS_SECONDS = 4 * 60 * 60;
|
|
6
6
|
function normalizeHorizonSendDays(value) {
|
|
7
|
-
if (value === undefined)
|
|
7
|
+
if (value === undefined || value === null)
|
|
8
8
|
return null;
|
|
9
|
-
if (typeof value !== "number" ||
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
value > 7) {
|
|
13
|
-
throw new Error("horizonSendDays must be an integer between 1 and 7.");
|
|
14
|
-
}
|
|
15
|
-
return value;
|
|
9
|
+
if (typeof value !== "number" || !Number.isFinite(value))
|
|
10
|
+
return null;
|
|
11
|
+
return Math.max(1, Math.min(7, Math.floor(value)));
|
|
16
12
|
}
|
|
17
13
|
function normalizeUntilDate(value) {
|
|
18
14
|
if (value === undefined || value === null || value === "")
|
|
@@ -95,7 +91,7 @@ export const refillSendsToolDefinitions = [
|
|
|
95
91
|
type: "number",
|
|
96
92
|
minimum: 1,
|
|
97
93
|
maximum: 7,
|
|
98
|
-
description: "Compatibility override for explicit
|
|
94
|
+
description: "Compatibility override for an explicit sender-local send-day horizon. Omit for the default scheduler-forward 48-hour target window.",
|
|
99
95
|
},
|
|
100
96
|
untilDate: {
|
|
101
97
|
type: "string",
|
|
@@ -188,7 +184,7 @@ export function refillSendsCommand(input = {}) {
|
|
|
188
184
|
horizonHours: horizonSendDays === null ? DEFAULT_SCHEDULER_FORWARD_HOURS : null,
|
|
189
185
|
description: horizonSendDays === null
|
|
190
186
|
? "Fill the default scheduler-forward 48-hour target window."
|
|
191
|
-
:
|
|
187
|
+
: "Fill the explicit compatibility horizon by sender-local send days.",
|
|
192
188
|
},
|
|
193
189
|
approvalMode,
|
|
194
190
|
campaignId: input.campaignId ?? null,
|
|
@@ -235,7 +231,7 @@ export function refillSendsCommand(input = {}) {
|
|
|
235
231
|
"Fresh reread get_campaign_refill_state immediately before any import, prep, approval, or horizon-fill mutation.",
|
|
236
232
|
"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.",
|
|
237
233
|
"Source/fallback primitives require receipt-proven exhaustion: existingRowFrontier.hasMoreFrontierRows:false, approvalCandidates:0, no fresh active prep, no stuckActiveCells, and no non-terminal approvedNotDispatched rows. Treat anomalies, stuckActiveCells, and non-terminal approvedNotDispatched as diagnose-and-report gates, not exhaustion. Terminal approvedNotDispatched blockers may be reported and then the ladder can proceed.",
|
|
238
|
-
"In --yolo, this tool automatically
|
|
234
|
+
"In manual/non-yolo, scheduled, and --yolo modes, this tool may automatically refresh stale or missing paid-InMail credit facts once per selected sender when the first target plan returns refresh_paid_inmail_credits candidates. This is the only newly allowed automatic write in manual/non-yolo mode; it reruns get_refill_target_plan and returns autoPaidInmailRefresh with attemptedSenderIds, refreshedPaidInmailSenderIds, failedPaidInmailRefreshes, and the post-refresh targetPlan before any prep/source-copy/bounded-approval/read-only wait action is chosen.",
|
|
239
235
|
"Freshness gate precedes scheduler wait: if any selected target.senderRefillPlans[].paidInmail.status is missing_credit_facts or stale_credit_facts, or the target plan contains refresh_paid_inmail_credits, do not enter wait_for_scheduler even when remainingReadyOrProjectedGap is 0; refresh exact sender credit facts once, reread get_refill_target_plan, then choose scheduler wait only if freshness is clean.",
|
|
240
236
|
"Scheduler-run receipt interpretation: cellsConsidered is allocation-attempt count, readyCellsFound is ready inventory before prefilters, and campaignScopeSummary must include the selected campaign/table before inferring it was ready-but-blocked. Read prefiltered, skipped, and deferred separately. For ready closed-InMail cells with stale paid-credit facts, route to refresh_paid_inmail_credits_then_rerun once, then rerun/status. wait_for_capacity_or_window means report loaded/capped/waiting and do not source or prep more rows. no_ready_cells_continue_refill_prep means return to the refill/prep ladder.",
|
|
241
237
|
"For wait_for_active_work and wait_for_scheduler, honor the receipt's absolute wait.deadlineAt when present. If the deadline is expired on this call, escalate to diagnostics with the receipt evidence instead of issuing another blind wait.",
|
|
@@ -379,7 +375,11 @@ export async function executeRefillSendsCommand(input = {}) {
|
|
|
379
375
|
? { ...input, workspaceId: workspaceContext.context.workspaceId }
|
|
380
376
|
: input;
|
|
381
377
|
const command = refillSendsCommand(scopedInput);
|
|
382
|
-
|
|
378
|
+
const workspaceId = workspaceContext && workspaceContext.ok
|
|
379
|
+
? workspaceContext.context.workspaceId
|
|
380
|
+
: normalizeExplicitWorkspaceId(scopedInput.workspaceId);
|
|
381
|
+
const canRefreshPaidInmailFacts = yolo || executionMode === "scheduled" || Boolean(workspaceId);
|
|
382
|
+
if (!canRefreshPaidInmailFacts) {
|
|
383
383
|
return {
|
|
384
384
|
...command,
|
|
385
385
|
autoPaidInmailRefresh: {
|
|
@@ -387,7 +387,7 @@ export async function executeRefillSendsCommand(input = {}) {
|
|
|
387
387
|
status: "not_run_without_yolo",
|
|
388
388
|
refreshedPaidInmailSenderIds: [],
|
|
389
389
|
failedPaidInmailRefreshes: [],
|
|
390
|
-
note: "Automatic paid InMail credit refresh
|
|
390
|
+
note: "Automatic paid InMail credit refresh requires --yolo, scheduled mode, or an explicit workspaceId so the request can refresh exact sender facts safely.",
|
|
391
391
|
},
|
|
392
392
|
yoloExecution: {
|
|
393
393
|
enabled: false,
|
|
@@ -397,9 +397,6 @@ export async function executeRefillSendsCommand(input = {}) {
|
|
|
397
397
|
},
|
|
398
398
|
};
|
|
399
399
|
}
|
|
400
|
-
const workspaceId = workspaceContext && workspaceContext.ok
|
|
401
|
-
? workspaceContext.context.workspaceId
|
|
402
|
-
: normalizeExplicitWorkspaceId(scopedInput.workspaceId);
|
|
403
400
|
const targetPlanInput = targetPlanInputFor(scopedInput);
|
|
404
401
|
const targetPlanBeforePaidRefresh = await getRefillTargetPlan(targetPlanInput);
|
|
405
402
|
const refreshActions = collectPaidInmailRefreshActions(targetPlanBeforePaidRefresh);
|
|
@@ -425,7 +422,7 @@ export async function executeRefillSendsCommand(input = {}) {
|
|
|
425
422
|
}
|
|
426
423
|
const refreshResult = await refreshPaidInmailCreditsWithRetry(action.senderId, workspaceId, paidRefreshOptionsFromApprovalPacket(approvalPacket));
|
|
427
424
|
if (refreshResult.receipt) {
|
|
428
|
-
|
|
425
|
+
const classification = classifyPaidInmailRefreshReceipt(refreshResult.receipt);
|
|
429
426
|
refreshReceipts.push({
|
|
430
427
|
senderId: action.senderId,
|
|
431
428
|
actionKey: action.actionKey ?? null,
|
|
@@ -434,7 +431,23 @@ export async function executeRefillSendsCommand(input = {}) {
|
|
|
434
431
|
approvalSource: "explicit_yolo_flag",
|
|
435
432
|
approvalPacket,
|
|
436
433
|
receipt: refreshResult.receipt,
|
|
434
|
+
receiptStatus: classification.status,
|
|
435
|
+
usableCurrentFacts: classification.usableCurrentFacts,
|
|
437
436
|
});
|
|
437
|
+
if (classification.usableCurrentFacts) {
|
|
438
|
+
refreshedPaidInmailSenderIds.push(action.senderId);
|
|
439
|
+
}
|
|
440
|
+
else {
|
|
441
|
+
failedPaidInmailRefreshes.push({
|
|
442
|
+
senderId: action.senderId,
|
|
443
|
+
attempts: refreshResult.attempts,
|
|
444
|
+
error: classification.error ??
|
|
445
|
+
"paid InMail credit refresh did not return usable current facts",
|
|
446
|
+
errors: refreshResult.errors,
|
|
447
|
+
receiptStatus: classification.status,
|
|
448
|
+
receipt: refreshResult.receipt,
|
|
449
|
+
});
|
|
450
|
+
}
|
|
438
451
|
}
|
|
439
452
|
else {
|
|
440
453
|
failedPaidInmailRefreshes.push({
|
|
@@ -449,8 +462,8 @@ export async function executeRefillSendsCommand(input = {}) {
|
|
|
449
462
|
const targetPlan = refreshActions.length > 0
|
|
450
463
|
? await getRefillTargetPlan(targetPlanInput)
|
|
451
464
|
: targetPlanBeforePaidRefresh;
|
|
452
|
-
const selectedAction = refreshActions.length
|
|
453
|
-
const primitiveAttempt = refreshActions.length > 0
|
|
465
|
+
const selectedAction = yolo && refreshActions.length === 0 ? firstGlobalAction(targetPlan) : null;
|
|
466
|
+
const primitiveAttempt = !yolo || refreshActions.length > 0
|
|
454
467
|
? null
|
|
455
468
|
: await executeOneYoloPrimitive(selectedAction, workspaceId ?? undefined);
|
|
456
469
|
const shouldRereadAfterPrimitive = primitiveAttempt?.status === "executed_and_reread" ||
|
|
@@ -463,7 +476,9 @@ export async function executeRefillSendsCommand(input = {}) {
|
|
|
463
476
|
...command,
|
|
464
477
|
targetPlan: finalTargetPlan,
|
|
465
478
|
targetPlanBeforePaidRefresh: refreshActions.length > 0 ? targetPlanBeforePaidRefresh : null,
|
|
466
|
-
targetPlanBeforeYoloPrimitive: refreshActions.length === 0 && postActionTargetPlan
|
|
479
|
+
targetPlanBeforeYoloPrimitive: yolo && refreshActions.length === 0 && postActionTargetPlan
|
|
480
|
+
? targetPlan
|
|
481
|
+
: null,
|
|
467
482
|
autoPaidInmailRefresh: {
|
|
468
483
|
enabled: true,
|
|
469
484
|
status: refreshActions.length === 0
|
|
@@ -482,23 +497,30 @@ export async function executeRefillSendsCommand(input = {}) {
|
|
|
482
497
|
? "refill_sends refreshed stale paid InMail credit facts internally with bounded retries, once per sender, then returned the post-refresh targetPlan."
|
|
483
498
|
: "No stale or missing paid InMail credit refresh candidates were present in the initial target plan.",
|
|
484
499
|
},
|
|
485
|
-
yoloExecution:
|
|
500
|
+
yoloExecution: !yolo
|
|
486
501
|
? {
|
|
487
|
-
enabled:
|
|
488
|
-
status: "
|
|
502
|
+
enabled: false,
|
|
503
|
+
status: "not_run_without_yolo",
|
|
489
504
|
selectedAction: null,
|
|
490
|
-
targetPlanReread:
|
|
505
|
+
targetPlanReread: false,
|
|
491
506
|
}
|
|
492
|
-
:
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
:
|
|
502
|
-
|
|
507
|
+
: refreshActions.length > 0
|
|
508
|
+
? {
|
|
509
|
+
enabled: true,
|
|
510
|
+
status: "skipped_after_paid_refresh",
|
|
511
|
+
selectedAction: null,
|
|
512
|
+
targetPlanReread: true,
|
|
513
|
+
}
|
|
514
|
+
: {
|
|
515
|
+
enabled: true,
|
|
516
|
+
status: primitiveAttempt?.status ?? "no_action",
|
|
517
|
+
selectedAction,
|
|
518
|
+
result: primitiveAttempt?.result,
|
|
519
|
+
targetPlanReread: shouldRereadAfterPrimitive,
|
|
520
|
+
refusalReason: primitiveAttempt?.refusalReason,
|
|
521
|
+
postActionFirstAction: postActionTargetPlan
|
|
522
|
+
? firstGlobalAction(postActionTargetPlan)
|
|
523
|
+
: null,
|
|
524
|
+
},
|
|
503
525
|
};
|
|
504
526
|
}
|
|
@@ -1026,16 +1026,6 @@ function sanitizeRefillTargetPlanResult(result) {
|
|
|
1026
1026
|
mcpSanitizedRefillLanes: true,
|
|
1027
1027
|
};
|
|
1028
1028
|
}
|
|
1029
|
-
function stripInternalTargetDateKeys(value) {
|
|
1030
|
-
if (Array.isArray(value)) {
|
|
1031
|
-
return value.map((item) => stripInternalTargetDateKeys(item));
|
|
1032
|
-
}
|
|
1033
|
-
if (!isRecord(value))
|
|
1034
|
-
return value;
|
|
1035
|
-
return Object.fromEntries(Object.entries(value)
|
|
1036
|
-
.filter(([key]) => key !== "targetDateKey")
|
|
1037
|
-
.map(([key, nested]) => [key, stripInternalTargetDateKeys(nested)]));
|
|
1038
|
-
}
|
|
1039
1029
|
export const refillTargetPlanToolDefinitions = [
|
|
1040
1030
|
{
|
|
1041
1031
|
name: "get_refill_target_plan",
|
|
@@ -1052,7 +1042,7 @@ export const refillTargetPlanToolDefinitions = [
|
|
|
1052
1042
|
type: "number",
|
|
1053
1043
|
minimum: 1,
|
|
1054
1044
|
maximum: 7,
|
|
1055
|
-
description: "Compatibility override for explicit
|
|
1045
|
+
description: "Compatibility override for explicit sender-local send-day horizon planning. Omit for the default scheduler-forward 48-hour target window; no-send days contribute zero target.",
|
|
1056
1046
|
},
|
|
1057
1047
|
untilDate: {
|
|
1058
1048
|
type: "string",
|
|
@@ -1062,7 +1052,7 @@ export const refillTargetPlanToolDefinitions = [
|
|
|
1062
1052
|
targetDate: {
|
|
1063
1053
|
type: "string",
|
|
1064
1054
|
pattern: "^\\d{4}-\\d{2}-\\d{2}$",
|
|
1065
|
-
description: "Optional
|
|
1055
|
+
description: "Optional exact sender-local YYYY-MM-DD date to fill. Distinct from untilDate: targetDate asks how many scheduler-fillable slots exist on only this date.",
|
|
1066
1056
|
},
|
|
1067
1057
|
campaignId: {
|
|
1068
1058
|
type: "string",
|
|
@@ -1112,14 +1102,11 @@ export const refillTargetPlanToolDefinitions = [
|
|
|
1112
1102
|
];
|
|
1113
1103
|
export async function getRefillTargetPlan(input = {}) {
|
|
1114
1104
|
const workspaceId = normalizeExplicitWorkspaceId(input.workspaceId);
|
|
1115
|
-
const targetDate = input.targetDate;
|
|
1116
|
-
const untilDate = targetDate ? undefined : input.untilDate;
|
|
1117
|
-
const horizonSendDays = targetDate || untilDate ? undefined : input.horizonSendDays;
|
|
1118
1105
|
const result = await postRefillTargetPlan({
|
|
1119
1106
|
intent: input.intent,
|
|
1120
|
-
horizonSendDays,
|
|
1121
|
-
untilDate,
|
|
1122
|
-
targetDate,
|
|
1107
|
+
horizonSendDays: input.horizonSendDays,
|
|
1108
|
+
untilDate: input.untilDate,
|
|
1109
|
+
targetDate: input.targetDate,
|
|
1123
1110
|
campaignId: input.campaignId,
|
|
1124
1111
|
tableId: input.tableId,
|
|
1125
1112
|
senderIds: input.senderIds,
|
|
@@ -1130,7 +1117,7 @@ export async function getRefillTargetPlan(input = {}) {
|
|
|
1130
1117
|
paidInmailCreditsMaxStalenessSeconds: MCP_PAID_INMAIL_CREDITS_MAX_STALENESS_SECONDS,
|
|
1131
1118
|
...(workspaceId ? { workspaceId } : {}),
|
|
1132
1119
|
}, workspaceId ?? undefined);
|
|
1133
|
-
const sanitized =
|
|
1120
|
+
const sanitized = sanitizeRefillTargetPlanResult(result);
|
|
1134
1121
|
if (!workspaceId || !isRecord(sanitized))
|
|
1135
1122
|
return sanitized;
|
|
1136
1123
|
return {
|
package/dist/tools/registry.d.ts
CHANGED
|
@@ -2758,22 +2758,6 @@ export declare const allTools: ({
|
|
|
2758
2758
|
enum: string[];
|
|
2759
2759
|
description: string;
|
|
2760
2760
|
};
|
|
2761
|
-
targetDate: {
|
|
2762
|
-
type: string;
|
|
2763
|
-
pattern: string;
|
|
2764
|
-
description: string;
|
|
2765
|
-
};
|
|
2766
|
-
untilDate: {
|
|
2767
|
-
type: string;
|
|
2768
|
-
pattern: string;
|
|
2769
|
-
description: string;
|
|
2770
|
-
};
|
|
2771
|
-
horizonSendDays: {
|
|
2772
|
-
type: string;
|
|
2773
|
-
minimum: number;
|
|
2774
|
-
maximum: number;
|
|
2775
|
-
description: string;
|
|
2776
|
-
};
|
|
2777
2761
|
journal: {
|
|
2778
2762
|
type: string;
|
|
2779
2763
|
description: string;
|
|
@@ -7401,10 +7385,6 @@ export declare const allTools: ({
|
|
|
7401
7385
|
enum: string[];
|
|
7402
7386
|
description: string;
|
|
7403
7387
|
};
|
|
7404
|
-
targetDate: {
|
|
7405
|
-
type: string;
|
|
7406
|
-
description: string;
|
|
7407
|
-
};
|
|
7408
7388
|
};
|
|
7409
7389
|
required: string[];
|
|
7410
7390
|
additionalProperties: boolean;
|
|
@@ -7446,22 +7426,6 @@ export declare const allTools: ({
|
|
|
7446
7426
|
type: string;
|
|
7447
7427
|
enum: string[];
|
|
7448
7428
|
};
|
|
7449
|
-
targetDate: {
|
|
7450
|
-
type: string;
|
|
7451
|
-
pattern: string;
|
|
7452
|
-
description: string;
|
|
7453
|
-
};
|
|
7454
|
-
untilDate: {
|
|
7455
|
-
type: string;
|
|
7456
|
-
pattern: string;
|
|
7457
|
-
description: string;
|
|
7458
|
-
};
|
|
7459
|
-
horizonSendDays: {
|
|
7460
|
-
type: string;
|
|
7461
|
-
minimum: number;
|
|
7462
|
-
maximum: number;
|
|
7463
|
-
description: string;
|
|
7464
|
-
};
|
|
7465
7429
|
};
|
|
7466
7430
|
required: string[];
|
|
7467
7431
|
additionalProperties: boolean;
|
|
@@ -10,7 +10,7 @@ async function postSchedulerFillCapacity(body, workspaceId) {
|
|
|
10
10
|
export const schedulerFillCapacityToolDefinitions = [
|
|
11
11
|
{
|
|
12
12
|
name: "get_scheduler_fill_capacity",
|
|
13
|
-
description: "read-only scheduler capacity query for refill-sends before any refill mutation. It asks the product scheduler model how many additional cells the scheduler will try to place for exact sender/action requests, using the default scheduler-forward horizon or one exact targetDate.
|
|
13
|
+
description: "read-only scheduler capacity query for refill-sends before any refill mutation. It asks the product scheduler model how many additional cells the scheduler will try to place for exact sender/action requests, using the default scheduler-forward horizon or one exact targetDate. It returns scheduler-fillable slots, occupied scheduled/processing slots, sender sendability gates, cooldowns, Sales Navigator status for paid InMail, cached paid-InMail credit feasibility, threshold source, blockers, warnings, and explicit sideEffects false. This tool does not create rows, import leads, prepare messages, approve messages, does not schedule sends, does not refresh paid InMail credits, mutate thresholds, start campaigns, launch, or send. Use exact senderId values only; never pass sender names.",
|
|
14
14
|
inputSchema: {
|
|
15
15
|
type: "object",
|
|
16
16
|
properties: {
|
|
@@ -2,7 +2,6 @@ type SchedulerRunAction = "run" | "status";
|
|
|
2
2
|
type RunSchedulerSweepInput = {
|
|
3
3
|
workspaceId: string;
|
|
4
4
|
action?: SchedulerRunAction;
|
|
5
|
-
targetDate?: string | null;
|
|
6
5
|
};
|
|
7
6
|
export declare const schedulerRunToolDefinitions: {
|
|
8
7
|
name: string;
|
|
@@ -19,10 +18,6 @@ export declare const schedulerRunToolDefinitions: {
|
|
|
19
18
|
enum: string[];
|
|
20
19
|
description: string;
|
|
21
20
|
};
|
|
22
|
-
targetDate: {
|
|
23
|
-
type: string;
|
|
24
|
-
description: string;
|
|
25
|
-
};
|
|
26
21
|
};
|
|
27
22
|
required: string[];
|
|
28
23
|
additionalProperties: boolean;
|
|
@@ -10,7 +10,7 @@ async function postSchedulerRun(body, workspaceId) {
|
|
|
10
10
|
export const schedulerRunToolDefinitions = [
|
|
11
11
|
{
|
|
12
12
|
name: "run_scheduler_sweep",
|
|
13
|
-
description: 'Trigger the product scheduler placement sweep for one explicit workspace now, or read the last on-demand scheduler run status with action "status".
|
|
13
|
+
description: 'Trigger the product scheduler placement sweep for one explicit workspace now, or read the last on-demand scheduler run status with action "status". A run is workspace-wide, not a scoped run for one campaign/table, and returns a synchronous envelope with status ran, attached, backoff, window_closed_noop, or failed; retryAfterMs for backoff replays; and a backward-compatible receipt. In v2 receipts, readyCellsFound is total scheduler-ready supply found before filters, cellsConsidered is the allocation-attempt count that survived prefilters, prefiltered means ready cells removed before allocation such as no capacity, stale paid InMail credit facts, or sender mismatch, skipped means considered cells rejected by hard scheduler gates, and deferred means considered cells waiting on windows/capacity/cooldown. campaignScopeSummary lists bounded tables/campaigns the workspace-wide run inspected; absence there is not a scoped-run guarantee that the target was ready. The receipt can include readyCellsByType, consideredCellsByType, prefilterReasons, skippedReasons, deferredReasons, summary, and nextAction. It places cells within existing scheduler gates only: it can move placement earlier, but it cannot bypass sending windows, daily limits, cooldowns, sender gates, billing, or credit thresholds, and it never sends messages directly. Repeated calls inside the backoff window replay the last receipt verbatim. Status is read-only and scoped to the last on-demand run only; cron sweeps are not recorded here.',
|
|
14
14
|
inputSchema: {
|
|
15
15
|
type: "object",
|
|
16
16
|
properties: {
|
|
@@ -23,33 +23,12 @@ export const schedulerRunToolDefinitions = [
|
|
|
23
23
|
enum: ["run", "status"],
|
|
24
24
|
description: 'Use "run" to trigger a placement sweep now. Use "status" for a read-only view of the last on-demand run. Defaults to "run".',
|
|
25
25
|
},
|
|
26
|
-
targetDate: {
|
|
27
|
-
type: "string",
|
|
28
|
-
description: "Optional one exact sender-local date (YYYY-MM-DD) to scope scheduler placement/status. The run remains workspace-wide inside that date.",
|
|
29
|
-
},
|
|
30
26
|
},
|
|
31
27
|
required: ["workspaceId"],
|
|
32
28
|
additionalProperties: false,
|
|
33
29
|
},
|
|
34
30
|
},
|
|
35
31
|
];
|
|
36
|
-
function isValidDateKey(value) {
|
|
37
|
-
if (!/^\d{4}-\d{2}-\d{2}$/.test(value))
|
|
38
|
-
return false;
|
|
39
|
-
const [year, month, day] = value.split("-").map(Number);
|
|
40
|
-
const date = new Date(Date.UTC(year, month - 1, day));
|
|
41
|
-
return (date.getUTCFullYear() === year &&
|
|
42
|
-
date.getUTCMonth() === month - 1 &&
|
|
43
|
-
date.getUTCDate() === day);
|
|
44
|
-
}
|
|
45
|
-
function normalizeTargetDate(value) {
|
|
46
|
-
if (value === undefined)
|
|
47
|
-
return undefined;
|
|
48
|
-
if (typeof value !== "string" || !isValidDateKey(value)) {
|
|
49
|
-
throw new Error("targetDate must be a valid YYYY-MM-DD calendar date.");
|
|
50
|
-
}
|
|
51
|
-
return value;
|
|
52
|
-
}
|
|
53
32
|
export async function runSchedulerSweep(input) {
|
|
54
33
|
const workspaceId = normalizeExplicitWorkspaceId(input.workspaceId);
|
|
55
34
|
if (!workspaceId) {
|
|
@@ -59,10 +38,8 @@ export async function runSchedulerSweep(input) {
|
|
|
59
38
|
if (action !== "run" && action !== "status") {
|
|
60
39
|
throw new Error('action must be "run" or "status" for run_scheduler_sweep.');
|
|
61
40
|
}
|
|
62
|
-
const targetDate = normalizeTargetDate(input.targetDate);
|
|
63
41
|
return postSchedulerRun({
|
|
64
42
|
workspaceId,
|
|
65
43
|
action,
|
|
66
|
-
targetDate,
|
|
67
44
|
}, workspaceId);
|
|
68
45
|
}
|
package/dist/tools/senders.d.ts
CHANGED
|
@@ -52,16 +52,22 @@ export type PaidInmailCreditStatus = {
|
|
|
52
52
|
};
|
|
53
53
|
export type RefreshPaidInmailCreditsResponse = {
|
|
54
54
|
senderId: string;
|
|
55
|
-
refreshed:
|
|
55
|
+
refreshed: boolean;
|
|
56
|
+
error?: string | null;
|
|
56
57
|
credits: PaidInmailCreditStatus;
|
|
57
|
-
receipt?:
|
|
58
|
+
receipt?: {
|
|
59
|
+
status?: string;
|
|
60
|
+
refreshed?: boolean;
|
|
61
|
+
error?: string;
|
|
62
|
+
[key: string]: unknown;
|
|
63
|
+
} | null;
|
|
58
64
|
sideEffects: {
|
|
59
|
-
refreshedLinkedInDerivedCreditFacts:
|
|
60
|
-
updatedSenderCreditCache:
|
|
61
|
-
campaignMutation:
|
|
62
|
-
schedulerMutation:
|
|
63
|
-
thresholdMutation:
|
|
64
|
-
sendMutation:
|
|
65
|
+
refreshedLinkedInDerivedCreditFacts: boolean;
|
|
66
|
+
updatedSenderCreditCache: boolean;
|
|
67
|
+
campaignMutation: boolean;
|
|
68
|
+
schedulerMutation: boolean;
|
|
69
|
+
thresholdMutation: boolean;
|
|
70
|
+
sendMutation: boolean;
|
|
65
71
|
};
|
|
66
72
|
};
|
|
67
73
|
export declare const senderToolDefinitions: ({
|
package/dist/tools/senders.js
CHANGED
|
@@ -237,6 +237,21 @@ function normalizeCreditStatus(raw) {
|
|
|
237
237
|
needsRefresh: raw?.needsRefresh === true,
|
|
238
238
|
};
|
|
239
239
|
}
|
|
240
|
+
function normalizeRefreshReceipt(raw) {
|
|
241
|
+
if (!raw || typeof raw !== "object")
|
|
242
|
+
return null;
|
|
243
|
+
return raw;
|
|
244
|
+
}
|
|
245
|
+
function normalizeCreditRefreshSideEffects(raw, receiptRefreshed) {
|
|
246
|
+
return {
|
|
247
|
+
refreshedLinkedInDerivedCreditFacts: raw?.refreshedLinkedInDerivedCreditFacts === true || receiptRefreshed,
|
|
248
|
+
updatedSenderCreditCache: raw?.updatedSenderCreditCache === true || receiptRefreshed,
|
|
249
|
+
campaignMutation: raw?.campaignMutation === true,
|
|
250
|
+
schedulerMutation: raw?.schedulerMutation === true,
|
|
251
|
+
thresholdMutation: raw?.thresholdMutation === true,
|
|
252
|
+
sendMutation: raw?.sendMutation === true,
|
|
253
|
+
};
|
|
254
|
+
}
|
|
240
255
|
export async function refreshPaidInmailCredits(input) {
|
|
241
256
|
const senderId = input.senderId?.trim();
|
|
242
257
|
if (!senderId) {
|
|
@@ -268,18 +283,14 @@ export async function refreshPaidInmailCredits(input) {
|
|
|
268
283
|
if (threshold !== null)
|
|
269
284
|
body.threshold = threshold;
|
|
270
285
|
const result = await api.post(`/api/v3/mcp/senders/${encodeURIComponent(senderId)}/refresh-inmail-credits`, body, requestOptions);
|
|
286
|
+
const receipt = normalizeRefreshReceipt(result?.receipt);
|
|
287
|
+
const receiptRefreshed = result?.refreshed === true || receipt?.refreshed === true;
|
|
271
288
|
return {
|
|
272
289
|
senderId,
|
|
273
|
-
refreshed:
|
|
290
|
+
refreshed: receiptRefreshed,
|
|
291
|
+
error: pickString(result?.error, receipt?.error),
|
|
274
292
|
credits: normalizeCreditStatus(result?.credits),
|
|
275
|
-
receipt
|
|
276
|
-
sideEffects:
|
|
277
|
-
refreshedLinkedInDerivedCreditFacts: true,
|
|
278
|
-
updatedSenderCreditCache: true,
|
|
279
|
-
campaignMutation: false,
|
|
280
|
-
schedulerMutation: false,
|
|
281
|
-
thresholdMutation: false,
|
|
282
|
-
sendMutation: false,
|
|
283
|
-
},
|
|
293
|
+
receipt,
|
|
294
|
+
sideEffects: normalizeCreditRefreshSideEffects(result?.sideEffects, receiptRefreshed),
|
|
284
295
|
};
|
|
285
296
|
}
|
package/package.json
CHANGED
|
@@ -87,12 +87,6 @@ Accepted invocation flags in the same user request:
|
|
|
87
87
|
preserves natural-language arguments better than shell-style flags.
|
|
88
88
|
- `targetDate: YYYY-MM-DD`: exact-date selector alternative when the host
|
|
89
89
|
preserves natural-language arguments better than shell-style flags.
|
|
90
|
-
- `horizonSendDays: N`: compatibility selector for the next N sender-local send
|
|
91
|
-
days when no exact or through-date selector is present.
|
|
92
|
-
|
|
93
|
-
Date selector precedence is `targetDate > untilDate > horizonSendDays`. Use
|
|
94
|
-
`targetDate` for one exact sender-local date, `untilDate` for an inclusive
|
|
95
|
-
through-date, and `horizonSendDays` for the next N sender-local send days.
|
|
96
90
|
|
|
97
91
|
When the host can call typed MCP tools, start with:
|
|
98
92
|
|
|
@@ -278,9 +272,7 @@ same sender/action/date; it tells the MCP how many cells the product scheduler
|
|
|
278
272
|
will try to place and does not import, approve, schedule, refresh credits, or
|
|
279
273
|
mutate.
|
|
280
274
|
When the refill loop has ready rows and needs scheduler pickup now, use
|
|
281
|
-
`run_scheduler_sweep
|
|
282
|
-
`untilDate` or `horizonSendDays` requests, sweep each planner-selected
|
|
283
|
-
`targetDate` with the same explicit `workspaceId`. The sweep can place cells
|
|
275
|
+
`run_scheduler_sweep` with the same explicit `workspaceId`; it can place cells
|
|
284
276
|
within existing scheduler gates and returns the receipt, but it never sends or
|
|
285
277
|
bypasses limits.
|
|
286
278
|
Scheduler-run receipt interpretation: `cellsConsidered is allocation-attempt
|
|
@@ -37,21 +37,16 @@ active workspace readback. Scheduled or autonomous usage must carry
|
|
|
37
37
|
`workspaceId` on every tool call. If the workspace is missing or ambiguous, stop
|
|
38
38
|
with `WORKSPACE_REQUIRED`; do not switch the shared active workspace.
|
|
39
39
|
|
|
40
|
-
Date selectors are sender-local and mutually exclusive by precedence:
|
|
41
|
-
`targetDate > untilDate > horizonSendDays`. Use `targetDate` for one exact sender-local date, `untilDate` for an inclusive through-date, and `horizonSendDays` for the next N sender-local send days. If none is provided, the planner uses the default scheduler-forward 48-hour behavior.
|
|
42
|
-
|
|
43
40
|
For a real refill run:
|
|
44
41
|
|
|
45
42
|
```text
|
|
46
|
-
refill_sends_v2({ workspaceId, intent:"auto", senderIds?, approvalMode
|
|
47
|
-
refill_sends_v2({ workspaceId, targetDate:"2026-07-07" })
|
|
48
|
-
refill_sends_v2({ workspaceId, untilDate:"2026-07-09" })
|
|
43
|
+
refill_sends_v2({ workspaceId, intent:"auto", senderIds?, approvalMode? })
|
|
49
44
|
```
|
|
50
45
|
|
|
51
46
|
For read-only inspection:
|
|
52
47
|
|
|
53
48
|
```text
|
|
54
|
-
refill_sends_v2({ workspaceId, dryRun:true, intent:"auto", senderIds
|
|
49
|
+
refill_sends_v2({ workspaceId, dryRun:true, intent:"auto", senderIds? })
|
|
55
50
|
```
|
|
56
51
|
|
|
57
52
|
To resume an in-progress run, pass the handle back exactly:
|
|
@@ -60,11 +55,6 @@ To resume an in-progress run, pass the handle back exactly:
|
|
|
60
55
|
refill_sends_v2({ workspaceId, runId, fence })
|
|
61
56
|
```
|
|
62
57
|
|
|
63
|
-
The original run's date window is stored in the run record. On resume, the
|
|
64
|
-
stored window is reused and conflicting resume input is blocked; do not add,
|
|
65
|
-
change, or remove `targetDate`, `untilDate`, or `horizonSendDays` while passing
|
|
66
|
-
an existing `{ runId, fence }`.
|
|
67
|
-
|
|
68
58
|
If a stale handle loses the lease, the tool reports the holder status and the
|
|
69
59
|
approximately 10 minute lockout window. Reinvoke with the current handle or wait
|
|
70
60
|
for lease expiry; never guess a fence.
|
|
@@ -135,12 +125,9 @@ host guard, heartbeats the run lease, and may return:
|
|
|
135
125
|
```
|
|
136
126
|
|
|
137
127
|
Reinvoke with that handle. The approximately five minute scheduler budget is at
|
|
138
|
-
the run level, not one tool call.
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
window-closed or loaded-awaiting scheduler report must include remaining-ready
|
|
142
|
-
count, exact expected pickup time, and the resume handle; never treat bare
|
|
143
|
-
"awaiting scheduler" copy as a final answer.
|
|
128
|
+
the run level, not one tool call. A window-closed or loaded-awaiting scheduler
|
|
129
|
+
report must include remaining-ready count, exact expected pickup time, and the
|
|
130
|
+
resume handle; never treat bare "awaiting scheduler" copy as a final answer.
|
|
144
131
|
Scheduler-run receipt interpretation still applies to terminal progress:
|
|
145
132
|
`cellsConsidered is allocation-attempt count`, not total ready supply, while
|
|
146
133
|
`readyCellsFound` is ready inventory found before prefilters. Inspect
|
|
@@ -33,16 +33,10 @@ local files or memory.
|
|
|
33
33
|
Resolve request-scoped `workspaceId` using read-only auth and workspace tools.
|
|
34
34
|
Scheduled or autonomous runs must not rely on implicit workspace state.
|
|
35
35
|
|
|
36
|
-
Carry the request date selector through bootstrap, planning, execution, and
|
|
37
|
-
resume. Date selector precedence is `targetDate > untilDate > horizonSendDays`:
|
|
38
|
-
`targetDate` is one exact sender-local date, `untilDate` is an inclusive
|
|
39
|
-
through-date, and `horizonSendDays` is the next N sender-local send days. If no
|
|
40
|
-
selector is present, use the default scheduler-forward 48-hour behavior.
|
|
41
|
-
|
|
42
36
|
Start or resume the execution loop:
|
|
43
37
|
|
|
44
38
|
```text
|
|
45
|
-
refill_sends_v2({ workspaceId, intent:"auto", senderIds?, approvalMode?,
|
|
39
|
+
refill_sends_v2({ workspaceId, intent:"auto", senderIds?, approvalMode?, runId?, fence? })
|
|
46
40
|
```
|
|
47
41
|
|
|
48
42
|
Use `dryRun:true` only when the user asked for read-only inspection. A dry run
|
|
@@ -50,11 +44,6 @@ writes a journal only. A real run creates or resumes a run record, refreshes
|
|
|
50
44
|
paid-credit trust only when packet facts require it, and returns a resume handle
|
|
51
45
|
when the current invocation must pause.
|
|
52
46
|
|
|
53
|
-
The run record stores the selected date window. On resume, reuse that stored
|
|
54
|
-
window and block conflicting resume input; do not accept a changed
|
|
55
|
-
`targetDate`, `untilDate`, or `horizonSendDays` with an existing `{ runId,
|
|
56
|
-
fence }`.
|
|
57
|
-
|
|
58
47
|
## G1 Plan
|
|
59
48
|
|
|
60
49
|
The loop reads `get_refill_plan_v2` with runState fed back from the run record.
|
|
@@ -127,10 +116,7 @@ outcome, then verifies before replanning.
|
|
|
127
116
|
Scheduler wait is cross-invocation. If the tool returns `in_progress` with
|
|
128
117
|
sweep guidance, re-invoke `refill_sends_v2` with `{runId, fence}`. The scheduler
|
|
129
118
|
budget is cumulative at the run level. Zero pickup after a confirmed sweep is
|
|
130
|
-
debugged from `pipelineDiagnosis`; it is not waited out forever.
|
|
131
|
-
runs request pickup with `run_scheduler_sweep({ workspaceId, targetDate })`;
|
|
132
|
-
`untilDate` and `horizonSendDays` runs sweep each planner-selected exact target
|
|
133
|
-
date.
|
|
119
|
+
debugged from `pipelineDiagnosis`; it is not waited out forever.
|
|
134
120
|
Scheduler-run receipt interpretation still applies to terminal progress:
|
|
135
121
|
`cellsConsidered is allocation-attempt count`, not total ready supply, while
|
|
136
122
|
`readyCellsFound` is ready inventory found before prefilters. Inspect
|