@sellable/mcp 0.1.55 → 0.1.56
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/tools/leads.d.ts +56 -0
- package/dist/tools/leads.js +66 -2
- package/package.json +1 -1
- package/skills/create-campaign-v2/SKILL.md +15 -9
- package/skills/create-campaign-v2/references/watch-link-handoff.md +1 -1
- package/skills/find-leads/SKILL.md +7 -0
- package/skills/providers/sales-nav.md +16 -0
package/dist/tools/leads.d.ts
CHANGED
|
@@ -314,6 +314,7 @@ export declare const leadToolDefinitions: ({
|
|
|
314
314
|
filters: {
|
|
315
315
|
type: string;
|
|
316
316
|
description: string;
|
|
317
|
+
items?: undefined;
|
|
317
318
|
properties?: undefined;
|
|
318
319
|
};
|
|
319
320
|
companyFilters: {
|
|
@@ -473,6 +474,59 @@ export declare const leadToolDefinitions: ({
|
|
|
473
474
|
filters: {
|
|
474
475
|
type: string;
|
|
475
476
|
description: string;
|
|
477
|
+
items: {
|
|
478
|
+
type: string;
|
|
479
|
+
properties: {
|
|
480
|
+
type: {
|
|
481
|
+
type: string;
|
|
482
|
+
};
|
|
483
|
+
values: {
|
|
484
|
+
type: string;
|
|
485
|
+
items: {
|
|
486
|
+
type: string;
|
|
487
|
+
properties: {
|
|
488
|
+
id: {
|
|
489
|
+
type: string;
|
|
490
|
+
};
|
|
491
|
+
text: {
|
|
492
|
+
type: string;
|
|
493
|
+
};
|
|
494
|
+
selectionType: {
|
|
495
|
+
type: string;
|
|
496
|
+
enum: string[];
|
|
497
|
+
};
|
|
498
|
+
parent: {
|
|
499
|
+
type: string;
|
|
500
|
+
properties: {
|
|
501
|
+
id: {
|
|
502
|
+
type: string;
|
|
503
|
+
};
|
|
504
|
+
};
|
|
505
|
+
};
|
|
506
|
+
};
|
|
507
|
+
required: string[];
|
|
508
|
+
};
|
|
509
|
+
};
|
|
510
|
+
rangeValue: {
|
|
511
|
+
type: string;
|
|
512
|
+
properties: {
|
|
513
|
+
min: {
|
|
514
|
+
type: string;
|
|
515
|
+
};
|
|
516
|
+
max: {
|
|
517
|
+
type: string;
|
|
518
|
+
};
|
|
519
|
+
};
|
|
520
|
+
required: string[];
|
|
521
|
+
};
|
|
522
|
+
selectedSubFilter: {
|
|
523
|
+
anyOf: {
|
|
524
|
+
type: string;
|
|
525
|
+
}[];
|
|
526
|
+
};
|
|
527
|
+
};
|
|
528
|
+
required: string[];
|
|
529
|
+
};
|
|
476
530
|
properties?: undefined;
|
|
477
531
|
};
|
|
478
532
|
keywords: {
|
|
@@ -1347,6 +1401,7 @@ export declare const leadToolDefinitions: ({
|
|
|
1347
1401
|
};
|
|
1348
1402
|
};
|
|
1349
1403
|
};
|
|
1404
|
+
items?: undefined;
|
|
1350
1405
|
};
|
|
1351
1406
|
page: {
|
|
1352
1407
|
type: string;
|
|
@@ -2015,6 +2070,7 @@ export declare const leadToolDefinitions: ({
|
|
|
2015
2070
|
})[];
|
|
2016
2071
|
export declare function searchApollo(input: ApolloSearchInput): Promise<unknown>;
|
|
2017
2072
|
export declare function searchSalesNav(input: SalesNavSearchInput): Promise<unknown>;
|
|
2073
|
+
export declare function normalizeSalesNavSearchInput(input: SalesNavSearchInput): SalesNavSearchInput;
|
|
2018
2074
|
export declare function searchProspeo(input: ProspeoSearchInput): Promise<any>;
|
|
2019
2075
|
export declare function loadCsvDomains(input: LoadCsvDomainsInput): Promise<{
|
|
2020
2076
|
ok: boolean;
|
package/dist/tools/leads.js
CHANGED
|
@@ -32,6 +32,46 @@ const prospeoFilterValueSchema = {
|
|
|
32
32
|
exclude: { type: "array", items: { type: "string" } },
|
|
33
33
|
},
|
|
34
34
|
};
|
|
35
|
+
const salesNavFilterValueSchema = {
|
|
36
|
+
type: "object",
|
|
37
|
+
properties: {
|
|
38
|
+
id: { type: "string" },
|
|
39
|
+
text: { type: "string" },
|
|
40
|
+
selectionType: {
|
|
41
|
+
type: "string",
|
|
42
|
+
enum: ["INCLUDED", "EXCLUDED"],
|
|
43
|
+
},
|
|
44
|
+
parent: {
|
|
45
|
+
type: "object",
|
|
46
|
+
properties: {
|
|
47
|
+
id: { type: "string" },
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
required: ["id", "text", "selectionType"],
|
|
52
|
+
};
|
|
53
|
+
const salesNavFilterSchema = {
|
|
54
|
+
type: "object",
|
|
55
|
+
properties: {
|
|
56
|
+
type: { type: "string" },
|
|
57
|
+
values: {
|
|
58
|
+
type: "array",
|
|
59
|
+
items: salesNavFilterValueSchema,
|
|
60
|
+
},
|
|
61
|
+
rangeValue: {
|
|
62
|
+
type: "object",
|
|
63
|
+
properties: {
|
|
64
|
+
min: { type: "number" },
|
|
65
|
+
max: { type: "number" },
|
|
66
|
+
},
|
|
67
|
+
required: ["min", "max"],
|
|
68
|
+
},
|
|
69
|
+
selectedSubFilter: {
|
|
70
|
+
anyOf: [{ type: "string" }, { type: "number" }],
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
required: ["type"],
|
|
74
|
+
};
|
|
35
75
|
const prospeoRangeFilterSchema = {
|
|
36
76
|
type: "object",
|
|
37
77
|
description: "Numeric range filter (min/max)",
|
|
@@ -540,7 +580,8 @@ export const leadToolDefinitions = [
|
|
|
540
580
|
properties: {
|
|
541
581
|
filters: {
|
|
542
582
|
type: "array",
|
|
543
|
-
description: "Sales Nav filter array",
|
|
583
|
+
description: "Sales Nav filter array. Pass filter objects, not JSON strings.",
|
|
584
|
+
items: salesNavFilterSchema,
|
|
544
585
|
},
|
|
545
586
|
keywords: {
|
|
546
587
|
type: "string",
|
|
@@ -1312,7 +1353,30 @@ export async function searchSalesNav(input) {
|
|
|
1312
1353
|
campaignOfferId: input?.campaignOfferId,
|
|
1313
1354
|
});
|
|
1314
1355
|
const api = getApi();
|
|
1315
|
-
return api.post(`/api/v3/sales-nav/search`, input);
|
|
1356
|
+
return api.post(`/api/v3/sales-nav/search`, normalizeSalesNavSearchInput(input));
|
|
1357
|
+
}
|
|
1358
|
+
export function normalizeSalesNavSearchInput(input) {
|
|
1359
|
+
return {
|
|
1360
|
+
...input,
|
|
1361
|
+
filters: normalizeSalesNavFilters(input.filters),
|
|
1362
|
+
};
|
|
1363
|
+
}
|
|
1364
|
+
function normalizeSalesNavFilters(filters) {
|
|
1365
|
+
return filters.map((filter, index) => {
|
|
1366
|
+
if (typeof filter !== "string") {
|
|
1367
|
+
return filter;
|
|
1368
|
+
}
|
|
1369
|
+
try {
|
|
1370
|
+
const parsed = JSON.parse(filter);
|
|
1371
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
1372
|
+
throw new Error("not an object");
|
|
1373
|
+
}
|
|
1374
|
+
return parsed;
|
|
1375
|
+
}
|
|
1376
|
+
catch {
|
|
1377
|
+
throw new Error(`Invalid Sales Nav filter at index ${index}. Pass filter objects, not JSON strings.`);
|
|
1378
|
+
}
|
|
1379
|
+
});
|
|
1316
1380
|
}
|
|
1317
1381
|
export async function searchProspeo(input) {
|
|
1318
1382
|
if (input?.campaignOfferId) {
|
package/package.json
CHANGED
|
@@ -423,7 +423,7 @@ should test for this campaign. Those can run in parallel and usually take
|
|
|
423
423
|
batching is available, batch independent tool reads/lookups only. If real
|
|
424
424
|
parallel execution is not available or not allowed, run the same DAG
|
|
425
425
|
sequentially and use honest copy: `I’ll tighten the filter first, then draft
|
|
426
|
-
|
|
426
|
+
the message from the same sample.` Never say `kicking off two workstreams`,
|
|
427
427
|
`in parallel`, or `background` unless parallel branches were actually
|
|
428
428
|
launched.
|
|
429
429
|
- Never run a downstream stage until the active `flow.v2.json` step's
|
|
@@ -574,14 +574,20 @@ Required behavior:
|
|
|
574
574
|
- Branch C: Prospeo / domains only when the campaign has a domain/account
|
|
575
575
|
path or the user supplied domains. Estimate email/contact scale and call out
|
|
576
576
|
weaker LinkedIn activity.
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
577
|
+
If the host cannot run these branches in parallel, run them sequentially and
|
|
578
|
+
do not claim they ran in parallel. If only one source angle is credible, say
|
|
579
|
+
that and run the best primary source plus one cheap fallback/quality check
|
|
580
|
+
when available. For Signals-first campaigns, search multiple Signals keyword
|
|
581
|
+
lanes and fetch top-post engagers in parallel when tool batching allows it.
|
|
582
|
+
For Sales Nav-first or Prospeo/account-first campaigns, run multiple preview
|
|
583
|
+
lanes for that provider in parallel and use Signals only as a warmth/quality
|
|
584
|
+
check when relevant
|
|
585
|
+
- after every Sales Nav preview, validate that filters actually applied before
|
|
586
|
+
using the lane in `lead-review.md`: `searchUrl` should include filters, the
|
|
587
|
+
first page should match the intended roles/companies, and the result count
|
|
588
|
+
should be plausible. If Sales Nav returns a giant unfiltered pool, drops the
|
|
589
|
+
filters, or errors after one clean retry, call it out as a provider/tool
|
|
590
|
+
issue and do not recommend Sales Nav.
|
|
585
591
|
- for Signals-first campaigns, raw post search volume is only inventory, not
|
|
586
592
|
lead volume. `492 post results` means matching LinkedIn posts found across
|
|
587
593
|
keyword lanes; it does not mean 492 prospects. The source decision must name
|
|
@@ -40,7 +40,7 @@ must contain:
|
|
|
40
40
|
- a plain confirmation that the campaign was created and the approved brief was
|
|
41
41
|
saved
|
|
42
42
|
- a one-line orientation sentence: `Open this to watch lead sourcing, rubric
|
|
43
|
-
|
|
43
|
+
scoring, and messaging populate live.`
|
|
44
44
|
- the `watchUrl` captured from the `create_campaign` response
|
|
45
45
|
|
|
46
46
|
Example skeleton:
|
|
@@ -293,6 +293,13 @@ Use first when LinkedIn activity plus tighter role / company filters matter.
|
|
|
293
293
|
- When you fall back from the recently-posted slice, say clearly that the posted filter was tested, explain why it was dropped, and keep the best non-posted lane as the source of truth.
|
|
294
294
|
- Use `RECENTLY_CHANGED_JOBS` when job-change activity is part of the targeting thesis.
|
|
295
295
|
- If quality is poor, tighten the lane with role, industry, seniority, geography, or activity filters.
|
|
296
|
+
- After each Sales Nav preview, sanity-check the result before using it in the
|
|
297
|
+
decision: the returned `searchUrl` should include filters, the first page
|
|
298
|
+
should visibly match the intended roles and companies, and the count should
|
|
299
|
+
be plausible. If filters did not apply, the search errors, or the total looks
|
|
300
|
+
obviously unfiltered, retry once with clean filter objects. If it still fails,
|
|
301
|
+
mark Sales Nav as a provider/tool issue and do not include it as a winning
|
|
302
|
+
source.
|
|
296
303
|
- If quality is good but scale is too small, widen the lane by adding/removing roles, expanding industries, widening headcount bands, or relaxing activity constraints.
|
|
297
304
|
- Use as many smart refinement steps as needed within the remaining probe budget instead of returning the first under-scaled recipe.
|
|
298
305
|
- If the lane is meant to support scalable outbound, do not stop at a merely borderline workable result when obvious expansion steps remain.
|
|
@@ -114,6 +114,7 @@ NEVER do these:
|
|
|
114
114
|
|
|
115
115
|
<filter_format>
|
|
116
116
|
ALL filter values MUST include id, text, and selectionType.
|
|
117
|
+
Pass `filters` as an array of objects. Do not stringify filters as JSON.
|
|
117
118
|
|
|
118
119
|
CORRECT:
|
|
119
120
|
|
|
@@ -145,6 +146,21 @@ WRONG:
|
|
|
145
146
|
|
|
146
147
|
</filter_format>
|
|
147
148
|
|
|
149
|
+
<result_validation>
|
|
150
|
+
After every `search_sales_nav` call, sanity-check the returned result before
|
|
151
|
+
using it in a source decision:
|
|
152
|
+
|
|
153
|
+
- `searchUrl` should include a `filters:List(...)` query, not only `keywords`.
|
|
154
|
+
- The sample rows should visibly match the intended role/company lane.
|
|
155
|
+
- The total result count should be plausible for the filters used.
|
|
156
|
+
|
|
157
|
+
If filters did not apply, the search errors, or the result count is obviously
|
|
158
|
+
unfiltered, do not present Sales Nav as a valid lane. Retry once with clean
|
|
159
|
+
filter objects if the issue was formatting. If it still fails, say plainly:
|
|
160
|
+
"Sales Nav did not apply the filters cleanly, so I’m not using it for this
|
|
161
|
+
decision." Then continue with Signals or Prospeo if they have usable evidence.
|
|
162
|
+
</result_validation>
|
|
163
|
+
|
|
148
164
|
<static_filters>
|
|
149
165
|
These filters need NO lookup - use these IDs directly:
|
|
150
166
|
|