-
Notifications
You must be signed in to change notification settings - Fork 215
Expand file tree
/
Copy pathsearch_actors.ts
More file actions
78 lines (72 loc) · 3.43 KB
/
Copy pathsearch_actors.ts
File metadata and controls
78 lines (72 loc) · 3.43 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
import dedent from 'dedent';
import { HelperTools } from '../../const.js';
import type { InternalToolArgs, ToolEntry } from '../../types.js';
import { searchAgentSafeActors } from '../../utils/actor_search.js';
import { buildMCPResponse } from '../../utils/mcp.js';
import { getUserInfoCached } from '../../utils/userid_cache.js';
import {
buildSearchActorsEmptyResponse,
buildSearchActorsResult,
searchActorsArgsSchema,
searchActorsMetadata,
} from '../core/search_actors_common.js';
/**
* Default mode search-actors tool.
* Returns text-based Actor cards without widget metadata.
*/
export const defaultSearchActors: ToolEntry = Object.freeze({
...searchActorsMetadata,
call: async (toolArgs: InternalToolArgs) => {
const { args, apifyToken, apifyClient, apifyMcpServer } = toolArgs;
const parsed = searchActorsArgsSchema.parse(args);
// Actor search and user-info fetch are independent; run in parallel to avoid a
// sequential round-trip on cache miss.
const [actors, { userPlanTier }] = await Promise.all([
searchAgentSafeActors({
keywords: parsed.keywords,
apifyToken,
limit: parsed.limit,
offset: parsed.offset,
paymentProvider: apifyMcpServer.options.paymentProvider,
}),
getUserInfoCached(apifyToken, apifyClient),
]);
if (actors.length === 0) {
return buildSearchActorsEmptyResponse(parsed.keywords);
}
const { actorCardText, actorCardStructured } = buildSearchActorsResult(actors, userPlanTier);
const structuredContent = {
actors: actorCardStructured,
query: parsed.keywords,
count: actors.length,
instructions: dedent`
If you need more detailed information about any of these Actors, including their
input schemas and usage instructions, please use the ${HelperTools.ACTOR_GET_DETAILS}
tool with the specific Actor name.
IMPORTANT: You MUST always do a second search with broader, more generic keywords
(e.g., just the platform name like "TikTok" instead of "TikTok posts") to make sure
you haven't missed a better Actor.
`,
};
// Build header and footer with separate `dedent` calls and concatenate around
// `actorCardText` — Actor cards may contain tab-indented lines (pay-per-event
// pricing) that would corrupt `dedent`'s indent detection if interpolated into
// the surrounding template.
const header = dedent`
# Search results:
- **Search query:** ${parsed.keywords}
- **Number of Actors found:** ${actors.length}
# Actors:
`;
const footer = dedent`
If you need more detailed information about any of these Actors, including their input
schemas and usage instructions, use the ${HelperTools.ACTOR_GET_DETAILS} tool with the
specific Actor name.
IMPORTANT: You MUST always do a second search with broader, more generic keywords
(e.g., just the platform name like "TikTok" instead of "TikTok posts") to make sure
you haven't missed a better Actor.
`;
const texts = [`${header}\n\n${actorCardText}\n\n${footer}`];
return buildMCPResponse({ texts, structuredContent });
},
} as const);