@bubblelab/bubble-core 0.1.22 → 0.1.24
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/bubble-bundle.d.ts +131 -28
- package/dist/bubble-factory.d.ts.map +1 -1
- package/dist/bubble-factory.js +10 -2
- package/dist/bubble-factory.js.map +1 -1
- package/dist/bubbles/service-bubble/browserbase/browserbase.schema.d.ts +8 -8
- package/dist/bubbles/service-bubble/crustdata/crustdata.d.ts +2784 -0
- package/dist/bubbles/service-bubble/crustdata/crustdata.d.ts.map +1 -0
- package/dist/bubbles/service-bubble/crustdata/crustdata.js +339 -0
- package/dist/bubbles/service-bubble/crustdata/crustdata.js.map +1 -0
- package/dist/bubbles/service-bubble/crustdata/crustdata.schema.d.ts +3995 -0
- package/dist/bubbles/service-bubble/{slack/slack.schema.d.ts.map → crustdata/crustdata.schema.d.ts.map} +1 -1
- package/dist/bubbles/service-bubble/crustdata/crustdata.schema.js +425 -0
- package/dist/bubbles/service-bubble/crustdata/crustdata.schema.js.map +1 -0
- package/dist/bubbles/service-bubble/crustdata/index.d.ts +3 -0
- package/dist/bubbles/service-bubble/crustdata/index.d.ts.map +1 -0
- package/dist/bubbles/service-bubble/crustdata/index.js +5 -0
- package/dist/bubbles/service-bubble/crustdata/index.js.map +1 -0
- package/dist/bubbles/service-bubble/google-drive.d.ts.map +1 -1
- package/dist/bubbles/service-bubble/google-drive.js +22 -1
- package/dist/bubbles/service-bubble/google-drive.js.map +1 -1
- package/dist/bubbles/service-bubble/google-sheets/google-sheets.schema.d.ts +10 -10
- package/dist/bubbles/tool-bubble/amazon-shopping-tool/amazon-shopping-tool.schema.d.ts +6 -6
- package/dist/bubbles/tool-bubble/company-enrichment-tool.d.ts +740 -0
- package/dist/bubbles/tool-bubble/company-enrichment-tool.d.ts.map +1 -0
- package/dist/bubbles/tool-bubble/company-enrichment-tool.js +351 -0
- package/dist/bubbles/tool-bubble/company-enrichment-tool.js.map +1 -0
- package/dist/bubbles/tool-bubble/people-search-tool.d.ts +934 -0
- package/dist/bubbles/tool-bubble/people-search-tool.d.ts.map +1 -0
- package/dist/bubbles/tool-bubble/people-search-tool.js +675 -0
- package/dist/bubbles/tool-bubble/people-search-tool.js.map +1 -0
- package/dist/bubbles.json +40 -2
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/utils/schema-comparison.d.ts +16 -0
- package/dist/utils/schema-comparison.d.ts.map +1 -1
- package/dist/utils/schema-comparison.js +98 -6
- package/dist/utils/schema-comparison.js.map +1 -1
- package/package.json +2 -2
- package/dist/bubbles/service-bubble/google-sheets/google-sheets.integration.flow.d.ts +0 -31
- package/dist/bubbles/service-bubble/google-sheets/google-sheets.integration.flow.d.ts.map +0 -1
- package/dist/bubbles/service-bubble/google-sheets/google-sheets.integration.flow.js +0 -184
- package/dist/bubbles/service-bubble/google-sheets/google-sheets.integration.flow.js.map +0 -1
- package/dist/bubbles/service-bubble/slack/slack.schema.d.ts +0 -3980
- package/dist/bubbles/service-bubble/slack/slack.schema.js +0 -1061
- package/dist/bubbles/service-bubble/slack/slack.schema.js.map +0 -1
- package/dist/bubbles/service-bubble/slack.d.ts +0 -2
- package/dist/bubbles/service-bubble/slack.d.ts.map +0 -1
- package/dist/bubbles/service-bubble/slack.js +0 -3
- package/dist/bubbles/service-bubble/slack.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"people-search-tool.d.ts","sourceRoot":"","sources":["../../../src/bubbles/tool-bubble/people-search-tool.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,UAAU,EAAE,MAAM,kCAAkC,CAAC;AAC9D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,KAAK,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAU5E,QAAA,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA2FtB,CAAC;AAcH,QAAA,MAAM,4BAA4B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAqKhC,CAAC;AAGH,QAAA,MAAM,4BAA4B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAKhC,CAAC;AAGH,KAAK,sBAAsB,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,4BAA4B,CAAC,CAAC;AAC5E,KAAK,sBAAsB,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,4BAA4B,CAAC,CAAC;AAC5E,KAAK,2BAA2B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,4BAA4B,CAAC,CAAC;AAChF,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAC/D,MAAM,MAAM,kBAAkB,GAAG,sBAAsB,CAAC;AAExD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,qBAAa,gBAAiB,SAAQ,UAAU,CAC9C,sBAAsB,EACtB,sBAAsB,CACvB;IACC,MAAM,CAAC,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAwB;IAC9D,MAAM,CAAC,QAAQ,CAAC,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAAgC;IACtD,MAAM,CAAC,QAAQ,CAAC,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAAgC;IAC5D,MAAM,CAAC,QAAQ,CAAC,gBAAgB,+EAC8C;IAC9E,MAAM,CAAC,QAAQ,CAAC,eAAe,46EAwC7B;IACF,MAAM,CAAC,QAAQ,CAAC,KAAK,YAAY;IACjC,MAAM,CAAC,QAAQ,CAAC,IAAI,UAAU;gBAG5B,MAAM,GAAE,2BAA+D,EACvE,OAAO,CAAC,EAAE,aAAa;IAKnB,aAAa,IAAI,OAAO,CAAC,sBAAsB,CAAC;IA8WtD;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAIzB;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAkExB;;OAEG;IACH,OAAO,CAAC,iBAAiB;CAQ1B"}
|
|
@@ -0,0 +1,675 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { ToolBubble } from '../../types/tool-bubble-class.js';
|
|
3
|
+
import { CredentialType } from '@bubblelab/shared-schemas';
|
|
4
|
+
import { CrustdataBubble, } from '../service-bubble/crustdata/index.js';
|
|
5
|
+
// Simplified person result schema with full profile information
|
|
6
|
+
const PersonResultSchema = z.object({
|
|
7
|
+
// Basic info
|
|
8
|
+
name: z.string().nullable().describe('Full name'),
|
|
9
|
+
title: z.string().nullable().describe('Current job title'),
|
|
10
|
+
headline: z.string().nullable().describe('LinkedIn headline'),
|
|
11
|
+
linkedinUrl: z.string().nullable().describe('LinkedIn profile URL'),
|
|
12
|
+
profilePictureUrl: z.string().nullable().describe('Profile picture URL'),
|
|
13
|
+
// Contact info
|
|
14
|
+
emails: z.array(z.string()).nullable().describe('Email addresses'),
|
|
15
|
+
twitterHandle: z.string().nullable().describe('Twitter/X handle'),
|
|
16
|
+
websites: z
|
|
17
|
+
.array(z.string())
|
|
18
|
+
.nullable()
|
|
19
|
+
.describe('Personal/professional websites'),
|
|
20
|
+
// Classification
|
|
21
|
+
seniorityLevel: z
|
|
22
|
+
.string()
|
|
23
|
+
.nullable()
|
|
24
|
+
.describe('Seniority level (CXO, Vice President, Director, etc.)'),
|
|
25
|
+
yearsOfExperience: z
|
|
26
|
+
.number()
|
|
27
|
+
.nullable()
|
|
28
|
+
.describe('Total years of professional experience'),
|
|
29
|
+
recentlyChangedJobs: z
|
|
30
|
+
.boolean()
|
|
31
|
+
.nullable()
|
|
32
|
+
.describe('Whether this person recently changed jobs'),
|
|
33
|
+
// Location
|
|
34
|
+
location: z.string().nullable().describe('Location/region'),
|
|
35
|
+
locationCity: z.string().nullable().describe('City'),
|
|
36
|
+
locationCountry: z.string().nullable().describe('Country'),
|
|
37
|
+
// Professional background
|
|
38
|
+
skills: z.array(z.string()).nullable().describe('Professional skills'),
|
|
39
|
+
languages: z.array(z.string()).nullable().describe('Languages spoken'),
|
|
40
|
+
summary: z.string().nullable().describe('Professional summary'),
|
|
41
|
+
numConnections: z
|
|
42
|
+
.number()
|
|
43
|
+
.nullable()
|
|
44
|
+
.describe('Number of LinkedIn connections'),
|
|
45
|
+
// Work history
|
|
46
|
+
currentEmployers: z
|
|
47
|
+
.array(z.object({
|
|
48
|
+
title: z.string().nullable().describe('Job title'),
|
|
49
|
+
companyName: z.string().nullable().describe('Company name'),
|
|
50
|
+
companyLinkedinUrl: z
|
|
51
|
+
.string()
|
|
52
|
+
.nullable()
|
|
53
|
+
.describe('Company LinkedIn URL'),
|
|
54
|
+
seniorityLevel: z.string().nullable().describe('Seniority level'),
|
|
55
|
+
functionCategory: z.string().nullable().describe('Function category'),
|
|
56
|
+
startDate: z.string().nullable().describe('Start date'),
|
|
57
|
+
yearsAtCompany: z.number().nullable().describe('Years at company'),
|
|
58
|
+
companyHeadcount: z.number().nullable().describe('Company headcount'),
|
|
59
|
+
companyIndustries: z
|
|
60
|
+
.array(z.string())
|
|
61
|
+
.nullable()
|
|
62
|
+
.describe('Company industries'),
|
|
63
|
+
}))
|
|
64
|
+
.nullable()
|
|
65
|
+
.describe('Current employment'),
|
|
66
|
+
pastEmployers: z
|
|
67
|
+
.array(z.object({
|
|
68
|
+
title: z.string().nullable().describe('Job title'),
|
|
69
|
+
companyName: z.string().nullable().describe('Company name'),
|
|
70
|
+
startDate: z.string().nullable().describe('Start date'),
|
|
71
|
+
endDate: z.string().nullable().describe('End date'),
|
|
72
|
+
}))
|
|
73
|
+
.nullable()
|
|
74
|
+
.describe('Past employment'),
|
|
75
|
+
// Education
|
|
76
|
+
education: z
|
|
77
|
+
.array(z.object({
|
|
78
|
+
instituteName: z.string().nullable().describe('Institution name'),
|
|
79
|
+
degreeName: z.string().nullable().describe('Degree name'),
|
|
80
|
+
fieldOfStudy: z.string().nullable().describe('Field of study'),
|
|
81
|
+
}))
|
|
82
|
+
.nullable()
|
|
83
|
+
.describe('Education history'),
|
|
84
|
+
});
|
|
85
|
+
// Geo distance search schema
|
|
86
|
+
const GeoDistanceSearchSchema = z.object({
|
|
87
|
+
location: z
|
|
88
|
+
.string()
|
|
89
|
+
.describe('Center point location (e.g., "San Francisco", "New York City")'),
|
|
90
|
+
radiusMiles: z
|
|
91
|
+
.number()
|
|
92
|
+
.positive()
|
|
93
|
+
.describe('Search radius in miles (e.g., 75)'),
|
|
94
|
+
});
|
|
95
|
+
// Tool parameters - comprehensive, agent-friendly interface
|
|
96
|
+
const PeopleSearchToolParamsSchema = z.object({
|
|
97
|
+
// ===== PRIMARY SEARCH CRITERIA (at least one required) =====
|
|
98
|
+
companyName: z
|
|
99
|
+
.string()
|
|
100
|
+
.optional()
|
|
101
|
+
.describe('Current company name to search within (e.g., "Google", "Microsoft")'),
|
|
102
|
+
companyLinkedinUrl: z
|
|
103
|
+
.string()
|
|
104
|
+
.optional()
|
|
105
|
+
.describe('Company LinkedIn URL for precise matching (e.g., "https://www.linkedin.com/company/google")'),
|
|
106
|
+
jobTitle: z
|
|
107
|
+
.string()
|
|
108
|
+
.optional()
|
|
109
|
+
.describe('Current job title to search for (e.g., "Software Engineer", "CEO"). Use jobTitles array for multiple titles.'),
|
|
110
|
+
jobTitles: z
|
|
111
|
+
.array(z.string())
|
|
112
|
+
.optional()
|
|
113
|
+
.describe('Multiple job titles to search for with OR logic (e.g., ["Senior Hardware Engineer", "Technical Product Manager"]). Use this when searching for people with any of several roles.'),
|
|
114
|
+
location: z
|
|
115
|
+
.string()
|
|
116
|
+
.optional()
|
|
117
|
+
.describe('Location/region to filter by with fuzzy matching (e.g., "San Francisco Bay Area", "New York")'),
|
|
118
|
+
// ===== GEO RADIUS SEARCH =====
|
|
119
|
+
locationRadius: GeoDistanceSearchSchema.optional().describe('Geographic radius search - find people within X miles of a location'),
|
|
120
|
+
// ===== SKILLS & EXPERIENCE =====
|
|
121
|
+
skills: z
|
|
122
|
+
.array(z.string())
|
|
123
|
+
.optional()
|
|
124
|
+
.describe('Skills to filter by (e.g., ["Python", "Machine Learning", "React"])'),
|
|
125
|
+
languages: z
|
|
126
|
+
.array(z.string())
|
|
127
|
+
.optional()
|
|
128
|
+
.describe('Languages spoken (e.g., ["English", "Spanish", "Mandarin"])'),
|
|
129
|
+
minYearsExperience: z
|
|
130
|
+
.number()
|
|
131
|
+
.optional()
|
|
132
|
+
.describe('Minimum total years of professional experience'),
|
|
133
|
+
maxYearsExperience: z
|
|
134
|
+
.number()
|
|
135
|
+
.optional()
|
|
136
|
+
.describe('Maximum total years of professional experience'),
|
|
137
|
+
// ===== SENIORITY & FUNCTION =====
|
|
138
|
+
seniorityLevels: z
|
|
139
|
+
.array(z.string())
|
|
140
|
+
.optional()
|
|
141
|
+
.describe('Seniority levels (e.g., ["CXO", "Vice President", "Director", "Manager", "Senior", "Entry"])'),
|
|
142
|
+
functionCategories: z
|
|
143
|
+
.array(z.string())
|
|
144
|
+
.optional()
|
|
145
|
+
.describe('Job function categories (e.g., ["Engineering", "Sales", "Marketing", "Finance", "Operations", "HR"])'),
|
|
146
|
+
// ===== COMPANY FILTERS =====
|
|
147
|
+
companyIndustries: z
|
|
148
|
+
.array(z.string())
|
|
149
|
+
.optional()
|
|
150
|
+
.describe('Company industries to filter by (e.g., ["Technology", "Healthcare", "Finance"])'),
|
|
151
|
+
minCompanyHeadcount: z
|
|
152
|
+
.number()
|
|
153
|
+
.optional()
|
|
154
|
+
.describe('Minimum company employee count (e.g., 100 for companies with 100+ employees)'),
|
|
155
|
+
maxCompanyHeadcount: z
|
|
156
|
+
.number()
|
|
157
|
+
.optional()
|
|
158
|
+
.describe('Maximum company employee count (e.g., 1000 for companies under 1000 employees)'),
|
|
159
|
+
minYearsAtCompany: z
|
|
160
|
+
.number()
|
|
161
|
+
.optional()
|
|
162
|
+
.describe('Minimum years at current company (tenure filter)'),
|
|
163
|
+
// ===== PAST EMPLOYMENT =====
|
|
164
|
+
pastCompanyName: z
|
|
165
|
+
.string()
|
|
166
|
+
.optional()
|
|
167
|
+
.describe('Past company name - find people who previously worked at a company'),
|
|
168
|
+
pastJobTitle: z
|
|
169
|
+
.string()
|
|
170
|
+
.optional()
|
|
171
|
+
.describe('Past job title - find people who previously held a specific title'),
|
|
172
|
+
// ===== EDUCATION =====
|
|
173
|
+
schoolName: z
|
|
174
|
+
.string()
|
|
175
|
+
.optional()
|
|
176
|
+
.describe('School/university name (e.g., "Stanford University", "MIT")'),
|
|
177
|
+
// ===== LOCATION SPECIFICS =====
|
|
178
|
+
country: z
|
|
179
|
+
.string()
|
|
180
|
+
.optional()
|
|
181
|
+
.describe('Country to filter by (e.g., "United States", "United Kingdom", "Germany")'),
|
|
182
|
+
city: z
|
|
183
|
+
.string()
|
|
184
|
+
.optional()
|
|
185
|
+
.describe('City to filter by (e.g., "San Francisco", "New York", "London")'),
|
|
186
|
+
// ===== STATUS FILTERS =====
|
|
187
|
+
recentlyChangedJobs: z
|
|
188
|
+
.boolean()
|
|
189
|
+
.optional()
|
|
190
|
+
.describe('Filter to people who recently changed jobs (useful for outreach)'),
|
|
191
|
+
minConnections: z
|
|
192
|
+
.number()
|
|
193
|
+
.optional()
|
|
194
|
+
.describe('Minimum number of LinkedIn connections'),
|
|
195
|
+
// ===== EXCLUSIONS =====
|
|
196
|
+
excludeCompanies: z
|
|
197
|
+
.array(z.string())
|
|
198
|
+
.optional()
|
|
199
|
+
.describe('Company names to exclude from results'),
|
|
200
|
+
excludeProfiles: z
|
|
201
|
+
.array(z.string())
|
|
202
|
+
.optional()
|
|
203
|
+
.describe('LinkedIn profile URLs to exclude from results'),
|
|
204
|
+
// ===== PAGINATION =====
|
|
205
|
+
limit: z
|
|
206
|
+
.number()
|
|
207
|
+
.max(100)
|
|
208
|
+
.default(20)
|
|
209
|
+
.optional()
|
|
210
|
+
.describe('Maximum results to return (default: 20, max: 100)'),
|
|
211
|
+
// Credentials (auto-injected)
|
|
212
|
+
credentials: z
|
|
213
|
+
.record(z.nativeEnum(CredentialType), z.string())
|
|
214
|
+
.optional()
|
|
215
|
+
.describe('Required credentials (auto-injected)'),
|
|
216
|
+
});
|
|
217
|
+
// Tool result schema
|
|
218
|
+
const PeopleSearchToolResultSchema = z.object({
|
|
219
|
+
people: z.array(PersonResultSchema).describe('List of people found'),
|
|
220
|
+
totalCount: z.number().describe('Total number of people available'),
|
|
221
|
+
success: z.boolean().describe('Whether the operation was successful'),
|
|
222
|
+
error: z.string().describe('Error message if operation failed'),
|
|
223
|
+
});
|
|
224
|
+
/**
|
|
225
|
+
* People Search Tool
|
|
226
|
+
*
|
|
227
|
+
* Agent-friendly tool for searching and discovering professionals.
|
|
228
|
+
* Uses the Crustdata PersonDB in-database search API for fast, comprehensive results.
|
|
229
|
+
*
|
|
230
|
+
* Features:
|
|
231
|
+
* - Search by company name/URL, job title, location, or skills
|
|
232
|
+
* - Filter by seniority level (CXO, VP, Director, etc.)
|
|
233
|
+
* - Filter by years of experience
|
|
234
|
+
* - Full profiles with work history and education
|
|
235
|
+
* - Exclude specific companies or profiles
|
|
236
|
+
*
|
|
237
|
+
* Use cases:
|
|
238
|
+
* - Find specific professionals at a company
|
|
239
|
+
* - Search for people by job title across companies
|
|
240
|
+
* - Discover professionals with specific skills
|
|
241
|
+
* - Find senior executives (CXOs, VPs, Directors)
|
|
242
|
+
* - Sales prospecting and lead generation
|
|
243
|
+
*
|
|
244
|
+
* Credits: 3 credits per 100 results returned
|
|
245
|
+
*/
|
|
246
|
+
export class PeopleSearchTool extends ToolBubble {
|
|
247
|
+
static bubbleName = 'people-search-tool';
|
|
248
|
+
static schema = PeopleSearchToolParamsSchema;
|
|
249
|
+
static resultSchema = PeopleSearchToolResultSchema;
|
|
250
|
+
static shortDescription = 'Comprehensive people search by company, title, location, skills, and more';
|
|
251
|
+
static longDescription = `
|
|
252
|
+
Comprehensive people search tool for finding and discovering professionals.
|
|
253
|
+
Uses the Crustdata PersonDB in-database search for fast, comprehensive results.
|
|
254
|
+
|
|
255
|
+
**SEARCH CRITERIA (at least one required):**
|
|
256
|
+
- Company: companyName, companyLinkedinUrl, pastCompanyName
|
|
257
|
+
- Job Title: jobTitle (single), jobTitles (multiple with OR logic), pastJobTitle
|
|
258
|
+
- Location: location (fuzzy), locationRadius (geo search), country, city
|
|
259
|
+
- Skills & Experience: skills, languages, minYearsExperience, maxYearsExperience
|
|
260
|
+
- Seniority & Function: seniorityLevels, functionCategories
|
|
261
|
+
- Company Attributes: companyIndustries, minCompanyHeadcount, maxCompanyHeadcount
|
|
262
|
+
- Education: schoolName
|
|
263
|
+
- Status: recentlyChangedJobs, minConnections, minYearsAtCompany
|
|
264
|
+
|
|
265
|
+
**GEO RADIUS SEARCH:**
|
|
266
|
+
Use locationRadius to find people within X miles of a location:
|
|
267
|
+
- locationRadius: { location: "San Francisco", radiusMiles: 75 }
|
|
268
|
+
- locationRadius: { location: "New York City", radiusMiles: 50 }
|
|
269
|
+
|
|
270
|
+
**WHAT YOU GET:**
|
|
271
|
+
- Full name, current title, and headline
|
|
272
|
+
- LinkedIn profile URL and email addresses
|
|
273
|
+
- Complete current and past work history with company details
|
|
274
|
+
- Education background with degrees and fields of study
|
|
275
|
+
- Skills, languages, seniority level, and years of experience
|
|
276
|
+
- Location details (city, country, region)
|
|
277
|
+
|
|
278
|
+
**EXAMPLE USE CASES:**
|
|
279
|
+
- companyName: "Stripe" → find people currently at Stripe
|
|
280
|
+
- jobTitle: "CEO", seniorityLevels: ["CXO"] → find CEOs
|
|
281
|
+
- jobTitles: ["Senior Hardware Engineer", "Technical Product Manager"] → find people with either role
|
|
282
|
+
- locationRadius: { location: "Austin", radiusMiles: 75 }, jobTitle: "Engineer" → engineers within 75 miles of Austin
|
|
283
|
+
- pastCompanyName: "Google", companyName: "Startup" → ex-Googlers at startups
|
|
284
|
+
- skills: ["Python", "ML"], minYearsExperience: 5 → experienced ML engineers
|
|
285
|
+
- companyIndustries: ["Healthcare"], functionCategories: ["Sales"] → healthcare sales professionals
|
|
286
|
+
- schoolName: "Stanford", seniorityLevels: ["CXO", "Vice President"] → Stanford alum executives
|
|
287
|
+
- recentlyChangedJobs: true, companyName: "Meta" → recent Meta hires (good for outreach)
|
|
288
|
+
- minCompanyHeadcount: 1000, maxCompanyHeadcount: 5000 → mid-size company employees
|
|
289
|
+
|
|
290
|
+
**CREDITS:** 3 credits per 100 results returned
|
|
291
|
+
`;
|
|
292
|
+
static alias = 'people';
|
|
293
|
+
static type = 'tool';
|
|
294
|
+
constructor(params = {}, context) {
|
|
295
|
+
super(params, context);
|
|
296
|
+
}
|
|
297
|
+
async performAction() {
|
|
298
|
+
const credentials = this.params?.credentials;
|
|
299
|
+
if (!credentials || !credentials[CredentialType.CRUSTDATA_API_KEY]) {
|
|
300
|
+
return this.createErrorResult('People search requires CRUSTDATA_API_KEY credential. Please configure it in your settings.');
|
|
301
|
+
}
|
|
302
|
+
try {
|
|
303
|
+
const {
|
|
304
|
+
// Primary search criteria
|
|
305
|
+
companyName, companyLinkedinUrl, jobTitle, jobTitles, location,
|
|
306
|
+
// Geo radius search
|
|
307
|
+
locationRadius,
|
|
308
|
+
// Skills & experience
|
|
309
|
+
skills, languages, minYearsExperience, maxYearsExperience,
|
|
310
|
+
// Seniority & function
|
|
311
|
+
seniorityLevels, functionCategories,
|
|
312
|
+
// Company filters
|
|
313
|
+
companyIndustries, minCompanyHeadcount, maxCompanyHeadcount, minYearsAtCompany,
|
|
314
|
+
// Past employment
|
|
315
|
+
pastCompanyName, pastJobTitle,
|
|
316
|
+
// Education
|
|
317
|
+
schoolName,
|
|
318
|
+
// Location specifics
|
|
319
|
+
country, city,
|
|
320
|
+
// Status filters
|
|
321
|
+
recentlyChangedJobs, minConnections,
|
|
322
|
+
// Exclusions
|
|
323
|
+
excludeCompanies, excludeProfiles,
|
|
324
|
+
// Pagination
|
|
325
|
+
limit = 20, } = this.params;
|
|
326
|
+
// Validate at least one search criteria is provided
|
|
327
|
+
const hasSearchCriteria = companyName ||
|
|
328
|
+
companyLinkedinUrl ||
|
|
329
|
+
jobTitle ||
|
|
330
|
+
(jobTitles && jobTitles.length > 0) ||
|
|
331
|
+
location ||
|
|
332
|
+
locationRadius ||
|
|
333
|
+
(skills && skills.length > 0) ||
|
|
334
|
+
(languages && languages.length > 0) ||
|
|
335
|
+
minYearsExperience !== undefined ||
|
|
336
|
+
maxYearsExperience !== undefined ||
|
|
337
|
+
(seniorityLevels && seniorityLevels.length > 0) ||
|
|
338
|
+
(functionCategories && functionCategories.length > 0) ||
|
|
339
|
+
(companyIndustries && companyIndustries.length > 0) ||
|
|
340
|
+
minCompanyHeadcount !== undefined ||
|
|
341
|
+
maxCompanyHeadcount !== undefined ||
|
|
342
|
+
minYearsAtCompany !== undefined ||
|
|
343
|
+
pastCompanyName ||
|
|
344
|
+
pastJobTitle ||
|
|
345
|
+
schoolName ||
|
|
346
|
+
country ||
|
|
347
|
+
city ||
|
|
348
|
+
recentlyChangedJobs !== undefined ||
|
|
349
|
+
minConnections !== undefined;
|
|
350
|
+
if (!hasSearchCriteria) {
|
|
351
|
+
return this.createErrorResult('At least one search criteria is required. Available options: companyName, companyLinkedinUrl, jobTitle, jobTitles, location, locationRadius, skills, languages, seniorityLevels, functionCategories, companyIndustries, minCompanyHeadcount, maxCompanyHeadcount, minYearsExperience, maxYearsExperience, minYearsAtCompany, pastCompanyName, pastJobTitle, schoolName, country, city, recentlyChangedJobs, minConnections');
|
|
352
|
+
}
|
|
353
|
+
// Build filter conditions (can include both simple conditions and nested OR groups)
|
|
354
|
+
const conditions = [];
|
|
355
|
+
// ===== CURRENT COMPANY FILTERS =====
|
|
356
|
+
if (companyLinkedinUrl) {
|
|
357
|
+
conditions.push({
|
|
358
|
+
column: 'current_employers.company_linkedin_profile_url',
|
|
359
|
+
type: '=',
|
|
360
|
+
value: companyLinkedinUrl,
|
|
361
|
+
});
|
|
362
|
+
}
|
|
363
|
+
else if (companyName) {
|
|
364
|
+
conditions.push({
|
|
365
|
+
column: 'current_employers.name',
|
|
366
|
+
type: '(.)',
|
|
367
|
+
value: companyName,
|
|
368
|
+
});
|
|
369
|
+
}
|
|
370
|
+
// Current job title(s) with fuzzy matching
|
|
371
|
+
// Merge jobTitle and jobTitles into a single list, then use OR logic if multiple
|
|
372
|
+
const allJobTitles = [];
|
|
373
|
+
if (jobTitle) {
|
|
374
|
+
allJobTitles.push(jobTitle);
|
|
375
|
+
}
|
|
376
|
+
if (jobTitles && jobTitles.length > 0) {
|
|
377
|
+
allJobTitles.push(...jobTitles);
|
|
378
|
+
}
|
|
379
|
+
if (allJobTitles.length === 1) {
|
|
380
|
+
// Single title - simple condition
|
|
381
|
+
conditions.push({
|
|
382
|
+
column: 'current_employers.title',
|
|
383
|
+
type: '(.)',
|
|
384
|
+
value: allJobTitles[0],
|
|
385
|
+
});
|
|
386
|
+
}
|
|
387
|
+
else if (allJobTitles.length > 1) {
|
|
388
|
+
// Multiple titles - OR condition group
|
|
389
|
+
const titleConditions = allJobTitles.map((title) => ({
|
|
390
|
+
column: 'current_employers.title',
|
|
391
|
+
type: '(.)',
|
|
392
|
+
value: title,
|
|
393
|
+
}));
|
|
394
|
+
conditions.push({
|
|
395
|
+
op: 'or',
|
|
396
|
+
conditions: titleConditions,
|
|
397
|
+
});
|
|
398
|
+
}
|
|
399
|
+
// ===== LOCATION FILTERS =====
|
|
400
|
+
// Geo radius search takes priority over fuzzy location
|
|
401
|
+
if (locationRadius) {
|
|
402
|
+
conditions.push({
|
|
403
|
+
column: 'region',
|
|
404
|
+
type: 'geo_distance',
|
|
405
|
+
value: {
|
|
406
|
+
location: locationRadius.location,
|
|
407
|
+
distance: locationRadius.radiusMiles,
|
|
408
|
+
unit: 'mi',
|
|
409
|
+
},
|
|
410
|
+
});
|
|
411
|
+
}
|
|
412
|
+
else if (location) {
|
|
413
|
+
conditions.push({
|
|
414
|
+
column: 'region',
|
|
415
|
+
type: '(.)',
|
|
416
|
+
value: location,
|
|
417
|
+
});
|
|
418
|
+
}
|
|
419
|
+
// Country filter
|
|
420
|
+
if (country) {
|
|
421
|
+
conditions.push({
|
|
422
|
+
column: 'location_country',
|
|
423
|
+
type: '(.)',
|
|
424
|
+
value: country,
|
|
425
|
+
});
|
|
426
|
+
}
|
|
427
|
+
// City filter
|
|
428
|
+
if (city) {
|
|
429
|
+
conditions.push({
|
|
430
|
+
column: 'location_city',
|
|
431
|
+
type: '(.)',
|
|
432
|
+
value: city,
|
|
433
|
+
});
|
|
434
|
+
}
|
|
435
|
+
// ===== SKILLS & EXPERIENCE FILTERS =====
|
|
436
|
+
if (skills && skills.length > 0) {
|
|
437
|
+
conditions.push({
|
|
438
|
+
column: 'skills',
|
|
439
|
+
type: 'in',
|
|
440
|
+
value: skills,
|
|
441
|
+
});
|
|
442
|
+
}
|
|
443
|
+
if (languages && languages.length > 0) {
|
|
444
|
+
conditions.push({
|
|
445
|
+
column: 'languages',
|
|
446
|
+
type: 'in',
|
|
447
|
+
value: languages,
|
|
448
|
+
});
|
|
449
|
+
}
|
|
450
|
+
if (minYearsExperience !== undefined) {
|
|
451
|
+
conditions.push({
|
|
452
|
+
column: 'years_of_experience_raw',
|
|
453
|
+
type: '=>',
|
|
454
|
+
value: minYearsExperience,
|
|
455
|
+
});
|
|
456
|
+
}
|
|
457
|
+
if (maxYearsExperience !== undefined) {
|
|
458
|
+
conditions.push({
|
|
459
|
+
column: 'years_of_experience_raw',
|
|
460
|
+
type: '=<',
|
|
461
|
+
value: maxYearsExperience,
|
|
462
|
+
});
|
|
463
|
+
}
|
|
464
|
+
// ===== SENIORITY & FUNCTION FILTERS =====
|
|
465
|
+
if (seniorityLevels && seniorityLevels.length > 0) {
|
|
466
|
+
conditions.push({
|
|
467
|
+
column: 'current_employers.seniority_level',
|
|
468
|
+
type: 'in',
|
|
469
|
+
value: seniorityLevels,
|
|
470
|
+
});
|
|
471
|
+
}
|
|
472
|
+
if (functionCategories && functionCategories.length > 0) {
|
|
473
|
+
conditions.push({
|
|
474
|
+
column: 'current_employers.function_category',
|
|
475
|
+
type: 'in',
|
|
476
|
+
value: functionCategories,
|
|
477
|
+
});
|
|
478
|
+
}
|
|
479
|
+
// ===== COMPANY ATTRIBUTE FILTERS =====
|
|
480
|
+
if (companyIndustries && companyIndustries.length > 0) {
|
|
481
|
+
conditions.push({
|
|
482
|
+
column: 'current_employers.company_industries',
|
|
483
|
+
type: 'in',
|
|
484
|
+
value: companyIndustries,
|
|
485
|
+
});
|
|
486
|
+
}
|
|
487
|
+
if (minCompanyHeadcount !== undefined) {
|
|
488
|
+
conditions.push({
|
|
489
|
+
column: 'current_employers.company_headcount_latest',
|
|
490
|
+
type: '=>',
|
|
491
|
+
value: minCompanyHeadcount,
|
|
492
|
+
});
|
|
493
|
+
}
|
|
494
|
+
if (maxCompanyHeadcount !== undefined) {
|
|
495
|
+
conditions.push({
|
|
496
|
+
column: 'current_employers.company_headcount_latest',
|
|
497
|
+
type: '=<',
|
|
498
|
+
value: maxCompanyHeadcount,
|
|
499
|
+
});
|
|
500
|
+
}
|
|
501
|
+
if (minYearsAtCompany !== undefined) {
|
|
502
|
+
conditions.push({
|
|
503
|
+
column: 'current_employers.years_at_company_raw',
|
|
504
|
+
type: '=>',
|
|
505
|
+
value: minYearsAtCompany,
|
|
506
|
+
});
|
|
507
|
+
}
|
|
508
|
+
// ===== PAST EMPLOYMENT FILTERS =====
|
|
509
|
+
if (pastCompanyName) {
|
|
510
|
+
conditions.push({
|
|
511
|
+
column: 'past_employers.name',
|
|
512
|
+
type: '(.)',
|
|
513
|
+
value: pastCompanyName,
|
|
514
|
+
});
|
|
515
|
+
}
|
|
516
|
+
if (pastJobTitle) {
|
|
517
|
+
conditions.push({
|
|
518
|
+
column: 'past_employers.title',
|
|
519
|
+
type: '(.)',
|
|
520
|
+
value: pastJobTitle,
|
|
521
|
+
});
|
|
522
|
+
}
|
|
523
|
+
// ===== EDUCATION FILTERS =====
|
|
524
|
+
if (schoolName) {
|
|
525
|
+
conditions.push({
|
|
526
|
+
column: 'education_background.institute_name',
|
|
527
|
+
type: '(.)',
|
|
528
|
+
value: schoolName,
|
|
529
|
+
});
|
|
530
|
+
}
|
|
531
|
+
// ===== STATUS FILTERS =====
|
|
532
|
+
if (recentlyChangedJobs !== undefined) {
|
|
533
|
+
conditions.push({
|
|
534
|
+
column: 'recently_changed_jobs',
|
|
535
|
+
type: '=',
|
|
536
|
+
value: recentlyChangedJobs,
|
|
537
|
+
});
|
|
538
|
+
}
|
|
539
|
+
if (minConnections !== undefined) {
|
|
540
|
+
conditions.push({
|
|
541
|
+
column: 'num_of_connections',
|
|
542
|
+
type: '=>',
|
|
543
|
+
value: minConnections,
|
|
544
|
+
});
|
|
545
|
+
}
|
|
546
|
+
// ===== EXCLUSION FILTERS =====
|
|
547
|
+
if (excludeCompanies && excludeCompanies.length > 0) {
|
|
548
|
+
conditions.push({
|
|
549
|
+
column: 'current_employers.name',
|
|
550
|
+
type: 'not_in',
|
|
551
|
+
value: excludeCompanies,
|
|
552
|
+
});
|
|
553
|
+
}
|
|
554
|
+
// Build the filter structure
|
|
555
|
+
let filters;
|
|
556
|
+
if (conditions.length === 1) {
|
|
557
|
+
filters = conditions[0];
|
|
558
|
+
}
|
|
559
|
+
else {
|
|
560
|
+
filters = {
|
|
561
|
+
op: 'and',
|
|
562
|
+
conditions,
|
|
563
|
+
};
|
|
564
|
+
}
|
|
565
|
+
// Build post-processing options
|
|
566
|
+
const postProcessing = excludeProfiles?.length
|
|
567
|
+
? { exclude_profiles: excludeProfiles }
|
|
568
|
+
: undefined;
|
|
569
|
+
// Call the Crustdata PersonDB search API
|
|
570
|
+
const searchBubble = new CrustdataBubble({
|
|
571
|
+
operation: 'person_search_db',
|
|
572
|
+
filters,
|
|
573
|
+
limit,
|
|
574
|
+
post_processing: postProcessing,
|
|
575
|
+
credentials,
|
|
576
|
+
}, this.context);
|
|
577
|
+
const searchResult = await searchBubble.action();
|
|
578
|
+
if (!searchResult.data.success) {
|
|
579
|
+
return this.createErrorResult(`Search failed: ${searchResult.data.error}`);
|
|
580
|
+
}
|
|
581
|
+
// Type assertion for person_search_db result
|
|
582
|
+
const personSearchData = searchResult.data;
|
|
583
|
+
// Transform results
|
|
584
|
+
const people = this.transformProfiles(personSearchData.profiles || []);
|
|
585
|
+
return {
|
|
586
|
+
people,
|
|
587
|
+
totalCount: personSearchData.total_count || people.length,
|
|
588
|
+
success: true,
|
|
589
|
+
error: '',
|
|
590
|
+
};
|
|
591
|
+
}
|
|
592
|
+
catch (error) {
|
|
593
|
+
return this.createErrorResult(error instanceof Error ? error.message : 'Unknown error occurred');
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
/**
|
|
597
|
+
* Transform API profiles to simplified format
|
|
598
|
+
*/
|
|
599
|
+
transformProfiles(profiles) {
|
|
600
|
+
return profiles.map((profile) => this.transformProfile(profile));
|
|
601
|
+
}
|
|
602
|
+
/**
|
|
603
|
+
* Transform a single PersonDB profile to PersonResult format
|
|
604
|
+
*/
|
|
605
|
+
transformProfile(profile) {
|
|
606
|
+
// Get current employer info for title and seniority
|
|
607
|
+
const currentEmployer = profile.current_employers?.[0];
|
|
608
|
+
// Transform current employers
|
|
609
|
+
const currentEmployers = profile.current_employers
|
|
610
|
+
? profile.current_employers.map((emp) => ({
|
|
611
|
+
title: emp.title || null,
|
|
612
|
+
companyName: emp.company_name || emp.name || null,
|
|
613
|
+
companyLinkedinUrl: emp.company_linkedin_profile_url || null,
|
|
614
|
+
seniorityLevel: emp.seniority_level || null,
|
|
615
|
+
functionCategory: emp.function_category || null,
|
|
616
|
+
startDate: emp.start_date || null,
|
|
617
|
+
yearsAtCompany: emp.years_at_company_raw || null,
|
|
618
|
+
companyHeadcount: emp.company_headcount_latest || null,
|
|
619
|
+
companyIndustries: emp.company_industries || null,
|
|
620
|
+
}))
|
|
621
|
+
: null;
|
|
622
|
+
// Transform past employers
|
|
623
|
+
const pastEmployers = profile.past_employers
|
|
624
|
+
? profile.past_employers.map((emp) => ({
|
|
625
|
+
title: emp.title || null,
|
|
626
|
+
companyName: emp.company_name || emp.name || null,
|
|
627
|
+
startDate: emp.start_date || null,
|
|
628
|
+
endDate: emp.end_date || null,
|
|
629
|
+
}))
|
|
630
|
+
: null;
|
|
631
|
+
// Transform education
|
|
632
|
+
const education = profile.education_background
|
|
633
|
+
? profile.education_background.map((edu) => ({
|
|
634
|
+
instituteName: edu.institute_name || null,
|
|
635
|
+
degreeName: edu.degree_name || null,
|
|
636
|
+
fieldOfStudy: edu.field_of_study || null,
|
|
637
|
+
}))
|
|
638
|
+
: null;
|
|
639
|
+
return {
|
|
640
|
+
name: profile.name || null,
|
|
641
|
+
title: currentEmployer?.title || null,
|
|
642
|
+
headline: profile.headline || null,
|
|
643
|
+
linkedinUrl: profile.linkedin_profile_url || profile.flagship_profile_url || null,
|
|
644
|
+
profilePictureUrl: profile.profile_picture_url || null,
|
|
645
|
+
emails: profile.emails || null,
|
|
646
|
+
twitterHandle: profile.twitter_handle || null,
|
|
647
|
+
websites: profile.websites || null,
|
|
648
|
+
seniorityLevel: currentEmployer?.seniority_level || null,
|
|
649
|
+
yearsOfExperience: profile.years_of_experience_raw || null,
|
|
650
|
+
recentlyChangedJobs: profile.recently_changed_jobs || null,
|
|
651
|
+
location: profile.region || null,
|
|
652
|
+
locationCity: profile.location_city || profile.location_details?.city || null,
|
|
653
|
+
locationCountry: profile.location_country || profile.location_details?.country || null,
|
|
654
|
+
skills: profile.skills || null,
|
|
655
|
+
languages: profile.languages || null,
|
|
656
|
+
summary: profile.summary || null,
|
|
657
|
+
numConnections: profile.num_of_connections || null,
|
|
658
|
+
currentEmployers,
|
|
659
|
+
pastEmployers,
|
|
660
|
+
education,
|
|
661
|
+
};
|
|
662
|
+
}
|
|
663
|
+
/**
|
|
664
|
+
* Create an error result
|
|
665
|
+
*/
|
|
666
|
+
createErrorResult(errorMessage) {
|
|
667
|
+
return {
|
|
668
|
+
people: [],
|
|
669
|
+
totalCount: 0,
|
|
670
|
+
success: false,
|
|
671
|
+
error: errorMessage,
|
|
672
|
+
};
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
//# sourceMappingURL=people-search-tool.js.map
|