@sellable/mcp 0.1.220 → 0.1.221

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.
@@ -197,6 +197,25 @@ const prospeoCompanyAttributesSchema = {
197
197
  mobileapps: { type: ["boolean", "null"] },
198
198
  onlinereviews: { type: ["boolean", "null"] },
199
199
  pricing: { type: ["boolean", "null"] },
200
+ uses_ai: { type: ["boolean", "null"] },
201
+ has_api: { type: ["boolean", "null"] },
202
+ has_chrome_extension: { type: ["boolean", "null"] },
203
+ has_sso: { type: ["boolean", "null"] },
204
+ has_uptime_guarantee: { type: ["boolean", "null"] },
205
+ has_open_source: { type: ["boolean", "null"] },
206
+ has_marketplace: { type: ["boolean", "null"] },
207
+ has_blog: { type: ["boolean", "null"] },
208
+ has_podcast: { type: ["boolean", "null"] },
209
+ has_community_forum: { type: ["boolean", "null"] },
210
+ has_knowledge_base: { type: ["boolean", "null"] },
211
+ has_academy: { type: ["boolean", "null"] },
212
+ has_affiliate_program: { type: ["boolean", "null"] },
213
+ has_esg_reports: { type: ["boolean", "null"] },
214
+ has_physical_offices: { type: ["boolean", "null"] },
215
+ is_venture_backed: { type: ["boolean", "null"] },
216
+ is_publicly_traded: { type: ["boolean", "null"] },
217
+ has_soc2: { type: ["boolean", "null"] },
218
+ data_residency: { type: "string", enum: ["EU"] },
200
219
  },
201
220
  };
202
221
  const prospeoCompanyRevenueSchema = {
@@ -236,6 +255,206 @@ const prospeoCompanyHeadcountByDepartmentSchema = {
236
255
  max: { type: "number" },
237
256
  },
238
257
  };
