@coldiq/mcp 0.2.6 → 0.2.8
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/registry.d.ts.map +1 -1
- package/dist/registry.js +9 -3
- package/dist/registry.js.map +1 -1
- package/dist/tools/find-signals.d.ts +2 -0
- package/dist/tools/find-signals.d.ts.map +1 -1
- package/dist/tools/find-signals.js +10 -1
- package/dist/tools/find-signals.js.map +1 -1
- package/dist/tools/search-places.d.ts +6 -0
- package/dist/tools/search-places.d.ts.map +1 -1
- package/dist/tools/search-places.js +48 -4
- package/dist/tools/search-places.js.map +1 -1
- package/dist/tools/search-reddit.d.ts +8 -5
- package/dist/tools/search-reddit.d.ts.map +1 -1
- package/dist/tools/search-reddit.js +15 -9
- package/dist/tools/search-reddit.js.map +1 -1
- package/package.json +1 -1
- package/src/registry.ts +8 -3
- package/src/tools/find-signals.ts +10 -1
- package/src/tools/search-places.ts +45 -4
- package/src/tools/search-reddit.ts +15 -9
- package/tests/registry-find-signals.test.ts +31 -0
- package/tests/registry.test.ts +18 -4
- package/tests/tools/search-places.test.ts +97 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"find-signals.d.ts","sourceRoot":"","sources":["../../src/tools/find-signals.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAIvB,eAAO,MAAM,eAAe,iBAAiB,CAAA;AAE7C,eAAO,MAAM,sBAAsB,
|
|
1
|
+
{"version":3,"file":"find-signals.d.ts","sourceRoot":"","sources":["../../src/tools/find-signals.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAIvB,eAAO,MAAM,eAAe,iBAAiB,CAAA;AAE7C,eAAO,MAAM,sBAAsB,QAOyL,CAAA;AAE5N,eAAO,MAAM,iBAAiB;;;;;;;;;;;CA6C7B,CAAA;AAED,wBAAsB,kBAAkB,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;;;;;;;;;;;;GAsEtE"}
|
|
@@ -5,7 +5,8 @@ export const findSignalsName = 'find_signals';
|
|
|
5
5
|
export const findSignalsDescription = 'Retrieve sales intelligence signals — funding rounds, acquisitions, hiring activity, job changes, buying intent, news, and startup posts. ' +
|
|
6
6
|
'Each call targets one signal type. Two modes: ' +
|
|
7
7
|
'Company-targeted (funding | acquisition | hiring | job_change | intent): accepts companies/domains/industries/countries/since filters. ' +
|
|
8
|
-
'
|
|
8
|
+
'funding additionally accepts `round_type` (e.g. ["Series A", "Seed"]). ' +
|
|
9
|
+
'intent REQUIRES at least one of companies or domains and additionally accepts `topics` (e.g. ["sales-automation"]) to narrow by intent keyword. ' +
|
|
9
10
|
'Feed-style (news | startup_post): country and since only — does NOT filter by company. Passing companies/domains for these types is rejected. ' +
|
|
10
11
|
'hiring returns individual job postings with company context (title, location, descriptionText, company industries) — for richer job-board queries with description/seniority/easy-apply filters use search_jobs instead.';
|
|
11
12
|
export const findSignalsSchema = {
|
|
@@ -35,6 +36,14 @@ export const findSignalsSchema = {
|
|
|
35
36
|
.array(z.string())
|
|
36
37
|
.optional()
|
|
37
38
|
.describe('ISO country codes or names to filter by (e.g. ["US", "GB"]). Works for all signal types.'),
|
|
39
|
+
round_type: z
|
|
40
|
+
.array(z.string())
|
|
41
|
+
.optional()
|
|
42
|
+
.describe('Funding round filter (e.g. ["Series A", "Seed"]). Only honored by signal_type=funding. Comma-joined and forwarded to Signalbase\'s `round` filter — case-insensitive substring match upstream, so "Series A" matches "Series A Extension" as well. Silently ignored for other signal types.'),
|
|
43
|
+
topics: z
|
|
44
|
+
.array(z.string())
|
|
45
|
+
.optional()
|
|
46
|
+
.describe('Intent topic / keyword slugs (e.g. ["sales-automation", "lead-generation"]). Only honored by signal_type=intent (forwarded to TheirStack as `keyword_slug_or`). Note: topics is supplemental — TheirStack still requires at least one of `companies` or `domains`, so topics narrows an existing company-targeted search rather than enabling pure topic discovery.'),
|
|
38
47
|
limit: z
|
|
39
48
|
.number()
|
|
40
49
|
.int()
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"find-signals.js","sourceRoot":"","sources":["../../src/tools/find-signals.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAA;AACtE,OAAO,EAAE,yBAAyB,EAAE,yBAAyB,EAAE,MAAM,+BAA+B,CAAA;AAEpG,MAAM,CAAC,MAAM,eAAe,GAAG,cAAc,CAAA;AAE7C,MAAM,CAAC,MAAM,sBAAsB,GACjC,4IAA4I;IAC5I,gDAAgD;IAChD,yIAAyI;IACzI,
|
|
1
|
+
{"version":3,"file":"find-signals.js","sourceRoot":"","sources":["../../src/tools/find-signals.ts"],"names":[],"mappings":"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"}
|
|
@@ -32,6 +32,12 @@ export declare const searchPlacesSchema: {
|
|
|
32
32
|
language: z.ZodOptional<z.ZodString>;
|
|
33
33
|
use_providers: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
34
34
|
};
|
|
35
|
+
export declare function applyPlaceFilters(data: unknown, filters: {
|
|
36
|
+
minRating?: number;
|
|
37
|
+
maxRating?: number;
|
|
38
|
+
minReviews?: number;
|
|
39
|
+
maxReviews?: number;
|
|
40
|
+
}): unknown;
|
|
35
41
|
export declare function searchPlacesHandler(input: Record<string, unknown>): Promise<{
|
|
36
42
|
content: {
|
|
37
43
|
type: "text";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"search-places.d.ts","sourceRoot":"","sources":["../../src/tools/search-places.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAIvB,eAAO,MAAM,gBAAgB,kBAAkB,CAAA;AAE/C,eAAO,MAAM,uBAAuB,2eACmb,CAAA;AAEvd,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAoC9B,CAAA;AAED,wBAAsB,mBAAmB,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"search-places.d.ts","sourceRoot":"","sources":["../../src/tools/search-places.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAIvB,eAAO,MAAM,gBAAgB,kBAAkB,CAAA;AAE/C,eAAO,MAAM,uBAAuB,2eACmb,CAAA;AAEvd,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAoC9B,CAAA;AAaD,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,OAAO,EACb,OAAO,EAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,GAC5F,OAAO,CAmBT;AAED,wBAAsB,mBAAmB,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;;;;;;;;;;;;GAiBvE"}
|
|
@@ -15,10 +15,10 @@ export const searchPlacesSchema = {
|
|
|
15
15
|
long: z.number().optional().describe('Openmart only. Longitude for radius search.'),
|
|
16
16
|
geo_radius: z.number().int().positive().optional().describe('Openmart only. Search radius in meters around lat/long.'),
|
|
17
17
|
tags: z.array(z.string()).max(100).optional().describe('Openmart only. Category tags (mutually exclusive with query upstream — query is ignored if tags non-empty).'),
|
|
18
|
-
min_overall_rating: z.number().min(0).max(5).optional().describe('Openmart
|
|
19
|
-
max_overall_rating: z.number().min(0).max(5).optional().describe('Openmart
|
|
20
|
-
min_total_reviews: z.number().int().min(0).optional().describe('Openmart
|
|
21
|
-
max_total_reviews: z.number().int().min(0).optional().describe('Openmart
|
|
18
|
+
min_overall_rating: z.number().min(0).max(5).optional().describe('Forwarded upstream to Openmart; applied client-side as a post-filter on Google Maps results (each place has a `totalScore` field). Use 0–5.'),
|
|
19
|
+
max_overall_rating: z.number().min(0).max(5).optional().describe('Forwarded upstream to Openmart; applied client-side as a post-filter on Google Maps results (each place has a `totalScore` field). Use 0–5.'),
|
|
20
|
+
min_total_reviews: z.number().int().min(0).optional().describe('Forwarded upstream to Openmart; applied client-side as a post-filter on Google Maps results (each place has a `reviewsCount` field).'),
|
|
21
|
+
max_total_reviews: z.number().int().min(0).optional().describe('Forwarded upstream to Openmart; applied client-side as a post-filter on Google Maps results (each place has a `reviewsCount` field).'),
|
|
22
22
|
ownership_type: z.enum(['INDEPENDENT', 'FAMILY', 'FRANCHISE', 'CHAIN']).optional().describe('Openmart only.'),
|
|
23
23
|
has_website: z.boolean().optional().describe('Openmart only.'),
|
|
24
24
|
has_valid_website: z.boolean().optional().describe('Openmart only.'),
|
|
@@ -34,6 +34,44 @@ export const searchPlacesSchema = {
|
|
|
34
34
|
language: z.string().optional().describe('Google Maps only. ISO 639-1 (e.g. "en", "fr"). Routes to Google Maps only when set.'),
|
|
35
35
|
use_providers: z.array(z.string()).optional().describe(`Optional ordered list of providers to use. Leave empty to let ColdIQ automatically pick the best tool for your inputs — recommended for most use cases. Available providers: ${getProvidersForCapability('search_places').join(', ')}. Provider names are matched fuzzily, so minor typos are tolerated.`),
|
|
36
36
|
};
|
|
37
|
+
function asNumber(v) {
|
|
38
|
+
return typeof v === 'number' && Number.isFinite(v) ? v : undefined;
|
|
39
|
+
}
|
|
40
|
+
// Google Maps Scraper does not honor min/max rating or review-count filters
|
|
41
|
+
// upstream, so the params would otherwise be silently dropped. Filter client-side
|
|
42
|
+
// against the `totalScore` (rating) and `reviewsCount` fields on each place.
|
|
43
|
+
// Applied to all routes for consistency; on Openmart this is a no-op since the
|
|
44
|
+
// filters were already enforced upstream and Openmart returns `{ data: [...] }`
|
|
45
|
+
// rather than `{ places: [...] }`.
|
|
46
|
+
// Pure: returns a new object instead of mutating its argument.
|
|
47
|
+
export function applyPlaceFilters(data, filters) {
|
|
48
|
+
const { minRating, maxRating, minReviews, maxReviews } = filters;
|
|
49
|
+
if (minRating === undefined && maxRating === undefined && minReviews === undefined && maxReviews === undefined)
|
|
50
|
+
return data;
|
|
51
|
+
if (!data || typeof data !== 'object')
|
|
52
|
+
return data;
|
|
53
|
+
const d = data;
|
|
54
|
+
const places = d.places;
|
|
55
|
+
if (!Array.isArray(places))
|
|
56
|
+
return data;
|
|
57
|
+
const filtered = places.filter((place) => {
|
|
58
|
+
if (!place || typeof place !== 'object')
|
|
59
|
+
return false;
|
|
60
|
+
const p = place;
|
|
61
|
+
const rating = asNumber(p.totalScore);
|
|
62
|
+
const reviews = asNumber(p.reviewsCount);
|
|
63
|
+
if (minRating !== undefined && (rating === undefined || rating < minRating))
|
|
64
|
+
return false;
|
|
65
|
+
if (maxRating !== undefined && (rating === undefined || rating > maxRating))
|
|
66
|
+
return false;
|
|
67
|
+
if (minReviews !== undefined && (reviews === undefined || reviews < minReviews))
|
|
68
|
+
return false;
|
|
69
|
+
if (maxReviews !== undefined && (reviews === undefined || reviews > maxReviews))
|
|
70
|
+
return false;
|
|
71
|
+
return true;
|
|
72
|
+
});
|
|
73
|
+
return { ...d, places: filtered };
|
|
74
|
+
}
|
|
37
75
|
export async function searchPlacesHandler(input) {
|
|
38
76
|
const { use_providers: rawUseProviders, ...restInput } = input;
|
|
39
77
|
const resolved = resolvePreferredProviders('search_places', restInput, rawUseProviders);
|
|
@@ -44,6 +82,12 @@ export async function searchPlacesHandler(input) {
|
|
|
44
82
|
if (isExecutionError(result)) {
|
|
45
83
|
return { content: [{ type: 'text', text: JSON.stringify(result) }], isError: true };
|
|
46
84
|
}
|
|
85
|
+
result.data = applyPlaceFilters(result.data, {
|
|
86
|
+
minRating: asNumber(restInput.min_overall_rating),
|
|
87
|
+
maxRating: asNumber(restInput.max_overall_rating),
|
|
88
|
+
minReviews: asNumber(restInput.min_total_reviews),
|
|
89
|
+
maxReviews: asNumber(restInput.max_total_reviews),
|
|
90
|
+
});
|
|
47
91
|
return { content: [{ type: 'text', text: JSON.stringify(result) }] };
|
|
48
92
|
}
|
|
49
93
|
//# sourceMappingURL=search-places.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"search-places.js","sourceRoot":"","sources":["../../src/tools/search-places.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAA;AACtE,OAAO,EAAE,yBAAyB,EAAE,yBAAyB,EAAE,MAAM,+BAA+B,CAAA;AAEpG,MAAM,CAAC,MAAM,gBAAgB,GAAG,eAAe,CAAA;AAE/C,MAAM,CAAC,MAAM,uBAAuB,GAClC,qdAAqd,CAAA;AAEvd,MAAM,CAAC,MAAM,kBAAkB,GAAG;IAChC,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,iGAAiG,CAAC;IACxI,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,4HAA4H,CAAC;IACrK,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,oCAAoC,CAAC;IAC1E,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,wGAAwG,CAAC;IACtK,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,yGAAyG,CAAC;IAE5K,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,6CAA6C,CAAC;IACpF,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,gBAAgB,CAAC;IAC1D,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,4CAA4C,CAAC;IACjF,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,6CAA6C,CAAC;IACnF,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,yDAAyD,CAAC;IAEtH,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,6GAA6G,CAAC;IAErK,kBAAkB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,
|
|
1
|
+
{"version":3,"file":"search-places.js","sourceRoot":"","sources":["../../src/tools/search-places.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
export declare const searchRedditName = "search_reddit";
|
|
3
|
-
export declare const searchRedditDescription = "Scrape Reddit posts
|
|
3
|
+
export declare const searchRedditDescription = "Scrape Reddit posts, comments, communities, or users via 1 provider (Reddit Scraper). Provide subreddit/post/user URLs and/or a keyword query. Optionally scope a query to one community, sort, filter by time, include comments, and limit by date. Async (~30\u2013120s). Cost: 1 credit per item returned.";
|
|
4
4
|
export declare const searchRedditSchema: {
|
|
5
|
-
start_urls: z.ZodArray<z.ZodString, "many"
|
|
5
|
+
start_urls: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
6
6
|
query: z.ZodOptional<z.ZodString>;
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
search_type: z.ZodDefault<z.ZodEnum<["posts", "comments", "communities", "users"]>>;
|
|
8
|
+
search_community_name: z.ZodOptional<z.ZodString>;
|
|
9
|
+
sort: z.ZodOptional<z.ZodEnum<["relevance", "hot", "top", "new", "rising", "comments"]>>;
|
|
9
10
|
time: z.ZodOptional<z.ZodEnum<["hour", "day", "week", "month", "year", "all"]>>;
|
|
10
11
|
limit: z.ZodDefault<z.ZodNumber>;
|
|
11
|
-
|
|
12
|
+
max_comments: z.ZodOptional<z.ZodNumber>;
|
|
12
13
|
include_comments: z.ZodOptional<z.ZodBoolean>;
|
|
14
|
+
post_date_limit: z.ZodOptional<z.ZodString>;
|
|
15
|
+
comment_date_limit: z.ZodOptional<z.ZodString>;
|
|
13
16
|
use_providers: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
14
17
|
};
|
|
15
18
|
export declare function searchRedditHandler(input: Record<string, unknown>): Promise<{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"search-reddit.d.ts","sourceRoot":"","sources":["../../src/tools/search-reddit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAIvB,eAAO,MAAM,gBAAgB,kBAAkB,CAAA;AAE/C,eAAO,MAAM,uBAAuB,
|
|
1
|
+
{"version":3,"file":"search-reddit.d.ts","sourceRoot":"","sources":["../../src/tools/search-reddit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAIvB,eAAO,MAAM,gBAAgB,kBAAkB,CAAA;AAE/C,eAAO,MAAM,uBAAuB,kTACwQ,CAAA;AAE5S,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;CAwB9B,CAAA;AAED,wBAAsB,mBAAmB,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;;;;;;;;;;;;GAWvE"}
|
|
@@ -2,24 +2,30 @@ import { z } from 'zod';
|
|
|
2
2
|
import { executeWithFallback, isExecutionError } from '../executor.js';
|
|
3
3
|
import { resolvePreferredProviders, getProvidersForCapability } from '../utils/provider-resolver.js';
|
|
4
4
|
export const searchRedditName = 'search_reddit';
|
|
5
|
-
export const searchRedditDescription = 'Scrape Reddit posts
|
|
5
|
+
export const searchRedditDescription = 'Scrape Reddit posts, comments, communities, or users via 1 provider (Reddit Scraper). Provide subreddit/post/user URLs and/or a keyword query. Optionally scope a query to one community, sort, filter by time, include comments, and limit by date. Async (~30–120s). Cost: 1 credit per item returned.';
|
|
6
6
|
export const searchRedditSchema = {
|
|
7
|
-
start_urls: z.array(z.string().url()).
|
|
8
|
-
.describe('Reddit URLs to scrape (subreddit, post, or search URL).
|
|
7
|
+
start_urls: z.array(z.string().url()).max(25).optional()
|
|
8
|
+
.describe('Reddit URLs to scrape (subreddit, post, user, or search URL). Up to 25. Provide this and/or query. Example: ["https://www.reddit.com/r/sales/"]'),
|
|
9
9
|
query: z.string().optional()
|
|
10
|
-
.describe('
|
|
11
|
-
|
|
12
|
-
.describe('
|
|
13
|
-
|
|
10
|
+
.describe('Keyword search query run across Reddit e.g. "best CRM for startups". Provide this and/or start_urls.'),
|
|
11
|
+
search_type: z.enum(['posts', 'comments', 'communities', 'users']).default('posts')
|
|
12
|
+
.describe('What the search query returns: posts, comments, communities, or users.'),
|
|
13
|
+
search_community_name: z.string().optional()
|
|
14
|
+
.describe('Restrict the search query to a single community e.g. "sales".'),
|
|
15
|
+
sort: z.enum(['relevance', 'hot', 'top', 'new', 'rising', 'comments']).optional()
|
|
14
16
|
.describe('Sort order for results.'),
|
|
15
17
|
time: z.enum(['hour', 'day', 'week', 'month', 'year', 'all']).optional()
|
|
16
18
|
.describe('Time filter.'),
|
|
17
19
|
limit: z.number().int().min(1).max(200).default(10)
|
|
18
20
|
.describe('Max items to return (1–200). 1 credit per item.'),
|
|
19
|
-
|
|
20
|
-
.describe('Max comments per post
|
|
21
|
+
max_comments: z.number().int().min(0).max(1000).optional()
|
|
22
|
+
.describe('Max comments to fetch per post. Set 0 to skip comments.'),
|
|
21
23
|
include_comments: z.boolean().optional()
|
|
22
24
|
.describe('Include comments alongside posts.'),
|
|
25
|
+
post_date_limit: z.string().optional()
|
|
26
|
+
.describe('Only return posts published on or after this date (ISO 8601, e.g. "2025-01-01").'),
|
|
27
|
+
comment_date_limit: z.string().optional()
|
|
28
|
+
.describe('Only return comments published on or after this date (ISO 8601, e.g. "2025-01-01").'),
|
|
23
29
|
use_providers: z.array(z.string()).optional().describe(`Optional ordered list of providers to use. Leave empty to let ColdIQ automatically pick the best tool for your inputs — recommended for most use cases. Available providers: ${getProvidersForCapability('search_reddit').join(', ')}. Provider names are matched fuzzily, so minor typos are tolerated.`),
|
|
24
30
|
};
|
|
25
31
|
export async function searchRedditHandler(input) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"search-reddit.js","sourceRoot":"","sources":["../../src/tools/search-reddit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAA;AACtE,OAAO,EAAE,yBAAyB,EAAE,yBAAyB,EAAE,MAAM,+BAA+B,CAAA;AAEpG,MAAM,CAAC,MAAM,gBAAgB,GAAG,eAAe,CAAA;AAE/C,MAAM,CAAC,MAAM,uBAAuB,GAClC,
|
|
1
|
+
{"version":3,"file":"search-reddit.js","sourceRoot":"","sources":["../../src/tools/search-reddit.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/src/registry.ts
CHANGED
|
@@ -2549,17 +2549,20 @@ const searchRedditProviders: ProviderEntry[] = [
|
|
|
2549
2549
|
endpoint: '/reddit/scrape',
|
|
2550
2550
|
method: 'POST',
|
|
2551
2551
|
priority: 1,
|
|
2552
|
-
isApplicable: (input) => isNonEmptyArray(input.start_urls),
|
|
2552
|
+
isApplicable: (input) => isNonEmptyArray(input.start_urls) || typeof input.query === 'string',
|
|
2553
2553
|
mapParams: (input) => ({
|
|
2554
2554
|
body: {
|
|
2555
2555
|
searchQueries: input.query ? [input.query] : undefined,
|
|
2556
2556
|
startUrls: (input.start_urls as string[] | undefined)?.map((url) => ({ url })),
|
|
2557
|
-
|
|
2557
|
+
searchType: input.search_type ?? 'posts',
|
|
2558
|
+
searchCommunityName: input.search_community_name,
|
|
2558
2559
|
sort: input.sort,
|
|
2559
2560
|
time: input.time,
|
|
2560
2561
|
maxItems: Math.min(Math.max((input.limit as number | undefined) ?? 10, 1), 200),
|
|
2561
|
-
|
|
2562
|
+
maxComments: input.max_comments,
|
|
2562
2563
|
includeComments: input.include_comments,
|
|
2564
|
+
postDateLimit: input.post_date_limit,
|
|
2565
|
+
commentDateLimit: input.comment_date_limit,
|
|
2563
2566
|
},
|
|
2564
2567
|
}),
|
|
2565
2568
|
hasResult: (data) => isNonEmptyArray((data as { items?: unknown[] }).items),
|
|
@@ -3063,6 +3066,7 @@ const findSignalsProviders: ProviderEntry[] = [
|
|
|
3063
3066
|
if (typeof input.since === 'string') qp.dateFrom = input.since
|
|
3064
3067
|
if (isNonEmptyArray(input.industries)) qp.industry = (input.industries as string[]).join(',')
|
|
3065
3068
|
if (isNonEmptyArray(input.countries)) qp.countries = (input.countries as string[]).join(',')
|
|
3069
|
+
if (isNonEmptyArray(input.round_type)) qp.round = (input.round_type as string[]).join(',')
|
|
3066
3070
|
qp.limit = String(Math.min((input.limit as number | undefined) ?? 25, 100))
|
|
3067
3071
|
return { queryParams: qp }
|
|
3068
3072
|
},
|
|
@@ -3171,6 +3175,7 @@ const findSignalsProviders: ProviderEntry[] = [
|
|
|
3171
3175
|
body: {
|
|
3172
3176
|
...(isNonEmptyArray(input.companies) && { company_name_or: input.companies }),
|
|
3173
3177
|
...(isNonEmptyArray(input.domains) && { company_domain: (input.domains as string[])[0] }),
|
|
3178
|
+
...(isNonEmptyArray(input.topics) && { keyword_slug_or: input.topics }),
|
|
3174
3179
|
},
|
|
3175
3180
|
}),
|
|
3176
3181
|
hasResult: (data) => isNonEmptyArray((data as Record<string, unknown>).data),
|
|
@@ -8,7 +8,8 @@ export const findSignalsDescription =
|
|
|
8
8
|
'Retrieve sales intelligence signals — funding rounds, acquisitions, hiring activity, job changes, buying intent, news, and startup posts. ' +
|
|
9
9
|
'Each call targets one signal type. Two modes: ' +
|
|
10
10
|
'Company-targeted (funding | acquisition | hiring | job_change | intent): accepts companies/domains/industries/countries/since filters. ' +
|
|
11
|
-
'
|
|
11
|
+
'funding additionally accepts `round_type` (e.g. ["Series A", "Seed"]). ' +
|
|
12
|
+
'intent REQUIRES at least one of companies or domains and additionally accepts `topics` (e.g. ["sales-automation"]) to narrow by intent keyword. ' +
|
|
12
13
|
'Feed-style (news | startup_post): country and since only — does NOT filter by company. Passing companies/domains for these types is rejected. ' +
|
|
13
14
|
'hiring returns individual job postings with company context (title, location, descriptionText, company industries) — for richer job-board queries with description/seniority/easy-apply filters use search_jobs instead.'
|
|
14
15
|
|
|
@@ -41,6 +42,14 @@ export const findSignalsSchema = {
|
|
|
41
42
|
.array(z.string())
|
|
42
43
|
.optional()
|
|
43
44
|
.describe('ISO country codes or names to filter by (e.g. ["US", "GB"]). Works for all signal types.'),
|
|
45
|
+
round_type: z
|
|
46
|
+
.array(z.string())
|
|
47
|
+
.optional()
|
|
48
|
+
.describe('Funding round filter (e.g. ["Series A", "Seed"]). Only honored by signal_type=funding. Comma-joined and forwarded to Signalbase\'s `round` filter — case-insensitive substring match upstream, so "Series A" matches "Series A Extension" as well. Silently ignored for other signal types.'),
|
|
49
|
+
topics: z
|
|
50
|
+
.array(z.string())
|
|
51
|
+
.optional()
|
|
52
|
+
.describe('Intent topic / keyword slugs (e.g. ["sales-automation", "lead-generation"]). Only honored by signal_type=intent (forwarded to TheirStack as `keyword_slug_or`). Note: topics is supplemental — TheirStack still requires at least one of `companies` or `domains`, so topics narrows an existing company-targeted search rather than enabling pure topic discovery.'),
|
|
44
53
|
limit: z
|
|
45
54
|
.number()
|
|
46
55
|
.int()
|
|
@@ -22,10 +22,10 @@ export const searchPlacesSchema = {
|
|
|
22
22
|
|
|
23
23
|
tags: z.array(z.string()).max(100).optional().describe('Openmart only. Category tags (mutually exclusive with query upstream — query is ignored if tags non-empty).'),
|
|
24
24
|
|
|
25
|
-
min_overall_rating: z.number().min(0).max(5).optional().describe('Openmart
|
|
26
|
-
max_overall_rating: z.number().min(0).max(5).optional().describe('Openmart
|
|
27
|
-
min_total_reviews: z.number().int().min(0).optional().describe('Openmart
|
|
28
|
-
max_total_reviews: z.number().int().min(0).optional().describe('Openmart
|
|
25
|
+
min_overall_rating: z.number().min(0).max(5).optional().describe('Forwarded upstream to Openmart; applied client-side as a post-filter on Google Maps results (each place has a `totalScore` field). Use 0–5.'),
|
|
26
|
+
max_overall_rating: z.number().min(0).max(5).optional().describe('Forwarded upstream to Openmart; applied client-side as a post-filter on Google Maps results (each place has a `totalScore` field). Use 0–5.'),
|
|
27
|
+
min_total_reviews: z.number().int().min(0).optional().describe('Forwarded upstream to Openmart; applied client-side as a post-filter on Google Maps results (each place has a `reviewsCount` field).'),
|
|
28
|
+
max_total_reviews: z.number().int().min(0).optional().describe('Forwarded upstream to Openmart; applied client-side as a post-filter on Google Maps results (each place has a `reviewsCount` field).'),
|
|
29
29
|
|
|
30
30
|
ownership_type: z.enum(['INDEPENDENT', 'FAMILY', 'FRANCHISE', 'CHAIN']).optional().describe('Openmart only.'),
|
|
31
31
|
has_website: z.boolean().optional().describe('Openmart only.'),
|
|
@@ -45,6 +45,41 @@ export const searchPlacesSchema = {
|
|
|
45
45
|
use_providers: z.array(z.string()).optional().describe(`Optional ordered list of providers to use. Leave empty to let ColdIQ automatically pick the best tool for your inputs — recommended for most use cases. Available providers: ${getProvidersForCapability('search_places').join(', ')}. Provider names are matched fuzzily, so minor typos are tolerated.`),
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
+
function asNumber(v: unknown): number | undefined {
|
|
49
|
+
return typeof v === 'number' && Number.isFinite(v) ? v : undefined
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Google Maps Scraper does not honor min/max rating or review-count filters
|
|
53
|
+
// upstream, so the params would otherwise be silently dropped. Filter client-side
|
|
54
|
+
// against the `totalScore` (rating) and `reviewsCount` fields on each place.
|
|
55
|
+
// Applied to all routes for consistency; on Openmart this is a no-op since the
|
|
56
|
+
// filters were already enforced upstream and Openmart returns `{ data: [...] }`
|
|
57
|
+
// rather than `{ places: [...] }`.
|
|
58
|
+
// Pure: returns a new object instead of mutating its argument.
|
|
59
|
+
export function applyPlaceFilters(
|
|
60
|
+
data: unknown,
|
|
61
|
+
filters: { minRating?: number; maxRating?: number; minReviews?: number; maxReviews?: number },
|
|
62
|
+
): unknown {
|
|
63
|
+
const { minRating, maxRating, minReviews, maxReviews } = filters
|
|
64
|
+
if (minRating === undefined && maxRating === undefined && minReviews === undefined && maxReviews === undefined) return data
|
|
65
|
+
if (!data || typeof data !== 'object') return data
|
|
66
|
+
const d = data as Record<string, unknown>
|
|
67
|
+
const places = d.places
|
|
68
|
+
if (!Array.isArray(places)) return data
|
|
69
|
+
const filtered = places.filter((place) => {
|
|
70
|
+
if (!place || typeof place !== 'object') return false
|
|
71
|
+
const p = place as Record<string, unknown>
|
|
72
|
+
const rating = asNumber(p.totalScore)
|
|
73
|
+
const reviews = asNumber(p.reviewsCount)
|
|
74
|
+
if (minRating !== undefined && (rating === undefined || rating < minRating)) return false
|
|
75
|
+
if (maxRating !== undefined && (rating === undefined || rating > maxRating)) return false
|
|
76
|
+
if (minReviews !== undefined && (reviews === undefined || reviews < minReviews)) return false
|
|
77
|
+
if (maxReviews !== undefined && (reviews === undefined || reviews > maxReviews)) return false
|
|
78
|
+
return true
|
|
79
|
+
})
|
|
80
|
+
return { ...d, places: filtered }
|
|
81
|
+
}
|
|
82
|
+
|
|
48
83
|
export async function searchPlacesHandler(input: Record<string, unknown>) {
|
|
49
84
|
const { use_providers: rawUseProviders, ...restInput } = input
|
|
50
85
|
const resolved = resolvePreferredProviders('search_places', restInput, rawUseProviders)
|
|
@@ -55,5 +90,11 @@ export async function searchPlacesHandler(input: Record<string, unknown>) {
|
|
|
55
90
|
if (isExecutionError(result)) {
|
|
56
91
|
return { content: [{ type: 'text' as const, text: JSON.stringify(result) }], isError: true }
|
|
57
92
|
}
|
|
93
|
+
result.data = applyPlaceFilters(result.data, {
|
|
94
|
+
minRating: asNumber(restInput.min_overall_rating),
|
|
95
|
+
maxRating: asNumber(restInput.max_overall_rating),
|
|
96
|
+
minReviews: asNumber(restInput.min_total_reviews),
|
|
97
|
+
maxReviews: asNumber(restInput.max_total_reviews),
|
|
98
|
+
})
|
|
58
99
|
return { content: [{ type: 'text' as const, text: JSON.stringify(result) }] }
|
|
59
100
|
}
|
|
@@ -5,25 +5,31 @@ import { resolvePreferredProviders, getProvidersForCapability } from '../utils/p
|
|
|
5
5
|
export const searchRedditName = 'search_reddit'
|
|
6
6
|
|
|
7
7
|
export const searchRedditDescription =
|
|
8
|
-
'Scrape Reddit posts
|
|
8
|
+
'Scrape Reddit posts, comments, communities, or users via 1 provider (Reddit Scraper). Provide subreddit/post/user URLs and/or a keyword query. Optionally scope a query to one community, sort, filter by time, include comments, and limit by date. Async (~30–120s). Cost: 1 credit per item returned.'
|
|
9
9
|
|
|
10
10
|
export const searchRedditSchema = {
|
|
11
|
-
start_urls: z.array(z.string().url()).
|
|
12
|
-
.describe('Reddit URLs to scrape (subreddit, post, or search URL).
|
|
11
|
+
start_urls: z.array(z.string().url()).max(25).optional()
|
|
12
|
+
.describe('Reddit URLs to scrape (subreddit, post, user, or search URL). Up to 25. Provide this and/or query. Example: ["https://www.reddit.com/r/sales/"]'),
|
|
13
13
|
query: z.string().optional()
|
|
14
|
-
.describe('
|
|
15
|
-
|
|
16
|
-
.describe('
|
|
17
|
-
|
|
14
|
+
.describe('Keyword search query run across Reddit e.g. "best CRM for startups". Provide this and/or start_urls.'),
|
|
15
|
+
search_type: z.enum(['posts', 'comments', 'communities', 'users']).default('posts')
|
|
16
|
+
.describe('What the search query returns: posts, comments, communities, or users.'),
|
|
17
|
+
search_community_name: z.string().optional()
|
|
18
|
+
.describe('Restrict the search query to a single community e.g. "sales".'),
|
|
19
|
+
sort: z.enum(['relevance', 'hot', 'top', 'new', 'rising', 'comments']).optional()
|
|
18
20
|
.describe('Sort order for results.'),
|
|
19
21
|
time: z.enum(['hour', 'day', 'week', 'month', 'year', 'all']).optional()
|
|
20
22
|
.describe('Time filter.'),
|
|
21
23
|
limit: z.number().int().min(1).max(200).default(10)
|
|
22
24
|
.describe('Max items to return (1–200). 1 credit per item.'),
|
|
23
|
-
|
|
24
|
-
.describe('Max comments per post
|
|
25
|
+
max_comments: z.number().int().min(0).max(1000).optional()
|
|
26
|
+
.describe('Max comments to fetch per post. Set 0 to skip comments.'),
|
|
25
27
|
include_comments: z.boolean().optional()
|
|
26
28
|
.describe('Include comments alongside posts.'),
|
|
29
|
+
post_date_limit: z.string().optional()
|
|
30
|
+
.describe('Only return posts published on or after this date (ISO 8601, e.g. "2025-01-01").'),
|
|
31
|
+
comment_date_limit: z.string().optional()
|
|
32
|
+
.describe('Only return comments published on or after this date (ISO 8601, e.g. "2025-01-01").'),
|
|
27
33
|
use_providers: z.array(z.string()).optional().describe(`Optional ordered list of providers to use. Leave empty to let ColdIQ automatically pick the best tool for your inputs — recommended for most use cases. Available providers: ${getProvidersForCapability('search_reddit').join(', ')}. Provider names are matched fuzzily, so minor typos are tolerated.`),
|
|
28
34
|
}
|
|
29
35
|
|
|
@@ -60,6 +60,18 @@ describe('signalbase-funding', () => {
|
|
|
60
60
|
expect((result.queryParams as Record<string, string>).limit).toBe('100')
|
|
61
61
|
})
|
|
62
62
|
|
|
63
|
+
it('mapParams forwards round_type as comma-joined `round` upstream param', () => {
|
|
64
|
+
const result = p().mapParams({ signal_type: 'funding', round_type: ['Series A', 'Seed'], limit: 10 })
|
|
65
|
+
expect((result.queryParams as Record<string, string>).round).toBe('Series A,Seed')
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
it('mapParams omits `round` when round_type is missing or empty', () => {
|
|
69
|
+
const noRound = p().mapParams({ signal_type: 'funding', limit: 10 })
|
|
70
|
+
expect((noRound.queryParams as Record<string, string>).round).toBeUndefined()
|
|
71
|
+
const emptyRound = p().mapParams({ signal_type: 'funding', round_type: [], limit: 10 })
|
|
72
|
+
expect((emptyRound.queryParams as Record<string, string>).round).toBeUndefined()
|
|
73
|
+
})
|
|
74
|
+
|
|
63
75
|
it('hasResult: true when data array non-empty', () => {
|
|
64
76
|
expect(p().hasResult({ data: [{ company: 'ColdIQ', amount: 1000000 }] })).toBe(true)
|
|
65
77
|
})
|
|
@@ -335,6 +347,25 @@ describe('theirstack-buying-intents', () => {
|
|
|
335
347
|
const body = result.body as Record<string, unknown>
|
|
336
348
|
expect(body.company_name_or).toBeUndefined()
|
|
337
349
|
expect(body.company_domain).toBeUndefined()
|
|
350
|
+
expect(body.keyword_slug_or).toBeUndefined()
|
|
351
|
+
})
|
|
352
|
+
|
|
353
|
+
it('mapParams forwards topics as keyword_slug_or upstream param', () => {
|
|
354
|
+
const result = p().mapParams({
|
|
355
|
+
signal_type: 'intent',
|
|
356
|
+
companies: ['ColdIQ'],
|
|
357
|
+
topics: ['sales-automation', 'lead-generation'],
|
|
358
|
+
})
|
|
359
|
+
const body = result.body as Record<string, unknown>
|
|
360
|
+
expect(body.keyword_slug_or).toEqual(['sales-automation', 'lead-generation'])
|
|
361
|
+
// topics is supplemental — company filter still forwarded.
|
|
362
|
+
expect(body.company_name_or).toEqual(['ColdIQ'])
|
|
363
|
+
})
|
|
364
|
+
|
|
365
|
+
it('mapParams omits keyword_slug_or when topics is empty', () => {
|
|
366
|
+
const result = p().mapParams({ signal_type: 'intent', companies: ['ColdIQ'], topics: [] })
|
|
367
|
+
const body = result.body as Record<string, unknown>
|
|
368
|
+
expect(body.keyword_slug_or).toBeUndefined()
|
|
338
369
|
})
|
|
339
370
|
|
|
340
371
|
it('hasResult: true when data non-empty', () => {
|
package/tests/registry.test.ts
CHANGED
|
@@ -1936,11 +1936,11 @@ describe('registry', () => {
|
|
|
1936
1936
|
expect(() => r.async!.extractId({})).toThrow('no jobId')
|
|
1937
1937
|
})
|
|
1938
1938
|
|
|
1939
|
-
it('reddit.isApplicable: true
|
|
1939
|
+
it('reddit.isApplicable: true when start_urls is non-empty or a query string is provided', () => {
|
|
1940
1940
|
const r = getProviders('search_reddit').find((p) => p.id === 'reddit')!
|
|
1941
1941
|
expect(r.isApplicable!({ start_urls: ['https://reddit.com/r/sales/'] })).toBe(true)
|
|
1942
1942
|
expect(r.isApplicable!({ query: 'x', start_urls: ['https://reddit.com/r/sales/'] })).toBe(true)
|
|
1943
|
-
expect(r.isApplicable!({ query: 'B2B sales' })).toBe(
|
|
1943
|
+
expect(r.isApplicable!({ query: 'B2B sales' })).toBe(true)
|
|
1944
1944
|
expect(r.isApplicable!({})).toBe(false)
|
|
1945
1945
|
expect(r.isApplicable!({ start_urls: [] })).toBe(false)
|
|
1946
1946
|
})
|
|
@@ -1949,18 +1949,32 @@ describe('registry', () => {
|
|
|
1949
1949
|
const r = getProviders('search_reddit').find((p) => p.id === 'reddit')!
|
|
1950
1950
|
const out = r.mapParams({
|
|
1951
1951
|
query: 'best CRM',
|
|
1952
|
-
|
|
1952
|
+
search_type: 'communities',
|
|
1953
|
+
search_community_name: 'sales',
|
|
1953
1954
|
sort: 'top',
|
|
1954
1955
|
time: 'month',
|
|
1955
1956
|
limit: 10,
|
|
1956
1957
|
include_comments: true,
|
|
1958
|
+
max_comments: 5,
|
|
1959
|
+
post_date_limit: '2025-01-01',
|
|
1960
|
+
comment_date_limit: '2025-02-01',
|
|
1957
1961
|
}).body as Record<string, unknown>
|
|
1958
1962
|
expect(out.searchQueries).toEqual(['best CRM'])
|
|
1959
|
-
expect(out.
|
|
1963
|
+
expect(out.searchType).toBe('communities')
|
|
1964
|
+
expect(out.searchCommunityName).toBe('sales')
|
|
1960
1965
|
expect(out.sort).toBe('top')
|
|
1961
1966
|
expect(out.time).toBe('month')
|
|
1962
1967
|
expect(out.maxItems).toBe(10)
|
|
1963
1968
|
expect(out.includeComments).toBe(true)
|
|
1969
|
+
expect(out.maxComments).toBe(5)
|
|
1970
|
+
expect(out.postDateLimit).toBe('2025-01-01')
|
|
1971
|
+
expect(out.commentDateLimit).toBe('2025-02-01')
|
|
1972
|
+
})
|
|
1973
|
+
|
|
1974
|
+
it('reddit.mapParams: defaults searchType to posts', () => {
|
|
1975
|
+
const r = getProviders('search_reddit').find((p) => p.id === 'reddit')!
|
|
1976
|
+
const out = r.mapParams({ query: 'x' }).body as Record<string, unknown>
|
|
1977
|
+
expect(out.searchType).toBe('posts')
|
|
1964
1978
|
})
|
|
1965
1979
|
|
|
1966
1980
|
it('reddit.mapParams: clamps maxItems to [1,200]', () => {
|