lumnisai 0.5.39 → 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 +194 -0
- package/dist/index.d.cts +188 -27
- package/dist/index.d.mts +188 -27
- package/dist/index.d.ts +188 -27
- package/dist/index.mjs +194 -0
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -3435,6 +3435,76 @@ class ResponsesResource {
|
|
|
3435
3435
|
throw new ValidationError("excludeUrls must be an array of strings for engagement_expansion");
|
|
3436
3436
|
}
|
|
3437
3437
|
}
|
|
3438
|
+
_validateInfluencerEngagementParams(params) {
|
|
3439
|
+
const seedProfiles = this._getParamValue(params, "seedProfiles", "seed_profiles");
|
|
3440
|
+
if (!Array.isArray(seedProfiles) || seedProfiles.some((url) => typeof url !== "string") || !seedProfiles.some((url) => url.trim().length > 0)) {
|
|
3441
|
+
throw new ValidationError(
|
|
3442
|
+
"seedProfiles is required for influencer_engagement and must contain at least one non-empty string"
|
|
3443
|
+
);
|
|
3444
|
+
}
|
|
3445
|
+
const engagementTypes = this._getParamValue(
|
|
3446
|
+
params,
|
|
3447
|
+
"engagementTypes",
|
|
3448
|
+
"engagement_types"
|
|
3449
|
+
);
|
|
3450
|
+
if (engagementTypes !== void 0) {
|
|
3451
|
+
if (!Array.isArray(engagementTypes) || engagementTypes.length === 0)
|
|
3452
|
+
throw new ValidationError("engagementTypes must contain at least one value");
|
|
3453
|
+
const validTypes = ["reactor", "commenter"];
|
|
3454
|
+
for (const type of engagementTypes) {
|
|
3455
|
+
if (!validTypes.includes(type)) {
|
|
3456
|
+
throw new ValidationError(
|
|
3457
|
+
`Invalid engagementTypes value: ${String(type)}. Expected 'reactor' and/or 'commenter'.`
|
|
3458
|
+
);
|
|
3459
|
+
}
|
|
3460
|
+
}
|
|
3461
|
+
}
|
|
3462
|
+
const postsDateRange = this._getParamValue(
|
|
3463
|
+
params,
|
|
3464
|
+
"postsDateRange",
|
|
3465
|
+
"posts_date_range"
|
|
3466
|
+
);
|
|
3467
|
+
if (postsDateRange !== void 0) {
|
|
3468
|
+
const validRanges = [
|
|
3469
|
+
"past-24h",
|
|
3470
|
+
"past-week",
|
|
3471
|
+
"past-month",
|
|
3472
|
+
"past-quarter",
|
|
3473
|
+
"past-6-months",
|
|
3474
|
+
"past-year",
|
|
3475
|
+
"past-2-years",
|
|
3476
|
+
"past-3-years"
|
|
3477
|
+
];
|
|
3478
|
+
if (!validRanges.includes(postsDateRange))
|
|
3479
|
+
throw new ValidationError(`Invalid postsDateRange value: ${String(postsDateRange)}`);
|
|
3480
|
+
}
|
|
3481
|
+
for (const [camel, snake, maximum] of [
|
|
3482
|
+
["limit", "limit", 1e3],
|
|
3483
|
+
["maxReactorsPerPost", "max_reactors_per_post", 5e3],
|
|
3484
|
+
["maxCommentsPerPost", "max_comments_per_post", 5e3]
|
|
3485
|
+
]) {
|
|
3486
|
+
const value = this._getParamValue(params, camel, snake);
|
|
3487
|
+
if (value !== void 0 && (!Number.isInteger(value) || value < 1 || value > maximum)) {
|
|
3488
|
+
throw new ValidationError(
|
|
3489
|
+
`${camel} must be an integer between 1 and ${maximum} for influencer_engagement`
|
|
3490
|
+
);
|
|
3491
|
+
}
|
|
3492
|
+
}
|
|
3493
|
+
for (const [camel, snake] of [
|
|
3494
|
+
["includeReactedPosts", "include_reacted_posts"],
|
|
3495
|
+
["postsEnableFiltering", "posts_enable_filtering"],
|
|
3496
|
+
["thoroughEnrichment", "thorough_enrichment"],
|
|
3497
|
+
["deepValidationUseRelevanceReranker", "deep_validation_use_relevance_reranker"]
|
|
3498
|
+
]) {
|
|
3499
|
+
const value = this._getParamValue(params, camel, snake);
|
|
3500
|
+
if (value !== void 0 && typeof value !== "boolean")
|
|
3501
|
+
throw new ValidationError(`${camel} must be a boolean for influencer_engagement`);
|
|
3502
|
+
}
|
|
3503
|
+
const excludeUrls = this._getParamValue(params, "excludeUrls", "exclude_urls");
|
|
3504
|
+
if (excludeUrls !== void 0 && (!Array.isArray(excludeUrls) || excludeUrls.some((url) => typeof url !== "string"))) {
|
|
3505
|
+
throw new ValidationError("excludeUrls must be an array of strings for influencer_engagement");
|
|
3506
|
+
}
|
|
3507
|
+
}
|
|
3438
3508
|
_validateSinceDays(value, agent) {
|
|
3439
3509
|
if (value === void 0)
|
|
3440
3510
|
return;
|
|
@@ -3480,6 +3550,60 @@ class ResponsesResource {
|
|
|
3480
3550
|
);
|
|
3481
3551
|
}
|
|
3482
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
|
+
}
|
|
3483
3607
|
_validateCriteriaParams(params, specializedAgent) {
|
|
3484
3608
|
if (!params)
|
|
3485
3609
|
return;
|
|
@@ -3595,6 +3719,8 @@ class ResponsesResource {
|
|
|
3595
3719
|
this._validateContentIntelligenceParams(rawParams);
|
|
3596
3720
|
if (specializedAgent === "engagement_expansion")
|
|
3597
3721
|
this._validateEngagementExpansionParams(rawParams);
|
|
3722
|
+
if (specializedAgent === "influencer_engagement")
|
|
3723
|
+
this._validateInfluencerEngagementParams(rawParams);
|
|
3598
3724
|
if (specializedAgent === "company_intelligence")
|
|
3599
3725
|
this._validateCompanyIntelligenceParams(rawParams);
|
|
3600
3726
|
if (specializedAgent === "person_intelligence")
|
|
@@ -3640,6 +3766,7 @@ class ResponsesResource {
|
|
|
3640
3766
|
for (const file of request.files)
|
|
3641
3767
|
this._validateFileReference(file.uri);
|
|
3642
3768
|
}
|
|
3769
|
+
this._validateSalesNavigatorRequest(request);
|
|
3643
3770
|
if (request.specializedAgentParams)
|
|
3644
3771
|
this._validateCriteriaParams(request.specializedAgentParams, request.specializedAgent);
|
|
3645
3772
|
return this.http.post("/responses", request);
|
|
@@ -3775,10 +3902,13 @@ class ResponsesResource {
|
|
|
3775
3902
|
* @param options.excludeCrmContacts - Exclude people in the acting user's synced CRM ledger; @default true
|
|
3776
3903
|
* @param options.crmExclusionOwners - Granted owner ledgers to exclude against (user id or email)
|
|
3777
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`
|
|
3778
3907
|
* @param options.searchJobSignal - CrustData job-listing signal search (decision makers at hiring companies); true | false | 'auto'
|
|
3779
3908
|
* @param options.deepVerify - Web verification for org/location/third-party criteria: 'auto' (default), 'always', or 'off'
|
|
3780
3909
|
* @param options.deepValidationUseRelevanceReranker - SLM relevance reranker for surfaced candidates (ranking-only); @default true
|
|
3781
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
|
|
3782
3912
|
* @param options.deepSearchCriteriaModel - Override criteria decomposition model (e.g. 'openai:gpt-5.4')
|
|
3783
3913
|
* @returns Response with structured_response containing:
|
|
3784
3914
|
* - candidates: Validated and scored candidates
|
|
@@ -3790,6 +3920,8 @@ class ResponsesResource {
|
|
|
3790
3920
|
messages: [{ role: "user", content: query }],
|
|
3791
3921
|
specializedAgent: "deep_people_search"
|
|
3792
3922
|
};
|
|
3923
|
+
if (options?.userId !== void 0)
|
|
3924
|
+
request.userId = options.userId;
|
|
3793
3925
|
const params = {
|
|
3794
3926
|
deepValidationUseRelevanceReranker: options?.deepValidationUseRelevanceReranker ?? true,
|
|
3795
3927
|
deepValidationBackfillBelowCriteria: options?.deepValidationBackfillBelowCriteria ?? true
|
|
@@ -3823,6 +3955,8 @@ class ResponsesResource {
|
|
|
3823
3955
|
params.crmExclusionOwners = options.crmExclusionOwners;
|
|
3824
3956
|
if (options.crmNameCompanyMatch !== void 0)
|
|
3825
3957
|
params.crmNameCompanyMatch = options.crmNameCompanyMatch;
|
|
3958
|
+
if (options.salesNavigatorUrl !== void 0)
|
|
3959
|
+
params.salesNavigatorUrl = options.salesNavigatorUrl;
|
|
3826
3960
|
if (options.searchProfiles !== void 0)
|
|
3827
3961
|
params.searchProfiles = options.searchProfiles;
|
|
3828
3962
|
if (options.searchPosts !== void 0)
|
|
@@ -3857,8 +3991,22 @@ class ResponsesResource {
|
|
|
3857
3991
|
params.searchJobSignal = options.searchJobSignal;
|
|
3858
3992
|
if (options.deepVerify !== void 0)
|
|
3859
3993
|
params.deepVerify = options.deepVerify;
|
|
3994
|
+
if (options.enrichEngagementHistory !== void 0)
|
|
3995
|
+
params.enrichEngagementHistory = options.enrichEngagementHistory;
|
|
3860
3996
|
if (options.deepSearchCriteriaModel)
|
|
3861
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
|
+
}
|
|
3862
4010
|
}
|
|
3863
4011
|
request.specializedAgentParams = params;
|
|
3864
4012
|
return this.create(request);
|
|
@@ -3995,6 +4143,52 @@ class ResponsesResource {
|
|
|
3995
4143
|
specializedAgentParams: params
|
|
3996
4144
|
});
|
|
3997
4145
|
}
|
|
4146
|
+
/**
|
|
4147
|
+
* Score people who react to or comment on posts connected to named LinkedIn profiles.
|
|
4148
|
+
*
|
|
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.
|
|
4153
|
+
*
|
|
4154
|
+
* @param query - Persona prompt used to select posts and score discovered people.
|
|
4155
|
+
* @param options - Seed profiles plus optional window, extraction, and cost controls.
|
|
4156
|
+
* @returns Response; poll with `get()` and read `structuredResponse` as
|
|
4157
|
+
* {@link InfluencerEngagementOutput}.
|
|
4158
|
+
*/
|
|
4159
|
+
async influencerEngagement(query, options) {
|
|
4160
|
+
if (!query.trim())
|
|
4161
|
+
throw new ValidationError("influencerEngagement requires a non-empty persona query");
|
|
4162
|
+
const params = {
|
|
4163
|
+
seedProfiles: options.seedProfiles
|
|
4164
|
+
};
|
|
4165
|
+
if (options.includeReactedPosts !== void 0)
|
|
4166
|
+
params.includeReactedPosts = options.includeReactedPosts;
|
|
4167
|
+
if (options.postsDateRange !== void 0)
|
|
4168
|
+
params.postsDateRange = options.postsDateRange;
|
|
4169
|
+
if (options.engagementTypes !== void 0)
|
|
4170
|
+
params.engagementTypes = options.engagementTypes;
|
|
4171
|
+
if (options.postsEnableFiltering !== void 0)
|
|
4172
|
+
params.postsEnableFiltering = options.postsEnableFiltering;
|
|
4173
|
+
if (options.thoroughEnrichment !== void 0)
|
|
4174
|
+
params.thoroughEnrichment = options.thoroughEnrichment;
|
|
4175
|
+
if (options.deepValidationUseRelevanceReranker !== void 0) {
|
|
4176
|
+
params.deepValidationUseRelevanceReranker = options.deepValidationUseRelevanceReranker;
|
|
4177
|
+
}
|
|
4178
|
+
if (options.maxReactorsPerPost !== void 0)
|
|
4179
|
+
params.maxReactorsPerPost = options.maxReactorsPerPost;
|
|
4180
|
+
if (options.maxCommentsPerPost !== void 0)
|
|
4181
|
+
params.maxCommentsPerPost = options.maxCommentsPerPost;
|
|
4182
|
+
if (options.excludeUrls !== void 0)
|
|
4183
|
+
params.excludeUrls = options.excludeUrls;
|
|
4184
|
+
if (options.limit !== void 0)
|
|
4185
|
+
params.limit = options.limit;
|
|
4186
|
+
return this.create({
|
|
4187
|
+
messages: [{ role: "user", content: query }],
|
|
4188
|
+
specializedAgent: "influencer_engagement",
|
|
4189
|
+
specializedAgentParams: params
|
|
4190
|
+
});
|
|
4191
|
+
}
|
|
3998
4192
|
/**
|
|
3999
4193
|
* Score people who reacted to or commented on competitor LinkedIn posts.
|
|
4000
4194
|
*
|