@sellable/mcp 0.1.149 → 0.1.151
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 +8 -4
- package/agents/post-find-leads-message-scout.md +2 -2
- package/agents/source-scout-prospeo-contact.md +12 -5
- package/agents/source-scout-sales-nav.md +13 -3
- package/dist/tools/leads.d.ts +2 -1
- package/dist/tools/leads.js +162 -15
- package/dist/tools/prompts.d.ts +1 -0
- package/dist/tools/prompts.js +4 -3
- package/dist/tools/registry.d.ts +9 -1
- package/dist/tools/rows.d.ts +1 -0
- package/dist/tools/rows.js +2 -0
- package/dist/tools/rubrics.d.ts +55 -23
- package/dist/tools/rubrics.js +95 -10
- package/package.json +1 -1
- package/skills/create-campaign/SKILL.md +57 -29
- package/skills/create-campaign/core/providers/apollo.json +4 -2
- package/skills/create-campaign/core/providers/prospeo.json +3 -2
- package/skills/create-campaign/references/provider-selection-strategy.md +66 -25
- package/skills/create-campaign-v2/SKILL.md +67 -37
- package/skills/create-campaign-v2/SOUL.md +11 -7
- package/skills/create-campaign-v2/core/flow.v2.json +70 -47
- package/skills/create-campaign-v2/references/approval-gate-framing.md +7 -8
- package/skills/create-campaign-v2/references/sample-validation-loop.md +9 -5
- package/skills/create-campaign-v2/references/step-13-import-leads.md +10 -4
- package/skills/create-campaign-v2/references/step-15-re-cascade.md +12 -7
- package/skills/create-campaign-v2/references/watch-guide-narration.md +16 -13
- package/skills/create-campaign-v2-tail/SKILL.md +24 -16
- package/skills/providers/apollo.md +8 -1
- package/skills/providers/prospeo.md +11 -1
- package/skills/providers/sales-nav.md +1 -1
- package/skills/research/config.json +9 -0
- package/skills/create-campaign-v2/references/message-review-safety-gate.md +0 -162
package/dist/tools/rubrics.d.ts
CHANGED
|
@@ -33,6 +33,7 @@ type WaitForRubricResultsInput = {
|
|
|
33
33
|
tableId?: string;
|
|
34
34
|
targetCount?: number;
|
|
35
35
|
minPassedCount?: number;
|
|
36
|
+
minMessagesCount?: number;
|
|
36
37
|
timeoutMs?: number;
|
|
37
38
|
intervalMs?: number;
|
|
38
39
|
includeRows?: boolean;
|
|
@@ -114,6 +115,7 @@ export declare const rubricToolDefinitions: ({
|
|
|
114
115
|
tableId?: undefined;
|
|
115
116
|
targetCount?: undefined;
|
|
116
117
|
minPassedCount?: undefined;
|
|
118
|
+
minMessagesCount?: undefined;
|
|
117
119
|
timeoutMs?: undefined;
|
|
118
120
|
intervalMs?: undefined;
|
|
119
121
|
includeRows?: undefined;
|
|
@@ -147,6 +149,7 @@ export declare const rubricToolDefinitions: ({
|
|
|
147
149
|
tableId?: undefined;
|
|
148
150
|
targetCount?: undefined;
|
|
149
151
|
minPassedCount?: undefined;
|
|
152
|
+
minMessagesCount?: undefined;
|
|
150
153
|
timeoutMs?: undefined;
|
|
151
154
|
intervalMs?: undefined;
|
|
152
155
|
includeRows?: undefined;
|
|
@@ -205,6 +208,7 @@ export declare const rubricToolDefinitions: ({
|
|
|
205
208
|
tableId?: undefined;
|
|
206
209
|
targetCount?: undefined;
|
|
207
210
|
minPassedCount?: undefined;
|
|
211
|
+
minMessagesCount?: undefined;
|
|
208
212
|
timeoutMs?: undefined;
|
|
209
213
|
intervalMs?: undefined;
|
|
210
214
|
includeRows?: undefined;
|
|
@@ -263,6 +267,7 @@ export declare const rubricToolDefinitions: ({
|
|
|
263
267
|
tableId?: undefined;
|
|
264
268
|
targetCount?: undefined;
|
|
265
269
|
minPassedCount?: undefined;
|
|
270
|
+
minMessagesCount?: undefined;
|
|
266
271
|
timeoutMs?: undefined;
|
|
267
272
|
intervalMs?: undefined;
|
|
268
273
|
includeRows?: undefined;
|
|
@@ -323,6 +328,7 @@ export declare const rubricToolDefinitions: ({
|
|
|
323
328
|
tableId?: undefined;
|
|
324
329
|
targetCount?: undefined;
|
|
325
330
|
minPassedCount?: undefined;
|
|
331
|
+
minMessagesCount?: undefined;
|
|
326
332
|
timeoutMs?: undefined;
|
|
327
333
|
intervalMs?: undefined;
|
|
328
334
|
includeRows?: undefined;
|
|
@@ -353,6 +359,7 @@ export declare const rubricToolDefinitions: ({
|
|
|
353
359
|
tableId?: undefined;
|
|
354
360
|
targetCount?: undefined;
|
|
355
361
|
minPassedCount?: undefined;
|
|
362
|
+
minMessagesCount?: undefined;
|
|
356
363
|
timeoutMs?: undefined;
|
|
357
364
|
intervalMs?: undefined;
|
|
358
365
|
includeRows?: undefined;
|
|
@@ -383,6 +390,7 @@ export declare const rubricToolDefinitions: ({
|
|
|
383
390
|
tableId?: undefined;
|
|
384
391
|
targetCount?: undefined;
|
|
385
392
|
minPassedCount?: undefined;
|
|
393
|
+
minMessagesCount?: undefined;
|
|
386
394
|
timeoutMs?: undefined;
|
|
387
395
|
intervalMs?: undefined;
|
|
388
396
|
includeRows?: undefined;
|
|
@@ -412,6 +420,10 @@ export declare const rubricToolDefinitions: ({
|
|
|
412
420
|
type: string;
|
|
413
421
|
description: string;
|
|
414
422
|
};
|
|
423
|
+
minMessagesCount: {
|
|
424
|
+
type: string;
|
|
425
|
+
description: string;
|
|
426
|
+
};
|
|
415
427
|
timeoutMs: {
|
|
416
428
|
type: string;
|
|
417
429
|
description: string;
|
|
@@ -508,6 +520,12 @@ export declare function checkRubric(input: CheckRubricInput): Promise<{
|
|
|
508
520
|
export declare function waitForRubricResults(input: WaitForRubricResultsInput): Promise<{
|
|
509
521
|
stats: WorkflowTableStats;
|
|
510
522
|
rows?: import("./rows.js").LightweightRow[] | undefined;
|
|
523
|
+
messageGeneration?: {
|
|
524
|
+
completed: number;
|
|
525
|
+
passingGeneratedMessages: number;
|
|
526
|
+
minMessagesCount: number;
|
|
527
|
+
floorMet: boolean;
|
|
528
|
+
} | undefined;
|
|
511
529
|
ready: boolean;
|
|
512
530
|
attempts: number;
|
|
513
531
|
elapsedMs: number;
|
|
@@ -520,28 +538,14 @@ export declare function waitForRubricResults(input: WaitForRubricResultsInput):
|
|
|
520
538
|
targetCount: number;
|
|
521
539
|
pending?: undefined;
|
|
522
540
|
};
|
|
523
|
-
reason?: undefined;
|
|
524
|
-
partialResult?: undefined;
|
|
525
|
-
diagnostic?: undefined;
|
|
526
|
-
guidance?: undefined;
|
|
527
541
|
} | {
|
|
528
542
|
stats: WorkflowTableStats;
|
|
529
543
|
rows?: import("./rows.js").LightweightRow[] | undefined;
|
|
530
|
-
ready: boolean;
|
|
531
|
-
partial: boolean;
|
|
532
|
-
reason: string;
|
|
533
|
-
attempts: number;
|
|
534
|
-
elapsedMs: number;
|
|
535
|
-
tableId: string;
|
|
536
|
-
passRate: {
|
|
537
|
-
completed: number;
|
|
538
|
-
passed: number;
|
|
539
|
-
pending: number;
|
|
540
|
-
percent: number;
|
|
541
|
-
targetCount: number;
|
|
542
|
-
minPassedCount: number;
|
|
543
|
-
};
|
|
544
544
|
partialResult: {
|
|
545
|
+
messagesCount?: number | undefined;
|
|
546
|
+
passingGeneratedMessages?: number | undefined;
|
|
547
|
+
minMessagesCount?: number | undefined;
|
|
548
|
+
messageFloorMet?: boolean | undefined;
|
|
545
549
|
completed: number;
|
|
546
550
|
passed: number;
|
|
547
551
|
pending: number;
|
|
@@ -551,23 +555,32 @@ export declare function waitForRubricResults(input: WaitForRubricResultsInput):
|
|
|
551
555
|
enoughToDiagnose: boolean;
|
|
552
556
|
floorMet: boolean;
|
|
553
557
|
};
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
558
|
+
messageGeneration?: {
|
|
559
|
+
completed: number;
|
|
560
|
+
passingGeneratedMessages: number;
|
|
561
|
+
minMessagesCount: number;
|
|
562
|
+
floorMet: boolean;
|
|
563
|
+
} | undefined;
|
|
557
564
|
ready: boolean;
|
|
565
|
+
partial: boolean;
|
|
558
566
|
reason: string;
|
|
559
567
|
attempts: number;
|
|
560
568
|
elapsedMs: number;
|
|
561
569
|
tableId: string;
|
|
562
570
|
passRate: {
|
|
563
|
-
minPassedCount?: number | undefined;
|
|
564
571
|
completed: number;
|
|
565
572
|
passed: number;
|
|
566
573
|
pending: number;
|
|
567
574
|
percent: number;
|
|
568
575
|
targetCount: number;
|
|
576
|
+
minPassedCount: number;
|
|
569
577
|
};
|
|
578
|
+
} | {
|
|
570
579
|
partialResult: {
|
|
580
|
+
messagesCount?: number | undefined;
|
|
581
|
+
passingGeneratedMessages?: number | undefined;
|
|
582
|
+
minMessagesCount?: number | undefined;
|
|
583
|
+
messageFloorMet?: boolean | undefined;
|
|
571
584
|
enoughToDiagnose: boolean;
|
|
572
585
|
floorMet: boolean;
|
|
573
586
|
minPassedCount?: number | undefined;
|
|
@@ -581,12 +594,31 @@ export declare function waitForRubricResults(input: WaitForRubricResultsInput):
|
|
|
581
594
|
totalRows: number;
|
|
582
595
|
enrichedCount: number | undefined;
|
|
583
596
|
needsEnrichCount: number | undefined;
|
|
584
|
-
messagesCount: number
|
|
597
|
+
messagesCount: number;
|
|
585
598
|
needsApprovalCount: number | undefined;
|
|
586
599
|
processingCount: number | undefined;
|
|
587
600
|
failedCount: number | undefined;
|
|
588
601
|
};
|
|
589
602
|
guidance: string;
|
|
590
603
|
stats: WorkflowTableStats | null;
|
|
604
|
+
messageGeneration?: {
|
|
605
|
+
completed: number;
|
|
606
|
+
passingGeneratedMessages: number;
|
|
607
|
+
minMessagesCount: number;
|
|
608
|
+
floorMet: boolean;
|
|
609
|
+
} | undefined;
|
|
610
|
+
ready: boolean;
|
|
611
|
+
reason: string;
|
|
612
|
+
attempts: number;
|
|
613
|
+
elapsedMs: number;
|
|
614
|
+
tableId: string;
|
|
615
|
+
passRate: {
|
|
616
|
+
minPassedCount?: number | undefined;
|
|
617
|
+
completed: number;
|
|
618
|
+
passed: number;
|
|
619
|
+
pending: number;
|
|
620
|
+
percent: number;
|
|
621
|
+
targetCount: number;
|
|
622
|
+
};
|
|
591
623
|
}>;
|
|
592
624
|
export {};
|
package/dist/tools/rubrics.js
CHANGED
|
@@ -9,6 +9,11 @@ const DEFAULT_INTERVAL_MS = 2000;
|
|
|
9
9
|
function sleep(ms) {
|
|
10
10
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
11
11
|
}
|
|
12
|
+
function countPassingGeneratedMessages(rowSnapshot) {
|
|
13
|
+
if (!rowSnapshot?.rows?.length)
|
|
14
|
+
return 0;
|
|
15
|
+
return rowSnapshot.rows.filter((row) => row.icpPassed === true && Boolean(row.message?.trim())).length;
|
|
16
|
+
}
|
|
12
17
|
function normalizeRubricItemDefaults(item) {
|
|
13
18
|
return {
|
|
14
19
|
...item,
|
|
@@ -393,6 +398,10 @@ export const rubricToolDefinitions = [
|
|
|
393
398
|
type: "number",
|
|
394
399
|
description: "Optional pass floor for bounded create-campaign samples. When this floor is met, the tool returns ready:true with partial:true instead of waiting for every target row to finish.",
|
|
395
400
|
},
|
|
401
|
+
minMessagesCount: {
|
|
402
|
+
type: "number",
|
|
403
|
+
description: "Optional generated-message floor. When provided with minPassedCount, the tool waits until both floors are met so create-campaign-v2 can review the first passing generated message without waiting for the full batch.",
|
|
404
|
+
},
|
|
396
405
|
timeoutMs: {
|
|
397
406
|
type: "number",
|
|
398
407
|
description: `Max time to wait in ms (default ${DEFAULT_TIMEOUT_MS}).`,
|
|
@@ -688,6 +697,7 @@ export async function waitForRubricResults(input) {
|
|
|
688
697
|
const intervalMs = Math.max(500, input.intervalMs ?? DEFAULT_INTERVAL_MS);
|
|
689
698
|
const targetCount = resolveMaxProspects(input.targetCount);
|
|
690
699
|
const minPassedCount = resolveMinPassedCount(input.minPassedCount);
|
|
700
|
+
const minMessagesCount = resolveMinPassedCount(input.minMessagesCount);
|
|
691
701
|
const includeRows = input.includeRows !== false;
|
|
692
702
|
let tableId = input.tableId;
|
|
693
703
|
if (!tableId && input.campaignOfferId) {
|
|
@@ -709,19 +719,34 @@ export async function waitForRubricResults(input) {
|
|
|
709
719
|
const totalRows = stats.totalRows ?? 0;
|
|
710
720
|
const effectiveTarget = totalRows > 0 ? Math.min(targetCount, totalRows) : targetCount;
|
|
711
721
|
const pending = Math.max(effectiveTarget - completed, 0);
|
|
722
|
+
const messagesCount = stats.messagesCount ?? 0;
|
|
712
723
|
const failedCount = stats.failedCount ?? 0;
|
|
713
724
|
const processingCount = stats.processingCount ?? 0;
|
|
714
725
|
const queuedCount = stats.queuedCount ?? 0;
|
|
715
726
|
const cancellableCount = stats.cancellableCount ?? 0;
|
|
716
727
|
const minPassFloorMet = minPassedCount !== null && passed >= minPassedCount;
|
|
728
|
+
const rawMessageFloorMet = minMessagesCount === null || messagesCount >= minMessagesCount;
|
|
729
|
+
let rowSnapshotForMessageCheck = null;
|
|
730
|
+
let passingGeneratedMessagesCount = null;
|
|
731
|
+
if (minMessagesCount !== null && minPassFloorMet && rawMessageFloorMet) {
|
|
732
|
+
rowSnapshotForMessageCheck = await getTableRowsMinimal(tableId, {
|
|
733
|
+
limit: effectiveTarget,
|
|
734
|
+
includeMessages: true,
|
|
735
|
+
});
|
|
736
|
+
passingGeneratedMessagesCount = countPassingGeneratedMessages(rowSnapshotForMessageCheck);
|
|
737
|
+
}
|
|
738
|
+
const messageFloorMet = minMessagesCount === null ||
|
|
739
|
+
(passingGeneratedMessagesCount ?? 0) >= minMessagesCount;
|
|
740
|
+
const earlyFloorMet = minPassFloorMet && messageFloorMet;
|
|
717
741
|
const unresolvedRowsResolvedAsFailures = pending > 0 && completed + failedCount >= effectiveTarget;
|
|
718
742
|
const noActiveProcessing = processingCount === 0 && queuedCount === 0 && cancellableCount === 0;
|
|
719
|
-
if (completed >= effectiveTarget) {
|
|
743
|
+
if (completed >= effectiveTarget && messageFloorMet) {
|
|
720
744
|
const percent = completed > 0 ? Math.round((passed / completed) * 100) : 0;
|
|
721
745
|
const rowSnapshot = includeRows
|
|
722
|
-
?
|
|
723
|
-
|
|
724
|
-
|
|
746
|
+
? (rowSnapshotForMessageCheck ??
|
|
747
|
+
(await getTableRowsMinimal(tableId, {
|
|
748
|
+
limit: effectiveTarget,
|
|
749
|
+
})))
|
|
725
750
|
: null;
|
|
726
751
|
return {
|
|
727
752
|
ready: true,
|
|
@@ -735,11 +760,21 @@ export async function waitForRubricResults(input) {
|
|
|
735
760
|
targetCount: effectiveTarget,
|
|
736
761
|
...(minPassedCount !== null ? { minPassedCount } : {}),
|
|
737
762
|
},
|
|
763
|
+
...(minMessagesCount !== null
|
|
764
|
+
? {
|
|
765
|
+
messageGeneration: {
|
|
766
|
+
completed: messagesCount,
|
|
767
|
+
passingGeneratedMessages: passingGeneratedMessagesCount ?? 0,
|
|
768
|
+
minMessagesCount,
|
|
769
|
+
floorMet: true,
|
|
770
|
+
},
|
|
771
|
+
}
|
|
772
|
+
: {}),
|
|
738
773
|
...(rowSnapshot ? { rows: rowSnapshot.rows } : {}),
|
|
739
774
|
stats,
|
|
740
775
|
};
|
|
741
776
|
}
|
|
742
|
-
if (
|
|
777
|
+
if (earlyFloorMet) {
|
|
743
778
|
const percent = completed > 0 ? Math.round((passed / completed) * 100) : 0;
|
|
744
779
|
const reason = !noActiveProcessing
|
|
745
780
|
? "min_passed_count_met_with_active_processing"
|
|
@@ -747,9 +782,10 @@ export async function waitForRubricResults(input) {
|
|
|
747
782
|
? "min_passed_count_met_with_resolved_failures"
|
|
748
783
|
: "min_passed_count_met_no_active_processing";
|
|
749
784
|
const rowSnapshot = includeRows
|
|
750
|
-
?
|
|
751
|
-
|
|
752
|
-
|
|
785
|
+
? (rowSnapshotForMessageCheck ??
|
|
786
|
+
(await getTableRowsMinimal(tableId, {
|
|
787
|
+
limit: effectiveTarget,
|
|
788
|
+
})))
|
|
753
789
|
: null;
|
|
754
790
|
return {
|
|
755
791
|
ready: true,
|
|
@@ -766,6 +802,16 @@ export async function waitForRubricResults(input) {
|
|
|
766
802
|
targetCount: effectiveTarget,
|
|
767
803
|
minPassedCount,
|
|
768
804
|
},
|
|
805
|
+
...(minMessagesCount !== null
|
|
806
|
+
? {
|
|
807
|
+
messageGeneration: {
|
|
808
|
+
completed: messagesCount,
|
|
809
|
+
passingGeneratedMessages: passingGeneratedMessagesCount ?? 0,
|
|
810
|
+
minMessagesCount,
|
|
811
|
+
floorMet: true,
|
|
812
|
+
},
|
|
813
|
+
}
|
|
814
|
+
: {}),
|
|
769
815
|
partialResult: {
|
|
770
816
|
completed,
|
|
771
817
|
passed,
|
|
@@ -775,6 +821,14 @@ export async function waitForRubricResults(input) {
|
|
|
775
821
|
minPassedCount,
|
|
776
822
|
enoughToDiagnose: true,
|
|
777
823
|
floorMet: true,
|
|
824
|
+
...(minMessagesCount !== null
|
|
825
|
+
? {
|
|
826
|
+
messagesCount,
|
|
827
|
+
passingGeneratedMessages: passingGeneratedMessagesCount ?? 0,
|
|
828
|
+
minMessagesCount,
|
|
829
|
+
messageFloorMet: true,
|
|
830
|
+
}
|
|
831
|
+
: {}),
|
|
778
832
|
},
|
|
779
833
|
...(rowSnapshot ? { rows: rowSnapshot.rows } : {}),
|
|
780
834
|
stats,
|
|
@@ -785,9 +839,22 @@ export async function waitForRubricResults(input) {
|
|
|
785
839
|
const completed = lastStats?.passRate?.completed ?? 0;
|
|
786
840
|
const passed = lastStats?.passRate?.passed ?? 0;
|
|
787
841
|
const percent = completed > 0 ? Math.round((passed / completed) * 100) : 0;
|
|
842
|
+
const messagesCount = lastStats?.messagesCount ?? 0;
|
|
788
843
|
const totalRows = lastStats?.totalRows ?? 0;
|
|
789
844
|
const effectiveTarget = totalRows > 0 ? Math.min(targetCount, totalRows) : targetCount;
|
|
790
845
|
const pending = Math.max(effectiveTarget - completed, 0);
|
|
846
|
+
let timeoutPassingGeneratedMessagesCount = null;
|
|
847
|
+
if (minMessagesCount !== null) {
|
|
848
|
+
try {
|
|
849
|
+
timeoutPassingGeneratedMessagesCount = countPassingGeneratedMessages(await getTableRowsMinimal(tableId, {
|
|
850
|
+
limit: effectiveTarget,
|
|
851
|
+
includeMessages: true,
|
|
852
|
+
}));
|
|
853
|
+
}
|
|
854
|
+
catch {
|
|
855
|
+
timeoutPassingGeneratedMessagesCount = null;
|
|
856
|
+
}
|
|
857
|
+
}
|
|
791
858
|
return {
|
|
792
859
|
ready: false,
|
|
793
860
|
reason: "timeout",
|
|
@@ -802,6 +869,16 @@ export async function waitForRubricResults(input) {
|
|
|
802
869
|
targetCount: effectiveTarget,
|
|
803
870
|
...(minPassedCount !== null ? { minPassedCount } : {}),
|
|
804
871
|
},
|
|
872
|
+
...(minMessagesCount !== null
|
|
873
|
+
? {
|
|
874
|
+
messageGeneration: {
|
|
875
|
+
completed: messagesCount,
|
|
876
|
+
passingGeneratedMessages: timeoutPassingGeneratedMessagesCount ?? 0,
|
|
877
|
+
minMessagesCount,
|
|
878
|
+
floorMet: (timeoutPassingGeneratedMessagesCount ?? 0) >= minMessagesCount,
|
|
879
|
+
},
|
|
880
|
+
}
|
|
881
|
+
: {}),
|
|
805
882
|
partialResult: {
|
|
806
883
|
completed,
|
|
807
884
|
passed,
|
|
@@ -811,17 +888,25 @@ export async function waitForRubricResults(input) {
|
|
|
811
888
|
...(minPassedCount !== null ? { minPassedCount } : {}),
|
|
812
889
|
enoughToDiagnose: completed > 0,
|
|
813
890
|
floorMet: minPassedCount !== null && passed >= minPassedCount,
|
|
891
|
+
...(minMessagesCount !== null
|
|
892
|
+
? {
|
|
893
|
+
messagesCount,
|
|
894
|
+
passingGeneratedMessages: timeoutPassingGeneratedMessagesCount ?? 0,
|
|
895
|
+
minMessagesCount,
|
|
896
|
+
messageFloorMet: (timeoutPassingGeneratedMessagesCount ?? 0) >= minMessagesCount,
|
|
897
|
+
}
|
|
898
|
+
: {}),
|
|
814
899
|
},
|
|
815
900
|
diagnostic: {
|
|
816
901
|
totalRows,
|
|
817
902
|
enrichedCount: lastStats?.enrichedCount,
|
|
818
903
|
needsEnrichCount: lastStats?.needsEnrichCount,
|
|
819
|
-
messagesCount
|
|
904
|
+
messagesCount,
|
|
820
905
|
needsApprovalCount: lastStats?.needsApprovalCount,
|
|
821
906
|
processingCount: lastStats?.processingCount,
|
|
822
907
|
failedCount: lastStats?.failedCount,
|
|
823
908
|
},
|
|
824
|
-
guidance: "If this is create-campaign-v2 validate-sample, do not repeat waits indefinitely. Use passRate/stats to diagnose and surface sample_revision_required before Settings when the sample is under the pass floor
|
|
909
|
+
guidance: "If this is create-campaign-v2 validate-sample, do not repeat waits indefinitely. Use passRate/stats to diagnose and surface sample_revision_required before Settings when the sample is under the pass floor. If minMessagesCount is set, one passing generated message is enough to start review; do not wait for a stronger sample.",
|
|
825
910
|
stats: lastStats,
|
|
826
911
|
};
|
|
827
912
|
}
|
package/package.json
CHANGED
|
@@ -143,11 +143,34 @@ why. Do not call `search_signals`, `search_sales_nav`, `search_prospeo`,
|
|
|
143
143
|
`fetch_post_engagers`, or provider-scoped subagents until the user approves this
|
|
144
144
|
source plan or explicitly chooses a different source.
|
|
145
145
|
|
|
146
|
+
For hiring-led campaigns, do not default to Sales Nav just because the target is
|
|
147
|
+
a role search. Prospeo is the primary lane when the brief asks for companies
|
|
148
|
+
actively hiring specific roles, open-role signals, account/contact coverage, or
|
|
149
|
+
verified contacts at hiring companies because `search_prospeo` supports
|
|
150
|
+
`company_job_posting_hiring_for` and `company_job_posting_quantity`. Signal
|
|
151
|
+
Discovery can be a parallel or fallback lane when relevant hiring conversations
|
|
152
|
+
are likely. Sales Nav is useful for recent LinkedIn activity, role/title
|
|
153
|
+
precision, and referral paths, but it does not provide hiring-by-role filters;
|
|
154
|
+
say that distinction plainly in the source-plan gate.
|
|
155
|
+
|
|
146
156
|
After scouting, ask for a second approval on the concrete source action. For
|
|
147
157
|
Signal Discovery, name how many selected posts will be scraped, the target
|
|
148
158
|
engager/source-candidate volume, and the bounded review-batch size. For Sales
|
|
149
|
-
Nav or Prospeo, name the specific approved import lane
|
|
150
|
-
`import_leads` or `confirm_lead_list` until this second approval is
|
|
159
|
+
Nav or Prospeo, name the specific approved import lane and source lead count.
|
|
160
|
+
Do not call `import_leads` or `confirm_lead_list` until this second approval is
|
|
161
|
+
granted.
|
|
162
|
+
|
|
163
|
+
For Sales Nav and Prospeo, the second gate approves materializing the source
|
|
164
|
+
lead list, not importing only the review batch. Use the first-page/sample review
|
|
165
|
+
to calculate projected good fits: sampled fit rate after conservative cleanup,
|
|
166
|
+
raw pool size, source target, and expected good-fit count. If the projected
|
|
167
|
+
good-fit pool is below the campaign target (normally about 150+ usable
|
|
168
|
+
prospects unless source defaults say otherwise), keep refining/broadening
|
|
169
|
+
filters before asking for import approval. Once it clears target, approve
|
|
170
|
+
`import_leads` with the source-list `targetLeadCount` (up to the raw count or
|
|
171
|
+
provider max). Only after the source list is ready should `confirm_lead_list`
|
|
172
|
+
clone the bounded review batch into the campaign table.
|
|
173
|
+
|
|
151
174
|
For Signal Discovery, the customer-facing approval card must use the exact
|
|
152
175
|
action shape "Approve scraping N Signal Discovery posts?" and the chat summary
|
|
153
176
|
should be a compact `## Source Recommendation` block with:
|
|
@@ -158,12 +181,13 @@ should be a compact `## Source Recommendation` block with:
|
|
|
158
181
|
- planning floor: continue with Signal Discovery only when sampled/projected
|
|
159
182
|
fit is at least 10% after cleanup; below that, move to Sales Nav recent
|
|
160
183
|
activity instead of scraping noisy engagers
|
|
161
|
-
- review checkpoint:
|
|
184
|
+
- review checkpoint: after the source list exists, clone only the bounded
|
|
185
|
+
review batch into the campaign for fit and message review
|
|
162
186
|
- a selected-post table with post author/topic, why it fits, and visible
|
|
163
187
|
engagement
|
|
164
188
|
- total visible pool and estimated good-fit pool
|
|
165
|
-
- first pass: build the source list
|
|
166
|
-
batch
|
|
189
|
+
- first pass: build the source list at the approved source-candidate target,
|
|
190
|
+
then clone only the bounded review batch into the campaign
|
|
167
191
|
- fallback: switch to Sales Nav recent activity if sampled/projected fit falls
|
|
168
192
|
below 10%, or if the review batch is vendor-heavy, agency-heavy, or off-ICP
|
|
169
193
|
|
|
@@ -171,7 +195,8 @@ When the user has not supplied a source and multiple source angles are viable,
|
|
|
171
195
|
scout those angles as independent branches when the host can actually do it:
|
|
172
196
|
LinkedIn Engagement / active post engagers (internal `signal-discovery`
|
|
173
197
|
provider prompt), Sales Nav / title + company filters, and Prospeo Contact /
|
|
174
|
-
domains
|
|
198
|
+
domains, hiring filters, or broad verified-contact expansion when relevant. In
|
|
199
|
+
Codex, explicitly spawn the named custom scouts
|
|
175
200
|
`source-scout-linkedin-engagement`, `source-scout-sales-nav`, and
|
|
176
201
|
`source-scout-prospeo-contact` for the credible lanes only when the current host
|
|
177
202
|
exposes those names; Codex does not infer subagent fan-out from generic source
|
|
@@ -193,16 +218,16 @@ that we are pulling sample engagers from these posts to confirm the ICP is
|
|
|
193
218
|
actually engaging and the source is viable.
|
|
194
219
|
|
|
195
220
|
After the bounded review batch exists, use the same registry pattern for
|
|
196
|
-
post-lead work
|
|
197
|
-
`
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
with MCP tools/assets.
|
|
221
|
+
post-lead work, but do not load that registry or any deep filter/message prompt
|
|
222
|
+
before the filter-choice question. After `confirm_lead_list`, ask add filters
|
|
223
|
+
vs skip filters immediately. Once the user answers, launch the message scout
|
|
224
|
+
from the same campaign/table basis. If the user chooses filters, also launch the
|
|
225
|
+
filter-leads scout, move to Filter Rules, save rubrics, then keep the browser on
|
|
226
|
+
Filter Leads while the message recommendation is reviewed. If the user skips
|
|
227
|
+
filters, move to Messages/message review. Workflow cell execution still waits
|
|
228
|
+
for filter and template approval. AI Generated is an explicit opt-out from the
|
|
229
|
+
template path. If the post-lead agents are absent, the main thread still
|
|
230
|
+
orchestrates the same branches from the compact context with MCP tools/assets.
|
|
206
231
|
|
|
207
232
|
Use rendered Markdown for user review surfaces, not fenced code blocks. Keep
|
|
208
233
|
lines short, use indexed section labels and bullets, and translate internal
|
|
@@ -615,12 +640,12 @@ updates.
|
|
|
615
640
|
available. The worker and parent-thread fallback must load the full
|
|
616
641
|
long-form `generate-messages` prompt with
|
|
617
642
|
`mcp__sellable__get_subskill_prompt({ subskillName: "generate-messages", offset, limit })`
|
|
618
|
-
until `hasMore=false`.
|
|
619
|
-
|
|
620
|
-
campaign state, campaign brief content, selected source state, and
|
|
621
|
-
review-batch rows as the source of truth; do not read stale local
|
|
622
|
-
such as `message-validation.md`, inspect the database directly, or
|
|
623
|
-
local validation artifacts from general knowledge.
|
|
643
|
+
until `hasMore=false`. Message review requires Message Draft Builder output:
|
|
644
|
+
do not draft from a checklist, local markdown artifact, or parent-thread
|
|
645
|
+
intuition. Use campaign state, campaign brief content, selected source state, and
|
|
646
|
+
imported review-batch rows as the source of truth; do not read stale local
|
|
647
|
+
markdown such as `message-validation.md`, inspect the database directly, or
|
|
648
|
+
synthesize local validation artifacts from general knowledge.
|
|
624
649
|
5. Create the campaign shell early with the v1 brief so the user can open the
|
|
625
650
|
watch link and see useful setup state immediately. Import only the first
|
|
626
651
|
bounded review batch after the source is attached to the campaign; do not
|
|
@@ -631,13 +656,16 @@ updates.
|
|
|
631
656
|
call `mcp__sellable__update_campaign({ campaignId, enableICPFilters: true, currentStep: "create-icp-rubric", watchNarration })`
|
|
632
657
|
so the watched app moves to Filter Rules while rubrics are drafted/saved.
|
|
633
658
|
After rubrics save, move the watched app to `apply-icp-rubric` / Filter
|
|
634
|
-
Leads and say the fit rules are saved;
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
659
|
+
Leads and say the fit rules are saved; the background message scout is
|
|
660
|
+
preparing the message recommendation and approval comes next while the
|
|
661
|
+
browser stays on Filter Leads. If filters are skipped, move the watched app to
|
|
662
|
+
Messages/message review and wait for message approval there. After approval,
|
|
663
|
+
save the template to the campaign brief, then queue the bounded review-batch
|
|
664
|
+
`enrichCellId` cells to kick off enrichment/filtering. Move to Messages only
|
|
665
|
+
after at least one review row passes and Generate Message cells are running or
|
|
666
|
+
ready.
|
|
667
|
+
Product Generate Message cells must not run before that template/token
|
|
668
|
+
approval.
|
|
641
669
|
Do not ask the user to approve the brief before shell creation unless they
|
|
642
670
|
explicitly requested a no-write draft; the shell itself is the review surface.
|
|
643
671
|
6. The main thread owns watch navigation. Call
|
|
@@ -21,10 +21,12 @@
|
|
|
21
21
|
"priority": 3,
|
|
22
22
|
"useWhen": [
|
|
23
23
|
"You need technology stack targeting",
|
|
24
|
-
"You need bulk domain list targeting",
|
|
25
24
|
"You need high volume and can accept lower reply rates"
|
|
26
25
|
],
|
|
27
|
-
"avoidWhen": [
|
|
26
|
+
"avoidWhen": [
|
|
27
|
+
"The user supplied a company-domain list; use Prospeo domainFilterId first",
|
|
28
|
+
"High reply rate and LinkedIn activity are the top priority"
|
|
29
|
+
],
|
|
28
30
|
"reason": "Best for scale and firmographic/technographic filters, but lower LinkedIn activity by default.",
|
|
29
31
|
"prose": "Since you need to find **{icp}**, I'd recommend **Apollo**.\n\nHere's why:\n- Apollo has technology filters that other sources don't\n- We can find people at companies using {techStack}\n- Heads up: reply rates will be lower since not all leads are active on LinkedIn\n\nShould I search Apollo for {techStack} users?"
|
|
30
32
|
},
|
|
@@ -21,11 +21,12 @@
|
|
|
21
21
|
"priority": 2,
|
|
22
22
|
"useWhen": [
|
|
23
23
|
"You want Prospeo filters or domain-based search",
|
|
24
|
+
"You need companies hiring for specific roles using job-posting filters",
|
|
24
25
|
"You need high deliverability from Prospeo"
|
|
25
26
|
],
|
|
26
27
|
"avoidWhen": ["You need LinkedIn activity filters"],
|
|
27
|
-
"reason": "Strong for Prospeo-specific filters and domain lists.",
|
|
28
|
-
"prose": "Since you're targeting **{icp}**, I'd recommend **Prospeo**.\n\nHere's why:\n- Prospeo
|
|
28
|
+
"reason": "Strong for hiring-led search, Prospeo-specific filters, verified contacts, and domain lists.",
|
|
29
|
+
"prose": "Since you're targeting **{icp}**, I'd recommend **Prospeo**.\n\nHere's why:\n- Prospeo can filter for companies hiring specific roles with job-posting filters\n- We can pair those company hiring signals with buyer/referrer titles\n- Good for verified-contact coverage when Sales Nav cannot filter by hiring role\n\nShould I search Prospeo for {icp}?"
|
|
29
30
|
},
|
|
30
31
|
"askOption": {
|
|
31
32
|
"label": "Prospeo",
|