composio-scavio 0.1.1 → 0.3.0

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
@@ -31,15 +31,14 @@ var str = (d) => import_zod.z.string().describe(d);
31
31
  var ostr = (d) => import_zod.z.string().optional().describe(d);
32
32
  var onum = (d) => import_zod.z.number().optional().describe(d);
33
33
  var obool = (d) => import_zod.z.boolean().optional().describe(d);
34
- function googleSearchParams(i) {
35
- const params = { query: i.query };
36
- if (i.countryCode != null) params.gl = i.countryCode;
37
- if (i.language != null) params.hl = i.language;
38
- if (i.page != null && i.page > 1) params.start = (i.page - 1) * 10;
39
- if (i.device != null) params.device = i.device;
40
- if (i.nfpr != null) params.nfpr = i.nfpr;
41
- return params;
42
- }
34
+ var gl = ostr("Country of the search (ISO 3166-1 alpha-2, e.g. 'us', 'gb', 'de').");
35
+ var hl = ostr("UI language (ISO 639-1, e.g. 'en').");
36
+ var googleDomain = ostr("Regional Google domain, e.g. 'google.co.uk'.");
37
+ var location = ostr("Canonical location name, e.g. 'Austin, Texas, United States'. Encoded server-side.");
38
+ var device = ostr("Device to emulate: 'desktop' or 'mobile'.");
39
+ var currency = ostr("Currency code (ISO 4217, e.g. 'USD').");
40
+ var checkInDate = str("Check-in date (YYYY-MM-DD).");
41
+ var checkOutDate = str("Check-out date (YYYY-MM-DD).");
43
42
  function buildScavioToolkit(options = {}) {
44
43
  const {
45
44
  apiKey,
@@ -49,7 +48,10 @@ function buildScavioToolkit(options = {}) {
49
48
  enableYoutube = true,
50
49
  enableReddit = true,
51
50
  enableTiktok = true,
51
+ enableTiktokShop = true,
52
52
  enableInstagram = true,
53
+ enableX = true,
54
+ enableLinkedin = true,
53
55
  all = false
54
56
  } = options;
55
57
  const client = new import_scavio.Scavio({ apiKey: apiKey ?? process.env.SCAVIO_API_KEY });
@@ -67,16 +69,239 @@ function buildScavioToolkit(options = {}) {
67
69
  tool(
68
70
  "GOOGLE_SEARCH",
69
71
  "Scavio Google Search",
70
- "Search Google for real-time web results (organic_results, ads, and the AI Overview when present). Costs 1 credit.",
72
+ "Search Google for real-time web results. Returns organic_results (each with title, link and snippet) plus knowledge_graph, related_questions, ads and the AI Overview when Google shows one. The body is flat - read organic_results at the top level, not under data. Costs 1 credit.",
71
73
  import_zod.z.object({
72
- query: str("The search query."),
73
- countryCode: ostr("Two-letter country code, e.g. 'us'."),
74
- language: ostr("Two-letter language code, e.g. 'en'."),
75
- page: onum("Result page number (1-based)."),
76
- device: ostr("Device profile: 'desktop' or 'mobile'."),
77
- nfpr: obool("Disable auto-correction of the query when true.")
74
+ query: str("The search query (1-500 characters)."),
75
+ gl,
76
+ hl,
77
+ google_domain: googleDomain,
78
+ location,
79
+ device,
80
+ start: onum("Result offset, NOT a page number: 0 is page 1, 10 is page 2, up to 990."),
81
+ time_period: ostr("Restrict results to a recent time window: 'last_hour', 'last_day', 'last_week', 'last_month', or 'last_year'."),
82
+ safe: ostr("Turn SafeSearch on with 'active'."),
83
+ nfpr: obool("Disable spelling correction and auto-fixes when true.")
84
+ }),
85
+ (i) => client.google.search(i)
86
+ ),
87
+ tool(
88
+ "GOOGLE_AI_MODE",
89
+ "Scavio Google AI Mode",
90
+ "Ask Google AI Mode a question. Returns Google's generated answer with its cited sources - use this for a synthesized answer and GOOGLE_SEARCH for a ranked result list. Costs 1 credit.",
91
+ import_zod.z.object({
92
+ query: str("Question or prompt (1-500 characters)."),
93
+ gl,
94
+ hl,
95
+ google_domain: googleDomain,
96
+ location,
97
+ device,
98
+ safe: ostr("Turn SafeSearch on with 'active'.")
99
+ }),
100
+ (i) => client.google.aiMode(i)
101
+ ),
102
+ tool(
103
+ "GOOGLE_MAPS_SEARCH",
104
+ "Scavio Google Maps Search",
105
+ "Search Google Maps for local businesses and places. Returns local results with ratings, review counts, addresses, phone numbers and place ids. Feed a place_id into GOOGLE_MAPS_PLACE or GOOGLE_MAPS_REVIEWS. Costs 1 credit.",
106
+ import_zod.z.object({
107
+ query: str("Search query, e.g. 'coffee shops in Austin' (1-500 characters)."),
108
+ ll: ostr("Map centre as '@lat,lng,zoomz'; controls which area results come from. Maps localizes by map centre, not gl."),
109
+ start: onum("Result offset; must be a multiple of 20 (0, 20, 40, ...)."),
110
+ gl,
111
+ hl,
112
+ google_domain: googleDomain
113
+ }),
114
+ (i) => client.google.mapsSearch(i)
115
+ ),
116
+ tool(
117
+ "GOOGLE_MAPS_PLACE",
118
+ "Scavio Google Maps Place",
119
+ "Fetch one Google Maps place in full: hours, address, phone, website, rating, price level and photos. Provide place_id or data_cid. Costs 1 credit.",
120
+ import_zod.z.object({
121
+ place_id: ostr("Place ID (starts with ChIJ). Provide this or data_cid."),
122
+ data_cid: ostr("Numeric CID. Provide this or place_id.")
123
+ }),
124
+ (i) => client.google.mapsPlace(i)
125
+ ),
126
+ tool(
127
+ "GOOGLE_MAPS_REVIEWS",
128
+ "Scavio Google Maps Reviews",
129
+ "List Google Maps reviews for a place. Provide data_id or place_id. Page with next_page_token; each page costs another credit. Costs 1 credit.",
130
+ import_zod.z.object({
131
+ place_id: ostr("Place ID (starts with ChIJ). Provide this or data_id."),
132
+ data_id: ostr("Data ID in 0xHEX:0xHEX form. Provide this or place_id."),
133
+ num: onum("Reviews per page (1-20)."),
134
+ sort_by: ostr("Review sort order: 'relevance', 'newest', 'highest_rating', or 'lowest_rating'."),
135
+ next_page_token: ostr("Pagination cursor from a prior response."),
136
+ gl,
137
+ hl,
138
+ google_domain: googleDomain
139
+ }),
140
+ (i) => client.google.mapsReviews(i)
141
+ ),
142
+ tool(
143
+ "GOOGLE_SHOPPING",
144
+ "Scavio Google Shopping",
145
+ "Search Google Shopping. Returns product cards with prices, merchants, ratings and catalog ids across retailers - use this for cross-retailer price comparison and AMAZON_SEARCH or WALMART_SEARCH for a single marketplace. Costs 1 credit.",
146
+ import_zod.z.object({
147
+ query: str("Product search query (1-500 characters)."),
148
+ min_price: onum("Minimum price filter."),
149
+ max_price: onum("Maximum price filter."),
150
+ sort_by: onum("0 = relevance, 1 = price ascending, 2 = price descending."),
151
+ free_shipping: obool("Only items with free shipping."),
152
+ on_sale: obool("Only items on sale."),
153
+ start: onum("Result offset."),
154
+ gl,
155
+ hl,
156
+ google_domain: googleDomain,
157
+ location,
158
+ device
159
+ }),
160
+ (i) => client.google.shopping(i)
161
+ ),
162
+ tool(
163
+ "GOOGLE_SHOPPING_PRODUCT",
164
+ "Scavio Google Shopping Product",
165
+ "Fetch one Google Shopping product: specs, reviews, and the sellers carrying it. Pass catalog_id together with query for full detail and the seller list. Costs 1 credit.",
166
+ import_zod.z.object({
167
+ catalog_id: ostr("Durable product catalog id from a shopping search."),
168
+ query: ostr("Product query. Required when catalog_id is set."),
169
+ product_id: ostr("Product id, as an alternative to catalog_id."),
170
+ page_token: ostr("Immersive product page token."),
171
+ sort_by: ostr("Seller sort order: 'base_price', 'total_price', 'promotion', or 'seller_rating'."),
172
+ load_all_stores: obool("Load every available store."),
173
+ more_stores: obool("Fetch additional stores."),
174
+ gl,
175
+ hl,
176
+ google_domain: googleDomain,
177
+ location,
178
+ device: ostr("Device to emulate: 'desktop', 'mobile', or 'tablet'.")
179
+ }),
180
+ (i) => client.google.shoppingProduct(i)
181
+ ),
182
+ tool(
183
+ "GOOGLE_SHOPPING_STORES",
184
+ "Scavio Google Shopping Stores",
185
+ "Fetch the next page of sellers for a Google Shopping product. Continuation of GOOGLE_SHOPPING_PRODUCT: pass the same catalog_id plus that response's next_page_token. Costs 1 credit.",
186
+ import_zod.z.object({
187
+ catalog_id: str("Durable product catalog id."),
188
+ next_page_token: str("Pagination cursor from GOOGLE_SHOPPING_PRODUCT.")
78
189
  }),
79
- (i) => client.google.search(googleSearchParams(i))
190
+ (i) => client.google.shoppingStores(i)
191
+ ),
192
+ tool(
193
+ "GOOGLE_FLIGHTS",
194
+ "Scavio Google Flights",
195
+ "Search Google Flights. Returns itineraries with prices, airlines, stops, durations and carbon emissions. Airports are IATA codes; dates are YYYY-MM-DD. Costs 1 credit.",
196
+ import_zod.z.object({
197
+ departure_id: str("Departure IATA code(s), comma-separated allowed, e.g. 'JFK'."),
198
+ arrival_id: str("Arrival IATA code(s), comma-separated allowed, e.g. 'LHR'."),
199
+ outbound_date: str("Outbound date (YYYY-MM-DD)."),
200
+ return_date: ostr("Return date (YYYY-MM-DD). Required when type is 1."),
201
+ type: onum("1 = round trip (default), 2 = one way, 3 = multi-city."),
202
+ adults: onum("Number of adults (1-9)."),
203
+ children: onum("Number of children (0-9)."),
204
+ infants_in_seat: onum("Infants in seat (0-4)."),
205
+ infants_on_lap: onum("Infants on lap (0-4)."),
206
+ travel_class: onum("1 = economy, 2 = premium economy, 3 = business, 4 = first."),
207
+ stops: onum("0 = any, 1 = nonstop, 2 = one stop or fewer, 3 = two or fewer."),
208
+ sort_by: onum("1 = top, 2 = price, 3 = departure, 4 = arrival, 5 = duration, 6 = emissions."),
209
+ include_airlines: ostr("Comma-separated airline or alliance codes to include."),
210
+ exclude_airlines: ostr("Comma-separated airline or alliance codes to exclude."),
211
+ currency,
212
+ gl,
213
+ hl
214
+ }),
215
+ (i) => client.google.flights(i)
216
+ ),
217
+ tool(
218
+ "GOOGLE_HOTELS",
219
+ "Scavio Google Hotels",
220
+ "Search Google Hotels. Returns properties with nightly prices, ratings, amenities and a detail_token for GOOGLE_HOTELS_DETAIL. Phrase the query as '<City> hotels'. Costs 1 credit.",
221
+ import_zod.z.object({
222
+ query: str("Search query; use a '<City> hotels' form."),
223
+ check_in_date: checkInDate,
224
+ check_out_date: checkOutDate,
225
+ sort_by: onum("3 = lowest price, 8 = highest rating, 13 = most reviewed."),
226
+ min_price: onum("Minimum nightly price."),
227
+ max_price: onum("Maximum nightly price."),
228
+ rating: onum("7 = 3.5+, 8 = 4.0+, 9 = 4.5+."),
229
+ hotel_class: ostr("Comma-separated star ratings (2-5)."),
230
+ amenities: ostr("Comma-separated amenity ids."),
231
+ property_types: ostr("Comma-separated property-type ids, e.g. '12' for vacation rentals."),
232
+ free_cancellation: obool("Only properties with free cancellation."),
233
+ eco_certified: obool("Only eco-certified properties."),
234
+ special_offers: obool("Only properties with special offers."),
235
+ limit: onum("Number of properties to return (1-20)."),
236
+ next_page_token: ostr("Pagination cursor from a prior response."),
237
+ currency,
238
+ gl,
239
+ hl
240
+ }),
241
+ (i) => client.google.hotels(i)
242
+ ),
243
+ tool(
244
+ "GOOGLE_HOTELS_DETAIL",
245
+ "Scavio Google Hotels Detail",
246
+ "Fetch one Google Hotels property in full: room types, per-night prices by provider, amenities, photos and reviews. Needs a detail_token from GOOGLE_HOTELS and the same stay dates. Costs 1 credit.",
247
+ import_zod.z.object({
248
+ detail_token: str("Property detail token from a hotels listing."),
249
+ check_in_date: checkInDate,
250
+ check_out_date: checkOutDate,
251
+ currency,
252
+ gl,
253
+ hl
254
+ }),
255
+ (i) => client.google.hotelsDetail(i)
256
+ ),
257
+ tool(
258
+ "GOOGLE_NEWS",
259
+ "Scavio Google News",
260
+ "Fetch Google News. Pass query to search, or a topic_token / story_token / publication_token from an earlier response to browse a topic, a full story or one publisher. Costs 1 credit.",
261
+ import_zod.z.object({
262
+ query: ostr("Keyword search."),
263
+ topic_token: ostr("Browse a news topic."),
264
+ section_token: ostr("Browse a topic section."),
265
+ story_token: ostr("Fetch full coverage of one story."),
266
+ publication_token: ostr("Browse one publication."),
267
+ kgmid: ostr("Knowledge Graph entity id."),
268
+ so: onum("Sort: 0 = relevance, 1 = date. Only applies with query or kgmid."),
269
+ gl,
270
+ hl,
271
+ google_domain: googleDomain
272
+ }),
273
+ (i) => client.google.news(i)
274
+ ),
275
+ tool(
276
+ "GOOGLE_TRENDS",
277
+ "Scavio Google Trends",
278
+ "Fetch Google Trends interest data. Comma-separate the query to compare terms, and pick the dataset with data_type: TIMESERIES for interest over time, GEO_MAP for interest by region, RELATED_QUERIES or RELATED_TOPICS for rising searches. Costs 1 credit.",
279
+ import_zod.z.object({
280
+ query: str("Search term(s); comma-separated to compare up to five."),
281
+ data_type: ostr("Which trends dataset to return: 'TIMESERIES', 'GEO_MAP', 'GEO_MAP_0', 'RELATED_QUERIES', or 'RELATED_TOPICS'."),
282
+ geo: ostr("Location code, e.g. 'US', 'GB', 'US-CA'. Omit for worldwide."),
283
+ date: ostr("Time range, e.g. 'today 12-m', 'now 7-d'."),
284
+ cat: ostr("Category id."),
285
+ gprop: ostr("Restrict to a Google property: 'images', 'news', 'youtube', or 'froogle'."),
286
+ region: ostr("Resolution for GEO_MAP data: 'COUNTRY', 'REGION', 'DMA', or 'CITY'."),
287
+ tz: ostr("Timezone offset in minutes."),
288
+ hl
289
+ }),
290
+ (i) => client.google.trends(i)
291
+ ),
292
+ tool(
293
+ "GOOGLE_TRENDING",
294
+ "Scavio Google Trending",
295
+ "List what is trending on Google right now for one country. geo is required. Use GOOGLE_TRENDS instead when you already know the term you care about. Costs 1 credit.",
296
+ import_zod.z.object({
297
+ geo: str("Country code, e.g. 'US'."),
298
+ hours: onum("Trending window in hours: 4, 24, 48 or 168."),
299
+ cat: onum("Category id (0-20)."),
300
+ sort: ostr("Sort order: 'relevance', 'search_volume', 'recency', or 'title'."),
301
+ status: ostr("Filter by trend status: 'all' or 'active'."),
302
+ hl
303
+ }),
304
+ (i) => client.google.trending(i)
80
305
  )
81
306
  );
82
307
  }
@@ -85,39 +310,33 @@ function buildScavioToolkit(options = {}) {
85
310
  tool(
86
311
  "AMAZON_SEARCH",
87
312
  "Scavio Amazon Search",
88
- "Search Amazon for products matching a query.",
313
+ "Search Amazon for products matching a query. Results are unsorted and cannot be filtered by category, merchant or price. Costs 1 credit.",
89
314
  import_zod.z.object({
90
315
  query: str("The product search query."),
91
- domain: ostr("Amazon domain, e.g. 'amazon.com'."),
92
- country: ostr("Two-letter country code."),
93
- language: ostr("Two-letter language code."),
94
- currency: ostr("Currency code, e.g. 'USD'."),
95
- device: ostr("Device profile: 'desktop' or 'mobile'."),
96
- sort_by: ostr("Sort order for results."),
97
- start_page: onum("First page to return."),
98
- pages: onum("Number of pages to return."),
99
- category_id: ostr("Restrict to an Amazon category id."),
100
- merchant_id: ostr("Restrict to a merchant id."),
101
- zip_code: ostr("Delivery ZIP/postal code."),
102
- autoselect_variant: obool("Auto-select the best product variant when true.")
316
+ country: ostr("Marketplace country code (ISO 3166-1 alpha-2), not a domain: 'us' (default), 'gb' (the UK is gb, not uk), 'ca', 'de', 'fr', 'es', 'it', 'jp', 'in', 'au', 'br', 'mx', 'nl', 'pl', 'se', 'sg', 'ae', 'sa', 'eg', 'cn', 'be', 'tr'. An unknown code falls back to us."),
317
+ page: onum("Result page, 1-based. One page per call, 1 credit each.")
103
318
  }),
104
319
  (i) => client.amazon.search(i)
105
320
  ),
106
321
  tool(
107
322
  "AMAZON_PRODUCT",
108
323
  "Scavio Amazon Product",
109
- "Fetch full Amazon product details by ASIN.",
324
+ "Fetch full Amazon product details by ASIN. price is the buy-box price only. Costs 1 credit.",
110
325
  import_zod.z.object({
111
326
  asin: str("Amazon Standard Identification Number (ASIN) of the product."),
112
- domain: ostr("Amazon domain, e.g. 'amazon.com'."),
113
- country: ostr("Two-letter country code."),
114
- language: ostr("Two-letter language code."),
115
- currency: ostr("Currency code, e.g. 'USD'."),
116
- device: ostr("Device profile: 'desktop' or 'mobile'."),
117
- zip_code: ostr("Delivery ZIP/postal code."),
118
- autoselect_variant: obool("Auto-select the best product variant when true.")
327
+ country: ostr("Marketplace country code (ISO 3166-1 alpha-2), not a domain: 'us' (default), 'gb' (the UK is gb, not uk), 'ca', 'de', 'fr', 'es', 'it', 'jp', 'in', 'au', 'br', 'mx', 'nl', 'pl', 'se', 'sg', 'ae', 'sa', 'eg', 'cn', 'be', 'tr'. An unknown code falls back to us.")
119
328
  }),
120
329
  (i) => client.amazon.product(i)
330
+ ),
331
+ tool(
332
+ "AMAZON_OFFERS",
333
+ "Scavio Amazon Offers",
334
+ "List every seller offer for one Amazon ASIN: price, seller, condition, shipping, and which offer holds the buy box. Page 1 only. Use this instead of AMAZON_PRODUCT when comparing sellers or checking who owns the buy box. Costs 1 credit.",
335
+ import_zod.z.object({
336
+ asin: str("Amazon Standard Identification Number (ASIN) of the product."),
337
+ country: ostr("Marketplace country code (ISO 3166-1 alpha-2), not a domain: 'us' (default), 'gb' (the UK is gb, not uk), 'ca', 'de', 'fr', 'es', 'it', 'jp', 'in', 'au', 'br', 'mx', 'nl', 'pl', 'se', 'sg', 'ae', 'sa', 'eg', 'cn', 'be', 'tr'. An unknown code falls back to us.")
338
+ }),
339
+ (i) => client.amazon.offers(i)
121
340
  )
122
341
  );
123
342
  }
