@sellable/mcp 0.1.556 → 0.1.557
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -2
- package/agents/registry.json +2 -2
- package/dist/api.js +3 -6
- package/dist/auth.d.ts +0 -6
- package/dist/auth.js +2 -44
- package/dist/refill-run-client.d.ts +0 -5
- package/dist/refill-run-client.js +0 -15
- package/dist/refill-run-loop.d.ts +1 -12
- package/dist/refill-run-loop.js +13 -158
- package/dist/server.js +23 -0
- package/dist/tools/auth.d.ts +0 -5
- package/dist/tools/auth.js +12 -49
- package/dist/tools/campaign-message-preparation.d.ts +0 -62
- package/dist/tools/campaign-message-preparation.js +0 -41
- package/dist/tools/campaigns.js +2 -2
- package/dist/tools/csv-dnc.js +2 -2
- package/dist/tools/evergreen-refill-plan.d.ts +0 -3
- package/dist/tools/evergreen-refill-plan.js +7 -29
- package/dist/tools/find-leads-runs.d.ts +151 -0
- package/dist/tools/find-leads-runs.js +98 -0
- package/dist/tools/leads.d.ts +317 -32
- package/dist/tools/leads.js +171 -10
- package/dist/tools/model-quality.js +4 -6
- package/dist/tools/prompts.d.ts +3 -3
- package/dist/tools/prompts.js +7 -15
- package/dist/tools/provider-preflight.d.ts +65 -2
- package/dist/tools/provider-preflight.js +97 -10
- package/dist/tools/readiness.d.ts +89 -5
- package/dist/tools/readiness.js +66 -0
- package/dist/tools/refill-executors.d.ts +0 -38
- package/dist/tools/refill-executors.js +3 -222
- package/dist/tools/refill-sends-v2.d.ts +1 -118
- package/dist/tools/refill-sends-v2.js +2 -310
- package/dist/tools/refill-sends.d.ts +32 -678
- package/dist/tools/refill-sends.js +13 -274
- package/dist/tools/refill-target-plan.js +14 -486
- package/dist/tools/registry.d.ts +330 -115
- package/dist/tools/registry.js +7 -1
- package/dist/tools/scheduler-fill-capacity.js +1 -1
- package/dist/tools/scheduler-run.d.ts +0 -71
- package/dist/tools/scheduler-run.js +1 -203
- package/dist/tools/setup-evergreen-campaigns.js +1 -1
- package/dist/tools/workspace-context.d.ts +1 -1
- package/dist/tools/workspace-context.js +3 -8
- package/dist/tools/workspace-export.js +2 -2
- package/dist/tools/workspaces.d.ts +2 -48
- package/dist/tools/workspaces.js +5 -48
- package/package.json +1 -1
- package/skills/create-campaign/SKILL.md +3 -3
- package/skills/create-campaign-v2/SKILL.md +1 -1
- package/skills/create-evergreen-campaigns/SKILL.md +16 -16
- package/skills/find-leads/SKILL.md +48 -630
- package/skills/find-leads-v2/SKILL.md +70 -0
- package/skills/find-leads-v2/core/flow.v1.json +31 -0
- package/skills/refill-sends/SKILL.md +353 -91
- package/skills/refill-sends-v2/SKILL.md +6 -6
- package/skills/refill-sends-v2-workflow/SKILL.md +5 -5
- package/skills/refill-sends-v2-workflow/core/flow.v1.json +8 -8
- package/skills/refill-sends-workflow/SKILL.md +743 -100
- package/skills/refill-sends-workflow/core/flow.v1.json +1 -185
- package/dist/refill-contract.d.ts +0 -157
- package/dist/refill-contract.js +0 -487
- package/skills/refill-sends-workflow/core/contract.v2.json +0 -543
package/dist/tools/registry.js
CHANGED
|
@@ -25,6 +25,7 @@ import { engageStateToolDefinitions } from "./engage-state.js";
|
|
|
25
25
|
import { enrichmentToolDefinitions } from "./enrichment.js";
|
|
26
26
|
import { refillPlanV2ToolDefinitions } from "./evergreen-refill-plan.js";
|
|
27
27
|
import { frameworkToolDefinitions } from "./framework.js";
|
|
28
|
+
import { findLeadsRunToolDefinitions } from "./find-leads-runs.js";
|
|
28
29
|
import { harvestJobToolDefinitions } from "./harvest-jobs.js";
|
|
29
30
|
import { inboxToolDefinitions } from "./inbox.js";
|
|
30
31
|
import { leadToolDefinitions } from "./leads.js";
|
|
@@ -32,11 +33,13 @@ import { linkedinToolDefinitions } from "./linkedin.js";
|
|
|
32
33
|
import { navigationToolDefinitions } from "./navigation.js";
|
|
33
34
|
import { onDemandToolDefinitions } from "./one-off.js";
|
|
34
35
|
import { processingToolDefinitions } from "./processing.js";
|
|
36
|
+
import { findLeadsProviderPreflightToolDefinitions } from "./provider-preflight.js";
|
|
35
37
|
import { promptToolDefinitions } from "./prompts.js";
|
|
36
38
|
import { readinessToolDefinitions } from "./readiness.js";
|
|
39
|
+
import { refreshSenderEngagementToolDefinitions } from "./refresh-sender-engagement.js";
|
|
40
|
+
import { refillSendsV2ToolDefinitions } from "./refill-sends-v2.js";
|
|
37
41
|
import { refillSendsToolDefinitions } from "./refill-sends.js";
|
|
38
42
|
import { refillTargetPlanToolDefinitions } from "./refill-target-plan.js";
|
|
39
|
-
import { refreshSenderEngagementToolDefinitions } from "./refresh-sender-engagement.js";
|
|
40
43
|
import { rowToolDefinitions } from "./rows.js";
|
|
41
44
|
import { rubricToolDefinitions } from "./rubrics.js";
|
|
42
45
|
import { schedulerFillCapacityToolDefinitions } from "./scheduler-fill-capacity.js";
|
|
@@ -60,6 +63,7 @@ export const allTools = [
|
|
|
60
63
|
...schedulerFillCapacityToolDefinitions,
|
|
61
64
|
...schedulerRunToolDefinitions,
|
|
62
65
|
...refillSendsToolDefinitions,
|
|
66
|
+
...refillSendsV2ToolDefinitions,
|
|
63
67
|
...setupEvergreenCampaignsToolDefinitions,
|
|
64
68
|
...campaignHorizonFillToolDefinitions,
|
|
65
69
|
...campaignMessagePreparationToolDefinitions,
|
|
@@ -72,6 +76,8 @@ export const allTools = [
|
|
|
72
76
|
...engageDiscoveryToolDefinitions,
|
|
73
77
|
...workspaceToolDefinitions,
|
|
74
78
|
...frameworkToolDefinitions,
|
|
79
|
+
...findLeadsRunToolDefinitions,
|
|
80
|
+
...findLeadsProviderPreflightToolDefinitions,
|
|
75
81
|
...contextToolDefinitions,
|
|
76
82
|
...contentPostToolDefinitions,
|
|
77
83
|
...navigationToolDefinitions,
|
|
@@ -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,
|
|
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: {
|
|
@@ -1,23 +1,8 @@
|
|
|
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
|
-
};
|
|
12
2
|
type RunSchedulerSweepInput = {
|
|
13
3
|
workspaceId: string;
|
|
14
4
|
action?: SchedulerRunAction;
|
|
15
5
|
targetDate?: string;
|
|
16
|
-
requestKey?: string;
|
|
17
|
-
targetShapeRevision?: string;
|
|
18
|
-
expectedTargets?: SchedulerExpectedTargetInput[];
|
|
19
|
-
expectedTargetsHash?: string;
|
|
20
|
-
maxPlacements?: number;
|
|
21
6
|
};
|
|
22
7
|
export declare const schedulerRunToolDefinitions: {
|
|
23
8
|
name: string;
|
|
@@ -38,62 +23,6 @@ export declare const schedulerRunToolDefinitions: {
|
|
|
38
23
|
type: string;
|
|
39
24
|
description: string;
|
|
40
25
|
};
|
|
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
|
-
};
|
|
97
26
|
};
|
|
98
27
|
required: string[];
|
|
99
28
|
additionalProperties: boolean;
|
|
@@ -1,9 +1,5 @@
|
|
|
1
|
-
import { createHash } from "crypto";
|
|
2
1
|
import { getApi } from "../api.js";
|
|
3
2
|
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;
|
|
7
3
|
async function postSchedulerRun(body, workspaceId) {
|
|
8
4
|
const api = getApi();
|
|
9
5
|
const requestOptions = workspaceRequestOptions(workspaceId);
|
|
@@ -25,97 +21,10 @@ function normalizeTargetDate(value) {
|
|
|
25
21
|
}
|
|
26
22
|
return targetDate;
|
|
27
23
|
}
|
|
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
|
-
}
|
|
115
24
|
export const schedulerRunToolDefinitions = [
|
|
116
25
|
{
|
|
117
26
|
name: "run_scheduler_sweep",
|
|
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
|
|
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 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.',
|
|
119
28
|
inputSchema: {
|
|
120
29
|
type: "object",
|
|
121
30
|
properties: {
|
|
@@ -132,64 +41,6 @@ export const schedulerRunToolDefinitions = [
|
|
|
132
41
|
type: "string",
|
|
133
42
|
description: "Optional one exact sender-local date (YYYY-MM-DD) to scope scheduler placement/status. The run remains workspace-wide inside that date.",
|
|
134
43
|
},
|
|
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
|
-
},
|
|
193
44
|
},
|
|
194
45
|
required: ["workspaceId"],
|
|
195
46
|
additionalProperties: false,
|
|
@@ -203,65 +54,12 @@ export async function runSchedulerSweep(input) {
|
|
|
203
54
|
}
|
|
204
55
|
const action = input.action ?? "run";
|
|
205
56
|
const targetDate = normalizeTargetDate(input.targetDate);
|
|
206
|
-
const requestKey = normalizeOptionalScopeValue(input.requestKey, "requestKey");
|
|
207
|
-
const targetShapeRevision = normalizeOptionalScopeValue(input.targetShapeRevision, "targetShapeRevision");
|
|
208
57
|
if (action !== "run" && action !== "status") {
|
|
209
58
|
throw new Error('action must be "run" or "status" for run_scheduler_sweep.');
|
|
210
59
|
}
|
|
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
|
-
}
|
|
258
60
|
return postSchedulerRun({
|
|
259
61
|
workspaceId,
|
|
260
62
|
action,
|
|
261
63
|
...(targetDate ? { targetDate } : {}),
|
|
262
|
-
...(requestKey ? { requestKey } : {}),
|
|
263
|
-
...(targetShapeRevision ? { targetShapeRevision } : {}),
|
|
264
|
-
...(expectedTargetRequest ?? {}),
|
|
265
|
-
...(expectedStatusScope ?? {}),
|
|
266
64
|
}, workspaceId);
|
|
267
65
|
}
|
|
@@ -6,7 +6,7 @@ async function postSetupEvergreenCampaigns(body, workspaceId) {
|
|
|
6
6
|
export const setupEvergreenCampaignsToolDefinitions = [
|
|
7
7
|
{
|
|
8
8
|
name: "setup_evergreen_campaigns",
|
|
9
|
-
description: "Evergreen campaign setup plan/verify command. Use plan mode first to inspect exact workspace/sender/campaign/table/source state and receive immutable lane packets. `selectedSenderIds` is a legacy shorthand for both scopes; prefer `postEngagerSenderIds` for the Post Engagers sender scope and `sharedSenderIds` for the shared lane sender scope when they differ. `sharedSenderIds` must include every intended shared-lane sender, not only the named Post Engagers sender; when adding other senders to existing shared evergreen campaigns, resolve those sender ids with list_senders and pass the full shared set. If a protected existing Post Engagers campaign must stay unchanged and the operator requested only shared lane execution, pass postEngagerSenderIds:[] and sharedSenderIds; do not include the protected active Post Engagers lane as a reuse packet because it can make the yolo plan non-autoExecutable. The command plans one Post Engagers lane per post-engager sender plus shared Signal Discovery and Shared Cold Fallback lanes for the shared sender set. Non-archived PAUSED/ACTIVE/DRAFT shared campaigns/tables are the reusable targets; archived campaigns, archived tables, and archived waterfall bindings are stale inventory and must not be counted as valid evergreen slots. If an existing non-archived shared campaign is already attached to additional senders, plan reporting should count those attached senders as existing shared-lane membership rather than treating them as missing or duplicate slots. yolo is only a parent-skill auto-execution hint for safe lane packets; pass yolo only in plan mode and never include yolo on mode:\"verify\" calls. This backend command remains read-only in plan mode and verifies receipts in verify mode. Package-backed prompt authority: the installed public wrapper can be the local Codex skill entrypoint, but lane workers must use get_subskill_prompt and get_subskill_asset for nested `$sellable:create-campaign`, create-campaign-v2, generate-messages, validation, and assets; nested filesystem prompt fallback is a failed UAT. Use mcp__sellable only for workspace selection and product mutations/readbacks. Do not use mcp__sellable_admin, direct DB, Prisma, SQL, built-in web search, browser search, web.run, or any external browsing/search tool as execution or research proof; if Sellable MCP research tools are insufficient, write a blocked receipt instead of browsing externally. Worker-local replans are read-only drift checks and must preserve the exact parent sender scopes, including postEngagerSenderIds:[] when intentionally empty and the exact sharedSenderIds array; if scope, planRevision, actionId, or laneKey drifts, stop with blocked:worker_plan_scope_drift before mutation. Each lane packet includes workerDispatch with preferredRuntime, runtimeFallbackOrder, acceptedRuntimes, rejectedRuntimes, requiresVisibleThreadOrDurableReceipt, receiptArtifactHint, receiptRunId, and receiptMustBeWrittenAfter; pre-existing receipts at old deterministic paths are stale and must not be used, so stop with blocked:stale_receipt_artifact if the receipt was not freshly written for the current receiptRunId. `multi_agent_v1.spawn_agent`/opaque spawn_agent is not accepted for mutating command proof unless the parent has visible thread or durable receipt proof. In local Codex, default to `workerDispatch.preferredRuntime` (`visible-codex-app-thread`): discover Codex app thread tools if needed, then call `codex_app.list_projects` and `codex_app.create_thread` with a local project target; do not create a worktree for lane execution. If Codex app thread tools are unavailable but local Codex CLI is available, use durable streaming workers with `codex -a never -s danger-full-access -c model_reasoning_effort=
|
|
9
|
+
description: "Evergreen campaign setup plan/verify command. Use plan mode first to inspect exact workspace/sender/campaign/table/source state and receive immutable lane packets. `selectedSenderIds` is a legacy shorthand for both scopes; prefer `postEngagerSenderIds` for the Post Engagers sender scope and `sharedSenderIds` for the shared lane sender scope when they differ. `sharedSenderIds` must include every intended shared-lane sender, not only the named Post Engagers sender; when adding other senders to existing shared evergreen campaigns, resolve those sender ids with list_senders and pass the full shared set. If a protected existing Post Engagers campaign must stay unchanged and the operator requested only shared lane execution, pass postEngagerSenderIds:[] and sharedSenderIds; do not include the protected active Post Engagers lane as a reuse packet because it can make the yolo plan non-autoExecutable. The command plans one Post Engagers lane per post-engager sender plus shared Signal Discovery and Shared Cold Fallback lanes for the shared sender set. Non-archived PAUSED/ACTIVE/DRAFT shared campaigns/tables are the reusable targets; archived campaigns, archived tables, and archived waterfall bindings are stale inventory and must not be counted as valid evergreen slots. If an existing non-archived shared campaign is already attached to additional senders, plan reporting should count those attached senders as existing shared-lane membership rather than treating them as missing or duplicate slots. yolo is only a parent-skill auto-execution hint for safe lane packets; pass yolo only in plan mode and never include yolo on mode:\"verify\" calls. This backend command remains read-only in plan mode and verifies receipts in verify mode. Package-backed prompt authority: the installed public wrapper can be the local Codex skill entrypoint, but lane workers must use get_subskill_prompt and get_subskill_asset for nested `$sellable:create-campaign`, create-campaign-v2, generate-messages, validation, and assets; nested filesystem prompt fallback is a failed UAT. Use mcp__sellable only for workspace selection and product mutations/readbacks. Do not use mcp__sellable_admin, direct DB, Prisma, SQL, built-in web search, browser search, web.run, or any external browsing/search tool as execution or research proof; if Sellable MCP research tools are insufficient, write a blocked receipt instead of browsing externally. Worker-local replans are read-only drift checks and must preserve the exact parent sender scopes, including postEngagerSenderIds:[] when intentionally empty and the exact sharedSenderIds array; if scope, planRevision, actionId, or laneKey drifts, stop with blocked:worker_plan_scope_drift before mutation. Each lane packet includes workerDispatch with preferredRuntime, runtimeFallbackOrder, acceptedRuntimes, rejectedRuntimes, requiresVisibleThreadOrDurableReceipt, receiptArtifactHint, receiptRunId, and receiptMustBeWrittenAfter; pre-existing receipts at old deterministic paths are stale and must not be used, so stop with blocked:stale_receipt_artifact if the receipt was not freshly written for the current receiptRunId. `multi_agent_v1.spawn_agent`/opaque spawn_agent is not accepted for mutating command proof unless the parent has visible thread or durable receipt proof. In local Codex, default to `workerDispatch.preferredRuntime` (`visible-codex-app-thread`): discover Codex app thread tools if needed, then call `codex_app.list_projects` and `codex_app.create_thread` with a local project target; do not create a worktree for lane execution. If Codex app thread tools are unavailable but local Codex CLI is available, use durable streaming workers with `codex -a never -s danger-full-access -c model_reasoning_effort=xhigh exec --skip-git-repo-check -m <worker-model> -C <repo> -o <worker-final-file> -` and include preferredRuntimeAttempt plus fallbackReason in createCampaignWorkflowReceipt; approval, sandbox, and reasoning-effort config flags must appear before `exec`, and current customer CLI installs reject `codex exec --ask-for-approval never` and `codex exec -a never`. Do not rely on default model or default reasoning effort: copy the parent model such as `gpt-5.5` into `-m` and always pass `-c model_reasoning_effort=xhigh`; a child worker that reports GPT 5.5 with high reasoning is a launcher bug to relaunch before mutation, not a user-continue path. Plan responses include approvalSummary; render approvalSummary when asking for bounded delegated approval because it explicitly lists campaignsToCreate, campaignsToUpdate, campaignsToVerifyOnly, campaignsLeftUntouched, attachedSenders, selectedActionIds, allowedSideEffects, forbiddenSideEffects, blockers, and approvalQuestion. When safe-yolo needs normal setup work, the parent skill may ask for bounded delegated approval: one approval over the current planRevision, selected action ids, caps, allowed side-effect classes, and stop conditions lets lane workers execute without per-substep approval while staying inside that packet. In exec/automation mode, do not call request_user_input; if yolo plan autoExecutable:false and no interactive approval can be received, stop with blocked:bounded_approval_unavailable_in_exec_mode before any mutation. Lane workers must explicitly load and use the installed `$sellable:create-campaign` wrapper as the nested workflow entrypoint, then load `create-campaign-v2` and `create-campaign-v2/core/flow.v2.json`; they must execute creation, source import, create-campaign workflow steps, generate-messages, sequence attachment, pause_campaign review-state transition when the current table is still DRAFT, and review readiness through that existing create-campaign workflow/subskills, then return receipts here for verification. Customer-visible verify receipts must set status:'succeeded' or status:'completed'; status:'passed', status:'pass', and status:'passed_with_warnings' are rejected as primary success statuses. Exception: a Post Engagers lane may write status:'blocked' with blocker:'post_engagers_no_sender_posts', 'post_engagers_no_recent_sender_posts', 'post_engagers_no_sender_owned_posts', or 'post_engagers_source_author_mismatch' when Sellable MCP readback proves no usable sender-authored posts/source exists; verify returns these as acceptedLaneBlockers so the parent can report the no-op instead of retrying invalid source repair. Any other blocked receipt, including model-quality/preflight or worker model availability blockers, is not a goal-complete success condition and must not let the parent report evergreen completion. Receipts must include createCampaignStepReceipt with setupPlanCall, createCampaignWorkflowReceipt, campaignBriefReceipt, sourceDecisionReceipt, filterDecisionReceipt, messageDraftingReceipt, reviewBatchReceipt, sequenceReceipt, and verifyCall nested inside createCampaignStepReceipt; top-level-only copies of those objects are not enough and are not promoted by verify. setupPlanCall must use canonical keys: planRevision, actionId, laneKey, workspaceId, senderIds, campaignId, tableId, createIntent. Do not use laneActionId, lanePacketActionId, delegatedPlanRevision, delegatedActionId, or requestedCall text as a substitute for those canonical fields. createCampaignWorkflowReceipt must include skillCommand:'$sellable:create-campaign', skillName:'create-campaign', wrapperSkillLoaded:true, workflowPromptName:'create-campaign-v2', workflowPromptLoadedToHasMoreFalse:true, workflowAssetPath:'create-campaign-v2/core/flow.v2.json', workflowAssetLoaded:true, workerRuntime, workerThreadId or receiptArtifactPath, durableReceiptWritten when using a receipt file, and notAdHoc:true; CLI durable fallback runtimes must also include preferredRuntimeAttempt for visible-codex-app-thread and fallbackReason. messageDraftingReceipt must use exactly statusSource:'branch' or statusSource:'packaged-generate-messages-worker'; descriptive aliases such as statusSource:'package-readback-local-thread' are rejected. It must include proof that generate-messages was loaded, start_campaign_message_preparation/get_campaign_message_preparation_status ran when the packaged worker path is used, validationResult:'passed', a passed qualityReview, and at least 3 concrete sampleMessages with rowId, generatedMessageText, verdict, and issues; Do not substitute `message` for `generatedMessageText`; Do not substitute `passVerdict` for `verdict`. Before writing durable receipts, run a receipt self-check: top-level `planRevision`, `actionId`, `laneKey`, `laneType`, `workspaceId`, and `senderIds` must exist; if the self-check fails, fix the receipt before ending. Use start_campaign_message_preparation with approvalMode:\"mark_ready\" only for evergreen setup. Never call `start_campaign_message_preparation` with `approvalMode:\"approve\"`; approve exactly one semantic Approved cell through select_campaign_cells/update_cell and final proof must show approvedGeneratedMessageCount exactly 1. Shared Cold Fallback samples with a standalone name followed by 'Hey there' are rejected. This command does not launch campaigns, does not schedule sends, does not assign scheduler-owned send fields, does not raw-write campaign status, does not archive/delete cleanup targets, and does not spend paid credits.",
|
|
10
10
|
inputSchema: {
|
|
11
11
|
type: "object",
|
|
12
12
|
properties: {
|
|
@@ -12,7 +12,7 @@ export interface WorkspaceContext {
|
|
|
12
12
|
executionMode: WorkspaceExecutionMode;
|
|
13
13
|
toolName?: string;
|
|
14
14
|
runId: string;
|
|
15
|
-
workspaceResolution: "explicit"
|
|
15
|
+
workspaceResolution: "explicit";
|
|
16
16
|
}
|
|
17
17
|
export interface WorkspaceRequiredResult {
|
|
18
18
|
ok: false;
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
|
-
import { getLockedWorkspaceId, resolveWorkspaceIdForRequest, } from "../auth.js";
|
|
3
2
|
export function workspaceRequired(params) {
|
|
4
3
|
const toolLabel = params.toolName ? ` for ${params.toolName}` : "";
|
|
5
4
|
return {
|
|
@@ -16,13 +15,11 @@ export function normalizeExplicitWorkspaceId(value) {
|
|
|
16
15
|
return typeof value === "string" && value.trim() ? value.trim() : null;
|
|
17
16
|
}
|
|
18
17
|
export function workspaceRequestOptions(workspaceId) {
|
|
19
|
-
const normalized =
|
|
18
|
+
const normalized = normalizeExplicitWorkspaceId(workspaceId);
|
|
20
19
|
return normalized ? Object.freeze({ workspaceId: normalized }) : undefined;
|
|
21
20
|
}
|
|
22
21
|
export function createWorkspaceContext(input) {
|
|
23
|
-
const
|
|
24
|
-
const lockedWorkspaceId = getLockedWorkspaceId();
|
|
25
|
-
const workspaceId = resolveWorkspaceIdForRequest(explicitWorkspaceId, input.toolName || "workspace context");
|
|
22
|
+
const workspaceId = normalizeExplicitWorkspaceId(input.workspaceId);
|
|
26
23
|
if (!workspaceId) {
|
|
27
24
|
return workspaceRequired({
|
|
28
25
|
executionMode: input.executionMode,
|
|
@@ -36,9 +33,7 @@ export function createWorkspaceContext(input) {
|
|
|
36
33
|
executionMode: input.executionMode,
|
|
37
34
|
toolName: input.toolName,
|
|
38
35
|
runId: input.runId?.trim() || randomUUID(),
|
|
39
|
-
workspaceResolution:
|
|
40
|
-
? "locked_profile"
|
|
41
|
-
: "explicit",
|
|
36
|
+
workspaceResolution: "explicit",
|
|
42
37
|
});
|
|
43
38
|
return { ok: true, context };
|
|
44
39
|
}
|
|
@@ -4,7 +4,7 @@ import { lstat, mkdir, readFile, rename, rm, writeFile, } from "node:fs/promises
|
|
|
4
4
|
import { tmpdir } from "node:os";
|
|
5
5
|
import path from "node:path";
|
|
6
6
|
import { getApi } from "../api.js";
|
|
7
|
-
import { getConfig
|
|
7
|
+
import { getConfig } from "../auth.js";
|
|
8
8
|
const MAX_FILTER_IDS = 100;
|
|
9
9
|
const MAX_QUERY_LENGTH = 8000;
|
|
10
10
|
export const workspaceExportToolDefinitions = [
|
|
@@ -340,7 +340,7 @@ async function writeJsonAtomic(filePath, value) {
|
|
|
340
340
|
}
|
|
341
341
|
export async function exportWorkspaceCsv(input = {}) {
|
|
342
342
|
const config = getConfig();
|
|
343
|
-
const workspaceId =
|
|
343
|
+
const workspaceId = config.activeWorkspaceId || config.workspaceId || null;
|
|
344
344
|
if (!workspaceId) {
|
|
345
345
|
throw new Error("No active workspace selected. Run list_workspaces then set_active_workspace before export_workspace_csv.");
|
|
346
346
|
}
|
|
@@ -140,56 +140,21 @@ export declare const workspaceToolDefinitions: ({
|
|
|
140
140
|
})[];
|
|
141
141
|
export declare function listWorkspaces(): Promise<{
|
|
142
142
|
workspaces: WorkspaceSummary[];
|
|
143
|
-
workspaceLock: {
|
|
144
|
-
enabled: boolean;
|
|
145
|
-
workspaceId?: undefined;
|
|
146
|
-
hiddenWorkspaceCount?: undefined;
|
|
147
|
-
};
|
|
148
|
-
} | {
|
|
149
|
-
workspaces: WorkspaceSummary[];
|
|
150
|
-
workspaceLock: {
|
|
151
|
-
enabled: boolean;
|
|
152
|
-
workspaceId: string;
|
|
153
|
-
hiddenWorkspaceCount: number;
|
|
154
|
-
};
|
|
155
143
|
}>;
|
|
156
144
|
export declare function getActiveWorkspace(): {
|
|
157
145
|
activeWorkspaceId: string | null;
|
|
158
146
|
activeWorkspaceName: string | null;
|
|
159
|
-
workspaceLock: {
|
|
160
|
-
enabled: boolean;
|
|
161
|
-
workspaceId: string;
|
|
162
|
-
} | {
|
|
163
|
-
enabled: boolean;
|
|
164
|
-
workspaceId?: undefined;
|
|
165
|
-
};
|
|
166
147
|
};
|
|
167
148
|
export declare function getWorkspace(workspaceId: string): Promise<{
|
|
168
|
-
ok: boolean;
|
|
169
|
-
error: string;
|
|
170
|
-
workspace?: undefined;
|
|
171
|
-
} | {
|
|
172
149
|
workspace: WorkspaceDetails;
|
|
173
|
-
ok?: undefined;
|
|
174
|
-
error?: undefined;
|
|
175
150
|
}>;
|
|
176
151
|
export declare function setActiveWorkspace(workspaceId: string, userConfirmed?: boolean): Promise<{
|
|
177
152
|
ok: boolean;
|
|
178
|
-
code: string;
|
|
179
|
-
activeWorkspaceId: string;
|
|
180
|
-
requestedWorkspaceId: string;
|
|
181
153
|
error: string;
|
|
182
154
|
requiresConfirmation?: undefined;
|
|
183
|
-
activeWorkspaceName?: undefined;
|
|
184
|
-
requestedWorkspaceName?: undefined;
|
|
185
|
-
} | {
|
|
186
|
-
ok: boolean;
|
|
187
|
-
error: string;
|
|
188
|
-
code?: undefined;
|
|
189
155
|
activeWorkspaceId?: undefined;
|
|
190
|
-
requestedWorkspaceId?: undefined;
|
|
191
|
-
requiresConfirmation?: undefined;
|
|
192
156
|
activeWorkspaceName?: undefined;
|
|
157
|
+
requestedWorkspaceId?: undefined;
|
|
193
158
|
requestedWorkspaceName?: undefined;
|
|
194
159
|
} | {
|
|
195
160
|
ok: boolean;
|
|
@@ -199,33 +164,22 @@ export declare function setActiveWorkspace(workspaceId: string, userConfirmed?:
|
|
|
199
164
|
requestedWorkspaceId: string;
|
|
200
165
|
requestedWorkspaceName: string;
|
|
201
166
|
error: string;
|
|
202
|
-
code?: undefined;
|
|
203
167
|
} | {
|
|
204
168
|
ok: boolean;
|
|
205
169
|
activeWorkspaceId: string;
|
|
206
170
|
activeWorkspaceName: string;
|
|
207
|
-
code?: undefined;
|
|
208
|
-
requestedWorkspaceId?: undefined;
|
|
209
171
|
error?: undefined;
|
|
210
172
|
requiresConfirmation?: undefined;
|
|
173
|
+
requestedWorkspaceId?: undefined;
|
|
211
174
|
requestedWorkspaceName?: undefined;
|
|
212
175
|
}>;
|
|
213
176
|
export declare function createWorkspace(name: string): Promise<{
|
|
214
|
-
ok: boolean;
|
|
215
|
-
code: string;
|
|
216
|
-
activeWorkspaceId: string;
|
|
217
|
-
error: string;
|
|
218
|
-
workspace?: undefined;
|
|
219
|
-
} | {
|
|
220
177
|
workspace: {
|
|
221
178
|
id: string;
|
|
222
179
|
name: string;
|
|
223
180
|
slug: string;
|
|
224
181
|
};
|
|
225
182
|
activeWorkspaceId: string;
|
|
226
|
-
ok?: undefined;
|
|
227
|
-
code?: undefined;
|
|
228
|
-
error?: undefined;
|
|
229
183
|
}>;
|
|
230
184
|
export declare function addTeammate(input: {
|
|
231
185
|
workspaceId?: string;
|