@sellable/mcp 0.1.553 → 0.1.555
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/refill-contract.d.ts +157 -0
- package/dist/refill-contract.js +487 -0
- package/dist/refill-run-client.d.ts +5 -0
- package/dist/refill-run-client.js +15 -0
- package/dist/refill-run-loop.d.ts +12 -1
- package/dist/refill-run-loop.js +158 -13
- package/dist/tools/campaign-message-preparation.d.ts +62 -0
- package/dist/tools/campaign-message-preparation.js +41 -0
- package/dist/tools/evergreen-refill-plan.d.ts +3 -0
- package/dist/tools/evergreen-refill-plan.js +29 -7
- package/dist/tools/prompts.js +9 -0
- package/dist/tools/refill-executors.d.ts +9 -1
- package/dist/tools/refill-executors.js +101 -8
- package/dist/tools/refill-sends-v2.d.ts +112 -1
- package/dist/tools/refill-sends-v2.js +302 -2
- package/dist/tools/refill-sends.d.ts +506 -2
- package/dist/tools/refill-sends.js +134 -1
- package/dist/tools/refill-target-plan.js +317 -23
- package/dist/tools/registry.d.ts +94 -33
- package/dist/tools/registry.js +1 -3
- 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 +91 -388
- 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 +100 -781
- package/skills/refill-sends-workflow/core/contract.v2.json +543 -0
- package/skills/refill-sends-workflow/core/flow.v1.json +122 -0
package/dist/tools/registry.d.ts
CHANGED
|
@@ -662,6 +662,18 @@ export declare const allTools: ({
|
|
|
662
662
|
enum: string[];
|
|
663
663
|
description: string;
|
|
664
664
|
};
|
|
665
|
+
targetDate: {
|
|
666
|
+
type: string;
|
|
667
|
+
description: string;
|
|
668
|
+
};
|
|
669
|
+
refillLaneKey: {
|
|
670
|
+
type: string;
|
|
671
|
+
description: string;
|
|
672
|
+
};
|
|
673
|
+
sourceEpoch: {
|
|
674
|
+
type: string;
|
|
675
|
+
description: string;
|
|
676
|
+
};
|
|
665
677
|
disableLowPassRateStop: {
|
|
666
678
|
type: string;
|
|
667
679
|
description: string;
|
|
@@ -671,6 +683,7 @@ export declare const allTools: ({
|
|
|
671
683
|
description: string;
|
|
672
684
|
};
|
|
673
685
|
jobId?: undefined;
|
|
686
|
+
expectedUpdatedAt?: undefined;
|
|
674
687
|
};
|
|
675
688
|
required: string[];
|
|
676
689
|
additionalProperties: boolean;
|
|
@@ -705,11 +718,52 @@ export declare const allTools: ({
|
|
|
705
718
|
autoContinue?: undefined;
|
|
706
719
|
senderId?: undefined;
|
|
707
720
|
actionType?: undefined;
|
|
721
|
+
targetDate?: undefined;
|
|
722
|
+
refillLaneKey?: undefined;
|
|
723
|
+
sourceEpoch?: undefined;
|
|
708
724
|
disableLowPassRateStop?: undefined;
|
|
725
|
+
expectedUpdatedAt?: undefined;
|
|
709
726
|
};
|
|
710
727
|
additionalProperties: boolean;
|
|
711
728
|
required?: undefined;
|
|
712
729
|
};
|
|
730
|
+
} | {
|
|
731
|
+
name: string;
|
|
732
|
+
description: string;
|
|
733
|
+
inputSchema: {
|
|
734
|
+
type: string;
|
|
735
|
+
properties: {
|
|
736
|
+
jobId: {
|
|
737
|
+
type: string;
|
|
738
|
+
};
|
|
739
|
+
expectedUpdatedAt: {
|
|
740
|
+
type: string;
|
|
741
|
+
description: string;
|
|
742
|
+
};
|
|
743
|
+
workspaceId: {
|
|
744
|
+
type: string;
|
|
745
|
+
description?: undefined;
|
|
746
|
+
};
|
|
747
|
+
campaignId?: undefined;
|
|
748
|
+
tableId?: undefined;
|
|
749
|
+
targetPreparedMessages?: undefined;
|
|
750
|
+
maxRowsToCheck?: undefined;
|
|
751
|
+
batchSize?: undefined;
|
|
752
|
+
maxBatchRows?: undefined;
|
|
753
|
+
approvalMode?: undefined;
|
|
754
|
+
rowSelector?: undefined;
|
|
755
|
+
excludeRowIds?: undefined;
|
|
756
|
+
autoContinue?: undefined;
|
|
757
|
+
senderId?: undefined;
|
|
758
|
+
actionType?: undefined;
|
|
759
|
+
targetDate?: undefined;
|
|
760
|
+
refillLaneKey?: undefined;
|
|
761
|
+
sourceEpoch?: undefined;
|
|
762
|
+
disableLowPassRateStop?: undefined;
|
|
763
|
+
};
|
|
764
|
+
required: string[];
|
|
765
|
+
additionalProperties: boolean;
|
|
766
|
+
};
|
|
713
767
|
} | {
|
|
714
768
|
name: string;
|
|
715
769
|
description: string;
|
|
@@ -7554,47 +7608,54 @@ export declare const allTools: ({
|
|
|
7554
7608
|
type: string;
|
|
7555
7609
|
description: string;
|
|
7556
7610
|
};
|
|
7557
|
-
|
|
7558
|
-
required: string[];
|
|
7559
|
-
additionalProperties: boolean;
|
|
7560
|
-
};
|
|
7561
|
-
} | {
|
|
7562
|
-
name: string;
|
|
7563
|
-
description: string;
|
|
7564
|
-
inputSchema: {
|
|
7565
|
-
type: string;
|
|
7566
|
-
properties: {
|
|
7567
|
-
workspaceId: {
|
|
7568
|
-
type: string;
|
|
7569
|
-
description: string;
|
|
7570
|
-
};
|
|
7571
|
-
runId: {
|
|
7611
|
+
expectedTargets: {
|
|
7572
7612
|
type: string;
|
|
7573
|
-
|
|
7574
|
-
|
|
7575
|
-
|
|
7576
|
-
|
|
7577
|
-
|
|
7613
|
+
maxItems: 25;
|
|
7614
|
+
items: {
|
|
7615
|
+
type: string;
|
|
7616
|
+
properties: {
|
|
7617
|
+
campaignId: {
|
|
7618
|
+
type: string;
|
|
7619
|
+
};
|
|
7620
|
+
tableId: {
|
|
7621
|
+
type: string;
|
|
7622
|
+
};
|
|
7623
|
+
refillLaneKey: {
|
|
7624
|
+
type: string;
|
|
7625
|
+
};
|
|
7626
|
+
branchActionTypes: {
|
|
7627
|
+
type: string;
|
|
7628
|
+
minItems: number;
|
|
7629
|
+
uniqueItems: boolean;
|
|
7630
|
+
items: {
|
|
7631
|
+
type: string;
|
|
7632
|
+
enum: string[];
|
|
7633
|
+
};
|
|
7634
|
+
};
|
|
7635
|
+
senderIds: {
|
|
7636
|
+
type: string;
|
|
7637
|
+
minItems: number;
|
|
7638
|
+
maxItems: 100;
|
|
7639
|
+
uniqueItems: boolean;
|
|
7640
|
+
items: {
|
|
7641
|
+
type: string;
|
|
7642
|
+
};
|
|
7643
|
+
};
|
|
7644
|
+
};
|
|
7645
|
+
required: string[];
|
|
7646
|
+
additionalProperties: boolean;
|
|
7647
|
+
};
|
|
7578
7648
|
};
|
|
7579
|
-
|
|
7649
|
+
expectedTargetsHash: {
|
|
7580
7650
|
type: string;
|
|
7581
7651
|
description: string;
|
|
7582
7652
|
};
|
|
7583
|
-
|
|
7653
|
+
maxPlacements: {
|
|
7584
7654
|
type: string;
|
|
7585
|
-
|
|
7655
|
+
minimum: number;
|
|
7656
|
+
maximum: 150;
|
|
7586
7657
|
description: string;
|
|
7587
7658
|
};
|
|
7588
|
-
senderIds: {
|
|
7589
|
-
type: string;
|
|
7590
|
-
items: {
|
|
7591
|
-
type: string;
|
|
7592
|
-
};
|
|
7593
|
-
};
|
|
7594
|
-
intent: {
|
|
7595
|
-
type: string;
|
|
7596
|
-
enum: string[];
|
|
7597
|
-
};
|
|
7598
7659
|
};
|
|
7599
7660
|
required: string[];
|
|
7600
7661
|
additionalProperties: boolean;
|
package/dist/tools/registry.js
CHANGED
|
@@ -34,10 +34,9 @@ import { onDemandToolDefinitions } from "./one-off.js";
|
|
|
34
34
|
import { processingToolDefinitions } from "./processing.js";
|
|
35
35
|
import { promptToolDefinitions } from "./prompts.js";
|
|
36
36
|
import { readinessToolDefinitions } from "./readiness.js";
|
|
37
|
-
import { refreshSenderEngagementToolDefinitions } from "./refresh-sender-engagement.js";
|
|
38
|
-
import { refillSendsV2ToolDefinitions } from "./refill-sends-v2.js";
|
|
39
37
|
import { refillSendsToolDefinitions } from "./refill-sends.js";
|
|
40
38
|
import { refillTargetPlanToolDefinitions } from "./refill-target-plan.js";
|
|
39
|
+
import { refreshSenderEngagementToolDefinitions } from "./refresh-sender-engagement.js";
|
|
41
40
|
import { rowToolDefinitions } from "./rows.js";
|
|
42
41
|
import { rubricToolDefinitions } from "./rubrics.js";
|
|
43
42
|
import { schedulerFillCapacityToolDefinitions } from "./scheduler-fill-capacity.js";
|
|
@@ -61,7 +60,6 @@ export const allTools = [
|
|
|
61
60
|
...schedulerFillCapacityToolDefinitions,
|
|
62
61
|
...schedulerRunToolDefinitions,
|
|
63
62
|
...refillSendsToolDefinitions,
|
|
64
|
-
...refillSendsV2ToolDefinitions,
|
|
65
63
|
...setupEvergreenCampaignsToolDefinitions,
|
|
66
64
|
...campaignHorizonFillToolDefinitions,
|
|
67
65
|
...campaignMessagePreparationToolDefinitions,
|
|
@@ -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;
|
|
@@ -1,5 +1,9 @@
|
|
|
1
|
+
import { createHash } from "crypto";
|
|
1
2
|
import { getApi } from "../api.js";
|
|
2
3
|
import { normalizeExplicitWorkspaceId, workspaceRequestOptions, } from "./workspace-context.js";
|
|
4
|
+
export const REFILL_SCHEDULER_EXPECTED_TARGET_LIMIT = 25;
|
|
5
|
+
export const REFILL_SCHEDULER_EXPECTED_TARGET_SENDER_LIMIT = 100;
|
|
6
|
+
export const REFILL_SCHEDULER_MAX_PLACEMENTS = 150;
|
|
3
7
|
async function postSchedulerRun(body, workspaceId) {
|
|
4
8
|
const api = getApi();
|
|
5
9
|
const requestOptions = workspaceRequestOptions(workspaceId);
|
|
@@ -29,10 +33,89 @@ function normalizeOptionalScopeValue(value, field) {
|
|
|
29
33
|
}
|
|
30
34
|
return value.trim();
|
|
31
35
|
}
|
|
36
|
+
function canonicalizeExpectedTargets(value) {
|
|
37
|
+
if (!Array.isArray(value) || value.length === 0) {
|
|
38
|
+
throw new Error("expectedTargets must be a non-empty array.");
|
|
39
|
+
}
|
|
40
|
+
if (value.length > REFILL_SCHEDULER_EXPECTED_TARGET_LIMIT) {
|
|
41
|
+
throw new Error(`expected_target_overflow: expectedTargets exceeds ${REFILL_SCHEDULER_EXPECTED_TARGET_LIMIT}.`);
|
|
42
|
+
}
|
|
43
|
+
const supportedActions = new Set([
|
|
44
|
+
"send_invite",
|
|
45
|
+
"send_inmail_open",
|
|
46
|
+
"send_inmail_closed",
|
|
47
|
+
]);
|
|
48
|
+
const canonical = value.map((rawTarget, index) => {
|
|
49
|
+
if (!rawTarget ||
|
|
50
|
+
typeof rawTarget !== "object" ||
|
|
51
|
+
Array.isArray(rawTarget)) {
|
|
52
|
+
throw new Error(`expectedTargets[${index}] must be an object.`);
|
|
53
|
+
}
|
|
54
|
+
const target = rawTarget;
|
|
55
|
+
const allowedKeys = new Set([
|
|
56
|
+
"campaignId",
|
|
57
|
+
"tableId",
|
|
58
|
+
"refillLaneKey",
|
|
59
|
+
"branchActionTypes",
|
|
60
|
+
"senderIds",
|
|
61
|
+
]);
|
|
62
|
+
if (Object.keys(target).some((key) => !allowedKeys.has(key))) {
|
|
63
|
+
throw new Error(`expectedTargets[${index}] contains unsupported fields.`);
|
|
64
|
+
}
|
|
65
|
+
const campaignId = normalizeOptionalScopeValue(target.campaignId, `expectedTargets[${index}].campaignId`);
|
|
66
|
+
const tableId = normalizeOptionalScopeValue(target.tableId, `expectedTargets[${index}].tableId`);
|
|
67
|
+
const refillLaneKey = normalizeOptionalScopeValue(target.refillLaneKey, `expectedTargets[${index}].refillLaneKey`);
|
|
68
|
+
if (!campaignId ||
|
|
69
|
+
!tableId ||
|
|
70
|
+
!refillLaneKey ||
|
|
71
|
+
!Array.isArray(target.branchActionTypes) ||
|
|
72
|
+
target.branchActionTypes.length === 0 ||
|
|
73
|
+
!Array.isArray(target.senderIds) ||
|
|
74
|
+
target.senderIds.length === 0) {
|
|
75
|
+
throw new Error(`expectedTargets[${index}] is incomplete.`);
|
|
76
|
+
}
|
|
77
|
+
if (target.senderIds.length > REFILL_SCHEDULER_EXPECTED_TARGET_SENDER_LIMIT) {
|
|
78
|
+
throw new Error(`expected_target_overflow: expectedTargets[${index}].senderIds exceeds ${REFILL_SCHEDULER_EXPECTED_TARGET_SENDER_LIMIT}.`);
|
|
79
|
+
}
|
|
80
|
+
const branchActionTypes = target.branchActionTypes.map((actionType) => {
|
|
81
|
+
if (typeof actionType !== "string" || !supportedActions.has(actionType)) {
|
|
82
|
+
throw new Error(`expectedTargets[${index}] contains an unsupported branch action.`);
|
|
83
|
+
}
|
|
84
|
+
return actionType;
|
|
85
|
+
});
|
|
86
|
+
const senderIds = target.senderIds.map((senderId) => {
|
|
87
|
+
const normalized = normalizeOptionalScopeValue(senderId, `expectedTargets[${index}].senderIds`);
|
|
88
|
+
if (!normalized) {
|
|
89
|
+
throw new Error(`expectedTargets[${index}].senderIds must be non-empty.`);
|
|
90
|
+
}
|
|
91
|
+
return normalized;
|
|
92
|
+
});
|
|
93
|
+
if (new Set(branchActionTypes).size !== branchActionTypes.length ||
|
|
94
|
+
new Set(senderIds).size !== senderIds.length) {
|
|
95
|
+
throw new Error(`expectedTargets[${index}] branchActionTypes and senderIds must be unique.`);
|
|
96
|
+
}
|
|
97
|
+
return {
|
|
98
|
+
campaignId,
|
|
99
|
+
tableId,
|
|
100
|
+
refillLaneKey,
|
|
101
|
+
branchActionTypes: branchActionTypes.sort(),
|
|
102
|
+
senderIds: senderIds.sort(),
|
|
103
|
+
};
|
|
104
|
+
});
|
|
105
|
+
canonical.sort((left, right) => JSON.stringify(left).localeCompare(JSON.stringify(right)));
|
|
106
|
+
const targetKeys = canonical.map((target) => JSON.stringify(target));
|
|
107
|
+
if (new Set(targetKeys).size !== targetKeys.length) {
|
|
108
|
+
throw new Error("expectedTargets contains duplicate canonical targets.");
|
|
109
|
+
}
|
|
110
|
+
return canonical;
|
|
111
|
+
}
|
|
112
|
+
function computeExpectedTargetsHash(targets) {
|
|
113
|
+
return createHash("sha256").update(JSON.stringify(targets)).digest("hex");
|
|
114
|
+
}
|
|
32
115
|
export const schedulerRunToolDefinitions = [
|
|
33
116
|
{
|
|
34
117
|
name: "run_scheduler_sweep",
|
|
35
|
-
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
|
|
118
|
+
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 v3 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 remains bounded display evidence, while expectedTargetSummary explains every hash-bound planner target exactly once without filtering placement. Expected targets require a frozen numeric total placement cap; unrelated eligible campaigns may consume that cap through normal workspace-wide gates, and changedCounts audits every actual placement by campaign, table, action, and sender. 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.',
|
|
36
119
|
inputSchema: {
|
|
37
120
|
type: "object",
|
|
38
121
|
properties: {
|
|
@@ -57,6 +140,56 @@ export const schedulerRunToolDefinitions = [
|
|
|
57
140
|
type: "string",
|
|
58
141
|
description: "Optional stable approved refill target-shape revision associated with requestKey.",
|
|
59
142
|
},
|
|
143
|
+
expectedTargets: {
|
|
144
|
+
type: "array",
|
|
145
|
+
maxItems: REFILL_SCHEDULER_EXPECTED_TARGET_LIMIT,
|
|
146
|
+
items: {
|
|
147
|
+
type: "object",
|
|
148
|
+
properties: {
|
|
149
|
+
campaignId: { type: "string" },
|
|
150
|
+
tableId: { type: "string" },
|
|
151
|
+
refillLaneKey: { type: "string" },
|
|
152
|
+
branchActionTypes: {
|
|
153
|
+
type: "array",
|
|
154
|
+
minItems: 1,
|
|
155
|
+
uniqueItems: true,
|
|
156
|
+
items: {
|
|
157
|
+
type: "string",
|
|
158
|
+
enum: [
|
|
159
|
+
"send_invite",
|
|
160
|
+
"send_inmail_open",
|
|
161
|
+
"send_inmail_closed",
|
|
162
|
+
],
|
|
163
|
+
},
|
|
164
|
+
},
|
|
165
|
+
senderIds: {
|
|
166
|
+
type: "array",
|
|
167
|
+
minItems: 1,
|
|
168
|
+
maxItems: REFILL_SCHEDULER_EXPECTED_TARGET_SENDER_LIMIT,
|
|
169
|
+
uniqueItems: true,
|
|
170
|
+
items: { type: "string" },
|
|
171
|
+
},
|
|
172
|
+
},
|
|
173
|
+
required: [
|
|
174
|
+
"campaignId",
|
|
175
|
+
"tableId",
|
|
176
|
+
"refillLaneKey",
|
|
177
|
+
"branchActionTypes",
|
|
178
|
+
"senderIds",
|
|
179
|
+
],
|
|
180
|
+
additionalProperties: false,
|
|
181
|
+
},
|
|
182
|
+
},
|
|
183
|
+
expectedTargetsHash: {
|
|
184
|
+
type: "string",
|
|
185
|
+
description: "Required SHA-256 of canonical expectedTargets for a target-aware run.",
|
|
186
|
+
},
|
|
187
|
+
maxPlacements: {
|
|
188
|
+
type: "integer",
|
|
189
|
+
minimum: 1,
|
|
190
|
+
maximum: REFILL_SCHEDULER_MAX_PLACEMENTS,
|
|
191
|
+
description: "Required frozen numeric total placement cap across the workspace-wide sweep when expectedTargets are present.",
|
|
192
|
+
},
|
|
60
193
|
},
|
|
61
194
|
required: ["workspaceId"],
|
|
62
195
|
additionalProperties: false,
|
|
@@ -75,11 +208,60 @@ export async function runSchedulerSweep(input) {
|
|
|
75
208
|
if (action !== "run" && action !== "status") {
|
|
76
209
|
throw new Error('action must be "run" or "status" for run_scheduler_sweep.');
|
|
77
210
|
}
|
|
211
|
+
const hasExpectedTargets = input.expectedTargets !== undefined;
|
|
212
|
+
const hasExpectedTargetScope = input.expectedTargetsHash !== undefined ||
|
|
213
|
+
input.maxPlacements !== undefined;
|
|
214
|
+
if (action === "status" && hasExpectedTargets) {
|
|
215
|
+
throw new Error("expectedTargets are only valid for action run.");
|
|
216
|
+
}
|
|
217
|
+
let expectedTargetRequest;
|
|
218
|
+
if (action === "run" && (hasExpectedTargets || hasExpectedTargetScope)) {
|
|
219
|
+
const expectedTargets = canonicalizeExpectedTargets(input.expectedTargets);
|
|
220
|
+
const expectedTargetsHash = normalizeOptionalScopeValue(input.expectedTargetsHash, "expectedTargetsHash");
|
|
221
|
+
if (!expectedTargetsHash ||
|
|
222
|
+
expectedTargetsHash !== computeExpectedTargetsHash(expectedTargets)) {
|
|
223
|
+
throw new Error("expectedTargetsHash must match the canonical expectedTargets payload.");
|
|
224
|
+
}
|
|
225
|
+
if (typeof input.maxPlacements !== "number" ||
|
|
226
|
+
!Number.isInteger(input.maxPlacements) ||
|
|
227
|
+
input.maxPlacements <= 0 ||
|
|
228
|
+
input.maxPlacements > REFILL_SCHEDULER_MAX_PLACEMENTS) {
|
|
229
|
+
throw new Error(`maxPlacements must be an integer from 1 to ${REFILL_SCHEDULER_MAX_PLACEMENTS}.`);
|
|
230
|
+
}
|
|
231
|
+
if (!targetDate || !requestKey || !targetShapeRevision) {
|
|
232
|
+
throw new Error("expectedTargets require targetDate, requestKey, and targetShapeRevision.");
|
|
233
|
+
}
|
|
234
|
+
expectedTargetRequest = {
|
|
235
|
+
expectedTargets,
|
|
236
|
+
expectedTargetsHash,
|
|
237
|
+
maxPlacements: input.maxPlacements,
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
let expectedStatusScope;
|
|
241
|
+
if (action === "status" && hasExpectedTargetScope) {
|
|
242
|
+
const expectedTargetsHash = normalizeOptionalScopeValue(input.expectedTargetsHash, "expectedTargetsHash");
|
|
243
|
+
if (!expectedTargetsHash ||
|
|
244
|
+
typeof input.maxPlacements !== "number" ||
|
|
245
|
+
!Number.isInteger(input.maxPlacements) ||
|
|
246
|
+
input.maxPlacements <= 0 ||
|
|
247
|
+
input.maxPlacements > REFILL_SCHEDULER_MAX_PLACEMENTS ||
|
|
248
|
+
!targetDate ||
|
|
249
|
+
!requestKey ||
|
|
250
|
+
!targetShapeRevision) {
|
|
251
|
+
throw new Error("hash-bound status requires expectedTargetsHash, maxPlacements, targetDate, requestKey, and targetShapeRevision.");
|
|
252
|
+
}
|
|
253
|
+
expectedStatusScope = {
|
|
254
|
+
expectedTargetsHash,
|
|
255
|
+
maxPlacements: input.maxPlacements,
|
|
256
|
+
};
|
|
257
|
+
}
|
|
78
258
|
return postSchedulerRun({
|
|
79
259
|
workspaceId,
|
|
80
260
|
action,
|
|
81
261
|
...(targetDate ? { targetDate } : {}),
|
|
82
262
|
...(requestKey ? { requestKey } : {}),
|
|
83
263
|
...(targetShapeRevision ? { targetShapeRevision } : {}),
|
|
264
|
+
...(expectedTargetRequest ?? {}),
|
|
265
|
+
...(expectedStatusScope ?? {}),
|
|
84
266
|
}, workspaceId);
|
|
85
267
|
}
|