@@ -126,7 +345,7 @@ function buildScavioToolkit(options = {}) {
126
345
  tool(
127
346
  "WALMART_SEARCH",
128
347
  "Scavio Walmart Search",
129
- "Search Walmart for products matching a query.",
348
+ "Search Walmart for products matching a query. Costs 1 credit.",
130
349
  import_zod.z.object({
131
350
  query: str("The product search query."),
132
351
  domain: ostr("Walmart domain."),
@@ -145,7 +364,7 @@ function buildScavioToolkit(options = {}) {
145
364
  tool(
146
365
  "WALMART_PRODUCT",
147
366
  "Scavio Walmart Product",
148
- "Fetch full Walmart product details by product id.",
367
+ "Fetch full Walmart product details by product id. Costs 1 credit.",
149
368
  import_zod.z.object({
150
369
  product_id: str("Walmart product id."),
151
370
  domain: ostr("Walmart domain."),
@@ -162,13 +381,15 @@ function buildScavioToolkit(options = {}) {
162
381
  tool(
163
382
  "YOUTUBE_SEARCH",
164
383
  "Scavio YouTube Search",
165
- "Search YouTube for videos, channels, or playlists.",
384
+ "Search YouTube for videos, channels, or playlists. Costs 2 credits.",
166
385
  import_zod.z.object({
167
386
  query: str("The video search query."),
168
- upload_date: ostr("Upload date filter, e.g. 'today', 'week', 'month'."),
169
- type: ostr("Result type, e.g. 'video', 'channel', 'playlist'."),
170
- duration: ostr("Duration filter, e.g. 'short', 'long'."),
171
- sort_by: ostr("Sort order for results."),
387
+ upload_date: ostr("Upload date filter: 'last_hour', 'today', 'this_week', 'this_month', 'this_year'."),
388
+ type: ostr("Result type: 'video', 'channel', 'playlist', or 'movie'."),
389
+ duration: ostr("Duration filter: 'short', 'medium', or 'long'."),
390
+ sort_by: ostr("Sort order: 'relevance', 'date', 'view_count', or 'rating'."),
391
+ features: import_zod.z.array(import_zod.z.string()).optional().describe("Feature filters, e.g. ['hd', '4k', 'subtitles', 'creative_commons', 'live', '360', '3d', 'hdr', 'vr180']."),
392
+ cursor: ostr("Pagination cursor from a prior response."),
172
393
  hd: obool("Restrict to HD videos when true."),
173
394
  subtitles: obool("Restrict to videos with subtitles when true."),
174
395
  creative_commons: obool("Restrict to Creative Commons videos when true."),
@@ -177,11 +398,136 @@ function buildScavioToolkit(options = {}) {
177
398
  (i) => client.youtube.search(i)
178
399
  ),
179
400
  tool(
180
- "YOUTUBE_METADATA",
181
- "Scavio YouTube Metadata",
182
- "Fetch metadata for a YouTube video by id.",
183
- import_zod.z.object({ video_id: str("YouTube video id.") }),
184
- (i) => client.youtube.metadata(i)
401
+ "YOUTUBE_SHORTS",
402
+ "Scavio YouTube Shorts",
403
+ "Search YouTube Shorts. Costs 2 credits.",
404
+ import_zod.z.object({
405
+ query: str("The Shorts search query."),
406
+ sort_by: ostr("Sort order: 'relevance', 'date', 'view_count', or 'rating'."),
407
+ cursor: ostr("Pagination cursor from a prior response.")
408
+ }),
409
+ (i) => client.youtube.shorts(i)
410
+ ),
411
+ tool(
412
+ "YOUTUBE_SUGGESTIONS",
413
+ "Scavio YouTube Suggestions",
414
+ "Get YouTube search autocomplete suggestions for a partial query. Costs 1 credit.",
415
+ import_zod.z.object({
416
+ query: str("The partial query to autocomplete."),
417
+ language: ostr("Suggestion language (ISO 639-1, default 'en')."),
418
+ region: ostr("Region code (ISO 3166-1 alpha-2, default 'US').")
419
+ }),
420
+ (i) => client.youtube.suggestions(i)
421
+ ),
422
+ tool(
423
+ "YOUTUBE_VIDEO",
424
+ "Scavio YouTube Video",
425
+ "Fetch full metadata for a YouTube video by id or watch URL. Costs 1 credit.",
426
+ import_zod.z.object({ video_id: str("YouTube video id or a full watch URL.") }),
427
+ (i) => client.youtube.video(i)
428
+ ),
429
+ tool(
430
+ "YOUTUBE_COMMENTS",
431
+ "Scavio YouTube Comments",
432
+ "List top-level comments on a YouTube video. Costs 1 credit.",
433
+ import_zod.z.object({
434
+ video_id: str("YouTube video id or a full watch URL."),
435
+ cursor: ostr("Pagination cursor from a prior response.")
436
+ }),
437
+ (i) => client.youtube.comments(i)
438
+ ),
439
+ tool(
440
+ "YOUTUBE_COMMENT_REPLIES",
441
+ "Scavio YouTube Comment Replies",
442
+ "List replies to a YouTube comment using its reply cursor. Costs 1 credit.",
443
+ import_zod.z.object({
444
+ video_id: str("YouTube video id or a full watch URL."),
445
+ reply_cursor: str("Reply cursor from a parent comment's 'reply_cursor' field."),
446
+ cursor: ostr("Pagination cursor from a prior response.")
447
+ }),
448
+ (i) => client.youtube.commentReplies(i)
449
+ ),
450
+ tool(
451
+ "YOUTUBE_TRANSCRIPT",
452
+ "Scavio YouTube Transcript",
453
+ "Fetch the transcript or timed captions for a YouTube video. Costs 8 credits.",
454
+ import_zod.z.object({
455
+ video_id: str("YouTube video id or a full watch URL."),
456
+ language: ostr("Caption language code (default 'en')."),
457
+ format: ostr("'text' for a plain transcript or 'srt' for timed subtitles (default 'text').")
458
+ }),
459
+ (i) => client.youtube.transcript(i)
460
+ ),
461
+ tool(
462
+ "YOUTUBE_RELATED",
463
+ "Scavio YouTube Related",
464
+ "List videos related to a YouTube video. Costs 1 credit.",
465
+ import_zod.z.object({
466
+ video_id: str("YouTube video id or a full watch URL."),
467
+ cursor: ostr("Pagination cursor from a prior response.")
468
+ }),
469
+ (i) => client.youtube.related(i)
470
+ ),
471
+ tool(
472
+ "YOUTUBE_CHANNEL_SEARCH",
473
+ "Scavio YouTube Channel Search",
474
+ "Search YouTube channels by keyword. Costs 1 credit.",
475
+ import_zod.z.object({
476
+ query: str("The channel search query."),
477
+ cursor: ostr("Pagination cursor from a prior response.")
478
+ }),
479
+ (i) => client.youtube.channelSearch(i)
480
+ ),
481
+ tool(
482
+ "YOUTUBE_CHANNEL",
483
+ "Scavio YouTube Channel",
484
+ "Fetch YouTube channel details by id, @handle, or URL. Costs 1 credit.",
485
+ import_zod.z.object({ channel_id: str("YouTube channel id, @handle, or channel URL.") }),
486
+ (i) => client.youtube.channel(i)
487
+ ),
488
+ tool(
489
+ "YOUTUBE_CHANNEL_VIDEOS",
490
+ "Scavio YouTube Channel Videos",
491
+ "List videos uploaded by a YouTube channel. Costs 1 credit.",
492
+ import_zod.z.object({
493
+ channel_id: str("YouTube channel id."),
494
+ cursor: ostr("Pagination cursor from a prior response.")
495
+ }),
496
+ (i) => client.youtube.channelVideos(i)
497
+ ),
498
+ tool(
499
+ "YOUTUBE_CHANNEL_SHORTS",
500
+ "Scavio YouTube Channel Shorts",
501
+ "List Shorts posted by a YouTube channel. Costs 1 credit.",
502
+ import_zod.z.object({
503
+ channel_id: str("YouTube channel id."),
504
+ cursor: ostr("Pagination cursor from a prior response.")
505
+ }),
506
+ (i) => client.youtube.channelShorts(i)
507
+ ),
508
+ tool(
509
+ "YOUTUBE_CHANNEL_COMMUNITY",
510
+ "Scavio YouTube Channel Community",
511
+ "List community posts from a YouTube channel. Costs 1 credit.",
512
+ import_zod.z.object({
513
+ channel_id: str("YouTube channel id."),
514
+ cursor: ostr("Pagination cursor from a prior response.")
515
+ }),
516
+ (i) => client.youtube.channelCommunity(i)
517
+ ),
518
+ tool(
519
+ "YOUTUBE_CHANNEL_RESOLVE",
520
+ "Scavio YouTube Channel Resolve",
521
+ "Resolve a YouTube @handle or channel URL to a channel id. Costs 1 credit.",
522
+ import_zod.z.object({ channel: str("A channel @handle or channel URL to resolve to a channel id.") }),
523
+ (i) => client.youtube.channelResolve(i)
524
+ ),
525
+ tool(
526
+ "YOUTUBE_STREAMS",
527
+ "Scavio YouTube Streams",
528
+ "Fetch playable or downloadable stream formats for a YouTube video. Costs 3 credits.",
529
+ import_zod.z.object({ video_id: str("YouTube video id or a full watch URL.") }),
530
+ (i) => client.youtube.streams(i)
185
531
  )
186
532
  );
187
533
  }
@@ -190,21 +536,112 @@ function buildScavioToolkit(options = {}) {
190
536
  tool(
191
537
  "REDDIT_SEARCH",
192
538
  "Scavio Reddit Search",
193
- "Search Reddit posts, subreddits, or users.",
539
+ "Search Reddit posts. Returns data.results with next_cursor and has_more; page with cursor. Results cannot be filtered or sorted. Costs 1 credit.",
194
540
  import_zod.z.object({
195
541
  query: str("The Reddit search query."),
196
- type: ostr("Search type, e.g. 'posts', 'subreddits', 'users'."),
197
- sort: ostr("Sort order, e.g. 'relevance', 'new', 'top'."),
198
- cursor: ostr("Pagination cursor.")
542
+ cursor: ostr("Pagination cursor: pass 'next_cursor' from a prior response.")
199
543
  }),
200
544
  (i) => client.reddit.search(i)
201
545
  ),
546
+ tool(
547
+ "REDDIT_SEARCH_SUGGESTIONS",
548
+ "Scavio Reddit Search Suggestions",
549
+ "Get Reddit search autocomplete suggestions for a query. Returns data.suggestions (plain strings) and total_count. Costs 1 credit.",
550
+ import_zod.z.object({ query: str("The partial or full query to expand.") }),
551
+ (i) => client.reddit.searchSuggestions(i)
552
+ ),
202
553
  tool(
203
554
  "REDDIT_POST",
204
555
  "Scavio Reddit Post",
205
- "Fetch a Reddit post and its comment thread by URL.",
206
- import_zod.z.object({ url: str("Full URL of the Reddit post to fetch with its comments.") }),
556
+ "Fetch one Reddit post by URL or post id. Returns a FLAT post object under data (post_id, title, text, url, subreddit, author, score, upvote_ratio, num_comments, created_at, is_nsfw, is_video, thumbnail, media); comments are NOT included - call REDDIT_POST_COMMENTS for those. Costs 1 credit.",
557
+ import_zod.z.object({
558
+ url: ostr("Full URL of the Reddit post. Provide this or post_id."),
559
+ post_id: ostr("Post fullname (t3_...) or bare id. Provide this or url.")
560
+ }),
207
561
  (i) => client.reddit.post(i)
562
+ ),
563
+ tool(
564
+ "REDDIT_POST_COMMENTS",
565
+ "Scavio Reddit Post Comments",
566
+ "List top-level comments on a Reddit post. Returns data.comments with next_cursor and has_more; each comment carries a reply_cursor for REDDIT_COMMENT_REPLIES. Costs 1 credit.",
567
+ import_zod.z.object({
568
+ post_id: str("Post fullname (t3_...), bare id, or post URL."),
569
+ sort: ostr("Comment sort order (UPPERCASE): 'HOT', 'NEW', 'TOP', 'BEST', or 'CONTROVERSIAL'. Defaults to TOP."),
570
+ cursor: ostr("Pagination cursor from a prior response.")
571
+ }),
572
+ (i) => client.reddit.postComments(i)
573
+ ),
574
+ tool(
575
+ "REDDIT_COMMENT_REPLIES",
576
+ "Scavio Reddit Comment Replies",
577
+ "List replies to one Reddit comment. cursor is REQUIRED here and must be a comment's 'reply_cursor' from REDDIT_POST_COMMENTS, not a 'next_cursor'. Costs 1 credit.",
578
+ import_zod.z.object({
579
+ post_id: str("Post fullname (t3_...) the comment belongs to."),
580
+ cursor: str("A comment's 'reply_cursor' from REDDIT_POST_COMMENTS. Required."),
581
+ sort: ostr("Comment sort order (UPPERCASE): 'HOT', 'NEW', 'TOP', 'BEST', or 'CONTROVERSIAL'. Defaults to TOP.")
582
+ }),
583
+ (i) => client.reddit.commentReplies(i)
584
+ ),
585
+ tool(
586
+ "REDDIT_SUBREDDIT",
587
+ "Scavio Reddit Subreddit",
588
+ "Fetch a subreddit's profile: title, description, subscribers, active_count, type, icon, banner and created_at. Costs 1 credit.",
589
+ import_zod.z.object({ subreddit: str("Subreddit name without the r/ prefix, e.g. 'AskReddit'.") }),
590
+ (i) => client.reddit.subreddit(i)
591
+ ),
592
+ tool(
593
+ "REDDIT_SUBREDDIT_POSTS",
594
+ "Scavio Reddit Subreddit Posts",
595
+ "List posts in a subreddit feed. Returns data.posts with next_cursor and has_more. This feed shape has no text and no thumbnail - use REDDIT_POST for a post's body. Costs 1 credit.",
596
+ import_zod.z.object({
597
+ subreddit: str("Subreddit name without the r/ prefix."),
598
+ sort: ostr("Feed sort order (UPPERCASE): 'BEST', 'HOT', 'NEW', 'TOP', 'CONTROVERSIAL', or 'RISING'. Defaults to HOT. This is the only endpoint accepting RISING."),
599
+ cursor: ostr("Pagination cursor from a prior response.")
600
+ }),
601
+ (i) => client.reddit.subredditPosts(i)
602
+ ),
603
+ tool(
604
+ "REDDIT_USER",
605
+ "Scavio Reddit User",
606
+ "Fetch a redditor's profile: karma split, account_type, avatar, description, verification flags and created_at. Costs 1 credit.",
607
+ import_zod.z.object({ username: str("Redditor username without the u/ prefix, e.g. 'spez'.") }),
608
+ (i) => client.reddit.user(i)
609
+ ),
610
+ tool(
611
+ "REDDIT_USER_POSTS",
612
+ "Scavio Reddit User Posts",
613
+ "List posts submitted by a redditor. Returns data.posts with next_cursor and has_more. Costs 1 credit.",
614
+ import_zod.z.object({
615
+ username: str("Redditor username without the u/ prefix."),
616
+ sort: ostr("Sort order (UPPERCASE): 'HOT', 'NEW', 'TOP', 'BEST', or 'CONTROVERSIAL'. Defaults to NEW."),
617
+ cursor: ostr("Pagination cursor from a prior response.")
618
+ }),
619
+ (i) => client.reddit.userPosts(i)
620
+ ),
621
+ tool(
622
+ "REDDIT_USER_COMMENTS",
623
+ "Scavio Reddit User Comments",
624
+ "List comments written by a redditor. Returns data.comments with next_cursor and has_more; each item nests the post it belongs to. Costs 1 credit.",
625
+ import_zod.z.object({
626
+ username: str("Redditor username without the u/ prefix."),
627
+ sort: ostr("Sort order (UPPERCASE): 'HOT', 'NEW', 'TOP', 'BEST', or 'CONTROVERSIAL'. Defaults to NEW."),
628
+ cursor: ostr("Pagination cursor from a prior response.")
629
+ }),
630
+ (i) => client.reddit.userComments(i)
631
+ ),
632
+ tool(
633
+ "REDDIT_POPULAR",
634
+ "Scavio Reddit Popular",
635
+ "List the site-wide r/popular feed. Returns data.posts with next_cursor and has_more. Costs 1 credit.",
636
+ import_zod.z.object({ cursor: ostr("Pagination cursor from a prior response. Omit for page 1.") }),
637
+ (i) => client.reddit.popular(i)
638
+ ),
639
+ tool(
640
+ "REDDIT_TRENDING",
641
+ "Scavio Reddit Trending",
642
+ "List Reddit's currently trending searches. Returns data.trending (query plus raw_query) and total_count. Takes no parameters. Costs 1 credit.",
643
+ import_zod.z.object({}),
644
+ () => client.reddit.trending()
208
645
  )
209
646
  );
210
647
  }
@@ -213,7 +650,7 @@ function buildScavioToolkit(options = {}) {
213
650
  tool(
214
651
  "TIKTOK_PROFILE",
215
652
  "Scavio TikTok Profile",
216
- "Fetch a TikTok user profile by username or secUid.",
653
+ "Fetch a TikTok user profile by username or secUid. Costs 1 credit.",
217
654
  import_zod.z.object({
218
655
  username: ostr("TikTok username (without @). Provide this or sec_user_id."),
219
656
  sec_user_id: ostr("TikTok secUid. Provide this or username.")
@@ -223,7 +660,7 @@ function buildScavioToolkit(options = {}) {
223
660
  tool(
224
661
  "TIKTOK_USER_POSTS",
225
662
  "Scavio TikTok User Posts",
226
- "List a TikTok user's posts by secUid.",
663
+ "List a TikTok user's posts by secUid. Costs 1 credit.",
227
664
  import_zod.z.object({
228
665
  sec_user_id: str("TikTok secUid of the user."),
229
666
  cursor: ostr("Pagination cursor."),
@@ -235,14 +672,14 @@ function buildScavioToolkit(options = {}) {
235
672
  tool(
236
673
  "TIKTOK_VIDEO",
237
674
  "Scavio TikTok Video",
238
- "Fetch a TikTok video by id.",
675
+ "Fetch a TikTok video by id. Costs 1 credit.",
239
676
  import_zod.z.object({ video_id: str("TikTok video id.") }),
240
677
  (i) => client.tiktok.video(i)
241
678
  ),
242
679
  tool(
243
680
  "TIKTOK_VIDEO_COMMENTS",
244
681
  "Scavio TikTok Video Comments",
245
- "List comments on a TikTok video.",
682
+ "List comments on a TikTok video. Costs 1 credit.",
246
683
  import_zod.z.object({
247
684
  video_id: str("TikTok video id."),
248
685
  cursor: ostr("Pagination cursor."),
@@ -253,7 +690,7 @@ function buildScavioToolkit(options = {}) {
253
690
  tool(
254
691
  "TIKTOK_COMMENT_REPLIES",
255
692
  "Scavio TikTok Comment Replies",
256
- "List replies to a TikTok video comment.",
693
+ "List replies to a TikTok video comment. Costs 1 credit.",
257
694
  import_zod.z.object({
258
695
  video_id: str("TikTok video id."),
259
696
  comment_id: str("Parent comment id."),
@@ -265,7 +702,7 @@ function buildScavioToolkit(options = {}) {
265
702
  tool(
266
703
  "TIKTOK_SEARCH_VIDEOS",
267
704
  "Scavio TikTok Search Videos",
268
- "Search TikTok videos by keyword.",
705
+ "Search TikTok videos by keyword. Costs 1 credit.",
269
706
  import_zod.z.object({
270
707
  keyword: str("Search keyword."),
271
708
  cursor: ostr("Pagination cursor."),
@@ -278,7 +715,7 @@ function buildScavioToolkit(options = {}) {
278
715
  tool(
279
716
  "TIKTOK_SEARCH_USERS",
280
717
  "Scavio TikTok Search Users",
281
- "Search TikTok users by keyword.",
718
+ "Search TikTok users by keyword. Costs 1 credit.",
282
719
  import_zod.z.object({
283
720
  keyword: str("Search keyword."),
284
721
  cursor: ostr("Pagination cursor."),
@@ -289,7 +726,7 @@ function buildScavioToolkit(options = {}) {
289
726
  tool(
290
727
  "TIKTOK_HASHTAG",
291
728
  "Scavio TikTok Hashtag",
292
- "Fetch a TikTok hashtag by name or id.",
729
+ "Fetch a TikTok hashtag by name or id. Costs 1 credit.",
293
730
  import_zod.z.object({
294
731
  hashtag_name: ostr("Hashtag name (without #). Provide this or hashtag_id."),
295
732
  hashtag_id: ostr("Hashtag id. Provide this or hashtag_name.")
@@ -299,7 +736,7 @@ function buildScavioToolkit(options = {}) {
299
736
  tool(
300
737
  "TIKTOK_HASHTAG_VIDEOS",
301
738
  "Scavio TikTok Hashtag Videos",
302
- "List videos for a TikTok hashtag by id.",
739
+ "List videos for a TikTok hashtag by id. Costs 1 credit.",
303
740
  import_zod.z.object({
304
741
  hashtag_id: str("Hashtag id."),
305
742
  cursor: ostr("Pagination cursor."),
@@ -310,7 +747,7 @@ function buildScavioToolkit(options = {}) {
310
747
  tool(
311
748
  "TIKTOK_USER_FOLLOWERS",
312
749
  "Scavio TikTok User Followers",
313
- "List a TikTok user's followers by secUid.",
750
+ "List a TikTok user's followers by secUid. Costs 1 credit.",
314
751
  import_zod.z.object({
315
752
  sec_user_id: str("TikTok secUid of the user."),
316
753
  count: onum("Number of followers to return."),
@@ -322,7 +759,7 @@ function buildScavioToolkit(options = {}) {
322
759
  tool(
323
760
  "TIKTOK_USER_FOLLOWINGS",
324
761
  "Scavio TikTok User Followings",
325
- "List the accounts a TikTok user follows, by secUid.",
762
+ "List the accounts a TikTok user follows, by secUid. Costs 1 credit.",
326
763
  import_zod.z.object({
327
764
  sec_user_id: str("TikTok secUid of the user."),
328
765
  count: onum("Number of followings to return."),
@@ -333,12 +770,98 @@ function buildScavioToolkit(options = {}) {
333
770
  )
334
771
  );
335
772
  }
773
+ if (all || enableTiktokShop) {
774
+ tools.push(
775
+ tool(
776
+ "TIKTOK_SHOP_SEARCH",
777
+ "Scavio TikTok Shop Search",
778
+ "Search TikTok Shop products by keyword (US catalog only), up to 30 per page with exact prices, ratings and shop details. One of the three endpoints that return exact prices. Paginate with next_cursor and dedupe by product_id across pages. Costs 1 credit.",
779
+ import_zod.z.object({
780
+ search: str("Search query (1-200 characters). The keyword field is named 'search', not 'query'."),
781
+ cursor: ostr("Opaque cursor from a prior response's next_cursor.")
782
+ }),
783
+ (i) => client.tiktokShop.search(i)
784
+ ),
785
+ tool(
786
+ "TIKTOK_SHOP_SEARCH_SUGGESTIONS",
787
+ "Scavio TikTok Shop Search Suggestions",
788
+ "Expand a partial TikTok Shop query into keyword suggestions across 8 marketplace regions. Suggestions are not guaranteed prefix matches: a misspelling returns typo corrections, and results can include brand and shop names. Costs 1 credit.",
789
+ import_zod.z.object({
790
+ search: str("Partial query to expand (1-100 characters). The field is 'search', not 'query'."),
791
+ region: ostr("Marketplace region: 'US' (default), 'GB', 'SG', 'MY', 'PH', 'TH', 'VN', or 'ID'.")
792
+ }),
793
+ (i) => client.tiktokShop.searchSuggestions(i)
794
+ ),
795
+ tool(
796
+ "TIKTOK_SHOP_PRODUCT",
797
+ "Scavio TikTok Shop Product",
798
+ "Full TikTok Shop product detail: description, images, variants with stock, shipping, shop profile, category path and top reviews. Two limits: it does NOT return a price (upstream masks it - get prices from TIKTOK_SHOP_SEARCH, TIKTOK_SHOP_SHOP_PRODUCTS or TIKTOK_SHOP_CATEGORY_PRODUCTS), and it resolves only about 44% of the product ids returned by search, so a 404 is a normal outcome to skip rather than retry. Costs 1 credit.",
799
+ import_zod.z.object({
800
+ product_id: str("TikTok Shop product id (6-25 digits)."),
801
+ region: ostr("Marketplace region: 'US' (default), 'GB', 'SG', 'MY', 'PH', 'TH', 'VN', or 'ID'.")
802
+ }),
803
+ (i) => client.tiktokShop.product(i)
804
+ ),
805
+ tool(
806
+ "TIKTOK_SHOP_PRODUCT_REVIEWS",
807
+ "Scavio TikTok Shop Product Reviews",
808
+ "Paginated TikTok Shop product reviews with text, images, star histogram and verified-purchase flags, up to 200 per call. total_reviews drifts between calls and must NOT be used to compute a page count - page with has_more instead. Often works for ids TIKTOK_SHOP_PRODUCT cannot resolve. Costs 1 credit.",
809
+ import_zod.z.object({
810
+ product_id: str("TikTok Shop product id (6-25 digits)."),
811
+ page: onum("1-based page number (1-500, default 1)."),
812
+ page_size: onum("Reviews per page (1-200, default 20)."),
813
+ sort: ostr("'relevant' (default) is text-complete and image-heavy; 'recent' is fresher but far more text-sparse."),
814
+ rating: onum("Only reviews with this star rating (1-5)."),
815
+ has_media: obool("Only reviews with a photo or video. Shares one upstream slot with verified_only, and wins when both are set."),
816
+ verified_only: obool("Only verified purchases. Ignored when has_media is also set."),
817
+ region: ostr("Marketplace region: 'US' (default), 'GB', 'SG', 'MY', 'PH', 'TH', 'VN', or 'ID'.")
818
+ }),
819
+ (i) => client.tiktokShop.productReviews(i)
820
+ ),
821
+ tool(
822
+ "TIKTOK_SHOP_CATEGORIES",
823
+ "Scavio TikTok Shop Categories",
824
+ "The global TikTok Shop category tree: 28 top-level categories, 240 nodes, two levels deep. Category ids are identical in every region and names are always English. Takes no parameters. Costs 1 credit.",
825
+ import_zod.z.object({}),
826
+ () => client.tiktokShop.categories()
827
+ ),
828
+ tool(
829
+ "TIKTOK_SHOP_CATEGORY_PRODUCTS",
830
+ "Scavio TikTok Shop Category Products",
831
+ "Products listed under a category id from TIKTOK_SHOP_CATEGORIES, with exact prices. Level 1 or 2 ids both work. Page size is inconsistent upstream (15 to 20), so always paginate with next_cursor; when has_more turns false after a few pages that is the end of a shallow listing, not an error. Costs 1 credit.",
832
+ import_zod.z.object({
833
+ category_id: str("Category id from TIKTOK_SHOP_CATEGORIES; level 1 or 2 both work."),
834
+ cursor: ostr("Opaque cursor from a prior response's next_cursor."),
835
+ region: ostr("Marketplace region, 'US' (default) or 'GB' only - not the 8-region list.")
836
+ }),
837
+ (i) => client.tiktokShop.categoryProducts(i)
838
+ ),
839
+ tool(
840
+ "TIKTOK_SHOP_SHOP_PRODUCTS",
841
+ "Scavio TikTok Shop Shop Products",
842
+ "A shop's TikTok Shop catalog, 30 per page, with exact prices. Shop follower count, location and shop-level rating are not available here - call TIKTOK_SHOP_PRODUCT for the full shop profile. Costs 1 credit.",
843
+ import_zod.z.object({
844
+ shop_id: str("TikTok Shop seller id (also called seller_id elsewhere on TikTok)."),
845
+ cursor: ostr("Opaque cursor from a prior response's next_cursor."),
846
+ region: ostr("Marketplace region: 'US' (default), 'GB', 'SG', 'MY', 'PH', 'TH', 'VN', or 'ID'.")
847
+ }),
848
+ (i) => client.tiktokShop.shopProducts(i)
849
+ ),
850
+ tool(
851
+ "TIKTOK_SHOP_RESOLVE",
852
+ "Scavio TikTok Shop Resolve",
853
+ "Resolve any TikTok Shop URL or share link to a product_id or shop_id, ready for the other TikTok Shop tools. Accepts shop.tiktok.com product and store pages, tiktok.com/view links, affiliate share links, and vt.tiktok.com short links. Costs 1 credit.",
854
+ import_zod.z.object({ url: str("A TikTok Shop product or store URL, affiliate share link, or vt.tiktok.com short link.") }),
855
+ (i) => client.tiktokShop.resolve(i)
856
+ )
857
+ );
858
+ }
336
859
  if (all || enableInstagram) {
337
860
  tools.push(
338
861
  tool(
339
862
  "INSTAGRAM_PROFILE",
340
863
  "Scavio Instagram Profile",
341
- "Fetch an Instagram profile by username or user id.",
864
+ "Fetch an Instagram profile by username or user id. Costs 10 credits.",
342
865
  import_zod.z.object({
343
866
  username: ostr("Instagram username. Provide this or user_id."),
344
867
  user_id: ostr("Instagram user id. Provide this or username.")
@@ -348,7 +871,7 @@ function buildScavioToolkit(options = {}) {
348
871
  tool(
349
872
  "INSTAGRAM_USER_POSTS",
350
873
  "Scavio Instagram User Posts",
351
- "List an Instagram user's posts.",
874
+ "List an Instagram user's posts. Costs 2 credits, the cheapest Instagram endpoint.",
352
875
  import_zod.z.object({
353
876
  username: ostr("Instagram username. Provide this or user_id."),
354
877
  user_id: ostr("Instagram user id. Provide this or username."),
@@ -360,7 +883,7 @@ function buildScavioToolkit(options = {}) {
360
883
  tool(
361
884
  "INSTAGRAM_USER_REELS",
362
885
  "Scavio Instagram User Reels",
363
- "List an Instagram user's reels.",
886
+ "List an Instagram user's reels. Costs 10 credits.",
364
887
  import_zod.z.object({
365
888
  username: ostr("Instagram username. Provide this or user_id."),
366
889
  user_id: ostr("Instagram user id. Provide this or username."),
@@ -372,7 +895,7 @@ function buildScavioToolkit(options = {}) {
372
895
  tool(
373
896
  "INSTAGRAM_USER_TAGGED",
374
897
  "Scavio Instagram User Tagged",
375
- "List posts an Instagram user is tagged in.",
898
+ "List posts an Instagram user is tagged in. Costs 10 credits.",
376
899
  import_zod.z.object({
377
900
  username: ostr("Instagram username. Provide this or user_id."),
378
901
  user_id: ostr("Instagram user id. Provide this or username."),
@@ -384,7 +907,7 @@ function buildScavioToolkit(options = {}) {
384
907
  tool(
385
908
  "INSTAGRAM_USER_STORIES",
386
909
  "Scavio Instagram User Stories",
387
- "Fetch an Instagram user's current stories.",
910
+ "Fetch an Instagram user's current stories. Costs 10 credits.",
388
911
  import_zod.z.object({
389
912
  username: ostr("Instagram username. Provide this or user_id."),
390
913
  user_id: ostr("Instagram user id. Provide this or username.")
@@ -394,7 +917,7 @@ function buildScavioToolkit(options = {}) {
394
917
  tool(
395
918
  "INSTAGRAM_POST",
396
919
  "Scavio Instagram Post",
397
- "Fetch an Instagram post by URL, media id, or shortcode.",
920
+ "Fetch an Instagram post by URL, media id, or shortcode. Costs 8 credits.",
398
921
  import_zod.z.object({
399
922
  url: ostr("Post URL. Provide one of url, media_id, or shortcode."),
400
923
  media_id: ostr("Post media id. Provide one of url, media_id, or shortcode."),
@@ -405,7 +928,7 @@ function buildScavioToolkit(options = {}) {
405
928
  tool(
406
929
  "INSTAGRAM_POST_COMMENTS",
407
930
  "Scavio Instagram Post Comments",
408
- "List comments on an Instagram post by shortcode or URL.",
931
+ "List comments on an Instagram post by shortcode or URL. Costs 10 credits.",
409
932
  import_zod.z.object({
410
933
  shortcode: ostr("Post shortcode. Provide this or url."),
411
934
  url: ostr("Post URL. Provide this or shortcode."),
@@ -417,7 +940,7 @@ function buildScavioToolkit(options = {}) {
417
940
  tool(
418
941
  "INSTAGRAM_COMMENT_REPLIES",
419
942
  "Scavio Instagram Comment Replies",
420
- "List replies to an Instagram post comment.",
943
+ "List replies to an Instagram post comment. Costs 8 credits.",
421
944
  import_zod.z.object({
422
945
  media_id: str("Post media id."),
423
946
  comment_id: str("Parent comment id."),
@@ -428,7 +951,7 @@ function buildScavioToolkit(options = {}) {
428
951
  tool(
429
952
  "INSTAGRAM_SEARCH_USERS",
430
953
  "Scavio Instagram Search Users",
431
- "Search Instagram users by keyword.",
954
+ "Search Instagram users by keyword. Costs 10 credits.",
432
955
  import_zod.z.object({
433
956
  keyword: str("Search keyword."),
434
957
  cursor: ostr("Pagination cursor.")
@@ -438,7 +961,7 @@ function buildScavioToolkit(options = {}) {
438
961
  tool(
439
962
  "INSTAGRAM_SEARCH_HASHTAGS",
440
963
  "Scavio Instagram Search Hashtags",
441
- "Search Instagram hashtags by keyword.",
964
+ "Search Instagram hashtags by keyword. Costs 10 credits.",
442
965
  import_zod.z.object({
443
966
  keyword: str("Search keyword."),
444
967
  cursor: ostr("Pagination cursor.")
@@ -448,7 +971,7 @@ function buildScavioToolkit(options = {}) {
448
971
  tool(
449
972
  "INSTAGRAM_USER_FOLLOWERS",
450
973
  "Scavio Instagram User Followers",
451
- "List an Instagram user's followers.",
974
+ "List an Instagram user's followers. Costs 10 credits.",
452
975
  import_zod.z.object({
453
976
  username: ostr("Instagram username. Provide this or user_id."),
454
977
  user_id: ostr("Instagram user id. Provide this or username."),
@@ -460,7 +983,7 @@ function buildScavioToolkit(options = {}) {
460
983
  tool(
461
984
  "INSTAGRAM_USER_FOLLOWINGS",
462
985
  "Scavio Instagram User Followings",
463
- "List the accounts an Instagram user follows.",
986
+ "List the accounts an Instagram user follows. Costs 10 credits.",
464
987
  import_zod.z.object({
465
988
  username: ostr("Instagram username. Provide this or user_id."),
466
989
  user_id: ostr("Instagram user id. Provide this or username."),
@@ -471,9 +994,215 @@ function buildScavioToolkit(options = {}) {
471
994
  )
472
995
  );
473
996
  }
997
+ if (all || enableX) {
998
+ tools.push(
999
+ tool(
1000
+ "X_SEARCH",
1001
+ "Scavio X Search",
1002
+ "Search X (Twitter) posts. Returns data.timeline with next_cursor, prev_cursor and has_more. Costs 1 credit.",
1003
+ import_zod.z.object({
1004
+ search: str("Search query (1-500 characters). The field is 'search', not 'query'."),
1005
+ search_type: ostr("Result category (Capitalized): 'Top' (default), 'Latest', 'People', 'Photos', or 'Videos'."),
1006
+ cursor: ostr("Pagination cursor from a prior response.")
1007
+ }),
1008
+ (i) => client.x.search(i)
1009
+ ),
1010
+ tool(
1011
+ "X_TWEET",
1012
+ "Scavio X Tweet",
1013
+ "Fetch one X post by id. Returns the tweet object plus reply_to, in_reply_to_screen_name, in_reply_to_status_id, in_reply_to_user_id and sensitive. Costs 1 credit.",
1014
+ import_zod.z.object({ tweet_id: str("Numeric post id as a string, e.g. '1808168603721650364'.") }),
1015
+ (i) => client.x.tweet(i)
1016
+ ),
1017
+ tool(
1018
+ "X_TWEET_COMMENTS",
1019
+ "Scavio X Tweet Comments",
1020
+ "List replies to an X post. Returns data.timeline with next_cursor, prev_cursor and has_more. rank switches the upstream feed: 'latest' is chronological, 'top' is ranked. Costs 1 credit.",
1021
+ import_zod.z.object({
1022
+ tweet_id: str("Numeric post id as a string."),
1023
+ rank: ostr("Reply ordering (lowercase): 'top' (default, ranked) or 'latest' (chronological)."),
1024
+ cursor: ostr("Pagination cursor from a prior response.")
1025
+ }),
1026
+ (i) => client.x.tweetComments(i)
1027
+ ),
1028
+ tool(
1029
+ "X_TWEET_RETWEETERS",
1030
+ "Scavio X Tweet Retweeters",
1031
+ "List the accounts that reposted an X post. Returns data.retweeters with next_cursor and has_more. Costs 1 credit.",
1032
+ import_zod.z.object({
1033
+ tweet_id: str("Numeric post id as a string."),
1034
+ cursor: ostr("Pagination cursor from a prior response.")
1035
+ }),
1036
+ (i) => client.x.tweetRetweeters(i)
1037
+ ),
1038
+ tool(
1039
+ "X_USER",
1040
+ "Scavio X User",
1041
+ "Fetch an X profile by handle: followers_count, friends_count, statuses_count, media_count, blue_verified, location, website, avatar, header_image and pinned_tweet_ids. Costs 1 credit.",
1042
+ import_zod.z.object({ screen_name: str("An X handle WITHOUT the @, e.g. 'elonmusk'.") }),
1043
+ (i) => client.x.user(i)
1044
+ ),
1045
+ tool(
1046
+ "X_USER_TWEETS",
1047
+ "Scavio X User Tweets",
1048
+ "List an X user's posts. Returns data.timeline plus pinned and user; there is no has_more on this endpoint, so page on next_cursor. Costs 1 credit.",
1049
+ import_zod.z.object({
1050
+ screen_name: str("An X handle WITHOUT the @."),
1051
+ cursor: ostr("Pagination cursor from a prior response.")
1052
+ }),
1053
+ (i) => client.x.userTweets(i)
1054
+ ),
1055
+ tool(
1056
+ "X_USER_REPLIES",
1057
+ "Scavio X User Replies",
1058
+ "List an X user's replies. Returns data.timeline with next_cursor and prev_cursor; no has_more. Costs 1 credit.",
1059
+ import_zod.z.object({
1060
+ screen_name: str("An X handle WITHOUT the @."),
1061
+ cursor: ostr("Pagination cursor from a prior response.")
1062
+ }),
1063
+ (i) => client.x.userReplies(i)
1064
+ ),
1065
+ tool(
1066
+ "X_USER_MEDIA",
1067
+ "Scavio X User Media",
1068
+ "List an X user's posts that carry photos or videos. Returns data.timeline with next_cursor and prev_cursor; no has_more. Costs 1 credit.",
1069
+ import_zod.z.object({
1070
+ screen_name: str("An X handle WITHOUT the @."),
1071
+ cursor: ostr("Pagination cursor from a prior response.")
1072
+ }),
1073
+ (i) => client.x.userMedia(i)
1074
+ ),
1075
+ tool(
1076
+ "X_USER_FOLLOWERS",
1077
+ "Scavio X User Followers",
1078
+ "List an X user's followers. Returns data.followers with followers_count, next_cursor and has_more. Costs 1 credit.",
1079
+ import_zod.z.object({
1080
+ screen_name: str("An X handle WITHOUT the @."),
1081
+ cursor: ostr("Pagination cursor from a prior response.")
1082
+ }),
1083
+ (i) => client.x.userFollowers(i)
1084
+ ),
1085
+ tool(
1086
+ "X_USER_FOLLOWINGS",
1087
+ "Scavio X User Followings",
1088
+ "List the accounts an X user follows. The response array is data.following (singular), not followings, and there is no following_count. Costs 1 credit.",
1089
+ import_zod.z.object({
1090
+ screen_name: str("An X handle WITHOUT the @."),
1091
+ cursor: ostr("Pagination cursor from a prior response.")
1092
+ }),
1093
+ (i) => client.x.userFollowings(i)
1094
+ ),
1095
+ tool(
1096
+ "X_TRENDING",
1097
+ "Scavio X Trending",
1098
+ "List what is trending on X for one country. Returns data.trends with no cursor and no has_more. Costs 1 credit.",
1099
+ import_zod.z.object({ country: ostr("Country NAME, not an ISO code, e.g. 'UnitedStates' (the default).") }),
1100
+ (i) => client.x.trending(i)
1101
+ )
1102
+ );
1103
+ }
1104
+ if (all || enableLinkedin) {
1105
+ tools.push(
1106
+ tool(
1107
+ "LINKEDIN_PERSON",
1108
+ "Scavio LinkedIn Person",
1109
+ "Fetch a full LinkedIn profile: headline, about, location, follower and connection counts, current_company, experiences, educations, honors_and_awards, bio_links and similar profiles. Costs 1 credit.",
1110
+ import_zod.z.object({
1111
+ username: ostr("Public identifier / vanity handle, e.g. 'williamhgates'. Provide this or url."),
1112
+ url: ostr("Full LinkedIn profile URL. Provide this or username.")
1113
+ }),
1114
+ (i) => client.linkedin.person(i)
1115
+ ),
1116
+ tool(
1117
+ "LINKEDIN_PERSON_ABOUT",
1118
+ "Scavio LinkedIn Person About",
1119
+ "The about-only slice of a LinkedIn profile: about, headline, education_summary, experiences, educations, honors_and_awards and bio_links. Same upstream call as LINKEDIN_PERSON, shaped down. Costs 1 credit.",
1120
+ import_zod.z.object({
1121
+ username: ostr("Public identifier / vanity handle. Provide this or url."),
1122
+ url: ostr("Full LinkedIn profile URL. Provide this or username.")
1123
+ }),
1124
+ (i) => client.linkedin.personAbout(i)
1125
+ ),
1126
+ tool(
1127
+ "LINKEDIN_PERSON_POSTS",
1128
+ "Scavio LinkedIn Person Posts",
1129
+ "A member's LinkedIn feed - their own posts, or posts they commented on or reacted to via type. 50 per page; advance with next_cursor. Costs 10 credits.",
1130
+ import_zod.z.object({
1131
+ username: ostr("Public identifier / vanity handle. Provide this or url."),
1132
+ url: ostr("Full LinkedIn profile URL. Provide this or username."),
1133
+ type: ostr("Which feed: 'posts' (default), 'comments' (posts they commented on), or 'reactions' (posts they reacted to)."),
1134
+ cursor: ostr("Opaque cursor from a prior response's next_cursor.")
1135
+ }),
1136
+ (i) => client.linkedin.personPosts(i)
1137
+ ),
1138
+ tool(
1139
+ "LINKEDIN_COMPANY",
1140
+ "Scavio LinkedIn Company",
1141
+ "Fetch a LinkedIn company profile: description, website, industries, specialties, employee and follower counts, headquarters, locations, similar and affiliated companies, and featured_employees (a 4-6 person sample, the documented substitute for the retired employee directory). Costs 1 credit.",
1142
+ import_zod.z.object({
1143
+ company: ostr("Company universal name / slug, e.g. 'microsoft'. Provide this or url."),
1144
+ url: ostr("Full LinkedIn company URL. Provide this or company.")
1145
+ }),
1146
+ (i) => client.linkedin.company(i)
1147
+ ),
1148
+ tool(
1149
+ "LINKEDIN_COMPANY_POSTS",
1150
+ "Scavio LinkedIn Company Posts",
1151
+ "Recent posts from a LinkedIn company page, 50 per page; advance with next_cursor. There is no type selector here - that is person-only. Costs 10 credits.",
1152
+ import_zod.z.object({
1153
+ company: ostr("Company universal name / slug. Provide this or url."),
1154
+ url: ostr("Full LinkedIn company URL. Provide this or company."),
1155
+ cursor: ostr("Opaque cursor from a prior response's next_cursor.")
1156
+ }),
1157
+ (i) => client.linkedin.companyPosts(i)
1158
+ ),
1159
+ tool(
1160
+ "LINKEDIN_SEARCH_JOBS",
1161
+ "Scavio LinkedIn Search Jobs",
1162
+ "Search LinkedIn job listings, 25 per page; advance with next_cursor. Upstream rotates its result set so pages overlap - dedupe by job id. Costs 10 credits.",
1163
+ import_zod.z.object({
1164
+ search: str("Search keyword, e.g. 'software engineer'. The field is 'search', not 'query'."),
1165
+ location: ostr("Geographic filter; omit to search everywhere."),
1166
+ cursor: ostr("Opaque cursor from a prior response's next_cursor.")
1167
+ }),
1168
+ (i) => client.linkedin.searchJobs(i)
1169
+ ),
1170
+ tool(
1171
+ "LINKEDIN_JOB",
1172
+ "Scavio LinkedIn Job",
1173
+ "Full detail for one LinkedIn job listing, including the hiring company. The most expensive endpoint in the API - about 1 in 5 ids from LINKEDIN_SEARCH_JOBS has no detail record upstream and answers 404 unbilled, so skip rather than retry. Costs 30 credits.",
1174
+ import_zod.z.object({
1175
+ job_id: ostr("Job listing id, e.g. '4415427228'. Provide this or url."),
1176
+ url: ostr("Full LinkedIn job URL. Provide this or job_id.")
1177
+ }),
1178
+ (i) => client.linkedin.job(i)
1179
+ ),
1180
+ tool(
1181
+ "LINKEDIN_POST",
1182
+ "Scavio LinkedIn Post",
1183
+ "Full detail for one LinkedIn post: text, media, hashtags, tagged companies and people, reaction and comment counts, author, and its top visible comments. Costs 1 credit.",
1184
+ import_zod.z.object({
1185
+ post_id: ostr("Post id or activity urn, e.g. '7488618410256523265'. Provide this or url."),
1186
+ url: ostr("Full LinkedIn post URL. Provide this or post_id.")
1187
+ }),
1188
+ (i) => client.linkedin.post(i)
1189
+ ),
1190
+ tool(
1191
+ "LINKEDIN_POST_COMMENTS",
1192
+ "Scavio LinkedIn Post Comments",
1193
+ "Comments on a LinkedIn post with their replies. This is the only LinkedIn endpoint paginated by a 1-based integer page rather than a cursor, and page size varies upstream - keep paging until a page comes back empty. Costs 10 credits.",
1194
+ import_zod.z.object({
1195
+ post_id: ostr("Post id or activity urn. Provide this or url."),
1196
+ url: ostr("Full LinkedIn post URL. Provide this or post_id."),
1197
+ page: onum("1-based page number (default 1). Page size varies, so page until empty.")
1198
+ }),
1199
+ (i) => client.linkedin.postComments(i)
1200
+ )
1201
+ );
1202
+ }
474
1203
  return (0, import_core.experimental_createToolkit)("SCAVIO", {
475
1204
  name: "Scavio",
476
- description: "Real-time structured search over Google, YouTube, Amazon, Walmart, Reddit, TikTok, and Instagram.",
1205
+ description: "Real-time structured search over Google (SERP, AI Mode, Maps, Shopping, Flights, Hotels, News, Trends), YouTube, Amazon, Walmart, Reddit, TikTok, TikTok Shop, Instagram, X and LinkedIn.",
477
1206
  tools
478
1207
  });
479
1208
  }