@coldiq/mcp 0.3.3 → 0.3.5
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/executor.d.ts +6 -0
- package/dist/executor.d.ts.map +1 -1
- package/dist/executor.js +18 -1
- package/dist/executor.js.map +1 -1
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +25 -8
- package/dist/registry.js.map +1 -1
- package/dist/tools/find-emails.d.ts.map +1 -1
- package/dist/tools/find-emails.js +46 -1
- package/dist/tools/find-emails.js.map +1 -1
- package/dist/utils/provider-display.d.ts +6 -0
- package/dist/utils/provider-display.d.ts.map +1 -0
- package/dist/utils/provider-display.js +140 -0
- package/dist/utils/provider-display.js.map +1 -0
- package/dist/utils/selection-insight.d.ts +20 -0
- package/dist/utils/selection-insight.d.ts.map +1 -0
- package/dist/utils/selection-insight.js +295 -0
- package/dist/utils/selection-insight.js.map +1 -0
- package/package.json +1 -1
- package/src/executor.ts +23 -1
- package/src/registry.ts +30 -8
- package/src/tools/find-emails.ts +43 -1
- package/src/utils/provider-display.ts +150 -0
- package/src/utils/selection-insight.ts +347 -0
- package/tests/executor.test.ts +77 -0
- package/tests/registry-find-signals.test.ts +15 -3
- package/tests/registry-search-jobs.test.ts +21 -0
- package/tests/tools/find-emails.test.ts +7 -7
- package/tests/utils/provider-display.test.ts +40 -0
- package/tests/utils/selection-insight.test.ts +114 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"selection-insight.js","sourceRoot":"","sources":["../../src/utils/selection-insight.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/src/executor.ts
CHANGED
|
@@ -1,11 +1,19 @@
|
|
|
1
1
|
import { callApi } from './client.js'
|
|
2
2
|
import { getProviders, getSearchWebProviders } from './registry.js'
|
|
3
3
|
import type { Capability, ProviderEntry } from './registry.js'
|
|
4
|
+
import { providerDisplayName } from './utils/provider-display.js'
|
|
5
|
+
import { buildSelectionInsight } from './utils/selection-insight.js'
|
|
4
6
|
|
|
5
7
|
export interface ExecutionResult {
|
|
6
8
|
data: unknown
|
|
7
9
|
_meta: {
|
|
8
10
|
provider: string
|
|
11
|
+
/** Clean branded display name for `provider` (never a raw slug or "Apify"). */
|
|
12
|
+
provider_name?: string
|
|
13
|
+
/** Data-quality-framed reason this provider was selected, for the chat surface. */
|
|
14
|
+
selection_insight?: string
|
|
15
|
+
/** Input dimensions that drove routing (e.g. ["tech-stack filter"]), for UI chips. */
|
|
16
|
+
selection_signals?: string[]
|
|
9
17
|
latencyMs: number
|
|
10
18
|
matchedFrom?: Record<string, string>
|
|
11
19
|
/** Net ColdIQ credits charged for this call (parsed from `X-ColdIQ-Credits-Charged`). */
|
|
@@ -306,7 +314,21 @@ export async function executeWithFallback(
|
|
|
306
314
|
|
|
307
315
|
if (hasResult) {
|
|
308
316
|
log(`${capability} → ${provider.id} ✓ (${result.latencyMs}ms)`)
|
|
309
|
-
const meta: ExecutionResult['_meta'] = {
|
|
317
|
+
const meta: ExecutionResult['_meta'] = {
|
|
318
|
+
provider: provider.id,
|
|
319
|
+
provider_name: providerDisplayName(provider.id),
|
|
320
|
+
latencyMs: result.latencyMs,
|
|
321
|
+
}
|
|
322
|
+
// `errors.length > 0` here means higher-ranked applicable providers returned
|
|
323
|
+
// nothing and we fell through — soften the insight wording accordingly.
|
|
324
|
+
const insight = buildSelectionInsight(capability, provider.id, input, {
|
|
325
|
+
wasFallback: errors.length > 0,
|
|
326
|
+
pinnedByUser: isConstrained,
|
|
327
|
+
})
|
|
328
|
+
if (insight) {
|
|
329
|
+
meta.selection_insight = insight.insight
|
|
330
|
+
if (insight.signals.length > 0) meta.selection_signals = insight.signals
|
|
331
|
+
}
|
|
310
332
|
if (options?.matchedFrom && Object.keys(options.matchedFrom).length > 0) {
|
|
311
333
|
meta.matchedFrom = options.matchedFrom
|
|
312
334
|
}
|
package/src/registry.ts
CHANGED
|
@@ -69,22 +69,44 @@ function isNonEmptyArray(v: unknown): boolean {
|
|
|
69
69
|
return Array.isArray(v) && v.length > 0
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
+
// TheirStack attaches a per-job `company_object` whose enrichment arrays dominate the
|
|
73
|
+
// payload (e.g. ~1,600-element technology_slugs/technology_names, plus long_description) —
|
|
74
|
+
// tens of KB per job. Drop these heavy fields while keeping company identity (name, domain,
|
|
75
|
+
// industry, employee_count, linkedin_url, founded_year, revenue, …).
|
|
76
|
+
const HEAVY_COMPANY_OBJECT_KEYS = [
|
|
77
|
+
'technology_slugs',
|
|
78
|
+
'technology_names',
|
|
79
|
+
'company_keywords',
|
|
80
|
+
'company_tags',
|
|
81
|
+
'keyword_slugs',
|
|
82
|
+
'long_description',
|
|
83
|
+
]
|
|
84
|
+
|
|
72
85
|
/**
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
*
|
|
86
|
+
* Trim a `{ data: Job[] }` provider response for lean payloads: drop job-level
|
|
87
|
+
* `description`/`description_html` (off by default; callers opt in via `include_description`)
|
|
88
|
+
* and slim each job's `company_object` by removing heavy enrichment arrays. Returns a new
|
|
89
|
+
* object; no-op when there's no `data` array.
|
|
76
90
|
*/
|
|
77
|
-
function
|
|
91
|
+
function trimJobPayload(data: unknown): unknown {
|
|
78
92
|
const d = data as { data?: unknown[] }
|
|
79
93
|
if (!Array.isArray(d.data)) return data
|
|
80
94
|
return {
|
|
81
95
|
...(d as Record<string, unknown>),
|
|
82
96
|
data: d.data.map((job) => {
|
|
83
97
|
if (!job || typeof job !== 'object') return job
|
|
84
|
-
const { description, description_html, ...rest } = job as Record<string, unknown>
|
|
98
|
+
const { description, description_html, company_object, ...rest } = job as Record<string, unknown>
|
|
85
99
|
void description
|
|
86
100
|
void description_html
|
|
87
|
-
|
|
101
|
+
if (company_object && typeof company_object === 'object' && !Array.isArray(company_object)) {
|
|
102
|
+
const slim = Object.fromEntries(
|
|
103
|
+
Object.entries(company_object as Record<string, unknown>).filter(
|
|
104
|
+
([k]) => !HEAVY_COMPANY_OBJECT_KEYS.includes(k),
|
|
105
|
+
),
|
|
106
|
+
)
|
|
107
|
+
return { ...rest, company_object: slim }
|
|
108
|
+
}
|
|
109
|
+
return company_object === undefined ? rest : { ...rest, company_object }
|
|
88
110
|
}),
|
|
89
111
|
}
|
|
90
112
|
}
|
|
@@ -2226,7 +2248,7 @@ const searchJobsProviders: ProviderEntry[] = [
|
|
|
2226
2248
|
// TheirStack returns full job descriptions in a passthrough response (tens of KB).
|
|
2227
2249
|
// career-site/LinkedIn gate descriptions upstream via descriptionType; TheirStack has
|
|
2228
2250
|
// no such flag, so strip them here unless the caller explicitly opts in.
|
|
2229
|
-
postFilter: (data, input) => (input.include_description === true ? data :
|
|
2251
|
+
postFilter: (data, input) => (input.include_description === true ? data : trimJobPayload(data)),
|
|
2230
2252
|
},
|
|
2231
2253
|
]
|
|
2232
2254
|
|
|
@@ -3256,7 +3278,7 @@ const findSignalsProviders: ProviderEntry[] = [
|
|
|
3256
3278
|
}),
|
|
3257
3279
|
hasResult: (data) => isNonEmptyArray((data as { data?: unknown[] }).data),
|
|
3258
3280
|
// Hiring signals don't need full descriptions; keep payloads lean.
|
|
3259
|
-
postFilter: (data) =>
|
|
3281
|
+
postFilter: (data) => trimJobPayload(data),
|
|
3260
3282
|
},
|
|
3261
3283
|
{
|
|
3262
3284
|
id: 'signalbase-hiring',
|
package/src/tools/find-emails.ts
CHANGED
|
@@ -2,6 +2,8 @@ import { z } from 'zod'
|
|
|
2
2
|
import { callApi, type ApiResponse } from '../client.js'
|
|
3
3
|
import { executeWithFallback, isExecutionError } from '../executor.js'
|
|
4
4
|
import { resolvePreferredProviders, buildAllFailedError, FIND_EMAILS_PROVIDERS } from '../utils/provider-resolver.js'
|
|
5
|
+
import { providerDisplayName } from '../utils/provider-display.js'
|
|
6
|
+
import { buildSelectionInsight } from '../utils/selection-insight.js'
|
|
5
7
|
|
|
6
8
|
// Single-find_email registry providers that the bulk pipeline does NOT already cover.
|
|
7
9
|
// Used as a fallback waterfall for residual misses after Prospeo + FullEnrich + Findymail + Icypeas.
|
|
@@ -462,6 +464,46 @@ export async function findEmailsHandler(input: Record<string, unknown>) {
|
|
|
462
464
|
meta.matchedFrom = resolved.matchedFrom
|
|
463
465
|
}
|
|
464
466
|
|
|
467
|
+
// Batch-level selection insight: the per-person waterfall returns a provider per
|
|
468
|
+
// result, so attribute the batch to the provider that resolved the most emails.
|
|
469
|
+
// Prospeo is the primary bulk step (Step 1); anything else means we relied on a
|
|
470
|
+
// fallback step, so soften the wording.
|
|
471
|
+
if (found > 0) {
|
|
472
|
+
const winCounts = new Map<string, number>()
|
|
473
|
+
for (const r of results) {
|
|
474
|
+
if (r.email && r.provider) winCounts.set(r.provider, (winCounts.get(r.provider) ?? 0) + 1)
|
|
475
|
+
}
|
|
476
|
+
// Tie-break deterministically by waterfall rank: scan in FIND_EMAILS_PROVIDERS
|
|
477
|
+
// order and replace only on a strictly greater count, so an equal-count primary
|
|
478
|
+
// (Prospeo, Step 1) is never displaced by a later fallback step — keeps the
|
|
479
|
+
// attribution stable regardless of people-input order.
|
|
480
|
+
let dominant: string | undefined
|
|
481
|
+
let best = 0
|
|
482
|
+
for (const id of FIND_EMAILS_PROVIDERS) {
|
|
483
|
+
const count = winCounts.get(id) ?? 0
|
|
484
|
+
if (count > best) { best = count; dominant = id }
|
|
485
|
+
}
|
|
486
|
+
if (dominant) {
|
|
487
|
+
const insight = buildSelectionInsight('find_emails', dominant, restInput, {
|
|
488
|
+
// Steps 2-4 only run on Prospeo's misses, so a non-Prospeo winner is a
|
|
489
|
+
// genuine fallthrough — unless the caller pinned providers (no Prospeo step),
|
|
490
|
+
// in which case the pinnedByUser branch governs the wording anyway.
|
|
491
|
+
wasFallback: dominant !== 'prospeo' && !isConstrained,
|
|
492
|
+
pinnedByUser: isConstrained,
|
|
493
|
+
})
|
|
494
|
+
if (insight) {
|
|
495
|
+
meta.selection_insight = insight.insight
|
|
496
|
+
if (insight.signals.length > 0) meta.selection_signals = insight.signals
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
// Surface branded provider names per person so users never see a raw slug.
|
|
502
|
+
const brandedResults = results.map((r) => ({
|
|
503
|
+
...r,
|
|
504
|
+
provider_name: r.provider ? providerDisplayName(r.provider) : null,
|
|
505
|
+
}))
|
|
506
|
+
|
|
465
507
|
// Surface the silent-failure case the user reported: 200 OK with all-nulls is misleading
|
|
466
508
|
// when the nulls were caused by provider failures rather than legitimate no-coverage.
|
|
467
509
|
const isError = batchStatus === 'failed'
|
|
@@ -470,7 +512,7 @@ export async function findEmailsHandler(input: Record<string, unknown>) {
|
|
|
470
512
|
content: [
|
|
471
513
|
{
|
|
472
514
|
type: 'text' as const,
|
|
473
|
-
text: JSON.stringify({ data: { results, found, total: people.length }, _meta: meta }),
|
|
515
|
+
text: JSON.stringify({ data: { results: brandedResults, found, total: people.length }, _meta: meta }),
|
|
474
516
|
},
|
|
475
517
|
],
|
|
476
518
|
...(isError ? { isError: true } : {}),
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// Provider display names
|
|
3
|
+
// ---------------------------------------------------------------------------
|
|
4
|
+
//
|
|
5
|
+
// Internal provider IDs (registry.ts + the find_emails waterfall) are a mix of
|
|
6
|
+
// clean vendor names ("apollo"), already-branded slugs ("reddit_ads"), and ugly
|
|
7
|
+
// internal slugs ("limadata-work-email"). User-facing surfaces — the selection
|
|
8
|
+
// insight and `_meta.provider_name` — must show a clean branded label instead.
|
|
9
|
+
//
|
|
10
|
+
// Naming the real data product (FullEnrich, TheirStack, …) is intentional: it IS
|
|
11
|
+
// the ColdIQ "we picked the best tool" intelligence on display. The ONLY thing
|
|
12
|
+
// that must never surface is the Apify backend — and since no ID contains the
|
|
13
|
+
// word "Apify", that constraint is satisfied by mapping the Apify-backed scrapers
|
|
14
|
+
// to their branded data-source name (e.g. "Reddit Ads").
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
|
|
17
|
+
const DISPLAY_NAMES: Record<string, string> = {
|
|
18
|
+
// --- B2B data vendors (shared across capabilities) -----------------------
|
|
19
|
+
companyenrich: 'CompanyEnrich',
|
|
20
|
+
companyenrich_props: 'CompanyEnrich',
|
|
21
|
+
apollo: 'Apollo',
|
|
22
|
+
'apollo-people-match': 'Apollo',
|
|
23
|
+
fullenrich: 'FullEnrich',
|
|
24
|
+
'fullenrich-people-search': 'FullEnrich',
|
|
25
|
+
pdl: 'People Data Labs',
|
|
26
|
+
'pdl-person-enrich': 'People Data Labs',
|
|
27
|
+
'pdl-person-identify': 'People Data Labs',
|
|
28
|
+
signalbase: 'SignalBase',
|
|
29
|
+
'signalbase-funding': 'SignalBase',
|
|
30
|
+
'signalbase-acquisition': 'SignalBase',
|
|
31
|
+
'signalbase-hiring': 'SignalBase',
|
|
32
|
+
'signalbase-job-change': 'SignalBase',
|
|
33
|
+
blitzapi: 'BlitzAPI',
|
|
34
|
+
'blitzapi-reverse-email': 'BlitzAPI',
|
|
35
|
+
limadata: 'LimaData',
|
|
36
|
+
'limadata-prospect-filter': 'LimaData',
|
|
37
|
+
'limadata-prospect-url': 'LimaData',
|
|
38
|
+
'limadata-work-email': 'LimaData',
|
|
39
|
+
'limadata-work-email-linkedin': 'LimaData',
|
|
40
|
+
predictleads: 'PredictLeads',
|
|
41
|
+
'predictleads-financing': 'PredictLeads',
|
|
42
|
+
'predictleads-news': 'PredictLeads',
|
|
43
|
+
'predictleads-startup-posts': 'PredictLeads',
|
|
44
|
+
theirstack: 'TheirStack',
|
|
45
|
+
'theirstack-jobs': 'TheirStack',
|
|
46
|
+
'theirstack-hiring': 'TheirStack',
|
|
47
|
+
'theirstack-intent-discovery': 'TheirStack',
|
|
48
|
+
'theirstack-buying-intents': 'TheirStack',
|
|
49
|
+
sumble: 'Sumble',
|
|
50
|
+
'sumble-people-find': 'Sumble',
|
|
51
|
+
prospeo: 'Prospeo',
|
|
52
|
+
'prospeo-search-company': 'Prospeo',
|
|
53
|
+
'prospeo-search-person': 'Prospeo',
|
|
54
|
+
'ai-ark': 'AI-ARK',
|
|
55
|
+
'ai-ark-companies': 'AI-ARK',
|
|
56
|
+
'ai-ark-people': 'AI-ARK',
|
|
57
|
+
'ai-ark-reverse-lookup': 'AI-ARK',
|
|
58
|
+
leadsfactory: 'LeadsFactory',
|
|
59
|
+
findymail: 'Findymail',
|
|
60
|
+
'findymail-search-employees': 'Findymail',
|
|
61
|
+
'findymail-business-profile': 'Findymail',
|
|
62
|
+
'findymail-reverse-email': 'Findymail',
|
|
63
|
+
icypeas: 'Icypeas',
|
|
64
|
+
'icypeas-scrape-profile': 'Icypeas',
|
|
65
|
+
'icypeas-url-search-profile': 'Icypeas',
|
|
66
|
+
'icypeas-reverse-email-lookup': 'Icypeas',
|
|
67
|
+
wiza: 'Wiza',
|
|
68
|
+
builtwith: 'BuiltWith',
|
|
69
|
+
openmart: 'Openmart',
|
|
70
|
+
instantly: 'Instantly',
|
|
71
|
+
|
|
72
|
+
// --- LinkupAPI (LinkedIn data) -------------------------------------------
|
|
73
|
+
linkupapi: 'LinkupAPI',
|
|
74
|
+
'linkupapi-search': 'LinkupAPI',
|
|
75
|
+
'linkupapi-fundraising': 'LinkupAPI',
|
|
76
|
+
'linkupapi-hiring': 'LinkupAPI',
|
|
77
|
+
'linkupapi-search-profiles': 'LinkupAPI',
|
|
78
|
+
'linkupapi-by-domain': 'LinkupAPI',
|
|
79
|
+
'linkupapi-by-url': 'LinkupAPI',
|
|
80
|
+
'linkupapi-profile-enrich': 'LinkupAPI',
|
|
81
|
+
'linkupapi-email-reverse': 'LinkupAPI',
|
|
82
|
+
'linkupapi-validate': 'LinkupAPI',
|
|
83
|
+
|
|
84
|
+
// --- search_web ----------------------------------------------------------
|
|
85
|
+
serper: 'Serper',
|
|
86
|
+
exa: 'Exa',
|
|
87
|
+
'exa-contents': 'Exa',
|
|
88
|
+
jina: 'Jina',
|
|
89
|
+
|
|
90
|
+
// --- search_jobs ---------------------------------------------------------
|
|
91
|
+
career_site_jobs: 'Career Site Jobs',
|
|
92
|
+
linkedin_jobs_api: 'LinkedIn Jobs',
|
|
93
|
+
|
|
94
|
+
// --- search_ads ----------------------------------------------------------
|
|
95
|
+
google_ads: 'Google Ads',
|
|
96
|
+
linkedin_ad_library: 'LinkedIn Ad Library',
|
|
97
|
+
meta_ads: 'Meta Ads',
|
|
98
|
+
twitter_ads: 'X Ads',
|
|
99
|
+
reddit_ads: 'Reddit Ads',
|
|
100
|
+
|
|
101
|
+
// --- search_places / reviews ---------------------------------------------
|
|
102
|
+
google_maps: 'Google Maps',
|
|
103
|
+
google_maps_reviews: 'Google Maps',
|
|
104
|
+
|
|
105
|
+
// --- find_influencers ----------------------------------------------------
|
|
106
|
+
influencers_similar: 'Influencer Discovery',
|
|
107
|
+
influencers_discovery: 'Influencer Discovery',
|
|
108
|
+
|
|
109
|
+
// --- search_reddit -------------------------------------------------------
|
|
110
|
+
reddit: 'Reddit',
|
|
111
|
+
|
|
112
|
+
// --- search_seo (functional sub-actions) ---------------------------------
|
|
113
|
+
kw_search_volume: 'Keyword Search Volume',
|
|
114
|
+
kw_trends: 'Keyword Trends',
|
|
115
|
+
serp_google: 'Google SERP',
|
|
116
|
+
serp_bing: 'Bing SERP',
|
|
117
|
+
serp_youtube: 'YouTube SERP',
|
|
118
|
+
bl_summary: 'Backlink Summary',
|
|
119
|
+
bl_backlinks: 'Backlinks',
|
|
120
|
+
bl_referring: 'Referring Domains',
|
|
121
|
+
domain_tech: 'Domain Technologies',
|
|
122
|
+
domain_whois: 'Domain WHOIS',
|
|
123
|
+
labs_rank_overview: 'Rank Overview',
|
|
124
|
+
labs_ranked_kw: 'Ranked Keywords',
|
|
125
|
+
labs_competitors: 'Competitor Domains',
|
|
126
|
+
labs_kw_ideas: 'Keyword Ideas',
|
|
127
|
+
page_lighthouse: 'Lighthouse Audit',
|
|
128
|
+
page_content: 'Page Content',
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Title-case an unmapped provider ID as a defensive fallback so a newly added
|
|
133
|
+
* provider still renders acceptably (and never leaks a raw slug). E.g.
|
|
134
|
+
* "some-new-vendor" → "Some New Vendor".
|
|
135
|
+
*/
|
|
136
|
+
function titleCaseId(id: string): string {
|
|
137
|
+
return id
|
|
138
|
+
.split(/[-_]/)
|
|
139
|
+
.filter(Boolean)
|
|
140
|
+
.map((word) => word.charAt(0).toUpperCase() + word.slice(1))
|
|
141
|
+
.join(' ')
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Map an internal provider ID to a clean, branded display name. Falls back to a
|
|
146
|
+
* title-cased form of the ID when unmapped. Never returns "Apify".
|
|
147
|
+
*/
|
|
148
|
+
export function providerDisplayName(id: string): string {
|
|
149
|
+
return DISPLAY_NAMES[id] ?? titleCaseId(id)
|
|
150
|
+
}
|