Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit dfcecf2

Browse files
authored
feat/update-tool-desc (#275)
* feat: Update tool descriptions
1 parent cdffc3e commit dfcecf2

19 files changed

+863
-168
lines changed

docs/claude-code-tools.json

Lines changed: 508 additions & 0 deletions
Large diffs are not rendered by default.

package-lock.json

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@
6464
"dotenv": "^16.4.7",
6565
"eslint": "^9.19.0",
6666
"eventsource": "^3.0.2",
67-
"tsx": "^4.6.2",
67+
"tsx": "^4.20.5",
6868
"typescript": "^5.3.3",
6969
"typescript-eslint": "^8.23.0",
7070
"vitest": "^3.0.8"

src/const.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,15 +47,16 @@ export enum HelperTools {
4747
GET_HTML_SKELETON = 'get-html-skeleton',
4848
}
4949

50-
export const ACTOR_RAG_WEB_BROWSER = 'apify/rag-web-browser';
50+
export const RAG_WEB_BROWSER = 'apify/rag-web-browser';
51+
export const RAG_WEB_BROWSER_WHITELISTED_FIELDS = ['query', 'maxResults', 'outputFormats'];
52+
export const RAG_WEB_BROWSER_ADDITIONAL_DESC = `This tool provides general web browsing functionality, for specific sites like e-commerce, social media it is always better to search for a specific Actor`;
5153

5254
export const defaults = {
5355
actors: [
54-
ACTOR_RAG_WEB_BROWSER,
56+
RAG_WEB_BROWSER,
5557
],
5658
};
5759

58-
export const ACTOR_ADDITIONAL_INSTRUCTIONS = 'Never call/execute tool/Actor unless confirmed by the user.';
5960
export const SKYFIRE_MIN_CHARGE_USD = 5.0;
6061
export const SKYFIRE_SELLER_ID = process.env.SKYFIRE_SELLER_SERVICE_ID;
6162

src/tools/actor.ts

Lines changed: 65 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,10 @@ import log from '@apify/log';
77

88
import { ApifyClient } from '../apify-client.js';
99
import {
10-
ACTOR_ADDITIONAL_INSTRUCTIONS,
1110
ACTOR_MAX_MEMORY_MBYTES,
1211
HelperTools,
12+
RAG_WEB_BROWSER,
13+
RAG_WEB_BROWSER_ADDITIONAL_DESC,
1314
SKYFIRE_TOOL_INSTRUCTIONS,
1415
TOOL_MAX_OUTPUT_CHARS,
1516
} from '../const.js';
@@ -27,7 +28,7 @@ import type { ProgressTracker } from '../utils/progress.js';
2728
import type { JsonSchemaProperty } from '../utils/schema-generation.js';
2829
import { generateSchemaFromItems } from '../utils/schema-generation.js';
2930
import { getActorDefinition } from './build.js';
30-
import { actorNameToToolName, fixedAjvCompile, getToolSchemaID, transformActorInputSchemaProperties } from './utils.js';
31+
import { actorNameToToolName, buildActorInputSchema, fixedAjvCompile } from './utils.js';
3132

3233
// Define a named return type for callActorGetDataset
3334
export type CallActorGetDatasetResult = {
@@ -157,45 +158,48 @@ export async function getNormalActorsAsTools(
157158
): Promise<ToolEntry[]> {
158159
const tools: ToolEntry[] = [];
159160

160-
// Zip the results with their corresponding actorIDs
161161
for (const actorInfo of actorsInfo) {
162162
const { actorDefinitionPruned } = actorInfo;
163163

164-
if (actorDefinitionPruned) {
165-
const schemaID = getToolSchemaID(actorDefinitionPruned.actorFullName);
166-
if (actorDefinitionPruned.input && 'properties' in actorDefinitionPruned.input && actorDefinitionPruned.input) {
167-
actorDefinitionPruned.input.properties = transformActorInputSchemaProperties(actorDefinitionPruned.input);
168-
// Add schema $id, each valid JSON schema should have a unique $id
169-
// see https://json-schema.org/understanding-json-schema/basics#declaring-a-unique-identifier
170-
actorDefinitionPruned.input.$id = schemaID;
171-
}
172-
try {
173-
const memoryMbytes = actorDefinitionPruned.defaultRunOptions?.memoryMbytes || ACTOR_MAX_MEMORY_MBYTES;
174-
const tool: ToolEntry = {
175-
type: 'actor',
176-
tool: {
177-
name: actorNameToToolName(actorDefinitionPruned.actorFullName),
178-
actorFullName: actorDefinitionPruned.actorFullName,
179-
description: `This tool calls the Actor "${actorDefinitionPruned.actorFullName}" and retrieves its output results. Use this tool instead of the "${HelperTools.ACTOR_CALL}" if user requests to use this specific Actor.
180-
Actor description: ${actorDefinitionPruned.description}
181-
Instructions: ${ACTOR_ADDITIONAL_INSTRUCTIONS}`,
182-
inputSchema: actorDefinitionPruned.input
183-
// So Actor without input schema works - MCP client expects JSON schema valid output
184-
|| {
185-
type: 'object',
186-
properties: {},
187-
required: [],
188-
},
189-
// Additional props true to allow skyfire-pay-id
190-
ajvValidate: fixedAjvCompile(ajv, { ...actorDefinitionPruned.input, additionalProperties: true }),
191-
memoryMbytes: memoryMbytes > ACTOR_MAX_MEMORY_MBYTES ? ACTOR_MAX_MEMORY_MBYTES : memoryMbytes,
192-
},
193-
};
194-
tools.push(tool);
195-
} catch (validationError) {
196-
log.error('Failed to compile AJV schema for Actor', { actorName: actorDefinitionPruned.actorFullName, error: validationError });
197-
}
164+
if (!actorDefinitionPruned) continue;
165+
166+
const isRag = actorDefinitionPruned.actorFullName === RAG_WEB_BROWSER;
167+
const { inputSchema } = buildActorInputSchema(actorDefinitionPruned.actorFullName, actorDefinitionPruned.input, isRag);
168+
169+
let description = `This tool calls the Actor "${actorDefinitionPruned.actorFullName}" and retrieves its output results.
170+
Use this tool instead of the "${HelperTools.ACTOR_CALL}" if user requests this specific Actor.
171+
Actor description: ${actorDefinitionPruned.description}`;
172+
if (isRag) {
173+
description += RAG_WEB_BROWSER_ADDITIONAL_DESC;
198174
}
175+
176+
const memoryMbytes = Math.min(
177+
actorDefinitionPruned.defaultRunOptions?.memoryMbytes || ACTOR_MAX_MEMORY_MBYTES,
178+
ACTOR_MAX_MEMORY_MBYTES,
179+
);
180+
181+
let ajvValidate;
182+
try {
183+
ajvValidate = fixedAjvCompile(ajv, { ...inputSchema, additionalProperties: true });
184+
} catch (e) {
185+
log.error('Failed to compile schema', {
186+
actorName: actorDefinitionPruned.actorFullName,
187+
error: e,
188+
});
189+
continue;
190+
}
191+
192+
tools.push({
193+
type: 'actor',
194+
tool: {
195+
name: actorNameToToolName(actorDefinitionPruned.actorFullName),
196+
actorFullName: actorDefinitionPruned.actorFullName,
197+
description,
198+
inputSchema,
199+
ajvValidate,
200+
memoryMbytes,
201+
},
202+
});
199203
}
200204
return tools;
201205
}
@@ -240,8 +244,7 @@ async function getMCPServersAsTools(
240244
// Skip this Actor, connectMCPClient will log the error
241245
return [];
242246
}
243-
const serverTools = await getMCPServerTools(actorId, client, mcpServerUrl);
244-
return serverTools;
247+
return await getMCPServerTools(actorId, client, mcpServerUrl);
245248
} finally {
246249
if (client) await client.close();
247250
}
@@ -304,7 +307,7 @@ const callActorArgs = z.object({
304307
.describe('The name of the Actor to call. For example, "apify/rag-web-browser".'),
305308
step: z.enum(['info', 'call'])
306309
.default('info')
307-
.describe(`Step to perform: "info" to get Actor details and input schema (required first step), "call" to execute the Actor (only after getting info).`),
310+
.describe(`Step to perform: "info" to get Actor details and input schema (required first step), "call" to run the Actor (only after getting info).`),
308311
input: z.object({}).passthrough()
309312
.optional()
310313
.describe(`The input JSON to pass to the Actor. For example, {"query": "apify", "maxResults": 5, "outputFormats": ["markdown"]}. Required only when step is "call".`),
@@ -327,33 +330,35 @@ export const callActor: ToolEntry = {
327330
tool: {
328331
name: HelperTools.ACTOR_CALL,
329332
actorFullName: HelperTools.ACTOR_CALL,
330-
description: `Call Any Actor from Apify Store - Two-Step Process
333+
description: `Call any Actor from the Apify Store using a mandatory two-step workflow.
334+
This ensures you first get the Actor’s input schema and details before executing it safely.
331335
332-
This tool uses a mandatory two-step process to safely call any Actor from the Apify store.
336+
There are two ways to run Actors:
337+
1. Dedicated Actor tools (e.g., ${actorNameToToolName('apify/rag-web-browser')}): These are pre-configured tools, offering a simpler and more direct experience.
338+
2. Generic call-actor tool (${HelperTools.ACTOR_CALL}): Use this when a dedicated tool is not available or when you want to run any Actor dynamically. This tool is especially useful if you do not want to add specific tools or your client does not support dynamic tool registration.
333339
334-
USAGE:
335-
• ONLY for Actors that are NOT available as dedicated tools
336-
• If a dedicated tool exists (e.g., ${actorNameToToolName('apify/rag-web-browser')}), use that instead
340+
**Important:**
341+
342+
Typically, a successful run returns a \`datasetId\` (the Actor's output stored as an Apify dataset) and a short preview of items.
343+
To fetch the full output, use the ${HelperTools.ACTOR_OUTPUT_GET} tool with the \`datasetId\`.
337344
338-
MANDATORY TWO-STEP WORKFLOW:
345+
USAGE:
346+
- Always use dedicated tools when available (e.g., ${actorNameToToolName('apify/rag-web-browser')})
347+
- Use the generic call-actor tool only if a dedicated tool does not exist for your Actor.
339348
349+
MANDATORY TWO-STEP-WORKFLOW:
340350
Step 1: Get Actor Info (step="info", default)
341-
• First call this tool with step="info" to get Actor details and input schema
342-
• For regular Actors: returns the Actor input schema
343-
• For MCP server Actors: returns list of available tools with their schemas
344-
• You MUST do this step first - it's required to understand how to call the Actor
351+
- First call this tool with step="info" to get Actor details and input schema
352+
- This returns the Actor description, documentation, and required input schema
353+
- You MUST do this step first - it's required to understand how to call the Actor
345354
346355
Step 2: Call Actor (step="call")
347-
• Only after step 1, call again with step="call" and proper input based on the schema
348-
• For regular Actors: executes the Actor and returns results
349-
• For MCP server Actors: use format "actor-name:tool-name" to call specific tools
350-
351-
MCP SERVER ACTORS:
352-
• For MCP server actors, step="info" lists available tools instead of input schema
353-
• To call an MCP tool, use actor name format: "actor-name:tool-name" with step="call"
354-
• Example: actor="apify/my-mcp-actor:search-tool", step="call", input={...}
356+
- Only after step 1, call this tool again with step="call" and proper input based on the schema
357+
- This runs the Actor. It will create an output as an Apify dataset (with datasetId).
358+
- This step returns a dataset preview, typically JSON-formatted tabular data.
355359
356-
The step parameter enforces this workflow - you cannot call an Actor without first getting its info.`,
360+
EXAMPLES:
361+
- user_input: Get instagram posts using apify/instagram-scraper`,
357362
inputSchema: zodToJsonSchema(callActorArgs),
358363
ajvValidate: ajv.compile({
359364
...zodToJsonSchema(callActorArgs),
@@ -414,6 +419,7 @@ The step parameter enforces this workflow - you cannot call an Actor without fir
414419
return buildMCPResponse([`Actor information for '${baseActorName}' was not found. Please check the Actor ID or name and ensure the Actor exists.`]);
415420
}
416421
const content = [
422+
// TODO: update result to say: this is result of info step, you must now call again with step=call and proper input
417423
{ type: 'text', text: `**Input Schema:**\n${JSON.stringify(details.inputSchema, null, 0)}` },
418424
];
419425
/**

src/tools/dataset.ts

Lines changed: 33 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,17 @@ export const getDataset: ToolEntry = {
4646
tool: {
4747
name: HelperTools.DATASET_GET,
4848
actorFullName: HelperTools.DATASET_GET,
49-
description: 'Dataset is a collection of structured data created by an Actor run. '
50-
+ 'Returns information about dataset object with metadata (itemCount, schema, fields, stats). '
51-
+ `Fields describe the structure of the dataset and can be used to filter the data with the ${HelperTools.DATASET_GET_ITEMS} tool. `
52-
+ 'Note: itemCount updates may have 5s delay.'
53-
+ 'The dataset can be accessed with the dataset URL: GET: https://api.apify.com/v2/datasets/:datasetId',
49+
description: `Get metadata for a dataset (collection of structured data created by an Actor run).
50+
The results will include dataset details such as itemCount, schema, fields, and stats.
51+
Use fields to understand structure for filtering with ${HelperTools.DATASET_GET_ITEMS}.
52+
Note: itemCount updates may be delayed by up to ~5 seconds.
53+
54+
USAGE:
55+
- Use when you need dataset metadata to understand its structure before fetching items.
56+
57+
USAGE EXAMPLES:
58+
- user_input: Show info for dataset 8TtYhCwKzQeQk7dJx
59+
- user_input: What fields does username~my-dataset have?`,
5460
inputSchema: zodToJsonSchema(getDatasetArgs),
5561
ajvValidate: ajv.compile(zodToJsonSchema(getDatasetArgs)),
5662
call: async (toolArgs) => {
@@ -74,16 +80,18 @@ export const getDatasetItems: ToolEntry = {
7480
tool: {
7581
name: HelperTools.DATASET_GET_ITEMS,
7682
actorFullName: HelperTools.DATASET_GET_ITEMS,
77-
description: 'Returns dataset items with pagination support. '
78-
+ 'Items can be sorted (newest to oldest) and filtered (clean mode skips empty items and hidden fields). '
79-
+ 'Supports field selection - include specific fields or exclude unwanted ones using comma-separated lists. '
80-
+ 'For nested objects, you must first flatten them using the flatten parameter before accessing their fields. '
81-
+ 'Example: To get URLs from items like [{"metadata":{"url":"example.com"}}], '
82-
+ 'use flatten="metadata" and then fields="metadata.url". '
83-
+ 'The flattening transforms nested objects into dot-notation format '
84-
+ '(e.g. {"metadata":{"url":"x"}} becomes {"metadata.url":"x"}). '
85-
+ 'Retrieve only the fields you need, reducing the response size and improving performance. '
86-
+ 'The response includes total count, offset, limit, and items array.',
83+
description: `Retrieve dataset items with pagination, sorting, and field selection.
84+
Use clean=true to skip empty items and hidden fields. Include or omit fields using comma-separated lists.
85+
For nested objects, first flatten them (e.g., flatten="metadata"), then reference nested fields via dot notation (e.g., fields="metadata.url").
86+
87+
The results will include items along with pagination info (limit, offset) and total count.
88+
89+
USAGE:
90+
- Use when you need to read data from a dataset (all items or only selected fields).
91+
92+
USAGE EXAMPLES:
93+
- user_input: Get first 100 items from dataset 8TtYhCwKzQeQk7dJx
94+
- user_input: Get only metadata.url and title from dataset username~my-dataset (flatten metadata)`,
8795
inputSchema: zodToJsonSchema(getDatasetItemsArgs),
8896
ajvValidate: ajv.compile(zodToJsonSchema(getDatasetItemsArgs)),
8997
call: async (toolArgs) => {
@@ -136,9 +144,16 @@ export const getDatasetSchema: ToolEntry = {
136144
tool: {
137145
name: HelperTools.DATASET_SCHEMA_GET,
138146
actorFullName: HelperTools.DATASET_SCHEMA_GET,
139-
description: 'Generates a JSON schema from dataset items. '
140-
+ 'The schema describes the structure of the data in the dataset, which can be used for validation, documentation, or data processing.'
141-
+ 'Since the dataset can be large it is convenient to understand the structure of the dataset before getting dataset items.',
147+
description: `Generate a JSON schema from a sample of dataset items.
148+
The schema describes the structure of the data and can be used for validation, documentation, or processing.
149+
Use this to understand the dataset before fetching many items.
150+
151+
USAGE:
152+
- Use when you need to infer the structure of dataset items for downstream processing or validation.
153+
154+
USAGE EXAMPLES:
155+
- user_input: Generate schema for dataset 8TtYhCwKzQeQk7dJx using 10 items
156+
- user_input: Show schema of username~my-dataset (clean items only)`,
142157
inputSchema: zodToJsonSchema(getDatasetSchemaArgs),
143158
ajvValidate: ajv.compile(zodToJsonSchema(getDatasetSchemaArgs)),
144159
call: async (toolArgs) => {

src/tools/dataset_collection.ts

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,18 @@ export const getUserDatasetsList: ToolEntry = {
3030
tool: {
3131
name: HelperTools.DATASET_LIST_GET,
3232
actorFullName: HelperTools.DATASET_LIST_GET,
33-
description: 'Lists datasets (collections of Actor run data). '
34-
+ 'Actor runs automatically produce unnamed datasets (use unnamed=true to include these). '
35-
+ 'Users can also create named datasets manually. '
36-
+ 'Each dataset includes itemCount, access settings, and usage stats (readCount, writeCount). '
37-
+ 'Results are sorted by createdAt in ascending order (use desc=true for descending). '
38-
+ 'Supports pagination with limit (max 20) and offset parameters.',
33+
description: `List datasets (collections of Actor run data) for the authenticated user.
34+
Actor runs automatically produce unnamed datasets (set unnamed=true to include them). Users can also create named datasets.
35+
36+
The results will include datasets with itemCount, access settings, and usage stats, sorted by createdAt (ascending by default).
37+
Use limit (max 20), offset, and desc to paginate and sort.
38+
39+
USAGE:
40+
- Use when you need to browse available datasets (named or unnamed) to locate data.
41+
42+
USAGE EXAMPLES:
43+
- user_input: List my last 10 datasets (newest first)
44+
- user_input: List unnamed datasets`,
3945
inputSchema: zodToJsonSchema(getUserDatasetsListArgs),
4046
ajvValidate: ajv.compile(zodToJsonSchema(getUserDatasetsListArgs)),
4147
call: async (toolArgs) => {

src/tools/fetch-actor-details.ts

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,17 @@ export const fetchActorDetailsTool: ToolEntry = {
1717
type: 'internal',
1818
tool: {
1919
name: HelperTools.ACTOR_GET_DETAILS,
20-
description: `Get detailed information about an Actor by its ID or full name.\n`
21-
+ `This tool returns title, description, URL, README (Actor's documentation), input schema, and usage statistics. \n`
22-
+ `The Actor name is always composed of "username/name", for example, "apify/rag-web-browser".\n`
23-
+ `Present Actor information in user-friendly format as an Actor card.\n`
24-
+ `USAGE:\n`
25-
+ `- Use when user asks about an Actor its details, description, input schema, etc.\n`
26-
+ `EXAMPLES:\n`
27-
+ `- user_input: How to use apify/rag-web-browser\n`
28-
+ `- user_input: What is the input schema for apify/rag-web-browser`,
20+
description: `Get detailed information about an Actor by its ID or full name (format: "username/name", e.g., "apify/rag-web-browser").
21+
This returns the Actor’s title, description, URL, README (documentation), input schema, pricing/usage information, and basic stats.
22+
Present the information in a user-friendly Actor card.
23+
24+
USAGE:
25+
- Use when a user asks about an Actor’s details, input schema, README, or how to use it.
26+
27+
USAGE EXAMPLES:
28+
- user_input: How to use apify/rag-web-browser
29+
- user_input: What is the input schema for apify/rag-web-browser?
30+
- user_input: What is the pricing for apify/instagram-scraper?`,
2931
inputSchema: zodToJsonSchema(fetchActorDetailsToolArgsSchema),
3032
ajvValidate: ajv.compile(zodToJsonSchema(fetchActorDetailsToolArgsSchema)),
3133
call: async (toolArgs) => {

0 commit comments

Comments
 (0)