@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.
Files changed (51) hide show
  1. package/dist/bubble-bundle.d.ts +131 -28
  2. package/dist/bubble-factory.d.ts.map +1 -1
  3. package/dist/bubble-factory.js +10 -2
  4. package/dist/bubble-factory.js.map +1 -1
  5. package/dist/bubbles/service-bubble/browserbase/browserbase.schema.d.ts +8 -8
  6. package/dist/bubbles/service-bubble/crustdata/crustdata.d.ts +2784 -0
  7. package/dist/bubbles/service-bubble/crustdata/crustdata.d.ts.map +1 -0
  8. package/dist/bubbles/service-bubble/crustdata/crustdata.js +339 -0
  9. package/dist/bubbles/service-bubble/crustdata/crustdata.js.map +1 -0
  10. package/dist/bubbles/service-bubble/crustdata/crustdata.schema.d.ts +3995 -0
  11. package/dist/bubbles/service-bubble/{slack/slack.schema.d.ts.map → crustdata/crustdata.schema.d.ts.map} +1 -1
  12. package/dist/bubbles/service-bubble/crustdata/crustdata.schema.js +425 -0
  13. package/dist/bubbles/service-bubble/crustdata/crustdata.schema.js.map +1 -0
  14. package/dist/bubbles/service-bubble/crustdata/index.d.ts +3 -0
  15. package/dist/bubbles/service-bubble/crustdata/index.d.ts.map +1 -0
  16. package/dist/bubbles/service-bubble/crustdata/index.js +5 -0
  17. package/dist/bubbles/service-bubble/crustdata/index.js.map +1 -0
  18. package/dist/bubbles/service-bubble/google-drive.d.ts.map +1 -1
  19. package/dist/bubbles/service-bubble/google-drive.js +22 -1
  20. package/dist/bubbles/service-bubble/google-drive.js.map +1 -1
  21. package/dist/bubbles/service-bubble/google-sheets/google-sheets.schema.d.ts +10 -10
  22. package/dist/bubbles/tool-bubble/amazon-shopping-tool/amazon-shopping-tool.schema.d.ts +6 -6
  23. package/dist/bubbles/tool-bubble/company-enrichment-tool.d.ts +740 -0
  24. package/dist/bubbles/tool-bubble/company-enrichment-tool.d.ts.map +1 -0
  25. package/dist/bubbles/tool-bubble/company-enrichment-tool.js +351 -0
  26. package/dist/bubbles/tool-bubble/company-enrichment-tool.js.map +1 -0
  27. package/dist/bubbles/tool-bubble/people-search-tool.d.ts +934 -0
  28. package/dist/bubbles/tool-bubble/people-search-tool.d.ts.map +1 -0
  29. package/dist/bubbles/tool-bubble/people-search-tool.js +675 -0
  30. package/dist/bubbles/tool-bubble/people-search-tool.js.map +1 -0
  31. package/dist/bubbles.json +40 -2
  32. package/dist/index.d.ts +5 -0
  33. package/dist/index.d.ts.map +1 -1
  34. package/dist/index.js +3 -0
  35. package/dist/index.js.map +1 -1
  36. package/dist/utils/schema-comparison.d.ts +16 -0
  37. package/dist/utils/schema-comparison.d.ts.map +1 -1
  38. package/dist/utils/schema-comparison.js +98 -6
  39. package/dist/utils/schema-comparison.js.map +1 -1
  40. package/package.json +2 -2
  41. package/dist/bubbles/service-bubble/google-sheets/google-sheets.integration.flow.d.ts +0 -31
  42. package/dist/bubbles/service-bubble/google-sheets/google-sheets.integration.flow.d.ts.map +0 -1
  43. package/dist/bubbles/service-bubble/google-sheets/google-sheets.integration.flow.js +0 -184
  44. package/dist/bubbles/service-bubble/google-sheets/google-sheets.integration.flow.js.map +0 -1
  45. package/dist/bubbles/service-bubble/slack/slack.schema.d.ts +0 -3980
  46. package/dist/bubbles/service-bubble/slack/slack.schema.js +0 -1061
  47. package/dist/bubbles/service-bubble/slack/slack.schema.js.map +0 -1
  48. package/dist/bubbles/service-bubble/slack.d.ts +0 -2
  49. package/dist/bubbles/service-bubble/slack.d.ts.map +0 -1
  50. package/dist/bubbles/service-bubble/slack.js +0 -3
  51. 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":"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"}
@@ -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