@sellable/mcp 0.1.554 → 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/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-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 +38 -0
- package/dist/tools/refill-executors.js +222 -3
- 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 +678 -32
- package/dist/tools/refill-sends.js +274 -13
- package/dist/tools/refill-target-plan.js +486 -14
- package/dist/tools/registry.d.ts +96 -27
- package/dist/tools/registry.js +1 -3
- package/dist/tools/scheduler-fill-capacity.js +1 -1
- package/dist/tools/scheduler-run.d.ts +71 -0
- package/dist/tools/scheduler-run.js +203 -1
- package/dist/tools/workspaces.d.ts +4 -6
- package/dist/tools/workspaces.js +11 -13
- package/package.json +1 -1
- package/skills/refill-sends/SKILL.md +91 -353
- 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 -743
- package/skills/refill-sends-workflow/core/contract.v2.json +543 -0
- package/skills/refill-sends-workflow/core/flow.v1.json +185 -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
- package/skills/research/config.json +0 -9
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;
|
|
@@ -7546,47 +7600,62 @@ export declare const allTools: ({
|
|
|
7546
7600
|
type: string;
|
|
7547
7601
|
description: string;
|
|
7548
7602
|
};
|
|
7549
|
-
|
|
7550
|
-
required: string[];
|
|
7551
|
-
additionalProperties: boolean;
|
|
7552
|
-
};
|
|
7553
|
-
} | {
|
|
7554
|
-
name: string;
|
|
7555
|
-
description: string;
|
|
7556
|
-
inputSchema: {
|
|
7557
|
-
type: string;
|
|
7558
|
-
properties: {
|
|
7559
|
-
workspaceId: {
|
|
7603
|
+
requestKey: {
|
|
7560
7604
|
type: string;
|
|
7561
7605
|
description: string;
|
|
7562
7606
|
};
|
|
7563
|
-
|
|
7607
|
+
targetShapeRevision: {
|
|
7564
7608
|
type: string;
|
|
7565
7609
|
description: string;
|
|
7566
7610
|
};
|
|
7567
|
-
|
|
7611
|
+
expectedTargets: {
|
|
7568
7612
|
type: string;
|
|
7569
|
-
|
|
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
|
+
};
|
|
7570
7648
|
};
|
|
7571
|
-
|
|
7649
|
+
expectedTargetsHash: {
|
|
7572
7650
|
type: string;
|
|
7573
7651
|
description: string;
|
|
7574
7652
|
};
|
|
7575
|
-
|
|
7653
|
+
maxPlacements: {
|
|
7576
7654
|
type: string;
|
|
7577
|
-
|
|
7655
|
+
minimum: number;
|
|
7656
|
+
maximum: 150;
|
|
7578
7657
|
description: string;
|
|
7579
7658
|
};
|
|
7580
|
-
senderIds: {
|
|
7581
|
-
type: string;
|
|
7582
|
-
items: {
|
|
7583
|
-
type: string;
|
|
7584
|
-
};
|
|
7585
|
-
};
|
|
7586
|
-
intent: {
|
|
7587
|
-
type: string;
|
|
7588
|
-
enum: string[];
|
|
7589
|
-
};
|
|
7590
7659
|
};
|
|
7591
7660
|
required: string[];
|
|
7592
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,
|
|
@@ -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. 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.",
|
|
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, rolling-weekly candidate timing that shows when capacity frees later in the send window, 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: {
|
|
@@ -1,8 +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;
|
|
16
|
+
requestKey?: string;
|
|
17
|
+
targetShapeRevision?: string;
|
|
18
|
+
expectedTargets?: SchedulerExpectedTargetInput[];
|
|
19
|
+
expectedTargetsHash?: string;
|
|
20
|
+
maxPlacements?: number;
|
|
6
21
|
};
|
|
7
22
|
export declare const schedulerRunToolDefinitions: {
|
|
8
23
|
name: string;
|
|
@@ -23,6 +38,62 @@ export declare const schedulerRunToolDefinitions: {
|
|
|
23
38
|
type: string;
|
|
24
39
|
description: string;
|
|
25
40
|
};
|
|
41
|
+
requestKey: {
|
|
42
|
+
type: string;
|
|
43
|
+
description: string;
|
|
44
|
+
};
|
|
45
|
+
targetShapeRevision: {
|
|
46
|
+
type: string;
|
|
47
|
+
description: string;
|
|
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
|
+
};
|
|
26
97
|
};
|
|
27
98
|
required: string[];
|
|
28
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);
|
|
@@ -21,10 +25,97 @@ function normalizeTargetDate(value) {
|
|
|
21
25
|
}
|
|
22
26
|
return targetDate;
|
|
23
27
|
}
|
|
28
|
+
function normalizeOptionalScopeValue(value, field) {
|
|
29
|
+
if (value === undefined || value === null)
|
|
30
|
+
return null;
|
|
31
|
+
if (typeof value !== "string" || !value.trim()) {
|
|
32
|
+
throw new Error(`${field} must be a non-empty string when provided.`);
|
|
33
|
+
}
|
|
34
|
+
return value.trim();
|
|
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
|
+
}
|
|
24
115
|
export const schedulerRunToolDefinitions = [
|
|
25
116
|
{
|
|
26
117
|
name: "run_scheduler_sweep",
|
|
27
|
-
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.',
|
|
28
119
|
inputSchema: {
|
|
29
120
|
type: "object",
|
|
30
121
|
properties: {
|
|
@@ -41,6 +132,64 @@ export const schedulerRunToolDefinitions = [
|
|
|
41
132
|
type: "string",
|
|
42
133
|
description: "Optional one exact sender-local date (YYYY-MM-DD) to scope scheduler placement/status. The run remains workspace-wide inside that date.",
|
|
43
134
|
},
|
|
135
|
+
requestKey: {
|
|
136
|
+
type: "string",
|
|
137
|
+
description: "Optional deterministic planner action key used to attach to or replay the same exact scheduler attempt.",
|
|
138
|
+
},
|
|
139
|
+
targetShapeRevision: {
|
|
140
|
+
type: "string",
|
|
141
|
+
description: "Optional stable approved refill target-shape revision associated with requestKey.",
|
|
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
|
+
},
|
|
44
193
|
},
|
|
45
194
|
required: ["workspaceId"],
|
|
46
195
|
additionalProperties: false,
|
|
@@ -54,12 +203,65 @@ export async function runSchedulerSweep(input) {
|
|
|
54
203
|
}
|
|
55
204
|
const action = input.action ?? "run";
|
|
56
205
|
const targetDate = normalizeTargetDate(input.targetDate);
|
|
206
|
+
const requestKey = normalizeOptionalScopeValue(input.requestKey, "requestKey");
|
|
207
|
+
const targetShapeRevision = normalizeOptionalScopeValue(input.targetShapeRevision, "targetShapeRevision");
|
|
57
208
|
if (action !== "run" && action !== "status") {
|
|
58
209
|
throw new Error('action must be "run" or "status" for run_scheduler_sweep.');
|
|
59
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
|
+
}
|
|
60
258
|
return postSchedulerRun({
|
|
61
259
|
workspaceId,
|
|
62
260
|
action,
|
|
63
261
|
...(targetDate ? { targetDate } : {}),
|
|
262
|
+
...(requestKey ? { requestKey } : {}),
|
|
263
|
+
...(targetShapeRevision ? { targetShapeRevision } : {}),
|
|
264
|
+
...(expectedTargetRequest ?? {}),
|
|
265
|
+
...(expectedStatusScope ?? {}),
|
|
64
266
|
}, workspaceId);
|
|
65
267
|
}
|
|
@@ -142,17 +142,15 @@ export declare function listWorkspaces(): Promise<{
|
|
|
142
142
|
workspaces: WorkspaceSummary[];
|
|
143
143
|
workspaceLock: {
|
|
144
144
|
enabled: boolean;
|
|
145
|
-
workspaceId
|
|
146
|
-
hiddenWorkspaceCount
|
|
147
|
-
siblingInventoryFetched: boolean;
|
|
145
|
+
workspaceId?: undefined;
|
|
146
|
+
hiddenWorkspaceCount?: undefined;
|
|
148
147
|
};
|
|
149
148
|
} | {
|
|
150
149
|
workspaces: WorkspaceSummary[];
|
|
151
150
|
workspaceLock: {
|
|
152
151
|
enabled: boolean;
|
|
153
|
-
workspaceId
|
|
154
|
-
hiddenWorkspaceCount
|
|
155
|
-
siblingInventoryFetched?: undefined;
|
|
152
|
+
workspaceId: string;
|
|
153
|
+
hiddenWorkspaceCount: number;
|
|
156
154
|
};
|
|
157
155
|
}>;
|
|
158
156
|
export declare function getActiveWorkspace(): {
|
package/dist/tools/workspaces.js
CHANGED
|
@@ -80,21 +80,19 @@ export const workspaceToolDefinitions = [
|
|
|
80
80
|
];
|
|
81
81
|
export async function listWorkspaces() {
|
|
82
82
|
const api = getApi();
|
|
83
|
+
const { workspaces } = await api.get("/api/v3/workspaces");
|
|
83
84
|
const lockedWorkspaceId = getLockedWorkspaceId();
|
|
84
|
-
if (lockedWorkspaceId) {
|
|
85
|
-
|
|
86
|
-
return {
|
|
87
|
-
workspaces: [workspace],
|
|
88
|
-
workspaceLock: {
|
|
89
|
-
enabled: true,
|
|
90
|
-
workspaceId: lockedWorkspaceId,
|
|
91
|
-
hiddenWorkspaceCount: 0,
|
|
92
|
-
siblingInventoryFetched: false,
|
|
93
|
-
},
|
|
94
|
-
};
|
|
85
|
+
if (!lockedWorkspaceId) {
|
|
86
|
+
return { workspaces, workspaceLock: { enabled: false } };
|
|
95
87
|
}
|
|
96
|
-
|
|
97
|
-
|
|
88
|
+
return {
|
|
89
|
+
workspaces: workspaces.filter((ws) => ws.id === lockedWorkspaceId),
|
|
90
|
+
workspaceLock: {
|
|
91
|
+
enabled: true,
|
|
92
|
+
workspaceId: lockedWorkspaceId,
|
|
93
|
+
hiddenWorkspaceCount: workspaces.filter((ws) => ws.id !== lockedWorkspaceId).length,
|
|
94
|
+
},
|
|
95
|
+
};
|
|
98
96
|
}
|
|
99
97
|
export function getActiveWorkspace() {
|
|
100
98
|
const config = getConfig();
|