258
+ const prospeoCompanyLookalikeSchema = {
259
+ type: "object",
260
+ description: 'Prospeo company lookalike filter. company_oids must be Prospeo company IDs from seed resolution/search. minimum_tier must serialize as "T1", "T2", or "T3"; public API rows do not expose row-level tier/score/reason.',
261
+ properties: {
262
+ company_oids: { type: "array", items: { type: "string" } },
263
+ minimum_tier: { type: "string", enum: ["T1", "T2", "T3"] },
264
+ match_all: { type: "boolean" },
265
+ same_language: { type: "boolean" },
266
+ },
267
+ required: ["company_oids"],
268
+ };
269
+ const prospeoCompanyNewsSchema = {
270
+ type: "object",
271
+ description: "Company news filters by keyword, category, and timeframe.",
272
+ properties: {
273
+ keywords: { type: "array", items: { type: "string" } },
274
+ categories: {
275
+ type: "array",
276
+ items: {
277
+ type: "string",
278
+ enum: [
279
+ "Funding & Investment",
280
+ "Mergers & Acquisitions",
281
+ "Product Launch",
282
+ "Partnership",
283
+ "Expansion",
284
+ "Layoffs & Restructuring",
285
+ "IPO",
286
+ "Leadership Change",
287
+ "Legal & Regulatory",
288
+ "Awards & Recognition",
289
+ ],
290
+ },
291
+ },
292
+ timeframe_days: { type: "number", enum: [60, 90, 180, 365] },
293
+ },
294
+ };
295
+ const prospeoCompanyAwardsSchema = {
296
+ type: "object",
297
+ description: 'Company awards filter. match_mode only supports "CONTAINS".',
298
+ properties: {
299
+ include: { type: "array", items: { type: "string" } },
300
+ exclude: { type: "array", items: { type: "string" } },
301
+ match_mode: { type: "string", enum: ["CONTAINS"] },
302
+ },
303
+ };
304
+ const prospeoCompanyWebsiteSearchSchema = {
305
+ type: "object",
306
+ description: "Company website search filter for pricing, docs, security, comparison, status, careers, and page-keyword signals.",
307
+ properties: {
308
+ include_keywords: { type: "array", items: { type: "string" } },
309
+ exclude_keywords: { type: "array", items: { type: "string" } },
310
+ url_contains: { type: "array", items: { type: "string" } },
311
+ has_persona_pages: { type: "boolean" },
312
+ has_industry_pages: { type: "boolean" },
313
+ has_solution_pages: { type: "boolean" },
314
+ has_careers_page: { type: "boolean" },
315
+ has_status_page: { type: "boolean" },
316
+ has_sla_page: { type: "boolean" },
317
+ has_developer_docs_page: { type: "boolean" },
318
+ has_investor_page: { type: "boolean" },
319
+ has_security_page: { type: "boolean" },
320
+ has_comparison_pages: { type: "boolean" },
321
+ },
322
+ };
323
+ const prospeoCompanyProductsServicesSchema = {
324
+ type: "object",
325
+ description: "Company products/services filters.",
326
+ properties: {
327
+ products_include: { type: "array", items: { type: "string" } },
328
+ products_exclude: { type: "array", items: { type: "string" } },
329
+ products_match_all: { type: "boolean" },
330
+ service_tags_include: { type: "array", items: { type: "string" } },
331
+ service_tags_exclude: { type: "array", items: { type: "string" } },
332
+ service_tags_match_all: { type: "boolean" },
333
+ },
334
+ };
335
+ const prospeoCompanySimpleIncludeExcludeSchema = {
336
+ type: "object",
337
+ properties: {
338
+ include: { type: "array", items: { type: "string" } },
339
+ exclude: { type: "array", items: { type: "string" } },
340
+ },
341
+ };
342
+ const prospeoCompanyIncludeOnlySchema = {
343
+ type: "object",
344
+ properties: {
345
+ include: { type: "array", items: { type: "string" } },
346
+ },
347
+ };
348
+ const prospeoCompanyGoogleDiscoverySchema = {
349
+ type: "object",
350
+ description: "Company Google discovery filters.",
351
+ properties: {
352
+ seo_keywords: { type: "array", items: { type: "string" } },
353
+ },
354
+ };
355
+ const prospeoCompanyHeadcountByLocationSchema = {
356
+ type: "object",
357
+ description: "Company headcount by location filter.",
358
+ properties: {
359
+ entries: {
360
+ type: "array",
361
+ items: {
362
+ type: "object",
363
+ properties: {
364
+ country: { type: "string" },
365
+ state: { type: "string" },
366
+ city: { type: "string" },
367
+ min_headcount: { type: "number" },
368
+ max_headcount: { type: "number" },
369
+ },
370
+ required: ["country"],
371
+ },
372
+ },
373
+ },
374
+ required: ["entries"],
375
+ };
376
+ const prospeoCompanyIcpSchema = {
377
+ type: "object",
378
+ description: "Structured company ICP filter.",
379
+ properties: {
380
+ titles_include: { type: "array", items: { type: "string" } },
381
+ titles_exclude: { type: "array", items: { type: "string" } },
382
+ departments: {
383
+ type: "object",
384
+ properties: {
385
+ include: { type: "array", items: { type: "string" } },
386
+ other: { type: "array", items: { type: "string" } },
387
+ match_mode: { type: "string", enum: ["ANY", "ALL"] },
388
+ },
389
+ },
390
+ company_sizes: {
391
+ type: "array",
392
+ items: {
393
+ type: "string",
394
+ enum: ["micro", "smb", "midmarket", "enterprise", "large_enterprise"],
395
+ },
396
+ },
397
+ industries: { type: "array", items: { type: "string" } },
398
+ geographic_markets: { type: "array", items: { type: "string" } },
399
+ geographic_scope: { type: "string" },
400
+ },
401
+ };
402
+ const prospeoCompanyWebsiteTrafficSchema = {
403
+ type: "object",
404
+ description: "Experimental website traffic filter. Availability may vary by Prospeo account/API policy.",
405
+ properties: {
406
+ min_monthly_visits: { type: "number" },
407
+ max_monthly_visits: { type: "number" },
408
+ visit_change: { type: "string", enum: ["increased", "decreased", "stable"] },
409
+ top_countries: { type: "array", items: { type: "string" } },
410
+ min_country_percentage: { type: "number" },
411
+ max_country_percentage: { type: "number" },
412
+ },
413
+ };
414
+ const prospeoCompanyKeyExecsSchema = {
415
+ type: "object",
416
+ description: "Experimental key executive change filter. Availability may vary by Prospeo account/API policy.",
417
+ properties: {
418
+ event_types: {
419
+ type: "array",
420
+ items: {
421
+ type: "string",
422
+ enum: [
423
+ "CEO Appointed",
424
+ "CFO Appointed",
425
+ "CTO Appointed",
426
+ "CMO Appointed",
427
+ "CRO Appointed",
428
+ "COO Appointed",
429
+ "VP of Sales Appointed",
430
+ "VP of Marketing Appointed",
431
+ "VP of Product Appointed",
432
+ ],
433
+ },
434
+ },
435
+ timeframe_days: { type: "number", enum: [90, 180, 365] },
436
+ },
437
+ };
438
+ const prospeoCompanyAccountWorkflowGuidance = `Company account workflow: search_prospeo_companies -> confirm_prospeo_company_accounts -> search_prospeo. Example: find companies like Red Rover that use AI and have an API:
439
+ search_prospeo_companies({
440
+ "seedDomains": ["tryredrover.com"],
441
+ "filters": {
442
+ "company_lookalike": { "company_oids": ["cmp_red_rover"], "minimum_tier": "T1" },
443
+ "company_attributes": { "uses_ai": true, "has_api": true, "pricing": true },
444
+ "company_website_search": {
445
+ "include_keywords": ["pricing"],
446
+ "has_developer_docs_page": true,
447
+ "has_security_page": true
448
+ }
449
+ }
450
+ })
451
+ For accounts in the news: { "company_news": { "categories": ["Funding & Investment"], "timeframe_days": 90 } }.
452
+ For awards: { "company_awards": { "include": ["G2"], "match_mode": "CONTAINS" } }.
453
+ For website traffic: { "company_website_traffic": { "min_monthly_visits": 50000 } }.
454
+ For products/services, integrations, key customers, and Google discovery use "company_products_services", "company_integrations", "company_key_customers", and "company_google_discovery".
455
+ For headcount by location: { "company_headcount_by_location": { "entries": [{ "country": "United States", "city": "Austin", "min_headcount": 10 }] } }.
456
+ For structured ICP: { "company_icp": { "titles_include": ["Head of RevOps"], "company_sizes": ["midmarket"], "departments": { "include": ["Sales"], "match_mode": "ANY" } } }.
457
+ company_intent is unsupported; support-channel AI Attribute guesses like phone/email/chat/ticket/social are not exposed. public API rows do not include lookalike tier/score/reason.`;
239
458
  function loadSignalDiscoveryConfig() {
240
459
  if (!existsSync(signalProviderConfigPath)) {
241
460
  return defaultSignalDiscoveryConfig;
@@ -1200,9 +1419,139 @@ export const leadToolDefinitions = [
1200
1419
  required: [],
1201
1420
  },
1202
1421
  },
1422
+ {
1423
+ name: "search_prospeo_companies",
1424
+ description: 'Search Prospeo for company/account results through the public /search-company lane. Requires get_provider_prompt({ provider: "prospeo" }) first. Use this first for company lookalike/account asks such as "find companies like Red Rover that use AI and have an API", "find founders at companies like our best customers", or "find accounts in the news about funding or partnerships". Results are accounts, not finished people leads. Review the returned accounts with the user, then call confirm_prospeo_company_accounts with the companySearchToken to create a domainFilterId before using search_prospeo for people at those accounts. Supports company lookalike, confirmed AI Attributes including pricing, company news, awards, website search, products/services, integrations, key customers, operating languages, Google discovery, headcount by location, structured company ICP, and experimental website traffic/key executive filters. company_intent and support-channel guesses like phone/email/chat/ticket/social are unsupported. Public API rows do not include lookalike tier/score/reason. ' +
1425
+ prospeoCompanyAccountWorkflowGuidance,
1426
+ inputSchema: {
1427
+ type: "object",
1428
+ properties: {
1429
+ campaignOfferId: {
1430
+ type: "string",
1431
+ description: "Campaign offer ID to associate the account discovery with.",
1432
+ },
1433
+ seedCompanies: {
1434
+ type: "array",
1435
+ items: { type: "string" },
1436
+ description: "Company names to resolve into Prospeo company IDs before applying company_lookalike.",
1437
+ },
1438
+ seedDomains: {
1439
+ type: "array",
1440
+ items: { type: "string" },
1441
+ description: "Company domains to resolve into Prospeo company IDs before applying company_lookalike.",
1442
+ },
1443
+ filters: {
1444
+ type: "object",
1445
+ description: 'Company/account filters. For lookalikes, use company_lookalike.company_oids when you already have Prospeo IDs; otherwise pass seedCompanies/seedDomains and the backend resolves IDs. minimum_tier must be "T1", "T2", or "T3". Do not use company_intent.',
1446
+ properties: {
1447
+ company_industry: prospeoFilterValueSchema,
1448
+ company_technology: prospeoFilterValueSchema,
1449
+ company_email_provider: { type: "array", items: { type: "string" } },
1450
+ company_naics: prospeoFilterValueSchema,
1451
+ company_sics: prospeoFilterValueSchema,
1452
+ company_headcount_range: {
1453
+ type: "array",
1454
+ items: { type: "string" },
1455
+ },
1456
+ company_headcount_custom: prospeoRangeFilterSchema,
1457
+ company_location_search: prospeoFilterValueSchema,
1458
+ company_type: { type: "string" },
1459
+ company_funding: prospeoFundingFilterSchema,
1460
+ company_keywords: prospeoCompanyKeywordsSchema,
1461
+ company_attributes: prospeoCompanyAttributesSchema,
1462
+ company_lookalike: prospeoCompanyLookalikeSchema,
1463
+ company_news: prospeoCompanyNewsSchema,
1464
+ company_awards: prospeoCompanyAwardsSchema,
1465
+ company_website_search: prospeoCompanyWebsiteSearchSchema,
1466
+ company_products_services: prospeoCompanyProductsServicesSchema,
1467
+ company_integrations: prospeoCompanySimpleIncludeExcludeSchema,
1468
+ company_key_customers: prospeoCompanyIncludeOnlySchema,
1469
+ company_operating_languages: prospeoCompanyIncludeOnlySchema,
1470
+ company_google_discovery: prospeoCompanyGoogleDiscoverySchema,
1471
+ company_headcount_by_location: prospeoCompanyHeadcountByLocationSchema,
1472
+ company_icp: prospeoCompanyIcpSchema,
1473
+ company_website_traffic: prospeoCompanyWebsiteTrafficSchema,
1474
+ company_key_execs: prospeoCompanyKeyExecsSchema,
1475
+ company_revenue: prospeoCompanyRevenueSchema,
1476
+ company_founded: prospeoCompanyFoundedSchema,
1477
+ company_headcount_growth: prospeoCompanyHeadcountGrowthSchema,
1478
+ company_job_posting_hiring_for: {
1479
+ type: "array",
1480
+ items: { type: "string" },
1481
+ },
1482
+ company_job_posting_quantity: prospeoRangeFilterSchema,
1483
+ company_headcount_by_department: {
1484
+ type: "array",
1485
+ items: prospeoCompanyHeadcountByDepartmentSchema,
1486
+ },
1487
+ },
1488
+ },
1489
+ limit: {
1490
+ type: "number",
1491
+ description: "Max compact account rows to return (default 25, max 100).",
1492
+ },
1493
+ page: {
1494
+ type: "number",
1495
+ description: "Page number (default 1).",
1496
+ },
1497
+ sort: {
1498
+ type: "string",
1499
+ description: "Optional requested sort label. Backend may ignore unsupported sort modes.",
1500
+ },
1501
+ previewOnly: {
1502
+ type: "boolean",
1503
+ description: "Optional hint that this is only account discovery; results are accounts either way.",
1504
+ },
1505
+ currentStep: {
1506
+ type: ["string", "null"],
1507
+ description: "Headless workflow step ID.",
1508
+ },
1509
+ confirmed: {
1510
+ type: "boolean",
1511
+ description: "Set true after user approval when interaction mode requires confirmation for search.",
1512
+ },
1513
+ },
1514
+ required: [],
1515
+ },
1516
+ },
1517
+ {
1518
+ name: "confirm_prospeo_company_accounts",
1519
+ description: "Convert approved Prospeo company account results into a domainFilterId for a follow-on search_prospeo people search. Requires the signed companySearchToken returned by search_prospeo_companies and selectedCompanyIds from that token. Do not submit raw account rows or raw domains as Prospeo-sourced provenance. This does not create people leads directly; it creates the generated-account equivalent of save_domain_filters and returns the next recommended search_prospeo call.",
1520
+ inputSchema: {
1521
+ type: "object",
1522
+ properties: {
1523
+ campaignOfferId: {
1524
+ type: "string",
1525
+ description: "Campaign offer ID. Must match the token campaign when the token is campaign-scoped.",
1526
+ },
1527
+ companySearchToken: {
1528
+ type: "string",
1529
+ description: "Signed token returned by search_prospeo_companies. Required.",
1530
+ },
1531
+ selectedCompanyIds: {
1532
+ type: "array",
1533
+ items: { type: "string" },
1534
+ description: "Prospeo company IDs selected from the token-bound account results.",
1535
+ },
1536
+ name: {
1537
+ type: "string",
1538
+ description: "Optional saved domain filter name.",
1539
+ },
1540
+ currentStep: {
1541
+ type: ["string", "null"],
1542
+ description: "Headless workflow step ID.",
1543
+ },
1544
+ confirmed: {
1545
+ type: "boolean",
1546
+ description: "Set true after user approval when interaction mode requires confirmation.",
1547
+ },
1548
+ },
1549
+ required: ["companySearchToken", "selectedCompanyIds"],
1550
+ },
1551
+ },
1203
1552
  {
1204
1553
  name: "search_prospeo",
1205
- description: 'Search Prospeo for people using filters and optional domainFilterId. Requires get_provider_prompt({ provider: "prospeo" }) first. Use Prospeo first for hiring-led targeting because it supports company_job_posting_hiring_for and company_job_posting_quantity; Sales Nav does not filter companies by hiring role. When targeting known accounts, call load_csv_domains for CSV-on-disk workflows or save_domain_filters for pasted/raw domain lists, then pass domainFilterId. Raw domain inputs and company-name targeting are NOT supported in this MCP tool. Strategy: start with 2-3 high-signal filters (title/seniority + industry or domainFilterId + headcount), add job-posting filters for hiring-led campaigns, then tighten one filter at a time. For security, AppSec, SOC, RevOps, Demand Gen, and similar function-specific lanes, do not widen with bare seniority labels like "Head" or "Director" alone; pair them with explicit function-title keywords and inspect the sample for off-function `Head of X` leakage. Prefer person location over company HQ unless HQ is explicitly needed. `campaignOfferId` routing rule: OMIT campaignOfferId ONLY in pre-mint Phase 84 `find leads` discovery mode (validating ICP before the commit gate). In every other context — post-mint lead additions, operator-driven searches on a live campaign, any search where the intent is to persist results to a specific campaign — you MUST pass campaignOfferId so the search shows up in that campaign\'s Contact Search panel. Post-mint create-campaign-v2 watch runs MUST pass currentStep: "prospeo". Omitting campaignOfferId post-mint orphans the search from the UI. Returns normalized results with pagination.',
1554
+ description: 'Search Prospeo for people using filters and optional domainFilterId. Requires get_provider_prompt({ provider: "prospeo" }) first. Use Prospeo first for hiring-led targeting because it supports company_job_posting_hiring_for and company_job_posting_quantity; Sales Nav does not filter companies by hiring role. When targeting known accounts, call load_csv_domains for CSV-on-disk workflows or save_domain_filters for pasted/raw domain lists, then pass domainFilterId. For company lookalike/account asks, call search_prospeo_companies first, review accounts, then confirm_prospeo_company_accounts to create a domainFilterId before using search_prospeo for people. Raw domain inputs and company-name targeting are NOT supported in this MCP tool. Strategy: start with 2-3 high-signal filters (title/seniority + industry or domainFilterId + headcount), add job-posting filters for hiring-led campaigns, then tighten one filter at a time. For security, AppSec, SOC, RevOps, Demand Gen, and similar function-specific lanes, do not widen with bare seniority labels like "Head" or "Director" alone; pair them with explicit function-title keywords and inspect the sample for off-function `Head of X` leakage. Prefer person location over company HQ unless HQ is explicitly needed. `campaignOfferId` routing rule: OMIT campaignOfferId ONLY in pre-mint Phase 84 `find leads` discovery mode (validating ICP before the commit gate). In every other context — post-mint lead additions, operator-driven searches on a live campaign, any search where the intent is to persist results to a specific campaign — you MUST pass campaignOfferId so the search shows up in that campaign\'s Contact Search panel. Post-mint create-campaign-v2 watch runs MUST pass currentStep: "prospeo". Omitting campaignOfferId post-mint orphans the search from the UI. Returns normalized results with pagination.',
1206
1555
  inputSchema: {
1207
1556
  type: "object",
1208
1557
  properties: {
@@ -1263,6 +1612,19 @@ export const leadToolDefinitions = [
1263
1612
  },
1264
1613
  company_keywords: prospeoCompanyKeywordsSchema,
1265
1614
  company_attributes: prospeoCompanyAttributesSchema,
1615
+ company_lookalike: prospeoCompanyLookalikeSchema,
1616
+ company_news: prospeoCompanyNewsSchema,
1617
+ company_awards: prospeoCompanyAwardsSchema,
1618
+ company_website_search: prospeoCompanyWebsiteSearchSchema,
1619
+ company_products_services: prospeoCompanyProductsServicesSchema,
1620
+ company_integrations: prospeoCompanySimpleIncludeExcludeSchema,
1621
+ company_key_customers: prospeoCompanyIncludeOnlySchema,
1622
+ company_operating_languages: prospeoCompanyIncludeOnlySchema,
1623
+ company_google_discovery: prospeoCompanyGoogleDiscoverySchema,
1624
+ company_headcount_by_location: prospeoCompanyHeadcountByLocationSchema,
1625
+ company_icp: prospeoCompanyIcpSchema,
1626
+ company_website_traffic: prospeoCompanyWebsiteTrafficSchema,
1627
+ company_key_execs: prospeoCompanyKeyExecsSchema,
1266
1628
  company_revenue: prospeoCompanyRevenueSchema,
1267
1629
  company_founded: prospeoCompanyFoundedSchema,
1268
1630
  company_headcount_growth: prospeoCompanyHeadcountGrowthSchema,
@@ -1903,6 +2265,150 @@ function normalizeSalesNavFilters(filters) {
1903
2265
  }
1904
2266
  });
1905
2267
  }
2268
+ export async function searchProspeoCompanies(input) {
2269
+ if (input?.campaignOfferId) {
2270
+ assertInteractionApproval({
2271
+ campaignId: input.campaignOfferId,
2272
+ action: "provider-search",
2273
+ confirmed: input.confirmed,
2274
+ });
2275
+ }
2276
+ assertProviderPromptLoaded({
2277
+ provider: "prospeo",
2278
+ campaignOfferId: input?.campaignOfferId,
2279
+ });
2280
+ const api = getApi();
2281
+ const response = await api.post("/api/v3/prospeo/company-search", removeUndefinedValues({
2282
+ campaignOfferId: input?.campaignOfferId,
2283
+ seedCompanies: input?.seedCompanies,
2284
+ seedDomains: input?.seedDomains,
2285
+ filters: input?.filters ?? {},
2286
+ limit: input?.limit,
2287
+ page: input?.page,
2288
+ sort: input?.sort,
2289
+ }));
2290
+ return compactProspeoCompanySearchResponse(response);
2291
+ }
2292
+ export async function confirmProspeoCompanyAccounts(input) {
2293
+ if (!input?.companySearchToken) {
2294
+ throw new Error("confirm_prospeo_company_accounts requires companySearchToken from search_prospeo_companies.");
2295
+ }
2296
+ if (!input.selectedCompanyIds || input.selectedCompanyIds.length === 0) {
2297
+ throw new Error("confirm_prospeo_company_accounts requires selectedCompanyIds from search_prospeo_companies results.");
2298
+ }
2299
+ const rawInput = input;
2300
+ if ("accounts" in rawInput || "domains" in rawInput) {
2301
+ throw new Error("confirm_prospeo_company_accounts does not accept raw account rows or domains. Use companySearchToken and selectedCompanyIds.");
2302
+ }
2303
+ if (input?.campaignOfferId) {
2304
+ assertInteractionApproval({
2305
+ campaignId: input.campaignOfferId,
2306
+ action: "provider-search",
2307
+ confirmed: input.confirmed,
2308
+ });
2309
+ }
2310
+ assertProviderPromptLoaded({
2311
+ provider: "prospeo",
2312
+ campaignOfferId: input?.campaignOfferId,
2313
+ });
2314
+ const api = getApi();
2315
+ const response = await api.post("/api/v3/prospeo/company-search/confirm-domain-filter", removeUndefinedValues({
2316
+ campaignOfferId: input?.campaignOfferId,
2317
+ companySearchToken: input.companySearchToken,
2318
+ selectedCompanyIds: input.selectedCompanyIds,
2319
+ name: input.name,
2320
+ }));
2321
+ return compactProspeoCompanyAccountConfirmationResponse(response);
2322
+ }
2323
+ function removeUndefinedValues(input) {
2324
+ return Object.fromEntries(Object.entries(input).filter(([, value]) => value !== undefined));
2325
+ }
2326
+ function compactProspeoCompanySearchResponse(response) {
2327
+ if (!response || typeof response !== "object") {
2328
+ return response;
2329
+ }
2330
+ const accountResults = Array.isArray(response.accounts)
2331
+ ? response.accounts
2332
+ : [];
2333
+ const sampleResults = accountResults
2334
+ .slice(0, 10)
2335
+ .map(compactProspeoCompanyAccount);
2336
+ return {
2337
+ success: response.success ?? true,
2338
+ totalCount: typeof response.totalCount === "number"
2339
+ ? response.totalCount
2340
+ : accountResults.length,
2341
+ currentPage: response.currentPage ?? null,
2342
+ totalPages: response.totalPages ?? null,
2343
+ accounts: {
2344
+ count: accountResults.length,
2345
+ sampleCount: sampleResults.length,
2346
+ results: sampleResults,
2347
+ },
2348
+ seedProvenance: response.seedProvenance ?? {
2349
+ resolved: [],
2350
+ unresolved: [],
2351
+ ambiguous: [],
2352
+ },
2353
+ requestedFilters: response.normalizedFilters ?? response.filters ?? {},
2354
+ warnings: Array.isArray(response.warnings) ? response.warnings : [],
2355
+ companySearchToken: response.companySearchToken ?? null,
2356
+ nextStep: "Review accounts, then call confirm_prospeo_company_accounts with companySearchToken and selectedCompanyIds. These accounts are not people leads yet.",
2357
+ };
2358
+ }
2359
+ function compactProspeoCompanyAccount(account) {
2360
+ const compact = {
2361
+ companyId: account?.companyId ?? account?.company_id ?? null,
2362
+ name: account?.name ?? null,
2363
+ domain: account?.domain ?? null,
2364
+ website: account?.website ?? null,
2365
+ industry: account?.industry ?? null,
2366
+ employeeCount: typeof account?.employeeCount === "number"
2367
+ ? account.employeeCount
2368
+ : typeof account?.employee_count === "number"
2369
+ ? account.employee_count
2370
+ : null,
2371
+ employeeRange: account?.employeeRange ?? account?.employee_range ?? null,
2372
+ sourceRank: typeof account?.sourceRank === "number"
2373
+ ? account.sourceRank
2374
+ : typeof account?.rank === "number"
2375
+ ? account.rank
2376
+ : null,
2377
+ };
2378
+ if (account?.seedMatch !== undefined) {
2379
+ compact.seedMatch = account.seedMatch;
2380
+ }
2381
+ if (account?.provenance !== undefined) {
2382
+ compact.provenance = account.provenance;
2383
+ }
2384
+ return compact;
2385
+ }
2386
+ function compactProspeoCompanyAccountConfirmationResponse(response) {
2387
+ if (!response || typeof response !== "object") {
2388
+ return response;
2389
+ }
2390
+ return {
2391
+ success: response.success ?? true,
2392
+ domainFilterId: response.domainFilterId ?? null,
2393
+ includedDomainCount: response.includedDomainCount ?? null,
2394
+ skippedDomainCount: response.skippedDomainCount ?? null,
2395
+ includeDomains: Array.isArray(response.includeDomains)
2396
+ ? response.includeDomains
2397
+ : [],
2398
+ skippedAccounts: Array.isArray(response.skippedAccounts)
2399
+ ? response.skippedAccounts
2400
+ : [],
2401
+ provenance: response.provenance ?? null,
2402
+ nextSearchProspeoCall: {
2403
+ tool: "search_prospeo",
2404
+ args: response.nextSearchProspeoCall ?? {
2405
+ campaignOfferId: response.campaignOfferId,
2406
+ domainFilterId: response.domainFilterId,
2407
+ filters: { max_person_per_company: 1 },
2408
+ },
2409
+ },
2410
+ };
2411
+ }
1906
2412
  export async function searchProspeo(input) {
1907
2413
  if (input?.campaignOfferId) {
1908
2414
  assertInteractionApproval({
@@ -1918,13 +2424,13 @@ export async function searchProspeo(input) {
1918
2424
  const api = getApi();
1919
2425
  const rawInput = input;
1920
2426
  if ("domains" in rawInput) {
1921
- throw new Error("search_prospeo does not accept raw domains. Use save_domain_filters and pass domainFilterId.");
2427
+ throw new Error("search_prospeo does not accept raw domains. Use load_csv_domains or save_domain_filters for known domain lists. For generated company/account lookalikes, use search_prospeo_companies, then confirm_prospeo_company_accounts, then pass the returned domainFilterId.");
1922
2428
  }
1923
2429
  const nestedCompany = input?.filters
1924
2430
  ?.company;
1925
2431
  if (nestedCompany?.websites !== undefined ||
1926
2432
  nestedCompany?.names !== undefined) {
1927
- throw new Error("search_prospeo does not accept filters.company.websites or filters.company.names. Resolve names to domains, then use save_domain_filters and pass domainFilterId.");
2433
+ throw new Error("search_prospeo does not accept filters.company.websites or filters.company.names. For known accounts, resolve names/domains into a domainFilterId with load_csv_domains or save_domain_filters. For company/account lookalikes, use search_prospeo_companies first, then confirm_prospeo_company_accounts.");
1928
2434
  }
1929
2435
  const response = await api.post(`/api/v3/prospeo/search`, input);
1930
2436
  return compactProspeoSearchResponse(response);