@sellable/mcp 0.1.188 → 0.1.190
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/agents/post-find-leads-message-scout.md +8 -7
- package/agents/registry.json +2 -2
- package/dist/index-dev.js +0 -0
- package/dist/index.js +0 -0
- package/dist/server.js +22 -0
- package/dist/tools/campaign-processing.d.ts +383 -0
- package/dist/tools/campaign-processing.js +304 -0
- package/dist/tools/leads.d.ts +63 -19
- package/dist/tools/leads.js +59 -8
- package/dist/tools/prompts.js +2 -2
- package/dist/tools/registry.d.ts +289 -37
- package/dist/tools/registry.js +2 -0
- package/package.json +1 -1
- package/skills/create-campaign/SKILL.md +17 -12
- package/skills/create-campaign-v2/SKILL.md +23 -25
- package/skills/create-campaign-v2/SOUL.md +11 -4
- package/skills/create-campaign-v2/core/flow.v2.json +1 -1
- package/skills/create-campaign-v2/core/policy.md +3 -3
- package/skills/create-campaign-v2/references/approval-gate-framing.md +5 -5
- package/skills/create-campaign-v2/references/filter-leads.md +5 -3
- package/skills/create-campaign-v2/references/parallel-critique-protocol.md +2 -2
- package/skills/create-campaign-v2/references/sample-validation-loop.md +46 -66
- package/skills/create-campaign-v2/references/step-15-re-cascade.md +20 -13
- package/skills/create-campaign-v2-tail/SKILL.md +52 -65
- package/skills/find-leads/SKILL.md +2 -1
- package/skills/generate-messages/SKILL.md +11 -0
- package/skills/generate-messages-compact/SKILL.md +100 -0
- package/skills/generate-messages-compact/references/examples-critique-revision.md +37 -0
- package/skills/providers/signal-discovery.md +9 -3
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
import { getApi } from "../api.js";
|
|
2
|
+
import { resolveWaitTimeout } from "./readiness.js";
|
|
3
|
+
const DEFAULT_TIMEOUT_MS = 90000;
|
|
4
|
+
const DEFAULT_INTERVAL_MS = 2000;
|
|
5
|
+
function sleep(ms) {
|
|
6
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
7
|
+
}
|
|
8
|
+
function stableHash(value) {
|
|
9
|
+
const text = JSON.stringify(value, Object.keys(value).sort());
|
|
10
|
+
let hash = 2166136261;
|
|
11
|
+
for (let index = 0; index < text.length; index += 1) {
|
|
12
|
+
hash ^= text.charCodeAt(index);
|
|
13
|
+
hash = Math.imul(hash, 16777619);
|
|
14
|
+
}
|
|
15
|
+
return (hash >>> 0).toString(16).padStart(8, "0");
|
|
16
|
+
}
|
|
17
|
+
async function postCampaignProcessing(body) {
|
|
18
|
+
const api = getApi();
|
|
19
|
+
return api.post("/api/v3/mcp/campaign-processing", body);
|
|
20
|
+
}
|
|
21
|
+
async function resolveSchema(input) {
|
|
22
|
+
return postCampaignProcessing({
|
|
23
|
+
action: "schema",
|
|
24
|
+
campaignId: input.campaignId,
|
|
25
|
+
tableId: input.tableId,
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
export const campaignProcessingToolDefinitions = [
|
|
29
|
+
{
|
|
30
|
+
name: "get_campaign_table_schema",
|
|
31
|
+
description: "Return compact semantic campaign-table schema: column roles, row count, review-batch metadata, and current approved brief hash. Use for debugging or recovery, not normal queueing.",
|
|
32
|
+
inputSchema: {
|
|
33
|
+
type: "object",
|
|
34
|
+
properties: {
|
|
35
|
+
campaignId: { type: "string" },
|
|
36
|
+
tableId: { type: "string" },
|
|
37
|
+
},
|
|
38
|
+
additionalProperties: false,
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
name: "select_campaign_cells",
|
|
43
|
+
description: "Dry-run semantic campaign-cell selection. Returns compact counts and a tiny sample, never bulky row data. Use before queue_campaign_cells only when debugging or explaining a recovery action.",
|
|
44
|
+
inputSchema: {
|
|
45
|
+
type: "object",
|
|
46
|
+
properties: {
|
|
47
|
+
campaignId: { type: "string" },
|
|
48
|
+
tableId: { type: "string" },
|
|
49
|
+
columnRole: {
|
|
50
|
+
type: "string",
|
|
51
|
+
enum: [
|
|
52
|
+
"enrich",
|
|
53
|
+
"passesRubric",
|
|
54
|
+
"icpScore",
|
|
55
|
+
"generateMessage",
|
|
56
|
+
"approved",
|
|
57
|
+
],
|
|
58
|
+
},
|
|
59
|
+
rowSelector: {
|
|
60
|
+
type: "object",
|
|
61
|
+
properties: {
|
|
62
|
+
type: {
|
|
63
|
+
type: "string",
|
|
64
|
+
enum: [
|
|
65
|
+
"reviewBatch",
|
|
66
|
+
"rowIds",
|
|
67
|
+
"passedRows",
|
|
68
|
+
"needsGeneratedMessage",
|
|
69
|
+
"staleGeneratedMessages",
|
|
70
|
+
],
|
|
71
|
+
},
|
|
72
|
+
basisHash: { type: "string" },
|
|
73
|
+
rowIds: { type: "array", items: { type: "string" } },
|
|
74
|
+
limit: { type: "number" },
|
|
75
|
+
},
|
|
76
|
+
required: ["type"],
|
|
77
|
+
additionalProperties: false,
|
|
78
|
+
},
|
|
79
|
+
limit: { type: "number" },
|
|
80
|
+
},
|
|
81
|
+
required: ["columnRole", "rowSelector"],
|
|
82
|
+
additionalProperties: false,
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
name: "queue_campaign_cells",
|
|
87
|
+
description: "Resolve and queue campaign cells by semantic role and row selector. Normal create-campaign tail should use this instead of fetching rows only to discover cell IDs. Use forceRerun:true for message-template revisions.",
|
|
88
|
+
inputSchema: {
|
|
89
|
+
type: "object",
|
|
90
|
+
properties: {
|
|
91
|
+
campaignId: { type: "string" },
|
|
92
|
+
tableId: { type: "string" },
|
|
93
|
+
columnRole: {
|
|
94
|
+
type: "string",
|
|
95
|
+
enum: ["enrich", "generateMessage", "approved"],
|
|
96
|
+
},
|
|
97
|
+
rowSelector: {
|
|
98
|
+
type: "object",
|
|
99
|
+
properties: {
|
|
100
|
+
type: {
|
|
101
|
+
type: "string",
|
|
102
|
+
enum: [
|
|
103
|
+
"reviewBatch",
|
|
104
|
+
"rowIds",
|
|
105
|
+
"passedRows",
|
|
106
|
+
"needsGeneratedMessage",
|
|
107
|
+
"staleGeneratedMessages",
|
|
108
|
+
],
|
|
109
|
+
},
|
|
110
|
+
basisHash: { type: "string" },
|
|
111
|
+
rowIds: { type: "array", items: { type: "string" } },
|
|
112
|
+
limit: { type: "number" },
|
|
113
|
+
},
|
|
114
|
+
required: ["type"],
|
|
115
|
+
additionalProperties: false,
|
|
116
|
+
},
|
|
117
|
+
forceRerun: { type: "boolean" },
|
|
118
|
+
limit: { type: "number" },
|
|
119
|
+
reason: { type: "string" },
|
|
120
|
+
},
|
|
121
|
+
required: ["columnRole", "rowSelector"],
|
|
122
|
+
additionalProperties: false,
|
|
123
|
+
},
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
name: "wait_for_campaign_processing",
|
|
127
|
+
description: "Stats-only campaign processing wait. Use for fit/message readiness instead of wait_for_rubric_results when waiting on campaign-table processing. Generated messages are counted separately from rubric passes; current template revision is enforced through messageDraftBasis.approvedBriefHash.",
|
|
128
|
+
inputSchema: {
|
|
129
|
+
type: "object",
|
|
130
|
+
properties: {
|
|
131
|
+
campaignId: { type: "string" },
|
|
132
|
+
tableId: { type: "string" },
|
|
133
|
+
minPassedCount: { type: "number" },
|
|
134
|
+
minGeneratedMessages: { type: "number" },
|
|
135
|
+
templateRevision: {
|
|
136
|
+
type: "string",
|
|
137
|
+
description: '"current" (default when minGeneratedMessages is set) or an explicit current approved brief hash.',
|
|
138
|
+
},
|
|
139
|
+
timeoutMs: { type: "number" },
|
|
140
|
+
intervalMs: { type: "number" },
|
|
141
|
+
},
|
|
142
|
+
additionalProperties: false,
|
|
143
|
+
},
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
name: "revise_message_template_and_rerun",
|
|
147
|
+
description: "Update the approved message template in the campaign brief, mark prior generated messages stale, reset unsent approvals, and force-rerun Generate Message cells. Does not directly overwrite row message cells.",
|
|
148
|
+
inputSchema: {
|
|
149
|
+
type: "object",
|
|
150
|
+
properties: {
|
|
151
|
+
campaignId: { type: "string" },
|
|
152
|
+
tableId: { type: "string" },
|
|
153
|
+
templateMarkdown: { type: "string" },
|
|
154
|
+
approvedMessageTemplate: { type: "string" },
|
|
155
|
+
rowSelector: {
|
|
156
|
+
type: "object",
|
|
157
|
+
properties: {
|
|
158
|
+
type: {
|
|
159
|
+
type: "string",
|
|
160
|
+
enum: [
|
|
161
|
+
"passedRows",
|
|
162
|
+
"needsGeneratedMessage",
|
|
163
|
+
"staleGeneratedMessages",
|
|
164
|
+
"rowIds",
|
|
165
|
+
],
|
|
166
|
+
},
|
|
167
|
+
rowIds: { type: "array", items: { type: "string" } },
|
|
168
|
+
limit: { type: "number" },
|
|
169
|
+
},
|
|
170
|
+
required: ["type"],
|
|
171
|
+
additionalProperties: false,
|
|
172
|
+
},
|
|
173
|
+
limit: { type: "number" },
|
|
174
|
+
},
|
|
175
|
+
required: ["campaignId"],
|
|
176
|
+
additionalProperties: false,
|
|
177
|
+
},
|
|
178
|
+
},
|
|
179
|
+
];
|
|
180
|
+
export async function getCampaignTableSchema(input) {
|
|
181
|
+
return resolveSchema(input);
|
|
182
|
+
}
|
|
183
|
+
export async function selectCampaignCells(input) {
|
|
184
|
+
return postCampaignProcessing({
|
|
185
|
+
action: "select",
|
|
186
|
+
...input,
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
export async function queueCampaignCells(input) {
|
|
190
|
+
return postCampaignProcessing({
|
|
191
|
+
action: "queue",
|
|
192
|
+
...input,
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
export async function reviseMessageTemplateAndRerun(input) {
|
|
196
|
+
return postCampaignProcessing({
|
|
197
|
+
action: "reviseTemplateAndRerun",
|
|
198
|
+
...input,
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
export async function waitForCampaignProcessing(input) {
|
|
202
|
+
const api = getApi();
|
|
203
|
+
const schema = await resolveSchema(input);
|
|
204
|
+
const { effectiveTimeoutMs, guardApplied, requestedTimeoutMs } = resolveWaitTimeout(input.timeoutMs ?? DEFAULT_TIMEOUT_MS);
|
|
205
|
+
const intervalMs = Math.max(500, input.intervalMs ?? DEFAULT_INTERVAL_MS);
|
|
206
|
+
const minPassedCount = typeof input.minPassedCount === "number" &&
|
|
207
|
+
Number.isFinite(input.minPassedCount)
|
|
208
|
+
? Math.max(1, Math.floor(input.minPassedCount))
|
|
209
|
+
: null;
|
|
210
|
+
const minGeneratedMessages = typeof input.minGeneratedMessages === "number" &&
|
|
211
|
+
Number.isFinite(input.minGeneratedMessages)
|
|
212
|
+
? Math.max(1, Math.floor(input.minGeneratedMessages))
|
|
213
|
+
: null;
|
|
214
|
+
const templateRevision = input.templateRevision ?? (minGeneratedMessages !== null ? "current" : null);
|
|
215
|
+
const pollKey = stableHash({
|
|
216
|
+
tableId: schema.tableId,
|
|
217
|
+
minPassedCount,
|
|
218
|
+
minGeneratedMessages,
|
|
219
|
+
templateRevision,
|
|
220
|
+
});
|
|
221
|
+
const start = Date.now();
|
|
222
|
+
let attempts = 0;
|
|
223
|
+
let lastStats = null;
|
|
224
|
+
while (Date.now() - start <= effectiveTimeoutMs) {
|
|
225
|
+
attempts += 1;
|
|
226
|
+
const stats = await api.get(`/api/v3/workflow-tables/${schema.tableId}/stats`);
|
|
227
|
+
lastStats = stats;
|
|
228
|
+
const currentRevisionHash = stats.currentTemplateRevisionHash ?? null;
|
|
229
|
+
if (templateRevision &&
|
|
230
|
+
templateRevision !== "current" &&
|
|
231
|
+
currentRevisionHash &&
|
|
232
|
+
templateRevision !== currentRevisionHash) {
|
|
233
|
+
return {
|
|
234
|
+
ready: false,
|
|
235
|
+
reason: "template_revision_mismatch",
|
|
236
|
+
attempts,
|
|
237
|
+
elapsedMs: Date.now() - start,
|
|
238
|
+
tableId: schema.tableId,
|
|
239
|
+
pollKey,
|
|
240
|
+
requestedTemplateRevision: templateRevision,
|
|
241
|
+
currentTemplateRevisionHash: currentRevisionHash,
|
|
242
|
+
guidance: "The requested templateRevision is not current. Re-read campaign state or wait using templateRevision:'current'.",
|
|
243
|
+
stats,
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
const passed = stats.passRate?.passed ?? 0;
|
|
247
|
+
const generated = templateRevision === "current" || templateRevision !== null
|
|
248
|
+
? (stats.currentRevisionGeneratedMessagesCount ?? 0)
|
|
249
|
+
: (stats.generatedMessagesCount ?? stats.messagesCount ?? 0);
|
|
250
|
+
const passFloorMet = minPassedCount === null || passed >= minPassedCount;
|
|
251
|
+
const generatedFloorMet = minGeneratedMessages === null || generated >= minGeneratedMessages;
|
|
252
|
+
if (passFloorMet && generatedFloorMet) {
|
|
253
|
+
return {
|
|
254
|
+
ready: true,
|
|
255
|
+
attempts,
|
|
256
|
+
elapsedMs: Date.now() - start,
|
|
257
|
+
tableId: schema.tableId,
|
|
258
|
+
pollKey,
|
|
259
|
+
floors: {
|
|
260
|
+
minPassedCount,
|
|
261
|
+
minGeneratedMessages,
|
|
262
|
+
templateRevision,
|
|
263
|
+
},
|
|
264
|
+
result: {
|
|
265
|
+
passedCount: passed,
|
|
266
|
+
generatedMessagesCount: stats.generatedMessagesCount ?? stats.messagesCount ?? 0,
|
|
267
|
+
currentRevisionGeneratedMessagesCount: stats.currentRevisionGeneratedMessagesCount ?? 0,
|
|
268
|
+
staleGeneratedMessagesCount: stats.staleGeneratedMessagesCount ?? 0,
|
|
269
|
+
generatedWithoutPassCount: stats.generatedWithoutPassCount ?? 0,
|
|
270
|
+
currentTemplateRevisionHash: currentRevisionHash,
|
|
271
|
+
},
|
|
272
|
+
stats,
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
await sleep(intervalMs);
|
|
276
|
+
}
|
|
277
|
+
const passed = lastStats?.passRate?.passed ?? 0;
|
|
278
|
+
return {
|
|
279
|
+
ready: false,
|
|
280
|
+
reason: guardApplied ? "tool_timeout_guard" : "timeout",
|
|
281
|
+
attempts,
|
|
282
|
+
elapsedMs: Date.now() - start,
|
|
283
|
+
tableId: schema.tableId,
|
|
284
|
+
pollKey,
|
|
285
|
+
warning: guardApplied
|
|
286
|
+
? `Stopped after ${effectiveTimeoutMs}ms to avoid host tool timeout (requested ${requestedTimeoutMs}ms).`
|
|
287
|
+
: undefined,
|
|
288
|
+
partialResult: {
|
|
289
|
+
passedCount: passed,
|
|
290
|
+
generatedMessagesCount: lastStats?.generatedMessagesCount ?? lastStats?.messagesCount ?? 0,
|
|
291
|
+
currentRevisionGeneratedMessagesCount: lastStats?.currentRevisionGeneratedMessagesCount ?? 0,
|
|
292
|
+
staleGeneratedMessagesCount: lastStats?.staleGeneratedMessagesCount ?? 0,
|
|
293
|
+
generatedWithoutPassCount: lastStats?.generatedWithoutPassCount ?? 0,
|
|
294
|
+
currentTemplateRevisionHash: lastStats?.currentTemplateRevisionHash ??
|
|
295
|
+
schema.currentApprovedBriefHash,
|
|
296
|
+
passFloorMet: minPassedCount === null || passed >= minPassedCount,
|
|
297
|
+
generatedFloorMet: minGeneratedMessages === null ||
|
|
298
|
+
(lastStats?.currentRevisionGeneratedMessagesCount ?? 0) >=
|
|
299
|
+
minGeneratedMessages,
|
|
300
|
+
},
|
|
301
|
+
guidance: "Do not repoll with identical arguments after this timeout. Use the partial diagnostics to revise filters/messages, queue missing work, or surface the blocked sample state.",
|
|
302
|
+
stats: lastStats,
|
|
303
|
+
};
|
|
304
|
+
}
|
package/dist/tools/leads.d.ts
CHANGED
|
@@ -146,6 +146,7 @@ export type ConfirmLeadListInput = {
|
|
|
146
146
|
keepInSync?: boolean;
|
|
147
147
|
jobId?: string;
|
|
148
148
|
reviewBatchLimit?: number;
|
|
149
|
+
includeRawImportResult?: boolean;
|
|
149
150
|
allowPartialSourceList?: boolean;
|
|
150
151
|
/**
|
|
151
152
|
* Deprecated alias for reviewBatchLimit. Confirming a lead list now copies the
|
|
@@ -246,6 +247,7 @@ export declare const leadToolDefinitions: ({
|
|
|
246
247
|
jobId?: undefined;
|
|
247
248
|
reviewBatchLimit?: undefined;
|
|
248
249
|
allowPartialSourceList?: undefined;
|
|
250
|
+
includeRawImportResult?: undefined;
|
|
249
251
|
selections?: undefined;
|
|
250
252
|
selectionMode?: undefined;
|
|
251
253
|
};
|
|
@@ -423,6 +425,7 @@ export declare const leadToolDefinitions: ({
|
|
|
423
425
|
jobId?: undefined;
|
|
424
426
|
reviewBatchLimit?: undefined;
|
|
425
427
|
allowPartialSourceList?: undefined;
|
|
428
|
+
includeRawImportResult?: undefined;
|
|
426
429
|
selections?: undefined;
|
|
427
430
|
selectionMode?: undefined;
|
|
428
431
|
};
|
|
@@ -499,6 +502,7 @@ export declare const leadToolDefinitions: ({
|
|
|
499
502
|
jobId?: undefined;
|
|
500
503
|
reviewBatchLimit?: undefined;
|
|
501
504
|
allowPartialSourceList?: undefined;
|
|
505
|
+
includeRawImportResult?: undefined;
|
|
502
506
|
selections?: undefined;
|
|
503
507
|
selectionMode?: undefined;
|
|
504
508
|
};
|
|
@@ -647,6 +651,7 @@ export declare const leadToolDefinitions: ({
|
|
|
647
651
|
jobId?: undefined;
|
|
648
652
|
reviewBatchLimit?: undefined;
|
|
649
653
|
allowPartialSourceList?: undefined;
|
|
654
|
+
includeRawImportResult?: undefined;
|
|
650
655
|
selections?: undefined;
|
|
651
656
|
selectionMode?: undefined;
|
|
652
657
|
};
|
|
@@ -737,6 +742,7 @@ export declare const leadToolDefinitions: ({
|
|
|
737
742
|
jobId?: undefined;
|
|
738
743
|
reviewBatchLimit?: undefined;
|
|
739
744
|
allowPartialSourceList?: undefined;
|
|
745
|
+
includeRawImportResult?: undefined;
|
|
740
746
|
selections?: undefined;
|
|
741
747
|
selectionMode?: undefined;
|
|
742
748
|
};
|
|
@@ -836,6 +842,7 @@ export declare const leadToolDefinitions: ({
|
|
|
836
842
|
jobId?: undefined;
|
|
837
843
|
reviewBatchLimit?: undefined;
|
|
838
844
|
allowPartialSourceList?: undefined;
|
|
845
|
+
includeRawImportResult?: undefined;
|
|
839
846
|
selections?: undefined;
|
|
840
847
|
selectionMode?: undefined;
|
|
841
848
|
};
|
|
@@ -917,6 +924,7 @@ export declare const leadToolDefinitions: ({
|
|
|
917
924
|
jobId?: undefined;
|
|
918
925
|
reviewBatchLimit?: undefined;
|
|
919
926
|
allowPartialSourceList?: undefined;
|
|
927
|
+
includeRawImportResult?: undefined;
|
|
920
928
|
selections?: undefined;
|
|
921
929
|
selectionMode?: undefined;
|
|
922
930
|
};
|
|
@@ -1537,6 +1545,7 @@ export declare const leadToolDefinitions: ({
|
|
|
1537
1545
|
jobId?: undefined;
|
|
1538
1546
|
reviewBatchLimit?: undefined;
|
|
1539
1547
|
allowPartialSourceList?: undefined;
|
|
1548
|
+
includeRawImportResult?: undefined;
|
|
1540
1549
|
selections?: undefined;
|
|
1541
1550
|
selectionMode?: undefined;
|
|
1542
1551
|
};
|
|
@@ -1670,6 +1679,7 @@ export declare const leadToolDefinitions: ({
|
|
|
1670
1679
|
jobId?: undefined;
|
|
1671
1680
|
reviewBatchLimit?: undefined;
|
|
1672
1681
|
allowPartialSourceList?: undefined;
|
|
1682
|
+
includeRawImportResult?: undefined;
|
|
1673
1683
|
selections?: undefined;
|
|
1674
1684
|
selectionMode?: undefined;
|
|
1675
1685
|
};
|
|
@@ -1791,6 +1801,7 @@ export declare const leadToolDefinitions: ({
|
|
|
1791
1801
|
jobId?: undefined;
|
|
1792
1802
|
reviewBatchLimit?: undefined;
|
|
1793
1803
|
allowPartialSourceList?: undefined;
|
|
1804
|
+
includeRawImportResult?: undefined;
|
|
1794
1805
|
selections?: undefined;
|
|
1795
1806
|
selectionMode?: undefined;
|
|
1796
1807
|
};
|
|
@@ -1870,6 +1881,7 @@ export declare const leadToolDefinitions: ({
|
|
|
1870
1881
|
jobId?: undefined;
|
|
1871
1882
|
reviewBatchLimit?: undefined;
|
|
1872
1883
|
allowPartialSourceList?: undefined;
|
|
1884
|
+
includeRawImportResult?: undefined;
|
|
1873
1885
|
selections?: undefined;
|
|
1874
1886
|
selectionMode?: undefined;
|
|
1875
1887
|
};
|
|
@@ -1921,6 +1933,10 @@ export declare const leadToolDefinitions: ({
|
|
|
1921
1933
|
type: string;
|
|
1922
1934
|
description: string;
|
|
1923
1935
|
};
|
|
1936
|
+
includeRawImportResult: {
|
|
1937
|
+
type: string;
|
|
1938
|
+
description: string;
|
|
1939
|
+
};
|
|
1924
1940
|
provider?: undefined;
|
|
1925
1941
|
searchMode?: undefined;
|
|
1926
1942
|
organization_num_employees_ranges?: undefined;
|
|
@@ -2083,6 +2099,7 @@ export declare const leadToolDefinitions: ({
|
|
|
2083
2099
|
jobId?: undefined;
|
|
2084
2100
|
reviewBatchLimit?: undefined;
|
|
2085
2101
|
allowPartialSourceList?: undefined;
|
|
2102
|
+
includeRawImportResult?: undefined;
|
|
2086
2103
|
};
|
|
2087
2104
|
required: string[];
|
|
2088
2105
|
};
|
|
@@ -2164,6 +2181,7 @@ export declare const leadToolDefinitions: ({
|
|
|
2164
2181
|
jobId?: undefined;
|
|
2165
2182
|
reviewBatchLimit?: undefined;
|
|
2166
2183
|
allowPartialSourceList?: undefined;
|
|
2184
|
+
includeRawImportResult?: undefined;
|
|
2167
2185
|
selections?: undefined;
|
|
2168
2186
|
selectionMode?: undefined;
|
|
2169
2187
|
};
|
|
@@ -2608,25 +2626,13 @@ export declare function cancelLeadImport(input: CancelLeadImportInput): Promise<
|
|
|
2608
2626
|
previousStatus?: undefined;
|
|
2609
2627
|
}>;
|
|
2610
2628
|
export declare function confirmLeadList(input: ConfirmLeadListInput): Promise<{
|
|
2611
|
-
|
|
2612
|
-
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
|
|
2618
|
-
leadsSkipped?: number;
|
|
2619
|
-
rowIds?: string[];
|
|
2620
|
-
requestedTargetLeadCount?: number;
|
|
2621
|
-
sourceRowLimit?: number;
|
|
2622
|
-
async?: boolean;
|
|
2623
|
-
hybrid?: boolean;
|
|
2624
|
-
campaignTableReady?: boolean;
|
|
2625
|
-
importStatus?: string | null;
|
|
2626
|
-
remainingRowCount?: number | null;
|
|
2627
|
-
rowCount?: number | null;
|
|
2628
|
-
sourceRowCount?: number | null;
|
|
2629
|
-
clonedSourceRowCount?: number | null;
|
|
2629
|
+
reviewBatch: {
|
|
2630
|
+
tableId: string | null;
|
|
2631
|
+
rowCount: number;
|
|
2632
|
+
rowIds: string[];
|
|
2633
|
+
enrichCellIds: string[];
|
|
2634
|
+
basisHash: string | null;
|
|
2635
|
+
recordedAt: string | null;
|
|
2630
2636
|
};
|
|
2631
2637
|
messageDraftBuilder: {
|
|
2632
2638
|
firstAllowedStartPoint: string;
|
|
@@ -2637,6 +2643,7 @@ export declare function confirmLeadList(input: ConfirmLeadListInput): Promise<{
|
|
|
2637
2643
|
selectedLeadListId: string;
|
|
2638
2644
|
workflowTableId: string | null;
|
|
2639
2645
|
reviewBatchRowIds: string[];
|
|
2646
|
+
reviewBatchBasisHash: string | null;
|
|
2640
2647
|
reviewBatchRowCount: number;
|
|
2641
2648
|
copiedCampaignRowCount: number;
|
|
2642
2649
|
};
|
|
@@ -2665,6 +2672,43 @@ export declare function confirmLeadList(input: ConfirmLeadListInput): Promise<{
|
|
|
2665
2672
|
warning: string | null;
|
|
2666
2673
|
};
|
|
2667
2674
|
message: string;
|
|
2675
|
+
importResult?: {
|
|
2676
|
+
workflowTableId?: string;
|
|
2677
|
+
campaignTableId?: string;
|
|
2678
|
+
campaignTableName?: string;
|
|
2679
|
+
leadsImported?: number;
|
|
2680
|
+
leadsSkipped?: number;
|
|
2681
|
+
rowIds?: string[];
|
|
2682
|
+
requestedTargetLeadCount?: number;
|
|
2683
|
+
sourceRowLimit?: number;
|
|
2684
|
+
async?: boolean;
|
|
2685
|
+
hybrid?: boolean;
|
|
2686
|
+
campaignTableReady?: boolean;
|
|
2687
|
+
importStatus?: string | null;
|
|
2688
|
+
remainingRowCount?: number | null;
|
|
2689
|
+
rowCount?: number | null;
|
|
2690
|
+
sourceRowCount?: number | null;
|
|
2691
|
+
clonedSourceRowCount?: number | null;
|
|
2692
|
+
} | undefined;
|
|
2693
|
+
sourceLeadListId: string;
|
|
2694
|
+
campaignTableId: string | null;
|
|
2695
|
+
importSummary: {
|
|
2696
|
+
workflowTableId: string | null;
|
|
2697
|
+
campaignTableId: string | null;
|
|
2698
|
+
campaignTableName: string | null;
|
|
2699
|
+
leadsImported: number | null;
|
|
2700
|
+
leadsSkipped: number | null;
|
|
2701
|
+
rowCount: number;
|
|
2702
|
+
requestedTargetLeadCount: number | null;
|
|
2703
|
+
sourceRowLimit: number | null;
|
|
2704
|
+
async: boolean;
|
|
2705
|
+
hybrid: boolean;
|
|
2706
|
+
campaignTableReady: true;
|
|
2707
|
+
importStatus: string | null;
|
|
2708
|
+
remainingRowCount: number;
|
|
2709
|
+
sourceRowCount: number | null;
|
|
2710
|
+
clonedSourceRowCount: number | null;
|
|
2711
|
+
};
|
|
2668
2712
|
}>;
|
|
2669
2713
|
export declare function getProviderPrompt(input: GetProviderPromptInput): string;
|
|
2670
2714
|
export declare function selectPromisingPosts(input: SelectPromisingPostsInput): Promise<{
|
package/dist/tools/leads.js
CHANGED
|
@@ -529,7 +529,7 @@ function buildSourceImportWatchNarration({ provider, selectedPostCount, estimate
|
|
|
529
529
|
: "Apollo";
|
|
530
530
|
const sourceDetail = provider === "signal-discovery"
|
|
531
531
|
? `${selectedPostCount ?? "selected"} approved post${selectedPostCount === 1 ? "" : "s"}${typeof estimatedEngagers === "number"
|
|
532
|
-
? ` with
|
|
532
|
+
? ` with up to ${estimatedEngagers.toLocaleString("en-US")} people to check before top-level scrape adjustment`
|
|
533
533
|
: ""}`
|
|
534
534
|
: `the approved ${providerLabel} source`;
|
|
535
535
|
const targetDetail = typeof targetLeadCount === "number"
|
|
@@ -806,8 +806,8 @@ function buildSignalDiscoverySourceRecommendation({ selectedPosts, targetEngager
|
|
|
806
806
|
? "the approved buyer-search target"
|
|
807
807
|
: `the ${Math.round(defaultFitRate * 100)}% starting estimate`;
|
|
808
808
|
const selectedPoolCopy = recommendedCount < selectedCount
|
|
809
|
-
? `**Posts considered:** ${selectedCount.toLocaleString("en-US")} selected posts with ${formatApproxInteger(totalVisibleEngagement)} public reactions/comments<br>\n**Recommended first set:** ${recommendedCount.toLocaleString("en-US")} post${recommendedCount === 1 ? "" : "s"} with ${formatApproxInteger(recommendedVisibleEngagement)} public reactions/comments and up to ${formatApproxInteger(scrapePlan.estimatedEngagers)} people to check<br>`
|
|
810
|
-
: `**
|
|
809
|
+
? `**Posts considered:** ${selectedCount.toLocaleString("en-US")} selected posts with ${formatApproxInteger(totalVisibleEngagement)} visible public reactions/comments<br>\n**Recommended first set:** ${recommendedCount.toLocaleString("en-US")} post${recommendedCount === 1 ? "" : "s"} with ${formatApproxInteger(recommendedVisibleEngagement)} visible public reactions/comments and up to ${formatApproxInteger(scrapePlan.estimatedEngagers)} people to check before top-level comment and dedupe adjustment<br>`
|
|
810
|
+
: `**Visible public activity in the selected posts:** ${formatApproxInteger(totalVisibleEngagement)} reactions/comments<br>\n**People we can check from this set:** up to ${formatApproxInteger(scrapePlan.estimatedEngagers)} before top-level comment and dedupe adjustment<br>`;
|
|
811
811
|
const message = `## Source Recommendation
|
|
812
812
|
|
|
813
813
|
Start with LinkedIn posts.
|
|
@@ -821,7 +821,7 @@ I found ${recommendedCount.toLocaleString("en-US")} recommended LinkedIn post${r
|
|
|
821
821
|
|
|
822
822
|
### Recommended posts
|
|
823
823
|
|
|
824
|
-
| Post | Why this post |
|
|
824
|
+
| Post | Why this post | Visible public activity | People we can check |
|
|
825
825
|
|---|---|---:|---:|
|
|
826
826
|
${tableRows || "| Recommended posts | Campaign-matched public activity | - | - |"}
|
|
827
827
|
|
|
@@ -1518,6 +1518,10 @@ export const leadToolDefinitions = [
|
|
|
1518
1518
|
type: "boolean",
|
|
1519
1519
|
description: "Set true after user approval when interaction mode requires confirmation for confirm/import.",
|
|
1520
1520
|
},
|
|
1521
|
+
includeRawImportResult: {
|
|
1522
|
+
type: "boolean",
|
|
1523
|
+
description: "Debug only. When true, include the raw import response; default compact output omits large row-id payloads.",
|
|
1524
|
+
},
|
|
1521
1525
|
},
|
|
1522
1526
|
required: ["campaignOfferId"],
|
|
1523
1527
|
},
|
|
@@ -2579,7 +2583,7 @@ export async function importLeads(input) {
|
|
|
2579
2583
|
maxPostsToScrape: normalizePositiveInteger(maxPostsToScrape) ?? null,
|
|
2580
2584
|
limitedSelectedPosts: importSelection.limited,
|
|
2581
2585
|
targetLeadCount: cappedTargetLeadCount ?? null,
|
|
2582
|
-
message: `Started scraping ${postsToScrape.length} posts (~${result.estimatedEngagers} people to check). Leads will appear as scraping completes.${importSelection.limited
|
|
2586
|
+
message: `Started scraping ${postsToScrape.length} posts (up to ~${result.estimatedEngagers} people to check before top-level scrape adjustment). Leads will appear as scraping completes.${importSelection.limited
|
|
2583
2587
|
? ` Limited from ${uniqueSelectedPosts.length} selected posts by the approved source-capacity scrape plan.`
|
|
2584
2588
|
: ""} The watched campaign has been moved to confirm-lead-list with import progress copy. Keep calling wait_for_lead_list_ready until it reports ready, failed, or cancelled before confirm_lead_list; only confirm a partial list with allowPartialSourceList after the user explicitly asks to keep going early. Do not call update_campaign to fix that step.`,
|
|
2585
2589
|
};
|
|
@@ -2741,7 +2745,7 @@ export async function cancelLeadImport(input) {
|
|
|
2741
2745
|
}
|
|
2742
2746
|
export async function confirmLeadList(input) {
|
|
2743
2747
|
const api = getApi();
|
|
2744
|
-
const { campaignOfferId, currentStep, confirmed, sourceLeadListId, campaignName, keepInSync, jobId, reviewBatchLimit, allowPartialSourceList, targetLeadCount, } = input;
|
|
2748
|
+
const { campaignOfferId, currentStep, confirmed, sourceLeadListId, campaignName, keepInSync, jobId, reviewBatchLimit, includeRawImportResult, allowPartialSourceList, targetLeadCount, } = input;
|
|
2745
2749
|
assertInteractionApproval({
|
|
2746
2750
|
campaignId: campaignOfferId,
|
|
2747
2751
|
action: "confirm-lead-list",
|
|
@@ -2988,6 +2992,50 @@ export async function confirmLeadList(input) {
|
|
|
2988
2992
|
reviewSampleRows = [];
|
|
2989
2993
|
}
|
|
2990
2994
|
}
|
|
2995
|
+
const sampleReviewRowIds = reviewSampleRows
|
|
2996
|
+
.map((row) => row.id)
|
|
2997
|
+
.filter((rowId) => typeof rowId === "string");
|
|
2998
|
+
const reviewBatchRowIds = importedRowIds.length > 0
|
|
2999
|
+
? importedRowIds.slice(0, keptReviewRowCount)
|
|
3000
|
+
: sampleReviewRowIds.slice(0, keptReviewRowCount);
|
|
3001
|
+
const reviewBatchEnrichCellIds = reviewSampleRows
|
|
3002
|
+
.map((row) => row.enrichCellId)
|
|
3003
|
+
.filter((cellId) => typeof cellId === "string");
|
|
3004
|
+
let recordedReviewBatch = null;
|
|
3005
|
+
if (campaignTableId && reviewBatchRowIds.length > 0) {
|
|
3006
|
+
const recordResult = await api.post("/api/v3/mcp/campaign-processing", {
|
|
3007
|
+
action: "recordReviewBatch",
|
|
3008
|
+
tableId: campaignTableId,
|
|
3009
|
+
rowIds: reviewBatchRowIds,
|
|
3010
|
+
enrichCellIds: reviewBatchEnrichCellIds,
|
|
3011
|
+
});
|
|
3012
|
+
recordedReviewBatch = recordResult.reviewBatch ?? null;
|
|
3013
|
+
}
|
|
3014
|
+
const compactReviewBatch = {
|
|
3015
|
+
tableId: campaignTableId ?? null,
|
|
3016
|
+
rowCount: recordedReviewBatch?.rowCount ?? reviewBatchRowIds.length,
|
|
3017
|
+
rowIds: recordedReviewBatch?.rowIds ?? reviewBatchRowIds,
|
|
3018
|
+
enrichCellIds: recordedReviewBatch?.enrichCellIds ?? reviewBatchEnrichCellIds,
|
|
3019
|
+
basisHash: recordedReviewBatch?.basisHash ?? null,
|
|
3020
|
+
recordedAt: recordedReviewBatch?.recordedAt ?? null,
|
|
3021
|
+
};
|
|
3022
|
+
const importSummary = {
|
|
3023
|
+
workflowTableId: campaignTableId ?? null,
|
|
3024
|
+
campaignTableId: campaignTableId ?? null,
|
|
3025
|
+
campaignTableName: importResult.campaignTableName ?? null,
|
|
3026
|
+
leadsImported: importResult.leadsImported ?? null,
|
|
3027
|
+
leadsSkipped: importResult.leadsSkipped ?? null,
|
|
3028
|
+
rowCount: importResult.rowCount ?? importedRowCount,
|
|
3029
|
+
requestedTargetLeadCount: importResult.requestedTargetLeadCount ?? null,
|
|
3030
|
+
sourceRowLimit: importResult.sourceRowLimit ?? null,
|
|
3031
|
+
async: importResult.async ?? false,
|
|
3032
|
+
hybrid: importResult.hybrid ?? false,
|
|
3033
|
+
campaignTableReady,
|
|
3034
|
+
importStatus: importResult.importStatus ?? null,
|
|
3035
|
+
remainingRowCount,
|
|
3036
|
+
sourceRowCount: importResult.sourceRowCount ?? null,
|
|
3037
|
+
clonedSourceRowCount: importResult.clonedSourceRowCount ?? null,
|
|
3038
|
+
};
|
|
2991
3039
|
// Persist currentStep if the caller asked for it. Do NOT touch
|
|
2992
3040
|
// selectedLeadListId here: the campaign table id is already saved to
|
|
2993
3041
|
// CampaignOffer.workflowTableId by /api/v3/campaign-builder/import-leads,
|
|
@@ -3014,7 +3062,9 @@ export async function confirmLeadList(input) {
|
|
|
3014
3062
|
return {
|
|
3015
3063
|
sourceLeadListId: resolvedLeadListId,
|
|
3016
3064
|
campaignTableId: campaignTableId ?? null,
|
|
3017
|
-
|
|
3065
|
+
importSummary,
|
|
3066
|
+
...(includeRawImportResult ? { importResult } : {}),
|
|
3067
|
+
reviewBatch: compactReviewBatch,
|
|
3018
3068
|
messageDraftBuilder: {
|
|
3019
3069
|
firstAllowedStartPoint: "confirm_lead_list",
|
|
3020
3070
|
startAllowed: true,
|
|
@@ -3023,7 +3073,8 @@ export async function confirmLeadList(input) {
|
|
|
3023
3073
|
campaignOfferId,
|
|
3024
3074
|
selectedLeadListId: resolvedLeadListId,
|
|
3025
3075
|
workflowTableId: campaignTableId ?? null,
|
|
3026
|
-
reviewBatchRowIds
|
|
3076
|
+
reviewBatchRowIds,
|
|
3077
|
+
reviewBatchBasisHash: compactReviewBatch.basisHash,
|
|
3027
3078
|
reviewBatchRowCount: keptReviewRowCount,
|
|
3028
3079
|
copiedCampaignRowCount: importedRowCount,
|
|
3029
3080
|
},
|
package/dist/tools/prompts.js
CHANGED
|
@@ -315,7 +315,7 @@ export function getPostFindLeadsScoutRegistry() {
|
|
|
315
315
|
"basis.workflowTableId",
|
|
316
316
|
"basis.reviewSampleRowHash or basis.reviewSampleRowIds",
|
|
317
317
|
],
|
|
318
|
-
promptRequired: 'get_subskill_prompt({ subskillName: "generate-messages",
|
|
318
|
+
promptRequired: 'get_subskill_prompt({ subskillName: "generate-messages-compact" }); load generate-messages-compact/references/examples-critique-revision.md only for critique, revision, or close-call examples',
|
|
319
319
|
basisFields: [
|
|
320
320
|
"campaign revision or updatedAt",
|
|
321
321
|
"brief hash",
|
|
@@ -342,7 +342,7 @@ export function getPostFindLeadsScoutRegistry() {
|
|
|
342
342
|
usage: {
|
|
343
343
|
codex: "After confirm_lead_list copies source rows and the initial campaign-table execution slice exists, ask the filter-choice question immediately. Do not spawn returned post-lead scout names before that question. Once the user answers, spawn Message Draft Builder from the same campaign/table basis. If the user chooses filters, also spawn Lead Fit Builder, move to Filter Rules, save rubrics, ask for filter approval, then keep the browser on Filter Leads and show `Filters saved + waiting for message approval` while the message recommendation is reviewed. If filters are skipped, move to Messages/message review.",
|
|
344
344
|
claude: "After confirm_lead_list copies source rows and the initial campaign-table execution slice exists, ask the filter-choice question immediately. Do not invoke returned post-lead Task/Agent names before that question. Once the user answers, invoke Message Draft Builder from the same campaign/table basis. If the user chooses filters, also invoke Lead Fit Builder, move to Filter Rules, save rubrics, ask for filter approval, then keep the browser on Filter Leads and show `Filters saved + waiting for message approval` while the message recommendation is reviewed. If filters are skipped, move to Messages/message review.",
|
|
345
|
-
parentThreadRule: 'Named agents are optional acceleration, but message drafting is not optional. If post-find-leads-message-scout is available, run it as the background Message Draft Builder after the filter-choice answer. If it is absent, do not customer-surface install status; the main thread must execute the same message branch from CampaignOffer state, selected source state, workflowTableId, and initial campaign-table execution slice rows. Local markdown/json files are not normal-path inputs. The filter-choice question is the first post-import user gate; do not load post-lead registries, filter references, or the full generate-messages prompt before it. Message drafting starts after the filter-choice answer, must load get_subskill_prompt({ subskillName: "generate-messages"
|
|
345
|
+
parentThreadRule: 'Named agents are optional acceleration, but message drafting is not optional. If post-find-leads-message-scout is available, run it as the background Message Draft Builder after the filter-choice answer. If it is absent, do not customer-surface install status; the main thread must execute the same message branch from CampaignOffer state, selected source state, workflowTableId, and initial campaign-table execution slice rows. Local markdown/json files are not normal-path inputs. The filter-choice question is the first post-import user gate; do not load post-lead registries, filter references, or the full legacy generate-messages prompt before it. Message drafting starts after the filter-choice answer, must load get_subskill_prompt({ subskillName: "generate-messages-compact" }), must read live campaign table state through scoped MCP/product tools, and must reject mismatched selectedLeadListId/workflowTableId/campaign/workspace input. Load generate-messages-compact/references/examples-critique-revision.md only for critique, revision, or close-call examples. On the filter path, keep the browser on Filter Rules after save_rubrics so the user can approve the saved criteria; only then move to Filter Leads, show `Filters saved + waiting for message approval`, and wait there for message approval. Enrichment, filtering, Generate Message cells, sender setup, sequence attach, and launch wait for template approval on the Use Template path. On the skip path, move to Messages/message review and wait for message approval before enrichment or Settings. Do not render message review from checklist or shortcut instructions; message review requires a messageDraftRecommendation whose basis proves the generate-messages-compact prompt ran for the current campaign/table execution slice. Do not automatically rerun Message Draft Builder after filters/enrichment finish; show the initial draft by default and offer an enriched rewrite only with explicit user opt-in.',
|
|
346
346
|
},
|
|
347
347
|
};
|
|
348
348
|
}
|