@sellable/mcp 0.1.570 → 0.1.572
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/index-dev.js +0 -0
- package/dist/index.js +0 -0
- package/dist/refill-contract.d.ts +157 -0
- package/dist/refill-contract.js +487 -0
- package/dist/refill-date-window.d.ts +34 -0
- package/dist/refill-date-window.js +210 -0
- package/dist/tools/prompts.d.ts +2 -0
- package/dist/tools/prompts.js +2 -1
- package/dist/tools/refill-executors.d.ts +20 -1
- package/dist/tools/refill-executors.js +168 -8
- package/dist/tools/refill-sends-evergreen.d.ts +28 -0
- package/dist/tools/refill-sends-evergreen.js +47 -0
- package/dist/tools/refill-sends.d.ts +4 -0
- package/dist/tools/refill-sends.js +14 -3
- package/dist/tools/refill-target-plan.js +122 -30
- package/dist/tools/registry.d.ts +48 -0
- package/dist/tools/scheduler-run.d.ts +61 -0
- package/dist/tools/scheduler-run.js +183 -1
- package/package.json +1 -1
- package/skills/refill-sends/SKILL.md +16 -8
- package/skills/refill-sends-workflow/SKILL.md +6 -2
- package/skills/research/config.json +9 -0
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
export const refillSendsEvergreenToolDefinitions = [
|
|
2
|
+
{
|
|
3
|
+
name: "refill_sends_evergreen",
|
|
4
|
+
description: "Read-only Phase 85 evergreen refill command contract. It performs no mutations and only tells the operator to call get_evergreen_refill_plan for a dry-run packet and journal.",
|
|
5
|
+
inputSchema: {
|
|
6
|
+
type: "object",
|
|
7
|
+
properties: {
|
|
8
|
+
workspaceId: {
|
|
9
|
+
type: "string",
|
|
10
|
+
description: "Explicit request-scoped workspace id.",
|
|
11
|
+
},
|
|
12
|
+
},
|
|
13
|
+
required: ["workspaceId"],
|
|
14
|
+
additionalProperties: false,
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
];
|
|
18
|
+
export function refillSendsEvergreenCommand(input) {
|
|
19
|
+
return {
|
|
20
|
+
readOnly: true,
|
|
21
|
+
workspaceId: input.workspaceId ?? null,
|
|
22
|
+
firstOperationalSteps: [
|
|
23
|
+
"Call get_evergreen_refill_plan with the explicit workspaceId.",
|
|
24
|
+
"Read the returned packet, globalActionQueue, per-sender plans, and itinerary before taking any action.",
|
|
25
|
+
"Review the dry-run journal file path returned by get_evergreen_refill_plan.",
|
|
26
|
+
"Phase 85 is PLAN-ONLY; execution arrives in Phase 86.",
|
|
27
|
+
],
|
|
28
|
+
approvalContract: "Nothing is approved or executable in Phase 85. The evergreen command is read-only; Phase 86 introduces execution approval.",
|
|
29
|
+
forbiddenActions: [
|
|
30
|
+
"Do not schedule sends.",
|
|
31
|
+
"Do not send messages.",
|
|
32
|
+
"Do not approve messages.",
|
|
33
|
+
"Do not prepare messages.",
|
|
34
|
+
"Do not start or launch campaigns.",
|
|
35
|
+
"Do not create campaigns.",
|
|
36
|
+
"Do not switch providers or source families.",
|
|
37
|
+
"Do not lower paid InMail thresholds.",
|
|
38
|
+
"Do not refresh paid InMail credits.",
|
|
39
|
+
"Do not write scheduler fields.",
|
|
40
|
+
],
|
|
41
|
+
fillWindow: "Use only the target window and caps returned by get_evergreen_refill_plan.",
|
|
42
|
+
hostExamples: [
|
|
43
|
+
"refill_sends_evergreen({ workspaceId })",
|
|
44
|
+
"get_evergreen_refill_plan({ workspaceId })",
|
|
45
|
+
],
|
|
46
|
+
};
|
|
47
|
+
}
|
|
@@ -418,6 +418,10 @@ export declare function executeRefillSendsCommand(input?: RefillSendsCommandInpu
|
|
|
418
418
|
workspaceResolution: string;
|
|
419
419
|
intent: RefillSendsIntent;
|
|
420
420
|
} | {
|
|
421
|
+
schedulerSweepDisclosure: {
|
|
422
|
+
workspaceWide: boolean;
|
|
423
|
+
reason: string | null;
|
|
424
|
+
} | null;
|
|
421
425
|
targetPlan: unknown;
|
|
422
426
|
targetPlanBeforePaidRefresh: unknown;
|
|
423
427
|
targetPlanBeforeYoloPrimitive: unknown;
|
|
@@ -272,13 +272,13 @@ function buildRefillSendsCommand(input) {
|
|
|
272
272
|
: horizonSendDays === null
|
|
273
273
|
? ""
|
|
274
274
|
: `, horizonSendDays: ${horizonSendDays}`}, approvalMode: "${approvalMode}" }) before any import, prep, approval, start, or schedule-affecting action.`,
|
|
275
|
-
"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.",
|
|
275
|
+
"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, Still need to schedule, and Still need to prepare. Never render an unlabeled Still need value.",
|
|
276
276
|
"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.",
|
|
277
277
|
"When expectedTargetShapeRevision or expectedActionKey is supplied from an already rendered packet, compare both against the first fresh target plan before paid-credit refresh or any primitive. Return approval_scope_changed with the fresh packet on mismatch.",
|
|
278
278
|
"Read target.senderRefillPlans[].refillReceipt as the public ladder receipt: it carries the selected campaign/sender/lane summary, skippedRungs, existingRowFrontier, and any absolute wait.deadlineAt. Do not choose source/copy/fallback work until that receipt proves the earlier ready/prep/approval rungs are exhausted.",
|
|
279
279
|
"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.",
|
|
280
280
|
"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.",
|
|
281
|
-
"If the exact-date global action is run_scheduler_sweep, execute it once and fully reread when remainingReadyOrProjectedGap is 0 but remainingProjectedGap is positive. Otherwise, run only
|
|
281
|
+
"If the exact-date global action is run_scheduler_sweep, execute it once and fully reread when remainingReadyOrProjectedGap is 0 but remainingProjectedGap is positive. Otherwise, run only the receipt-scoped read-only scheduler wait/reread loop using its deadline and about-30-second reread metadata; stop at receipt_deadline, then unchanged_poll_bound, then run_budget. Never redispatch an active/uncertain request key, ask for prep/import/approval, or close out while scheduler pickup is the only remaining state.",
|
|
282
282
|
`Resolve route with resolve_campaign_fill_route({ intent: "${intent}"${workspaceId ? `, workspaceId: "${workspaceId}"` : ""}${input.campaignId ? `, campaignId: "${input.campaignId}"` : ""}${input.tableId ? `, tableId: "${input.tableId}"` : ""} }).`,
|
|
283
283
|
`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"${workspaceId ? `, workspaceId: "${workspaceId}"` : ""} }) and inspect current dashboard-active ACTIVE/PAUSED campaign-backed sequence campaigns before declaring a sender blocked.`,
|
|
284
284
|
workspaceId
|
|
@@ -590,7 +590,17 @@ export async function executeRefillSendsCommand(input = {}) {
|
|
|
590
590
|
const targetPlan = refreshActions.length > 0
|
|
591
591
|
? await getRefillTargetPlan(targetPlanInput)
|
|
592
592
|
: targetPlanBeforePaidRefresh;
|
|
593
|
-
const
|
|
593
|
+
const firstAction = firstGlobalAction(targetPlan);
|
|
594
|
+
const firstActionRecord = recordValue(firstAction);
|
|
595
|
+
const schedulerSweepDisclosure = firstActionRecord?.type === "run_scheduler_sweep" &&
|
|
596
|
+
firstActionRecord.workspaceWide === true &&
|
|
597
|
+
stringValue(firstActionRecord.reason)
|
|
598
|
+
? {
|
|
599
|
+
workspaceWide: true,
|
|
600
|
+
reason: stringValue(firstActionRecord.reason),
|
|
601
|
+
}
|
|
602
|
+
: null;
|
|
603
|
+
const selectedAction = yolo && refreshActions.length === 0 ? firstAction : null;
|
|
594
604
|
const primitiveAttempt = !yolo || refreshActions.length > 0
|
|
595
605
|
? null
|
|
596
606
|
: await executeOneYoloPrimitive(selectedAction, workspaceId ?? undefined);
|
|
@@ -602,6 +612,7 @@ export async function executeRefillSendsCommand(input = {}) {
|
|
|
602
612
|
const finalTargetPlan = postActionTargetPlan ?? targetPlan;
|
|
603
613
|
return {
|
|
604
614
|
...command,
|
|
615
|
+
schedulerSweepDisclosure,
|
|
605
616
|
targetPlan: finalTargetPlan,
|
|
606
617
|
targetPlanBeforePaidRefresh: refreshActions.length > 0 ? targetPlanBeforePaidRefresh : null,
|
|
607
618
|
targetPlanBeforeYoloPrimitive: yolo && refreshActions.length === 0 && postActionTargetPlan
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { getApi } from "../api.js";
|
|
2
|
+
import { REFILL_SCHEDULER_EXPECTED_TARGET_LIMIT, REFILL_SCHEDULER_EXPECTED_TARGET_SENDER_LIMIT, REFILL_SCHEDULER_MAX_PLACEMENTS, } from "./scheduler-run.js";
|
|
2
3
|
import { normalizeExplicitWorkspaceId, workspaceRequestOptions, } from "./workspace-context.js";
|
|
3
4
|
const REFILL_TARGET_ACTION_TYPES = [
|
|
4
5
|
"send_invite",
|
|
@@ -88,7 +89,13 @@ const SCHEDULER_SWEEP_RECEIPT_GROUPS = [
|
|
|
88
89
|
"campaignId",
|
|
89
90
|
"tableId",
|
|
90
91
|
"actionType",
|
|
92
|
+
"senderId",
|
|
91
93
|
];
|
|
94
|
+
const SCHEDULER_EXPECTED_BRANCH_ACTION_TYPES = new Set([
|
|
95
|
+
"send_invite",
|
|
96
|
+
"send_inmail_open",
|
|
97
|
+
"send_inmail_closed",
|
|
98
|
+
]);
|
|
92
99
|
async function postRefillTargetPlan(body, workspaceId) {
|
|
93
100
|
const api = getApi();
|
|
94
101
|
const requestOptions = workspaceRequestOptions(workspaceId);
|
|
@@ -726,7 +733,12 @@ function paidInmailRefreshActionForSenderPlan(plan, paidInmail) {
|
|
|
726
733
|
availableCredits: numberValue(paidInmail?.availableCredits),
|
|
727
734
|
oldThreshold: numberValue(paidInmail?.threshold),
|
|
728
735
|
maxStalenessSeconds: MCP_PAID_INMAIL_CREDITS_MAX_STALENESS_SECONDS,
|
|
729
|
-
actionKey: [
|
|
736
|
+
actionKey: [
|
|
737
|
+
"refresh_paid_inmail_credits",
|
|
738
|
+
senderId,
|
|
739
|
+
campaignId,
|
|
740
|
+
columnId,
|
|
741
|
+
].join(":"),
|
|
730
742
|
rereadAfter: "get_refill_target_plan",
|
|
731
743
|
reason: stringValue(paidInmail?.reason) ??
|
|
732
744
|
"MCP paid InMail sender-credit facts require refresh.",
|
|
@@ -767,6 +779,34 @@ function sanitizeStructuredSenderPlans(value, selectedBySender) {
|
|
|
767
779
|
.map((action, index) => sanitizeStructuredAction(action, selectedBySender, "manual", index + 1))
|
|
768
780
|
.filter((action) => Boolean(action))
|
|
769
781
|
: [];
|
|
782
|
+
const rawCoverage = isRecord(plan.coverage) ? plan.coverage : null;
|
|
783
|
+
const coverage = rawCoverage
|
|
784
|
+
? (() => {
|
|
785
|
+
const goal = numberValue(rawCoverage.goal);
|
|
786
|
+
const alreadySent = numberValue(rawCoverage.alreadySent);
|
|
787
|
+
const scheduled = numberValue(rawCoverage.scheduled);
|
|
788
|
+
const readyAndWaitingToBeScheduled = numberValue(rawCoverage.readyAndWaitingToBeScheduled);
|
|
789
|
+
const stillNeedToSchedule = typeof rawCoverage.stillNeedToSchedule === "number"
|
|
790
|
+
? numberValue(rawCoverage.stillNeedToSchedule)
|
|
791
|
+
: Math.max(0, goal - alreadySent - scheduled);
|
|
792
|
+
const stillNeedToPrepare = typeof rawCoverage.stillNeedToPrepare === "number"
|
|
793
|
+
? numberValue(rawCoverage.stillNeedToPrepare)
|
|
794
|
+
: numberValue(rawCoverage.needToPrepare);
|
|
795
|
+
return {
|
|
796
|
+
goal,
|
|
797
|
+
alreadySent,
|
|
798
|
+
scheduled,
|
|
799
|
+
readyAndWaitingToBeScheduled,
|
|
800
|
+
stillNeedToSchedule,
|
|
801
|
+
stillNeedToPrepare,
|
|
802
|
+
stillNeed: numberValue(rawCoverage.stillNeed),
|
|
803
|
+
needToPrepare: numberValue(rawCoverage.needToPrepare),
|
|
804
|
+
coveredTotal: typeof rawCoverage.coveredTotal === "number"
|
|
805
|
+
? rawCoverage.coveredTotal
|
|
806
|
+
: undefined,
|
|
807
|
+
};
|
|
808
|
+
})()
|
|
809
|
+
: null;
|
|
770
810
|
return {
|
|
771
811
|
senderId: plan.senderId,
|
|
772
812
|
senderName: stringValue(plan.senderName) ?? "",
|
|
@@ -790,20 +830,18 @@ function sanitizeStructuredSenderPlans(value, selectedBySender) {
|
|
|
790
830
|
schedulerCapacityMode: stringValue(plan.horizon.schedulerCapacityMode),
|
|
791
831
|
}
|
|
792
832
|
: {},
|
|
793
|
-
coverage:
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
: {},
|
|
806
|
-
coverageDisplay: stringArray(plan.coverageDisplay),
|
|
833
|
+
coverage: coverage ?? {},
|
|
834
|
+
coverageDisplay: coverage
|
|
835
|
+
? [
|
|
836
|
+
`Need to prepare: ${coverage.stillNeedToPrepare} more rows`,
|
|
837
|
+
`Goal: ${coverage.goal} sends`,
|
|
838
|
+
`Already sent: ${coverage.alreadySent}`,
|
|
839
|
+
`Scheduled: ${coverage.scheduled}`,
|
|
840
|
+
`Ready and waiting to be scheduled: ${coverage.readyAndWaitingToBeScheduled}`,
|
|
841
|
+
`Still need to schedule: ${coverage.stillNeedToSchedule}`,
|
|
842
|
+
`Still need to prepare: ${coverage.stillNeedToPrepare}`,
|
|
843
|
+
]
|
|
844
|
+
: [],
|
|
807
845
|
campaignRanking: sanitizeCampaignRanking(plan.campaignRanking),
|
|
808
846
|
paidInmail,
|
|
809
847
|
sourcePlan: sanitizeSourcePlan(plan.sourcePlan),
|
|
@@ -848,15 +886,10 @@ function sanitizeSchedulerSweepSourceScopes(value) {
|
|
|
848
886
|
const tableId = stringValue(entry.tableId)?.trim();
|
|
849
887
|
const sourceLeadListId = stringValue(entry.sourceLeadListId)?.trim();
|
|
850
888
|
const leadSourceProvider = stringValue(entry.leadSourceProvider)?.trim();
|
|
851
|
-
if (!campaignId ||
|
|
852
|
-
!tableId ||
|
|
853
|
-
!sourceLeadListId ||
|
|
854
|
-
!leadSourceProvider) {
|
|
889
|
+
if (!campaignId || !tableId || !sourceLeadListId || !leadSourceProvider) {
|
|
855
890
|
return [];
|
|
856
891
|
}
|
|
857
|
-
return [
|
|
858
|
-
{ campaignId, tableId, sourceLeadListId, leadSourceProvider },
|
|
859
|
-
];
|
|
892
|
+
return [{ campaignId, tableId, sourceLeadListId, leadSourceProvider }];
|
|
860
893
|
});
|
|
861
894
|
const unique = new Map(scopes.map((scope) => [
|
|
862
895
|
[
|
|
@@ -874,20 +907,56 @@ function sanitizeSchedulerSweepSourceScopes(value) {
|
|
|
874
907
|
return a.tableId.localeCompare(b.tableId);
|
|
875
908
|
});
|
|
876
909
|
}
|
|
910
|
+
function sanitizeSchedulerExpectedTargets(value, scope) {
|
|
911
|
+
if (!Array.isArray(value) ||
|
|
912
|
+
value.length === 0 ||
|
|
913
|
+
value.length > REFILL_SCHEDULER_EXPECTED_TARGET_LIMIT) {
|
|
914
|
+
return null;
|
|
915
|
+
}
|
|
916
|
+
const expectedTargets = [];
|
|
917
|
+
let senderCount = 0;
|
|
918
|
+
for (const rawTarget of value) {
|
|
919
|
+
if (!isRecord(rawTarget))
|
|
920
|
+
return null;
|
|
921
|
+
const campaignId = stringValue(rawTarget.campaignId)?.trim();
|
|
922
|
+
const tableId = stringValue(rawTarget.tableId)?.trim();
|
|
923
|
+
const refillLaneKey = allowedActionType(rawTarget.refillLaneKey);
|
|
924
|
+
const senderIds = sortedUniqueStrings(rawTarget.senderIds);
|
|
925
|
+
const branchActionTypes = sortedUniqueStrings(rawTarget.branchActionTypes).filter((actionType) => SCHEDULER_EXPECTED_BRANCH_ACTION_TYPES.has(actionType));
|
|
926
|
+
senderCount += senderIds.length;
|
|
927
|
+
if (!campaignId ||
|
|
928
|
+
!tableId ||
|
|
929
|
+
!refillLaneKey ||
|
|
930
|
+
senderIds.length === 0 ||
|
|
931
|
+
senderCount > REFILL_SCHEDULER_EXPECTED_TARGET_SENDER_LIMIT ||
|
|
932
|
+
branchActionTypes.length === 0 ||
|
|
933
|
+
!scope.campaignIds.includes(campaignId) ||
|
|
934
|
+
!scope.tableIds.includes(tableId) ||
|
|
935
|
+
senderIds.some((senderId) => !scope.senderIds.includes(senderId))) {
|
|
936
|
+
return null;
|
|
937
|
+
}
|
|
938
|
+
expectedTargets.push({
|
|
939
|
+
campaignId,
|
|
940
|
+
tableId,
|
|
941
|
+
refillLaneKey,
|
|
942
|
+
senderIds,
|
|
943
|
+
branchActionTypes,
|
|
944
|
+
});
|
|
945
|
+
}
|
|
946
|
+
return expectedTargets;
|
|
947
|
+
}
|
|
877
948
|
function sanitizeTargetSchedulerSweep(params) {
|
|
878
949
|
if (!Array.isArray(params.value) ||
|
|
879
950
|
!params.expectedWorkspaceId ||
|
|
880
951
|
!params.expectedTargetDate ||
|
|
881
952
|
!/^\d{4}-\d{2}-\d{2}$/.test(params.expectedTargetDate) ||
|
|
882
953
|
!params.expectedTargetShapeRevision ||
|
|
883
|
-
!params.expectedStateRevision
|
|
884
|
-
params.remainingProjectedGap <= 0 ||
|
|
885
|
-
params.remainingReadyOrProjectedGap !== 0) {
|
|
954
|
+
!params.expectedStateRevision) {
|
|
886
955
|
return null;
|
|
887
956
|
}
|
|
888
|
-
const expectedSenderIds = [...params.
|
|
957
|
+
const expectedSenderIds = [...params.sweepEligibleBySender.keys()].sort();
|
|
889
958
|
const expectedActionTypes = [
|
|
890
|
-
...new Set(params.
|
|
959
|
+
...new Set(params.sweepEligibleBySender.values()),
|
|
891
960
|
].sort();
|
|
892
961
|
if (expectedSenderIds.length === 0 || expectedActionTypes.length === 0) {
|
|
893
962
|
return null;
|
|
@@ -904,6 +973,9 @@ function sanitizeTargetSchedulerSweep(params) {
|
|
|
904
973
|
const campaignIds = sortedUniqueStrings(input.campaignIds);
|
|
905
974
|
const tableIds = sortedUniqueStrings(input.tableIds);
|
|
906
975
|
const sourceScopes = sanitizeSchedulerSweepSourceScopes(input.sourceScopes);
|
|
976
|
+
const expectedTargets = sanitizeSchedulerExpectedTargets(input.expectedTargets, { senderIds, campaignIds, tableIds });
|
|
977
|
+
const expectedTargetsHash = stringValue(input.expectedTargetsHash)?.trim();
|
|
978
|
+
const maxPlacements = numberValue(input.maxPlacements);
|
|
907
979
|
const receiptRequirements = isRecord(rawAction.receiptRequirements)
|
|
908
980
|
? rawAction.receiptRequirements
|
|
909
981
|
: {};
|
|
@@ -933,7 +1005,13 @@ function sanitizeTargetSchedulerSweep(params) {
|
|
|
933
1005
|
rawAction.workspaceWide !== true ||
|
|
934
1006
|
rawAction.yoloEligible !== true ||
|
|
935
1007
|
receiptRequirements.nonTruncated !== true ||
|
|
1008
|
+
receiptRequirements.expectedTargetSummary !== true ||
|
|
936
1009
|
!sameStrings(groupBy, SCHEDULER_SWEEP_RECEIPT_GROUPS) ||
|
|
1010
|
+
!expectedTargets ||
|
|
1011
|
+
!expectedTargetsHash ||
|
|
1012
|
+
!Number.isInteger(maxPlacements) ||
|
|
1013
|
+
maxPlacements <= 0 ||
|
|
1014
|
+
maxPlacements > REFILL_SCHEDULER_MAX_PLACEMENTS ||
|
|
937
1015
|
!sameStrings(allowedSideEffects, SCHEDULER_SWEEP_ALLOWED_SIDE_EFFECTS) ||
|
|
938
1016
|
!sameStrings(forbiddenSideEffects, SCHEDULER_SWEEP_FORBIDDEN_SIDE_EFFECTS)) {
|
|
939
1017
|
continue;
|
|
@@ -955,6 +1033,9 @@ function sanitizeTargetSchedulerSweep(params) {
|
|
|
955
1033
|
campaignIds,
|
|
956
1034
|
tableIds,
|
|
957
1035
|
sourceScopes,
|
|
1036
|
+
expectedTargets,
|
|
1037
|
+
expectedTargetsHash,
|
|
1038
|
+
maxPlacements,
|
|
958
1039
|
targetShapeRevision: params.expectedTargetShapeRevision,
|
|
959
1040
|
stateRevision: params.expectedStateRevision,
|
|
960
1041
|
requestKey,
|
|
@@ -972,6 +1053,7 @@ function sanitizeTargetSchedulerSweep(params) {
|
|
|
972
1053
|
forbiddenSideEffects: [...SCHEDULER_SWEEP_FORBIDDEN_SIDE_EFFECTS],
|
|
973
1054
|
receiptRequirements: {
|
|
974
1055
|
nonTruncated: true,
|
|
1056
|
+
expectedTargetSummary: true,
|
|
975
1057
|
groupBy: [...SCHEDULER_SWEEP_RECEIPT_GROUPS],
|
|
976
1058
|
},
|
|
977
1059
|
actionKey,
|
|
@@ -1141,15 +1223,25 @@ function sanitizeRefillTargetPlanResult(result) {
|
|
|
1141
1223
|
const paidRefreshNeededSenderIdSet = paidRefreshNeededSenderIds(senderRefillPlans);
|
|
1142
1224
|
const blockers = sanitizeBlockers(result.blockers, selectedKeys, paidRefreshNeededSenderIdSet);
|
|
1143
1225
|
const request = isRecord(result.request) ? result.request : {};
|
|
1226
|
+
const sweepEligibleBySender = new Map();
|
|
1227
|
+
for (const plan of senderPlans) {
|
|
1228
|
+
const senderId = stringValue(plan.senderId);
|
|
1229
|
+
const actionType = allowedActionType(plan.actionType);
|
|
1230
|
+
if (senderId &&
|
|
1231
|
+
actionType &&
|
|
1232
|
+
numberValue(plan.remainingProjectedGap) > 0 &&
|
|
1233
|
+
numberValue(plan.remainingReadyOrProjectedGap) === 0 &&
|
|
1234
|
+
numberValue(plan.readyBuffer) > 0) {
|
|
1235
|
+
sweepEligibleBySender.set(senderId, actionType);
|
|
1236
|
+
}
|
|
1237
|
+
}
|
|
1144
1238
|
const schedulerSweepAction = sanitizeTargetSchedulerSweep({
|
|
1145
1239
|
value: target.globalActionQueue,
|
|
1146
|
-
|
|
1240
|
+
sweepEligibleBySender,
|
|
1147
1241
|
expectedWorkspaceId: stringValue(target.workspaceId),
|
|
1148
1242
|
expectedTargetDate: stringValue(request.targetDate),
|
|
1149
1243
|
expectedTargetShapeRevision: stringValue(result.targetShapeRevision),
|
|
1150
1244
|
expectedStateRevision: stringValue(result.stateRevision),
|
|
1151
|
-
remainingProjectedGap,
|
|
1152
|
-
remainingReadyOrProjectedGap,
|
|
1153
1245
|
});
|
|
1154
1246
|
const globalActionQueue = schedulerSweepAction
|
|
1155
1247
|
? [schedulerSweepAction]
|
package/dist/tools/registry.d.ts
CHANGED
|
@@ -7838,6 +7838,54 @@ export declare const allTools: ({
|
|
|
7838
7838
|
type: string;
|
|
7839
7839
|
description: string;
|
|
7840
7840
|
};
|
|
7841
|
+
expectedTargets: {
|
|
7842
|
+
type: string;
|
|
7843
|
+
maxItems: 25;
|
|
7844
|
+
items: {
|
|
7845
|
+
type: string;
|
|
7846
|
+
properties: {
|
|
7847
|
+
campaignId: {
|
|
7848
|
+
type: string;
|
|
7849
|
+
};
|
|
7850
|
+
tableId: {
|
|
7851
|
+
type: string;
|
|
7852
|
+
};
|
|
7853
|
+
refillLaneKey: {
|
|
7854
|
+
type: string;
|
|
7855
|
+
};
|
|
7856
|
+
branchActionTypes: {
|
|
7857
|
+
type: string;
|
|
7858
|
+
minItems: number;
|
|
7859
|
+
uniqueItems: boolean;
|
|
7860
|
+
items: {
|
|
7861
|
+
type: string;
|
|
7862
|
+
enum: string[];
|
|
7863
|
+
};
|
|
7864
|
+
};
|
|
7865
|
+
senderIds: {
|
|
7866
|
+
type: string;
|
|
7867
|
+
minItems: number;
|
|
7868
|
+
maxItems: 100;
|
|
7869
|
+
uniqueItems: boolean;
|
|
7870
|
+
items: {
|
|
7871
|
+
type: string;
|
|
7872
|
+
};
|
|
7873
|
+
};
|
|
7874
|
+
};
|
|
7875
|
+
required: string[];
|
|
7876
|
+
additionalProperties: boolean;
|
|
7877
|
+
};
|
|
7878
|
+
};
|
|
7879
|
+
expectedTargetsHash: {
|
|
7880
|
+
type: string;
|
|
7881
|
+
description: string;
|
|
7882
|
+
};
|
|
7883
|
+
maxPlacements: {
|
|
7884
|
+
type: string;
|
|
7885
|
+
minimum: number;
|
|
7886
|
+
maximum: 150;
|
|
7887
|
+
description: string;
|
|
7888
|
+
};
|
|
7841
7889
|
};
|
|
7842
7890
|
required: string[];
|
|
7843
7891
|
additionalProperties: boolean;
|
|
@@ -1,10 +1,23 @@
|
|
|
1
1
|
type SchedulerRunAction = "run" | "status";
|
|
2
|
+
export declare const REFILL_SCHEDULER_EXPECTED_TARGET_LIMIT: 25;
|
|
3
|
+
export declare const REFILL_SCHEDULER_EXPECTED_TARGET_SENDER_LIMIT: 100;
|
|
4
|
+
export declare const REFILL_SCHEDULER_MAX_PLACEMENTS: 150;
|
|
5
|
+
export type SchedulerExpectedTargetInput = {
|
|
6
|
+
campaignId: string;
|
|
7
|
+
tableId: string;
|
|
8
|
+
refillLaneKey: string;
|
|
9
|
+
branchActionTypes: Array<"send_invite" | "send_inmail_open" | "send_inmail_closed">;
|
|
10
|
+
senderIds: string[];
|
|
11
|
+
};
|
|
2
12
|
type RunSchedulerSweepInput = {
|
|
3
13
|
workspaceId: string;
|
|
4
14
|
action?: SchedulerRunAction;
|
|
5
15
|
targetDate?: string;
|
|
6
16
|
requestKey?: string;
|
|
7
17
|
targetShapeRevision?: string;
|
|
18
|
+
expectedTargets?: SchedulerExpectedTargetInput[];
|
|
19
|
+
expectedTargetsHash?: string;
|
|
20
|
+
maxPlacements?: number;
|
|
8
21
|
};
|
|
9
22
|
export declare const schedulerRunToolDefinitions: {
|
|
10
23
|
name: string;
|
|
@@ -33,6 +46,54 @@ export declare const schedulerRunToolDefinitions: {
|
|
|
33
46
|
type: string;
|
|
34
47
|
description: string;
|
|
35
48
|
};
|
|
49
|
+
expectedTargets: {
|
|
50
|
+
type: string;
|
|
51
|
+
maxItems: 25;
|
|
52
|
+
items: {
|
|
53
|
+
type: string;
|
|
54
|
+
properties: {
|
|
55
|
+
campaignId: {
|
|
56
|
+
type: string;
|
|
57
|
+
};
|
|
58
|
+
tableId: {
|
|
59
|
+
type: string;
|
|
60
|
+
};
|
|
61
|
+
refillLaneKey: {
|
|
62
|
+
type: string;
|
|
63
|
+
};
|
|
64
|
+
branchActionTypes: {
|
|
65
|
+
type: string;
|
|
66
|
+
minItems: number;
|
|
67
|
+
uniqueItems: boolean;
|
|
68
|
+
items: {
|
|
69
|
+
type: string;
|
|
70
|
+
enum: string[];
|
|
71
|
+
};
|
|
72
|
+
};
|
|
73
|
+
senderIds: {
|
|
74
|
+
type: string;
|
|
75
|
+
minItems: number;
|
|
76
|
+
maxItems: 100;
|
|
77
|
+
uniqueItems: boolean;
|
|
78
|
+
items: {
|
|
79
|
+
type: string;
|
|
80
|
+
};
|
|
81
|
+
};
|
|
82
|
+
};
|
|
83
|
+
required: string[];
|
|
84
|
+
additionalProperties: boolean;
|
|
85
|
+
};
|
|
86
|
+
};
|
|
87
|
+
expectedTargetsHash: {
|
|
88
|
+
type: string;
|
|
89
|
+
description: string;
|
|
90
|
+
};
|
|
91
|
+
maxPlacements: {
|
|
92
|
+
type: string;
|
|
93
|
+
minimum: number;
|
|
94
|
+
maximum: 150;
|
|
95
|
+
description: string;
|
|
96
|
+
};
|
|
36
97
|
};
|
|
37
98
|
required: string[];
|
|
38
99
|
additionalProperties: boolean;
|