lumnisai 0.5.40 → 0.5.41

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/index.cjs CHANGED
@@ -3491,6 +3491,7 @@ class ResponsesResource {
3491
3491
  }
3492
3492
  }
3493
3493
  for (const [camel, snake] of [
3494
+ ["includeReactedPosts", "include_reacted_posts"],
3494
3495
  ["postsEnableFiltering", "posts_enable_filtering"],
3495
3496
  ["thoroughEnrichment", "thorough_enrichment"],
3496
3497
  ["deepValidationUseRelevanceReranker", "deep_validation_use_relevance_reranker"]
@@ -3549,6 +3550,60 @@ class ResponsesResource {
3549
3550
  );
3550
3551
  }
3551
3552
  }
3553
+ _validateSalesNavigatorRequest(request) {
3554
+ const directParams = request.specializedAgentParams;
3555
+ const directUrl = directParams ? this._getParamValue(directParams, "salesNavigatorUrl", "sales_navigator_url") : void 0;
3556
+ const requestOptions = request.options;
3557
+ const nestedParams = requestOptions ? this._getParamValue(
3558
+ requestOptions,
3559
+ "specializedAgentParams",
3560
+ "specialized_agent_params"
3561
+ ) : void 0;
3562
+ const nestedUrl = this._isPlainObject(nestedParams) ? this._getParamValue(nestedParams, "salesNavigatorUrl", "sales_navigator_url") : void 0;
3563
+ const optionsUrl = requestOptions ? this._getParamValue(requestOptions, "salesNavigatorUrl", "sales_navigator_url") : void 0;
3564
+ const salesNavigatorUrl = directUrl ?? nestedUrl ?? optionsUrl;
3565
+ if (salesNavigatorUrl === void 0 || salesNavigatorUrl === null)
3566
+ return;
3567
+ if (typeof salesNavigatorUrl !== "string" || salesNavigatorUrl.length > 8192 || !salesNavigatorUrl.trim()) {
3568
+ throw new ValidationError(
3569
+ "salesNavigatorUrl must be a non-empty string no longer than 8192 characters"
3570
+ );
3571
+ }
3572
+ if ([...salesNavigatorUrl].some((character) => character.charCodeAt(0) < 32) || salesNavigatorUrl.includes("\\")) {
3573
+ throw new ValidationError("salesNavigatorUrl contains unsafe characters");
3574
+ }
3575
+ let parsed;
3576
+ try {
3577
+ parsed = new URL(salesNavigatorUrl);
3578
+ } catch {
3579
+ throw new ValidationError("salesNavigatorUrl is malformed");
3580
+ }
3581
+ const authorityMatch = salesNavigatorUrl.match(/^[a-z][a-z\d+.-]*:\/\/([^/?#]*)/i);
3582
+ const rawAuthority = authorityMatch?.[1];
3583
+ if (parsed.protocol !== "https:")
3584
+ throw new ValidationError("salesNavigatorUrl must use https");
3585
+ if (parsed.hostname !== "www.linkedin.com")
3586
+ throw new ValidationError("salesNavigatorUrl must use www.linkedin.com");
3587
+ if (parsed.username || parsed.password || parsed.port || rawAuthority?.toLowerCase() !== "www.linkedin.com") {
3588
+ throw new ValidationError("salesNavigatorUrl cannot contain credentials or a custom port");
3589
+ }
3590
+ if (parsed.hash)
3591
+ throw new ValidationError("salesNavigatorUrl cannot contain a fragment");
3592
+ const rawSuffix = authorityMatch ? salesNavigatorUrl.slice(authorityMatch[0].length) : "";
3593
+ const rawPath = rawSuffix.split(/[?#]/, 1)[0];
3594
+ if (rawPath === "/sales/search/company") {
3595
+ throw new ValidationError(
3596
+ "Company Sales Navigator searches are not supported yet; use a people search or people list URL"
3597
+ );
3598
+ }
3599
+ if (rawPath !== "/sales/search/people" && !/^\/sales\/lists\/people\/\d+$/.test(rawPath)) {
3600
+ throw new ValidationError(
3601
+ "salesNavigatorUrl must be a Sales Navigator people-search or people-list URL"
3602
+ );
3603
+ }
3604
+ if (typeof request.userId !== "string" || !request.userId.trim())
3605
+ throw new ValidationError("userId is required when salesNavigatorUrl is provided");
3606
+ }
3552
3607
  _validateCriteriaParams(params, specializedAgent) {
3553
3608
  if (!params)
3554
3609
  return;
@@ -3711,6 +3766,7 @@ class ResponsesResource {
3711
3766
  for (const file of request.files)
3712
3767
  this._validateFileReference(file.uri);
3713
3768
  }
3769
+ this._validateSalesNavigatorRequest(request);
3714
3770
  if (request.specializedAgentParams)
3715
3771
  this._validateCriteriaParams(request.specializedAgentParams, request.specializedAgent);
3716
3772
  return this.http.post("/responses", request);
@@ -3846,10 +3902,13 @@ class ResponsesResource {
3846
3902
  * @param options.excludeCrmContacts - Exclude people in the acting user's synced CRM ledger; @default true
3847
3903
  * @param options.crmExclusionOwners - Granted owner ledgers to exclude against (user id or email)
3848
3904
  * @param options.crmNameCompanyMatch - Also exclude by exact name+company; @default true
3905
+ * @param options.salesNavigatorUrl - Sales Navigator people-search or people-list URL to use as the only discovery source
3906
+ * @param options.userId - Acting user whose owned Sales Navigator connection should be used; required with `salesNavigatorUrl`
3849
3907
  * @param options.searchJobSignal - CrustData job-listing signal search (decision makers at hiring companies); true | false | 'auto'
3850
3908
  * @param options.deepVerify - Web verification for org/location/third-party criteria: 'auto' (default), 'always', or 'off'
3851
3909
  * @param options.deepValidationUseRelevanceReranker - SLM relevance reranker for surfaced candidates (ranking-only); @default true
3852
3910
  * @param options.deepValidationBackfillBelowCriteria - Pad with criteria-failed candidates when under count; @default true
3911
+ * @param options.enrichEngagementHistory - Add recent LinkedIn engagement evidence before validation; forced off for Sales Navigator V1
3853
3912
  * @param options.deepSearchCriteriaModel - Override criteria decomposition model (e.g. 'openai:gpt-5.4')
3854
3913
  * @returns Response with structured_response containing:
3855
3914
  * - candidates: Validated and scored candidates
@@ -3861,6 +3920,8 @@ class ResponsesResource {
3861
3920
  messages: [{ role: "user", content: query }],
3862
3921
  specializedAgent: "deep_people_search"
3863
3922
  };
3923
+ if (options?.userId !== void 0)
3924
+ request.userId = options.userId;
3864
3925
  const params = {
3865
3926
  deepValidationUseRelevanceReranker: options?.deepValidationUseRelevanceReranker ?? true,
3866
3927
  deepValidationBackfillBelowCriteria: options?.deepValidationBackfillBelowCriteria ?? true
@@ -3894,6 +3955,8 @@ class ResponsesResource {
3894
3955
  params.crmExclusionOwners = options.crmExclusionOwners;
3895
3956
  if (options.crmNameCompanyMatch !== void 0)
3896
3957
  params.crmNameCompanyMatch = options.crmNameCompanyMatch;
3958
+ if (options.salesNavigatorUrl !== void 0)
3959
+ params.salesNavigatorUrl = options.salesNavigatorUrl;
3897
3960
  if (options.searchProfiles !== void 0)
3898
3961
  params.searchProfiles = options.searchProfiles;
3899
3962
  if (options.searchPosts !== void 0)
@@ -3928,8 +3991,22 @@ class ResponsesResource {
3928
3991
  params.searchJobSignal = options.searchJobSignal;
3929
3992
  if (options.deepVerify !== void 0)
3930
3993
  params.deepVerify = options.deepVerify;
3994
+ if (options.enrichEngagementHistory !== void 0)
3995
+ params.enrichEngagementHistory = options.enrichEngagementHistory;
3931
3996
  if (options.deepSearchCriteriaModel)
3932
3997
  params.deepSearchCriteriaModel = options.deepSearchCriteriaModel;
3998
+ if (options.salesNavigatorUrl !== void 0) {
3999
+ params.searchProfiles = false;
4000
+ params.searchPosts = false;
4001
+ params.searchConnections = false;
4002
+ params.searchJobSignal = false;
4003
+ params.includeEngagementInScore = false;
4004
+ params.postsEnableEnrichment = false;
4005
+ params.postsEnableFiltering = false;
4006
+ params.deepValidationUseRelevanceReranker = false;
4007
+ params.deepValidationBackfillBelowCriteria = false;
4008
+ params.enrichEngagementHistory = false;
4009
+ }
3933
4010
  }
3934
4011
  request.specializedAgentParams = params;
3935
4012
  return this.create(request);
@@ -4069,10 +4146,10 @@ class ResponsesResource {
4069
4146
  /**
4070
4147
  * Score people who react to or comment on posts connected to named LinkedIn profiles.
4071
4148
  *
4072
- * The backend reads posts each seed authored and reacted to within the requested
4073
- * window, selects posts relevant to the persona prompt, then runs their engagers
4074
- * through the deep people-search scoring chain. Seed profiles are always excluded
4075
- * from delivered candidates.
4149
+ * The backend reads posts each seed authored within the requested window and can
4150
+ * optionally include posts they reacted to. It selects posts relevant to the
4151
+ * persona prompt, then runs their engagers through the deep people-search scoring
4152
+ * chain. Seed profiles are always excluded from delivered candidates.
4076
4153
  *
4077
4154
  * @param query - Persona prompt used to select posts and score discovered people.
4078
4155
  * @param options - Seed profiles plus optional window, extraction, and cost controls.
@@ -4085,6 +4162,8 @@ class ResponsesResource {
4085
4162
  const params = {
4086
4163
  seedProfiles: options.seedProfiles
4087
4164
  };
4165
+ if (options.includeReactedPosts !== void 0)
4166
+ params.includeReactedPosts = options.includeReactedPosts;
4088
4167
  if (options.postsDateRange !== void 0)
4089
4168
  params.postsDateRange = options.postsDateRange;
4090
4169
  if (options.engagementTypes !== void 0)
package/dist/index.d.cts CHANGED
@@ -2005,8 +2005,14 @@ interface EngagementExpansionOutput {
2005
2005
 
2006
2006
  /** Options accepted by {@link ResponsesResource.influencerEngagement}. */
2007
2007
  interface InfluencerEngagementOptions {
2008
- /** LinkedIn profile URLs whose authored and reacted-to posts seed discovery. */
2008
+ /** LinkedIn profile URLs whose authored posts seed discovery. */
2009
2009
  seedProfiles: string[];
2010
+ /**
2011
+ * Also use posts the seeds reacted to. These posts describe a wider,
2012
+ * third-party audience and are disabled by default.
2013
+ * @default false
2014
+ */
2015
+ includeReactedPosts?: boolean;
2010
2016
  /** How far back to inspect each seed's activity. @default 'past-month' */
2011
2017
  postsDateRange?: PostsDateRange;
2012
2018
  /** Candidate engagement roles to collect. @default ['reactor', 'commenter'] */
@@ -2034,6 +2040,7 @@ interface InfluencerEngagementOptions {
2034
2040
  /** Resolved parameters echoed in `structuredResponse.agentParams`. */
2035
2041
  interface InfluencerEngagementResolvedParams {
2036
2042
  seedProfiles: string[];
2043
+ includeReactedPosts: boolean;
2037
2044
  postsDateRange: PostsDateRange;
2038
2045
  engagementTypes: PostEngagementType[];
2039
2046
  postsEnableFiltering: boolean;
@@ -2497,6 +2504,8 @@ interface ValidatedCandidate {
2497
2504
  name: string;
2498
2505
  /** LinkedIn profile URL */
2499
2506
  linkedinUrl?: string;
2507
+ /** LinkedIn/provider member identifier, including Sales Navigator hidden-profile IDs. */
2508
+ linkedinMemberId?: string | null;
2500
2509
  /**
2501
2510
  * Current job title. When the reranker runs, may reflect the resolved primary
2502
2511
  * operating role (`primaryTitle`); see `enrichedCurrentTitle` for the pre-rerank value.
@@ -2552,8 +2561,9 @@ interface ValidatedCandidate {
2552
2561
  intentSignals?: IntentSignal[];
2553
2562
  /**
2554
2563
  * Holistic relevance score (0-100) from the SLM reranker (on by default).
2555
- * Ranking-only: absent only when `deepValidationUseRelevanceReranker` was false;
2556
- * does not change `overallScore` or routing.
2564
+ * Ranking-only: absent when `deepValidationUseRelevanceReranker` was false or
2565
+ * when the fixed Sales Navigator lane was used; does not change `overallScore`
2566
+ * or routing.
2557
2567
  */
2558
2568
  relevanceScore?: number;
2559
2569
  /** Coarse match tier paired with `relevanceScore`. */
@@ -2619,6 +2629,12 @@ interface ValidatedCandidate {
2619
2629
  refoundOnNewPost?: boolean;
2620
2630
  /** Source of candidate data */
2621
2631
  source?: string;
2632
+ /** Candidate-source lanes that found this person, including `sales_navigator`. */
2633
+ discoverySources?: string[];
2634
+ /** LinkedIn relationship distance reported by Sales Navigator. */
2635
+ networkDistance?: 'FIRST_DEGREE' | 'SECOND_DEGREE' | 'THIRD_DEGREE' | 'OUT_OF_NETWORK' | null;
2636
+ /** Number of mutual LinkedIn connections reported by Sales Navigator. */
2637
+ mutualConnectionsCount?: number | null;
2622
2638
  /** When source is job_signal: hiring-company context from CrustData job listings */
2623
2639
  jobSignalMetadata?: {
2624
2640
  companyId?: number | null;
@@ -2774,7 +2790,8 @@ type PostsDateRange = 'past-24h' | 'past-week' | 'past-month' | 'past-quarter' |
2774
2790
  interface SpecializedAgentParams {
2775
2791
  /**
2776
2792
  * Maximum number of results.
2777
- * Agent-specific ranges: quick_people_search (1-100), competitor_post_engagement (1-1000).
2793
+ * Agent-specific ranges: quick_people_search (1-100), deep_people_search
2794
+ * alias (1-1000), competitor_post_engagement (1-1000).
2778
2795
  */
2779
2796
  limit?: number;
2780
2797
  /**
@@ -2782,6 +2799,17 @@ interface SpecializedAgentParams {
2782
2799
  * Range: 1-1000
2783
2800
  */
2784
2801
  requestedCandidates?: number;
2802
+ /**
2803
+ * LinkedIn Sales Navigator people-search or people-list URL used as the
2804
+ * deterministic candidate source for deep_people_search. Requires `userId`
2805
+ * on the create request so the backend can resolve the acting user's owned
2806
+ * LinkedIn connection. V1 accepts people-search and people-list URLs only,
2807
+ * caps provider extraction at 2,500 rows, and disables all other discovery
2808
+ * lanes, relevance reranking, below-criteria backfill, and engagement-history
2809
+ * enrichment.
2810
+ * @maxLength 8192
2811
+ */
2812
+ salesNavigatorUrl?: string;
2785
2813
  /**
2786
2814
  * Specific data sources to use (agent-specific)
2787
2815
  * For people search agents: ["PDL", "CORESIGNAL", "CRUST_DATA"]
@@ -2855,10 +2883,17 @@ interface SpecializedAgentParams {
2855
2883
  */
2856
2884
  candidateProfiles?: Array<Record<string, any>>;
2857
2885
  /**
2858
- * LinkedIn profile URLs whose authored and reacted-to posts seed discovery.
2886
+ * LinkedIn profile URLs whose authored posts seed discovery.
2859
2887
  * Required by influencer_engagement. Seeds are always excluded from results.
2860
2888
  */
2861
2889
  seedProfiles?: string[];
2890
+ /**
2891
+ * Whether influencer_engagement should also use posts the seeds reacted to.
2892
+ * These posts describe a wider, third-party audience and may carry no
2893
+ * engagement counts, so they can rank below authored posts.
2894
+ * @default false
2895
+ */
2896
+ includeReactedPosts?: boolean;
2862
2897
  /**
2863
2898
  * Re-cook the content package stored on a prior response without repeating
2864
2899
  * audience search or engagement collection.
@@ -2936,7 +2971,8 @@ interface SpecializedAgentParams {
2936
2971
  * For deep_people_search / competitor_post_engagement it bounds POST recency;
2937
2972
  * for competitor_rep_engagement it bounds how far back each rep's OUTGOING
2938
2973
  * engagement is considered (also bounded by `maxEngagementsPerRep`); for
2939
- * influencer_engagement it bounds each seed's authored and reacted-to posts;
2974
+ * influencer_engagement it bounds each seed's authored posts and, when
2975
+ * `includeReactedPosts` is true, reacted-to posts;
2940
2976
  * for content_intelligence it bounds each audience member's reaction history.
2941
2977
  *
2942
2978
  * NOTE on keyword post search: Crustdata's keyword-post API only supports up to
@@ -3007,7 +3043,8 @@ interface SpecializedAgentParams {
3007
3043
  * `intentScore` are untouched. Adds `relevanceScore` / `relevanceTier` per candidate.
3008
3044
  * @default true
3009
3045
  * Used by deep_people_search, people_scoring, competitor_post_engagement,
3010
- * competitor_rep_engagement, and influencer_engagement.
3046
+ * competitor_rep_engagement, and influencer_engagement. Forced off for the
3047
+ * Sales Navigator V1 source lane.
3011
3048
  */
3012
3049
  deepValidationUseRelevanceReranker?: boolean;
3013
3050
  /**
@@ -3015,9 +3052,18 @@ interface SpecializedAgentParams {
3015
3052
  * promoting top-scoring excluded candidates (tagged `backfilled=true`). Set false for
3016
3053
  * quality-over-count (return only passing candidates, even if fewer than requested).
3017
3054
  * @default true
3018
- * Used by deep_people_search and people_scoring.
3055
+ * Used by deep_people_search and people_scoring. Forced off for the Sales
3056
+ * Navigator V1 source lane.
3019
3057
  */
3020
3058
  deepValidationBackfillBelowCriteria?: boolean;
3059
+ /**
3060
+ * Enrich fast-filter survivors with recent LinkedIn engagement history before
3061
+ * deep validation. This is an optional paid stage and is forced off for the
3062
+ * Sales Navigator V1 source lane.
3063
+ * @default true
3064
+ * Used by deep_people_search.
3065
+ */
3066
+ enrichEngagementHistory?: boolean;
3021
3067
  /**
3022
3068
  * Override the model used for criteria decomposition (e.g. 'openai:gpt-5.4').
3023
3069
  * Defaults to the configured deep-search model. Only changes the criteria generator,
@@ -7176,6 +7222,7 @@ declare class ResponsesResource {
7176
7222
  private _validateSinceDays;
7177
7223
  private _validateCompanyIntelligenceParams;
7178
7224
  private _validatePersonIntelligenceParams;
7225
+ private _validateSalesNavigatorRequest;
7179
7226
  private _validateCriteriaParams;
7180
7227
  private _validateFileReference;
7181
7228
  /**
@@ -7278,10 +7325,13 @@ declare class ResponsesResource {
7278
7325
  * @param options.excludeCrmContacts - Exclude people in the acting user's synced CRM ledger; @default true
7279
7326
  * @param options.crmExclusionOwners - Granted owner ledgers to exclude against (user id or email)
7280
7327
  * @param options.crmNameCompanyMatch - Also exclude by exact name+company; @default true
7328
+ * @param options.salesNavigatorUrl - Sales Navigator people-search or people-list URL to use as the only discovery source
7329
+ * @param options.userId - Acting user whose owned Sales Navigator connection should be used; required with `salesNavigatorUrl`
7281
7330
  * @param options.searchJobSignal - CrustData job-listing signal search (decision makers at hiring companies); true | false | 'auto'
7282
7331
  * @param options.deepVerify - Web verification for org/location/third-party criteria: 'auto' (default), 'always', or 'off'
7283
7332
  * @param options.deepValidationUseRelevanceReranker - SLM relevance reranker for surfaced candidates (ranking-only); @default true
7284
7333
  * @param options.deepValidationBackfillBelowCriteria - Pad with criteria-failed candidates when under count; @default true
7334
+ * @param options.enrichEngagementHistory - Add recent LinkedIn engagement evidence before validation; forced off for Sales Navigator V1
7285
7335
  * @param options.deepSearchCriteriaModel - Override criteria decomposition model (e.g. 'openai:gpt-5.4')
7286
7336
  * @returns Response with structured_response containing:
7287
7337
  * - candidates: Validated and scored candidates
@@ -7308,6 +7358,8 @@ declare class ResponsesResource {
7308
7358
  excludeCrmContacts?: boolean;
7309
7359
  crmExclusionOwners?: string[];
7310
7360
  crmNameCompanyMatch?: boolean;
7361
+ salesNavigatorUrl?: string;
7362
+ userId?: string;
7311
7363
  searchProfiles?: boolean | 'auto';
7312
7364
  searchPosts?: boolean | 'auto';
7313
7365
  includeEngagementInScore?: boolean | 'auto';
@@ -7327,6 +7379,7 @@ declare class ResponsesResource {
7327
7379
  deepVerify?: 'off' | 'auto' | 'always';
7328
7380
  deepValidationUseRelevanceReranker?: boolean;
7329
7381
  deepValidationBackfillBelowCriteria?: boolean;
7382
+ enrichEngagementHistory?: boolean;
7330
7383
  deepSearchCriteriaModel?: string;
7331
7384
  }): Promise<CreateResponseResponse>;
7332
7385
  /**
@@ -7403,10 +7456,10 @@ declare class ResponsesResource {
7403
7456
  /**
7404
7457
  * Score people who react to or comment on posts connected to named LinkedIn profiles.
7405
7458
  *
7406
- * The backend reads posts each seed authored and reacted to within the requested
7407
- * window, selects posts relevant to the persona prompt, then runs their engagers
7408
- * through the deep people-search scoring chain. Seed profiles are always excluded
7409
- * from delivered candidates.
7459
+ * The backend reads posts each seed authored within the requested window and can
7460
+ * optionally include posts they reacted to. It selects posts relevant to the
7461
+ * persona prompt, then runs their engagers through the deep people-search scoring
7462
+ * chain. Seed profiles are always excluded from delivered candidates.
7410
7463
  *
7411
7464
  * @param query - Persona prompt used to select posts and score discovered people.
7412
7465
  * @param options - Seed profiles plus optional window, extraction, and cost controls.
package/dist/index.d.mts CHANGED
@@ -2005,8 +2005,14 @@ interface EngagementExpansionOutput {
2005
2005
 
2006
2006
  /** Options accepted by {@link ResponsesResource.influencerEngagement}. */
2007
2007
  interface InfluencerEngagementOptions {
2008
- /** LinkedIn profile URLs whose authored and reacted-to posts seed discovery. */
2008
+ /** LinkedIn profile URLs whose authored posts seed discovery. */
2009
2009
  seedProfiles: string[];
2010
+ /**
2011
+ * Also use posts the seeds reacted to. These posts describe a wider,
2012
+ * third-party audience and are disabled by default.
2013
+ * @default false
2014
+ */
2015
+ includeReactedPosts?: boolean;
2010
2016
  /** How far back to inspect each seed's activity. @default 'past-month' */
2011
2017
  postsDateRange?: PostsDateRange;
2012
2018
  /** Candidate engagement roles to collect. @default ['reactor', 'commenter'] */
@@ -2034,6 +2040,7 @@ interface InfluencerEngagementOptions {
2034
2040
  /** Resolved parameters echoed in `structuredResponse.agentParams`. */
2035
2041
  interface InfluencerEngagementResolvedParams {
2036
2042
  seedProfiles: string[];
2043
+ includeReactedPosts: boolean;
2037
2044
  postsDateRange: PostsDateRange;
2038
2045
  engagementTypes: PostEngagementType[];
2039
2046
  postsEnableFiltering: boolean;
@@ -2497,6 +2504,8 @@ interface ValidatedCandidate {
2497
2504
  name: string;
2498
2505
  /** LinkedIn profile URL */
2499
2506
  linkedinUrl?: string;
2507
+ /** LinkedIn/provider member identifier, including Sales Navigator hidden-profile IDs. */
2508
+ linkedinMemberId?: string | null;
2500
2509
  /**
2501
2510
  * Current job title. When the reranker runs, may reflect the resolved primary
2502
2511
  * operating role (`primaryTitle`); see `enrichedCurrentTitle` for the pre-rerank value.
@@ -2552,8 +2561,9 @@ interface ValidatedCandidate {
2552
2561
  intentSignals?: IntentSignal[];
2553
2562
  /**
2554
2563
  * Holistic relevance score (0-100) from the SLM reranker (on by default).
2555
- * Ranking-only: absent only when `deepValidationUseRelevanceReranker` was false;
2556
- * does not change `overallScore` or routing.
2564
+ * Ranking-only: absent when `deepValidationUseRelevanceReranker` was false or
2565
+ * when the fixed Sales Navigator lane was used; does not change `overallScore`
2566
+ * or routing.
2557
2567
  */
2558
2568
  relevanceScore?: number;
2559
2569
  /** Coarse match tier paired with `relevanceScore`. */
@@ -2619,6 +2629,12 @@ interface ValidatedCandidate {
2619
2629
  refoundOnNewPost?: boolean;
2620
2630
  /** Source of candidate data */
2621
2631
  source?: string;
2632
+ /** Candidate-source lanes that found this person, including `sales_navigator`. */
2633
+ discoverySources?: string[];
2634
+ /** LinkedIn relationship distance reported by Sales Navigator. */
2635
+ networkDistance?: 'FIRST_DEGREE' | 'SECOND_DEGREE' | 'THIRD_DEGREE' | 'OUT_OF_NETWORK' | null;
2636
+ /** Number of mutual LinkedIn connections reported by Sales Navigator. */
2637
+ mutualConnectionsCount?: number | null;
2622
2638
  /** When source is job_signal: hiring-company context from CrustData job listings */
2623
2639
  jobSignalMetadata?: {
2624
2640
  companyId?: number | null;
@@ -2774,7 +2790,8 @@ type PostsDateRange = 'past-24h' | 'past-week' | 'past-month' | 'past-quarter' |
2774
2790
  interface SpecializedAgentParams {
2775
2791
  /**
2776
2792
  * Maximum number of results.
2777
- * Agent-specific ranges: quick_people_search (1-100), competitor_post_engagement (1-1000).
2793
+ * Agent-specific ranges: quick_people_search (1-100), deep_people_search
2794
+ * alias (1-1000), competitor_post_engagement (1-1000).
2778
2795
  */
2779
2796
  limit?: number;
2780
2797
  /**
@@ -2782,6 +2799,17 @@ interface SpecializedAgentParams {
2782
2799
  * Range: 1-1000
2783
2800
  */
2784
2801
  requestedCandidates?: number;
2802
+ /**
2803
+ * LinkedIn Sales Navigator people-search or people-list URL used as the
2804
+ * deterministic candidate source for deep_people_search. Requires `userId`
2805
+ * on the create request so the backend can resolve the acting user's owned
2806
+ * LinkedIn connection. V1 accepts people-search and people-list URLs only,
2807
+ * caps provider extraction at 2,500 rows, and disables all other discovery
2808
+ * lanes, relevance reranking, below-criteria backfill, and engagement-history
2809
+ * enrichment.
2810
+ * @maxLength 8192
2811
+ */
2812
+ salesNavigatorUrl?: string;
2785
2813
  /**
2786
2814
  * Specific data sources to use (agent-specific)
2787
2815
  * For people search agents: ["PDL", "CORESIGNAL", "CRUST_DATA"]
@@ -2855,10 +2883,17 @@ interface SpecializedAgentParams {
2855
2883
  */
2856
2884
  candidateProfiles?: Array<Record<string, any>>;
2857
2885
  /**
2858
- * LinkedIn profile URLs whose authored and reacted-to posts seed discovery.
2886
+ * LinkedIn profile URLs whose authored posts seed discovery.
2859
2887
  * Required by influencer_engagement. Seeds are always excluded from results.
2860
2888
  */
2861
2889
  seedProfiles?: string[];
2890
+ /**
2891
+ * Whether influencer_engagement should also use posts the seeds reacted to.
2892
+ * These posts describe a wider, third-party audience and may carry no
2893
+ * engagement counts, so they can rank below authored posts.
2894
+ * @default false
2895
+ */
2896
+ includeReactedPosts?: boolean;
2862
2897
  /**
2863
2898
  * Re-cook the content package stored on a prior response without repeating
2864
2899
  * audience search or engagement collection.
@@ -2936,7 +2971,8 @@ interface SpecializedAgentParams {
2936
2971
  * For deep_people_search / competitor_post_engagement it bounds POST recency;
2937
2972
  * for competitor_rep_engagement it bounds how far back each rep's OUTGOING
2938
2973
  * engagement is considered (also bounded by `maxEngagementsPerRep`); for
2939
- * influencer_engagement it bounds each seed's authored and reacted-to posts;
2974
+ * influencer_engagement it bounds each seed's authored posts and, when
2975
+ * `includeReactedPosts` is true, reacted-to posts;
2940
2976
  * for content_intelligence it bounds each audience member's reaction history.
2941
2977
  *
2942
2978
  * NOTE on keyword post search: Crustdata's keyword-post API only supports up to
@@ -3007,7 +3043,8 @@ interface SpecializedAgentParams {
3007
3043
  * `intentScore` are untouched. Adds `relevanceScore` / `relevanceTier` per candidate.
3008
3044
  * @default true
3009
3045
  * Used by deep_people_search, people_scoring, competitor_post_engagement,
3010
- * competitor_rep_engagement, and influencer_engagement.
3046
+ * competitor_rep_engagement, and influencer_engagement. Forced off for the
3047
+ * Sales Navigator V1 source lane.
3011
3048
  */
3012
3049
  deepValidationUseRelevanceReranker?: boolean;
3013
3050
  /**
@@ -3015,9 +3052,18 @@ interface SpecializedAgentParams {
3015
3052
  * promoting top-scoring excluded candidates (tagged `backfilled=true`). Set false for
3016
3053
  * quality-over-count (return only passing candidates, even if fewer than requested).
3017
3054
  * @default true
3018
- * Used by deep_people_search and people_scoring.
3055
+ * Used by deep_people_search and people_scoring. Forced off for the Sales
3056
+ * Navigator V1 source lane.
3019
3057
  */
3020
3058
  deepValidationBackfillBelowCriteria?: boolean;
3059
+ /**
3060
+ * Enrich fast-filter survivors with recent LinkedIn engagement history before
3061
+ * deep validation. This is an optional paid stage and is forced off for the
3062
+ * Sales Navigator V1 source lane.
3063
+ * @default true
3064
+ * Used by deep_people_search.
3065
+ */
3066
+ enrichEngagementHistory?: boolean;
3021
3067
  /**
3022
3068
  * Override the model used for criteria decomposition (e.g. 'openai:gpt-5.4').
3023
3069
  * Defaults to the configured deep-search model. Only changes the criteria generator,
@@ -7176,6 +7222,7 @@ declare class ResponsesResource {
7176
7222
  private _validateSinceDays;
7177
7223
  private _validateCompanyIntelligenceParams;
7178
7224
  private _validatePersonIntelligenceParams;
7225
+ private _validateSalesNavigatorRequest;
7179
7226
  private _validateCriteriaParams;
7180
7227
  private _validateFileReference;
7181
7228
  /**
@@ -7278,10 +7325,13 @@ declare class ResponsesResource {
7278
7325
  * @param options.excludeCrmContacts - Exclude people in the acting user's synced CRM ledger; @default true
7279
7326
  * @param options.crmExclusionOwners - Granted owner ledgers to exclude against (user id or email)
7280
7327
  * @param options.crmNameCompanyMatch - Also exclude by exact name+company; @default true
7328
+ * @param options.salesNavigatorUrl - Sales Navigator people-search or people-list URL to use as the only discovery source
7329
+ * @param options.userId - Acting user whose owned Sales Navigator connection should be used; required with `salesNavigatorUrl`
7281
7330
  * @param options.searchJobSignal - CrustData job-listing signal search (decision makers at hiring companies); true | false | 'auto'
7282
7331
  * @param options.deepVerify - Web verification for org/location/third-party criteria: 'auto' (default), 'always', or 'off'
7283
7332
  * @param options.deepValidationUseRelevanceReranker - SLM relevance reranker for surfaced candidates (ranking-only); @default true
7284
7333
  * @param options.deepValidationBackfillBelowCriteria - Pad with criteria-failed candidates when under count; @default true
7334
+ * @param options.enrichEngagementHistory - Add recent LinkedIn engagement evidence before validation; forced off for Sales Navigator V1
7285
7335
  * @param options.deepSearchCriteriaModel - Override criteria decomposition model (e.g. 'openai:gpt-5.4')
7286
7336
  * @returns Response with structured_response containing:
7287
7337
  * - candidates: Validated and scored candidates
@@ -7308,6 +7358,8 @@ declare class ResponsesResource {
7308
7358
  excludeCrmContacts?: boolean;
7309
7359
  crmExclusionOwners?: string[];
7310
7360
  crmNameCompanyMatch?: boolean;
7361
+ salesNavigatorUrl?: string;
7362
+ userId?: string;
7311
7363
  searchProfiles?: boolean | 'auto';
7312
7364
  searchPosts?: boolean | 'auto';
7313
7365
  includeEngagementInScore?: boolean | 'auto';
@@ -7327,6 +7379,7 @@ declare class ResponsesResource {
7327
7379
  deepVerify?: 'off' | 'auto' | 'always';
7328
7380
  deepValidationUseRelevanceReranker?: boolean;
7329
7381
  deepValidationBackfillBelowCriteria?: boolean;
7382
+ enrichEngagementHistory?: boolean;
7330
7383
  deepSearchCriteriaModel?: string;
7331
7384
  }): Promise<CreateResponseResponse>;
7332
7385
  /**
@@ -7403,10 +7456,10 @@ declare class ResponsesResource {
7403
7456
  /**
7404
7457
  * Score people who react to or comment on posts connected to named LinkedIn profiles.
7405
7458
  *
7406
- * The backend reads posts each seed authored and reacted to within the requested
7407
- * window, selects posts relevant to the persona prompt, then runs their engagers
7408
- * through the deep people-search scoring chain. Seed profiles are always excluded
7409
- * from delivered candidates.
7459
+ * The backend reads posts each seed authored within the requested window and can
7460
+ * optionally include posts they reacted to. It selects posts relevant to the
7461
+ * persona prompt, then runs their engagers through the deep people-search scoring
7462
+ * chain. Seed profiles are always excluded from delivered candidates.
7410
7463
  *
7411
7464
  * @param query - Persona prompt used to select posts and score discovered people.
7412
7465
  * @param options - Seed profiles plus optional window, extraction, and cost controls.
package/dist/index.d.ts CHANGED
@@ -2005,8 +2005,14 @@ interface EngagementExpansionOutput {
2005
2005
 
2006
2006
  /** Options accepted by {@link ResponsesResource.influencerEngagement}. */
2007
2007
  interface InfluencerEngagementOptions {
2008
- /** LinkedIn profile URLs whose authored and reacted-to posts seed discovery. */
2008
+ /** LinkedIn profile URLs whose authored posts seed discovery. */
2009
2009
  seedProfiles: string[];
2010
+ /**
2011
+ * Also use posts the seeds reacted to. These posts describe a wider,
2012
+ * third-party audience and are disabled by default.
2013
+ * @default false
2014
+ */
2015
+ includeReactedPosts?: boolean;
2010
2016
  /** How far back to inspect each seed's activity. @default 'past-month' */
2011
2017
  postsDateRange?: PostsDateRange;
2012
2018
  /** Candidate engagement roles to collect. @default ['reactor', 'commenter'] */
@@ -2034,6 +2040,7 @@ interface InfluencerEngagementOptions {
2034
2040
  /** Resolved parameters echoed in `structuredResponse.agentParams`. */
2035
2041
  interface InfluencerEngagementResolvedParams {
2036
2042
  seedProfiles: string[];
2043
+ includeReactedPosts: boolean;
2037
2044
  postsDateRange: PostsDateRange;
2038
2045
  engagementTypes: PostEngagementType[];
2039
2046
  postsEnableFiltering: boolean;
@@ -2497,6 +2504,8 @@ interface ValidatedCandidate {
2497
2504
  name: string;
2498
2505
  /** LinkedIn profile URL */
2499
2506
  linkedinUrl?: string;
2507
+ /** LinkedIn/provider member identifier, including Sales Navigator hidden-profile IDs. */
2508
+ linkedinMemberId?: string | null;
2500
2509
  /**
2501
2510
  * Current job title. When the reranker runs, may reflect the resolved primary
2502
2511
  * operating role (`primaryTitle`); see `enrichedCurrentTitle` for the pre-rerank value.
@@ -2552,8 +2561,9 @@ interface ValidatedCandidate {
2552
2561
  intentSignals?: IntentSignal[];
2553
2562
  /**
2554
2563
  * Holistic relevance score (0-100) from the SLM reranker (on by default).
2555
- * Ranking-only: absent only when `deepValidationUseRelevanceReranker` was false;
2556
- * does not change `overallScore` or routing.
2564
+ * Ranking-only: absent when `deepValidationUseRelevanceReranker` was false or
2565
+ * when the fixed Sales Navigator lane was used; does not change `overallScore`
2566
+ * or routing.
2557
2567
  */
2558
2568
  relevanceScore?: number;
2559
2569
  /** Coarse match tier paired with `relevanceScore`. */
@@ -2619,6 +2629,12 @@ interface ValidatedCandidate {
2619
2629
  refoundOnNewPost?: boolean;
2620
2630
  /** Source of candidate data */
2621
2631
  source?: string;
2632
+ /** Candidate-source lanes that found this person, including `sales_navigator`. */
2633
+ discoverySources?: string[];
2634
+ /** LinkedIn relationship distance reported by Sales Navigator. */
2635
+ networkDistance?: 'FIRST_DEGREE' | 'SECOND_DEGREE' | 'THIRD_DEGREE' | 'OUT_OF_NETWORK' | null;
2636
+ /** Number of mutual LinkedIn connections reported by Sales Navigator. */
2637
+ mutualConnectionsCount?: number | null;
2622
2638
  /** When source is job_signal: hiring-company context from CrustData job listings */
2623
2639
  jobSignalMetadata?: {
2624
2640
  companyId?: number | null;
@@ -2774,7 +2790,8 @@ type PostsDateRange = 'past-24h' | 'past-week' | 'past-month' | 'past-quarter' |
2774
2790
  interface SpecializedAgentParams {
2775
2791
  /**
2776
2792
  * Maximum number of results.
2777
- * Agent-specific ranges: quick_people_search (1-100), competitor_post_engagement (1-1000).
2793
+ * Agent-specific ranges: quick_people_search (1-100), deep_people_search
2794
+ * alias (1-1000), competitor_post_engagement (1-1000).
2778
2795
  */
2779
2796
  limit?: number;
2780
2797
  /**
@@ -2782,6 +2799,17 @@ interface SpecializedAgentParams {
2782
2799
  * Range: 1-1000
2783
2800
  */
2784
2801
  requestedCandidates?: number;
2802
+ /**
2803
+ * LinkedIn Sales Navigator people-search or people-list URL used as the
2804
+ * deterministic candidate source for deep_people_search. Requires `userId`
2805
+ * on the create request so the backend can resolve the acting user's owned
2806
+ * LinkedIn connection. V1 accepts people-search and people-list URLs only,
2807
+ * caps provider extraction at 2,500 rows, and disables all other discovery
2808
+ * lanes, relevance reranking, below-criteria backfill, and engagement-history
2809
+ * enrichment.
2810
+ * @maxLength 8192
2811
+ */
2812
+ salesNavigatorUrl?: string;
2785
2813
  /**
2786
2814
  * Specific data sources to use (agent-specific)
2787
2815
  * For people search agents: ["PDL", "CORESIGNAL", "CRUST_DATA"]
@@ -2855,10 +2883,17 @@ interface SpecializedAgentParams {
2855
2883
  */
2856
2884
  candidateProfiles?: Array<Record<string, any>>;
2857
2885
  /**
2858
- * LinkedIn profile URLs whose authored and reacted-to posts seed discovery.
2886
+ * LinkedIn profile URLs whose authored posts seed discovery.
2859
2887
  * Required by influencer_engagement. Seeds are always excluded from results.
2860
2888
  */
2861
2889
  seedProfiles?: string[];
2890
+ /**
2891
+ * Whether influencer_engagement should also use posts the seeds reacted to.
2892
+ * These posts describe a wider, third-party audience and may carry no
2893
+ * engagement counts, so they can rank below authored posts.
2894
+ * @default false
2895
+ */
2896
+ includeReactedPosts?: boolean;
2862
2897
  /**
2863
2898
  * Re-cook the content package stored on a prior response without repeating
2864
2899
  * audience search or engagement collection.
@@ -2936,7 +2971,8 @@ interface SpecializedAgentParams {
2936
2971
  * For deep_people_search / competitor_post_engagement it bounds POST recency;
2937
2972
  * for competitor_rep_engagement it bounds how far back each rep's OUTGOING
2938
2973
  * engagement is considered (also bounded by `maxEngagementsPerRep`); for
2939
- * influencer_engagement it bounds each seed's authored and reacted-to posts;
2974
+ * influencer_engagement it bounds each seed's authored posts and, when
2975
+ * `includeReactedPosts` is true, reacted-to posts;
2940
2976
  * for content_intelligence it bounds each audience member's reaction history.
2941
2977
  *
2942
2978
  * NOTE on keyword post search: Crustdata's keyword-post API only supports up to
@@ -3007,7 +3043,8 @@ interface SpecializedAgentParams {
3007
3043
  * `intentScore` are untouched. Adds `relevanceScore` / `relevanceTier` per candidate.
3008
3044
  * @default true
3009
3045
  * Used by deep_people_search, people_scoring, competitor_post_engagement,
3010
- * competitor_rep_engagement, and influencer_engagement.
3046
+ * competitor_rep_engagement, and influencer_engagement. Forced off for the
3047
+ * Sales Navigator V1 source lane.
3011
3048
  */
3012
3049
  deepValidationUseRelevanceReranker?: boolean;
3013
3050
  /**
@@ -3015,9 +3052,18 @@ interface SpecializedAgentParams {
3015
3052
  * promoting top-scoring excluded candidates (tagged `backfilled=true`). Set false for
3016
3053
  * quality-over-count (return only passing candidates, even if fewer than requested).
3017
3054
  * @default true
3018
- * Used by deep_people_search and people_scoring.
3055
+ * Used by deep_people_search and people_scoring. Forced off for the Sales
3056
+ * Navigator V1 source lane.
3019
3057
  */
3020
3058
  deepValidationBackfillBelowCriteria?: boolean;
3059
+ /**
3060
+ * Enrich fast-filter survivors with recent LinkedIn engagement history before
3061
+ * deep validation. This is an optional paid stage and is forced off for the
3062
+ * Sales Navigator V1 source lane.
3063
+ * @default true
3064
+ * Used by deep_people_search.
3065
+ */
3066
+ enrichEngagementHistory?: boolean;
3021
3067
  /**
3022
3068
  * Override the model used for criteria decomposition (e.g. 'openai:gpt-5.4').
3023
3069
  * Defaults to the configured deep-search model. Only changes the criteria generator,
@@ -7176,6 +7222,7 @@ declare class ResponsesResource {
7176
7222
  private _validateSinceDays;
7177
7223
  private _validateCompanyIntelligenceParams;
7178
7224
  private _validatePersonIntelligenceParams;
7225
+ private _validateSalesNavigatorRequest;
7179
7226
  private _validateCriteriaParams;
7180
7227
  private _validateFileReference;
7181
7228
  /**
@@ -7278,10 +7325,13 @@ declare class ResponsesResource {
7278
7325
  * @param options.excludeCrmContacts - Exclude people in the acting user's synced CRM ledger; @default true
7279
7326
  * @param options.crmExclusionOwners - Granted owner ledgers to exclude against (user id or email)
7280
7327
  * @param options.crmNameCompanyMatch - Also exclude by exact name+company; @default true
7328
+ * @param options.salesNavigatorUrl - Sales Navigator people-search or people-list URL to use as the only discovery source
7329
+ * @param options.userId - Acting user whose owned Sales Navigator connection should be used; required with `salesNavigatorUrl`
7281
7330
  * @param options.searchJobSignal - CrustData job-listing signal search (decision makers at hiring companies); true | false | 'auto'
7282
7331
  * @param options.deepVerify - Web verification for org/location/third-party criteria: 'auto' (default), 'always', or 'off'
7283
7332
  * @param options.deepValidationUseRelevanceReranker - SLM relevance reranker for surfaced candidates (ranking-only); @default true
7284
7333
  * @param options.deepValidationBackfillBelowCriteria - Pad with criteria-failed candidates when under count; @default true
7334
+ * @param options.enrichEngagementHistory - Add recent LinkedIn engagement evidence before validation; forced off for Sales Navigator V1
7285
7335
  * @param options.deepSearchCriteriaModel - Override criteria decomposition model (e.g. 'openai:gpt-5.4')
7286
7336
  * @returns Response with structured_response containing:
7287
7337
  * - candidates: Validated and scored candidates
@@ -7308,6 +7358,8 @@ declare class ResponsesResource {
7308
7358
  excludeCrmContacts?: boolean;
7309
7359
  crmExclusionOwners?: string[];
7310
7360
  crmNameCompanyMatch?: boolean;
7361
+ salesNavigatorUrl?: string;
7362
+ userId?: string;
7311
7363
  searchProfiles?: boolean | 'auto';
7312
7364
  searchPosts?: boolean | 'auto';
7313
7365
  includeEngagementInScore?: boolean | 'auto';
@@ -7327,6 +7379,7 @@ declare class ResponsesResource {
7327
7379
  deepVerify?: 'off' | 'auto' | 'always';
7328
7380
  deepValidationUseRelevanceReranker?: boolean;
7329
7381
  deepValidationBackfillBelowCriteria?: boolean;
7382
+ enrichEngagementHistory?: boolean;
7330
7383
  deepSearchCriteriaModel?: string;
7331
7384
  }): Promise<CreateResponseResponse>;
7332
7385
  /**
@@ -7403,10 +7456,10 @@ declare class ResponsesResource {
7403
7456
  /**
7404
7457
  * Score people who react to or comment on posts connected to named LinkedIn profiles.
7405
7458
  *
7406
- * The backend reads posts each seed authored and reacted to within the requested
7407
- * window, selects posts relevant to the persona prompt, then runs their engagers
7408
- * through the deep people-search scoring chain. Seed profiles are always excluded
7409
- * from delivered candidates.
7459
+ * The backend reads posts each seed authored within the requested window and can
7460
+ * optionally include posts they reacted to. It selects posts relevant to the
7461
+ * persona prompt, then runs their engagers through the deep people-search scoring
7462
+ * chain. Seed profiles are always excluded from delivered candidates.
7410
7463
  *
7411
7464
  * @param query - Persona prompt used to select posts and score discovered people.
7412
7465
  * @param options - Seed profiles plus optional window, extraction, and cost controls.
package/dist/index.mjs CHANGED
@@ -3485,6 +3485,7 @@ class ResponsesResource {
3485
3485
  }
3486
3486
  }
3487
3487
  for (const [camel, snake] of [
3488
+ ["includeReactedPosts", "include_reacted_posts"],
3488
3489
  ["postsEnableFiltering", "posts_enable_filtering"],
3489
3490
  ["thoroughEnrichment", "thorough_enrichment"],
3490
3491
  ["deepValidationUseRelevanceReranker", "deep_validation_use_relevance_reranker"]
@@ -3543,6 +3544,60 @@ class ResponsesResource {
3543
3544
  );
3544
3545
  }
3545
3546
  }
3547
+ _validateSalesNavigatorRequest(request) {
3548
+ const directParams = request.specializedAgentParams;
3549
+ const directUrl = directParams ? this._getParamValue(directParams, "salesNavigatorUrl", "sales_navigator_url") : void 0;
3550
+ const requestOptions = request.options;
3551
+ const nestedParams = requestOptions ? this._getParamValue(
3552
+ requestOptions,
3553
+ "specializedAgentParams",
3554
+ "specialized_agent_params"
3555
+ ) : void 0;
3556
+ const nestedUrl = this._isPlainObject(nestedParams) ? this._getParamValue(nestedParams, "salesNavigatorUrl", "sales_navigator_url") : void 0;
3557
+ const optionsUrl = requestOptions ? this._getParamValue(requestOptions, "salesNavigatorUrl", "sales_navigator_url") : void 0;
3558
+ const salesNavigatorUrl = directUrl ?? nestedUrl ?? optionsUrl;
3559
+ if (salesNavigatorUrl === void 0 || salesNavigatorUrl === null)
3560
+ return;
3561
+ if (typeof salesNavigatorUrl !== "string" || salesNavigatorUrl.length > 8192 || !salesNavigatorUrl.trim()) {
3562
+ throw new ValidationError(
3563
+ "salesNavigatorUrl must be a non-empty string no longer than 8192 characters"
3564
+ );
3565
+ }
3566
+ if ([...salesNavigatorUrl].some((character) => character.charCodeAt(0) < 32) || salesNavigatorUrl.includes("\\")) {
3567
+ throw new ValidationError("salesNavigatorUrl contains unsafe characters");
3568
+ }
3569
+ let parsed;
3570
+ try {
3571
+ parsed = new URL(salesNavigatorUrl);
3572
+ } catch {
3573
+ throw new ValidationError("salesNavigatorUrl is malformed");
3574
+ }
3575
+ const authorityMatch = salesNavigatorUrl.match(/^[a-z][a-z\d+.-]*:\/\/([^/?#]*)/i);
3576
+ const rawAuthority = authorityMatch?.[1];
3577
+ if (parsed.protocol !== "https:")
3578
+ throw new ValidationError("salesNavigatorUrl must use https");
3579
+ if (parsed.hostname !== "www.linkedin.com")
3580
+ throw new ValidationError("salesNavigatorUrl must use www.linkedin.com");
3581
+ if (parsed.username || parsed.password || parsed.port || rawAuthority?.toLowerCase() !== "www.linkedin.com") {
3582
+ throw new ValidationError("salesNavigatorUrl cannot contain credentials or a custom port");
3583
+ }
3584
+ if (parsed.hash)
3585
+ throw new ValidationError("salesNavigatorUrl cannot contain a fragment");
3586
+ const rawSuffix = authorityMatch ? salesNavigatorUrl.slice(authorityMatch[0].length) : "";
3587
+ const rawPath = rawSuffix.split(/[?#]/, 1)[0];
3588
+ if (rawPath === "/sales/search/company") {
3589
+ throw new ValidationError(
3590
+ "Company Sales Navigator searches are not supported yet; use a people search or people list URL"
3591
+ );
3592
+ }
3593
+ if (rawPath !== "/sales/search/people" && !/^\/sales\/lists\/people\/\d+$/.test(rawPath)) {
3594
+ throw new ValidationError(
3595
+ "salesNavigatorUrl must be a Sales Navigator people-search or people-list URL"
3596
+ );
3597
+ }
3598
+ if (typeof request.userId !== "string" || !request.userId.trim())
3599
+ throw new ValidationError("userId is required when salesNavigatorUrl is provided");
3600
+ }
3546
3601
  _validateCriteriaParams(params, specializedAgent) {
3547
3602
  if (!params)
3548
3603
  return;
@@ -3705,6 +3760,7 @@ class ResponsesResource {
3705
3760
  for (const file of request.files)
3706
3761
  this._validateFileReference(file.uri);
3707
3762
  }
3763
+ this._validateSalesNavigatorRequest(request);
3708
3764
  if (request.specializedAgentParams)
3709
3765
  this._validateCriteriaParams(request.specializedAgentParams, request.specializedAgent);
3710
3766
  return this.http.post("/responses", request);
@@ -3840,10 +3896,13 @@ class ResponsesResource {
3840
3896
  * @param options.excludeCrmContacts - Exclude people in the acting user's synced CRM ledger; @default true
3841
3897
  * @param options.crmExclusionOwners - Granted owner ledgers to exclude against (user id or email)
3842
3898
  * @param options.crmNameCompanyMatch - Also exclude by exact name+company; @default true
3899
+ * @param options.salesNavigatorUrl - Sales Navigator people-search or people-list URL to use as the only discovery source
3900
+ * @param options.userId - Acting user whose owned Sales Navigator connection should be used; required with `salesNavigatorUrl`
3843
3901
  * @param options.searchJobSignal - CrustData job-listing signal search (decision makers at hiring companies); true | false | 'auto'
3844
3902
  * @param options.deepVerify - Web verification for org/location/third-party criteria: 'auto' (default), 'always', or 'off'
3845
3903
  * @param options.deepValidationUseRelevanceReranker - SLM relevance reranker for surfaced candidates (ranking-only); @default true
3846
3904
  * @param options.deepValidationBackfillBelowCriteria - Pad with criteria-failed candidates when under count; @default true
3905
+ * @param options.enrichEngagementHistory - Add recent LinkedIn engagement evidence before validation; forced off for Sales Navigator V1
3847
3906
  * @param options.deepSearchCriteriaModel - Override criteria decomposition model (e.g. 'openai:gpt-5.4')
3848
3907
  * @returns Response with structured_response containing:
3849
3908
  * - candidates: Validated and scored candidates
@@ -3855,6 +3914,8 @@ class ResponsesResource {
3855
3914
  messages: [{ role: "user", content: query }],
3856
3915
  specializedAgent: "deep_people_search"
3857
3916
  };
3917
+ if (options?.userId !== void 0)
3918
+ request.userId = options.userId;
3858
3919
  const params = {
3859
3920
  deepValidationUseRelevanceReranker: options?.deepValidationUseRelevanceReranker ?? true,
3860
3921
  deepValidationBackfillBelowCriteria: options?.deepValidationBackfillBelowCriteria ?? true
@@ -3888,6 +3949,8 @@ class ResponsesResource {
3888
3949
  params.crmExclusionOwners = options.crmExclusionOwners;
3889
3950
  if (options.crmNameCompanyMatch !== void 0)
3890
3951
  params.crmNameCompanyMatch = options.crmNameCompanyMatch;
3952
+ if (options.salesNavigatorUrl !== void 0)
3953
+ params.salesNavigatorUrl = options.salesNavigatorUrl;
3891
3954
  if (options.searchProfiles !== void 0)
3892
3955
  params.searchProfiles = options.searchProfiles;
3893
3956
  if (options.searchPosts !== void 0)
@@ -3922,8 +3985,22 @@ class ResponsesResource {
3922
3985
  params.searchJobSignal = options.searchJobSignal;
3923
3986
  if (options.deepVerify !== void 0)
3924
3987
  params.deepVerify = options.deepVerify;
3988
+ if (options.enrichEngagementHistory !== void 0)
3989
+ params.enrichEngagementHistory = options.enrichEngagementHistory;
3925
3990
  if (options.deepSearchCriteriaModel)
3926
3991
  params.deepSearchCriteriaModel = options.deepSearchCriteriaModel;
3992
+ if (options.salesNavigatorUrl !== void 0) {
3993
+ params.searchProfiles = false;
3994
+ params.searchPosts = false;
3995
+ params.searchConnections = false;
3996
+ params.searchJobSignal = false;
3997
+ params.includeEngagementInScore = false;
3998
+ params.postsEnableEnrichment = false;
3999
+ params.postsEnableFiltering = false;
4000
+ params.deepValidationUseRelevanceReranker = false;
4001
+ params.deepValidationBackfillBelowCriteria = false;
4002
+ params.enrichEngagementHistory = false;
4003
+ }
3927
4004
  }
3928
4005
  request.specializedAgentParams = params;
3929
4006
  return this.create(request);
@@ -4063,10 +4140,10 @@ class ResponsesResource {
4063
4140
  /**
4064
4141
  * Score people who react to or comment on posts connected to named LinkedIn profiles.
4065
4142
  *
4066
- * The backend reads posts each seed authored and reacted to within the requested
4067
- * window, selects posts relevant to the persona prompt, then runs their engagers
4068
- * through the deep people-search scoring chain. Seed profiles are always excluded
4069
- * from delivered candidates.
4143
+ * The backend reads posts each seed authored within the requested window and can
4144
+ * optionally include posts they reacted to. It selects posts relevant to the
4145
+ * persona prompt, then runs their engagers through the deep people-search scoring
4146
+ * chain. Seed profiles are always excluded from delivered candidates.
4070
4147
  *
4071
4148
  * @param query - Persona prompt used to select posts and score discovered people.
4072
4149
  * @param options - Seed profiles plus optional window, extraction, and cost controls.
@@ -4079,6 +4156,8 @@ class ResponsesResource {
4079
4156
  const params = {
4080
4157
  seedProfiles: options.seedProfiles
4081
4158
  };
4159
+ if (options.includeReactedPosts !== void 0)
4160
+ params.includeReactedPosts = options.includeReactedPosts;
4082
4161
  if (options.postsDateRange !== void 0)
4083
4162
  params.postsDateRange = options.postsDateRange;
4084
4163
  if (options.engagementTypes !== void 0)
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "lumnisai",
3
3
  "type": "module",
4
- "version": "0.5.40",
4
+ "version": "0.5.41",
5
5
  "description": "Official Node.js SDK for the Lumnis AI API",
6
6
  "author": "Lumnis AI",
7
7
  "license": "MIT",